Add enroll command to backend
This commit introduces the enroll command endpoint. Test Plan: PASS: Deploy a system controller and run subcloud add enroll without bootstrap-values. Verify that the API returns an error. PASS: Deploy a system controller and run subcloud add enroll passing all required parameters. Verify in dcmanager log that the API returned a success code. Change-Id: I525d26166dbb7d7afcb26b96191b5045eee7b52d Signed-off-by: Gustavo Pereira <gustavo.lyrapereira@windriver.com>
This commit is contained in:
parent
9bf56e9e30
commit
3c9a9314ca
@ -34,6 +34,7 @@ CONFIG = consts.DEPLOY_PHASE_CONFIG
|
||||
COMPLETE = consts.DEPLOY_PHASE_COMPLETE
|
||||
ABORT = consts.DEPLOY_PHASE_ABORT
|
||||
RESUME = consts.DEPLOY_PHASE_RESUME
|
||||
ENROLL = consts.DEPLOY_PHASE_ENROLL
|
||||
|
||||
SUBCLOUD_CREATE_REQUIRED_PARAMETERS = (
|
||||
consts.BOOTSTRAP_VALUES,
|
||||
@ -55,6 +56,10 @@ SUBCLOUD_BOOTSTRAP_GET_FILE_CONTENTS = (
|
||||
consts.BOOTSTRAP_VALUES,
|
||||
)
|
||||
|
||||
SUBCLOUD_ENROLL_GET_FILE_CONTENTS = (
|
||||
consts.BOOTSTRAP_VALUES,
|
||||
)
|
||||
|
||||
SUBCLOUD_CONFIG_GET_FILE_CONTENTS = (
|
||||
consts.DEPLOY_CONFIG,
|
||||
)
|
||||
@ -92,6 +97,12 @@ VALID_STATES_FOR_DEPLOY_ABORT = (
|
||||
consts.DEPLOY_STATE_CONFIGURING
|
||||
)
|
||||
|
||||
VALID_STATES_FOR_DEPLOY_ENROLL = (
|
||||
consts.DEPLOY_STATE_CREATED,
|
||||
consts.DEPLOY_STATE_ENROLL_FAILED,
|
||||
consts.DEPLOY_STATE_ENROLLED,
|
||||
)
|
||||
|
||||
FILES_FOR_RESUME_INSTALL = \
|
||||
SUBCLOUD_INSTALL_GET_FILE_CONTENTS + \
|
||||
SUBCLOUD_BOOTSTRAP_GET_FILE_CONTENTS + \
|
||||
@ -506,6 +517,39 @@ class PhasedSubcloudDeployController(object):
|
||||
LOG.exception("Unable to resume subcloud %s deployment" % subcloud.name)
|
||||
pecan.abort(500, _('Unable to resume subcloud deployment'))
|
||||
|
||||
def _deploy_enroll(self, context: RequestContext,
|
||||
request: pecan.Request, subcloud: models.Subcloud):
|
||||
if subcloud.deploy_status not in VALID_STATES_FOR_DEPLOY_ENROLL:
|
||||
valid_states_str = ', '.join(VALID_STATES_FOR_DEPLOY_ENROLL)
|
||||
msg = f'Subcloud deploy status must be either: {valid_states_str}'
|
||||
pecan.abort(400, _(msg))
|
||||
|
||||
has_bootstrap_values = consts.BOOTSTRAP_VALUES in request.POST
|
||||
|
||||
payload = psd_common.get_request_data(
|
||||
request, subcloud, SUBCLOUD_ENROLL_GET_FILE_CONTENTS)
|
||||
|
||||
psd_common.validate_enroll_parameter(payload, request)
|
||||
|
||||
# Try to load the existing override values
|
||||
override_file = psd_common.get_config_file_path(subcloud.name)
|
||||
if os.path.exists(override_file):
|
||||
if not has_bootstrap_values:
|
||||
psd_common.populate_payload_with_pre_existing_data(
|
||||
payload, subcloud, SUBCLOUD_BOOTSTRAP_GET_FILE_CONTENTS)
|
||||
elif not has_bootstrap_values:
|
||||
msg = ("Required bootstrap-values file was not provided and it was "
|
||||
f"not previously available at {override_file}")
|
||||
pecan.abort(400, _(msg))
|
||||
|
||||
payload['software_version'] = subcloud.software_version
|
||||
|
||||
pecan.abort(400, "subcloud deploy enrollment is not "
|
||||
"available yet")
|
||||
# TODO(glyraper): Enroll function in development
|
||||
# TODO(glyraper): Create cover tests
|
||||
return ""
|
||||
|
||||
@pecan.expose(generic=True, template='json')
|
||||
def index(self):
|
||||
# Route the request to specific methods with parameters
|
||||
@ -555,6 +599,8 @@ class PhasedSubcloudDeployController(object):
|
||||
subcloud = self._deploy_config(context, pecan.request, subcloud)
|
||||
elif verb == COMPLETE:
|
||||
subcloud = self._deploy_complete(context, subcloud)
|
||||
elif verb == ENROLL:
|
||||
subcloud = self._deploy_enroll(context, pecan.request, subcloud)
|
||||
else:
|
||||
pecan.abort(400, _('Invalid request'))
|
||||
|
||||
|
@ -561,6 +561,9 @@ class SubcloudsController(object):
|
||||
|
||||
psd_common.validate_secondary_parameter(payload, request)
|
||||
|
||||
if payload.get('enroll'):
|
||||
psd_common.validate_enroll_parameter(payload, request)
|
||||
|
||||
# Compares to match both supplied and bootstrap name param
|
||||
# of the subcloud if migrate is on
|
||||
if payload.get('migrate') == 'true' and bootstrap_sc_name is not None:
|
||||
|
@ -40,6 +40,7 @@ DEPLOY_PHASE_CONFIG = 'configure'
|
||||
DEPLOY_PHASE_COMPLETE = 'complete'
|
||||
DEPLOY_PHASE_ABORT = 'abort'
|
||||
DEPLOY_PHASE_RESUME = 'resume'
|
||||
DEPLOY_PHASE_ENROLL = 'enroll'
|
||||
|
||||
# Admin status for hosts
|
||||
ADMIN_LOCKED = 'locked'
|
||||
@ -217,6 +218,8 @@ DEPLOY_STATE_INSTALL_ABORTED = 'install-aborted'
|
||||
DEPLOY_STATE_ABORTING_BOOTSTRAP = 'aborting-bootstrap'
|
||||
DEPLOY_STATE_ABORTING_CONFIG = 'aborting-config'
|
||||
DEPLOY_STATE_CONFIG_ABORTED = 'config-aborted'
|
||||
DEPLOY_STATE_ENROLLED = 'enroll-complete'
|
||||
DEPLOY_STATE_ENROLL_FAILED = 'enroll-failed'
|
||||
DEPLOY_STATE_MIGRATING_DATA = 'migrating-data'
|
||||
DEPLOY_STATE_DATA_MIGRATION_FAILED = 'data-migration-failed'
|
||||
DEPLOY_STATE_MIGRATED = 'migrated'
|
||||
@ -226,6 +229,7 @@ DEPLOY_STATE_RESTORE_PREP_FAILED = 'restore-prep-failed'
|
||||
DEPLOY_STATE_RESTORING = 'restoring'
|
||||
DEPLOY_STATE_RESTORE_FAILED = 'restore-failed'
|
||||
DEPLOY_STATE_PRE_REHOME = 'pre-rehome'
|
||||
DEPLOY_STATE_PRE_ENROLL = 'pre-enroll'
|
||||
# If any of the following rehoming or secondary statuses
|
||||
# are modified, cert-mon code will need to be updated.
|
||||
DEPLOY_STATE_REHOMING = 'rehoming'
|
||||
|
@ -162,6 +162,13 @@ def validate_migrate_parameter(payload, request):
|
||||
'not allowed'))
|
||||
|
||||
|
||||
def validate_enroll_parameter(payload, request):
|
||||
enroll_str = payload.get('enroll')
|
||||
if enroll_str and enroll_str not in ["true", "false"]:
|
||||
pecan.abort(400, _('The enroll option is invalid, '
|
||||
'valid options are true and false.'))
|
||||
|
||||
|
||||
def validate_secondary_parameter(payload, request):
|
||||
secondary_str = payload.get('secondary')
|
||||
migrate_str = payload.get('migrate')
|
||||
|
@ -844,6 +844,7 @@ class SubcloudManager(manager.Manager):
|
||||
|
||||
rehoming = payload.get('migrate', '').lower() == "true"
|
||||
secondary = (payload.get('secondary', '').lower() == "true")
|
||||
enroll = payload.get('enroll', '').lower() == "true"
|
||||
initial_deployment = True if not rehoming else False
|
||||
|
||||
# Create the subcloud
|
||||
@ -873,8 +874,11 @@ class SubcloudManager(manager.Manager):
|
||||
phases_to_run = []
|
||||
if consts.INSTALL_VALUES in payload:
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_INSTALL)
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_BOOTSTRAP)
|
||||
if consts.DEPLOY_CONFIG in payload:
|
||||
if enroll:
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_ENROLL)
|
||||
else:
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_BOOTSTRAP)
|
||||
if not enroll and consts.DEPLOY_CONFIG in payload:
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_CONFIG)
|
||||
else:
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_COMPLETE)
|
||||
@ -1566,6 +1570,11 @@ class SubcloudManager(manager.Manager):
|
||||
deploy_status=consts.DEPLOY_STATE_PRE_INSTALL_FAILED)
|
||||
return False
|
||||
|
||||
def subcloud_deploy_enroll(self, context, subcloud_id, payload,
|
||||
initial_deployment=False):
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def subcloud_deploy_bootstrap(self, context, subcloud_id, payload,
|
||||
initial_deployment=False):
|
||||
"""Bootstrap subcloud
|
||||
@ -2226,6 +2235,9 @@ class SubcloudManager(manager.Manager):
|
||||
if consts.DEPLOY_PHASE_INSTALL in deploy_phases_to_run:
|
||||
succeeded = self.subcloud_deploy_install(
|
||||
context, subcloud_id, payload, initial_deployment)
|
||||
if succeeded and consts.DEPLOY_PHASE_ENROLL in deploy_phases_to_run:
|
||||
succeeded = self.subcloud_deploy_enroll(
|
||||
context, subcloud_id, payload, initial_deployment)
|
||||
if succeeded and consts.DEPLOY_PHASE_BOOTSTRAP in deploy_phases_to_run:
|
||||
succeeded = self.subcloud_deploy_bootstrap(
|
||||
context, subcloud_id, payload, initial_deployment)
|
||||
|
@ -1075,3 +1075,32 @@ class TestPhasedSubcloudDeployPatchResume(BaseTestPhasedSubcloudDeployPatch):
|
||||
"Unable to resume subcloud deployment"
|
||||
)
|
||||
self.mock_rpc_client().subcloud_deploy_resume.assert_called_once()
|
||||
|
||||
|
||||
class TestSubcloudDeployEnroll(BaseTestPhasedSubcloudDeployPatch):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.url = f"{self.url}/enroll"
|
||||
|
||||
self._update_subcloud(
|
||||
deploy_status=consts.DEPLOY_STATE_CREATED, software_version=SW_VERSION
|
||||
)
|
||||
|
||||
modified_bootstrap_data = copy.copy(fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA)
|
||||
fake_content = json.dumps(modified_bootstrap_data).encode("utf-8")
|
||||
|
||||
self.upload_files = \
|
||||
[("bootstrap_values", "bootstrap_fake_filename", fake_content)]
|
||||
|
||||
def test_patch_enroll_fails(self):
|
||||
"""Test patch enroll fails"""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
# self._assert_response(response)
|
||||
# self._assert_payload()
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "subcloud deploy enrollment is not "
|
||||
"available yet"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user