From 1cd6f2829fae1d400d424070fc62165316cf5074 Mon Sep 17 00:00:00 2001 From: James Slagle Date: Tue, 3 Aug 2021 17:53:04 -0400 Subject: [PATCH] Refactor --stack-only, --setup-only, --config-download-only Refactors the --stack-only, --setup-only, --config-download-only, to work with ephemeral-heat. The arguments now do the expected behavior and work with how they previously worked prior to ephemeral heat. --stack-only: create the stack, download the config. no overcloud node changes --setup-only: ssh admin authorization setup. --config-download-only: run config-download playbook(s) to configure the overcloud. Signed-off-by: James Slagle Depends-On: Ie47abe2d7c5d7891aceb88d9008d45d7922dea15 Change-Id: Ia765c2c2ea548a1dcd20f592eda8741f40a1cf16 --- ...factor-only-cli-args-cb70ed8ba8b166a9.yaml | 10 + .../overcloud_deploy/test_overcloud_deploy.py | 2 +- .../test_overcloud_upgrade.py | 2 +- .../tests/workflows/test_deployment.py | 2 +- tripleoclient/v1/overcloud_deploy.py | 271 ++++++++++-------- tripleoclient/v1/overcloud_upgrade.py | 4 +- tripleoclient/workflows/deployment.py | 26 +- 7 files changed, 165 insertions(+), 152 deletions(-) create mode 100644 releasenotes/notes/refactor-only-cli-args-cb70ed8ba8b166a9.yaml diff --git a/releasenotes/notes/refactor-only-cli-args-cb70ed8ba8b166a9.yaml b/releasenotes/notes/refactor-only-cli-args-cb70ed8ba8b166a9.yaml new file mode 100644 index 000000000..f5c98bc8c --- /dev/null +++ b/releasenotes/notes/refactor-only-cli-args-cb70ed8ba8b166a9.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + The cli arguments that control what parts of the deployment to execute + have been refactored to better align with the user expected intention, + --stack-only: create the stack, download the config. no overcloud node + changes + --setup-only: ssh admin authorization setup. + --config-download-only: run config-download playbook(s) to configure the + overcloud. diff --git a/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py b/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py index f4a2a13f0..405c22adf 100644 --- a/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py +++ b/tripleoclient/tests/v1/overcloud_deploy/test_overcloud_deploy.py @@ -1396,7 +1396,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud): 'region': 'region1'} # assuming heat deploy consumed a 3m out of total 451m timeout with mock.patch('time.time', side_effect=[1585820346, - 12345678, 0, 0, + 12345678, 0, 1585820526, 0, 0, 0, 0]): self.cmd.take_action(parsed_args) diff --git a/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py b/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py index 8f7a8df11..5253d7029 100644 --- a/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py +++ b/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py @@ -87,7 +87,7 @@ class TestOvercloudUpgradePrepare(fakes.TestOvercloudUpgradePrepare): mock_overcloud_deploy.assert_called_once_with(parsed_args) args, kwargs = mock_overcloud_deploy.call_args # Check config_download arg is set to False - self.assertEqual(args[0].config_download, False) + self.assertEqual(args[0].stack_only, True) mock_enable_ssh_admin.assert_called_once_with( mock_stack, parsed_args.overcloud_ssh_network, diff --git a/tripleoclient/tests/workflows/test_deployment.py b/tripleoclient/tests/workflows/test_deployment.py index a6347fa44..4fcfbecb8 100644 --- a/tripleoclient/tests/workflows/test_deployment.py +++ b/tripleoclient/tests/workflows/test_deployment.py @@ -135,7 +135,7 @@ class TestDeploymentWorkflows(utils.TestCommand): 'ssh_key', 'ssh_networks', 'output_dir', False, 'timeout') - self.assertEqual(3, mock_playbook.call_count) + self.assertEqual(2, mock_playbook.call_count) def test_config_download_dirs(self): stack = 'teststack' diff --git a/tripleoclient/v1/overcloud_deploy.py b/tripleoclient/v1/overcloud_deploy.py index 825bac5e6..ee574e0f8 100644 --- a/tripleoclient/v1/overcloud_deploy.py +++ b/tripleoclient/v1/overcloud_deploy.py @@ -603,9 +603,6 @@ class DeployOvercloud(command.Command): def setup_ephemeral_heat(self, parsed_args): self.log.info("Using ephemeral heat for stack operation") - restore_db = (parsed_args.setup_only or - parsed_args.config_download_only) - # Skip trying to pull the images if they are set to the default # as they can't be pulled since they are tagged as localhost. # If the images are missing for some reason, podman will still pull @@ -627,8 +624,7 @@ class DeployOvercloud(command.Command): use_tmp_dir=False, rm_heat=parsed_args.rm_heat, skip_heat_pull=skip_heat_pull) - self.orchestration_client = \ - utils.launch_heat(self.heat_launcher, restore_db=restore_db) + self.orchestration_client = utils.launch_heat(self.heat_launcher) self.clients.orchestration = self.orchestration_client def get_parser(self, prog_name): @@ -828,35 +824,38 @@ class DeployOvercloud(command.Command): '--config-download', action='store_true', default=True, - help=_('Run deployment via config-download mechanism. This is ' - 'now the default, and this CLI options may be removed in ' - 'the future.') + help=_('DEPRECATED: Run deployment via config-download mechanism. ' + 'This is now the default, and this CLI options has no ' + 'effect.') ) parser.add_argument( '--no-config-download', '--stack-only', - action='store_false', + action='store_true', default=False, - dest='config_download', + dest='stack_only', help=_('Disable the config-download workflow and only create ' - 'the stack and associated OpenStack resources. No ' - 'software configuration will be applied.') + 'the stack and download the config. No software ' + 'configuration, setup, or any changes will be applied ' + 'to overcloud nodes.') ) parser.add_argument( '--config-download-only', action='store_true', default=False, - help=_('Disable the stack create/update, and only run the ' + help=_('Disable the stack create and setup, and only run the ' 'config-download workflow to apply the software ' - 'configuration.') + 'configuration. Requires that config-download setup ' + 'was previously completed, either with --stack-only ' + 'and --setup-only or a full deployment') ) parser.add_argument( '--setup-only', action='store_true', default=False, - help=_('option will automate the setup and download steps ' - 'required to prepare the environment for manual ' - 'ansible execution.') + help=_('Disable the stack and config-download workflow to apply ' + 'the software configuration and only run the setup to ' + 'enable ssh connectivity.') ) parser.add_argument( '--config-dir', @@ -1134,15 +1133,38 @@ class DeployOvercloud(command.Command): stack, parsed_args, new_tht_root, user_tht_root) if parsed_args.heat_type != 'installed': - self.setup_ephemeral_heat(parsed_args) + ephemeral_heat = True else: + ephemeral_heat = False self.log.warning( ("DEPRECATED: Using --heat-type=installed is deprecated " "and will be removed in a future release.")) + # full_deploy means we're doing a full deployment + # e.g., no --*-only args were passed + full_deploy = not (parsed_args.stack_only or parsed_args.setup_only or + parsed_args.config_download_only) + # do_stack is True when: + # --stack-only + # a full deployment + do_stack = (parsed_args.stack_only or full_deploy) + # do_setup is True when: + # --setup-only OR + # a full deployment + do_setup = parsed_args.setup_only or full_deploy + # do_config_download is True when: + # --config-download-only OR + # a full deployment + do_config_download = parsed_args.config_download_only or full_deploy + + if ephemeral_heat and do_stack: + self.setup_ephemeral_heat(parsed_args) + + config_download_dir = parsed_args.output_dir or \ + os.path.join(self.working_dir, "config-download") + try: - if not (parsed_args.config_download_only or - parsed_args.setup_only): + if do_stack: self.deploy_tripleo_heat_templates( stack, parsed_args, new_tht_root, user_tht_root, created_env_files) @@ -1151,6 +1173,39 @@ class DeployOvercloud(command.Command): self.orchestration_client, parsed_args.stack) utils.save_stack_outputs( self.orchestration_client, stack, self.working_dir) + + # Download config + config_dir = parsed_args.config_dir or config_download_dir + config_type = parsed_args.config_type + preserve_config_dir = parsed_args.preserve_config_dir + key_file = utils.get_key(parsed_args.stack) + extra_vars = { + 'plan': parsed_args.stack, + 'config_dir': config_dir, + 'preserve_config': preserve_config_dir, + 'output_dir': config_download_dir, + 'ansible_ssh_user': parsed_args.overcloud_ssh_user, + 'ansible_ssh_private_key_file': key_file, + 'ssh_network': parsed_args.overcloud_ssh_network, + 'python_interpreter': + parsed_args.deployment_python_interpreter, + } + if parsed_args.config_type: + extra_vars['config_type'] = config_type + + playbook = 'cli-config-download.yaml' + ansible_work_dir = os.path.join( + self.working_dir, os.path.splitext(playbook)[0]) + utils.run_ansible_playbook( + playbook='cli-config-download.yaml', + inventory='localhost,', + workdir=ansible_work_dir, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + reproduce_command=True, + verbosity=utils.playbook_verbosity(self=self), + extra_vars=extra_vars + ) + except Exception: if parsed_args.heat_type != 'installed' and self.heat_launcher: self.log.info("Stopping ephemeral heat.") @@ -1158,59 +1213,45 @@ class DeployOvercloud(command.Command): utils.rm_heat(self.heat_launcher, backup_db=True) raise - # Get a new copy of the stack after stack update/create. If it - # was a create then the previous stack object would be None. - stack = utils.get_stack( - self.orchestration_client, parsed_args.stack) - overcloud_endpoint = None old_rcpath = None rcpath = None horizon_url = None try: - # Force fetching of attributes - stack.get() - overcloud_endpoint = utils.get_overcloud_endpoint(stack) - horizon_url = deployment.get_horizon_url( - stack=stack.stack_name, - heat_type=parsed_args.heat_type, - working_dir=self.working_dir) - rc_params = utils.get_rc_params( - self.orchestration_client, - parsed_args.stack) + if stack: + # Force fetching of attributes + stack.get() + overcloud_endpoint = utils.get_overcloud_endpoint(stack) + horizon_url = deployment.get_horizon_url( + stack=stack.stack_name, + heat_type=parsed_args.heat_type, + working_dir=self.working_dir) + rc_params = utils.get_rc_params( + self.orchestration_client, + parsed_args.stack) - # For backwards compatibility, we will also write overcloudrc to - # $HOME and then self.working_dir. - old_rcpath = deployment.create_overcloudrc( - stack, rc_params, parsed_args.no_proxy) - rcpath = deployment.create_overcloudrc( - stack, rc_params, parsed_args.no_proxy, - self.working_dir) + # For backwards compatibility, we will also write overcloudrc + # to $HOME and then self.working_dir. + old_rcpath = deployment.create_overcloudrc( + stack, rc_params, parsed_args.no_proxy) + rcpath = deployment.create_overcloudrc( + stack, rc_params, parsed_args.no_proxy, + self.working_dir) - config_download_dir = parsed_args.output_dir or \ - os.path.join(self.working_dir, "config-download") - - if parsed_args.config_download: - self.log.info("Deploying overcloud configuration") - deployment.set_deployment_status( - stack.stack_name, - status='DEPLOYING', - working_dir=self.working_dir + if do_setup: + deployment.get_hosts_and_enable_ssh_admin( + parsed_args.stack, + parsed_args.overcloud_ssh_network, + parsed_args.overcloud_ssh_user, + self.get_key_pair(parsed_args), + parsed_args.overcloud_ssh_port_timeout, + self.working_dir, + verbosity=utils.playbook_verbosity(self=self), + heat_type=parsed_args.heat_type ) - if not parsed_args.config_download_only: - deployment.get_hosts_and_enable_ssh_admin( - parsed_args.stack, - parsed_args.overcloud_ssh_network, - parsed_args.overcloud_ssh_user, - self.get_key_pair(parsed_args), - parsed_args.overcloud_ssh_port_timeout, - self.working_dir, - verbosity=utils.playbook_verbosity(self=self), - heat_type=parsed_args.heat_type - ) - + if do_config_download: if parsed_args.config_download_timeout: timeout = parsed_args.config_download_timeout else: @@ -1220,61 +1261,45 @@ class DeployOvercloud(command.Command): raise exceptions.DeploymentError( 'Deployment timed out after %sm' % used) - if not parsed_args.setup_only: - deployment_options = {} - if parsed_args.deployment_python_interpreter: - deployment_options['ansible_python_interpreter'] = \ - parsed_args.deployment_python_interpreter - - deployment.make_config_download_dir(config_download_dir, - parsed_args.stack) - - deployment.config_download( - self.log, - self.clients, - parsed_args.stack, - parsed_args.overcloud_ssh_network, - config_download_dir, - parsed_args.override_ansible_cfg, - timeout=parsed_args.overcloud_ssh_port_timeout, - verbosity=utils.playbook_verbosity(self=self), - deployment_options=deployment_options, - in_flight_validations=parsed_args.inflight, - deployment_timeout=timeout, - tags=parsed_args.tags, - skip_tags=parsed_args.skip_tags, - limit_hosts=utils.playbook_limit_parse( - limit_nodes=parsed_args.limit - ), - forks=parsed_args.ansible_forks, - denyed_hostnames=utils.get_stack_saved_output_item( - 'BlacklistedHostnames', self.working_dir)) + self.log.info("Deploying overcloud configuration") deployment.set_deployment_status( - stack.stack_name, - status=deploy_status, - working_dir=self.working_dir) - elif not parsed_args.config_download or parsed_args.setup_only: - # Download config - config_dir = parsed_args.config_dir or config_download_dir - config_type = parsed_args.config_type - preserve_config_dir = parsed_args.preserve_config_dir - extra_vars = { - 'plan': stack.stack_name, - 'config_dir': config_dir, - 'preserve_config': preserve_config_dir - } - if parsed_args.config_type: - extra_vars['config_type'] = config_type + parsed_args.stack, + status='DEPLOYING', + working_dir=self.working_dir + ) - with utils.TempDirs() as tmp: - utils.run_ansible_playbook( - playbook='cli-config-download-export.yaml', - inventory='localhost,', - workdir=tmp, - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=utils.playbook_verbosity(self=self), - extra_vars=extra_vars - ) + deployment_options = {} + if parsed_args.deployment_python_interpreter: + deployment_options['ansible_python_interpreter'] = \ + parsed_args.deployment_python_interpreter + + deployment.make_config_download_dir(config_download_dir, + parsed_args.stack) + + deployment.config_download( + self.log, + self.clients, + parsed_args.stack, + parsed_args.overcloud_ssh_network, + config_download_dir, + parsed_args.override_ansible_cfg, + timeout=parsed_args.overcloud_ssh_port_timeout, + verbosity=utils.playbook_verbosity(self=self), + deployment_options=deployment_options, + in_flight_validations=parsed_args.inflight, + deployment_timeout=timeout, + tags=parsed_args.tags, + skip_tags=parsed_args.skip_tags, + limit_hosts=utils.playbook_limit_parse( + limit_nodes=parsed_args.limit + ), + forks=parsed_args.ansible_forks, + denyed_hostnames=utils.get_stack_saved_output_item( + 'BlacklistedHostnames', self.working_dir)) + deployment.set_deployment_status( + parsed_args.stack, + status=deploy_status, + working_dir=self.working_dir) except (BaseException, Exception): with excutils.save_and_reraise_exception(): deploy_status = 'DEPLOY_FAILED' @@ -1286,7 +1311,7 @@ class DeployOvercloud(command.Command): finally: try: # Run postconfig on create or force - if (stack_create or parsed_args.force_postconfig + if (stack or parsed_args.force_postconfig and not parsed_args.skip_postconfig): self._deploy_postconfig(stack, parsed_args) except Exception as e: @@ -1327,11 +1352,13 @@ class DeployOvercloud(command.Command): self.log.error('Exception creating overcloud export.') self.log.error(e) - print("Overcloud Endpoint: {0}".format(overcloud_endpoint)) - print("Overcloud Horizon Dashboard URL: {0}".format(horizon_url)) - print("Overcloud rc file: {} and {}".format( - rcpath, old_rcpath)) - print("Overcloud Deployed {0}".format(deploy_message)) + if do_config_download: + print("Overcloud Endpoint: {0}".format(overcloud_endpoint)) + print("Overcloud Horizon Dashboard URL: {0}".format( + horizon_url)) + print("Overcloud rc file: {} and {}".format( + rcpath, old_rcpath)) + print("Overcloud Deployed {0}".format(deploy_message)) try: if parsed_args.heat_type != 'installed': diff --git a/tripleoclient/v1/overcloud_upgrade.py b/tripleoclient/v1/overcloud_upgrade.py index 172011698..9b04709e6 100644 --- a/tripleoclient/v1/overcloud_upgrade.py +++ b/tripleoclient/v1/overcloud_upgrade.py @@ -71,9 +71,9 @@ class UpgradePrepare(DeployOvercloud): clients = self.app.client_manager # In case of update and upgrade we need to force the - # config_download to false. The heat stack update will be performed + # stack_only to true. The heat stack update will be performed # by DeployOvercloud class but skipping the config download part. - parsed_args.config_download = False + parsed_args.stack_only = True # Add the template attribute environment to set noops etc templates_dir = (parsed_args.templates or constants.TRIPLEO_HEAT_TEMPLATES) diff --git a/tripleoclient/workflows/deployment.py b/tripleoclient/workflows/deployment.py index 1f62ada75..ff2876ce1 100644 --- a/tripleoclient/workflows/deployment.py +++ b/tripleoclient/workflows/deployment.py @@ -385,30 +385,6 @@ def config_download(log, clients, stack_name, ssh_network='ctlplane', ':'.join(['!{}'.format(i) for i in denyed_hostnames if i])) - key_file = utils.get_key(stack_name) - python_interpreter = deployment_options.get('ansible_python_interpreter') - - playbook = 'cli-config-download.yaml' - ansible_work_dir = os.path.join( - working_dir, os.path.splitext(playbook)[0]) - utils.run_ansible_playbook( - playbook=playbook, - inventory='localhost,', - workdir=ansible_work_dir, - playbook_dir=ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=verbosity, - reproduce_command=True, - extra_vars={ - 'plan': stack_name, - 'output_dir': output_dir, - 'ansible_ssh_user': ssh_user, - 'ansible_ssh_private_key_file': key_file, - 'ssh_network': ssh_network, - 'python_interpreter': python_interpreter, - 'inventory_path': inventory_path - } - ) - _log_and_print( message='Executing deployment playbook for stack: {}'.format( stack_name @@ -438,7 +414,7 @@ def config_download(log, clients, stack_name, ssh_network='ctlplane', ansible_cfg=override_ansible_cfg, verbosity=verbosity, ssh_user=ssh_user, - key=key_file, + key=utils.get_key(stack_name), limit_hosts=limit_hosts, ansible_timeout=timeout, reproduce_command=True,