Merge "Add subcloud redeploy option to dcmanager"
This commit is contained in:
commit
b6723b8f67
|
@ -90,6 +90,21 @@ class subcloud_manager(base.ResourceManager):
|
|||
resource.append(self.json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def subcloud_redeploy(self, url, body, data):
|
||||
fields = dict()
|
||||
for k, v in body.items():
|
||||
fields.update({k: (v, open(v, 'rb'),)})
|
||||
fields.update(data)
|
||||
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_prestage(self, url, data):
|
||||
data = json.dumps(data)
|
||||
resp = self.http_client.patch(url, data)
|
||||
|
@ -169,3 +184,9 @@ class subcloud_manager(base.ResourceManager):
|
|||
data = kwargs.get('data')
|
||||
url = '/subclouds/%s/reinstall' % subcloud_ref
|
||||
return self.subcloud_reinstall(url, files, data)
|
||||
|
||||
def redeploy_subcloud(self, subcloud_ref, **kwargs):
|
||||
files = kwargs.get('files')
|
||||
data = kwargs.get('data')
|
||||
url = '/subclouds/%s/redeploy' % subcloud_ref
|
||||
return self.subcloud_redeploy(url, files, data)
|
||||
|
|
|
@ -739,6 +739,134 @@ class ReinstallSubcloud(base.DCManagerShowOne):
|
|||
raise exceptions.DCManagerClientException(msg)
|
||||
|
||||
|
||||
class RedeploySubcloud(base.DCManagerShowOne):
|
||||
"""Redeploy a subcloud."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return detail_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(RedeploySubcloud, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'subcloud',
|
||||
help='Name or ID of the subcloud to redeploy.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--install-values',
|
||||
required=False,
|
||||
help='YAML file containing parameters required for the '
|
||||
'remote install of the subcloud.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--bootstrap-values',
|
||||
required=False,
|
||||
help='YAML file containing subcloud configuration settings. '
|
||||
'Can be either a local file path or a URL.'
|
||||
)
|
||||
|
||||
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.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--bmc-password',
|
||||
required=False,
|
||||
help='bmc password of the subcloud to be configured, if not '
|
||||
'provided you will be prompted. This parameter is only'
|
||||
' valid if the --install-values are specified.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--release',
|
||||
required=False,
|
||||
help='software release used to install, bootstrap and/or deploy '
|
||||
'the subcloud with. If not specified, the current software '
|
||||
'release of the system controller will be used.'
|
||||
)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
subcloud_ref = parsed_args.subcloud
|
||||
dcmanager_client = self.app.client_manager.subcloud_manager
|
||||
files = dict()
|
||||
data = dict()
|
||||
|
||||
# Get the install values yaml file
|
||||
if parsed_args.install_values is not None:
|
||||
if not os.path.isfile(parsed_args.install_values):
|
||||
error_msg = "install-values does not exist: %s" % \
|
||||
parsed_args.install_values
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files['install_values'] = parsed_args.install_values
|
||||
|
||||
# Get the bootstrap values yaml file
|
||||
if parsed_args.bootstrap_values is not None:
|
||||
if not os.path.isfile(parsed_args.bootstrap_values):
|
||||
error_msg = "bootstrap-values does not exist: %s" % \
|
||||
parsed_args.bootstrap_values
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files['bootstrap_values'] = parsed_args.bootstrap_values
|
||||
|
||||
# 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 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"))
|
||||
|
||||
if parsed_args.install_values:
|
||||
if parsed_args.bmc_password:
|
||||
data['bmc_password'] = base64.b64encode(
|
||||
parsed_args.bmc_password.encode("utf-8"))
|
||||
else:
|
||||
password = utils.prompt_for_password('bmc')
|
||||
data["bmc_password"] = base64.b64encode(
|
||||
password.encode("utf-8"))
|
||||
|
||||
if parsed_args.release is not None:
|
||||
data['release'] = parsed_args.release
|
||||
|
||||
# Require user to type redeploy to confirm
|
||||
print("WARNING: This will redeploy the subcloud. "
|
||||
"All applications and data on the subcloud will be lost.")
|
||||
confirm = six.moves.input(
|
||||
"Please type \"redeploy\" to confirm: ").strip().lower()
|
||||
if confirm == 'redeploy':
|
||||
try:
|
||||
return dcmanager_client.subcloud_manager.redeploy_subcloud(
|
||||
subcloud_ref=subcloud_ref, files=files, data=data)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_msg = "Unable to redeploy subcloud %s" % (subcloud_ref)
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
else:
|
||||
msg = "Subcloud %s will not be redeployed" % (subcloud_ref)
|
||||
raise exceptions.DCManagerClientException(msg)
|
||||
|
||||
|
||||
class RestoreSubcloud(base.DCManagerShowOne):
|
||||
"""Restore a subcloud."""
|
||||
|
||||
|
|
|
@ -533,6 +533,7 @@ class DCManagerShell(app.App):
|
|||
'subcloud update': sm.UpdateSubcloud,
|
||||
'subcloud reconfig': sm.ReconfigSubcloud,
|
||||
'subcloud reinstall': sm.ReinstallSubcloud,
|
||||
'subcloud redeploy': sm.RedeploySubcloud,
|
||||
'subcloud restore': sm.RestoreSubcloud,
|
||||
'subcloud prestage': sm.PrestageSubcloud,
|
||||
'subcloud-backup create': sbm.CreateSubcloudBackup,
|
||||
|
|
|
@ -266,6 +266,71 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
self.assertTrue('bootstrap-values does not exist'
|
||||
in str(e))
|
||||
|
||||
@mock.patch('getpass.getpass', return_value='testpassword')
|
||||
@mock.patch('six.moves.input', return_value='redeploy')
|
||||
def test_redeploy_subcloud(self, mock_input, getpass):
|
||||
self.client.subcloud_manager.redeploy_subcloud. \
|
||||
return_value = [base.SUBCLOUD_RESOURCE]
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w') as bootstrap_file,\
|
||||
tempfile.NamedTemporaryFile(mode='w') as config_file,\
|
||||
tempfile.NamedTemporaryFile(mode='w') as install_file:
|
||||
|
||||
bootstrap_file_path = os.path.abspath(bootstrap_file.name)
|
||||
config_file_path = os.path.abspath(config_file.name)
|
||||
install_file_path = os.path.abspath(install_file.name)
|
||||
|
||||
actual_call = self.call(
|
||||
subcloud_cmd.RedeploySubcloud, app_args=[
|
||||
base.NAME,
|
||||
'--bootstrap-values', bootstrap_file_path,
|
||||
'--install-values', install_file_path,
|
||||
'--deploy-config', config_file_path,
|
||||
'--release', base.SOFTWARE_VERSION,
|
||||
])
|
||||
self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST, actual_call[1])
|
||||
|
||||
@mock.patch('getpass.getpass', return_value='testpassword')
|
||||
@mock.patch('six.moves.input', return_value='redeploy')
|
||||
def test_redeploy_subcloud_no_parameters(self, mock_input, getpass):
|
||||
self.client.subcloud_manager.redeploy_subcloud.\
|
||||
return_value = [base.SUBCLOUD_RESOURCE]
|
||||
actual_call = self.call(
|
||||
subcloud_cmd.RedeploySubcloud,
|
||||
app_args=[base.ID])
|
||||
self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST, actual_call[1])
|
||||
|
||||
@mock.patch('getpass.getpass', return_value='testpassword')
|
||||
@mock.patch('six.moves.input', return_value='redeploy')
|
||||
def test_redeploy_bootstrap_files_does_not_exists(
|
||||
self, mock_input, getpass):
|
||||
self.client.subcloud_manager.redeploy_subcloud.\
|
||||
return_value = [base.SUBCLOUD_RESOURCE]
|
||||
with tempfile.NamedTemporaryFile(mode='w') as bootstrap_file,\
|
||||
tempfile.NamedTemporaryFile(mode='w') as config_file,\
|
||||
tempfile.NamedTemporaryFile(mode='w') as install_file:
|
||||
|
||||
bootstrap_file_path = os.path.abspath(bootstrap_file.name)
|
||||
config_file_path = os.path.abspath(config_file.name)
|
||||
install_file_path = os.path.abspath(install_file.name)
|
||||
|
||||
app_args_install = [base.NAME,
|
||||
'--install-values', install_file_path]
|
||||
app_args_bootstrap = [base.NAME,
|
||||
'--bootstrap-values', bootstrap_file_path]
|
||||
app_args_config = [base.NAME, '--deploy-config', config_file_path]
|
||||
args_dict = {'install-values': app_args_install,
|
||||
'bootstrap-values': app_args_bootstrap,
|
||||
'deploy-config': app_args_config}
|
||||
|
||||
for file in ['install-values', 'bootstrap-values',
|
||||
'deploy-config']:
|
||||
e = self.assertRaises(DCManagerClientException,
|
||||
self.call,
|
||||
subcloud_cmd.RedeploySubcloud,
|
||||
app_args=args_dict[file])
|
||||
self.assertTrue(f'{file} does not exist' in str(e))
|
||||
|
||||
@mock.patch('getpass.getpass', return_value='testpassword')
|
||||
def test_restore_subcloud(self, getpass):
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
|
|
Loading…
Reference in New Issue