Merge "Add subcloud enroll command"
This commit is contained in:
commit
0e7b4f5d93
@ -79,3 +79,9 @@ class PhasedSubcloudDeployManager(base.ResourceManager):
|
||||
files = kwargs.get("files")
|
||||
url = BASE_URL + f"{subcloud_ref}/resume"
|
||||
return self._deploy_operation(url, files, data, method="patch")
|
||||
|
||||
def subcloud_deploy_enroll(self, subcloud_ref, **kwargs):
|
||||
data = kwargs.get("data")
|
||||
files = kwargs.get("files")
|
||||
url = BASE_URL + f"{subcloud_ref}/enroll"
|
||||
return self._deploy_operation(url, files, data, method="patch")
|
||||
|
@ -147,13 +147,7 @@ class PhasedSubcloudDeployResume(base.DCManagerShowOne):
|
||||
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:
|
||||
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"))
|
||||
utils.set_sysadmin_password(parsed_args, data)
|
||||
|
||||
if parsed_args.install_values:
|
||||
if parsed_args.bmc_password:
|
||||
@ -336,13 +330,7 @@ class InstallPhasedSubcloudDeploy(base.DCManagerShowOne):
|
||||
data = {}
|
||||
|
||||
# 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"))
|
||||
utils.set_sysadmin_password(parsed_args, data)
|
||||
|
||||
if parsed_args.install_values is not None:
|
||||
if not os.path.isfile(parsed_args.install_values):
|
||||
@ -428,13 +416,7 @@ class BootstrapPhasedSubcloudDeploy(base.DCManagerShowOne):
|
||||
files["bootstrap_values"] = parsed_args.bootstrap_values
|
||||
|
||||
# Prompt the user for the subcloud's password if it isn't provided
|
||||
if parsed_args.sysadmin_password:
|
||||
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"))
|
||||
utils.set_sysadmin_password(parsed_args, data)
|
||||
|
||||
subcloud_ref = parsed_args.subcloud
|
||||
|
||||
@ -488,13 +470,7 @@ class ConfigPhasedSubcloudDeploy(base.DCManagerShowOne):
|
||||
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"))
|
||||
utils.set_sysadmin_password(parsed_args, data)
|
||||
|
||||
try:
|
||||
return phased_subcloud_deploy_manager.subcloud_deploy_config(
|
||||
@ -537,3 +513,106 @@ class CompletePhasedSubcloudDeploy(base.DCManagerShowOne):
|
||||
f"Unable to complete the deployment of subcloud {subcloud_ref}"
|
||||
)
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
|
||||
class EnrollPhasedSubcloudDeploy(base.DCManagerShowOne):
|
||||
"""Enrolls a subcloud."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return utils.subcloud_detail_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
"subcloud", help="Name or ID of the subcloud to enroll."
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--install-values",
|
||||
required=False,
|
||||
help="YAML file containing parameters required for the "
|
||||
"enrollment of the subcloud.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--deploy-config",
|
||||
required=False,
|
||||
help="YAML file containing parameters required for the initial "
|
||||
"configuration and unlock of the subcloud.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--bootstrap-address",
|
||||
required=False,
|
||||
help="IP address for initial subcloud controller.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--bootstrap-values",
|
||||
required=False,
|
||||
help="YAML file containing the parameters required for the "
|
||||
"subcloud enrollment.",
|
||||
)
|
||||
|
||||
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.",
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
phased_subcloud_deploy_manager = (
|
||||
self.app.client_manager.phased_subcloud_deploy_manager
|
||||
)
|
||||
files = {}
|
||||
data = {}
|
||||
|
||||
if parsed_args.bootstrap_address:
|
||||
data["bootstrap-address"] = parsed_args.bootstrap_address
|
||||
|
||||
# Get the bootstrap values yaml file
|
||||
if parsed_args.bootstrap_values:
|
||||
if not os.path.isfile(parsed_args.bootstrap_values):
|
||||
error_msg = (
|
||||
"bootstrap-values does not exist: "
|
||||
f"{parsed_args.bootstrap_values}"
|
||||
)
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files["bootstrap_values"] = parsed_args.bootstrap_values
|
||||
|
||||
if parsed_args.install_values:
|
||||
if not os.path.isfile(parsed_args.install_values):
|
||||
error_msg = (
|
||||
f"install-values does not exist: {parsed_args.install_values}"
|
||||
)
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files["install_values"] = parsed_args.install_values
|
||||
|
||||
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"))
|
||||
|
||||
utils.set_sysadmin_password(parsed_args, data)
|
||||
|
||||
subcloud_ref = parsed_args.subcloud
|
||||
|
||||
return phased_subcloud_deploy_manager.subcloud_deploy_enroll(
|
||||
subcloud_ref, files=files, data=data
|
||||
)
|
||||
|
@ -264,6 +264,13 @@ class AddSubcloud(base.DCManagerShowOne):
|
||||
"release of the system controller will be used.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--enroll",
|
||||
required=False,
|
||||
action="store_true",
|
||||
help="Enroll a subcloud",
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
@ -303,6 +310,10 @@ class AddSubcloud(base.DCManagerShowOne):
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files["deploy_config"] = parsed_args.deploy_config
|
||||
|
||||
if parsed_args.migrate and parsed_args.enroll:
|
||||
error_msg = "cannot run migrate and enroll commands together"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
# 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(
|
||||
@ -327,6 +338,9 @@ class AddSubcloud(base.DCManagerShowOne):
|
||||
if parsed_args.migrate:
|
||||
data["migrate"] = "true"
|
||||
|
||||
if parsed_args.enroll:
|
||||
data["enroll"] = "true"
|
||||
|
||||
if parsed_args.release is not None:
|
||||
data["release"] = parsed_args.release
|
||||
|
||||
@ -338,6 +352,10 @@ class AddSubcloud(base.DCManagerShowOne):
|
||||
--migrate option."
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
if parsed_args.release and parsed_args.enroll:
|
||||
error_msg = "Enroll does not support backwards compatibility."
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
result = subcloud_manager.add_subcloud(files=files, data=data)
|
||||
update_fields_values(result)
|
||||
return result
|
||||
|
@ -601,6 +601,7 @@ class DCManagerShell(app.App):
|
||||
"subcloud deploy delete": sdm.SubcloudDeployDelete,
|
||||
"subcloud deploy install": psdm.InstallPhasedSubcloudDeploy,
|
||||
"subcloud deploy resume": psdm.PhasedSubcloudDeployResume,
|
||||
"subcloud deploy enroll": psdm.EnrollPhasedSubcloudDeploy,
|
||||
"subcloud deploy show": sdm.SubcloudDeployShow,
|
||||
"subcloud deploy upload": sdm.SubcloudDeployUpload,
|
||||
"subcloud errors": sm.ShowSubcloudError,
|
||||
|
@ -271,3 +271,57 @@ class TestCLIPhasedSubcloudDeployManagerV1(base.BaseCommandTest):
|
||||
],
|
||||
)
|
||||
self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST_WITH_PEERID, actual_call[1])
|
||||
|
||||
def test_subcloud_deploy_enroll(self):
|
||||
self.client.subcloud_deploy_enroll.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(
|
||||
cmd.EnrollPhasedSubcloudDeploy,
|
||||
app_args=[
|
||||
base.ID,
|
||||
"--bootstrap-address",
|
||||
base.BOOTSTRAP_ADDRESS,
|
||||
"--bootstrap-values",
|
||||
bootstrap_file_path,
|
||||
"--install-values",
|
||||
install_file_path,
|
||||
"--deploy-config",
|
||||
config_file_path
|
||||
],
|
||||
)
|
||||
self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST_WITH_PEERID, actual_call[1])
|
||||
|
||||
def test_subcloud_deploy_enroll_only_required_params(self):
|
||||
self.client.subcloud_deploy_enroll.return_value = [base.SUBCLOUD_RESOURCE]
|
||||
|
||||
actual_call = self.call(
|
||||
cmd.EnrollPhasedSubcloudDeploy,
|
||||
app_args=[
|
||||
base.NAME
|
||||
],
|
||||
)
|
||||
self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST_WITH_PEERID, actual_call[1])
|
||||
|
||||
def test_subcloud_deploy_enroll_invalid_bootstrap_file_path(self):
|
||||
self.client.subcloud_deploy_enroll.return_value = [base.SUBCLOUD_RESOURCE]
|
||||
|
||||
self.assertRaises(
|
||||
DCManagerClientException,
|
||||
self.call, cmd.EnrollPhasedSubcloudDeploy,
|
||||
app_args=[
|
||||
base.ID,
|
||||
"--bootstrap-values",
|
||||
"missing_path"
|
||||
]
|
||||
)
|
||||
|
@ -240,6 +240,51 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
||||
result_list[1] = base.NAME_SC2
|
||||
self.assertEqual(tuple(result_list), actual_call[1])
|
||||
|
||||
@mock.patch("getpass.getpass", return_value="testpassword")
|
||||
def test_add_enroll_subcloud(self, _mock_getpass):
|
||||
self.client.subcloud_manager.add_subcloud.return_value = [
|
||||
self.subcloud_resource
|
||||
]
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w") as f:
|
||||
yaml.dump(base.FAKE_BOOTSTRAP_VALUES, f)
|
||||
file_path = os.path.abspath(f.name)
|
||||
actual_call = self.call(
|
||||
subcloud_cmd.AddSubcloud,
|
||||
app_args=[
|
||||
"--bootstrap-address",
|
||||
base.BOOTSTRAP_ADDRESS,
|
||||
"--bootstrap-values",
|
||||
file_path,
|
||||
"--enroll",
|
||||
],
|
||||
)
|
||||
self.assertEqual(base.SUBCLOUD_FIELD_RESULT_LIST_WITH_PEERID, actual_call[1])
|
||||
|
||||
@mock.patch("getpass.getpass", return_value="testpassword")
|
||||
def test_subcloud_enroll_failure_invalid_parameter(self, _mock_getpass):
|
||||
self.client.subcloud_manager.add_subcloud.return_value = [
|
||||
self.subcloud_resource
|
||||
]
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w") as f:
|
||||
yaml.dump(base.FAKE_BOOTSTRAP_VALUES, f)
|
||||
file_path = os.path.abspath(f.name)
|
||||
|
||||
self.assertRaises(
|
||||
DCManagerClientException,
|
||||
self.call,
|
||||
subcloud_cmd.AddSubcloud,
|
||||
app_args=[
|
||||
"--bootstrap-address",
|
||||
base.BOOTSTRAP_ADDRESS,
|
||||
"--bootstrap-values",
|
||||
file_path,
|
||||
"--enroll",
|
||||
"--migrate"
|
||||
]
|
||||
)
|
||||
|
||||
def test_rename_subcloud(self):
|
||||
subcloud_renamed = copy.copy(base.SUBCLOUD_RESOURCE_WITH_PEERID)
|
||||
subcloud_renamed.name = base.NAME_SC2
|
||||
|
@ -19,6 +19,7 @@
|
||||
import getpass
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
from urllib import parse, request
|
||||
|
||||
import yaml
|
||||
@ -166,3 +167,14 @@ def subcloud_detail_format(subcloud=None):
|
||||
data = (("<none>",) * len(columns),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def set_sysadmin_password(parsed_args, data):
|
||||
|
||||
if parsed_args.sysadmin_password:
|
||||
data["sysadmin_password"] = base64.b64encode(
|
||||
parsed_args.sysadmin_password.encode("utf-8")
|
||||
)
|
||||
else:
|
||||
password = prompt_for_password()
|
||||
data["sysadmin_password"] = base64.b64encode(password.encode("utf-8"))
|
||||
|
Loading…
x
Reference in New Issue
Block a user