From edd9b1face6aac248d134d9261574e451a8121e7 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Thu, 11 Jan 2018 17:27:20 +0000 Subject: [PATCH] Add action for running archive-deleted-rows Add an action for moving stale data to shadow tables using nova-manage *1. This will speed up other operations such as map_instances which no longer need to work against stale data. *1 https://docs.openstack.org/nova/pike/cli/nova-manage.html Change-Id: I03f3d641b50cfc6f02262edb0f714ba6e9566775 Partial-Bug: #1742115 --- actions.yaml | 7 +++++++ actions/actions.py | 20 ++++++++++++++++++-- actions/archive-data | 1 + hooks/nova_cc_utils.py | 18 ++++++++++++++++++ unit_tests/test_nova_cc_utils.py | 31 +++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 120000 actions/archive-data diff --git a/actions.yaml b/actions.yaml index 002aec3a..6ba77538 100644 --- a/actions.yaml +++ b/actions.yaml @@ -4,3 +4,10 @@ pause: description: Pause the nova-cloud-controller unit. This action will stop related services. resume: descrpition: Resume the nova-cloud-controller unit. This action will start related services. +archive-data: + descrpition: Run job to archive deleted rows in database + params: + batch-size: + type: integer + default: 10000 + description: Archive old data to shadow tables diff --git a/actions/actions.py b/actions/actions.py index e59d45ca..c6e43c81 100755 --- a/actions/actions.py +++ b/actions/actions.py @@ -19,11 +19,16 @@ import sys sys.path.append('hooks/') -from charmhelpers.core.hookenv import action_fail +from charmhelpers.core.hookenv import ( + action_fail, + action_get, + action_set, +) from nova_cc_utils import ( pause_unit_helper, resume_unit_helper, register_configs, + archive_deleted_rows, ) @@ -40,9 +45,20 @@ def resume(args): resume_unit_helper(register_configs()) +def archive_data(args): + """Run data archival process + @raises Exception should the archival fail""" + action_set({ + 'archive-deleted-rows': archive_deleted_rows( + max_rows=action_get('batch-size'))}) + + # A dictionary of all the defined actions to callables (which take # parsed arguments). -ACTIONS = {"pause": pause, "resume": resume} +ACTIONS = { + "pause": pause, + "resume": resume, + "archive-data": archive_data} def main(args): diff --git a/actions/archive-data b/actions/archive-data new file mode 120000 index 00000000..405a394e --- /dev/null +++ b/actions/archive-data @@ -0,0 +1 @@ +actions.py \ No newline at end of file diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 7a0749a3..4e7cc399 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -775,6 +775,24 @@ def map_instances(): raise +def archive_deleted_rows(max_rows=None): + log('Archiving deleted rows', level=INFO) + cmd = ['nova-manage', 'db', 'archive_deleted_rows', '--verbose'] + if max_rows: + cmd.extend(['--max_rows', str(max_rows)]) + process = subprocess.Popen(cmd, stdout=subprocess.PIPE) + stdout, stderr = process.communicate() + exit_code = process.wait() + if exit_code not in [0, 1]: + msg = 'Archiving deleted rows failed\nstdout: {}\nstderr: {}'.format( + stdout, + stderr) + log(msg, level=ERROR) + raise Exception(msg) + else: + return stdout + + def add_hosts_to_cell(): '''Map compute hosts to cell''' log('Cell1 discover_hosts', level=INFO) diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index b36b141e..9b3149d4 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -1033,6 +1033,37 @@ class NovaCCUtilsTests(CharmTestCase): 'map_instances', '--cell_uuid', cell_uuid]) + @patch('subprocess.Popen') + def test_archive_deleted_rows(self, mock_popen): + process_mock = MagicMock() + attrs = { + 'communicate.return_value': ('output', 'error'), + 'wait.return_value': 0} + process_mock.configure_mock(**attrs) + mock_popen.return_value = process_mock + expectd_calls = [ + call([ + 'nova-manage', + 'db', + 'archive_deleted_rows', + '--verbose'], stdout=-1), + call().communicate(), + call().wait()] + + utils.archive_deleted_rows() + self.assertEqual(mock_popen.mock_calls, expectd_calls) + + @patch('subprocess.Popen') + def test_archive_deleted_rows_excpetion(self, mock_popen): + process_mock = MagicMock() + attrs = { + 'communicate.return_value': ('output', 'error'), + 'wait.return_value': 123} + process_mock.configure_mock(**attrs) + mock_popen.return_value = process_mock + with self.assertRaises(Exception): + utils.archive_deleted_rows() + @patch.object(utils, 'get_cell_uuid') @patch('subprocess.check_output') def test_add_hosts_to_cell(self, mock_check_output, mock_get_cell_uuid):