Rework the default handlers into layer-openstack-*
Due to commit 95493a4 in charms.reactive, the default handlers in charms.openstack broke. This is because charms.reactive no longer will run handlers that are not in the hooks/ or reactive/ directory tree; the default handlers in charms.openstack are in the library code, which is pip installed into the module packages. This patch, and related patches in layer-openstack and layer-openstack-api enable the default handlers to function again. Note that from a charm author perspective, the API to default handlers is identical. This is merely an implementation change. Change-Id: I7786a39ab29ab71a4cdb8bd652e8927cbd5fcf5c Partial-Bug: #1707685
This commit is contained in:
parent
03ba9967c3
commit
698337c5ee
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue