[james-page] Add support for optional resize support
[r,gandelman-a]
This commit is contained in:
commit
465b5899e2
|
@ -50,6 +50,11 @@ options:
|
|||
default: "yes"
|
||||
type: string
|
||||
description: Whether to run nova-api and nova-network on the compute nodes.
|
||||
enable-resize:
|
||||
default: False
|
||||
type: boolean
|
||||
description: Enable instance resizing, which requires that passwordless SSH
|
||||
access be setup between compute hosts.
|
||||
enable-live-migration:
|
||||
default: False
|
||||
type: boolean
|
||||
|
|
|
@ -48,7 +48,8 @@ from nova_compute_utils import (
|
|||
register_configs,
|
||||
NOVA_CONF,
|
||||
QUANTUM_CONF, NEUTRON_CONF,
|
||||
ceph_config_file, CEPH_SECRET
|
||||
ceph_config_file, CEPH_SECRET,
|
||||
enable_shell, disable_shell
|
||||
)
|
||||
|
||||
from nova_compute_context import CEPH_SECRET_UUID
|
||||
|
@ -75,7 +76,14 @@ def config_changed():
|
|||
# Check-in with nova-c-c and register new ssh key, if it has just been
|
||||
# generated.
|
||||
initialize_ssh_keys()
|
||||
[compute_joined(rid) for rid in relation_ids('cloud-compute')]
|
||||
|
||||
if config('enable-resize') is True:
|
||||
enable_shell(user='nova')
|
||||
initialize_ssh_keys(user='nova')
|
||||
else:
|
||||
disable_shell(user='nova')
|
||||
|
||||
[compute_joined(rid) for rid in relation_ids('cloud-compute')]
|
||||
|
||||
CONFIGS.write_all()
|
||||
|
||||
|
@ -140,15 +148,19 @@ def image_service_changed():
|
|||
|
||||
@hooks.hook('cloud-compute-relation-joined')
|
||||
def compute_joined(rid=None):
|
||||
if not migration_enabled():
|
||||
return
|
||||
auth_type = config('migration-auth-type')
|
||||
settings = {
|
||||
'migration_auth_type': auth_type
|
||||
}
|
||||
if auth_type == 'ssh':
|
||||
settings['ssh_public_key'] = public_ssh_key()
|
||||
relation_set(relation_id=rid, **settings)
|
||||
if migration_enabled():
|
||||
auth_type = config('migration-auth-type')
|
||||
settings = {
|
||||
'migration_auth_type': auth_type
|
||||
}
|
||||
if auth_type == 'ssh':
|
||||
settings['ssh_public_key'] = public_ssh_key()
|
||||
relation_set(relation_id=rid, **settings)
|
||||
if config('enable-resize'):
|
||||
settings = {
|
||||
'nova_ssh_public_key': public_ssh_key(user='nova')
|
||||
}
|
||||
relation_set(relation_id=rid, **settings)
|
||||
|
||||
|
||||
@hooks.hook('cloud-compute-relation-changed')
|
||||
|
@ -158,6 +170,7 @@ def compute_changed():
|
|||
# config advertised from controller.
|
||||
CONFIGS.write_all()
|
||||
import_authorized_keys()
|
||||
import_authorized_keys(user='nova', prefix='nova')
|
||||
import_keystone_ca_cert()
|
||||
if (network_manager() in ['quantum', 'neutron']
|
||||
and neutron_plugin() == 'ovs'):
|
||||
|
|
|
@ -315,13 +315,18 @@ def initialize_ssh_keys(user='root'):
|
|||
check_output(['chown', '-R', user, ssh_dir])
|
||||
|
||||
|
||||
def import_authorized_keys(user='root'):
|
||||
def import_authorized_keys(user='root', prefix=None):
|
||||
"""Import SSH authorized_keys + known_hosts from a cloud-compute relation
|
||||
and store in user's $HOME/.ssh.
|
||||
"""
|
||||
# XXX: Should this be managed via templates + contexts?
|
||||
hosts = relation_get('known_hosts')
|
||||
auth_keys = relation_get('authorized_keys')
|
||||
if prefix:
|
||||
hosts = relation_get('{}_known_hosts'.format(prefix))
|
||||
auth_keys = relation_get('{}_authorized_keys'.format(prefix))
|
||||
else:
|
||||
# XXX: Should this be managed via templates + contexts?
|
||||
hosts = relation_get('known_hosts')
|
||||
auth_keys = relation_get('authorized_keys')
|
||||
|
||||
# XXX: Need to fix charm-helpers to return None for empty settings,
|
||||
# in all cases.
|
||||
if not hosts or not auth_keys:
|
||||
|
@ -380,3 +385,13 @@ def create_libvirt_secret(secret_file, secret_uuid, key):
|
|||
cmd = ['virsh', 'secret-set-value', '--secret', secret_uuid,
|
||||
'--base64', key]
|
||||
check_call(cmd)
|
||||
|
||||
|
||||
def enable_shell(user):
|
||||
cmd = ['usermod', '-s', '/bin/bash', user]
|
||||
check_call(cmd)
|
||||
|
||||
|
||||
def disable_shell(user):
|
||||
cmd = ['usermod', '-s', '/bin/false', user]
|
||||
check_call(cmd)
|
||||
|
|
|
@ -48,6 +48,8 @@ TO_PATCH = [
|
|||
'neutron_plugin',
|
||||
'public_ssh_key',
|
||||
'register_configs',
|
||||
'disable_shell',
|
||||
'enable_shell',
|
||||
# misc_utils
|
||||
'ensure_ceph_keyring',
|
||||
'execd_preinstall'
|
||||
|
@ -95,6 +97,38 @@ class NovaComputeRelationsTests(CharmTestCase):
|
|||
call('cloud-compute:1'),
|
||||
]
|
||||
self.assertEquals(ex, compute_joined.call_args_list)
|
||||
self.assertTrue(self.initialize_ssh_keys.called)
|
||||
|
||||
@patch.object(hooks, 'compute_joined')
|
||||
def test_config_changed_with_resize(self, compute_joined):
|
||||
self.test_config.set('enable-resize', True)
|
||||
self.relation_ids.return_value = [
|
||||
'cloud-compute:0',
|
||||
'cloud-compute:1'
|
||||
]
|
||||
hooks.config_changed()
|
||||
ex = [
|
||||
call('cloud-compute:0'),
|
||||
call('cloud-compute:1'),
|
||||
]
|
||||
self.assertEquals(ex, compute_joined.call_args_list)
|
||||
self.initialize_ssh_keys.assert_called_with(user='nova')
|
||||
self.enable_shell.assert_called_with(user='nova')
|
||||
|
||||
@patch.object(hooks, 'compute_joined')
|
||||
def test_config_changed_without_resize(self, compute_joined):
|
||||
self.test_config.set('enable-resize', False)
|
||||
self.relation_ids.return_value = [
|
||||
'cloud-compute:0',
|
||||
'cloud-compute:1'
|
||||
]
|
||||
hooks.config_changed()
|
||||
ex = [
|
||||
call('cloud-compute:0'),
|
||||
call('cloud-compute:1'),
|
||||
]
|
||||
self.assertEquals(ex, compute_joined.call_args_list)
|
||||
self.disable_shell.assert_called_with(user='nova')
|
||||
|
||||
@patch.object(hooks, 'compute_joined')
|
||||
def test_config_changed_no_upgrade_no_migration(self, compute_joined):
|
||||
|
@ -239,7 +273,7 @@ class NovaComputeRelationsTests(CharmTestCase):
|
|||
hooks.image_service_changed()
|
||||
configs.write.assert_called_with('/etc/nova/nova.conf')
|
||||
|
||||
def test_compute_joined_no_migration(self):
|
||||
def test_compute_joined_no_migration_no_resize(self):
|
||||
self.migration_enabled.return_value = False
|
||||
hooks.compute_joined()
|
||||
self.assertFalse(self.relation_set.called)
|
||||
|
@ -261,14 +295,27 @@ class NovaComputeRelationsTests(CharmTestCase):
|
|||
migration_auth_type='ssh'
|
||||
)
|
||||
|
||||
def test_compute_joined_with_resize(self):
|
||||
self.test_config.set('enable-resize', True)
|
||||
self.public_ssh_key.return_value = 'bar'
|
||||
hooks.compute_joined()
|
||||
self.relation_set.assert_called_with(
|
||||
relation_id=None,
|
||||
nova_ssh_public_key='bar'
|
||||
)
|
||||
hooks.compute_joined(rid='cloud-compute:2')
|
||||
self.relation_set.assert_called_with(
|
||||
relation_id='cloud-compute:2',
|
||||
nova_ssh_public_key='bar'
|
||||
)
|
||||
|
||||
def test_compute_changed(self):
|
||||
hooks.compute_changed()
|
||||
expected_funcs = [
|
||||
self.import_authorized_keys,
|
||||
self.import_keystone_ca_cert,
|
||||
]
|
||||
for func in expected_funcs:
|
||||
self.assertTrue(func.called)
|
||||
self.assertTrue(self.import_keystone_ca_cert.called)
|
||||
self.import_authorized_keys.assert_has_calls([
|
||||
call(),
|
||||
call(user='nova', prefix='nova'),
|
||||
])
|
||||
|
||||
def test_ceph_joined(self):
|
||||
hooks.ceph_joined()
|
||||
|
|
|
@ -179,7 +179,7 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||
self.assertFalse(_open.called)
|
||||
|
||||
@patch('pwd.getpwnam')
|
||||
def test_import_authorized_keys(self, getpwnam):
|
||||
def _test_import_authorized_keys_base(self, getpwnam, prefix=None):
|
||||
getpwnam.return_value = self.fake_user('foo')
|
||||
self.relation_get.side_effect = [
|
||||
'Zm9vX2tleQo=', # relation_get('known_hosts')
|
||||
|
@ -200,6 +200,38 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||
self.assertEquals(ex_open, _open.call_args_list)
|
||||
self.assertEquals(ex_write, _file.write.call_args_list)
|
||||
|
||||
self.relation_get.assert_has_called([
|
||||
call('known_hosts').
|
||||
call('authorized_keys')
|
||||
])
|
||||
|
||||
@patch('pwd.getpwnam')
|
||||
def test_import_authorized_keys_prefix(self, getpwnam):
|
||||
getpwnam.return_value = self.fake_user('foo')
|
||||
self.relation_get.side_effect = [
|
||||
'Zm9vX2tleQo=', # relation_get('known_hosts')
|
||||
'Zm9vX2hvc3QK', # relation_get('authorized_keys')
|
||||
]
|
||||
|
||||
ex_open = [
|
||||
call('/home/foo/.ssh/authorized_keys', 'wb'),
|
||||
call('/home/foo/.ssh/known_hosts', 'wb')
|
||||
]
|
||||
ex_write = [
|
||||
call('foo_host\n'),
|
||||
call('foo_key\n'),
|
||||
]
|
||||
|
||||
with patch_open() as (_open, _file):
|
||||
utils.import_authorized_keys(user='foo', prefix='bar')
|
||||
self.assertEquals(ex_open, _open.call_args_list)
|
||||
self.assertEquals(ex_write, _file.write.call_args_list)
|
||||
|
||||
self.relation_get.assert_has_called([
|
||||
call('bar_known_hosts').
|
||||
call('bar_authorized_keys')
|
||||
])
|
||||
|
||||
@patch('subprocess.check_call')
|
||||
def test_import_keystone_cert_missing_data(self, check_call):
|
||||
self.relation_get.return_value = None
|
||||
|
@ -247,3 +279,14 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||
call('/etc/nova/nova.conf', [ctxt1])
|
||||
]
|
||||
self.assertEquals(fake_renderer.register.call_args_list, ex_reg)
|
||||
|
||||
@patch.object(utils, 'check_call')
|
||||
def test_enable_shell(self, _check_call):
|
||||
utils.enable_shell('dummy')
|
||||
_check_call.assert_called_with(['usermod', '-s', '/bin/bash', 'dummy'])
|
||||
|
||||
@patch.object(utils, 'check_call')
|
||||
def test_disable_shell(self, _check_call):
|
||||
utils.disable_shell('dummy')
|
||||
_check_call.assert_called_with(['usermod', '-s', '/bin/false',
|
||||
'dummy'])
|
||||
|
|
Loading…
Reference in New Issue