Construct package list and restart_map dynamically. Check-in tests.
This commit is contained in:
parent
8139e43440
commit
4b969f7722
10
charm-helpers.yaml
Normal file
10
charm-helpers.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
branch: lp:charm-helpers
|
||||||
|
destination: hooks/charmhelpers
|
||||||
|
include:
|
||||||
|
- core
|
||||||
|
- contrib.openstack|inc=*
|
||||||
|
- contrib.storage
|
||||||
|
- contrib.hahelpers:
|
||||||
|
- apache
|
||||||
|
- ceph
|
||||||
|
- cluster
|
1
hooks/install
Symbolic link
1
hooks/install
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
nova_compute_relations.py
|
@ -24,8 +24,7 @@ from charmhelpers.contrib.openstack.utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from nova_compute_utils import (
|
from nova_compute_utils import (
|
||||||
PACKAGES,
|
determine_packages,
|
||||||
RESTART_MAP,
|
|
||||||
import_authorized_keys,
|
import_authorized_keys,
|
||||||
import_keystone_ca_cert,
|
import_keystone_ca_cert,
|
||||||
migration_enabled,
|
migration_enabled,
|
||||||
@ -33,9 +32,11 @@ from nova_compute_utils import (
|
|||||||
configure_network_service,
|
configure_network_service,
|
||||||
configure_volume_service,
|
configure_volume_service,
|
||||||
do_openstack_upgrade,
|
do_openstack_upgrade,
|
||||||
|
quantum_attribute,
|
||||||
quantum_enabled,
|
quantum_enabled,
|
||||||
quantum_plugin_config,
|
quantum_plugin,
|
||||||
public_ssh_key,
|
public_ssh_key,
|
||||||
|
restart_map,
|
||||||
register_configs,
|
register_configs,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,11 +52,11 @@ CONFIGS = register_configs()
|
|||||||
def install():
|
def install():
|
||||||
configure_installation_source(config('openstack-origin'))
|
configure_installation_source(config('openstack-origin'))
|
||||||
apt_update()
|
apt_update()
|
||||||
apt_install(PACKAGES, fatal=True)
|
apt_install(determine_packages(), fatal=True)
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('config-changed')
|
@hooks.hook('config-changed')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def config_changed():
|
def config_changed():
|
||||||
if openstack_upgrade_available('nova-common'):
|
if openstack_upgrade_available('nova-common'):
|
||||||
do_openstack_upgrade()
|
do_openstack_upgrade()
|
||||||
@ -68,13 +69,13 @@ def config_changed():
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('amqp-relation-joined')
|
@hooks.hook('amqp-relation-joined')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def amqp_joined():
|
def amqp_joined():
|
||||||
relation_set(username=config('rabbit-user'), vhost=config('rabbit-vhost'))
|
relation_set(username=config('rabbit-user'), vhost=config('rabbit-vhost'))
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('amqp-relation-changed')
|
@hooks.hook('amqp-relation-changed')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def amqp_changed():
|
def amqp_changed():
|
||||||
if 'amqp' not in CONFIGS.complete_contexts():
|
if 'amqp' not in CONFIGS.complete_contexts():
|
||||||
log('amqp relation incomplete. Peer not ready?')
|
log('amqp relation incomplete. Peer not ready?')
|
||||||
@ -91,18 +92,19 @@ def db_joined():
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('shared-db-relation-changed')
|
@hooks.hook('shared-db-relation-changed')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def db_changed():
|
def db_changed():
|
||||||
if 'shared-db' not in CONFIGS.complete_contexts():
|
if 'shared-db' not in CONFIGS.complete_contexts():
|
||||||
log('shared-db relation incomplete. Peer not ready?')
|
log('shared-db relation incomplete. Peer not ready?')
|
||||||
return
|
return
|
||||||
CONFIGS.write('/etc/nova/nova.conf')
|
CONFIGS.write('/etc/nova/nova.conf')
|
||||||
if quantum_enabled():
|
if quantum_enabled():
|
||||||
CONFIGS.write(quantum_plugin_config())
|
plugin = quantum_plugin()
|
||||||
|
CONFIGS.write(quantum_attribute(plugin, 'config'))
|
||||||
|
|
||||||
|
|
||||||
@hooks.hook('image-service-relation-changed')
|
@hooks.hook('image-service-relation-changed')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def image_service_changed():
|
def image_service_changed():
|
||||||
if 'image-service' not in CONFIGS.complete_contexts():
|
if 'image-service' not in CONFIGS.complete_contexts():
|
||||||
log('image-service relation incomplete. Peer not ready?')
|
log('image-service relation incomplete. Peer not ready?')
|
||||||
@ -124,7 +126,7 @@ def compute_joined(rid=None):
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('cloud-compute-relation-changed')
|
@hooks.hook('cloud-compute-relation-changed')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def compute_changed():
|
def compute_changed():
|
||||||
configure_network_service()
|
configure_network_service()
|
||||||
configure_volume_service()
|
configure_volume_service()
|
||||||
@ -133,7 +135,7 @@ def compute_changed():
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('ceph-relation-joined')
|
@hooks.hook('ceph-relation-joined')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def ceph_joined():
|
def ceph_joined():
|
||||||
if not os.path.isdir('/etc/ceph'):
|
if not os.path.isdir('/etc/ceph'):
|
||||||
os.mkdir('/etc/ceph')
|
os.mkdir('/etc/ceph')
|
||||||
@ -141,7 +143,7 @@ def ceph_joined():
|
|||||||
|
|
||||||
|
|
||||||
@hooks.hook('ceph-relation-changed')
|
@hooks.hook('ceph-relation-changed')
|
||||||
@restart_on_change(RESTART_MAP)
|
@restart_on_change(restart_map())
|
||||||
def ceph_changed():
|
def ceph_changed():
|
||||||
if 'ceph' not in CONFIGS.complete_contexts():
|
if 'ceph' not in CONFIGS.complete_contexts():
|
||||||
log('ceph relation incomplete. Peer not ready?')
|
log('ceph relation incomplete. Peer not ready?')
|
||||||
|
@ -1,12 +1,47 @@
|
|||||||
|
import copy
|
||||||
from charmhelpers.core.hookenv import (
|
from charmhelpers.core.hookenv import (
|
||||||
config,
|
config,
|
||||||
|
log,
|
||||||
|
related_units,
|
||||||
|
relation_ids,
|
||||||
|
relation_get,
|
||||||
|
ERROR,
|
||||||
)
|
)
|
||||||
|
|
||||||
PACKAGES = []
|
BASE_PACKAGES = [
|
||||||
|
'nova-compute',
|
||||||
|
'genisoimage', # was missing as a package dependency until raring.
|
||||||
|
]
|
||||||
|
|
||||||
RESTART_MAP = {
|
BASE_RESTART_MAP = {
|
||||||
'/etc/libvirt/qemu.conf': ['libvirt-bin'],
|
'/etc/libvirt/qemu.conf': ['libvirt-bin'],
|
||||||
'/etc/default/libvirt-bin': ['libvirt-bin']
|
'/etc/default/libvirt-bin': ['libvirt-bin'],
|
||||||
|
'/etc/nova/nova.conf': ['nova-compute'],
|
||||||
|
'/etc/nova/nova-compute.conf': ['nova-compute'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QUANTUM_PLUGINS = {
|
||||||
|
'ovs': {
|
||||||
|
'config': '/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini',
|
||||||
|
'services': ['quantum-plugin-openvswitch-agent'],
|
||||||
|
'packages': ['quantum-plugin-openvswitch-agent',
|
||||||
|
'openvswitch-datapath-dkms'],
|
||||||
|
},
|
||||||
|
'nvp': {
|
||||||
|
'config': '/etc/quantum/plugins/nicira/nvp.ini',
|
||||||
|
'services': [],
|
||||||
|
'packages': ['quantum-plugin-nicira'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Maps virt-type config to a compute package(s).
|
||||||
|
VIRT_TYPES = {
|
||||||
|
'kvm': ['nova-compute-kvm'],
|
||||||
|
'qemu': ['nova-compute-qemu'],
|
||||||
|
'xen': ['nova-compute-xen'],
|
||||||
|
'uml': ['nova-compute-uml'],
|
||||||
|
'lxc': ['nova-compute-lxc'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# This is just a label and it must be consistent across
|
# This is just a label and it must be consistent across
|
||||||
@ -14,6 +49,58 @@ RESTART_MAP = {
|
|||||||
CEPH_SECRET_UUID = '514c9fca-8cbe-11e2-9c52-3bc8c7819472'
|
CEPH_SECRET_UUID = '514c9fca-8cbe-11e2-9c52-3bc8c7819472'
|
||||||
|
|
||||||
|
|
||||||
|
def restart_map():
|
||||||
|
'''
|
||||||
|
Constructs a restart map based on charm config settings and relation
|
||||||
|
state.
|
||||||
|
'''
|
||||||
|
_restart_map = copy.copy(BASE_RESTART_MAP)
|
||||||
|
|
||||||
|
net_manager = network_manager()
|
||||||
|
|
||||||
|
if (net_manager in ['FlatManager', 'FlatDHCPManager'] and
|
||||||
|
config('multi-host').lower() == 'yes'):
|
||||||
|
_restart_map['/etc/nova/nova.conf'].extend(
|
||||||
|
['nova-api', 'nova-network']
|
||||||
|
)
|
||||||
|
elif net_manager == 'Quantum':
|
||||||
|
plugin = quantum_plugin()
|
||||||
|
if plugin:
|
||||||
|
conf = quantum_attribute(plugin, 'config')
|
||||||
|
svcs = quantum_attribute(plugin, 'services')
|
||||||
|
_restart_map[conf] = svcs
|
||||||
|
_restart_map['/etc/quantum/quantum.conf'] = svcs
|
||||||
|
return _restart_map
|
||||||
|
|
||||||
|
|
||||||
|
def determine_packages():
|
||||||
|
packages = [] + BASE_PACKAGES
|
||||||
|
|
||||||
|
net_manager = network_manager()
|
||||||
|
if (net_manager in ['FlatManager', 'FlatDHCPManager'] and
|
||||||
|
config('multi-host').lower() == 'yes'):
|
||||||
|
packages.extend(['nova-api', 'nova-network'])
|
||||||
|
elif net_manager == 'Quantum':
|
||||||
|
plugin = quantum_plugin()
|
||||||
|
packages.extend(quantum_attribute(plugin, 'packages'))
|
||||||
|
|
||||||
|
if relation_ids('ceph'):
|
||||||
|
packages.append('ceph-common')
|
||||||
|
|
||||||
|
virt_type = config('virt-type')
|
||||||
|
try:
|
||||||
|
packages.extend(VIRT_TYPES[virt_type])
|
||||||
|
except KeyError:
|
||||||
|
log('Unsupported virt-type configured: %s' % virt_type)
|
||||||
|
|
||||||
|
raise
|
||||||
|
return packages
|
||||||
|
|
||||||
|
|
||||||
|
def register_configs():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def migration_enabled():
|
def migration_enabled():
|
||||||
return config('enable-live-migration').lower() == 'true'
|
return config('enable-live-migration').lower() == 'true'
|
||||||
|
|
||||||
@ -22,8 +109,37 @@ def quantum_enabled():
|
|||||||
return config('network-manager').lower() == 'quantum'
|
return config('network-manager').lower() == 'quantum'
|
||||||
|
|
||||||
|
|
||||||
def quantum_plugin_config():
|
def _network_config():
|
||||||
pass
|
'''
|
||||||
|
Obtain all relevant network configuration settings from nova-c-c via
|
||||||
|
cloud-compute interface.
|
||||||
|
'''
|
||||||
|
settings = ['network_manager', 'quantum_plugin']
|
||||||
|
net_config = {}
|
||||||
|
for rid in relation_ids('cloud-compute'):
|
||||||
|
for unit in related_units(rid):
|
||||||
|
for setting in settings:
|
||||||
|
value = relation_get(setting, rid=rid, unit=unit)
|
||||||
|
if value:
|
||||||
|
net_config[setting] = value
|
||||||
|
return net_config
|
||||||
|
|
||||||
|
|
||||||
|
def quantum_plugin():
|
||||||
|
return _network_config().get('quantum_plugin')
|
||||||
|
|
||||||
|
|
||||||
|
def network_manager():
|
||||||
|
return _network_config().get('network_manager')
|
||||||
|
|
||||||
|
|
||||||
|
def quantum_attribute(plugin, attr):
|
||||||
|
try:
|
||||||
|
_plugin = QUANTUM_PLUGINS[plugin]
|
||||||
|
except KeyError:
|
||||||
|
log('Unrecognised plugin for quantum: %s' % plugin, level=ERROR)
|
||||||
|
raise
|
||||||
|
return _plugin[attr]
|
||||||
|
|
||||||
|
|
||||||
def public_ssh_key(user='root'):
|
def public_ssh_key(user='root'):
|
||||||
@ -59,10 +175,6 @@ def do_openstack_upgrade():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def register_configs():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def import_keystone_ca_cert():
|
def import_keystone_ca_cert():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
257
tests/test_nova_compute_relations.py
Normal file
257
tests/test_nova_compute_relations.py
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
from mock import call, patch, MagicMock
|
||||||
|
|
||||||
|
from tests.test_utils import CharmTestCase
|
||||||
|
|
||||||
|
import hooks.nova_compute_utils as utils
|
||||||
|
|
||||||
|
_reg = utils.register_configs
|
||||||
|
_map = utils.restart_map
|
||||||
|
|
||||||
|
utils.register_configs = MagicMock()
|
||||||
|
utils.restart_map = MagicMock()
|
||||||
|
|
||||||
|
import hooks.nova_compute_relations as relations
|
||||||
|
|
||||||
|
utils.register_configs = _reg
|
||||||
|
utils.restart_map = _map
|
||||||
|
|
||||||
|
TO_PATCH = [
|
||||||
|
# charmhelpers.core.hookenv
|
||||||
|
'Hooks',
|
||||||
|
'config',
|
||||||
|
'log',
|
||||||
|
'relation_ids',
|
||||||
|
'relation_set',
|
||||||
|
'service_name',
|
||||||
|
'unit_get',
|
||||||
|
# charmhelpers.core.host
|
||||||
|
'apt_install',
|
||||||
|
'apt_update',
|
||||||
|
'restart_on_change',
|
||||||
|
#charmhelpers.contrib.openstack.utils
|
||||||
|
'configure_installation_source',
|
||||||
|
'openstack_upgrade_available',
|
||||||
|
# nova_compute_utils
|
||||||
|
#'PACKAGES',
|
||||||
|
'restart_map',
|
||||||
|
'determine_packages',
|
||||||
|
'import_authorized_keys',
|
||||||
|
'import_keystone_ca_cert',
|
||||||
|
'migration_enabled',
|
||||||
|
'configure_live_migration',
|
||||||
|
'configure_network_service',
|
||||||
|
'configure_volume_service',
|
||||||
|
'do_openstack_upgrade',
|
||||||
|
'quantum_attribute',
|
||||||
|
'quantum_enabled',
|
||||||
|
'quantum_plugin',
|
||||||
|
'public_ssh_key',
|
||||||
|
'register_configs',
|
||||||
|
# misc_utils
|
||||||
|
'ensure_ceph_keyring',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class NovaComputeRelationsTests(CharmTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(NovaComputeRelationsTests, self).setUp(relations,
|
||||||
|
TO_PATCH)
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
|
||||||
|
def test_install_hook(self):
|
||||||
|
repo = 'cloud:precise-grizzly'
|
||||||
|
self.test_config.set('openstack-origin', repo)
|
||||||
|
self.determine_packages.return_value = ['foo', 'bar']
|
||||||
|
relations.install()
|
||||||
|
self.configure_installation_source.assert_called_with(repo)
|
||||||
|
self.assertTrue(self.apt_update.called)
|
||||||
|
self.apt_install.assert_called_with(['foo', 'bar'], fatal=True)
|
||||||
|
|
||||||
|
def test_config_changed_with_upgrade(self):
|
||||||
|
self.openstack_upgrade_available.return_value = True
|
||||||
|
relations.config_changed()
|
||||||
|
self.assertTrue(self.do_openstack_upgrade.called)
|
||||||
|
|
||||||
|
@patch.object(relations, 'compute_joined')
|
||||||
|
def test_config_changed_with_migration(self, compute_joined):
|
||||||
|
self.migration_enabled.return_value = True
|
||||||
|
self.test_config.set('migration-auth-type', 'ssh')
|
||||||
|
self.relation_ids.return_value = [
|
||||||
|
'cloud-compute:0',
|
||||||
|
'cloud-compute:1'
|
||||||
|
]
|
||||||
|
relations.config_changed()
|
||||||
|
ex = [
|
||||||
|
call('cloud-compute:0'),
|
||||||
|
call('cloud-compute:1'),
|
||||||
|
]
|
||||||
|
self.assertEquals(ex, compute_joined.call_args_list)
|
||||||
|
|
||||||
|
@patch.object(relations, 'compute_joined')
|
||||||
|
def test_config_changed_no_upgrade_no_migration(self, compute_joined):
|
||||||
|
self.openstack_upgrade_available.return_value = False
|
||||||
|
self.migration_enabled.return_value = False
|
||||||
|
relations.config_changed()
|
||||||
|
self.assertFalse(self.do_openstack_upgrade.called)
|
||||||
|
self.assertTrue(self.configure_live_migration)
|
||||||
|
self.assertFalse(compute_joined.called)
|
||||||
|
|
||||||
|
def test_amqp_joined(self):
|
||||||
|
relations.amqp_joined()
|
||||||
|
self.relation_set.assert_called_with(username='nova', vhost='nova')
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_amqp_changed_missing_relation_data(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = []
|
||||||
|
relations.amqp_changed()
|
||||||
|
self.log.assert_called_with(
|
||||||
|
'amqp relation incomplete. Peer not ready?'
|
||||||
|
)
|
||||||
|
|
||||||
|
def _amqp_test(self, configs, quantum=False):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = ['amqp']
|
||||||
|
configs.write = MagicMock()
|
||||||
|
self.quantum_enabled.return_value = quantum
|
||||||
|
relations.amqp_changed()
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_amqp_changed_with_data_no_quantum(self, configs):
|
||||||
|
self._amqp_test(configs, quantum=False)
|
||||||
|
self.assertEquals([call('/etc/nova/nova.conf')],
|
||||||
|
configs.write.call_args_list)
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_amqp_changed_with_data_and_quantum(self, configs):
|
||||||
|
self._amqp_test(configs, quantum=True)
|
||||||
|
self.assertEquals([call('/etc/nova/nova.conf'),
|
||||||
|
call('/etc/quantum/quantum.conf')],
|
||||||
|
configs.write.call_args_list)
|
||||||
|
|
||||||
|
def test_db_joined(self):
|
||||||
|
self.unit_get.return_value = 'nova.foohost.com'
|
||||||
|
relations.db_joined()
|
||||||
|
self.relation_set.assert_called_with(database='nova', username='nova',
|
||||||
|
hostname='nova.foohost.com')
|
||||||
|
self.unit_get.assert_called_with('private-address')
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_db_changed_missing_relation_data(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = []
|
||||||
|
relations.db_changed()
|
||||||
|
self.log.assert_called_with(
|
||||||
|
'shared-db relation incomplete. Peer not ready?'
|
||||||
|
)
|
||||||
|
|
||||||
|
def _shared_db_test(self, configs, quantum=False):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = ['shared-db']
|
||||||
|
configs.write = MagicMock()
|
||||||
|
self.quantum_enabled.return_value = quantum
|
||||||
|
relations.db_changed()
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_db_changed_with_data_no_quantum(self, configs):
|
||||||
|
self._shared_db_test(configs, quantum=False)
|
||||||
|
self.assertEquals([call('/etc/nova/nova.conf')],
|
||||||
|
configs.write.call_args_list)
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_db_changed_with_data_and_quantum(self, configs):
|
||||||
|
self.quantum_attribute.return_value = '/etc/quantum/plugin.conf'
|
||||||
|
self._shared_db_test(configs, quantum=True)
|
||||||
|
ex = [call('/etc/nova/nova.conf'), call('/etc/quantum/plugin.conf')]
|
||||||
|
self.assertEquals(ex, configs.write.call_args_list)
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_image_service_missing_relation_data(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = []
|
||||||
|
relations.image_service_changed()
|
||||||
|
self.log.assert_called_with(
|
||||||
|
'image-service relation incomplete. Peer not ready?'
|
||||||
|
)
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_image_service_with_relation_data(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.write = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = ['image-service']
|
||||||
|
relations.image_service_changed()
|
||||||
|
configs.write.assert_called_with('/etc/nova/nova.conf')
|
||||||
|
|
||||||
|
def test_compute_joined_no_migration(self):
|
||||||
|
self.migration_enabled.return_value = False
|
||||||
|
relations.compute_joined()
|
||||||
|
self.assertFalse(self.relation_set.called)
|
||||||
|
|
||||||
|
def test_compute_joined_with_ssh_migration(self):
|
||||||
|
self.migration_enabled.return_value = True
|
||||||
|
self.test_config.set('migration-auth-type', 'ssh')
|
||||||
|
self.public_ssh_key.return_value = 'foo'
|
||||||
|
relations.compute_joined()
|
||||||
|
self.relation_set.assert_called_with(
|
||||||
|
relation_id=None,
|
||||||
|
ssh_public_key='foo',
|
||||||
|
migration_auth_type='ssh'
|
||||||
|
)
|
||||||
|
relations.compute_joined(rid='cloud-compute:2')
|
||||||
|
self.relation_set.assert_called_with(
|
||||||
|
relation_id='cloud-compute:2',
|
||||||
|
ssh_public_key='foo',
|
||||||
|
migration_auth_type='ssh'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_compute_changed(self):
|
||||||
|
relations.compute_changed()
|
||||||
|
expected_funcs = [
|
||||||
|
self.configure_network_service,
|
||||||
|
self.configure_volume_service,
|
||||||
|
self.import_authorized_keys,
|
||||||
|
self.import_keystone_ca_cert,
|
||||||
|
]
|
||||||
|
for func in expected_funcs:
|
||||||
|
self.assertTrue(func.called)
|
||||||
|
|
||||||
|
@patch('os.mkdir')
|
||||||
|
@patch('os.path.isdir')
|
||||||
|
def test_ceph_joined(self, isdir, mkdir):
|
||||||
|
isdir.return_value = False
|
||||||
|
relations.ceph_joined()
|
||||||
|
mkdir.assert_called_with('/etc/ceph')
|
||||||
|
self.apt_install.assert_called_with('ceph-common')
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_ceph_changed_missing_relation_data(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = []
|
||||||
|
relations.ceph_changed()
|
||||||
|
self.log.assert_called_with(
|
||||||
|
'ceph relation incomplete. Peer not ready?'
|
||||||
|
)
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_ceph_changed_no_keyring(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = ['ceph']
|
||||||
|
self.ensure_ceph_keyring.return_value = False
|
||||||
|
relations.ceph_changed()
|
||||||
|
self.log.assert_called_with(
|
||||||
|
'Could not create ceph keyring: peer not ready?'
|
||||||
|
)
|
||||||
|
|
||||||
|
@patch.object(relations, 'CONFIGS')
|
||||||
|
def test_ceph_changed_with_key_and_relation_data(self, configs):
|
||||||
|
configs.complete_contexts = MagicMock()
|
||||||
|
configs.complete_contexts.return_value = ['ceph']
|
||||||
|
configs.write = MagicMock()
|
||||||
|
self.ensure_ceph_keyring.return_value = True
|
||||||
|
relations.ceph_changed()
|
||||||
|
ex = [
|
||||||
|
call('/etc/ceph/ceph.conf'),
|
||||||
|
call('/etc/ceph/secret.xml'),
|
||||||
|
call('/etc/nova/nova.conf'),
|
||||||
|
]
|
||||||
|
self.assertEquals(ex, configs.write.call_args_list)
|
105
tests/test_nova_compute_utils.py
Normal file
105
tests/test_nova_compute_utils.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
from mock import patch
|
||||||
|
|
||||||
|
from tests.test_utils import CharmTestCase
|
||||||
|
|
||||||
|
|
||||||
|
import hooks.nova_compute_utils as utils
|
||||||
|
|
||||||
|
TO_PATCH = [
|
||||||
|
'config',
|
||||||
|
'log',
|
||||||
|
'related_units',
|
||||||
|
'relation_ids',
|
||||||
|
'relation_get',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class NovaComputeUtilsTests(CharmTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(NovaComputeUtilsTests, self).setUp(utils, TO_PATCH)
|
||||||
|
self.config.side_effect = self.test_config.get
|
||||||
|
|
||||||
|
@patch.object(utils, 'network_manager')
|
||||||
|
def test_determine_packages_nova_network(self, net_man):
|
||||||
|
net_man.return_value = 'FlatDHCPManager'
|
||||||
|
self.relation_ids.return_value = []
|
||||||
|
result = utils.determine_packages()
|
||||||
|
ex = utils.BASE_PACKAGES + [
|
||||||
|
'nova-api',
|
||||||
|
'nova-network',
|
||||||
|
'nova-compute-kvm'
|
||||||
|
]
|
||||||
|
self.assertEquals(ex, result)
|
||||||
|
|
||||||
|
@patch.object(utils, 'quantum_plugin')
|
||||||
|
@patch.object(utils, 'network_manager')
|
||||||
|
def test_determine_packages_quantum(self, net_man, q_plugin):
|
||||||
|
net_man.return_value = 'Quantum'
|
||||||
|
q_plugin.return_value = 'ovs'
|
||||||
|
self.relation_ids.return_value = []
|
||||||
|
result = utils.determine_packages()
|
||||||
|
ex = utils.BASE_PACKAGES + [
|
||||||
|
'quantum-plugin-openvswitch-agent',
|
||||||
|
'openvswitch-datapath-dkms',
|
||||||
|
'nova-compute-kvm'
|
||||||
|
]
|
||||||
|
self.assertEquals(ex, result)
|
||||||
|
|
||||||
|
@patch.object(utils, 'quantum_plugin')
|
||||||
|
@patch.object(utils, 'network_manager')
|
||||||
|
def test_determine_packages_quantum_ceph(self, net_man, q_plugin):
|
||||||
|
net_man.return_value = 'Quantum'
|
||||||
|
q_plugin.return_value = 'ovs'
|
||||||
|
self.relation_ids.return_value = ['ceph:0']
|
||||||
|
result = utils.determine_packages()
|
||||||
|
ex = utils.BASE_PACKAGES + [
|
||||||
|
'quantum-plugin-openvswitch-agent',
|
||||||
|
'openvswitch-datapath-dkms',
|
||||||
|
'ceph-common',
|
||||||
|
'nova-compute-kvm'
|
||||||
|
]
|
||||||
|
self.assertEquals(ex, result)
|
||||||
|
|
||||||
|
# NOTE: These tests faill if run together, something is holding
|
||||||
|
# a reference to BASE_RESOURCE_MAP ?
|
||||||
|
@patch.object(utils, 'network_manager')
|
||||||
|
def test_resource_map_nova_network_no_multihost(self, net_man):
|
||||||
|
self.test_config.set('multi-host', 'no')
|
||||||
|
net_man.return_value = 'FlatDHCPManager'
|
||||||
|
result = utils.restart_map()
|
||||||
|
ex = {
|
||||||
|
'/etc/default/libvirt-bin': ['libvirt-bin'],
|
||||||
|
'/etc/libvirt/qemu.conf': ['libvirt-bin'],
|
||||||
|
'/etc/nova/nova-compute.conf': ['nova-compute'],
|
||||||
|
'/etc/nova/nova.conf': ['nova-compute']
|
||||||
|
}
|
||||||
|
self.assertEquals(ex, result)
|
||||||
|
|
||||||
|
@patch.object(utils, 'network_manager')
|
||||||
|
def test_resource_map_nova_network(self, net_man):
|
||||||
|
net_man.return_value = 'FlatDHCPManager'
|
||||||
|
result = utils.restart_map()
|
||||||
|
ex = {
|
||||||
|
'/etc/default/libvirt-bin': ['libvirt-bin'],
|
||||||
|
'/etc/libvirt/qemu.conf': ['libvirt-bin'],
|
||||||
|
'/etc/nova/nova-compute.conf': ['nova-compute'],
|
||||||
|
'/etc/nova/nova.conf': ['nova-compute', 'nova-api', 'nova-network']
|
||||||
|
}
|
||||||
|
self.assertEquals(ex, result)
|
||||||
|
|
||||||
|
@patch.object(utils, 'quantum_plugin')
|
||||||
|
@patch.object(utils, 'network_manager')
|
||||||
|
def test_resource_map_quantum_ovs(self, net_man, _plugin):
|
||||||
|
net_man.return_value = 'Quantum'
|
||||||
|
_plugin.return_value = 'ovs'
|
||||||
|
result = utils.restart_map()
|
||||||
|
ex = {
|
||||||
|
'/etc/default/libvirt-bin': ['libvirt-bin'],
|
||||||
|
'/etc/libvirt/qemu.conf': ['libvirt-bin'],
|
||||||
|
'/etc/nova/nova-compute.conf': ['nova-compute'],
|
||||||
|
'/etc/nova/nova.conf': ['nova-compute'],
|
||||||
|
'/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini':
|
||||||
|
['quantum-plugin-openvswitch-agent'],
|
||||||
|
'/etc/quantum/quantum.conf': ['quantum-plugin-openvswitch-agent']
|
||||||
|
}
|
||||||
|
self.assertEquals(ex, result)
|
101
tests/test_utils.py
Normal file
101
tests/test_utils.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import logging
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
def load_config():
|
||||||
|
'''
|
||||||
|
Walk backwords from __file__ looking for config.yaml, load and return the
|
||||||
|
'options' section'
|
||||||
|
'''
|
||||||
|
config = None
|
||||||
|
f = __file__
|
||||||
|
while config is None:
|
||||||
|
d = os.path.dirname(f)
|
||||||
|
if os.path.isfile(os.path.join(d, 'config.yaml')):
|
||||||
|
config = os.path.join(d, 'config.yaml')
|
||||||
|
break
|
||||||
|
f = d
|
||||||
|
|
||||||
|
if not config:
|
||||||
|
logging.error('Could not find config.yaml in any parent directory '
|
||||||
|
'of %s. ' % file)
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
return yaml.safe_load(open(config).read())['options']
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_config():
|
||||||
|
'''
|
||||||
|
Load default charm config from config.yaml return as a dict.
|
||||||
|
If no default is set in config.yaml, its value is None.
|
||||||
|
'''
|
||||||
|
default_config = {}
|
||||||
|
config = load_config()
|
||||||
|
for k, v in config.iteritems():
|
||||||
|
if 'default' in v:
|
||||||
|
default_config[k] = v['default']
|
||||||
|
else:
|
||||||
|
default_config[k] = None
|
||||||
|
return default_config
|
||||||
|
|
||||||
|
|
||||||
|
class CharmTestCase(unittest.TestCase):
|
||||||
|
def setUp(self, obj, patches):
|
||||||
|
super(CharmTestCase, self).setUp()
|
||||||
|
self.patches = patches
|
||||||
|
self.obj = obj
|
||||||
|
self.test_config = TestConfig()
|
||||||
|
self.test_relation = TestRelation()
|
||||||
|
self.patch_all()
|
||||||
|
|
||||||
|
def patch(self, method):
|
||||||
|
_m = patch.object(self.obj, method)
|
||||||
|
mock = _m.start()
|
||||||
|
self.addCleanup(_m.stop)
|
||||||
|
return mock
|
||||||
|
|
||||||
|
def patch_all(self):
|
||||||
|
for method in self.patches:
|
||||||
|
setattr(self, method, self.patch(method))
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfig(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.config = get_default_config()
|
||||||
|
|
||||||
|
def get(self, attr=None):
|
||||||
|
if not attr:
|
||||||
|
return self.get_all()
|
||||||
|
try:
|
||||||
|
return self.config[attr]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_all(self):
|
||||||
|
return self.config
|
||||||
|
|
||||||
|
def set(self, attr, value):
|
||||||
|
if attr not in self.config:
|
||||||
|
raise KeyError
|
||||||
|
self.config[attr] = value
|
||||||
|
|
||||||
|
|
||||||
|
class TestRelation(object):
|
||||||
|
def __init__(self, relation_data={}):
|
||||||
|
self.relation_data = relation_data
|
||||||
|
|
||||||
|
def set(self, relation_data):
|
||||||
|
self.relation_data = relation_data
|
||||||
|
|
||||||
|
def get(self, attr=None, unit=None, rid=None):
|
||||||
|
if attr == None:
|
||||||
|
return self.relation_data
|
||||||
|
elif attr in self.relation_data:
|
||||||
|
return self.relation_data[attr]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user