From c5f5a172b8352ff4414ee61d44a40b8bf51f0c20 Mon Sep 17 00:00:00 2001 From: Victor Romano Date: Tue, 16 May 2023 11:19:49 -0300 Subject: [PATCH] Add the subcloud deploy config option to dcmanager This commit adds the command "subcloud deploy config" to dcmanager client. It has the same options as "subcloud reconfig". Usage: dcmanager subcloud deploy config --sysadmin-password [--deploy-config ] Test Plan: - PASS: Verify the command works with or without --deploy-config. - PASS: Verify that, when provided, the deploy-config is successfully passed to backend. Depends-on: https://review.opendev.org/c/starlingx/distcloud/+/883265 Story: 2010756 Task: 48023 Signed-off-by: Victor Romano Change-Id: I48919ac0e7cf2fc6c2975ee0e95439a934f37211 --- .../api/v1/phased_subcloud_deploy_manager.py | 6 ++ .../v1/phased_subcloud_deploy_manager.py | 63 +++++++++++++++++++ .../dcmanagerclient/shell.py | 1 + .../tests/v1/test_phased_subcloud_deploy.py | 31 ++++++++- 4 files changed, 100 insertions(+), 1 deletion(-) diff --git a/distributedcloud-client/dcmanagerclient/api/v1/phased_subcloud_deploy_manager.py b/distributedcloud-client/dcmanagerclient/api/v1/phased_subcloud_deploy_manager.py index b9ac971..55f3225 100644 --- a/distributedcloud-client/dcmanagerclient/api/v1/phased_subcloud_deploy_manager.py +++ b/distributedcloud-client/dcmanagerclient/api/v1/phased_subcloud_deploy_manager.py @@ -48,3 +48,9 @@ class phased_subcloud_deploy_manager(base.ResourceManager): files = kwargs.get('files') url = BASE_URL + "%s/bootstrap" % subcloud_ref return self._deploy_operation(url, files, data, "patch") + + def subcloud_deploy_config(self, subcloud_ref, **kwargs): + data = kwargs.get('data') + files = kwargs.get('files') + url = BASE_URL + "%s/configure" % subcloud_ref + return self._deploy_operation(url, files, data, method='patch') diff --git a/distributedcloud-client/dcmanagerclient/commands/v1/phased_subcloud_deploy_manager.py b/distributedcloud-client/dcmanagerclient/commands/v1/phased_subcloud_deploy_manager.py index 7683f4f..379caaa 100644 --- a/distributedcloud-client/dcmanagerclient/commands/v1/phased_subcloud_deploy_manager.py +++ b/distributedcloud-client/dcmanagerclient/commands/v1/phased_subcloud_deploy_manager.py @@ -186,3 +186,66 @@ class BootstrapPhasedSubcloudDeploy(base.DCManagerShowOne): return dcmanager_client.subcloud_deploy_bootstrap( subcloud_ref, files=files, data=data) + + +class ConfigPhasedSubcloudDeploy(base.DCManagerShowOne): + """Configure a subcloud.""" + + def _get_format_function(self): + return utils.subcloud_detail_format + + def get_parser(self, prog_name): + parser = super(ConfigPhasedSubcloudDeploy, self).get_parser(prog_name) + + parser.add_argument( + 'subcloud', + help='Name or ID of the subcloud to update.' + ) + + parser.add_argument( + '--deploy-config', + required=False, + help='YAML file containing subcloud variables to be passed to the ' + 'deploy playbook.' + ) + + parser.add_argument( + '--sysadmin-password', + required=False, + help='sysadmin password of the subcloud to be configured, ' + 'if not provided you will be prompted.' + ) + + return parser + + def _get_resources(self, parsed_args): + subcloud_ref = parsed_args.subcloud + dcmanager_client = self.app.client_manager.\ + phased_subcloud_deploy_manager.phased_subcloud_deploy_manager + files = dict() + data = dict() + + # Get the deploy config yaml file + if parsed_args.deploy_config is not None: + if not os.path.isfile(parsed_args.deploy_config): + error_msg = "deploy-config file does not exist: %s" % \ + parsed_args.deploy_config + raise exceptions.DCManagerClientException(error_msg) + files['deploy_config'] = parsed_args.deploy_config + + # Prompt the user for the subcloud's password if it isn't provided + if parsed_args.sysadmin_password is not None: + data['sysadmin_password'] = base64.b64encode( + parsed_args.sysadmin_password.encode("utf-8")) + else: + password = utils.prompt_for_password() + data["sysadmin_password"] = base64.b64encode( + password.encode("utf-8")) + + try: + return dcmanager_client.subcloud_deploy_config( + subcloud_ref=subcloud_ref, files=files, data=data) + except Exception as e: + print(e) + error_msg = "Unable to configure subcloud %s" % (subcloud_ref) + raise exceptions.DCManagerClientException(error_msg) diff --git a/distributedcloud-client/dcmanagerclient/shell.py b/distributedcloud-client/dcmanagerclient/shell.py index 383454b..2a3660e 100644 --- a/distributedcloud-client/dcmanagerclient/shell.py +++ b/distributedcloud-client/dcmanagerclient/shell.py @@ -546,6 +546,7 @@ class DCManagerShell(app.App): 'subcloud-group update': gm.UpdateSubcloudGroup, 'subcloud deploy create': psdm.CreatePhasedSubcloudDeploy, 'subcloud deploy bootstrap': psdm.BootstrapPhasedSubcloudDeploy, + 'subcloud deploy config': psdm.ConfigPhasedSubcloudDeploy, 'subcloud-deploy upload': sdm.SubcloudDeployUpload, 'subcloud-deploy show': sdm.SubcloudDeployShow, 'alarm summary': am.ListAlarmSummary, diff --git a/distributedcloud-client/dcmanagerclient/tests/v1/test_phased_subcloud_deploy.py b/distributedcloud-client/dcmanagerclient/tests/v1/test_phased_subcloud_deploy.py index b59da33..b38e155 100644 --- a/distributedcloud-client/dcmanagerclient/tests/v1/test_phased_subcloud_deploy.py +++ b/distributedcloud-client/dcmanagerclient/tests/v1/test_phased_subcloud_deploy.py @@ -4,11 +4,13 @@ # SPDX-License-Identifier: Apache-2.0 # -import mock import os import tempfile +import mock + from dcmanagerclient.commands.v1 import phased_subcloud_deploy_manager as cmd +from dcmanagerclient.exceptions import DCManagerClientException from dcmanagerclient.tests import base @@ -57,3 +59,30 @@ class TestCLIPhasedSubcloudDeployManagerV1(base.BaseCommandTest): '--bootstrap-values', bootstrap_file_path, ]) self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST, actual_call[1]) + + @mock.patch('getpass.getpass', return_value='testpassword') + def test_success_configure_subcloud(self, getpass): + self.client.subcloud_deploy_config.return_value = [ + base.SUBCLOUD_RESOURCE] + + with tempfile.NamedTemporaryFile() as f: + file_path = os.path.abspath(f.name) + actual_call = self.call( + cmd.ConfigPhasedSubcloudDeploy, + app_args=[base.NAME, '--deploy-config', file_path]) + self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST, actual_call[1]) + + @mock.patch('getpass.getpass', return_value='testpassword') + def test_configure_file_does_not_exist(self, getpass): + self.client.subcloud_deploy_config.return_value = [ + base.SUBCLOUD_RESOURCE] + + with tempfile.NamedTemporaryFile() as f: + file_path = os.path.abspath(f.name) + + e = self.assertRaises(DCManagerClientException, + self.call, + cmd.ConfigPhasedSubcloudDeploy, + app_args=[base.NAME, + '--deploy-config', file_path]) + self.assertTrue('deploy-config file does not exist' in str(e))