diff --git a/charms_openstack/charm/defaults.py b/charms_openstack/charm/defaults.py index c425cd3..57f6a2c 100644 --- a/charms_openstack/charm/defaults.py +++ b/charms_openstack/charm/defaults.py @@ -1,5 +1,4 @@ import charmhelpers.contrib.openstack.utils as os_utils -import charmhelpers.core.hookenv as hookenv import charmhelpers.core.unitdata as unitdata import charms.reactive as reactive @@ -69,20 +68,12 @@ def _map_default_handler(state): @_map_default_handler('charm.installed') def make_default_install_handler(): - - @reactive.when_not('charm.installed') - def default_install(): - """Provide a default install handler - - The instance automagically becomes the derived OpenStackCharm instance. - The kv() key charmers.openstack-release-version' is used to cache the - release being used for this charm. It is determined by the - default_select_release() function below, unless this is overriden by - the charm author - """ - unitdata.kv().unset(OPENSTACK_RELEASE_KEY) - OpenStackCharm.singleton.install() - reactive.set_state('charm.installed') + """Set the default charm.installed state so that the default handler in + layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state('charms.openstack.do-default-charm.installed') @_map_default_handler('charm.default-select-release') @@ -109,94 +100,64 @@ def make_default_select_release_handler(): @_map_default_handler('amqp.connected') def make_default_amqp_connection_handler(): - - @reactive.when('amqp.connected') - def default_amqp_connection(amqp): - """Handle the default amqp connection. - - This requires that the charm implements get_amqp_credentials() to - provide a tuple of the (user, vhost) for the amqp server - """ - instance = OpenStackCharm.singleton - user, vhost = instance.get_amqp_credentials() - amqp.request_access(username=user, vhost=vhost) - instance.assess_status() + """Set the default amqp.connected state so that the default handler in + layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state('charms.openstack.do-default-amqp.connected') @_map_default_handler('shared-db.connected') def make_default_setup_database_handler(): - - @reactive.when('shared-db.connected') - def default_setup_database(database): - """Handle the default database connection setup - - This requires that the charm implements get_database_setup() to provide - a list of dictionaries; - [{'database': ..., 'username': ..., 'hostname': ..., 'prefix': ...}] - - The prefix can be missing: it defaults to None. - """ - instance = OpenStackCharm.singleton - for db in instance.get_database_setup(): - database.configure(**db) - instance.assess_status() + """Set the default shared-db.connected state so that the default handler in + layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state('charms.openstack.do-default-shared-db.connected') @_map_default_handler('identity-service.connected') def make_default_setup_endpoint_connection(): - - @reactive.when('identity-service.connected') - def default_setup_endpoint_connection(keystone): - """When the keystone interface connects, register this unit into the - catalog. This is the default handler, and calls on the charm class to - provide the endpoint information. If multiple endpoints are needed, - then a custom endpoint handler will be needed. - """ - instance = OpenStackCharm.singleton - keystone.register_endpoints(instance.service_type, - instance.region, - instance.public_url, - instance.internal_url, - instance.admin_url) - instance.assess_status() + """Set the default identity-service.connected state so that the default + handler in layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state( + 'charms.openstack.do-default-identity-service.connected') @_map_default_handler('identity-service.available') def make_setup_endpoint_available_handler(): - - @reactive.when('identity-service.available') - def default_setup_endpoint_available(keystone): - """When the identity-service interface is available, this default - handler switches on the SSL support. - """ - instance = OpenStackCharm.singleton - instance.configure_ssl(keystone) - instance.assess_status() + """Set the default identity-service.available state so that the default + handler in layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state( + 'charms.openstack.do-default-identity-service.available') @_map_default_handler('config.changed') def make_default_config_changed_handler(): - - @reactive.when('config.changed') - def default_config_changed(): - """Default handler for config.changed state from reactive. Just see if - our status has changed. This is just to clear any errors that may have - got stuck due to missing async handlers, etc. - """ - instance = OpenStackCharm.singleton - instance.config_changed() - instance.assess_status() + """Set the default config.changed state so that the default handler in + layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state('charms.openstack.do-default-config.changed') @_map_default_handler('upgrade-charm') def make_default_upgrade_charm_handler(): - - @reactive.hook('upgrade-charm') - def default_upgrade_charm(): - """Default handler for the 'upgrade-charm' hook. - This calls the charm.singleton.upgrade_charm() function as a default. - """ - OpenStackCharm.singleton.upgrade_charm() + """Set the default upgrade-charm state so that the default handler in + layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state('charms.openstack.do-default-upgrade-charm') def default_render_configs(*interfaces): @@ -214,12 +175,9 @@ def default_render_configs(*interfaces): @_map_default_handler('update-status') def make_default_update_status_handler(): - - @reactive.hook('update-status') - def default_update_status(): - """Default handler for update-status state. - Just call update status. - """ - instance = OpenStackCharm.singleton - hookenv.application_version_set(instance.application_version) - instance.assess_status() + """Set the default upgrade-status state so that the default handler in + layer-openstack can run. + Convoluted, because charms.reactive will only run handlers in the reactive + or hooks directory. + """ + reactive.set_state('charms.openstack.do-default-update-status') diff --git a/unit_tests/charms_openstack/charm/test_defaults.py b/unit_tests/charms_openstack/charm/test_defaults.py index f4421d6..033888b 100644 --- a/unit_tests/charms_openstack/charm/test_defaults.py +++ b/unit_tests/charms_openstack/charm/test_defaults.py @@ -86,22 +86,11 @@ class TestDefaults(BaseOpenStackCharmTest): def test_default_install_handler(self): self.assertIn('charm.installed', chm._default_handler_map) - self.patch_object(chm.reactive, 'when_not') - h = self.mock_decorator_gen() - self.when_not.side_effect = h.decorator - # call the default handler installer function, and check its map. + self.patch_object(chm.reactive, 'set_state') f = chm._default_handler_map['charm.installed'] f() - self.assertIn('charm.installed', h.map) - # verify that the installed function calls the charm installer - self.patch_object(chm, 'OpenStackCharm', name='charm') - kv = mock.MagicMock() - self.patch_object(chm.unitdata, 'kv', new=lambda: kv) - self.patch_object(chm.reactive, 'set_state') - h.map['charm.installed']() - kv.unset.assert_called_once_with(chm.OPENSTACK_RELEASE_KEY) - self.charm.singleton.install.assert_called_once_with() - self.set_state.assert_called_once_with('charm.installed') + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-charm.installed') def test_default_select_release_handler(self): self.assertIn('charm.default-select-release', chm._default_handler_map) @@ -133,116 +122,62 @@ class TestDefaults(BaseOpenStackCharmTest): def test_default_amqp_connection_handler(self): self.assertIn('amqp.connected', chm._default_handler_map) - self.patch_object(chm.reactive, 'when') - h = self.mock_decorator_gen() - self.when.side_effect = h.decorator + self.patch_object(chm.reactive, 'set_state') # call the default handler installer function, and check its map. f = chm._default_handler_map['amqp.connected'] f() - self.assertIn('amqp.connected', h.map) - # verify that the installed function works - self.patch_object(chm, 'OpenStackCharm', name='charm') - self.charm.singleton.get_amqp_credentials.return_value = \ - ('user', 'vhost') - amqp = mock.MagicMock() - h.map['amqp.connected'](amqp) - self.charm.singleton.get_amqp_credentials.assert_called_once_with() - amqp.request_access.assert_called_once_with(username='user', - vhost='vhost') - self.charm.singleton.assess_status.assert_called_once_with() + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-amqp.connected') def test_default_setup_datatbase_handler(self): self.assertIn('shared-db.connected', chm._default_handler_map) - self.patch_object(chm.reactive, 'when') - h = self.mock_decorator_gen() - self.when.side_effect = h.decorator + self.patch_object(chm.reactive, 'set_state') # call the default handler installer function, and check its map. f = chm._default_handler_map['shared-db.connected'] f() - self.assertIn('shared-db.connected', h.map) - # verify that the installed function works - self.patch_object(chm, 'OpenStackCharm', name='charm') - self.charm.singleton.get_database_setup.return_value = [ - {'database': 'configuration'}] - database = mock.MagicMock() - h.map['shared-db.connected'](database) - self.charm.singleton.get_database_setup.assert_called_once_with() - database.configure.assert_called_once_with(database='configuration') - self.charm.singleton.assess_status.assert_called_once_with() + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-shared-db.connected') def test_default_setup_endpoint_handler(self): self.assertIn('identity-service.connected', chm._default_handler_map) - self.patch_object(chm.reactive, 'when') - h = self.mock_decorator_gen() - self.when.side_effect = h.decorator - # call the default handler installer function, and check its map. + self.patch_object(chm.reactive, 'set_state') f = chm._default_handler_map['identity-service.connected'] f() - self.assertIn('identity-service.connected', h.map) - # verify that the installed function works - - OpenStackCharm = mock.MagicMock() - - class Instance(object): - service_type = 'type1' - region = 'region1' - public_url = 'public_url' - internal_url = 'internal_url' - admin_url = 'admin_url' - assess_status = mock.MagicMock() - - OpenStackCharm.singleton = Instance - with mock.patch.object(chm, 'OpenStackCharm', new=OpenStackCharm): - keystone = mock.MagicMock() - h.map['identity-service.connected'](keystone) - keystone.register_endpoints.assert_called_once_with( - 'type1', 'region1', 'public_url', 'internal_url', 'admin_url') - Instance.assess_status.assert_called_once_with() + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-identity-service.connected') def test_default_setup_endpoint_available_handler(self): self.assertIn('identity-service.available', chm._default_handler_map) - self.patch_object(chm.reactive, 'when') - h = self.mock_decorator_gen() - self.when.side_effect = h.decorator + self.patch_object(chm.reactive, 'set_state') # call the default handler installer function, and check its map. f = chm._default_handler_map['identity-service.available'] f() - self.assertIn('identity-service.available', h.map) - # verify that the installed function works - self.patch_object(chm, 'OpenStackCharm', name='charm') - h.map['identity-service.available']('keystone') - self.charm.singleton.configure_ssl.assert_called_once_with('keystone') - self.charm.singleton.assess_status.assert_called_once_with() + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-identity-service.available') def test_default_config_changed_handler(self): self.assertIn('config.changed', chm._default_handler_map) - self.patch_object(chm.reactive, 'when') - h = self.mock_decorator_gen() - self.when.side_effect = h.decorator - # call the default handler installer function, and check its map. + self.patch_object(chm.reactive, 'set_state') f = chm._default_handler_map['config.changed'] f() - self.assertIn('config.changed', h.map) - # verify that the installed function works - self.patch_object(chm, 'OpenStackCharm', name='charm') - h.map['config.changed']() - self.charm.singleton.assess_status.assert_called_once_with() + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-config.changed') def test_default_update_status_handler(self): self.assertIn('update-status', chm._default_handler_map) - self.patch_object(chm.reactive, 'hook') - h = self.mock_decorator_gen() - self.hook.side_effect = h.decorator - # call the default handler installer function, and check its map. + self.patch_object(chm.reactive, 'set_state') f = chm._default_handler_map['update-status'] f() - self.assertIn('update-status', h.map) - # verify that the installed function works - self.patch_object(chm, 'OpenStackCharm', name='charm') - self.patch_object(chm.hookenv, 'application_version_set') - h.map['update-status']() - self.charm.singleton.assess_status.assert_called_once_with() - self.application_version_set.assert_called_once_with(mock.ANY) + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-update-status') + + def test_default_upgrade_charm_handler(self): + self.assertIn('upgrade-charm', chm._default_handler_map) + self.patch_object(chm.reactive, 'set_state') + f = chm._default_handler_map['upgrade-charm'] + f() + self.set_state.assert_called_once_with( + 'charms.openstack.do-default-upgrade-charm') def test_default_render_configs(self): self.patch_object(chm, 'OpenStackCharm', name='charm')