From 33d8e1f8d544b6fdf97ae9e1e1496e316d4da617 Mon Sep 17 00:00:00 2001 From: Yuxing Jiang Date: Mon, 17 Aug 2020 17:15:00 -0400 Subject: [PATCH] Add an CLI command to reinstall a subcloud This commit adds a new CLI command to reinstall a subcloud with its previous install configurations. The reinstall process will reuse the previous install values and use the same software version as the system controller. CLI format: dcmanager subcloud reinstall Users are required to type "reinstall" to start the reinstall, any other input will abort the reinstall operation. After the reinstall and bootstrap tasks complete a subcloud reconfigure command with deploy_config file is expected to deploy the subcloud and make it online. Tests see in https://review.opendev.org/#/c/746615/. Change-Id: Iecc439ae23cc0f018bcc3d1eebcbf1d0a8b29d45 Story: 2007267 Task: 40731 Depends-On: https://review.opendev.org/#/c/746615/ Signed-off-by: Yuxing Jiang --- .../api/v1/subcloud_manager.py | 18 ++++++++- .../commands/v1/subcloud_manager.py | 37 +++++++++++++++++++ .../dcmanagerclient/shell.py | 1 + .../tests/v1/test_subcloud_manager.py | 16 ++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/distributedcloud-client/dcmanagerclient/api/v1/subcloud_manager.py b/distributedcloud-client/dcmanagerclient/api/v1/subcloud_manager.py index 1cc789d..b1b5915 100644 --- a/distributedcloud-client/dcmanagerclient/api/v1/subcloud_manager.py +++ b/distributedcloud-client/dcmanagerclient/api/v1/subcloud_manager.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# Copyright (c) 2017-2019 Wind River Systems, Inc. +# Copyright (c) 2017-2020 Wind River Systems, Inc. # # The right to copy, distribute, modify, or otherwise make use # of this software may be licensed only pursuant to the terms @@ -128,6 +128,18 @@ class subcloud_manager(base.ResourceManager): resource.append(self.json_to_resource(json_object)) return resource + def subcloud_reinstall(self, url): + fields = dict() + enc = MultipartEncoder(fields=fields) + headers = {'Content-Type': enc.content_type} + resp = self.http_client.patch(url, enc, headers=headers) + if resp.status_code != 200: + self._raise_api_exception(resp) + json_object = get_json(resp) + resource = list() + resource.append(self.json_to_resource(json_object)) + return resource + def subcloud_list(self, url): resp = self.http_client.get(url) if resp.status_code != 200: @@ -224,3 +236,7 @@ class subcloud_manager(base.ResourceManager): data = kwargs.get('data') url = '/subclouds/%s/reconfigure' % subcloud_ref return self.subcloud_reconfigure(url, files, data) + + def reinstall_subcloud(self, subcloud_ref): + url = '/subclouds/%s/reinstall' % subcloud_ref + return self.subcloud_reinstall(url) diff --git a/distributedcloud-client/dcmanagerclient/commands/v1/subcloud_manager.py b/distributedcloud-client/dcmanagerclient/commands/v1/subcloud_manager.py index 8d5ee2d..f3435ed 100644 --- a/distributedcloud-client/dcmanagerclient/commands/v1/subcloud_manager.py +++ b/distributedcloud-client/dcmanagerclient/commands/v1/subcloud_manager.py @@ -22,6 +22,7 @@ import base64 import getpass import os +import six from osc_lib.command import command @@ -557,3 +558,39 @@ class ReconfigSubcloud(base.DCManagerShowOne): except Exception: error_msg = "Unable to reconfigure subcloud %s" % (subcloud_ref) raise exceptions.DCManagerClientException(error_msg) + + +class ReinstallSubcloud(base.DCManagerShowOne): + """Reinstall a subcloud.""" + + def _get_format_function(self): + return detail_format + + def get_parser(self, prog_name): + parser = super(ReinstallSubcloud, self).get_parser(prog_name) + + parser.add_argument( + 'subcloud', + help='Name or ID of the subcloud to reinstall.' + ) + return parser + + def _get_resources(self, parsed_args): + subcloud_ref = parsed_args.subcloud + dcmanager_client = self.app.client_manager.subcloud_manager + + # Require user to type reinstall to confirm + print("WARNING: This will reinstall the subcloud. " + "All applications and data on the subcloud will be lost.") + confirm = six.moves.input( + "Please type \"reinstall\" to confirm:").strip().lower() + if confirm == 'reinstall': + try: + return dcmanager_client.subcloud_manager.reinstall_subcloud( + subcloud_ref=subcloud_ref) + except Exception: + error_msg = "Unable to reinstall subcloud %s" % (subcloud_ref) + raise exceptions.DCManagerClientException(error_msg) + else: + msg = "Subcloud %s will not be reinstalled" % (subcloud_ref) + raise exceptions.DCManagerClientException(msg) diff --git a/distributedcloud-client/dcmanagerclient/shell.py b/distributedcloud-client/dcmanagerclient/shell.py index 6665f8d..1b3525c 100644 --- a/distributedcloud-client/dcmanagerclient/shell.py +++ b/distributedcloud-client/dcmanagerclient/shell.py @@ -490,6 +490,7 @@ class DCManagerShell(app.App): 'subcloud manage': sm.ManageSubcloud, 'subcloud update': sm.UpdateSubcloud, 'subcloud reconfig': sm.ReconfigSubcloud, + 'subcloud reinstall': sm.ReinstallSubcloud, 'subcloud-group add': gm.AddSubcloudGroup, 'subcloud-group delete': gm.DeleteSubcloudGroup, 'subcloud-group list': gm.ListSubcloudGroup, diff --git a/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py b/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py index fb185ba..fb9e5b4 100644 --- a/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py +++ b/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py @@ -314,3 +314,19 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest): app_args=[ID, '--deploy-config', file_path]) self.assertTrue('deploy-config file does not exist' in str(e)) + + @mock.patch('six.moves.input', return_value='reinstall') + def test_reinstall_subcloud(self, mock_input): + self.client.subcloud_manager.reinstall_subcloud.\ + return_value = [SUBCLOUD] + actual_call = self.call( + subcloud_cmd.ReinstallSubcloud, app_args=[ID]) + self.assertEqual((ID, NAME, + DESCRIPTION, LOCATION, + SOFTWARE_VERSION, MANAGEMENT_STATE, + AVAILABILITY_STATUS, DEPLOY_STATUS, + MANAGEMENT_SUBNET, MANAGEMENT_START_IP, + MANAGEMENT_END_IP, MANAGEMENT_GATEWAY_IP, + SYSTEMCONTROLLER_GATEWAY_IP, + DEFAULT_SUBCLOUD_GROUP_ID, + TIME_NOW, TIME_NOW), actual_call[1])