From 0161dde79660a248742e41e67f92ed13af561dd7 Mon Sep 17 00:00:00 2001 From: David Ames Date: Thu, 7 Sep 2017 09:13:12 -0700 Subject: [PATCH] Resolve OS upgrade bugs Ensure that the os_release cache is cleared during the openstack upgrade process, ensuring that package list and configuration options are correctly set for the new OpenStack version. Ensure that map_instances gets run on upgrade. This updates the nova_api.instance_mappings table with pre-existing instances. Change-Id: Idfcdc48c25b24d0cc9ded3eda2bc4d13d3b04f6d Closes-Bug: 1715624 --- hooks/nova_cc_utils.py | 50 +++++++++++++++++++++++--------- unit_tests/test_nova_cc_utils.py | 22 ++++++++++++++ 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 494771cd..e737f6e2 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -51,6 +51,7 @@ from charmhelpers.contrib.openstack.utils import ( incomplete_relation_data, is_ip, os_release, + reset_os_release, save_script_rc as _save_script_rc, is_unit_paused_set, make_assess_status_func, @@ -587,12 +588,6 @@ def disable_policy_rcd(): os.unlink('/usr/sbin/policy-rc.d') -def reset_os_release(): - # Ugly hack to make os_release re-read versions - import charmhelpers.contrib.openstack.utils as utils - utils.os_rel = None - - def is_db_initialised(): if relation_ids('cluster'): dbsync_state = peer_retrieve('dbsync_state') @@ -630,6 +625,7 @@ def _do_openstack_upgrade(new_src): apt_update(fatal=True) apt_upgrade(options=dpkg_opts, fatal=True, dist=True) + reset_os_release() apt_install(determine_packages(), fatal=True) disable_policy_rcd() @@ -637,7 +633,6 @@ def _do_openstack_upgrade(new_src): # NOTE(jamespage) upgrade with existing config files as the # havana->icehouse migration enables new service_plugins which # create issues with db upgrades - reset_os_release() configs = register_configs(release=new_os_rel) configs.write_all() @@ -751,12 +746,27 @@ def initialize_cell_databases(): # TODO: Update to subprocess.check_call(), but note that rc == 2 is # not a failure so only allow exception to be raised if rc == 1. if rc == 0: - log('cell1 mapping was successfully created', level=INFO) + log('cell1 was successfully created', level=INFO) elif rc == 1: raise Exception("Cannot initialize cell1 because of missing " "transport_url or database connection") +def get_cell_uuid(cell): + '''Get cell uuid + :param cell: string cell name i.e. 'cell1' + :returns: string cell uuid + ''' + log("Listing cell, '{}'".format(cell), level=INFO) + cmd = ['sudo', 'nova-manage', 'cell_v2', 'list_cells'] + out = subprocess.check_output(cmd) + cell_uuid = out.split(cell, 1)[1].split()[1] + if not cell_uuid: + raise Exception("Cannot find cell, '{}', in list_cells." + "".format(cell)) + return cell_uuid + + def update_cell_database(): '''Update the cell1 database properties @@ -764,10 +774,7 @@ def update_cell_database(): changed to update the transport_url in the nova_api cell_mappings table. ''' log('Updating cell1 properties', level=INFO) - cmd = ['sudo', 'nova-manage', 'cell_v2', 'list_cells'] - out = subprocess.check_output(cmd) - cell1_uuid = out.split("cell1", 1)[1].split()[1] - + cell1_uuid = get_cell_uuid('cell1') cmd = ['nova-manage', 'cell_v2', 'update_cell', '--cell_uuid', cell1_uuid] rc = subprocess.call(cmd) # TODO: Update to subprocess.check_call(), but note that rc == 2 is @@ -778,6 +785,22 @@ def update_cell_database(): raise Exception("Cannot find cell1 while attempting properties update") +def map_instances(): + '''Map instances + + Updates nova_api.inatance_mappings with pre-existing instances + ''' + log('Cell1 map_instances', level=INFO) + cell1_uuid = get_cell_uuid('cell1') + cmd = ['nova-manage', 'cell_v2', 'map_instances', + '--cell_uuid', cell1_uuid] + rc = subprocess.call(cmd) + if rc == 0: + log('Cell1 map_instances updated successfully', level=INFO) + elif rc == 1: + raise Exception("map_instances failed") + + def add_hosts_to_cell(): '''Add any new compute hosts to cell1''' # TODO: Replace the following checks with a Cellsv2 context check. @@ -826,6 +849,7 @@ def migrate_nova_databases(): migrate_nova_database() online_data_migrations_if_needed() add_hosts_to_cell() + map_instances() finalize_migrate_nova_databases() @@ -1023,7 +1047,7 @@ def determine_endpoints(public_url, internal_url, admin_url): '''Generates a dictionary containing all relevant endpoints to be passed to keystone as relation settings.''' region = config('region') - os_rel = os_release('nova-common', reset_cache=True) + os_rel = os_release('nova-common') cmp_os_rel = CompareOpenStackReleases(os_rel) nova_public_url = ('%s:%s/v2/$(tenant_id)s' % diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index a21c7f79..e3776462 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -1367,3 +1367,25 @@ class NovaCCUtilsTests(CharmTestCase): s_resume.assert_has_calls([call(s) for s in utils.AWS_COMPAT_SERVICES]) s_pause.assert_not_called() + + @patch('subprocess.check_output') + def test_get_cell_uuid(self, mock_check_call): + mock_check_call.return_value = (""" + +-------+--------------------------------------+ + | Name | UUID | + +-------+--------------------------------------+ + | cell0 | 00000000-0000-0000-0000-000000000000 | + | cell1 | c83121db-f1c7-464a-b657-38c28fac84c6 | + +-------+--------------------------------------+""") + expected = 'c83121db-f1c7-464a-b657-38c28fac84c6' + self.assertEqual(expected, utils.get_cell_uuid('cell1')) + + @patch.object(utils, 'get_cell_uuid') + @patch('subprocess.call') + def test_map_instances(self, mock_call, mock_get_cell_uuid): + cell_uuid = 'c83121db-f1c7-464a-b657-38c28fac84c6' + mock_get_cell_uuid.return_value = cell_uuid + utils.map_instances() + mock_call.assert_called_with(['nova-manage', 'cell_v2', + 'map_instances', '--cell_uuid', + cell_uuid])