diff --git a/api-ref/source/api-ref-dcmanager-v1.rst b/api-ref/source/api-ref-dcmanager-v1.rst index 3f6f74b02..2be454753 100644 --- a/api-ref/source/api-ref-dcmanager-v1.rst +++ b/api-ref/source/api-ref-dcmanager-v1.rst @@ -404,151 +404,6 @@ Response Example :language: json -********************************** -Reconfigures a specific subcloud -********************************** - -.. rest_method:: PATCH /v1.0/subclouds/{subcloud}/reconfigure - -The attributes of a subcloud which are modifiable: - -- subcloud configuration (which is provided through deploy_config file) - -**Normal response codes** - -200 - -**Error response codes** - -badRequest (400), unauthorized (401), forbidden (403), badMethod (405), -HTTPUnprocessableEntity (422), internalServerError (500), -serviceUnavailable (503) - -**Request parameters** - -.. rest_parameters:: parameters.yaml - - - subcloud: subcloud_uri - - deploy_config: deploy_config - - sysadmin_password: sysadmin_password - -Accepts Content-Type multipart/form-data - -Request Example ----------------- - -.. literalinclude:: samples/subclouds/subcloud-patch-reconfigure-request.json - :language: json - -**Response parameters** - -.. rest_parameters:: parameters.yaml - - - id: subcloud_id - - group_id: group_id - - name: subcloud_name - - description: subcloud_description - - location: subcloud_location - - software-version: software_version - - availability-status: availability_status - - error-description: error_description - - deploy-status: deploy_status - - backup-status: backup_status - - backup-datetime: backup_datetime - - openstack-installed: openstack_installed - - management-state: management_state - - systemcontroller-gateway-ip: systemcontroller_gateway_ip - - management-start-ip: management_start_ip - - management-end-ip: management_end_ip - - management-subnet: management_subnet - - management-gateway-ip: management_gateway_ip - - created-at: created_at - - updated-at: updated_at - - data_install: data_install - - data_upgrade: data_upgrade - - endpoint_sync_status: endpoint_sync_status - - sync_status: sync_status - - endpoint_type: sync_status_type - -Response Example ----------------- - -.. literalinclude:: samples/subclouds/subcloud-patch-reconfigure-response.json - :language: json - - -******************************** -Reinstalls a specific subcloud -******************************** - -.. rest_method:: PATCH /v1.0/subclouds/{subcloud}/reinstall - -Reinstall and bootstrap a subcloud based on its previous install configurations. -After reinstall, a reconfigure operation with deploy_config file is expected -to deploy the subcloud. - -**Normal response codes** - -200 - -**Error response codes** - -badRequest (400), unauthorized (401), forbidden (403), badMethod (405), -HTTPUnprocessableEntity (422), internalServerError (500), -serviceUnavailable (503) - -**Request parameters** - -.. rest_parameters:: parameters.yaml - - - subcloud: subcloud_uri - - bootstrap_values: bootstrap_values - - deploy_config: deploy_config - - release: release - - sysadmin_password: sysadmin_password - -Request Example ----------------- - -.. literalinclude:: samples/subclouds/subcloud-patch-reinstall-request.json - :language: json - -**Response parameters** - -.. rest_parameters:: parameters.yaml - - - id: subcloud_id - - group_id: group_id - - name: subcloud_name - - description: subcloud_description - - location: subcloud_location - - software-version: software_version - - availability-status: availability_status - - error-description: error_description - - deploy-status: deploy_status - - backup-status: backup_status - - backup-datetime: backup_datetime - - openstack-installed: openstack_installed - - management-state: management_state - - systemcontroller-gateway-ip: systemcontroller_gateway_ip - - management-start-ip: management_start_ip - - management-end-ip: management_end_ip - - management-subnet: management_subnet - - management-gateway-ip: management_gateway_ip - - created-at: created_at - - updated-at: updated_at - - data_install: data_install - - data_upgrade: data_upgrade - - endpoint_sync_status: endpoint_sync_status - - sync_status: sync_status - - endpoint_type: sync_status_type - -Response Example ----------------- - -.. literalinclude:: samples/subclouds/subcloud-patch-reinstall-response.json - :language: json - ******************************** Redeploy a specific subcloud ******************************** @@ -2064,7 +1919,7 @@ Response Example Installs a subcloud ********************************** -.. rest_method:: POST /v1.0/phased-subcloud-deploy/{subcloud}/install +.. rest_method:: PATCH /v1.0/phased-subcloud-deploy/{subcloud}/install **Normal response codes** @@ -2341,7 +2196,7 @@ Response Example Resume subcloud deployment **************************** -.. rest_method:: POST /v1.0/phased-subcloud-deploy +.. rest_method:: PATCH /v1.0/phased-subcloud-deploy/{subcloud}/resume Accepts Content-Type multipart/form-data. @@ -2360,6 +2215,7 @@ serviceUnavailable (503) .. rest_parameters:: parameters.yaml + - subcloud: subcloud_uri - bmc_password: bmc_password - bootstrap-address: bootstrap_address - bootstrap_values: bootstrap_values diff --git a/api-ref/source/samples/subclouds/subcloud-patch-reconfigure-request.json b/api-ref/source/samples/subclouds/subcloud-patch-reconfigure-request.json deleted file mode 100644 index 6abc828f9..000000000 --- a/api-ref/source/samples/subclouds/subcloud-patch-reconfigure-request.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sysadmin_password": "XXXXXXX", - "deploy_config": "path to some file" - -} diff --git a/api-ref/source/samples/subclouds/subcloud-patch-reconfigure-response.json b/api-ref/source/samples/subclouds/subcloud-patch-reconfigure-response.json deleted file mode 100644 index abf248c26..000000000 --- a/api-ref/source/samples/subclouds/subcloud-patch-reconfigure-response.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "id": 1, - "name": "subcloud1", - "created-at": "2021-11-08T18:41:19.530228", - "updated-at": "2021-11-15T14:15:59.944851", - "availability-status": "online", - "data_install": null, - "data_upgrade": null, - "deploy-status": "complete", - "backup-status": "complete", - "backup-datetime": "2022-07-08 11:23:58.132134", - "description": "Ottawa Site", - "group_id": 1, - "location": "YOW", - "management-end-ip": "192.168.101.50", - "management-gateway-ip": "192.168.101.1", - "management-start-ip": "192.168.101.2", - "management-state": "unmanaged", - "management-subnet": "192.168.101.0/24", - "openstack-installed": false, - "software-version": "21.12", - "systemcontroller-gateway-ip": "192.168.204.101", -} diff --git a/api-ref/source/samples/subclouds/subcloud-patch-reinstall-request.json b/api-ref/source/samples/subclouds/subcloud-patch-reinstall-request.json deleted file mode 100644 index 6d9252079..000000000 --- a/api-ref/source/samples/subclouds/subcloud-patch-reinstall-request.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sysadmin_password": "XXXXXXX", - "bootstrap_values": "path to boostrap file", - "deploy_config": "path to deploy file" -} diff --git a/api-ref/source/samples/subclouds/subcloud-patch-reinstall-response.json b/api-ref/source/samples/subclouds/subcloud-patch-reinstall-response.json deleted file mode 100644 index ce36f462e..000000000 --- a/api-ref/source/samples/subclouds/subcloud-patch-reinstall-response.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "id": 1, - "name": "subcloud1", - "created-at": "2021-11-08T18:41:19.530228", - "updated-at": "2021-11-15T14:15:59.944851", - "availability-status": "online", - "data_install": { - "bootstrap_interface": "eno1" - } - "data_upgrade": null, - "deploy-status": "complete", - "backup-status": "complete", - "backup-datetime": "2022-07-08 11:23:58.132134", - "description": "Ottawa Site", - "group_id": 1, - "location": "YOW", - "management-end-ip": "192.168.101.50", - "management-gateway-ip": "192.168.101.1", - "management-start-ip": "192.168.101.2", - "management-state": "unmanaged", - "management-subnet": "192.168.101.0/24", - "openstack-installed": false, - "software-version": "21.12", - "systemcontroller-gateway-ip": "192.168.204.101", -} diff --git a/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py b/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py index f1685a232..f6d94c17d 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py +++ b/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py @@ -80,15 +80,16 @@ VALID_STATES_FOR_DEPLOY_BOOTSTRAP = [ consts.DEPLOY_STATE_CREATED ] -# TODO(vgluzrom): remove deploy_failed once 'subcloud reconfig' -# has been deprecated VALID_STATES_FOR_DEPLOY_CONFIG = ( consts.DEPLOY_STATE_DONE, consts.DEPLOY_STATE_PRE_CONFIG_FAILED, consts.DEPLOY_STATE_CONFIG_FAILED, - consts.DEPLOY_STATE_DEPLOY_FAILED, consts.DEPLOY_STATE_BOOTSTRAPPED, - consts.DEPLOY_STATE_CONFIG_ABORTED + consts.DEPLOY_STATE_CONFIG_ABORTED, + # The next two states are needed due to upgrade scenario: + # TODO(gherzman): remove states when they are no longer needed + consts.DEPLOY_STATE_DEPLOY_FAILED, + consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, ) VALID_STATES_FOR_DEPLOY_ABORT = ( diff --git a/distributedcloud/dcmanager/api/controllers/v1/subclouds.py b/distributedcloud/dcmanager/api/controllers/v1/subclouds.py index 4d28b40e8..daa0f6a1d 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/subclouds.py +++ b/distributedcloud/dcmanager/api/controllers/v1/subclouds.py @@ -62,52 +62,22 @@ LOG = logging.getLogger(__name__) LOCK_NAME = 'SubcloudsController' -BOOTSTRAP_VALUES = 'bootstrap_values' -INSTALL_VALUES = 'install_values' - -SUBCLOUD_ADD_MANDATORY_FILE = [ - BOOTSTRAP_VALUES, -] - -SUBCLOUD_RECONFIG_MANDATORY_FILE = [ - consts.DEPLOY_CONFIG, -] - SUBCLOUD_ADD_GET_FILE_CONTENTS = [ - BOOTSTRAP_VALUES, - INSTALL_VALUES, + consts.BOOTSTRAP_VALUES, + consts.INSTALL_VALUES, ] SUBCLOUD_REDEPLOY_GET_FILE_CONTENTS = [ - INSTALL_VALUES, - BOOTSTRAP_VALUES, + consts.INSTALL_VALUES, + consts.BOOTSTRAP_VALUES, consts.DEPLOY_CONFIG ] -BOOTSTRAP_VALUES_ADDRESSES = [ - 'bootstrap-address', 'bootstrap_address', 'management_start_address', 'management_end_address', - 'management_gateway_address', 'systemcontroller_gateway_address', - 'external_oam_gateway_address', 'external_oam_floating_address', - 'admin_start_address', 'admin_end_address', 'admin_gateway_address' -] - -INSTALL_VALUES_ADDRESSES = [ - 'bootstrap_address', 'bmc_address', 'nexthop_gateway', - 'network_address' -] - SUBCLOUD_MANDATORY_NETWORK_PARAMS = [ 'management_subnet', 'management_gateway_ip', 'management_start_ip', 'management_end_ip' ] -ANSIBLE_BOOTSTRAP_VALIDATE_CONFIG_VARS = \ - consts.ANSIBLE_CURRENT_VERSION_BASE_PATH + \ - '/roles/bootstrap/validate-config/vars/main.yml' - -FRESH_INSTALL_K8S_VERSION = 'fresh_install_k8s_version' -KUBERNETES_VERSION = 'kubernetes_version' - def _get_multipart_field_name(part): content = part.headers[b"Content-Disposition"].decode("utf8") @@ -146,7 +116,7 @@ class SubcloudsController(object): field_content = part.text # only the install_values field is yaml, force should be bool - if field_name in [INSTALL_VALUES, 'force']: + if field_name in [consts.INSTALL_VALUES, 'force']: field_content = yaml.safe_load(field_content) payload[field_name] = field_content @@ -189,27 +159,6 @@ class SubcloudsController(object): payload[consts.PRESTAGE_REQUEST_RELEASE] = val return payload - def _get_reconfig_payload(self, request, subcloud_name, software_version): - payload = dict() - multipart_data = decoder.MultipartDecoder( - request.body, pecan.request.headers.get('Content-Type')) - - for filename in SUBCLOUD_RECONFIG_MANDATORY_FILE: - for part in multipart_data.parts: - for hk, hv in part.headers.items(): - hv = hv.decode('utf8') - if hk.decode('utf8') == 'Content-Disposition': - if filename in hv: - fn = psd_common.get_config_file_path( - subcloud_name, consts.DEPLOY_CONFIG) - psd_common.upload_config_file( - part.content, fn, consts.DEPLOY_CONFIG) - payload.update({consts.DEPLOY_CONFIG: fn}) - elif "sysadmin_password" in hv: - payload.update({'sysadmin_password': part.content}) - psd_common.get_common_deploy_files(payload, software_version) - return payload - @staticmethod def _get_updatestatus_payload(request): """retrieve payload of a patch request for update_status @@ -382,8 +331,8 @@ class SubcloudsController(object): re.search(r"err_code\s*=\s*(\S*)", err_msg[0], re.IGNORECASE) if err_code and err_code.group(1) in err_dict: err_msg.append(err_dict.get(err_code.group(1))) - if status == consts.DEPLOY_STATE_DEPLOY_FAILED: - err_msg.append(err_dict.get(consts.DEPLOY_ERROR_MSG)) + if status == consts.DEPLOY_STATE_CONFIG_FAILED: + err_msg.append(err_dict.get(consts.CONFIG_ERROR_MSG)) elif status == consts.DEPLOY_STATE_BOOTSTRAP_FAILED: err_msg.append(err_dict.get(consts.BOOTSTRAP_ERROR_MSG)) subcloud['error-description'] = '\n'.join(err_msg) @@ -661,9 +610,9 @@ class SubcloudsController(object): exceptions.SubcloudGroupNotFound): pecan.abort(400, _('Invalid group')) - if INSTALL_VALUES in payload: + if consts.INSTALL_VALUES in payload: psd_common.validate_install_values(payload, subcloud) - payload['data_install'] = json.dumps(payload[INSTALL_VALUES]) + payload['data_install'] = json.dumps(payload[consts.INSTALL_VALUES]) try: if reconfigure_network: @@ -684,138 +633,7 @@ class SubcloudsController(object): # additional exceptions. LOG.exception(e) pecan.abort(500, _('Unable to update subcloud')) - elif verb == 'reconfigure': - if utils.subcloud_is_secondary_state(subcloud.deploy_status): - pecan.abort(500, _("Cannot perform on %s " - "state subcloud" % subcloud.deploy_status)) - payload = self._get_reconfig_payload( - request, subcloud.name, subcloud.software_version) - if not payload: - pecan.abort(400, _('Body required')) - if (subcloud.deploy_status - not in [consts.DEPLOY_STATE_DONE, - consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, - consts.DEPLOY_STATE_DEPLOY_FAILED] - and not prestage.is_deploy_status_prestage( - subcloud.deploy_status)): - pecan.abort(400, - _('Subcloud deploy status must be either ' - 'complete, deploy-prep-failed, deploy-failed, ' - 'or prestage-...')) - sysadmin_password = \ - payload.get('sysadmin_password') - if not sysadmin_password: - pecan.abort(400, _('subcloud sysadmin_password required')) - - try: - payload['sysadmin_password'] = \ - utils.decode_and_normalize_passwd(sysadmin_password) - except Exception: - msg = _('Failed to decode subcloud sysadmin_password, ' - 'verify the password is base64 encoded') - LOG.exception(msg) - pecan.abort(400, msg) - - try: - subcloud = self.dcmanager_rpc_client.reconfigure_subcloud( - context, subcloud_id, payload) - return subcloud - except RemoteError as e: - pecan.abort(422, e.value) - except Exception: - LOG.exception("Unable to reconfigure subcloud %s" % subcloud.name) - pecan.abort(500, _('Unable to reconfigure subcloud')) - elif verb == "reinstall": - if utils.subcloud_is_secondary_state(subcloud.deploy_status): - pecan.abort(500, _("Cannot perform on %s " - "state subcloud" % subcloud.deploy_status)) - psd_common.check_required_parameters(request, - SUBCLOUD_ADD_MANDATORY_FILE) - - payload = psd_common.get_request_data( - request, subcloud, SUBCLOUD_ADD_GET_FILE_CONTENTS) - - install_values = psd_common.get_subcloud_db_install_values(subcloud) - - if subcloud.availability_status == dccommon_consts.AVAILABILITY_ONLINE: - msg = _('Cannot re-install an online subcloud') - LOG.exception(msg) - pecan.abort(400, msg) - - psd_common.validate_bootstrap_values(payload) - - psd_common.validate_sysadmin_password(payload) - - if payload.get('name') != subcloud.name: - pecan.abort(400, _('name is incorrect for the subcloud')) - - psd_common.validate_subcloud_config(context, payload, verb) - - # If a subcloud release is not passed, use the current - # system controller software_version - payload['software_version'] = payload.get('release', tsc.SW_VERSION) - - psd_common.validate_k8s_version(payload) - - # If the software version of the subcloud is different from the - # specified or active load, update the software version in install - # value and delete the image path in install values, then the subcloud - # will be reinstalled using the image in dc_vault. - if install_values.get( - 'software_version') != payload['software_version']: - install_values['software_version'] = payload['software_version'] - install_values.pop('image', None) - - # Confirm the specified or active load is still in dc-vault if - # image not in install values, add the matching image into the - # install values. - matching_iso, err_msg = utils.get_matching_iso( - payload['software_version']) - if err_msg: - LOG.exception(err_msg) - pecan.abort(400, _(err_msg)) - LOG.info("Image in install_values is set to %s" % matching_iso) - install_values['image'] = matching_iso - - # Update the install values in payload - payload.update({ - 'bmc_password': install_values.get('bmc_password'), - 'install_values': install_values, - }) - - # Update data install(software version, image path) - data_install = None - if 'install_values' in payload: - data_install = json.dumps(payload['install_values']) - - # Upload the deploy config files if it is included in the request - psd_common.upload_deploy_config_file(request, payload) - - try: - # Align the software version of the subcloud with reinstall - # version. Update description, location and group id if offered, - # update the deploy status as pre-install. - subcloud = db_api.subcloud_update( - context, - subcloud_id, - description=payload.get('description', subcloud.description), - location=payload.get('location', subcloud.location), - software_version=payload['software_version'], - management_state=dccommon_consts.MANAGEMENT_UNMANAGED, - deploy_status=consts.DEPLOY_STATE_PRE_INSTALL, - first_identity_sync_complete=False, - data_install=data_install) - - self.dcmanager_rpc_client.reinstall_subcloud( - context, subcloud_id, payload) - - return db_api.subcloud_db_model_to_dict(subcloud) - except RemoteError as e: - pecan.abort(422, e.value) - except Exception: - LOG.exception("Unable to reinstall subcloud %s" % subcloud.name) - pecan.abort(500, _('Unable to reinstall subcloud')) elif verb == "redeploy": if utils.subcloud_is_secondary_state(subcloud.deploy_status): pecan.abort(500, _("Cannot perform on %s " @@ -845,7 +663,7 @@ class SubcloudsController(object): # values if this phase should be executed. files_for_redeploy = SUBCLOUD_REDEPLOY_GET_FILE_CONTENTS.copy() if has_bootstrap_values: - files_for_redeploy.remove(BOOTSTRAP_VALUES) + files_for_redeploy.remove(consts.BOOTSTRAP_VALUES) if not has_config_values: files_for_redeploy.remove(consts.DEPLOY_CONFIG) @@ -883,9 +701,19 @@ class SubcloudsController(object): except Exception: LOG.exception("Unable to redeploy subcloud %s" % subcloud.name) pecan.abort(500, _('Unable to redeploy subcloud')) + elif verb == "restore": pecan.abort(410, _('This API is deprecated. ' 'Please use /v1.0/subcloud-backup/restore')) + + elif verb == "reconfigure": + pecan.abort(410, _('This API is deprecated. ' + 'Please use /v1.0/phased-subcloud-deploy/{subcloud}/configure')) + + elif verb == "reinstall": + pecan.abort(410, _('This API is deprecated. ' + 'Please use /v1.0/subclouds/{subcloud}/redeploy')) + elif verb == 'update_status': res = self.updatestatus(subcloud.name) return res diff --git a/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py b/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py index 68111de43..9e925ab7d 100644 --- a/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py +++ b/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py @@ -112,9 +112,12 @@ class SubcloudAuditWorkerManager(manager.Manager): # so that the subcloud can be set as offline if (subcloud.deploy_status not in [consts.DEPLOY_STATE_DONE, - consts.DEPLOY_STATE_DEPLOYING, - consts.DEPLOY_STATE_DEPLOY_FAILED, + consts.DEPLOY_STATE_CONFIGURING, + consts.DEPLOY_STATE_CONFIG_FAILED, + consts.DEPLOY_STATE_CONFIG_ABORTED, + consts.DEPLOY_STATE_PRE_CONFIG_FAILED, consts.DEPLOY_STATE_INSTALL_FAILED, + consts.DEPLOY_STATE_INSTALL_ABORTED, consts.DEPLOY_STATE_PRE_INSTALL_FAILED, consts.DEPLOY_STATE_DATA_MIGRATION_FAILED, consts.DEPLOY_STATE_MIGRATED, diff --git a/distributedcloud/dcmanager/common/consts.py b/distributedcloud/dcmanager/common/consts.py index 116e94cab..64bfdea64 100644 --- a/distributedcloud/dcmanager/common/consts.py +++ b/distributedcloud/dcmanager/common/consts.py @@ -202,7 +202,6 @@ DEPLOY_STATE_DEPLOY_FAILED = 'deploy-failed' DEPLOY_STATE_ABORTING_INSTALL = 'aborting-install' DEPLOY_STATE_INSTALL_ABORTED = 'install-aborted' DEPLOY_STATE_ABORTING_BOOTSTRAP = 'aborting-bootstrap' -DEPLOY_STATE_BOOTSTRAP_ABORTED = 'bootstrap-aborted' DEPLOY_STATE_ABORTING_CONFIG = 'aborting-config' DEPLOY_STATE_CONFIG_ABORTED = 'config-aborted' DEPLOY_STATE_MIGRATING_DATA = 'migrating-data' @@ -228,7 +227,7 @@ ERROR_DESC_CMD = 'dcmanager subcloud errors ' # Static content for error messages BOOTSTRAP_ERROR_MSG = DEPLOY_STATE_BOOTSTRAP_FAILED -DEPLOY_ERROR_MSG = DEPLOY_STATE_DEPLOY_FAILED +CONFIG_ERROR_MSG = DEPLOY_STATE_CONFIG_FAILED ERR_MSG_DICT = { @@ -236,9 +235,9 @@ ERR_MSG_DICT = { "the subcloud after the cause of failure has been " "resolved.", - DEPLOY_ERROR_MSG: "For deployment failures, please use dcmanager subcloud " - "reconfig command to reconfigure the subcloud after the " - "cause of failure has been resolved.", + CONFIG_ERROR_MSG: "For configuration failures, please use dcmanager subcloud " + "deploy config command to reconfigure the subcloud after " + "the cause of failure has been resolved.", "bmc_cred": "Check BMC credentials in install-values.yml. Check basic " "authenticacion to the BMC: curl -u <> " @@ -379,10 +378,14 @@ VALID_DEPLOY_STATES_FOR_BACKUP = [DEPLOY_STATE_DONE, PRESTAGE_STATE_COMPLETE] # States to reject when processing a subcloud-backup restore request -INVALID_DEPLOY_STATES_FOR_RESTORE = [DEPLOY_STATE_PRE_INSTALL, +INVALID_DEPLOY_STATES_FOR_RESTORE = [DEPLOY_STATE_CREATING, + DEPLOY_STATE_PRE_INSTALL, DEPLOY_STATE_INSTALLING, + DEPLOY_STATE_PRE_BOOTSTRAP, DEPLOY_STATE_BOOTSTRAPPING, - DEPLOY_STATE_DEPLOYING, + DEPLOY_STATE_PRE_CONFIG, + DEPLOY_STATE_CONFIGURING, + DEPLOY_STATE_PRE_REHOME, DEPLOY_STATE_REHOMING, DEPLOY_STATE_PRE_RESTORE, DEPLOY_STATE_RESTORING] diff --git a/distributedcloud/dcmanager/common/phased_subcloud_deploy.py b/distributedcloud/dcmanager/common/phased_subcloud_deploy.py index 7ab06a950..891aca398 100644 --- a/distributedcloud/dcmanager/common/phased_subcloud_deploy.py +++ b/distributedcloud/dcmanager/common/phased_subcloud_deploy.py @@ -37,7 +37,6 @@ ANSIBLE_BOOTSTRAP_VALIDATE_CONFIG_VARS = \ FRESH_INSTALL_K8S_VERSION = 'fresh_install_k8s_version' KUBERNETES_VERSION = 'kubernetes_version' -INSTALL_VALUES = 'install_values' INSTALL_VALUES_ADDRESSES = [ 'bootstrap_address', 'bmc_address', 'nexthop_gateway', 'network_address' @@ -700,16 +699,16 @@ def format_ip_address(payload): The IPv6 addresses can be represented in multiple ways. Format and update the IP addresses in payload before saving it to database. """ - if INSTALL_VALUES in payload: + if consts.INSTALL_VALUES in payload: for k in INSTALL_VALUES_ADDRESSES: - if k in payload[INSTALL_VALUES]: + if k in payload[consts.INSTALL_VALUES]: try: - address = netaddr.IPAddress(payload[INSTALL_VALUES] + address = netaddr.IPAddress(payload[consts.INSTALL_VALUES] .get(k)).format() except netaddr.AddrFormatError as e: LOG.exception(e) pecan.abort(400, _("%s invalid: %s") % (k, e)) - payload[INSTALL_VALUES].update({k: address}) + payload[consts.INSTALL_VALUES].update({k: address}) for k in BOOTSTRAP_VALUES_ADDRESSES: if k in payload: diff --git a/distributedcloud/dcmanager/common/utils.py b/distributedcloud/dcmanager/common/utils.py index 9b15237b0..9cf04537c 100644 --- a/distributedcloud/dcmanager/common/utils.py +++ b/distributedcloud/dcmanager/common/utils.py @@ -133,8 +133,7 @@ def validate_network_str(network_str, minimum_size, existing_networks=None, "least %d addresses" % minimum_size) elif network.version == 6 and network.prefixlen < 64: raise exceptions.ValidateFail("IPv6 minimum prefix length is 64") - elif existing_networks and (operation != 'reinstall' - and operation != 'redeploy'): + elif existing_networks and operation != 'redeploy': if any(network.ip in subnet for subnet in existing_networks): raise exceptions.ValidateFail("Subnet overlaps with another " "configured subnet") diff --git a/distributedcloud/dcmanager/manager/service.py b/distributedcloud/dcmanager/manager/service.py index 7ab90b6a5..45b13da54 100644 --- a/distributedcloud/dcmanager/manager/service.py +++ b/distributedcloud/dcmanager/manager/service.py @@ -138,22 +138,6 @@ class DCManagerService(service.Service): subcloud_id, payload) - @request_context - def reconfigure_subcloud(self, context, subcloud_id, payload): - # Reconfigures a subcloud - LOG.info("Handling reconfigure_subcloud request for: %s" % subcloud_id) - return self.subcloud_manager.reconfigure_subcloud(context, - subcloud_id, - payload) - - @request_context - def reinstall_subcloud(self, context, subcloud_id, payload): - # Reinstall a subcloud - LOG.info("Handling reinstall_subcloud request for: %s" % payload.get('name')) - return self.subcloud_manager.reinstall_subcloud(context, - subcloud_id, - payload) - @request_context def redeploy_subcloud(self, context, subcloud_id, payload): # Redeploy a subcloud diff --git a/distributedcloud/dcmanager/manager/subcloud_manager.py b/distributedcloud/dcmanager/manager/subcloud_manager.py index 06830daba..151a5927b 100644 --- a/distributedcloud/dcmanager/manager/subcloud_manager.py +++ b/distributedcloud/dcmanager/manager/subcloud_manager.py @@ -105,8 +105,7 @@ SC_INTERMEDIATE_CERT_RENEW_BEFORE = "720h" # 30 days CERT_NAMESPACE = "dc-cert" TRANSITORY_STATES = { - consts.DEPLOY_STATE_NONE: consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, - consts.DEPLOY_STATE_PRE_DEPLOY: consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, + consts.DEPLOY_STATE_NONE: consts.DEPLOY_STATE_CREATE_FAILED, consts.DEPLOY_STATE_CREATING: consts.DEPLOY_STATE_CREATE_FAILED, consts.DEPLOY_STATE_PRE_INSTALL: consts.DEPLOY_STATE_PRE_INSTALL_FAILED, consts.DEPLOY_STATE_INSTALLING: consts.DEPLOY_STATE_INSTALL_FAILED, @@ -114,15 +113,20 @@ TRANSITORY_STATES = { consts.DEPLOY_STATE_BOOTSTRAPPING: consts.DEPLOY_STATE_BOOTSTRAP_FAILED, consts.DEPLOY_STATE_PRE_CONFIG: consts.DEPLOY_STATE_PRE_CONFIG_FAILED, consts.DEPLOY_STATE_CONFIGURING: consts.DEPLOY_STATE_CONFIG_FAILED, - consts.DEPLOY_STATE_DEPLOYING: consts.DEPLOY_STATE_DEPLOY_FAILED, consts.DEPLOY_STATE_ABORTING_INSTALL: consts.DEPLOY_STATE_INSTALL_FAILED, consts.DEPLOY_STATE_ABORTING_BOOTSTRAP: consts.DEPLOY_STATE_BOOTSTRAP_FAILED, consts.DEPLOY_STATE_ABORTING_CONFIG: consts.DEPLOY_STATE_CONFIG_FAILED, consts.DEPLOY_STATE_MIGRATING_DATA: consts.DEPLOY_STATE_DATA_MIGRATION_FAILED, consts.DEPLOY_STATE_PRE_RESTORE: consts.DEPLOY_STATE_RESTORE_PREP_FAILED, consts.DEPLOY_STATE_RESTORING: consts.DEPLOY_STATE_RESTORE_FAILED, + consts.DEPLOY_STATE_PRE_REHOME: consts.DEPLOY_STATE_REHOME_PREP_FAILED, + consts.DEPLOY_STATE_REHOMING: consts.DEPLOY_STATE_REHOME_FAILED, consts.PRESTAGE_STATE_PACKAGES: consts.PRESTAGE_STATE_FAILED, consts.PRESTAGE_STATE_IMAGES: consts.PRESTAGE_STATE_FAILED, + # The next two states are needed due to upgrade scenario: + # TODO(gherzman): remove states when they are no longer needed + consts.DEPLOY_STATE_PRE_DEPLOY: consts.DEPLOY_STATE_PRE_CONFIG_FAILED, + consts.DEPLOY_STATE_DEPLOYING: consts.DEPLOY_STATE_CONFIG_FAILED, } @@ -448,122 +452,6 @@ class SubcloudManager(manager.Manager): LOG.info(f"Finished adding subcloud {subcloud['name']}.") - def reconfigure_subcloud(self, context, subcloud_id, payload): - """Reconfigure subcloud - - :param context: request context object - :param subcloud_id: id of the subcloud - :param payload: subcloud configuration - """ - LOG.info("Reconfiguring subcloud %s." % subcloud_id) - - subcloud = db_api.subcloud_update( - context, subcloud_id, - deploy_status=consts.DEPLOY_STATE_PRE_DEPLOY) - try: - # Ansible inventory filename for the specified subcloud - ansible_subcloud_inventory_file = self._get_ansible_filename( - subcloud.name, INVENTORY_FILE_POSTFIX) - - config_command = None - if "deploy_playbook" in payload: - self._prepare_for_deployment(payload, subcloud.name) - config_command = self.compose_config_command( - subcloud.name, - ansible_subcloud_inventory_file, - payload) - - del payload['sysadmin_password'] - apply_thread = threading.Thread( - target=self.run_deploy_thread, - args=(subcloud, payload, context, None, None, config_command)) - apply_thread.start() - return db_api.subcloud_db_model_to_dict(subcloud) - except Exception: - LOG.exception("Failed to create subcloud %s" % subcloud.name) - # If we failed to create the subcloud, update the - # deployment status - db_api.subcloud_update( - context, subcloud_id, - deploy_status=consts.DEPLOY_STATE_DEPLOY_PREP_FAILED) - - def reinstall_subcloud(self, context, subcloud_id, payload): - """Reinstall subcloud - - :param context: request context object - :param subcloud_id: subcloud id from db - :param payload: subcloud reinstall - """ - - # Retrieve the subcloud details from the database - subcloud = db_api.subcloud_get(context, subcloud_id) - - LOG.info("Reinstalling subcloud %s." % subcloud_id) - - try: - ansible_subcloud_inventory_file = self._get_ansible_filename( - subcloud.name, INVENTORY_FILE_POSTFIX) - - m_ks_client = OpenStackDriver( - region_name=dccommon_consts.DEFAULT_REGION_NAME, - region_clients=None).keystone_client - cached_regionone_data = self._get_cached_regionone_data(m_ks_client) - self._populate_payload_with_cached_keystone_data( - cached_regionone_data, payload) - - payload['install_values']['ansible_ssh_pass'] = \ - payload['sysadmin_password'] - payload['install_values']['ansible_become_pass'] = \ - payload['sysadmin_password'] - payload['bootstrap-address'] = \ - payload['install_values']['bootstrap_address'] - - config_command = None - if "deploy_playbook" in payload: - self._prepare_for_deployment(payload, subcloud.name) - config_command = self.compose_config_command( - subcloud.name, - ansible_subcloud_inventory_file, - payload) - del payload['sysadmin_password'] - - payload['users'] = dict() - for user in USERS_TO_REPLICATE: - payload['users'][user] = \ - str(keyring.get_password( - user, dccommon_consts.SERVICES_USER_NAME)) - - utils.create_subcloud_inventory(payload, - ansible_subcloud_inventory_file) - - self._create_intermediate_ca_cert(payload) - - self._write_subcloud_ansible_config(cached_regionone_data, payload) - - install_command = self.compose_install_command( - subcloud.name, - ansible_subcloud_inventory_file, - payload['software_version']) - bootstrap_command = self.compose_bootstrap_command( - subcloud.name, - ansible_subcloud_inventory_file, - payload['software_version']) - network_reconfig = utils.has_network_reconfig(payload, subcloud) - apply_thread = threading.Thread( - target=self.run_deploy_thread, - args=(subcloud, payload, context, - install_command, bootstrap_command, config_command, - None, network_reconfig)) - apply_thread.start() - return db_api.subcloud_db_model_to_dict(subcloud) - except Exception: - LOG.exception("Failed to reinstall subcloud %s" % subcloud.name) - # If we failed to reinstall the subcloud, update the - # deployment status - db_api.subcloud_update( - context, subcloud_id, - deploy_status=consts.DEPLOY_STATE_PRE_INSTALL_FAILED) - def redeploy_subcloud(self, context, subcloud_id, payload): """Redeploy subcloud diff --git a/distributedcloud/dcmanager/rpc/client.py b/distributedcloud/dcmanager/rpc/client.py index be118b39b..f93bcdab2 100644 --- a/distributedcloud/dcmanager/rpc/client.py +++ b/distributedcloud/dcmanager/rpc/client.py @@ -154,16 +154,6 @@ class ManagerClient(RPCClient): subcloud_id=subcloud_id, payload=payload)) - def reconfigure_subcloud(self, ctxt, subcloud_id, payload): - return self.call(ctxt, self.make_msg('reconfigure_subcloud', - subcloud_id=subcloud_id, - payload=payload)) - - def reinstall_subcloud(self, ctxt, subcloud_id, payload): - return self.cast(ctxt, self.make_msg('reinstall_subcloud', - subcloud_id=subcloud_id, - payload=payload)) - def redeploy_subcloud(self, ctxt, subcloud_id, payload): return self.cast(ctxt, self.make_msg('redeploy_subcloud', subcloud_id=subcloud_id, diff --git a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_backup.py b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_backup.py index 58ac2c025..224fc2c1f 100644 --- a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_backup.py +++ b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_backup.py @@ -1156,18 +1156,12 @@ class TestSubcloudRestore(testroot.DCManagerApiTest): @mock.patch.object(rpc_client, 'ManagerClient') def test_backup_restore_subcloud_invalid_deploy_states(self, mock_rpc_client): - - invalid_deploy_states = [consts.DEPLOY_STATE_INSTALLING, - consts.DEPLOY_STATE_BOOTSTRAPPING, - consts.DEPLOY_STATE_DEPLOYING, - consts.DEPLOY_STATE_REHOMING] - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) fake_password = (base64.b64encode('testpass'.encode("utf-8"))).decode('ascii') data = {'sysadmin_password': fake_password, 'subcloud': '1'} mock_rpc_client().restore_subcloud_backups.return_value = True - for status in invalid_deploy_states: + for status in consts.INVALID_DEPLOY_STATES_FOR_RESTORE: db_api.subcloud_update(self.ctx, subcloud.id, availability_status=dccommon_consts.AVAILABILITY_ONLINE, diff --git a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subclouds.py b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subclouds.py index 999860a3a..608ab4790 100644 --- a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subclouds.py +++ b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subclouds.py @@ -29,6 +29,7 @@ from tsconfig.tsconfig import SW_VERSION import webtest from dccommon import consts as dccommon_consts +from dcmanager.api.controllers.v1 import phased_subcloud_deploy as psd from dcmanager.api.controllers.v1 import subclouds from dcmanager.common import consts from dcmanager.common import exceptions @@ -197,7 +198,7 @@ class SubcloudAPIMixin(APIMixin): "install_type": 2, } - list_of_post_files = subclouds.SUBCLOUD_ADD_MANDATORY_FILE + list_of_post_files = psd.SUBCLOUD_BOOTSTRAP_GET_FILE_CONTENTS bootstrap_data = copy.copy(FAKE_BOOTSTRAP_DATA) install_data = copy.copy(FAKE_INSTALL_DATA) @@ -245,9 +246,9 @@ class SubcloudAPIMixin(APIMixin): for f in self.list_of_post_files: fake_name = f + "_fake" # The data in the bootstrap file needs to be dictionary syntax - if f == subclouds.BOOTSTRAP_VALUES: + if f == consts.BOOTSTRAP_VALUES: fake_content = json.dumps(self.bootstrap_data).encode("utf-8") - elif f == subclouds.INSTALL_VALUES: + elif f == consts.INSTALL_VALUES: fake_content = json.dumps(self.install_data).encode("utf-8") else: fake_content = "fake content".encode("utf-8") @@ -270,7 +271,7 @@ class TestSubcloudPost(testroot.DCManagerApiTest, PostMixin): def setUp(self): super(TestSubcloudPost, self).setUp() - self.list_of_post_files = subclouds.SUBCLOUD_ADD_MANDATORY_FILE + self.list_of_post_files = psd.SUBCLOUD_BOOTSTRAP_GET_FILE_CONTENTS self.bootstrap_data = copy.copy(self.FAKE_BOOTSTRAP_DATA) self.install_data = copy.copy(self.FAKE_INSTALL_DATA) @@ -345,7 +346,7 @@ class TestSubcloudPost(testroot.DCManagerApiTest, Example: name is a required field """ - self.list_of_post_files = subclouds.SUBCLOUD_ADD_MANDATORY_FILE + self.list_of_post_files = psd.SUBCLOUD_BOOTSTRAP_GET_FILE_CONTENTS params = self.get_post_params() for key in self.FAKE_BOOTSTRAP_DATA: @@ -1416,67 +1417,6 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest): bootstrap_address=None) self.assertEqual(response.status_int, 200) - @mock.patch.object(subclouds.SubcloudsController, '_get_reconfig_payload') - def test_reconfigure_subcloud(self, mock_get_reconfig_payload): - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - fake_password = (base64.b64encode('testpass'.encode("utf-8"))).decode('ascii') - data = {'sysadmin_password': fake_password} - - self.mock_rpc_client().reconfigure_subcloud.return_value = True - mock_get_reconfig_payload.return_value = data - - response = self.app.patch_json(FAKE_URL + '/' + str(subcloud.id) + - '/reconfigure', - headers=FAKE_HEADERS, - params=data) - self.mock_rpc_client().reconfigure_subcloud.assert_called_once_with( - mock.ANY, - subcloud.id, - mock.ANY) - self.assertEqual(response.status_int, 200) - - @mock.patch.object(subclouds.SubcloudsController, '_get_reconfig_payload') - def test_reconfigure_subcloud_no_body(self, mock_get_reconfig_payload): - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - # Pass an empty request body - data = {} - mock_get_reconfig_payload.return_value = data - self.mock_rpc_client().reconfigure_subcloud.return_value = True - - six.assertRaisesRegex(self, webtest.app.AppError, "400 *", - self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reconfigure', - headers=FAKE_HEADERS, params=data) - - @mock.patch.object(subclouds.SubcloudsController, '_get_reconfig_payload') - def test_reconfigure_subcloud_bad_password(self, mock_get_reconfig_payload): - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - # Pass a sysadmin_password which is not base64 encoded - data = {'sysadmin_password': 'not_base64'} - mock_get_reconfig_payload.return_value = data - self.mock_rpc_client().reconfigure_subcloud.return_value = True - - six.assertRaisesRegex(self, webtest.app.AppError, "400 *", - self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reconfigure', - headers=FAKE_HEADERS, params=data) - - @mock.patch.object(subclouds.SubcloudsController, '_get_reconfig_payload') - def test_reconfigure_invalid_deploy_status(self, - mock_get_reconfig_payload): - subcloud = fake_subcloud.create_fake_subcloud( - self.ctx, - deploy_status=consts.DEPLOY_STATE_BOOTSTRAP_FAILED) - fake_password = base64.b64encode('testpass'.encode("utf-8")).decode("utf-8") - data = {'sysadmin_password': fake_password} - mock_get_reconfig_payload.return_value = data - self.mock_rpc_client().reconfigure_subcloud.return_value = True - - six.assertRaisesRegex(self, webtest.app.AppError, "400 *", - self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reconfigure', - headers=FAKE_HEADERS, params=data) - @mock.patch.object(subclouds.SubcloudsController, '_get_updatestatus_payload') def test_subcloud_updatestatus(self, mock_get_updatestatus_payload): subcloud = fake_subcloud.create_fake_subcloud(self.ctx) @@ -1551,17 +1491,17 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest): psd_common.format_ip_address(fake_payload) self.assertEqual(fake_payload['bootstrap-address'], v) - fake_payload[subclouds.INSTALL_VALUES] = {} + fake_payload[consts.INSTALL_VALUES] = {} for k, v in good_values.items(): - fake_payload[subclouds.INSTALL_VALUES]['bmc_address'] = k + fake_payload[consts.INSTALL_VALUES]['bmc_address'] = k psd_common.format_ip_address(fake_payload) - self.assertEqual(fake_payload[subclouds.INSTALL_VALUES]['bmc_address'], v) + self.assertEqual(fake_payload[consts.INSTALL_VALUES]['bmc_address'], v) fake_payload['othervalues1'] = 'othervalues1' - fake_payload[subclouds.INSTALL_VALUES]['othervalues2'] = 'othervalues2' + fake_payload[consts.INSTALL_VALUES]['othervalues2'] = 'othervalues2' psd_common.format_ip_address(fake_payload) self.assertEqual(fake_payload['othervalues1'], 'othervalues1') - self.assertEqual(fake_payload[subclouds.INSTALL_VALUES]['othervalues2'], 'othervalues2') + self.assertEqual(fake_payload[consts.INSTALL_VALUES]['othervalues2'], 'othervalues2') def test_get_subcloud_db_install_values(self): install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES) @@ -1587,218 +1527,9 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest): six.assertRaisesRegex(self, webtest.app.AppError, "400 *", self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reinstall', + str(subcloud.id) + '/redeploy', headers=FAKE_HEADERS) - @mock.patch.object(cutils, 'get_vault_load_files') - @mock.patch.object(psd_common, 'upload_deploy_config_file') - @mock.patch.object(psd_common, 'validate_k8s_version') - @mock.patch.object(psd_common, 'validate_subcloud_config') - @mock.patch.object(psd_common, 'validate_bootstrap_values') - def test_reinstall_subcloud( - self, mock_validate_bootstrap_values, mock_validate_subcloud_config, - mock_validate_k8s_version, mock_upload_deploy_config_file, - mock_get_vault_load_files): - - encoded_password = base64.b64encode( - 'bmc_password'.encode("utf-8")).decode('utf-8') - - data_install = {**FAKE_SUBCLOUD_INSTALL_VALUES, - 'bmc_password': encoded_password} - - subcloud = fake_subcloud.create_fake_subcloud( - self.ctx, name=fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA["name"], - data_install=json.dumps(data_install)) - - fake_bootstrap_content = json.dumps( - fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA).encode("utf-8") - - mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path') - - params = {'sysadmin_password': encoded_password} - - response = self.app.patch( - FAKE_URL + '/' + str(subcloud.id) + '/reinstall', - headers=FAKE_HEADERS, params=params, - upload_files=[("bootstrap_values", - "bootstrap_fake_filename", - fake_bootstrap_content)]) - - mock_validate_bootstrap_values.assert_called_once() - mock_validate_subcloud_config.assert_called_once() - mock_validate_k8s_version.assert_called_once() - self.mock_rpc_client().reinstall_subcloud.assert_called_once_with( - mock.ANY, - subcloud.id, - mock.ANY) - self.assertEqual(response.status_int, 200) - - mock_upload_deploy_config_file.assert_called_once() - self.assertEqual(SW_VERSION, response.json['software-version']) - - @mock.patch.object(psd_common, 'check_required_parameters') - @mock.patch.object(cutils, 'get_vault_load_files') - @mock.patch.object(psd_common, 'upload_deploy_config_file') - @mock.patch.object(psd_common, 'validate_k8s_version') - @mock.patch.object(psd_common, 'validate_subcloud_config') - @mock.patch.object(psd_common, 'validate_bootstrap_values') - @mock.patch.object(psd_common, 'get_subcloud_db_install_values') - @mock.patch.object(psd_common, 'get_request_data') - def test_reinstall_subcloud_with_release_parameter( - self, mock_get_request_data, mock_get_subcloud_db_install_values, - mock_validate_install_parameters, mock_validate_subcloud_config, - mock_validate_k8s_version, mock_upload_deploy_config_file, - mock_get_vault_load_files, mock_check_required_parameters): - - software_version = '21.12' - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES) - reinstall_data = copy.copy(FAKE_SUBCLOUD_BOOTSTRAP_PAYLOAD) - reinstall_data['release'] = software_version - mock_get_request_data.return_value = reinstall_data - - encoded_password = base64.b64encode( - 'bmc_password'.encode("utf-8")).decode('utf-8') - bmc_password = {'bmc_password': encoded_password} - install_data.update(bmc_password) - mock_get_subcloud_db_install_values.return_value = install_data - - self.mock_rpc_client().reinstall_subcloud.return_value = True - mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path') - - response = self.app.patch_json( - FAKE_URL + '/' + str(subcloud.id) + '/reinstall', - headers=FAKE_HEADERS, params=reinstall_data) - - mock_validate_install_parameters.assert_called_once() - mock_validate_subcloud_config.assert_called_once() - self.mock_rpc_client().reinstall_subcloud.assert_called_once_with( - mock.ANY, - subcloud.id, - mock.ANY) - self.assertEqual(response.status_int, 200) - - mock_validate_k8s_version.assert_called_once() - mock_upload_deploy_config_file.assert_called_once() - self.assertEqual(software_version, response.json['software-version']) - self.assertIn(software_version, - json.loads(response.json['data_install'])['software_version']) - - @mock.patch.object(cutils, 'get_vault_load_files') - @mock.patch.object(psd_common, 'get_subcloud_db_install_values') - @mock.patch.object(psd_common, 'validate_bootstrap_values') - @mock.patch.object(psd_common, 'get_request_data') - def test_reinstall_subcloud_no_body( - self, mock_get_request_data, mock_validate_install_parameters, - mock_get_subcloud_db_install_values, mock_get_vault_load_files): - - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES) - mock_get_request_data.return_value = {} - encoded_password = base64.b64encode( - 'bmc_password'.encode("utf-8")).decode('utf-8') - bmc_password = {'bmc_password': encoded_password} - install_data.update(bmc_password) - - mock_validate_install_parameters.assert_not_called() - mock_get_subcloud_db_install_values.return_value = install_data - self.mock_rpc_client().reinstall_subcloud.return_value = True - six.assertRaisesRegex(self, webtest.app.AppError, "400 *", - self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reinstall', - headers=FAKE_HEADERS, params={}) - - @mock.patch.object(cutils, 'get_vault_load_files') - @mock.patch.object(psd_common, 'get_subcloud_db_install_values') - @mock.patch.object(psd_common, 'validate_bootstrap_values') - @mock.patch.object(psd_common, 'get_request_data') - def test_reinstall_online_subcloud( - self, mock_get_request_data, mock_validate_install_parameters, - mock_get_subcloud_db_install_values, mock_get_vault_load_files): - - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - db_api.subcloud_update( - self.ctx, subcloud.id, - availability_status=dccommon_consts.AVAILABILITY_ONLINE - ) - install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES) - reinstall_data = copy.copy(FAKE_SUBCLOUD_BOOTSTRAP_PAYLOAD) - mock_get_request_data.return_value = reinstall_data - encoded_password = base64.b64encode( - 'bmc_password'.encode("utf-8")).decode('utf-8') - bmc_password = {'bmc_password': encoded_password} - install_data.update(bmc_password) - - mock_validate_install_parameters.assert_not_called() - mock_get_subcloud_db_install_values.return_value = install_data - self.mock_rpc_client().reinstall_subcloud.return_value = True - six.assertRaisesRegex(self, webtest.app.AppError, "400 *", - self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reinstall', - headers=FAKE_HEADERS, params={}) - - @mock.patch.object(psd_common, 'get_subcloud_db_install_values') - @mock.patch.object(psd_common, 'get_request_data') - def test_reinstall_subcloud_missing_required_value( - self, mock_get_request_data, mock_get_subcloud_db_install_values): - - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES) - - encoded_password = base64.b64encode( - 'bmc_password'.encode("utf-8")).decode('utf-8') - bmc_password = {'bmc_password': encoded_password} - install_data.update(bmc_password) - mock_get_subcloud_db_install_values.return_value = install_data - self.mock_rpc_client().reinstall_subcloud.return_value = True - - for k in ['name', 'system_mode', 'external_oam_subnet', - 'external_oam_gateway_address', 'external_oam_floating_address', - 'sysadmin_password']: - reinstall_data = copy.copy(FAKE_SUBCLOUD_BOOTSTRAP_PAYLOAD) - del reinstall_data[k] - mock_get_request_data.return_value = reinstall_data - six.assertRaisesRegex(self, webtest.app.AppError, "400 *", - self.app.patch_json, FAKE_URL + '/' + - str(subcloud.id) + '/reinstall', - headers=FAKE_HEADERS, params=reinstall_data) - - @mock.patch.object(psd_common, 'check_required_parameters') - @mock.patch.object(cutils, 'get_vault_load_files') - @mock.patch.object(psd_common, 'get_subcloud_db_install_values') - @mock.patch.object(psd_common, 'validate_k8s_version') - @mock.patch.object(psd_common, 'validate_subcloud_config') - @mock.patch.object(psd_common, 'validate_bootstrap_values') - @mock.patch.object(psd_common, 'get_request_data') - def test_reinstall_subcloud_missing_stored_value( - self, mock_get_request_data, mock_validate_install_parameters, - mock_validate_subcloud_config, mock_validate_k8s_version, - mock_get_subcloud_db_install_values, mock_get_vault_load_files, - mock_check_required_parameters): - - subcloud = fake_subcloud.create_fake_subcloud(self.ctx) - install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES) - - encoded_password = base64.b64encode( - 'bmc_password'.encode("utf-8")).decode('utf-8') - bmc_password = {'bmc_password': encoded_password} - install_data.update(bmc_password) - mock_get_subcloud_db_install_values.return_value = install_data - - self.mock_rpc_client().reinstall_subcloud.return_value = True - mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path') - - for k in ['management_subnet', 'management_start_address', - 'management_end_address', 'management_gateway_address', - 'systemcontroller_gateway_address']: - reinstall_data = copy.copy(FAKE_SUBCLOUD_BOOTSTRAP_PAYLOAD) - del reinstall_data[k] - mock_get_request_data.return_value = reinstall_data - response = self.app.patch_json( - FAKE_URL + '/' + str(subcloud.id) + '/reinstall', - headers=FAKE_HEADERS, params=reinstall_data) - self.assertEqual(response.status_int, 200) - @mock.patch.object(psd_common, 'upload_config_file') @mock.patch.object(psd_common.PatchingClient, 'query') @mock.patch.object(os.path, 'isdir') diff --git a/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py b/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py index eed1df3fd..8fa9d5a6f 100644 --- a/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py +++ b/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py @@ -1674,29 +1674,6 @@ class TestSubcloudManager(base.DCManagerTestCase): updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name) self.assertEqual(updated_subcloud.openstack_installed, False) - @mock.patch.object(subcloud_manager.SubcloudManager, - '_prepare_for_deployment') - @mock.patch.object(threading.Thread, - 'start') - def test_reconfig_subcloud(self, mock_thread_start, - mock_prepare_for_deployment): - subcloud = self.create_subcloud_static( - self.ctx, - name='subcloud1', - deploy_status=consts.DEPLOY_STATE_PRE_DEPLOY) - - fake_payload = {"sysadmin_password": "testpass", - "deploy_playbook": "test_playbook.yaml", - "deploy_overrides": "test_overrides.yaml", - "deploy_chart": "test_chart.yaml", - "deploy_config": "subcloud1.yaml"} - sm = subcloud_manager.SubcloudManager() - sm.reconfigure_subcloud(self.ctx, - subcloud.id, - payload=fake_payload) - mock_thread_start.assert_called_once() - mock_prepare_for_deployment.assert_called_once() - def test_get_ansible_filename(self): filename = cutils.get_ansible_filename('subcloud1', consts.INVENTORY_FILE_POSTFIX) @@ -1787,60 +1764,6 @@ class TestSubcloudManager(base.DCManagerTestCase): ] ) - @mock.patch.object( - subcloud_manager.SubcloudManager, '_write_subcloud_ansible_config') - @mock.patch.object( - subcloud_manager.SubcloudManager, '_create_intermediate_ca_cert') - @mock.patch.object( - subcloud_manager.SubcloudManager, 'compose_install_command') - @mock.patch.object( - subcloud_manager.SubcloudManager, 'compose_bootstrap_command') - @mock.patch.object(cutils, 'create_subcloud_inventory') - @mock.patch.object(subcloud_manager.SubcloudManager, '_get_cached_regionone_data') - @mock.patch.object(subcloud_manager, 'OpenStackDriver') - @mock.patch.object(threading.Thread, 'start') - @mock.patch.object(subcloud_manager, 'keyring') - def test_reinstall_subcloud( - self, mock_keyring, mock_thread_start, - mock_keystone_client, mock_get_cached_regionone_data, mock_create_subcloud_inventory, - mock_compose_bootstrap_command, mock_compose_install_command, - mock_create_intermediate_ca_cert, mock_write_subcloud_ansible_config): - - subcloud_name = 'subcloud1' - subcloud = self.create_subcloud_static( - self.ctx, - name=subcloud_name, - deploy_status=consts.DEPLOY_STATE_PRE_INSTALL) - - fake_install_values = \ - copy.copy(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES) - fake_install_values['software_version'] = SW_VERSION - fake_payload = copy.copy(fake_subcloud.FAKE_SUBCLOUD_BOOTSTRAP_PAYLOAD) - fake_payload.update({ - 'bmc_password': 'bmc_pass', - 'software_version': FAKE_PREVIOUS_SW_VERSION, - 'install_values': fake_install_values}) - - sm = subcloud_manager.SubcloudManager() - mock_keyring.get_password.return_value = "testpassword" - mock_get_cached_regionone_data.return_value = FAKE_CACHED_REGIONONE_DATA - - sm.reinstall_subcloud(self.ctx, subcloud.id, payload=fake_payload) - mock_keystone_client.assert_called_once() - mock_get_cached_regionone_data.assert_called_once() - mock_create_subcloud_inventory.assert_called_once() - mock_create_intermediate_ca_cert.assert_called_once() - mock_write_subcloud_ansible_config.assert_called_once() - mock_compose_install_command.assert_called_once_with( - subcloud_name, - cutils.get_ansible_filename(subcloud_name, consts.INVENTORY_FILE_POSTFIX), - FAKE_PREVIOUS_SW_VERSION) - mock_compose_bootstrap_command.assert_called_once_with( - subcloud_name, - cutils.get_ansible_filename(subcloud_name, consts.INVENTORY_FILE_POSTFIX), - FAKE_PREVIOUS_SW_VERSION) - mock_thread_start.assert_called_once() - @mock.patch.object(subcloud_manager.SubcloudManager, '_run_subcloud_install') @mock.patch.object(subcloud_manager.SubcloudManager, @@ -1933,12 +1856,32 @@ class TestSubcloudManager(base.DCManagerTestCase): self.ctx, name='subcloud9', deploy_status=consts.DEPLOY_STATE_NONE) + subcloud10 = self.create_subcloud_static( + self.ctx, + name='subcloud10', + deploy_status=consts.DEPLOY_STATE_CREATING) + subcloud11 = self.create_subcloud_static( + self.ctx, + name='subcloud11', + deploy_status=consts.DEPLOY_STATE_PRE_BOOTSTRAP) + subcloud12 = self.create_subcloud_static( + self.ctx, + name='subcloud12', + deploy_status=consts.DEPLOY_STATE_ABORTING_INSTALL) + subcloud13 = self.create_subcloud_static( + self.ctx, + name='subcloud13', + deploy_status=consts.DEPLOY_STATE_ABORTING_BOOTSTRAP) + subcloud14 = self.create_subcloud_static( + self.ctx, + name='subcloud14', + deploy_status=consts.DEPLOY_STATE_ABORTING_CONFIG) sm = subcloud_manager.SubcloudManager() sm.handle_subcloud_operations_in_progress() subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud1.name) - self.assertEqual(consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, + self.assertEqual(consts.DEPLOY_STATE_PRE_CONFIG_FAILED, subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud2.name) @@ -1954,7 +1897,7 @@ class TestSubcloudManager(base.DCManagerTestCase): subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud5.name) - self.assertEqual(consts.DEPLOY_STATE_DEPLOY_FAILED, + self.assertEqual(consts.DEPLOY_STATE_CONFIG_FAILED, subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud6.name) @@ -1970,14 +1913,34 @@ class TestSubcloudManager(base.DCManagerTestCase): subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud9.name) - self.assertEqual(consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, + self.assertEqual(consts.DEPLOY_STATE_CREATE_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud10.name) + self.assertEqual(consts.DEPLOY_STATE_CREATE_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud11.name) + self.assertEqual(consts.DEPLOY_STATE_PRE_BOOTSTRAP_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud12.name) + self.assertEqual(consts.DEPLOY_STATE_INSTALL_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud13.name) + self.assertEqual(consts.DEPLOY_STATE_BOOTSTRAP_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud14.name) + self.assertEqual(consts.DEPLOY_STATE_CONFIG_FAILED, subcloud.deploy_status) def test_handle_completed_subcloud_operations(self): subcloud1 = self.create_subcloud_static( self.ctx, name='subcloud1', - deploy_status=consts.DEPLOY_STATE_DEPLOY_PREP_FAILED) + deploy_status=consts.DEPLOY_STATE_CREATE_FAILED) subcloud2 = self.create_subcloud_static( self.ctx, name='subcloud2', @@ -1997,7 +1960,7 @@ class TestSubcloudManager(base.DCManagerTestCase): subcloud6 = self.create_subcloud_static( self.ctx, name='subcloud6', - deploy_status=consts.DEPLOY_STATE_DEPLOY_FAILED) + deploy_status=consts.DEPLOY_STATE_CONFIG_FAILED) subcloud7 = self.create_subcloud_static( self.ctx, name='subcloud7', @@ -2018,12 +1981,24 @@ class TestSubcloudManager(base.DCManagerTestCase): self.ctx, name='subcloud11', deploy_status=consts.DEPLOY_STATE_DONE) + subcloud12 = self.create_subcloud_static( + self.ctx, + name='subcloud12', + deploy_status=consts.DEPLOY_STATE_CREATE_FAILED) + subcloud13 = self.create_subcloud_static( + self.ctx, + name='subcloud13', + deploy_status=consts.DEPLOY_STATE_PRE_BOOTSTRAP_FAILED) + subcloud14 = self.create_subcloud_static( + self.ctx, + name='subcloud14', + deploy_status=consts.DEPLOY_STATE_PRE_CONFIG_FAILED) sm = subcloud_manager.SubcloudManager() sm.handle_subcloud_operations_in_progress() subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud1.name) - self.assertEqual(consts.DEPLOY_STATE_DEPLOY_PREP_FAILED, + self.assertEqual(consts.DEPLOY_STATE_CREATE_FAILED, subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud2.name) @@ -2043,7 +2018,7 @@ class TestSubcloudManager(base.DCManagerTestCase): subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud6.name) - self.assertEqual(consts.DEPLOY_STATE_DEPLOY_FAILED, + self.assertEqual(consts.DEPLOY_STATE_CONFIG_FAILED, subcloud.deploy_status) subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud7.name) @@ -2066,6 +2041,18 @@ class TestSubcloudManager(base.DCManagerTestCase): self.assertEqual(consts.DEPLOY_STATE_DONE, subcloud.deploy_status) + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud12.name) + self.assertEqual(consts.DEPLOY_STATE_CREATE_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud13.name) + self.assertEqual(consts.DEPLOY_STATE_PRE_BOOTSTRAP_FAILED, + subcloud.deploy_status) + + subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud14.name) + self.assertEqual(consts.DEPLOY_STATE_PRE_CONFIG_FAILED, + subcloud.deploy_status) + @mock.patch.object(cutils, 'is_subcloud_healthy', return_value=True) @mock.patch.object(subcloud_manager.SubcloudManager, '_run_subcloud_backup_create_playbook')