From d9f2fab0bb7e4614ce506d2fcd480dce9f125e07 Mon Sep 17 00:00:00 2001 From: James Page Date: Tue, 1 Apr 2014 17:53:45 +0100 Subject: [PATCH] Add upgrade support --- hooks/ceilometer_hooks.py | 13 ++++++- hooks/ceilometer_utils.py | 37 ++++++++++++++++++- .../charmhelpers/contrib/openstack/context.py | 32 +++++++++++++++- hooks/config-changed | 1 + unit_tests/test_ceilometer_hooks.py | 18 +++++++++ unit_tests/test_ceilometer_utils.py | 30 ++++++++++++++- 6 files changed, 126 insertions(+), 5 deletions(-) create mode 120000 hooks/config-changed diff --git a/hooks/ceilometer_hooks.py b/hooks/ceilometer_hooks.py index cffbd25..ecc96e2 100755 --- a/hooks/ceilometer_hooks.py +++ b/hooks/ceilometer_hooks.py @@ -17,13 +17,15 @@ from charmhelpers.core.host import ( lsb_release, ) from charmhelpers.contrib.openstack.utils import ( - configure_installation_source + configure_installation_source, + openstack_upgrade_available ) from ceilometer_utils import ( restart_map, register_configs, CEILOMETER_AGENT_PACKAGES, - NOVA_SETTINGS + NOVA_SETTINGS, + do_openstack_upgrade ) hooks = Hooks() @@ -55,6 +57,13 @@ def ceilometer_changed(): CONFIGS.write_all() +@hooks.hook('config-changed') +@restart_on_change(restart_map(), stopstart=True) +def config_changed(): + if openstack_upgrade_available('ceilometer-common'): + do_openstack_upgrade(CONFIGS) + CONFIGS.write_all() + if __name__ == '__main__': try: hooks.execute(sys.argv) diff --git a/hooks/ceilometer_utils.py b/hooks/ceilometer_utils.py index 10d50ba..09ce338 100644 --- a/hooks/ceilometer_utils.py +++ b/hooks/ceilometer_utils.py @@ -5,8 +5,15 @@ from ceilometer_contexts import ( CeilometerServiceContext ) from charmhelpers.contrib.openstack.utils import ( - get_os_codename_package + get_os_codename_package, + get_os_codename_install_source, + configure_installation_source ) +from charmhelpers.core.hookenv import ( + config, + log, +) +from charmhelpers.fetch import apt_update, apt_install, apt_upgrade CEILOMETER_CONF_DIR = "/etc/ceilometer" CEILOMETER_CONF = "%s/ceilometer.conf" % CEILOMETER_CONF_DIR @@ -85,3 +92,31 @@ def restart_map(): if svcs: _map[f] = svcs return _map + + +def do_openstack_upgrade(configs): + """ + Perform an upgrade. Takes care of upgrading packages, rewriting + configs, database migrations and potentially any other post-upgrade + actions. + + :param configs: The charms main OSConfigRenderer object. + """ + new_src = config('openstack-origin') + new_os_rel = get_os_codename_install_source(new_src) + + log('Performing OpenStack upgrade to %s.' % (new_os_rel)) + + configure_installation_source(new_src) + dpkg_opts = [ + '--option', 'Dpkg::Options::=--force-confnew', + '--option', 'Dpkg::Options::=--force-confdef', + ] + apt_update(fatal=True) + apt_upgrade(options=dpkg_opts, fatal=True, dist=True) + apt_install(packages=CEILOMETER_AGENT_PACKAGES, + options=dpkg_opts, + fatal=True) + + # set CONFIGS to load templates from new release + configs.set_release(openstack_release=new_os_rel) diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index d254de1..8429d83 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -147,7 +147,8 @@ class SharedDBContext(OSContextGenerator): 'database_host': rdata.get('db_host'), 'database': self.database, 'database_user': self.user, - 'database_password': rdata.get(password_setting) + 'database_password': rdata.get(password_setting), + 'database_type': 'mysql' } if context_complete(ctxt): db_ssl(rdata, ctxt, self.ssl_dir) @@ -155,6 +156,35 @@ class SharedDBContext(OSContextGenerator): return {} +class PostgresqlDBContext(OSContextGenerator): + interfaces = ['pgsql-db'] + + def __init__(self, database=None): + self.database = database + + def __call__(self): + self.database = self.database or config('database') + if self.database is None: + log('Could not generate postgresql_db context. ' + 'Missing required charm config options. ' + '(database name)') + raise OSContextError + ctxt = {} + + for rid in relation_ids(self.interfaces[0]): + for unit in related_units(rid): + ctxt = { + 'database_host': relation_get('host', rid=rid, unit=unit), + 'database': self.database, + 'database_user': relation_get('user', rid=rid, unit=unit), + 'database_password': relation_get('password', rid=rid, unit=unit), + 'database_type': 'postgresql', + } + if context_complete(ctxt): + return ctxt + return {} + + def db_ssl(rdata, ctxt, ssl_dir): if 'ssl_ca' in rdata and ssl_dir: ca_path = os.path.join(ssl_dir, 'db-client.ca') diff --git a/hooks/config-changed b/hooks/config-changed new file mode 120000 index 0000000..c948469 --- /dev/null +++ b/hooks/config-changed @@ -0,0 +1 @@ +ceilometer_hooks.py \ No newline at end of file diff --git a/unit_tests/test_ceilometer_hooks.py b/unit_tests/test_ceilometer_hooks.py index 1a49537..8523827 100644 --- a/unit_tests/test_ceilometer_hooks.py +++ b/unit_tests/test_ceilometer_hooks.py @@ -21,6 +21,8 @@ TO_PATCH = [ 'filter_installed_packages', 'CONFIGS', 'relation_set', + 'openstack_upgrade_available', + 'do_openstack_upgrade' ] @@ -53,3 +55,19 @@ class CeilometerHooksTest(CharmTestCase): hooks.hooks.execute(['hooks/nova-ceilometer-relation-joined']) self.relation_set.assert_called_with( subordinate_configuration=json.dumps(ceilometer_utils.NOVA_SETTINGS)) + + def test_config_changed_no_upgrade(self): + self.openstack_upgrade_available.return_value = False + hooks.hooks.execute(['hooks/config-changed']) + self.openstack_upgrade_available.\ + assert_called_with('ceilometer-common') + self.assertFalse(self.do_openstack_upgrade.called) + self.assertTrue(self.CONFIGS.write_all.called) + + def test_config_changed_upgrade(self): + self.openstack_upgrade_available.return_value = True + hooks.hooks.execute(['hooks/config-changed']) + self.openstack_upgrade_available.\ + assert_called_with('ceilometer-common') + self.assertTrue(self.do_openstack_upgrade.called) + self.assertTrue(self.CONFIGS.write_all.called) diff --git a/unit_tests/test_ceilometer_utils.py b/unit_tests/test_ceilometer_utils.py index 34e8b65..61d7d76 100644 --- a/unit_tests/test_ceilometer_utils.py +++ b/unit_tests/test_ceilometer_utils.py @@ -1,4 +1,4 @@ -from mock import patch, call +from mock import patch, call, MagicMock import ceilometer_utils as utils @@ -8,6 +8,13 @@ TO_PATCH = [ 'get_os_codename_package', 'templating', 'CeilometerServiceContext', + 'config', + 'get_os_codename_install_source', + 'configure_installation_source', + 'apt_install', + 'apt_update', + 'apt_upgrade', + 'log' ] @@ -32,3 +39,24 @@ class CeilometerUtilsTest(CharmTestCase): self.assertEquals(restart_map, {'/etc/ceilometer/ceilometer.conf': [ 'ceilometer-agent-compute']}) + + def test_do_openstack_upgrade(self): + self.config.side_effect = self.test_config.get + self.test_config.set('openstack-origin', 'cloud:precise-havana') + self.get_os_codename_install_source.return_value = 'havana' + configs = MagicMock() + utils.do_openstack_upgrade(configs) + configs.set_release.assert_called_with(openstack_release='havana') + self.log.assert_called() + self.apt_update.assert_called_with(fatal=True) + dpkg_opts = [ + '--option', 'Dpkg::Options::=--force-confnew', + '--option', 'Dpkg::Options::=--force-confdef', + ] + self.apt_install.assert_called_with( + packages=utils.CEILOMETER_AGENT_PACKAGES, + options=dpkg_opts, fatal=True + ) + self.configure_installation_source.assert_called_with( + 'cloud:precise-havana' + )