From 234a41b7dd03002f2f7b41d17f87199686147560 Mon Sep 17 00:00:00 2001 From: James Slagle Date: Fri, 21 May 2021 12:18:31 -0400 Subject: [PATCH] Ephemeral Heat: Add a --refresh option to external update run In order to support ephemeral Heat, the external update run command should rely on the already downloaded config-download playbooks as generated by update prepare. There is no Heat instance available to re-download the playbooks automatically. To support the old behavior with a system installed Heat, a --refresh option is added which will refresh the config-download playbooks. We can not have an option to refresh the playbooks automatically with ephemeral Heat, because the command would need to inherit from DeployCommand and require environment files so that we can use the ContainerImagePrepare value to get the ephemeral Heat container images, as well as the ephemeral Heat setup and tear down code. As this would be a much larger refactor to the CLI, we avoid it. The correct fix for the case where the stack may have been modified out of order is to require another run of update prepare which will regenerate the playbooks. Change-Id: Ib01d920112f5e84190fbcd9470dd7bac269b3987 Signed-off-by: James Slagle (cherry picked from commit 76c95906368af3445b6dd789617c9caa5cfbe118) --- .../test_overcloud_external_update.py | 36 +++++++ tripleoclient/v1/overcloud_external_update.py | 94 +++++++++++++------ tripleoclient/workflows/deployment.py | 14 ++- 3 files changed, 111 insertions(+), 33 deletions(-) diff --git a/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py b/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py index 6946646f2..44a3a1073 100644 --- a/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py +++ b/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py @@ -13,7 +13,9 @@ # under the License. # +import fixtures import mock +import os from tripleoclient.tests import fakes as ooofakes from tripleoclient.tests.v1.overcloud_external_update import fakes @@ -89,3 +91,37 @@ class TestOvercloudExternalUpdateRun(fakes.TestOvercloudExternalUpdateRun): ] self.check_parser(self.cmd, argslist, verifylist) + + @mock.patch('tripleoclient.workflows.deployment.config_download') + @mock.patch('tripleoclient.utils.get_default_working_dir', autospec=True) + @mock.patch('tripleoclient.workflows.deployment.snapshot_dir', + autospec=True) + @mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True) + @mock.patch('tripleoclient.utils.get_key') + def test_update_with_refresh( + self, mock_get_key, + mock_run_ansible_playbook, + mock_snapshot_dir, + mock_get_default_working_dir, + mock_config_download): + argslist = ['--yes', '--refresh'] + verifylist = [ + ('refresh', True) + ] + parsed_args = self.check_parser(self.cmd, argslist, verifylist) + argslist = ['--yes'] + verifylist = [ + ('refresh', False) + ] + parsed_args = self.check_parser(self.cmd, argslist, verifylist) + + mock_get_key.return_value = '/test/key' + work_dir = self.useFixture(fixtures.TempDir()) + mock_get_default_working_dir.return_value = work_dir.path + ansible_dir = os.path.join(work_dir.path, 'config-download', + 'overcloud') + self.cmd.take_action(parsed_args) + mock_get_key.assert_called_once_with('overcloud') + mock_snapshot_dir.assert_called_once_with(ansible_dir) + mock_run_ansible_playbook.assert_called() + mock_config_download.assert_not_called() diff --git a/tripleoclient/v1/overcloud_external_update.py b/tripleoclient/v1/overcloud_external_update.py index 724c67c83..42499e629 100644 --- a/tripleoclient/v1/overcloud_external_update.py +++ b/tripleoclient/v1/overcloud_external_update.py @@ -13,6 +13,8 @@ # under the License. # +import os + from oslo_config import cfg from oslo_log import log as logging @@ -114,6 +116,11 @@ class ExternalUpdateRun(command.Command): help=_('The number of Ansible forks to use for the' ' config-download ansible-playbook command.') ) + parser.add_argument( + '--refresh', + action='store_true', + help=_('Refresh the config-download playbooks') + ) return parser @@ -128,35 +135,60 @@ class ExternalUpdateRun(command.Command): constants.UPDATE_PROMPT, self.log)): raise OvercloudUpdateNotConfirmed(constants.UPDATE_NO) - _, ansible_dir = self.get_ansible_key_and_dir( - no_workflow=True, - stack=parsed_args.stack, - orchestration=self.app.client_manager.orchestration - ) - deployment.config_download( - log=self.log, - clients=self.app.client_manager, - stack=oooutils.get_stack( - self.app.client_manager.orchestration, - parsed_args.stack - ), - output_dir=ansible_dir, - verbosity=oooutils.playbook_verbosity(self=self), - ansible_playbook_name=constants.EXTERNAL_UPDATE_PLAYBOOKS, - extra_vars=oooutils.parse_extra_vars( - extra_var_strings=parsed_args.extra_vars - ), - inventory_path=oooutils.get_tripleo_ansible_inventory( - parsed_args.static_inventory, - parsed_args.ssh_user, - parsed_args.stack, - return_inventory_file_path=True - ), - tags=parsed_args.tags, - skip_tags=parsed_args.skip_tags, - limit_hosts=oooutils.playbook_limit_parse( - limit_nodes=parsed_args.limit - ), - forks=parsed_args.ansible_forks - ) + if parsed_args.refresh: + _, ansible_dir = self.get_ansible_key_and_dir( + no_workflow=True, + stack=parsed_args.stack, + orchestration=self.app.client_manager.orchestration + ) + deployment.config_download( + log=self.log, + clients=self.app.client_manager, + stack=oooutils.get_stack( + self.app.client_manager.orchestration, + parsed_args.stack + ), + output_dir=ansible_dir, + verbosity=oooutils.playbook_verbosity(self=self), + ansible_playbook_name=constants.EXTERNAL_UPDATE_PLAYBOOKS, + extra_vars=oooutils.parse_extra_vars( + extra_var_strings=parsed_args.extra_vars + ), + inventory_path=oooutils.get_tripleo_ansible_inventory( + parsed_args.static_inventory, + parsed_args.ssh_user, + parsed_args.stack, + return_inventory_file_path=True + ), + tags=parsed_args.tags, + skip_tags=parsed_args.skip_tags, + limit_hosts=oooutils.playbook_limit_parse( + limit_nodes=parsed_args.limit + ), + forks=parsed_args.ansible_forks + ) + else: + working_dir = oooutils.get_default_working_dir(parsed_args.stack) + config_download_dir = os.path.join(working_dir, 'config-download') + ansible_dir = os.path.join(config_download_dir, parsed_args.stack) + inventory_path = os.path.join(ansible_dir, + 'tripleo-ansible-inventory.yaml') + key = oooutils.get_key(parsed_args.stack) + playbooks = [os.path.join(ansible_dir, p) + for p in constants.EXTERNAL_UPDATE_PLAYBOOKS] + oooutils.run_ansible_playbook( + playbook=playbooks, + inventory=inventory_path, + workdir=config_download_dir, + tags=parsed_args.tags, + skip_tags=parsed_args.skip_tags, + limit_hosts=oooutils.playbook_limit_parse( + limit_nodes=parsed_args.limit + ), + forks=parsed_args.ansible_forks, + key=key, + reproduce_command=True + ) + deployment.snapshot_dir(ansible_dir) + self.log.info("Completed Overcloud External Update Run.") diff --git a/tripleoclient/workflows/deployment.py b/tripleoclient/workflows/deployment.py index e32ed1cb9..aded5cdbd 100644 --- a/tripleoclient/workflows/deployment.py +++ b/tripleoclient/workflows/deployment.py @@ -469,9 +469,19 @@ def config_download(log, clients, stack, ssh_network='ctlplane', print_msg=(verbosity == 0) ) - if os.path.exists(stack_work_dir): + snapshot_dir(stack_work_dir) + + +def snapshot_dir(directory): + """Git snapshot a directory + + :params directory: Directory to snapshot + :type directory: string + :returns: None + """ + if os.path.exists(directory): # Object to the git repository - repo = git.Repo(stack_work_dir) + repo = git.Repo(directory) # Configure git user.name and user.email git_config_user = "mistral"