diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index e8662b0f..d356d59d 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -780,11 +780,11 @@ def guard_map(): if relation_ids('pgsql-neutron-db'): neutron_interfaces.append('pgsql-neutron-db') else: - neutron_interfaces.append('shared-db') + neutron_interfaces.append('shared-db') if network_manager() == 'quantum': - gmap['quantum-server'] = neutron_interfaces + gmap['quantum-server'] = neutron_interfaces else: - gmap['neutron-server'] = neutron_interfaces + gmap['neutron-server'] = neutron_interfaces return gmap @@ -802,9 +802,10 @@ def service_guard(guard_map, contexts, active=False): incomplete_services.append(svc) f(*args) for svc in incomplete_services: - if service_running(svc): - log('Service {} has unfulfilled interface requirements, stopping.'.format(svc)) - service_stop(svc) + if service_running(svc): + log('Service {} has unfulfilled ' + 'interface requirements, stopping.'.format(svc)) + service_stop(svc) else: f(*args) return wrapped_f diff --git a/unit_tests/test_nova_cc_hooks.py b/unit_tests/test_nova_cc_hooks.py index f4c0b7df..d5696e36 100644 --- a/unit_tests/test_nova_cc_hooks.py +++ b/unit_tests/test_nova_cc_hooks.py @@ -11,7 +11,11 @@ _map = utils.restart_map utils.register_configs = MagicMock() utils.restart_map = MagicMock() -import nova_cc_hooks as hooks +with patch('nova_cc_utils.guard_map') as gmap: + with patch('charmhelpers.core.hookenv.config') as config: + config.return_value = False + gmap.return_value = {} + import nova_cc_hooks as hooks utils.register_configs = _reg utils.restart_map = _map diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index 45e764f7..4573f5be 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -35,7 +35,9 @@ TO_PATCH = [ 'remote_unit', '_save_script_rc', 'service_start', - 'services' + 'services', + 'service_running', + 'service_stop' ] SCRIPTRC_ENV_VARS = { @@ -596,3 +598,113 @@ class NovaCCUtilsTests(CharmTestCase): utils.do_openstack_upgrade() expected = [call('cloud:precise-icehouse')] self.assertEquals(_do_openstack_upgrade.call_args_list, expected) + + def test_guard_map_nova(self): + self.relation_ids.return_value = [] + self.os_release.return_value = 'havana' + self.assertEqual( + {'nova-api-ec2': ['identity-service', 'amqp', 'shared-db'], + 'nova-api-os-compute': ['identity-service', 'amqp', 'shared-db'], + 'nova-cert': ['identity-service', 'amqp', 'shared-db'], + 'nova-conductor': ['identity-service', 'amqp', 'shared-db'], + 'nova-objectstore': ['identity-service', 'amqp', 'shared-db'], + 'nova-scheduler': ['identity-service', 'amqp', 'shared-db']}, + utils.guard_map() + ) + self.os_release.return_value = 'essex' + self.assertEqual( + {'nova-api-ec2': ['identity-service', 'amqp', 'shared-db'], + 'nova-api-os-compute': ['identity-service', 'amqp', 'shared-db'], + 'nova-cert': ['identity-service', 'amqp', 'shared-db'], + 'nova-objectstore': ['identity-service', 'amqp', 'shared-db'], + 'nova-scheduler': ['identity-service', 'amqp', 'shared-db']}, + utils.guard_map() + ) + + def test_guard_map_neutron(self): + self.relation_ids.return_value = [] + self.network_manager.return_value = 'neutron' + self.os_release.return_value = 'icehouse' + self.assertEqual( + {'neutron-server': ['identity-service', 'amqp', 'shared-db'], + 'nova-api-ec2': ['identity-service', 'amqp', 'shared-db'], + 'nova-api-os-compute': ['identity-service', 'amqp', 'shared-db'], + 'nova-cert': ['identity-service', 'amqp', 'shared-db'], + 'nova-conductor': ['identity-service', 'amqp', 'shared-db'], + 'nova-objectstore': ['identity-service', 'amqp', 'shared-db'], + 'nova-scheduler': ['identity-service', 'amqp', 'shared-db'], }, + utils.guard_map() + ) + self.network_manager.return_value = 'quantum' + self.os_release.return_value = 'grizzly' + self.assertEqual( + {'quantum-server': ['identity-service', 'amqp', 'shared-db'], + 'nova-api-ec2': ['identity-service', 'amqp', 'shared-db'], + 'nova-api-os-compute': ['identity-service', 'amqp', 'shared-db'], + 'nova-cert': ['identity-service', 'amqp', 'shared-db'], + 'nova-conductor': ['identity-service', 'amqp', 'shared-db'], + 'nova-objectstore': ['identity-service', 'amqp', 'shared-db'], + 'nova-scheduler': ['identity-service', 'amqp', 'shared-db'], }, + utils.guard_map() + ) + + def test_guard_map_pgsql(self): + self.relation_ids.return_value = ['pgsql:1'] + self.network_manager.return_value = 'neutron' + self.os_release.return_value = 'icehouse' + self.assertEqual( + {'neutron-server': ['identity-service', 'amqp', + 'pgsql-neutron-db'], + 'nova-api-ec2': ['identity-service', 'amqp', 'pgsql-nova-db'], + 'nova-api-os-compute': ['identity-service', 'amqp', + 'pgsql-nova-db'], + 'nova-cert': ['identity-service', 'amqp', 'pgsql-nova-db'], + 'nova-conductor': ['identity-service', 'amqp', 'pgsql-nova-db'], + 'nova-objectstore': ['identity-service', 'amqp', + 'pgsql-nova-db'], + 'nova-scheduler': ['identity-service', 'amqp', + 'pgsql-nova-db'], }, + utils.guard_map() + ) + + def test_service_guard_inactive(self): + '''Ensure that if disabled, service guards nothing''' + contexts = MagicMock() + + @utils.service_guard({'test': ['interfacea', 'interfaceb']}, + contexts, False) + def dummy_func(): + pass + dummy_func() + self.assertFalse(self.service_running.called) + self.assertFalse(contexts.complete_contexts.called) + + def test_service_guard_active_guard(self): + '''Ensure services with incomplete interfaces are stopped''' + contexts = MagicMock() + contexts.complete_contexts.return_value = ['interfacea'] + self.service_running.return_value = True + + @utils.service_guard({'test': ['interfacea', 'interfaceb']}, + contexts, True) + def dummy_func(): + pass + dummy_func() + self.service_running.assert_called_with('test') + self.service_stop.assert_called_with('test') + self.assertTrue(contexts.complete_contexts.called) + + def test_service_guard_active_release(self): + '''Ensure services with complete interfaces are not stopped''' + contexts = MagicMock() + contexts.complete_contexts.return_value = ['interfacea', + 'interfaceb'] + + @utils.service_guard({'test': ['interfacea', 'interfaceb']}, + contexts, True) + def dummy_func(): + pass + dummy_func() + self.assertFalse(self.service_running.called) + self.assertFalse(self.service_stop.called) + self.assertTrue(contexts.complete_contexts.called) diff --git a/unit_tests/test_utils.py b/unit_tests/test_utils.py index c9c7bace..a59f8970 100644 --- a/unit_tests/test_utils.py +++ b/unit_tests/test_utils.py @@ -82,9 +82,9 @@ class TestConfig(object): return self.config def set(self, attr, value): - if attr not in self.config: - raise KeyError - self.config[attr] = value + if attr not in self.config: + raise KeyError + self.config[attr] = value class TestRelation(object):