diff --git a/api-ref/source/api-ref-dcmanager-v1.rst b/api-ref/source/api-ref-dcmanager-v1.rst index 2df4d5310..2ff5afd1d 100644 --- a/api-ref/source/api-ref-dcmanager-v1.rst +++ b/api-ref/source/api-ref-dcmanager-v1.rst @@ -78,6 +78,7 @@ Response - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -173,6 +174,7 @@ Request Example - management-gateway-ip: management_gateway_ip - management-start-ip: management_start_ip - management-end-ip: management_end_ip + - region-name: region_name Response Example ---------------- @@ -283,6 +285,7 @@ This operation does not accept a request body. - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -314,6 +317,8 @@ Modifies a specific subcloud The attributes of a subcloud which are modifiable: +- name + - description - location @@ -349,6 +354,7 @@ serviceUnavailable (503) .. rest_parameters:: parameters.yaml - subcloud: subcloud_uri + - name: subcloud_name - description: subcloud_description - location: subcloud_location - management-state: subcloud_management_state @@ -382,6 +388,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -526,6 +533,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -857,6 +865,7 @@ This operation does not accept a request body. - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -1025,6 +1034,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -1136,6 +1146,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -1830,6 +1841,7 @@ Request Example - backup-status: backup_status - backup-datetime: backup_datetime - error-description: error_description + - region-name: region_name - management-subnet: management_subnet - management-start-ip: management_start_ip - management-end-ip: management_end_ip @@ -1897,6 +1909,7 @@ Request Example - backup-status: backup_status - backup-datetime: backup_datetime - error-description: error_description + - region-name: region_name - management-subnet: management_subnet - management-start-ip: management_start_ip - management-end-ip: management_end_ip @@ -1963,6 +1976,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -2036,6 +2050,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -2103,6 +2118,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -2170,6 +2186,7 @@ Request Example - deploy-status: deploy_status - backup-status: backup_status - backup-datetime: backup_datetime + - region-name: region_name - openstack-installed: openstack_installed - management-state: management_state - systemcontroller-gateway-ip: systemcontroller_gateway_ip @@ -2246,6 +2263,7 @@ Request Example - backup-status: backup_status - backup-datetime: backup_datetime - error-description: error_description + - region-name: region_name - management-subnet: management_subnet - management-start-ip: management_start_ip - management-end-ip: management_end_ip diff --git a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-abort-response.json b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-abort-response.json index 18b325132..770f39975 100644 --- a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-abort-response.json +++ b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-abort-response.json @@ -9,6 +9,7 @@ "deploy-status": "aborting-install", "backup-status": null, "backup-datetime": null, + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-configure-response.json b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-configure-response.json index 55777e614..ca2a3ae62 100644 --- a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-configure-response.json +++ b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-configure-response.json @@ -9,6 +9,7 @@ "deploy-status": "complete", "backup-status": "complete", "backup-datetime": "2023-05-02 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-continue-response.json b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-continue-response.json index 7a53a1913..b8ebe79fb 100644 --- a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-continue-response.json +++ b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-continue-response.json @@ -9,6 +9,7 @@ "deploy-status": "complete", "backup-status": "complete", "backup-datetime": "2023-05-02 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-resume-response.json b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-resume-response.json index d976dcaf3..7dec4e70b 100644 --- a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-resume-response.json +++ b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-patch-resume-response.json @@ -10,6 +10,7 @@ "backup-status": null, "backup-datetime": null, "error-description": "No errors present", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "management-subnet": "192.168.102.0/24", "management-start-ip": "192.168.102.2", "management-end-ip": "192.168.102.50", diff --git a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-install-response.json b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-install-response.json index 39e056326..1c6b35d55 100644 --- a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-install-response.json +++ b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-install-response.json @@ -9,6 +9,7 @@ "deploy-status": "pre-install", "backup-status": null, "backup-datetime": null, + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-response.json b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-response.json index 9cbb22e62..8a95cd020 100644 --- a/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-response.json +++ b/api-ref/source/samples/phased-subcloud-deploy/phased-subcloud-deploy-post-response.json @@ -10,6 +10,7 @@ "backup-status": null, "backup-datetime": null, "error-description": "No errors present", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "management-subnet": "192.168.102.0/24", "management-start-ip": "192.168.102.2", "management-end-ip": "192.168.102.50", diff --git a/api-ref/source/samples/subcloud-backup/subcloud-create-backup-response.json b/api-ref/source/samples/subcloud-backup/subcloud-create-backup-response.json index af25e74dd..bcb5b8171 100644 --- a/api-ref/source/samples/subcloud-backup/subcloud-create-backup-response.json +++ b/api-ref/source/samples/subcloud-backup/subcloud-create-backup-response.json @@ -14,6 +14,7 @@ "error-description": "", "backup-status": "complete", "backup-datetime": "2022-07-08 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/subcloud-backup/subcloud-restore-backup-response.json b/api-ref/source/samples/subcloud-backup/subcloud-restore-backup-response.json index b1cc38773..84ac2f34c 100644 --- a/api-ref/source/samples/subcloud-backup/subcloud-restore-backup-response.json +++ b/api-ref/source/samples/subcloud-backup/subcloud-restore-backup-response.json @@ -14,6 +14,7 @@ "error-description": "", "backup-status": "complete", "backup-datetime": "2022-07-08 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/subcloud-groups/subcloud-groups-get-subclouds-response.json b/api-ref/source/samples/subcloud-groups/subcloud-groups-get-subclouds-response.json index 5c5bcf234..ba52a7b86 100644 --- a/api-ref/source/samples/subcloud-groups/subcloud-groups-get-subclouds-response.json +++ b/api-ref/source/samples/subcloud-groups/subcloud-groups-get-subclouds-response.json @@ -12,6 +12,7 @@ "deploy-status": "complete", "backup-status": "complete", "backup-datetime": "2022-07-08 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "openstack-installed": false, "management-state": "managed", "systemcontroller-gateway-ip": "192.168.204.101", diff --git a/api-ref/source/samples/subclouds/subcloud-get-detail-response.json b/api-ref/source/samples/subclouds/subcloud-get-detail-response.json index 6690b8424..90c7ec71d 100644 --- a/api-ref/source/samples/subclouds/subcloud-get-detail-response.json +++ b/api-ref/source/samples/subclouds/subcloud-get-detail-response.json @@ -21,7 +21,8 @@ "data_install": null, "data_upgrade": null, "oam_floating_ip": "192.168.101.2", - "deploy_config_sync_status": "Deployment: configurations up-to-date" + "deploy_config_sync_status": "Deployment: configurations up-to-date", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "endpoint_sync_status": [ { "sync_status": "in-sync", diff --git a/api-ref/source/samples/subclouds/subcloud-patch-prestage-response.json b/api-ref/source/samples/subclouds/subcloud-patch-prestage-response.json index 872eb5289..a863484aa 100644 --- a/api-ref/source/samples/subclouds/subcloud-patch-prestage-response.json +++ b/api-ref/source/samples/subclouds/subcloud-patch-prestage-response.json @@ -11,6 +11,7 @@ "deploy-status": "complete", "backup-status": "complete", "backup-datetime": "2022-07-08 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/subclouds/subcloud-patch-response.json b/api-ref/source/samples/subclouds/subcloud-patch-response.json index abf248c26..dff913e30 100644 --- a/api-ref/source/samples/subclouds/subcloud-patch-response.json +++ b/api-ref/source/samples/subclouds/subcloud-patch-response.json @@ -9,6 +9,7 @@ "deploy-status": "complete", "backup-status": "complete", "backup-datetime": "2022-07-08 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "description": "Ottawa Site", "group_id": 1, "location": "YOW", diff --git a/api-ref/source/samples/subclouds/subclouds-get-response.json b/api-ref/source/samples/subclouds/subclouds-get-response.json index 8cb90c0f3..6bc27a6de 100644 --- a/api-ref/source/samples/subclouds/subclouds-get-response.json +++ b/api-ref/source/samples/subclouds/subclouds-get-response.json @@ -12,6 +12,7 @@ "deploy-status": "complete", "backup-status": "complete", "backup-datetime": "2022-07-08 11:23:58.132134", + "region-name": "bbadb3e8e2ab473792c80ef09c5a12a4", "openstack-installed": false, "management-state": "managed", "systemcontroller-gateway-ip": "192.168.204.101", diff --git a/api-ref/source/samples/subclouds/subclouds-post-response.json b/api-ref/source/samples/subclouds/subclouds-post-response.json index 6259afafc..ef1abce0a 100644 --- a/api-ref/source/samples/subclouds/subclouds-post-response.json +++ b/api-ref/source/samples/subclouds/subclouds-post-response.json @@ -13,5 +13,6 @@ "management-gateway-ip": "192.168.205.1", "management-end-ip": "192.168.205.160", "id": 4, - "name": "subcloud7" + "name": "subcloud7", + "region-name": "b098933127ed408e9ad7f6e81c587edb" } diff --git a/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py b/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py index f6d94c17d..1b4013e71 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py +++ b/distributedcloud/dcmanager/api/controllers/v1/phased_subcloud_deploy.py @@ -171,6 +171,8 @@ class PhasedSubcloudDeployController(object): payload = get_create_payload(request) + psd_common.subcloud_region_create(payload, context) + psd_common.pre_deploy_create(payload, context, request) try: diff --git a/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py b/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py index abb57f728..5503c14ba 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py +++ b/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py @@ -201,7 +201,7 @@ class SubcloudBackupController(object): and request_entity.type == 'subcloud'): # Check the system health only if the command was issued # to a single subcloud to avoid huge delays. - if not utils.is_subcloud_healthy(subcloud.name): + if not utils.is_subcloud_healthy(subcloud.region_name): msg = _('Subcloud %s must be in good health for ' 'subcloud-backup create.' % subcloud.name) pecan.abort(400, msg) diff --git a/distributedcloud/dcmanager/api/controllers/v1/subclouds.py b/distributedcloud/dcmanager/api/controllers/v1/subclouds.py index daa0f6a1d..ca04a8e1a 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/subclouds.py +++ b/distributedcloud/dcmanager/api/controllers/v1/subclouds.py @@ -404,6 +404,10 @@ class SubcloudsController(object): first_time = False for s in subcloud_list: + # This is to reduce changes on cert-mon + # Overwrites the name value with region + if utils.is_req_from_cert_mon_agent(request): + s['name'] = s['region-name'] result['subclouds'].append(s) return result @@ -421,11 +425,19 @@ class SubcloudsController(object): except exceptions.SubcloudNotFound: pecan.abort(404, _('Subcloud not found')) else: - # Look up subcloud by name try: - subcloud = db_api.subcloud_get_by_name(context, - subcloud_ref) - except exceptions.SubcloudNameNotFound: + # This method replaces subcloud_get_by_name, since it + # allows to lookup the subcloud either by region name + # or subcloud name. + # When the request comes from the cert-monitor, it is + # based on the region name (which is UUID format). + # Whereas, if the request comes from a client other + # than cert-monitor, it will do the lookup based on + # the subcloud name. + subcloud = db_api.subcloud_get_by_name_or_region_name( + context, + subcloud_ref) + except exceptions.SubcloudNameOrRegionNameNotFound: pecan.abort(404, _('Subcloud not found')) subcloud_id = subcloud.id @@ -448,6 +460,8 @@ class SubcloudsController(object): self._append_static_err_content(subcloud_dict) + subcloud_region = subcloud.region_name + subcloud_dict.pop('region-name') if detail is not None: oam_floating_ip = "unavailable" deploy_config_sync_status = "unknown" @@ -455,19 +469,20 @@ class SubcloudsController(object): # Get the keystone client that will be used # for _get_deploy_config_sync_status and _get_oam_addresses - sc_ks_client = psd_common.get_ks_client(subcloud.name) + sc_ks_client = psd_common.get_ks_client(subcloud_region) oam_addresses = self._get_oam_addresses(context, - subcloud.name, sc_ks_client) + subcloud_region, sc_ks_client) if oam_addresses is not None: oam_floating_ip = oam_addresses.oam_floating_ip deploy_config_state = self._get_deploy_config_sync_status( - context, subcloud.name, sc_ks_client) + context, subcloud_region, sc_ks_client) if deploy_config_state is not None: deploy_config_sync_status = deploy_config_state extra_details = {"oam_floating_ip": oam_floating_ip, - "deploy_config_sync_status": deploy_config_sync_status} + "deploy_config_sync_status": deploy_config_sync_status, + "region_name": subcloud_region} subcloud_dict.update(extra_details) return subcloud_dict @@ -481,6 +496,8 @@ class SubcloudsController(object): restcomm.extract_credentials_for_policy()) context = restcomm.extract_context_from_environ() + bootstrap_sc_name = psd_common.get_bootstrap_subcloud_name(request) + payload = psd_common.get_request_data(request, None, SUBCLOUD_ADD_GET_FILE_CONTENTS) @@ -488,10 +505,19 @@ class SubcloudsController(object): psd_common.validate_secondary_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: + if bootstrap_sc_name != payload.get('name'): + pecan.abort(400, _('subcloud name does not match the ' + 'name defined in bootstrap file')) + # No need sysadmin_password when add a secondary subcloud if 'secondary' not in payload: psd_common.validate_sysadmin_password(payload) + psd_common.subcloud_region_create(payload, context) + psd_common.pre_deploy_create(payload, context, request) try: @@ -537,12 +563,21 @@ class SubcloudsController(object): except exceptions.SubcloudNotFound: pecan.abort(404, _('Subcloud not found')) else: - # Look up subcloud by name try: - subcloud = db_api.subcloud_get_by_name(context, - subcloud_ref) - except exceptions.SubcloudNameNotFound: - pecan.abort(404, _('Subcloud not found')) + # This method replaces subcloud_get_by_name, since it + # allows to lookup the subcloud either by region name + # or subcloud name. + # When the request comes from the cert-monitor, it is + # based on the region name (which is UUID format). + # Whereas, if the request comes from a client other + # than cert-monitor, it will do the lookup based on + # the subcloud name. + subcloud = db_api.subcloud_get_by_name_or_region_name( + context, + subcloud_ref) + except exceptions.SubcloudNameOrRegionNameNotFound: + pecan.abort(404, _('Subcloud not found')) + subcloud_id = subcloud.id if verb is None: @@ -551,6 +586,43 @@ class SubcloudsController(object): if not payload: pecan.abort(400, _('Body required')) + # Rename the subcloud + new_subcloud_name = payload.get('name') + if new_subcloud_name is not None: + # To be renamed the subcloud must be in unmanaged and valid deploy state + if subcloud.management_state != dccommon_consts.MANAGEMENT_UNMANAGED \ + or subcloud.deploy_status not in consts.STATES_FOR_SUBCLOUD_RENAME: + msg = ('Subcloud %s must be unmanaged and in a valid deploy state ' + 'for the subcloud rename operation.' % subcloud.name) + + # Validates new name + if not utils.is_subcloud_name_format_valid(new_subcloud_name): + pecan.abort(400, _("new name must contain alphabetic characters")) + + # Checks if new subcloud name is the same as the current subcloud + if new_subcloud_name == subcloud.name: + pecan.abort(400, _('Provided subcloud name %s is the same as the ' + 'current subcloud %s. A different name is ' + 'required to rename the subcloud' % + (new_subcloud_name, subcloud.name))) + + error_msg = ('Unable to rename subcloud %s with their region %s to %s' % + (subcloud.name, subcloud.region_name, new_subcloud_name)) + try: + LOG.info("Renaming subcloud %s to: %s\n" % (subcloud.name, + new_subcloud_name)) + sc = self.dcmanager_rpc_client.rename_subcloud(context, + subcloud_id, + subcloud.name, + new_subcloud_name) + subcloud.name = sc['name'] + except RemoteError as e: + LOG.error(error_msg) + pecan.abort(422, e.value) + except Exception: + LOG.error(error_msg) + pecan.abort(500, _('Unable to rename subcloud')) + # Check if exist any network reconfiguration parameters reconfigure_network = any(payload.get(value) is not None for value in ( SUBCLOUD_MANDATORY_NETWORK_PARAMS)) @@ -562,6 +634,7 @@ class SubcloudsController(object): system_controller_mgmt_pool = psd_common.get_network_address_pool() # Required parameters payload['name'] = subcloud.name + payload['region_name'] = subcloud.region_name payload['system_controller_network'] = ( system_controller_mgmt_pool.network) payload['system_controller_network_prefix'] = ( @@ -715,7 +788,7 @@ class SubcloudsController(object): 'Please use /v1.0/subclouds/{subcloud}/redeploy')) elif verb == 'update_status': - res = self.updatestatus(subcloud.name) + res = self.updatestatus(subcloud.name, subcloud.region_name) return res elif verb == 'prestage': if utils.subcloud_is_secondary_state(subcloud.deploy_status): @@ -816,10 +889,11 @@ class SubcloudsController(object): LOG.exception(e) pecan.abort(500, _('Unable to delete subcloud')) - def updatestatus(self, subcloud_name): + def updatestatus(self, subcloud_name, subcloud_region): """Update subcloud sync status :param subcloud_name: name of the subcloud + :param subcloud_region: name of the subcloud region :return: json result object for the operation on success """ @@ -848,7 +922,7 @@ class SubcloudsController(object): LOG.info('update %s set %s=%s' % (subcloud_name, endpoint, status)) context = restcomm.extract_context_from_environ() self.dcmanager_state_rpc_client.update_subcloud_endpoint_status( - context, subcloud_name, endpoint, status) + context, subcloud_name, subcloud_region, endpoint, status) result = {'result': 'OK'} return result diff --git a/distributedcloud/dcmanager/audit/auditor.py b/distributedcloud/dcmanager/audit/auditor.py index 5b5c9e18d..28191944a 100644 --- a/distributedcloud/dcmanager/audit/auditor.py +++ b/distributedcloud/dcmanager/audit/auditor.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2021-2022 Wind River Systems, Inc. +# Copyright (c) 2021-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -20,21 +20,22 @@ class Auditor(object): self.state_rpc_client = dcmanager_state_rpc_client self.endpoint_type = endpoint_type - def _set_subcloud_sync_status(self, sc_name, sc_sync_status): + def _set_subcloud_sync_status(self, sc_name, sc_region, sc_sync_status): """Update the sync status for endpoint.""" self.state_rpc_client.update_subcloud_endpoint_status( self.context, subcloud_name=sc_name, + subcloud_region=sc_region, endpoint_type=self.endpoint_type, sync_status=sc_sync_status) - def set_subcloud_endpoint_in_sync(self, sc_name): + def set_subcloud_endpoint_in_sync(self, sc_name, sc_region): """Set the endpoint sync status of this subcloud to be in sync""" - self._set_subcloud_sync_status(sc_name, dccommon_consts.SYNC_STATUS_IN_SYNC) + self._set_subcloud_sync_status(sc_name, sc_region, dccommon_consts.SYNC_STATUS_IN_SYNC) - def set_subcloud_endpoint_out_of_sync(self, sc_name): + def set_subcloud_endpoint_out_of_sync(self, sc_name, sc_region): """Set the endpoint sync status of this subcloud to be out of sync""" - self._set_subcloud_sync_status(sc_name, + self._set_subcloud_sync_status(sc_name, sc_region, dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) @abc.abstractmethod diff --git a/distributedcloud/dcmanager/audit/firmware_audit.py b/distributedcloud/dcmanager/audit/firmware_audit.py index c71c61adc..401fb8717 100644 --- a/distributedcloud/dcmanager/audit/firmware_audit.py +++ b/distributedcloud/dcmanager/audit/firmware_audit.py @@ -1,5 +1,5 @@ # Copyright 2017 Ericsson AB. -# Copyright (c) 2017-2022 Wind River Systems, Inc. +# Copyright (c) 2017-2023 Wind River Systems, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -75,11 +75,12 @@ class FirmwareAudit(object): self.state_rpc_client = dcmanager_state_rpc_client self.audit_count = 0 - def _update_subcloud_sync_status(self, sc_name, sc_endpoint_type, + def _update_subcloud_sync_status(self, sc_name, sc_region, sc_endpoint_type, sc_status): self.state_rpc_client.update_subcloud_endpoint_status( self.context, subcloud_name=sc_name, + subcloud_region=sc_region, endpoint_type=sc_endpoint_type, sync_status=sc_status) @@ -225,19 +226,20 @@ class FirmwareAudit(object): return False return True - def subcloud_firmware_audit(self, subcloud_name, audit_data): + def subcloud_firmware_audit(self, subcloud_name, subcloud_region, audit_data): LOG.info('Triggered firmware audit for: %s.' % subcloud_name) if not audit_data: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, dccommon_consts.SYNC_STATUS_IN_SYNC) LOG.debug('No images to audit, exiting firmware audit') return try: - sc_os_client = OpenStackDriver(region_name=subcloud_name, + sc_os_client = OpenStackDriver(region_name=subcloud_region, region_clients=None).keystone_client endpoint = sc_os_client.endpoint_cache.get_endpoint('sysinv') - sysinv_client = SysinvClient(subcloud_name, sc_os_client.session, + sysinv_client = SysinvClient(subcloud_region, sc_os_client.session, endpoint=endpoint) except (keystone_exceptions.EndpointNotFound, keystone_exceptions.ConnectFailure, @@ -267,7 +269,8 @@ class FirmwareAudit(object): LOG.info("No enabled devices on the subcloud %s," "exiting firmware audit" % subcloud_name) self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, dccommon_consts.SYNC_STATUS_IN_SYNC) return @@ -312,10 +315,12 @@ class FirmwareAudit(object): if out_of_sync: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) else: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_FIRMWARE, dccommon_consts.SYNC_STATUS_IN_SYNC) LOG.info('Firmware audit completed for: %s.' % subcloud_name) diff --git a/distributedcloud/dcmanager/audit/kube_rootca_update_audit.py b/distributedcloud/dcmanager/audit/kube_rootca_update_audit.py index 8c8fb53fa..d68d71dd4 100644 --- a/distributedcloud/dcmanager/audit/kube_rootca_update_audit.py +++ b/distributedcloud/dcmanager/audit/kube_rootca_update_audit.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2021-2022 Wind River Systems, Inc. +# Copyright (c) 2021-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -46,20 +46,21 @@ class KubeRootcaUpdateAudit(Auditor): """ return [] - def subcloud_audit(self, subcloud_name, region_one_audit_data): + def subcloud_audit(self, subcloud_name, subcloud_region, region_one_audit_data): """Perform an audit of kube root CA update info in a subcloud. :param subcloud_name: the name of the subcloud + :param subcloud_region: the region of the subcloud :param region_one_audit_data: ignored. Always an empty list """ LOG.info("Triggered %s audit for: %s" % (self.audit_type, subcloud_name)) # check for a particular alarm in the subcloud try: - sc_os_client = OpenStackDriver(region_name=subcloud_name, + sc_os_client = OpenStackDriver(region_name=subcloud_region, region_clients=None) session = sc_os_client.keystone_client.session - fm_client = FmClient(subcloud_name, session) + fm_client = FmClient(subcloud_region, session) except (keystone_exceptions.EndpointNotFound, keystone_exceptions.ConnectFailure, keystone_exceptions.ConnectTimeout, @@ -75,8 +76,8 @@ class KubeRootcaUpdateAudit(Auditor): out_of_sync = True break if out_of_sync: - self.set_subcloud_endpoint_out_of_sync(subcloud_name) + self.set_subcloud_endpoint_out_of_sync(subcloud_name, subcloud_region) else: - self.set_subcloud_endpoint_in_sync(subcloud_name) + self.set_subcloud_endpoint_in_sync(subcloud_name, subcloud_region) LOG.info("%s audit completed for: %s" % (self.audit_type, subcloud_name)) diff --git a/distributedcloud/dcmanager/audit/kubernetes_audit.py b/distributedcloud/dcmanager/audit/kubernetes_audit.py index 0c17e457a..b3a3afcd5 100644 --- a/distributedcloud/dcmanager/audit/kubernetes_audit.py +++ b/distributedcloud/dcmanager/audit/kubernetes_audit.py @@ -1,5 +1,5 @@ # Copyright 2017 Ericsson AB. -# Copyright (c) 2017-2022 Wind River Systems, Inc. +# Copyright (c) 2017-2023 Wind River Systems, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,11 +55,12 @@ class KubernetesAudit(object): self.state_rpc_client = dcmanager_state_rpc_client self.audit_count = 0 - def _update_subcloud_sync_status(self, sc_name, sc_endpoint_type, + def _update_subcloud_sync_status(self, sc_name, sc_region, sc_endpoint_type, sc_status): self.state_rpc_client.update_subcloud_endpoint_status( self.context, subcloud_name=sc_name, + subcloud_region=sc_region, endpoint_type=sc_endpoint_type, sync_status=sc_status) @@ -90,19 +91,20 @@ class KubernetesAudit(object): LOG.debug("RegionOne kubernetes versions: %s" % region_one_data) return region_one_data - def subcloud_kubernetes_audit(self, subcloud_name, audit_data): + def subcloud_kubernetes_audit(self, subcloud_name, subcloud_region, audit_data): LOG.info('Triggered kubernetes audit for: %s' % subcloud_name) if not audit_data: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_KUBERNETES, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_KUBERNETES, dccommon_consts.SYNC_STATUS_IN_SYNC) LOG.debug('No region one audit data, exiting kubernetes audit') return try: - sc_os_client = OpenStackDriver(region_name=subcloud_name, + sc_os_client = OpenStackDriver(region_name=subcloud_region, region_clients=None).keystone_client endpoint = sc_os_client.endpoint_cache.get_endpoint('sysinv') - sysinv_client = SysinvClient(subcloud_name, sc_os_client.session, + sysinv_client = SysinvClient(subcloud_region, sc_os_client.session, endpoint=endpoint) except (keystone_exceptions.EndpointNotFound, keystone_exceptions.ConnectFailure, @@ -152,10 +154,12 @@ class KubernetesAudit(object): if out_of_sync: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_KUBERNETES, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_KUBERNETES, dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) else: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_KUBERNETES, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_KUBERNETES, dccommon_consts.SYNC_STATUS_IN_SYNC) LOG.info('Kubernetes audit completed for: %s' % subcloud_name) diff --git a/distributedcloud/dcmanager/audit/patch_audit.py b/distributedcloud/dcmanager/audit/patch_audit.py index 3310682ec..85addeb8c 100644 --- a/distributedcloud/dcmanager/audit/patch_audit.py +++ b/distributedcloud/dcmanager/audit/patch_audit.py @@ -1,5 +1,5 @@ # Copyright 2017 Ericsson AB. -# Copyright (c) 2017-2022 Wind River Systems, Inc. +# Copyright (c) 2017-2023 Wind River Systems, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -62,11 +62,12 @@ class PatchAudit(object): self.state_rpc_client = dcmanager_state_rpc_client self.audit_count = 0 - def _update_subcloud_sync_status(self, sc_name, sc_endpoint_type, + def _update_subcloud_sync_status(self, sc_name, sc_region, sc_endpoint_type, sc_status): self.state_rpc_client.update_subcloud_endpoint_status( self.context, subcloud_name=sc_name, + subcloud_region=sc_region, endpoint_type=sc_endpoint_type, sync_status=sc_status) @@ -132,19 +133,19 @@ class PatchAudit(object): return PatchAuditData(regionone_patches, applied_patch_ids, committed_patch_ids, regionone_software_version) - def subcloud_patch_audit(self, subcloud_name, audit_data, do_load_audit): + def subcloud_patch_audit(self, subcloud_name, subcloud_region, audit_data, do_load_audit): LOG.info('Triggered patch audit for: %s.' % subcloud_name) try: - sc_os_client = OpenStackDriver(region_name=subcloud_name, + sc_os_client = OpenStackDriver(region_name=subcloud_region, region_clients=None).keystone_client session = sc_os_client.session patching_endpoint = sc_os_client.endpoint_cache.get_endpoint('patching') sysinv_endpoint = sc_os_client.endpoint_cache.get_endpoint('sysinv') patching_client = PatchingClient( - subcloud_name, session, + subcloud_region, session, endpoint=patching_endpoint) sysinv_client = SysinvClient( - subcloud_name, session, + subcloud_region, session, endpoint=sysinv_endpoint) except (keystone_exceptions.EndpointNotFound, keystone_exceptions.ConnectFailure, @@ -227,11 +228,13 @@ class PatchAudit(object): if out_of_sync: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_PATCHING, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_PATCHING, dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) else: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_PATCHING, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_PATCHING, dccommon_consts.SYNC_STATUS_IN_SYNC) # Check subcloud software version every other audit cycle @@ -251,16 +254,19 @@ class PatchAudit(object): if subcloud_software_version == audit_data.software_version: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_LOAD, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_LOAD, dccommon_consts.SYNC_STATUS_IN_SYNC) else: self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_LOAD, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_LOAD, dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) else: # As upgrade is still in progress, set the subcloud load # status as out-of-sync. self._update_subcloud_sync_status( - subcloud_name, dccommon_consts.ENDPOINT_TYPE_LOAD, + subcloud_name, + subcloud_region, dccommon_consts.ENDPOINT_TYPE_LOAD, dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) LOG.info('Patch audit completed for: %s.' % subcloud_name) diff --git a/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py b/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py index e5215b1ea..88f7aa3a0 100644 --- a/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py +++ b/distributedcloud/dcmanager/audit/subcloud_audit_worker_manager.py @@ -153,7 +153,7 @@ class SubcloudAuditWorkerManager(manager.Manager): # Create a new greenthread for each subcloud to allow the audits # to be done in parallel. If there are not enough greenthreads # in the pool, this will block until one becomes available. - self.subcloud_workers[subcloud.name] = \ + self.subcloud_workers[subcloud.region_name] = \ self.thread_group_manager.start(self._do_audit_subcloud, subcloud, update_subcloud_state, @@ -204,12 +204,13 @@ class SubcloudAuditWorkerManager(manager.Manager): 'audit_fail_count for subcloud: %s' % subcloud.name) def _update_subcloud_availability(self, subcloud_name, + subcloud_region, availability_status=None, update_state_only=False, audit_fail_count=None): try: self.state_rpc_client.update_subcloud_availability( - self.context, subcloud_name, availability_status, + self.context, subcloud_name, subcloud_region, availability_status, update_state_only, audit_fail_count) LOG.info('Notifying dcmanager-state, subcloud:%s, availability:%s' % (subcloud_name, @@ -339,7 +340,7 @@ class SubcloudAuditWorkerManager(manager.Manager): db_api.subcloud_audits_end_audit(self.context, subcloud.id, audits_done) # Remove the worker for this subcloud - self.subcloud_workers.pop(subcloud.name, None) + self.subcloud_workers.pop(subcloud.region_name, None) LOG.debug("PID: %s, done auditing subcloud: %s." % (self.pid, subcloud.name)) @@ -361,6 +362,7 @@ class SubcloudAuditWorkerManager(manager.Manager): avail_status_current = subcloud.availability_status audit_fail_count = subcloud.audit_fail_count subcloud_name = subcloud.name + subcloud_region = subcloud.region_name audits_done = list() failures = list() @@ -371,7 +373,7 @@ class SubcloudAuditWorkerManager(manager.Manager): fm_client = None avail_to_set = dccommon_consts.AVAILABILITY_OFFLINE try: - os_client = OpenStackDriver(region_name=subcloud_name, + os_client = OpenStackDriver(region_name=subcloud_region, thread_name='subcloud-audit', region_clients=['fm', 'sysinv']) sysinv_client = os_client.sysinv_client @@ -452,6 +454,7 @@ class SubcloudAuditWorkerManager(manager.Manager): (avail_to_set, subcloud_name)) self._update_subcloud_availability( subcloud_name, + subcloud_region, availability_status=avail_to_set, audit_fail_count=audit_fail_count) @@ -470,6 +473,7 @@ class SubcloudAuditWorkerManager(manager.Manager): % subcloud_name) self._update_subcloud_availability( subcloud_name, + subcloud_region, availability_status=avail_status_current, update_state_only=True) @@ -488,6 +492,7 @@ class SubcloudAuditWorkerManager(manager.Manager): if do_patch_audit and patch_audit_data: try: self.patch_audit.subcloud_patch_audit(subcloud_name, + subcloud_region, patch_audit_data, do_load_audit) audits_done.append('patch') @@ -504,6 +509,7 @@ class SubcloudAuditWorkerManager(manager.Manager): if do_firmware_audit: try: self.firmware_audit.subcloud_firmware_audit(subcloud_name, + subcloud_region, firmware_audit_data) audits_done.append('firmware') except Exception: @@ -514,6 +520,7 @@ class SubcloudAuditWorkerManager(manager.Manager): try: self.kubernetes_audit.subcloud_kubernetes_audit( subcloud_name, + subcloud_region, kubernetes_audit_data) audits_done.append('kubernetes') except Exception: @@ -524,6 +531,7 @@ class SubcloudAuditWorkerManager(manager.Manager): try: self.kube_rootca_update_audit.subcloud_audit( subcloud_name, + subcloud_region, kube_rootca_update_audit_data) audits_done.append('kube-rootca-update') except Exception: @@ -536,7 +544,7 @@ class SubcloudAuditWorkerManager(manager.Manager): # audits_done to be empty: try: self._audit_subcloud_openstack_app( - subcloud_name, sysinv_client, subcloud.openstack_installed) + subcloud_region, sysinv_client, subcloud.openstack_installed) except Exception: LOG.exception(failmsg % (subcloud.name, 'openstack')) failures.append('openstack') diff --git a/distributedcloud/dcmanager/common/consts.py b/distributedcloud/dcmanager/common/consts.py index c54685daa..578e6e33e 100644 --- a/distributedcloud/dcmanager/common/consts.py +++ b/distributedcloud/dcmanager/common/consts.py @@ -418,3 +418,9 @@ ALTERNATE_DEPLOY_PLAYBOOK_DIR = ALTERNATE_DEPLOY_FILES_DIR + '/playbooks' DEPLOY_PLAYBOOK_POSTFIX = 'deployment-manager.yaml' SUPPORTED_UPGRADES_METADATA_FILE_PATH = '/usr/rootdirs/opt/upgrades/metadata.xml' + +# Required for subcloud name configuration +CERT_MON_HTTP_AGENT = 'cert-mon/1.0' +OS_REGION_NAME = "OS_REGION_NAME" +STATES_FOR_SUBCLOUD_RENAME = [DEPLOY_STATE_DONE, + PRESTAGE_STATE_COMPLETE] diff --git a/distributedcloud/dcmanager/common/exceptions.py b/distributedcloud/dcmanager/common/exceptions.py index 2d401b0b4..650a96733 100644 --- a/distributedcloud/dcmanager/common/exceptions.py +++ b/distributedcloud/dcmanager/common/exceptions.py @@ -115,6 +115,18 @@ class SubcloudNameNotFound(NotFound): message = _("Subcloud with name %(name)s doesn't exist.") +class SubcloudRegionNameNotFound(NotFound): + message = _("Subcloud with region name %(region_name)s doesn't exist.") + + +class SubcloudNameOrRegionNameNotFound(NotFound): + message = _("Subcloud with name or region name %(name)s doesn't exist.") + + +class SubcloudOrRegionNameAlreadyExists(Conflict): + message = _("Subcloud with name or region name %(name)s already exist.") + + class SubcloudNotOnline(DCManagerException): message = _("Subcloud is not online.") diff --git a/distributedcloud/dcmanager/common/phased_subcloud_deploy.py b/distributedcloud/dcmanager/common/phased_subcloud_deploy.py index 891aca398..9bd40a345 100644 --- a/distributedcloud/dcmanager/common/phased_subcloud_deploy.py +++ b/distributedcloud/dcmanager/common/phased_subcloud_deploy.py @@ -11,6 +11,7 @@ import typing import netaddr from oslo_log import log as logging +from oslo_utils import uuidutils import pecan import tsconfig.tsconfig as tsc import yaml @@ -730,7 +731,18 @@ def upload_deploy_config_file(request, payload): pecan.abort(400, _("No %s file uploaded" % consts.DEPLOY_CONFIG)) file_item.file.seek(0, os.SEEK_SET) - contents = file_item.file.read() + file_lines = file_item.file.readlines() + + # Updates the OS_REGION_NAME param which is required for deployment + contents = "" + for line in file_lines: + dec_line = line.decode('utf8') + if consts.OS_REGION_NAME in dec_line: + os_reg_item = dec_line.split(":") + dec_line = os_reg_item[0] + ": " + payload['region_name'] + "\n" + contents = contents + dec_line + contents = contents.encode() + # the deploy config needs to upload to the override location fn = get_config_file_path(payload['name'], consts.DEPLOY_CONFIG) upload_config_file(contents, fn, consts.DEPLOY_CONFIG) @@ -844,6 +856,9 @@ def add_subcloud_to_database(context, payload): if 'install_values' in payload: data_install = json.dumps(payload['install_values']) + LOG.info("Creating subcloud %s with region: %s", payload.get('name'), + payload.get('region_name')) + subcloud = db_api.subcloud_create( context, payload['name'], @@ -857,6 +872,7 @@ def add_subcloud_to_database(context, payload): payload['systemcontroller_gateway_address'], consts.DEPLOY_STATE_NONE, consts.ERROR_DESC_EMPTY, + payload['region_name'], False, group_id, data_install=data_install) @@ -1023,3 +1039,118 @@ def pre_deploy_bootstrap(context: RequestContext, payload: dict, # again: validate_system_controller_patch_status("bootstrap") validate_k8s_version(payload) + + +def get_bootstrap_subcloud_name(request: pecan.Request): + bootstrap_values = request.POST.get(consts.BOOTSTRAP_VALUES) + bootstrap_sc_name = None + if bootstrap_values is not None: + bootstrap_values.file.seek(0, os.SEEK_SET) + contents = bootstrap_values.file.read() + data = yaml.safe_load(contents.decode('utf8')) + bootstrap_sc_name = data.get('name') + + return bootstrap_sc_name + + +def get_region_value_from_subcloud(payload: dict): + subcloud_region = None + # It connects to the subcloud via the bootstrap-address IP and tries + # to get the region from it + if payload['bootstrap-address'] is not None: + try: + subcloud_region = utils.\ + get_region_from_subcloud_address(payload) + LOG.info("Retrieved region value from subcloud to be migrated: %s" + % subcloud_region) + if subcloud_region is None: + msg = ("Cannot find subcloud's region name from address: %s" + % payload['bootstrap-address']) + LOG.error(msg) + raise exceptions.InvalidParameterValue(err=msg) + except Exception: + LOG.error("Unable to retrieve the region value from subcloud " + "address %s" % payload['bootstrap-address']) + raise + return subcloud_region + + +def is_migrate_scenario(payload: dict): + migrate = False + migrate_str = payload.get('migrate') + + if migrate_str is not None: + if migrate_str == "true": + migrate = True + return migrate + + +def generate_subcloud_unique_region(context: RequestContext, payload: dict): + LOG.debug("Begin generate subcloud unique region for subcloud %s" + % payload['name']) + + is_migrate = is_migrate_scenario(payload) + migrate_sc_region = None + + # If migration flag is present, tries to connect to subcloud to + # get the region value + if is_migrate: + LOG.debug("The scenario matches that of the subcloud migration, " + "therefore it will try to obtain the value of the " + "region from subcloud %s..." % payload['name']) + migrate_sc_region = get_region_value_from_subcloud(payload) + else: + LOG.debug("The scenario matches that of creating a new subcloud, " + "so a region will be generated randomly for " + "subcloud %s..." % payload['name']) + while True: + # If migrate flag is not present, creates a random region value + if not is_migrate: + subcloud_region = uuidutils.generate_uuid().replace("-", "") + else: + # In the migration/rehome scenario uses the region value + # returned by queried subcloud + subcloud_region = migrate_sc_region + # Lookup region to check if exists + try: + db_api.subcloud_get_by_region_name(context, + subcloud_region) + LOG.info("Subcloud region: %s already exists. " + "Generating new one..." % (subcloud_region)) + # In the migration scenario, it is intended to use the + # same region that the current subcloud has, therefore + # another region value cannot be generated. + if is_migrate: + LOG.error("Subcloud region to migrate: %s already exists " + "and it is not allowed to generate a new region " + "for a subcloud migration" % (subcloud_region)) + raise exceptions.SubcloudAlreadyExists( + region_name=subcloud_region) + except exceptions.SubcloudRegionNameNotFound: + break + except Exception: + message = "Unable to generate subcloud region" + LOG.error(message) + raise + if not is_migrate: + LOG.info("Generated region for new subcloud %s: %s" + % (payload.get('name'), subcloud_region)) + else: + LOG.info("Region for subcloud %s to be migrated: %s" + % (payload.get('name'), subcloud_region)) + return subcloud_region + + +def subcloud_region_create(payload: dict, context: RequestContext): + try: + # Generates a unique region value + payload['region_name'] = generate_subcloud_unique_region(context, + payload) + except Exception: + # For logging purpose only + msg = "Unable to generate or retrieve region value" + if not is_migrate_scenario(payload): + msg = "Unable to generate region value to update deploy \ + config for subcloud %s" % payload.get('name') + LOG.exception(msg) + pecan.abort(400, _(msg)) diff --git a/distributedcloud/dcmanager/common/prestage.py b/distributedcloud/dcmanager/common/prestage.py index 208fe5875..4e5ed3da1 100644 --- a/distributedcloud/dcmanager/common/prestage.py +++ b/distributedcloud/dcmanager/common/prestage.py @@ -188,7 +188,7 @@ def validate_prestage(subcloud, payload): initial_subcloud_validate(subcloud, installed_loads, software_version) subcloud_type, system_health, oam_floating_ip = \ - _get_prestage_subcloud_info(subcloud.name) + _get_prestage_subcloud_info(subcloud) if subcloud_type != consts.SYSTEM_MODE_SIMPLEX: raise exceptions.PrestagePreCheckFailedException( @@ -287,18 +287,18 @@ def _prestage_standalone_thread(context, subcloud, payload): raise -def _get_prestage_subcloud_info(subcloud_name): +def _get_prestage_subcloud_info(subcloud): """Retrieve prestage data from the subcloud. Pull all required data here in order to minimize keystone/sysinv client interactions. """ try: - os_client = OpenStackDriver(region_name=subcloud_name, + os_client = OpenStackDriver(region_name=subcloud.region_name, region_clients=None) keystone_client = os_client.keystone_client endpoint = keystone_client.endpoint_cache.get_endpoint('sysinv') - sysinv_client = SysinvClient(subcloud_name, + sysinv_client = SysinvClient(subcloud.region_name, keystone_client.session, endpoint=endpoint) mode = sysinv_client.get_system().system_mode @@ -309,7 +309,7 @@ def _get_prestage_subcloud_info(subcloud_name): except Exception as e: LOG.exception(e) raise exceptions.PrestagePreCheckFailedException( - subcloud=subcloud_name, + subcloud=subcloud.name, details="Failed to retrieve subcloud system mode and system health.") diff --git a/distributedcloud/dcmanager/common/utils.py b/distributedcloud/dcmanager/common/utils.py index 7ef51a026..d7d75587e 100644 --- a/distributedcloud/dcmanager/common/utils.py +++ b/distributedcloud/dcmanager/common/utils.py @@ -55,6 +55,7 @@ DC_MANAGER_GRPNAME = "root" # Max lines output msg from logs MAX_LINES_MSG = 10 +REGION_VALUE_CMD = "grep " + consts.OS_REGION_NAME + " /etc/platform/openrc" ABORT_UPDATE_STATUS = { consts.DEPLOY_STATE_INSTALLING: consts.DEPLOY_STATE_ABORTING_INSTALL, @@ -552,23 +553,23 @@ def subcloud_db_list_to_dict(subclouds): for subcloud in subclouds]} -def get_oam_addresses(subcloud_name, sc_ks_client): +def get_oam_addresses(subcloud, sc_ks_client): """Get the subclouds oam addresses""" # First need to retrieve the Subcloud's Keystone session try: endpoint = sc_ks_client.endpoint_cache.get_endpoint('sysinv') - sysinv_client = SysinvClient(subcloud_name, + sysinv_client = SysinvClient(subcloud.region_name, sc_ks_client.session, endpoint=endpoint) return sysinv_client.get_oam_addresses() except (keystone_exceptions.EndpointNotFound, IndexError) as e: message = ("Identity endpoint for subcloud: %s not found. %s" % - (subcloud_name, e)) + (subcloud.name, e)) LOG.error(message) except dccommon_exceptions.OAMAddressesNotFound: message = ("OAM addresses for subcloud: %s not found." % - subcloud_name) + subcloud.name) LOG.error(message) return None @@ -596,6 +597,65 @@ def pre_check_management_affected_alarm(system_health): return True +def is_subcloud_name_format_valid(name): + """Validates subcloud name format + + Regex based on RFC 1123 subdomain validation + + param: name = Subcloud name + returns True if name is valid, otherwise it returns false. + """ + rex = r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*" + + pat = re.compile(rex) + if re.fullmatch(pat, name): + return True + return False + + +def get_region_from_subcloud_address(payload): + """Retrieves the current region from the subcloud being migrated + + param: payload = Subcloud payload + returns the OS_REGION_NAME value from subcloud + """ + cmd = [ + "sshpass", + "-p", + str(payload['sysadmin_password']), + "ssh", + "-q", + "sysadmin@" + str(payload['bootstrap-address']), + REGION_VALUE_CMD, + ] + + try: + LOG.info("Getting region value from subcloud %s" % payload['name']) + task = subprocess.check_output( + cmd, + stderr=subprocess.STDOUT).decode('utf-8') + if len(task) < 1: + return None + subcloud_region = str(task.split("=")[1]).strip() + except Exception: + LOG.error("Unable to get region value from subcloud %s" + % payload['name']) + raise + + system_regions = [dccommon_consts.DEFAULT_REGION_NAME, + dccommon_consts.SYSTEM_CONTROLLER_NAME] + + if subcloud_region in system_regions: + LOG.error("Invalid region value: %s" % subcloud_region) + raise exceptions.InvalidParameterValue( + err="Invalid region value: %s" % subcloud_region) + + # Returns the region value from result: + # Current systems: export OS_REGION_NAME=subcloudX + # New systems: export OS_REGION_NAME=abcdefghhijlkmnopqrstuvqxyz12342 + return subcloud_region + + def find_ansible_error_msg(subcloud_name, log_file, stage=None): """Find errors into ansible logs. @@ -817,15 +877,15 @@ def get_matching_iso(software_version=None): return None, str(e) -def is_subcloud_healthy(subcloud_name): +def is_subcloud_healthy(subcloud_region): system_health = "" try: - os_client = OpenStackDriver(region_name=subcloud_name, + os_client = OpenStackDriver(region_name=subcloud_region, region_clients=None) keystone_client = os_client.keystone_client endpoint = keystone_client.endpoint_cache.get_endpoint('sysinv') - sysinv_client = SysinvClient(subcloud_name, + sysinv_client = SysinvClient(subcloud_region, keystone_client.session, endpoint=endpoint) system_health = sysinv_client.get_system_health() @@ -1083,19 +1143,19 @@ def decode_and_normalize_passwd(input_passwd): return passwd -def get_failure_msg(subcloud_name): +def get_failure_msg(subcloud_region): try: - os_client = OpenStackDriver(region_name=subcloud_name, + os_client = OpenStackDriver(region_name=subcloud_region, region_clients=None) keystone_client = os_client.keystone_client endpoint = keystone_client.endpoint_cache.get_endpoint('sysinv') - sysinv_client = SysinvClient(subcloud_name, + sysinv_client = SysinvClient(subcloud_region, keystone_client.session, endpoint=endpoint) msg = sysinv_client.get_error_msg() return msg except Exception as e: - LOG.exception("{}: {}".format(subcloud_name, e)) + LOG.exception("{}: {}".format(subcloud_region, e)) return consts.ERROR_DESC_FAILED @@ -1181,3 +1241,19 @@ def get_current_supported_upgrade_versions(): supported_versions.append(version.strip()) return supported_versions + + +# Feature: Subcloud Name Reconfiguration +# This method is useful to determine the origin of the request +# towards the api. The goal was to avoid any code changes in +# the cert-monitor module, since it only needs the region reference. +# When this method is called, the condition is applied to replace the +# value of the "name" field with the value of the "region_name" field +# in the response. In this way, the cert-monitor does not lose the +# region reference in subcloud rename operation. +def is_req_from_cert_mon_agent(request): + ua = request.headers.get("User-Agent") + if ua == consts.CERT_MON_HTTP_AGENT: + return True + else: + return False diff --git a/distributedcloud/dcmanager/db/api.py b/distributedcloud/dcmanager/db/api.py index dfc1049d1..5cf18b4cc 100644 --- a/distributedcloud/dcmanager/db/api.py +++ b/distributedcloud/dcmanager/db/api.py @@ -112,6 +112,7 @@ def subcloud_db_model_to_dict(subcloud): "backup-status": subcloud.backup_status, "backup-datetime": subcloud.backup_datetime, "error-description": subcloud.error_description, + 'region-name': subcloud.region_name, "management-subnet": subcloud.management_subnet, "management-start-ip": subcloud.management_start_ip, "management-end-ip": subcloud.management_end_ip, @@ -132,14 +133,14 @@ def subcloud_create(context, name, description, location, software_version, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, systemcontroller_gateway_ip, deploy_status, error_description, - openstack_installed, group_id, data_install=None): + region_name, openstack_installed, group_id, data_install=None): """Create a subcloud.""" return IMPL.subcloud_create(context, name, description, location, software_version, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, systemcontroller_gateway_ip, deploy_status, - error_description, openstack_installed, group_id, + error_description, region_name, openstack_installed, group_id, data_install) @@ -158,6 +159,16 @@ def subcloud_get_by_name(context, name) -> models.Subcloud: return IMPL.subcloud_get_by_name(context, name) +def subcloud_get_by_region_name(context, region_name): + """Retrieve a subcloud by region name or raise if it does not exist.""" + return IMPL.subcloud_get_by_region_name(context, region_name) + + +def subcloud_get_by_name_or_region_name(context, name): + """Retrieve a subcloud by name or region name or raise if it does not exist.""" + return IMPL.subcloud_get_by_name_or_region_name(context, name) + + def subcloud_get_all(context): """Retrieve all subclouds.""" return IMPL.subcloud_get_all(context) @@ -174,7 +185,7 @@ def subcloud_get_all_with_status(context): def subcloud_update(context, subcloud_id, management_state=None, - availability_status=None, software_version=None, + availability_status=None, software_version=None, name=None, description=None, management_subnet=None, management_gateway_ip=None, management_start_ip=None, management_end_ip=None, location=None, audit_fail_count=None, @@ -187,7 +198,7 @@ def subcloud_update(context, subcloud_id, management_state=None, rehome_data=None): """Update a subcloud or raise if it does not exist.""" return IMPL.subcloud_update(context, subcloud_id, management_state, - availability_status, software_version, + availability_status, software_version, name, description, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, location, audit_fail_count, deploy_status, backup_status, @@ -677,3 +688,7 @@ def subcloud_alarms_update(context, name, values): def subcloud_alarms_delete(context, name): return IMPL.subcloud_alarms_delete(context, name) + + +def subcloud_rename_alarms(context, subcloud_name, new_name): + return IMPL.subcloud_rename_alarms(context, subcloud_name, new_name) diff --git a/distributedcloud/dcmanager/db/sqlalchemy/api.py b/distributedcloud/dcmanager/db/sqlalchemy/api.py index f7d910447..f57505f34 100644 --- a/distributedcloud/dcmanager/db/sqlalchemy/api.py +++ b/distributedcloud/dcmanager/db/sqlalchemy/api.py @@ -32,6 +32,7 @@ from oslo_utils import strutils from oslo_utils import uuidutils from sqlalchemy import desc +from sqlalchemy import or_ from sqlalchemy.orm.exc import MultipleResultsFound from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm import joinedload_all @@ -317,6 +318,32 @@ def subcloud_get_by_name(context, name): return result +@require_context +def subcloud_get_by_region_name(context, region_name): + result = model_query(context, models.Subcloud). \ + filter_by(deleted=0). \ + filter_by(region_name=region_name). \ + first() + + if not result: + raise exception.SubcloudRegionNameNotFound(region_name=region_name) + + return result + + +@require_context +def subcloud_get_by_name_or_region_name(context, name): + result = model_query(context, models.Subcloud). \ + filter_by(deleted=0). \ + filter(or_(models.Subcloud.name == name, models.Subcloud.region_name == name)). \ + first() + + if not result: + raise exception.SubcloudNameOrRegionNameNotFound(name=name) + + return result + + @require_context def subcloud_get_all(context): return model_query(context, models.Subcloud). \ @@ -349,7 +376,7 @@ def subcloud_create(context, name, description, location, software_version, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, systemcontroller_gateway_ip, deploy_status, error_description, - openstack_installed, group_id, + region_name, openstack_installed, group_id, data_install=None): with write_session() as session: subcloud_ref = models.Subcloud() @@ -366,6 +393,7 @@ def subcloud_create(context, name, description, location, software_version, subcloud_ref.systemcontroller_gateway_ip = systemcontroller_gateway_ip subcloud_ref.deploy_status = deploy_status subcloud_ref.error_description = error_description + subcloud_ref.region_name = region_name subcloud_ref.audit_fail_count = 0 subcloud_ref.openstack_installed = openstack_installed subcloud_ref.group_id = group_id @@ -381,7 +409,7 @@ def subcloud_create(context, name, description, location, software_version, @require_admin_context def subcloud_update(context, subcloud_id, management_state=None, availability_status=None, software_version=None, - description=None, management_subnet=None, + name=None, description=None, management_subnet=None, management_gateway_ip=None, management_start_ip=None, management_end_ip=None, location=None, audit_fail_count=None, deploy_status=None, backup_status=None, @@ -401,6 +429,8 @@ def subcloud_update(context, subcloud_id, management_state=None, subcloud_ref.availability_status = availability_status if software_version is not None: subcloud_ref.software_version = software_version + if name is not None: + subcloud_ref.name = name if description is not None: subcloud_ref.description = description if management_subnet is not None: @@ -1221,3 +1251,12 @@ def subcloud_alarms_delete(context, name): with write_session() as session: session.query(models.SubcloudAlarmSummary).\ filter_by(name=name).delete() + + +@require_admin_context +def subcloud_rename_alarms(context, subcloud_name, new_name): + with write_session() as session: + result = _subcloud_alarms_get(context, subcloud_name) + result.name = new_name + result.save(session) + return result diff --git a/distributedcloud/dcmanager/db/sqlalchemy/migrate_repo/versions/015_add_subcloud_region_name_column.py b/distributedcloud/dcmanager/db/sqlalchemy/migrate_repo/versions/015_add_subcloud_region_name_column.py new file mode 100644 index 000000000..1e7ee2972 --- /dev/null +++ b/distributedcloud/dcmanager/db/sqlalchemy/migrate_repo/versions/015_add_subcloud_region_name_column.py @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Wind River Systems, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +from sqlalchemy import Column, MetaData, String, Table + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + subclouds = Table('subclouds', meta, autoload=True) + + # Add the 'region_name' column to the subclouds table. + subclouds.create_column(Column('region_name', + String(255))) + + # populates region_name with name field value for existing subclouds + if migrate_engine.name == 'postgresql': + with migrate_engine.begin() as conn: + conn.execute("UPDATE subclouds SET region_name = name") + + return True + + +def downgrade(migrate_engine): + raise NotImplementedError('Database downgrade is unsupported.') diff --git a/distributedcloud/dcmanager/db/sqlalchemy/models.py b/distributedcloud/dcmanager/db/sqlalchemy/models.py index 3c13a93e4..e7a12c45a 100644 --- a/distributedcloud/dcmanager/db/sqlalchemy/models.py +++ b/distributedcloud/dcmanager/db/sqlalchemy/models.py @@ -148,6 +148,7 @@ class Subcloud(BASE, DCManagerBase): backup_status = Column(String(255)) backup_datetime = Column(DateTime(timezone=False)) error_description = Column(String(2048)) + region_name = Column(String(255), unique=True) data_upgrade = Column(String()) management_subnet = Column(String(255)) management_gateway_ip = Column(String(255)) diff --git a/distributedcloud/dcmanager/manager/service.py b/distributedcloud/dcmanager/manager/service.py index 45b13da54..e85caeffe 100644 --- a/distributedcloud/dcmanager/manager/service.py +++ b/distributedcloud/dcmanager/manager/service.py @@ -110,6 +110,27 @@ class DCManagerService(service.Service): LOG.info("Handling delete_subcloud request for: %s" % subcloud_id) return self.subcloud_manager.delete_subcloud(context, subcloud_id) + @request_context + def rename_subcloud(self, context, subcloud_id, curr_subcloud_name, + new_subcloud_name=None): + # Rename a subcloud + LOG.info("Handling rename_subcloud request for: %s" % + curr_subcloud_name) + subcloud = self.subcloud_manager.rename_subcloud(context, + subcloud_id, + curr_subcloud_name, + new_subcloud_name) + return subcloud + + @request_context + def get_subcloud_name_by_region_name(self, context, subcloud_region): + # get subcloud by region name + LOG.debug("Handling get_subcloud_name_by_region_name request for " + "region: %s" % subcloud_region) + subcloud = self.subcloud_manager.get_subcloud_name_by_region_name(context, + subcloud_region) + return subcloud + @request_context def update_subcloud(self, context, subcloud_id, management_state=None, description=None, location=None, diff --git a/distributedcloud/dcmanager/manager/subcloud_manager.py b/distributedcloud/dcmanager/manager/subcloud_manager.py index c01a028bf..2a1a982c7 100644 --- a/distributedcloud/dcmanager/manager/subcloud_manager.py +++ b/distributedcloud/dcmanager/manager/subcloud_manager.py @@ -179,10 +179,10 @@ class SubcloudManager(manager.Manager): @staticmethod def _create_intermediate_ca_cert(payload): - subcloud_name = payload["name"] - cert_name = SubcloudManager._get_subcloud_cert_name(subcloud_name) + subcloud_region = payload["region_name"] + cert_name = SubcloudManager._get_subcloud_cert_name(subcloud_region) secret_name = SubcloudManager._get_subcloud_cert_secret_name( - subcloud_name) + subcloud_region) cert = { "apiVersion": "%s/%s" % (kubeoperator.CERT_MANAGER_GROUP, @@ -255,6 +255,7 @@ class SubcloudManager(manager.Manager): return install_command def compose_bootstrap_command(self, subcloud_name, + subcloud_region, ansible_subcloud_inventory_file, software_version=None): bootstrap_command = [ @@ -268,7 +269,7 @@ class SubcloudManager(manager.Manager): # which overrides to load bootstrap_command += [ "-e", str("override_files_dir='%s' region_name=%s") % ( - dccommon_consts.ANSIBLE_OVERRIDES_PATH, subcloud_name), + dccommon_consts.ANSIBLE_OVERRIDES_PATH, subcloud_region), "-e", "install_release_version=%s" % software_version if software_version else SW_VERSION] return bootstrap_command @@ -324,7 +325,7 @@ class SubcloudManager(manager.Manager): subcloud_name + "_update_values.yml"] return subcloud_update_command - def compose_rehome_command(self, subcloud_name, + def compose_rehome_command(self, subcloud_name, subcloud_region, ansible_subcloud_inventory_file, software_version): rehome_command = [ @@ -335,7 +336,7 @@ class SubcloudManager(manager.Manager): "--limit", subcloud_name, "--timeout", REHOME_PLAYBOOK_TIMEOUT, "-e", str("override_files_dir='%s' region_name=%s") % ( - dccommon_consts.ANSIBLE_OVERRIDES_PATH, subcloud_name)] + dccommon_consts.ANSIBLE_OVERRIDES_PATH, subcloud_region)] return rehome_command def migrate_subcloud(self, context, subcloud_ref, payload): @@ -394,6 +395,7 @@ class SubcloudManager(manager.Manager): rehome_command = self.compose_rehome_command( subcloud.name, + subcloud.region_name, ansible_subcloud_inventory_file, subcloud.software_version) @@ -407,7 +409,7 @@ class SubcloudManager(manager.Manager): :param subcloud_id: id of the subcloud :param payload: subcloud configuration """ - LOG.info(f"Adding subcloud {payload['name']}.") + LOG.info(f"Adding subcloud {payload['name']} with region {payload['region_name']}.") rehoming = payload.get('migrate', '').lower() == "true" secondary = (payload.get('secondary', '').lower() == "true") @@ -653,6 +655,7 @@ class SubcloudManager(manager.Manager): bootstrap_command = self.compose_bootstrap_command( subcloud.name, + subcloud.region_name, ansible_subcloud_inventory_file, subcloud.software_version) return bootstrap_command @@ -923,7 +926,7 @@ class SubcloudManager(manager.Manager): endpoint["id"], endpoint['admin_endpoint_url'], interface=dccommon_consts.KS_ENDPOINT_ADMIN, - region=subcloud.name) + region=subcloud.region_name) except Exception as e: # Keystone service must be temporarily busy, retry LOG.error(str(e)) @@ -931,11 +934,11 @@ class SubcloudManager(manager.Manager): endpoint["id"], endpoint['admin_endpoint_url'], interface=dccommon_consts.KS_ENDPOINT_ADMIN, - region=subcloud.name) + region=subcloud.region_name) # Inform orchestrator that subcloud has been added self.dcorch_rpc_client.add_subcloud( - context, subcloud.name, subcloud.software_version) + context, subcloud.region_name, subcloud.software_version) # create entry into alarm summary table, will get real values later alarm_updates = {'critical_alarms': -1, @@ -1282,7 +1285,7 @@ class SubcloudManager(manager.Manager): def _backup_subcloud(self, context, payload, subcloud): try: # Health check validation - if not utils.is_subcloud_healthy(subcloud.name): + if not utils.is_subcloud_healthy(subcloud.region_name): db_api.subcloud_update( context, subcloud.id, @@ -1442,9 +1445,9 @@ class SubcloudManager(manager.Manager): else: # Use subcloud floating IP for host reachability keystone_client = OpenStackDriver( - region_name=subcloud.name, + region_name=subcloud.region_name, region_clients=None).keystone_client - oam_fip = utils.get_oam_addresses(subcloud.name, keystone_client)\ + oam_fip = utils.get_oam_addresses(subcloud, keystone_client)\ .oam_floating_ip # Add parameters used to generate inventory @@ -2042,10 +2045,10 @@ class SubcloudManager(manager.Manager): 1) @staticmethod - def _delete_subcloud_cert(subcloud_name): - cert_name = SubcloudManager._get_subcloud_cert_name(subcloud_name) + def _delete_subcloud_cert(subcloud_region): + cert_name = SubcloudManager._get_subcloud_cert_name(subcloud_region) secret_name = SubcloudManager._get_subcloud_cert_secret_name( - subcloud_name) + subcloud_region) kube = kubeoperator.KubeOperator() kube.delete_cert_manager_certificate(CERT_NAMESPACE, cert_name) @@ -2059,7 +2062,7 @@ class SubcloudManager(manager.Manager): """Remove subcloud details from database and inform orchestrators""" # Inform orchestrators that subcloud has been deleted try: - self.dcorch_rpc_client.del_subcloud(context, subcloud.name) + self.dcorch_rpc_client.del_subcloud(context, subcloud.region_name) except RemoteError as e: # TODO(kmacleod): this should be caught as explicit remote exception # Fix when centos/python2 is no longer supported @@ -2083,8 +2086,8 @@ class SubcloudManager(manager.Manager): region_clients=None).keystone_client # Delete keystone endpoints for subcloud - keystone_client.delete_endpoints(subcloud.name) - keystone_client.delete_region(subcloud.name) + keystone_client.delete_endpoints(subcloud.region_name) + keystone_client.delete_region(subcloud.region_name) # Delete the routes to this subcloud self._delete_subcloud_routes(keystone_client, subcloud) @@ -2100,7 +2103,7 @@ class SubcloudManager(manager.Manager): utils.delete_subcloud_inventory(ansible_subcloud_inventory_file) # Delete the subcloud intermediate certificate - SubcloudManager._delete_subcloud_cert(subcloud.name) + SubcloudManager._delete_subcloud_cert(subcloud.region_name) # Delete the subcloud backup path self._delete_subcloud_backup_data(subcloud.name) @@ -2142,6 +2145,42 @@ class SubcloudManager(manager.Manager): if os.path.exists(install_path): shutil.rmtree(install_path) + def _rename_subcloud_ansible_files(self, cur_sc_name, new_sc_name): + """Renames the ansible and logs files from the given subcloud""" + + ansible_path = dccommon_consts.ANSIBLE_OVERRIDES_PATH + log_path = consts.DC_ANSIBLE_LOG_DIR + + ansible_file_list = os.listdir(ansible_path) + log_file_list = os.listdir(log_path) + + ansible_file_list = [ansible_path + '/' + x for x in ansible_file_list] + log_file_list = [log_path + '/' + x for x in log_file_list] + + for cur_file in ansible_file_list + log_file_list: + new_file = cur_file.replace(cur_sc_name, new_sc_name) + if os.path.exists(cur_file) and new_sc_name in new_file: + os.rename(cur_file, new_file) + + # Gets new ansible inventory file + ansible_inv_file = self._get_ansible_filename(new_sc_name, + INVENTORY_FILE_POSTFIX) + + # Updates inventory host param with the new subcloud name + with open(ansible_inv_file, 'r') as f: + data = yaml.safe_load(f) + + mkey = list(data.keys())[0] + + if mkey in data and 'hosts' in data[mkey] and \ + cur_sc_name in data[mkey]['hosts']: + + data[mkey]['hosts'][new_sc_name] = \ + data[mkey]['hosts'].pop(cur_sc_name) + + with open(ansible_inv_file, 'w') as f: + yaml.dump(data, f, sort_keys=False) + @staticmethod def _delete_subcloud_backup_data(subcloud_name): try: @@ -2208,6 +2247,62 @@ class SubcloudManager(manager.Manager): (subcloud.name, alarm_id)) LOG.exception(e) + def rename_subcloud(self, + context, + subcloud_id, + curr_subcloud_name, + new_subcloud_name=None): + """Rename subcloud. + + :param context: request context object. + :param subcloud_id: id of subcloud to rename + :param curr_subcloud_name: current subcloud name + :param new_subcloud_name: new subcloud name + """ + try: + subcloud = db_api.\ + subcloud_get_by_name_or_region_name(context, + new_subcloud_name) + except exceptions.SubcloudNameOrRegionNameNotFound: + pass + else: + # If the found subcloud id is not the same as the received + # subcloud id, it indicates that the name change does not + # correspond to the current subcloud. + # Therefore it is not allowed to change the name. + if subcloud_id != subcloud.id: + raise exceptions.SubcloudOrRegionNameAlreadyExists( + name=new_subcloud_name) + + # updates subcloud name + subcloud = db_api.subcloud_update(context, subcloud_id, + name=new_subcloud_name) + # updates subcloud names on alarms + db_api.subcloud_rename_alarms(context, curr_subcloud_name, + new_subcloud_name) + # Deletes subcloud alarms + entity_instance_id = "subcloud=%s" % curr_subcloud_name + self.fm_api.clear_all(entity_instance_id) + + # Regenerate the dnsmasq host entry + self._create_addn_hosts_dc(context) + + # Rename related subcloud files + self._rename_subcloud_ansible_files(curr_subcloud_name, + new_subcloud_name) + + return subcloud + + def get_subcloud_name_by_region_name(self, + context, + subcloud_region): + subcloud_name = None + if subcloud_region is not None: + sc = db_api.subcloud_get_by_region_name(context, subcloud_region) + subcloud_name = sc.get("name") + + return subcloud_name + def update_subcloud(self, context, subcloud_id, @@ -2363,7 +2458,7 @@ class SubcloudManager(manager.Manager): # Inform orchestrator of state change self.dcorch_rpc_client.update_subcloud_states( context, - subcloud.name, + subcloud.region_name, management_state, subcloud.availability_status) @@ -2391,6 +2486,7 @@ class SubcloudManager(manager.Manager): self.state_rpc_client.update_subcloud_endpoint_status_sync( context, subcloud_name=subcloud.name, + subcloud_region=subcloud.region_name, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_UNKNOWN, ignore_endpoints=[dccommon_consts.ENDPOINT_TYPE_DC_CERT]) @@ -2399,7 +2495,7 @@ class SubcloudManager(manager.Manager): # Tell cert-mon to audit endpoint certificate LOG.info('Request certmon audit for %s' % subcloud.name) dc_notification = dcmanager_rpc_client.DCManagerNotifications() - dc_notification.subcloud_managed(context, subcloud.name) + dc_notification.subcloud_managed(context, subcloud.region_name) return db_api.subcloud_db_model_to_dict(subcloud) @@ -2487,6 +2583,7 @@ class SubcloudManager(manager.Manager): :param update_db: whether it should update the db on success/failure """ subcloud_name = subcloud.name + subcloud_region = subcloud.region_name subcloud_id = subcloud.id sys_controller_gw_ip = payload.get("systemcontroller_gateway_address", subcloud.systemcontroller_gateway_ip) @@ -2509,7 +2606,7 @@ class SubcloudManager(manager.Manager): return try: self._update_services_endpoint( - context, payload, subcloud_name, m_ks_client) + context, payload, subcloud_region, m_ks_client) except Exception: LOG.exception("Failed to update subcloud %s endpoints" % subcloud_name) if update_db: @@ -2541,7 +2638,7 @@ class SubcloudManager(manager.Manager): 1) def _update_services_endpoint( - self, context, payload, subcloud_name, m_ks_client): + self, context, payload, subcloud_region, m_ks_client): endpoint_ip = utils.get_management_start_address(payload) if netaddr.IPAddress(endpoint_ip).version == 6: endpoint_ip = f"[{endpoint_ip}]" @@ -2556,7 +2653,7 @@ class SubcloudManager(manager.Manager): } for endpoint in m_ks_client.keystone_client.endpoints.list( - region=subcloud_name): + region=subcloud_region): service_type = m_ks_client.keystone_client.services.get( endpoint.service_id).type if service_type == dccommon_consts.ENDPOINT_TYPE_PLATFORM: @@ -2576,17 +2673,17 @@ class SubcloudManager(manager.Manager): m_ks_client.keystone_client.endpoints.update( endpoint, url=admin_endpoint_url) - LOG.info("Update services endpoint to %s in subcloud %s" % ( - endpoint_ip, subcloud_name)) + LOG.info("Update services endpoint to %s in subcloud region %s" % ( + endpoint_ip, subcloud_region)) # Update service URLs in subcloud endpoint cache self.audit_rpc_client.trigger_subcloud_endpoints_update( - context, subcloud_name, services_endpoints) + context, subcloud_region, services_endpoints) self.dcorch_rpc_client.update_subcloud_endpoints( - context, subcloud_name, services_endpoints) + context, subcloud_region, services_endpoints) # Update sysinv URL in cert-mon cache dc_notification = dcmanager_rpc_client.DCManagerNotifications() dc_notification.subcloud_sysinv_endpoint_update( - context, subcloud_name, services_endpoints.get("sysinv")) + context, subcloud_region, services_endpoints.get("sysinv")) def _create_subcloud_update_overrides_file( self, payload, subcloud_name, filename_suffix): @@ -2630,7 +2727,7 @@ class SubcloudManager(manager.Manager): payload['override_values']['sc_ca_key'] = payload['sc_ca_key'] def update_subcloud_sync_endpoint_type(self, context, - subcloud_name, + subcloud_region, endpoint_type_list, openstack_installed): operation = 'add' if openstack_installed else 'remove' @@ -2646,17 +2743,17 @@ class SubcloudManager(manager.Manager): } try: - subcloud = db_api.subcloud_get_by_name(context, subcloud_name) + subcloud = db_api.subcloud_get_by_region_name(context, subcloud_region) except Exception: - LOG.exception("Failed to get subcloud by name: %s" % subcloud_name) + LOG.exception("Failed to get subcloud by region name: %s" % subcloud_region) raise try: # Notify dcorch to add/remove sync endpoint type list - func_switcher[operation][0](self.context, subcloud_name, + func_switcher[operation][0](self.context, subcloud_region, endpoint_type_list) LOG.info('Notifying dcorch, subcloud: %s new sync endpoint: %s' % - (subcloud_name, endpoint_type_list)) + (subcloud.name, endpoint_type_list)) # Update subcloud status table by adding/removing openstack sync # endpoint types @@ -2668,7 +2765,7 @@ class SubcloudManager(manager.Manager): openstack_installed=openstack_installed) except Exception: LOG.exception('Problem informing dcorch of subcloud sync endpoint' - ' type change, subcloud: %s' % subcloud_name) + ' type change, subcloud region: %s' % subcloud_region) def handle_subcloud_operations_in_progress(self): """Identify subclouds in transitory stages and update subcloud diff --git a/distributedcloud/dcmanager/orchestrator/orch_thread.py b/distributedcloud/dcmanager/orchestrator/orch_thread.py index 45b626a20..b38164e83 100644 --- a/distributedcloud/dcmanager/orchestrator/orch_thread.py +++ b/distributedcloud/dcmanager/orchestrator/orch_thread.py @@ -156,6 +156,14 @@ class OrchThread(threading.Thread): @staticmethod def get_region_name(strategy_step): """Get the region name for a strategy step""" + if strategy_step.subcloud_id is None: + # This is the SystemController. + return dccommon_consts.DEFAULT_REGION_NAME + return strategy_step.subcloud.region_name + + @staticmethod + def get_subcloud_name(strategy_step): + """Get the subcloud name for a strategy step""" if strategy_step.subcloud_id is None: # This is the SystemController. return dccommon_consts.DEFAULT_REGION_NAME @@ -263,18 +271,18 @@ class OrchThread(threading.Thread): for strategy_step in strategy_steps: if strategy_step.state == consts.STRATEGY_STATE_COMPLETE: # This step is complete - self._delete_subcloud_worker(strategy_step.subcloud.name, + self._delete_subcloud_worker(strategy_step.subcloud.region_name, strategy_step.subcloud_id) continue elif strategy_step.state == consts.STRATEGY_STATE_ABORTED: # This step was aborted - self._delete_subcloud_worker(strategy_step.subcloud.name, + self._delete_subcloud_worker(strategy_step.subcloud.region_name, strategy_step.subcloud_id) abort_detected = True continue elif strategy_step.state == consts.STRATEGY_STATE_FAILED: failure_detected = True - self._delete_subcloud_worker(strategy_step.subcloud.name, + self._delete_subcloud_worker(strategy_step.subcloud.region_name, strategy_step.subcloud_id) # This step has failed and needs no further action if strategy_step.subcloud_id is None: @@ -572,7 +580,7 @@ class OrchThread(threading.Thread): % (self.update_type, strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step))) + self.get_subcloud_name(strategy_step))) # Instantiate the state operator and perform the state actions state_operator = self.determine_state_operator(strategy_step) state_operator.registerStopEvent(self._stop) @@ -585,7 +593,7 @@ class OrchThread(threading.Thread): % (self.update_type, strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step))) + strategy_step.subcloud.name)) # Transition immediately to complete. Update the details to show # that this subcloud has been skipped details = self.format_update_details(None, str(ex)) @@ -598,7 +606,7 @@ class OrchThread(threading.Thread): % (self.update_type, strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step))) + strategy_step.subcloud.name)) details = self.format_update_details(strategy_step.state, str(ex)) self.strategy_step_update(strategy_step.subcloud_id, state=consts.STRATEGY_STATE_FAILED, diff --git a/distributedcloud/dcmanager/orchestrator/states/base.py b/distributedcloud/dcmanager/orchestrator/states/base.py index 3786e80b7..fb550a7f6 100644 --- a/distributedcloud/dcmanager/orchestrator/states/base.py +++ b/distributedcloud/dcmanager/orchestrator/states/base.py @@ -55,39 +55,47 @@ class BaseState(object): LOG.debug("Stage: %s, State: %s, Subcloud: %s, Details: %s" % (strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step), + self.get_subcloud_name(strategy_step), details)) def info_log(self, strategy_step, details): LOG.info("Stage: %s, State: %s, Subcloud: %s, Details: %s" % (strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step), + self.get_subcloud_name(strategy_step), details)) def warn_log(self, strategy_step, details): LOG.warn("Stage: %s, State: %s, Subcloud: %s, Details: %s" % (strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step), + self.get_subcloud_name(strategy_step), details)) def error_log(self, strategy_step, details): LOG.error("Stage: %s, State: %s, Subcloud: %s, Details: %s" % (strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step), + self.get_subcloud_name(strategy_step), details)) def exception_log(self, strategy_step, details): LOG.exception("Stage: %s, State: %s, Subcloud: %s, Details: %s" % (strategy_step.stage, strategy_step.state, - self.get_region_name(strategy_step), + self.get_subcloud_name(strategy_step), details)) @staticmethod def get_region_name(strategy_step): + """Get the region name for a strategy step""" + if strategy_step.subcloud_id is None: + # This is the SystemController. + return dccommon_consts.DEFAULT_REGION_NAME + return strategy_step.subcloud.region_name + + @staticmethod + def get_subcloud_name(strategy_step): """Get the region name for a strategy step""" if strategy_step.subcloud_id is None: # This is the SystemController. diff --git a/distributedcloud/dcmanager/orchestrator/states/firmware/finishing_fw_update.py b/distributedcloud/dcmanager/orchestrator/states/firmware/finishing_fw_update.py index 53fcc7dfd..ff3f7cebb 100644 --- a/distributedcloud/dcmanager/orchestrator/states/firmware/finishing_fw_update.py +++ b/distributedcloud/dcmanager/orchestrator/states/firmware/finishing_fw_update.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2022 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -33,10 +33,11 @@ class FinishingFwUpdateState(BaseState): % (dccommon_consts.ENDPOINT_TYPE_FIRMWARE, dccommon_consts.SYNC_STATUS_IN_SYNC)) dcmanager_state_rpc_client = dcmanager_rpc_client.SubcloudStateClient() - # The subcloud name is the same as the region in the strategy_step + # The subcloud name may differ from the region name in the strategy_step dcmanager_state_rpc_client.update_subcloud_endpoint_status( self.context, - subcloud_name=self.get_region_name(strategy_step), + subcloud_name=self.get_subcloud_name(strategy_step), + subcloud_region=self.get_region_name(strategy_step), endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC) diff --git a/distributedcloud/dcmanager/orchestrator/states/lock_host.py b/distributedcloud/dcmanager/orchestrator/states/lock_host.py index e14e26b9c..1a03cc46b 100644 --- a/distributedcloud/dcmanager/orchestrator/states/lock_host.py +++ b/distributedcloud/dcmanager/orchestrator/states/lock_host.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2021 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -33,7 +33,7 @@ class LockHostState(BaseState): """ # Create a sysinv client on the subcloud - sysinv_client = self.get_sysinv_client(strategy_step.subcloud.name) + sysinv_client = self.get_sysinv_client(strategy_step.subcloud.region_name) host = sysinv_client.get_host(self.target_hostname) @@ -58,7 +58,7 @@ class LockHostState(BaseState): raise StrategyStoppedException() # query the administrative state to see if it is the new state. host = self.get_sysinv_client( - strategy_step.subcloud.name).get_host(self.target_hostname) + strategy_step.subcloud.region_name).get_host(self.target_hostname) if host.administrative == consts.ADMIN_LOCKED: msg = "Host: %s is now: %s" % (self.target_hostname, host.administrative) diff --git a/distributedcloud/dcmanager/orchestrator/states/unlock_host.py b/distributedcloud/dcmanager/orchestrator/states/unlock_host.py index 82258c75c..17da5e234 100644 --- a/distributedcloud/dcmanager/orchestrator/states/unlock_host.py +++ b/distributedcloud/dcmanager/orchestrator/states/unlock_host.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2021 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -61,7 +61,7 @@ class UnlockHostState(BaseState): """ # Retrieve host from sysinv client on the subcloud - host = self._get_host_with_retry(strategy_step.subcloud.name) + host = self._get_host_with_retry(strategy_step.subcloud.region_name) # if the host is already in the desired state, no need for action if self.check_host_ready(host): @@ -85,7 +85,7 @@ class UnlockHostState(BaseState): while True: try: response = self.get_sysinv_client( - strategy_step.subcloud.name).unlock_host(host.id) + strategy_step.subcloud.region_name).unlock_host(host.id) if (response.ihost_action != 'unlock' or response.task != 'Unlocking'): raise Exception("Unable to unlock host %s" @@ -113,7 +113,7 @@ class UnlockHostState(BaseState): try: # query the administrative state to see if it is the new state. host = self.get_sysinv_client( - strategy_step.subcloud.name).get_host(self.target_hostname) + strategy_step.subcloud.region_name).get_host(self.target_hostname) if self.check_host_ready(host): # Success. Break out of the loop. msg = "Host: %s is now: %s %s %s" % (self.target_hostname, diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/activating.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/activating.py index a097478d4..3ccba2b5c 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/activating.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/activating.py @@ -38,7 +38,7 @@ class ActivatingUpgradeState(BaseState): def get_upgrade_state(self, strategy_step): try: upgrades = self.get_sysinv_client( - strategy_step.subcloud.name).get_upgrades() + strategy_step.subcloud.region_name).get_upgrades() except Exception as exception: self.warn_log(strategy_step, @@ -86,7 +86,7 @@ class ActivatingUpgradeState(BaseState): # if max retries have occurred, fail the state if activate_retry_counter >= self.max_failed_retries: - error_msg = utils.get_failure_msg(strategy_step.subcloud.name) + error_msg = utils.get_failure_msg(strategy_step.subcloud.region_name) db_api.subcloud_update( self.context, strategy_step.subcloud_id, error_description=error_msg[0:consts.ERROR_DESCRIPTION_LENGTH]) @@ -104,7 +104,7 @@ class ActivatingUpgradeState(BaseState): # (no upgrade found, bad host state, auth) try: self.get_sysinv_client( - strategy_step.subcloud.name).upgrade_activate() + strategy_step.subcloud.region_name).upgrade_activate() first_activate = False # clear first activation flag activate_retry_counter = 0 # reset activation retries except Exception as exception: @@ -128,7 +128,7 @@ class ActivatingUpgradeState(BaseState): % upgrade_state) try: self.get_sysinv_client( - strategy_step.subcloud.name).upgrade_activate() + strategy_step.subcloud.region_name).upgrade_activate() except Exception as exception: self.warn_log(strategy_step, "Encountered exception: %s, " @@ -146,7 +146,7 @@ class ActivatingUpgradeState(BaseState): break audit_counter += 1 if audit_counter >= self.max_queries: - error_msg = utils.get_failure_msg(strategy_step.subcloud.name) + error_msg = utils.get_failure_msg(strategy_step.subcloud.region_name) db_api.subcloud_update( self.context, strategy_step.subcloud_id, error_description=error_msg[0:consts.ERROR_DESCRIPTION_LENGTH]) diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/deleting_load.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/deleting_load.py index 9abf3bae7..aa33f644a 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/deleting_load.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/deleting_load.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -32,7 +32,7 @@ class DeletingLoadState(BaseState): Any exceptions raised by this method set the strategy to FAILED. """ # get the sysinv client for the subcloud - sysinv_client = self.get_sysinv_client(strategy_step.subcloud.name) + sysinv_client = self.get_sysinv_client(strategy_step.subcloud.region_name) current_loads = sysinv_client.get_loads() load_id = None diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/finishing_patch_strategy.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/finishing_patch_strategy.py index 76e318a69..ad2be2bb7 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/finishing_patch_strategy.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/finishing_patch_strategy.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2022 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -56,7 +56,7 @@ class FinishingPatchStrategyState(BaseState): "RegionOne committed_patch_ids: %s" % committed_patch_ids) subcloud_patches = self.get_patching_client( - strategy_step.subcloud.name).query() + strategy_step.subcloud.region_name).query() self.debug_log(strategy_step, "Patches for subcloud: %s" % subcloud_patches) @@ -93,6 +93,6 @@ class FinishingPatchStrategyState(BaseState): self.info_log(strategy_step, "Committing patches %s in subcloud" % patches_to_commit) self.get_patching_client( - strategy_step.subcloud.name).commit(patches_to_commit) + strategy_step.subcloud.region_name).commit(patches_to_commit) return self.next_state diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/importing_load.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/importing_load.py index 95132f940..991a924f9 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/importing_load.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/importing_load.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2022 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -49,13 +49,13 @@ class ImportingLoadState(BaseState): self.info_log(strategy_step, "Retrieving load list from subcloud...") # success when only one load, the active load, remains if len(self.get_sysinv_client( - strategy_step.subcloud.name).get_loads()) == 1: + strategy_step.subcloud.region_name).get_loads()) == 1: msg = "Load: %s has been removed." % load_version self.info_log(strategy_step, msg) return True else: load = self.get_sysinv_client( - strategy_step.subcloud.name).get_load(load_id) + strategy_step.subcloud.region_name).get_load(load_id) if load.state == consts.IMPORTED_LOAD_STATE: # success when load is imported msg = "Load: %s is now: %s" % (load_version, @@ -102,7 +102,7 @@ class ImportingLoadState(BaseState): load_info = {} # Check if the load is already imported by checking the version current_loads = self.get_sysinv_client( - strategy_step.subcloud.name).get_loads() + strategy_step.subcloud.region_name).get_loads() for load in current_loads: if load.software_version == target_version: @@ -140,12 +140,12 @@ class ImportingLoadState(BaseState): self.info_log(strategy_step, "Deleting load %s..." % load_id_to_be_deleted) self.get_sysinv_client( - strategy_step.subcloud.name).delete_load(load_id_to_be_deleted) + strategy_step.subcloud.region_name).delete_load(load_id_to_be_deleted) req_info['type'] = LOAD_DELETE_REQUEST_TYPE self._wait_for_request_to_complete(strategy_step, req_info) subcloud_type = self.get_sysinv_client( - strategy_step.subcloud.name).get_system().system_mode + strategy_step.subcloud.region_name).get_system().system_mode load_import_retry_counter = 0 load = None if subcloud_type == consts.SYSTEM_MODE_SIMPLEX: @@ -158,7 +158,7 @@ class ImportingLoadState(BaseState): target_load = {key: target_load[key] for key in creation_keys} try: load = self.get_sysinv_client( - strategy_step.subcloud.name).import_load_metadata(target_load) + strategy_step.subcloud.region_name).import_load_metadata(target_load) self.info_log(strategy_step, "Load: %s is now: %s" % ( load.software_version, load.state)) @@ -190,7 +190,7 @@ class ImportingLoadState(BaseState): # Call the API. import_load blocks until the load state is 'importing' self.info_log(strategy_step, "Sending load import request...") load = self.get_sysinv_client( - strategy_step.subcloud.name).import_load(iso_path, sig_path) + strategy_step.subcloud.region_name).import_load(iso_path, sig_path) break except VaultLoadMissingError: diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/installing_license.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/installing_license.py index eb4b60bd0..6ca45c2da 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/installing_license.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/installing_license.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2022 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -64,7 +64,7 @@ class InstallingLicenseState(BaseState): # retrieve the keystone session for the subcloud and query its license subcloud_sysinv_client = \ - self.get_sysinv_client(strategy_step.subcloud.name) + self.get_sysinv_client(strategy_step.subcloud.region_name) subcloud_license_response = subcloud_sysinv_client.get_license() subcloud_license = subcloud_license_response.get('content') subcloud_error = subcloud_license_response.get('error') diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/migrating_data.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/migrating_data.py index 7494ac7ba..f429cb681 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/migrating_data.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/migrating_data.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2022 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -76,7 +76,7 @@ class MigratingDataState(BaseState): try: # query the administrative state to see if it is the new state. host = self.get_sysinv_client( - strategy_step.subcloud.name).get_host(target_hostname) + strategy_step.subcloud.region_name).get_host(target_hostname) if (host.administrative == consts.ADMIN_UNLOCKED and host.operational == consts.OPERATIONAL_ENABLED): # Success. Break out of the loop. @@ -160,7 +160,7 @@ class MigratingDataState(BaseState): msg_subcloud = utils.find_ansible_error_msg( strategy_step.subcloud.name, log_file, consts.DEPLOY_STATE_MIGRATING_DATA) # Get script output in case it is available - error_msg = utils.get_failure_msg(strategy_step.subcloud.name) + error_msg = utils.get_failure_msg(strategy_step.subcloud.region_name) failure = ('%s \n%s' % (error_msg, msg_subcloud)) db_api.subcloud_update( self.context, strategy_step.subcloud_id, diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/pre_check.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/pre_check.py index f8e2781c9..07e43d3cf 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/pre_check.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/pre_check.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020-2022 Wind River Systems, Inc. +# Copyright (c) 2020-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -204,8 +204,8 @@ class PreCheckState(BaseState): if subcloud.availability_status == dccommon_consts.AVAILABILITY_ONLINE: subcloud_sysinv_client = None try: - subcloud_sysinv_client = self.get_sysinv_client(strategy_step.subcloud.name) - subcloud_fm_client = self.get_fm_client(strategy_step.subcloud.name) + subcloud_sysinv_client = self.get_sysinv_client(strategy_step.subcloud.region_name) + subcloud_fm_client = self.get_fm_client(strategy_step.subcloud.region_name) except Exception: # if getting the token times out, the orchestrator may have # restarted and subcloud may be offline; so will attempt @@ -220,7 +220,7 @@ class PreCheckState(BaseState): host = subcloud_sysinv_client.get_host("controller-0") subcloud_type = self.get_sysinv_client( - strategy_step.subcloud.name).get_system().system_mode + strategy_step.subcloud.region_name).get_system().system_mode upgrades = subcloud_sysinv_client.get_upgrades() if subcloud_type == consts.SYSTEM_MODE_SIMPLEX: @@ -313,7 +313,7 @@ class PreCheckState(BaseState): all_hosts_upgraded = True subcloud_hosts = self.get_sysinv_client( - strategy_step.subcloud.name).get_hosts() + strategy_step.subcloud.region_name).get_hosts() for subcloud_host in subcloud_hosts: if(subcloud_host.software_load != target_version or subcloud_host.administrative == consts.ADMIN_LOCKED or diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/starting_upgrade.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/starting_upgrade.py index 51d41320f..93aa9c094 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/starting_upgrade.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/starting_upgrade.py @@ -36,7 +36,7 @@ class StartingUpgradeState(BaseState): def get_upgrade_state(self, strategy_step): try: upgrades = self.get_sysinv_client( - strategy_step.subcloud.name).get_upgrades() + strategy_step.subcloud.region_name).get_upgrades() except Exception as exception: self.warn_log(strategy_step, "Encountered exception: %s, " @@ -58,7 +58,7 @@ class StartingUpgradeState(BaseState): # Check if an existing upgrade is already in progress. # The list of upgrades will never contain more than one entry. upgrades = self.get_sysinv_client( - strategy_step.subcloud.name).get_upgrades() + strategy_step.subcloud.region_name).get_upgrades() if upgrades is not None and len(upgrades) > 0: for upgrade in upgrades: # If a previous upgrade exists (even one that failed) skip @@ -79,7 +79,7 @@ class StartingUpgradeState(BaseState): # This call is asynchronous and throws an exception on failure. self.get_sysinv_client( - strategy_step.subcloud.name).upgrade_start(force=force_flag) + strategy_step.subcloud.region_name).upgrade_start(force=force_flag) # Do not move to the next state until the upgrade state is correct counter = 0 @@ -96,7 +96,7 @@ class StartingUpgradeState(BaseState): if upgrade_state in UPGRADE_RETRY_STATES: retry_counter += 1 if retry_counter >= self.max_failed_retries: - error_msg = utils.get_failure_msg(strategy_step.subcloud.name) + error_msg = utils.get_failure_msg(strategy_step.subcloud.region_name) db_api.subcloud_update( self.context, strategy_step.subcloud_id, error_description=error_msg[0:consts.ERROR_DESCRIPTION_LENGTH]) @@ -110,7 +110,7 @@ class StartingUpgradeState(BaseState): % upgrade_state) try: self.get_sysinv_client( - strategy_step.subcloud.name).upgrade_start(force=force_flag) + strategy_step.subcloud.region_name).upgrade_start(force=force_flag) except Exception as exception: self.warn_log(strategy_step, "Encountered exception: %s, " diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/transfer_ca_certificate.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/transfer_ca_certificate.py index c018611c9..43fc6215c 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/transfer_ca_certificate.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/transfer_ca_certificate.py @@ -48,7 +48,7 @@ class TransferCACertificateState(BaseState): retry_counter = 0 while True: try: - sysinv_client = self.get_sysinv_client(strategy_step.subcloud.name) + sysinv_client = self.get_sysinv_client(strategy_step.subcloud.region_name) data = {'mode': 'openldap_ca'} ldap_ca_cert, ldap_ca_key = utils.get_certificate_from_secret( diff --git a/distributedcloud/dcmanager/orchestrator/states/upgrade/upgrading_simplex.py b/distributedcloud/dcmanager/orchestrator/states/upgrade/upgrading_simplex.py index 69dd1f7ea..468ae1803 100644 --- a/distributedcloud/dcmanager/orchestrator/states/upgrade/upgrading_simplex.py +++ b/distributedcloud/dcmanager/orchestrator/states/upgrade/upgrading_simplex.py @@ -38,9 +38,9 @@ class UpgradingSimplexState(BaseState): subcloud_barbican_client = None try: subcloud_sysinv_client = self.get_sysinv_client( - strategy_step.subcloud.name) + strategy_step.subcloud.region_name) subcloud_barbican_client = self.get_barbican_client( - strategy_step.subcloud.name) + strategy_step.subcloud.region_name) except Exception: # if getting the token times out, the orchestrator may have # restarted and subcloud may be offline; so will attempt diff --git a/distributedcloud/dcmanager/rpc/client.py b/distributedcloud/dcmanager/rpc/client.py index f93bcdab2..9cafd765b 100644 --- a/distributedcloud/dcmanager/rpc/client.py +++ b/distributedcloud/dcmanager/rpc/client.py @@ -69,6 +69,7 @@ class SubcloudStateClient(RPCClient): def update_subcloud_availability(self, ctxt, subcloud_name, + subcloud_region, availability_status, update_state_only=False, audit_fail_count=None): @@ -77,11 +78,13 @@ class SubcloudStateClient(RPCClient): ctxt, self.make_msg('update_subcloud_availability', subcloud_name=subcloud_name, + subcloud_region=subcloud_region, availability_status=availability_status, update_state_only=update_state_only, audit_fail_count=audit_fail_count)) def update_subcloud_endpoint_status(self, ctxt, subcloud_name=None, + subcloud_region=None, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC, ignore_endpoints=None, @@ -90,12 +93,14 @@ class SubcloudStateClient(RPCClient): # See below for synchronous method call return self.cast(ctxt, self.make_msg('update_subcloud_endpoint_status', subcloud_name=subcloud_name, + subcloud_region=subcloud_region, endpoint_type=endpoint_type, sync_status=sync_status, ignore_endpoints=ignore_endpoints, alarmable=alarmable)) def update_subcloud_endpoint_status_sync(self, ctxt, subcloud_name=None, + subcloud_region=None, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC, ignore_endpoints=None, @@ -103,6 +108,7 @@ class SubcloudStateClient(RPCClient): # Note: synchronous return self.call(ctxt, self.make_msg('update_subcloud_endpoint_status', subcloud_name=subcloud_name, + subcloud_region=subcloud_region, endpoint_type=endpoint_type, sync_status=sync_status, ignore_endpoints=ignore_endpoints, @@ -133,6 +139,12 @@ class ManagerClient(RPCClient): return self.call(ctxt, self.make_msg('delete_subcloud', subcloud_id=subcloud_id)) + def rename_subcloud(self, ctxt, subcloud_id, curr_subcloud_name, new_subcloud_name=None): + return self.call(ctxt, self.make_msg('rename_subcloud', + subcloud_id=subcloud_id, + curr_subcloud_name=curr_subcloud_name, + new_subcloud_name=new_subcloud_name)) + def update_subcloud(self, ctxt, subcloud_id, management_state=None, description=None, location=None, group_id=None, data_install=None, force=None, @@ -173,13 +185,13 @@ class ManagerClient(RPCClient): payload=payload)) def update_subcloud_sync_endpoint_type(self, ctxt, - subcloud_name, + subcloud_region, endpoint_type_list, openstack_installed): return self.cast( ctxt, self.make_msg('update_subcloud_sync_endpoint_type', - subcloud_name=subcloud_name, + subcloud_region=subcloud_region, endpoint_type_list=endpoint_type_list, openstack_installed=openstack_installed)) @@ -229,6 +241,10 @@ class ManagerClient(RPCClient): subcloud_ref=subcloud_ref, payload=payload)) + def get_subcloud_name_by_region_name(self, ctxt, subcloud_region): + return self.call(ctxt, self.make_msg('get_subcloud_name_by_region_name', + subcloud_region=subcloud_region)) + class DCManagerNotifications(RPCClient): """DC Manager Notification interface to broadcast subcloud state changed diff --git a/distributedcloud/dcmanager/state/service.py b/distributedcloud/dcmanager/state/service.py index d21e44c35..ec20621fa 100644 --- a/distributedcloud/dcmanager/state/service.py +++ b/distributedcloud/dcmanager/state/service.py @@ -10,7 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2017-2022 Wind River Systems, Inc. +# Copyright (c) 2017-2023 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 @@ -113,6 +113,7 @@ class DCManagerStateService(service.Service): @request_context def update_subcloud_endpoint_status(self, context, subcloud_name=None, + subcloud_region=None, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC, alarmable=True, @@ -124,7 +125,7 @@ class DCManagerStateService(service.Service): self.subcloud_state_manager. \ update_subcloud_endpoint_status(context, - subcloud_name, + subcloud_region, endpoint_type, sync_status, alarmable, @@ -153,6 +154,7 @@ class DCManagerStateService(service.Service): @request_context def update_subcloud_availability(self, context, subcloud_name, + subcloud_region, availability_status, update_state_only=False, audit_fail_count=None): @@ -161,7 +163,7 @@ class DCManagerStateService(service.Service): subcloud_name) self.subcloud_state_manager.update_subcloud_availability( context, - subcloud_name, + subcloud_region, availability_status, update_state_only, audit_fail_count) diff --git a/distributedcloud/dcmanager/state/subcloud_state_manager.py b/distributedcloud/dcmanager/state/subcloud_state_manager.py index 2e5fea369..26ad0746f 100644 --- a/distributedcloud/dcmanager/state/subcloud_state_manager.py +++ b/distributedcloud/dcmanager/state/subcloud_state_manager.py @@ -42,9 +42,9 @@ def sync_update_subcloud_endpoint_status(func): """Synchronized lock decorator for _update_subcloud_endpoint_status. """ def _get_lock_and_call(*args, **kwargs): - """Get a single fair lock per subcloud based on subcloud name. """ + """Get a single fair lock per subcloud based on subcloud region. """ - # subcloud name is the 3rd argument to + # subcloud region is the 3rd argument to # _update_subcloud_endpoint_status() @utils.synchronized(args[2], external=True, fair=True) def _call_func(*args, **kwargs): @@ -262,7 +262,7 @@ class SubcloudStateManager(manager.Manager): @sync_update_subcloud_endpoint_status def _update_subcloud_endpoint_status( self, context, - subcloud_name, + subcloud_region, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC, alarmable=True, @@ -270,7 +270,7 @@ class SubcloudStateManager(manager.Manager): """Update subcloud endpoint status :param context: request context object - :param subcloud_name: name of subcloud to update + :param subcloud_region: name of subcloud region to update :param endpoint_type: endpoint type to update :param sync_status: sync status to set :param alarmable: controls raising an alarm if applicable @@ -281,13 +281,13 @@ class SubcloudStateManager(manager.Manager): if ignore_endpoints is None: ignore_endpoints = [] - if not subcloud_name: + if not subcloud_region: raise exceptions.BadRequest( resource='subcloud', - msg='Subcloud name not provided') + msg='Subcloud region not provided') try: - subcloud = db_api.subcloud_get_by_name(context, subcloud_name) + subcloud = db_api.subcloud_get_by_region_name(context, subcloud_region) except Exception as e: LOG.exception(e) raise e @@ -327,12 +327,12 @@ class SubcloudStateManager(manager.Manager): else: LOG.info("Ignoring subcloud sync_status update for subcloud:%s " "availability:%s management:%s endpoint:%s sync:%s" % - (subcloud_name, subcloud.availability_status, + (subcloud.name, subcloud.availability_status, subcloud.management_state, endpoint_type, sync_status)) def update_subcloud_endpoint_status( self, context, - subcloud_name=None, + subcloud_region=None, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC, alarmable=True, @@ -340,7 +340,7 @@ class SubcloudStateManager(manager.Manager): """Update subcloud endpoint status :param context: request context object - :param subcloud_name: name of subcloud to update + :param subcloud_region: region of subcloud to update :param endpoint_type: endpoint type to update :param sync_status: sync status to set :param alarmable: controls raising an alarm if applicable @@ -351,18 +351,18 @@ class SubcloudStateManager(manager.Manager): if ignore_endpoints is None: ignore_endpoints = [] - if subcloud_name: + if subcloud_region: self._update_subcloud_endpoint_status( - context, subcloud_name, endpoint_type, sync_status, alarmable, + context, subcloud_region, endpoint_type, sync_status, alarmable, ignore_endpoints) else: # update all subclouds for subcloud in db_api.subcloud_get_all(context): self._update_subcloud_endpoint_status( - context, subcloud.name, endpoint_type, sync_status, + context, subcloud.region_name, endpoint_type, sync_status, alarmable, ignore_endpoints) - def _update_subcloud_state(self, context, subcloud_name, + def _update_subcloud_state(self, context, subcloud_name, subcloud_region, management_state, availability_status): try: LOG.info('Notifying dcorch, subcloud:%s management: %s, ' @@ -372,7 +372,7 @@ class SubcloudStateManager(manager.Manager): availability_status)) self.dcorch_rpc_client.update_subcloud_states( - context, subcloud_name, management_state, availability_status) + context, subcloud_region, management_state, availability_status) except Exception: LOG.exception('Problem informing dcorch of subcloud state change,' @@ -418,20 +418,21 @@ class SubcloudStateManager(manager.Manager): LOG.exception("Failed to raise offline alarm for subcloud: %s", subcloud_name) - def update_subcloud_availability(self, context, subcloud_name, + def update_subcloud_availability(self, context, subcloud_region, availability_status, update_state_only=False, audit_fail_count=None): try: - subcloud = db_api.subcloud_get_by_name(context, subcloud_name) + subcloud = db_api.subcloud_get_by_region_name(context, subcloud_region) except Exception: - LOG.exception("Failed to get subcloud by name: %s" % subcloud_name) + LOG.exception("Failed to get subcloud by region name %s" % subcloud_region) raise if update_state_only: # Nothing has changed, but we want to send a state update for this # subcloud as an audit. Get the most up-to-date data. - self._update_subcloud_state(context, subcloud_name, + self._update_subcloud_state(context, subcloud.name, + subcloud.region_name, subcloud.management_state, availability_status) elif availability_status is None: @@ -443,17 +444,17 @@ class SubcloudStateManager(manager.Manager): # slim possibility subcloud could have been deleted since # we found it in db, ignore this benign error. LOG.info('Ignoring SubcloudNotFound when attempting ' - 'audit_fail_count update: %s' % subcloud_name) + 'audit_fail_count update: %s' % subcloud.name) return else: - self._raise_or_clear_subcloud_status_alarm(subcloud_name, + self._raise_or_clear_subcloud_status_alarm(subcloud.name, availability_status) if availability_status == dccommon_consts.AVAILABILITY_OFFLINE: # Subcloud is going offline, set all endpoint statuses to # unknown. self._update_subcloud_endpoint_status( - context, subcloud_name, endpoint_type=None, + context, subcloud.region_name, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_UNKNOWN) try: @@ -466,27 +467,28 @@ class SubcloudStateManager(manager.Manager): # slim possibility subcloud could have been deleted since # we found it in db, ignore this benign error. LOG.info('Ignoring SubcloudNotFound when attempting state' - ' update: %s' % subcloud_name) + ' update: %s' % subcloud.name) return if availability_status == dccommon_consts.AVAILABILITY_ONLINE: # Subcloud is going online # Tell cert-mon to audit endpoint certificate. - LOG.info('Request for online audit for %s' % subcloud_name) + LOG.info('Request for online audit for %s' % subcloud.name) dc_notification = rpc_client.DCManagerNotifications() - dc_notification.subcloud_online(context, subcloud_name) + dc_notification.subcloud_online(context, subcloud.region_name) # Trigger all the audits for the subcloud so it can update the # sync status ASAP. self.audit_rpc_client.trigger_subcloud_audits(context, subcloud.id) # Send dcorch a state update - self._update_subcloud_state(context, subcloud_name, + self._update_subcloud_state(context, subcloud.name, + subcloud.region_name, updated_subcloud.management_state, availability_status) def update_subcloud_sync_endpoint_type(self, context, - subcloud_name, + subcloud_region, endpoint_type_list, openstack_installed): operation = 'add' if openstack_installed else 'remove' @@ -502,17 +504,17 @@ class SubcloudStateManager(manager.Manager): } try: - subcloud = db_api.subcloud_get_by_name(context, subcloud_name) + subcloud = db_api.subcloud_get_by_region_name(context, subcloud_region) except Exception: - LOG.exception("Failed to get subcloud by name: %s" % subcloud_name) + LOG.exception("Failed to get subcloud by region name: %s" % subcloud_region) raise try: # Notify dcorch to add/remove sync endpoint type list - func_switcher[operation][0](self.context, subcloud_name, + func_switcher[operation][0](self.context, subcloud_region, endpoint_type_list) LOG.info('Notifying dcorch, subcloud: %s new sync endpoint: %s' % - (subcloud_name, endpoint_type_list)) + (subcloud.name, endpoint_type_list)) # Update subcloud status table by adding/removing openstack sync # endpoint types @@ -524,4 +526,4 @@ class SubcloudStateManager(manager.Manager): openstack_installed=openstack_installed) except Exception: LOG.exception('Problem informing dcorch of subcloud sync endpoint' - ' type change, subcloud: %s' % subcloud_name) + ' type change, subcloud: %s' % subcloud.name) diff --git a/distributedcloud/dcmanager/tests/base.py b/distributedcloud/dcmanager/tests/base.py index 34b04762e..69eee435c 100644 --- a/distributedcloud/dcmanager/tests/base.py +++ b/distributedcloud/dcmanager/tests/base.py @@ -36,6 +36,29 @@ get_engine = api.get_engine from sqlalchemy.engine import Engine from sqlalchemy import event +SUBCLOUD_1 = {'name': 'subcloud1', + 'region_name': '2ec93dfb654846909efe61d1b39dd2ce'} +SUBCLOUD_2 = {'name': 'subcloud2', + 'region_name': 'ca2761ee7aa34cbe8415ec9a3c86854f'} +SUBCLOUD_3 = {'name': 'subcloud3', + 'region_name': '659e12e5f7ad411abfcd83f5cedca0bf'} +SUBCLOUD_4 = {'name': 'subcloud4', + 'region_name': 'c25f3b0553384104b664789bd93a2ba8'} +SUBCLOUD_5 = {'name': 'subcloud5', + 'region_name': '809581dc2d154e008480bac1f43b7aff'} +SUBCLOUD_6 = {'name': 'subcloud6', + 'region_name': '8c60b99f3e1245b7bc5a049802ade8d2'} +SUBCLOUD_7 = {'name': 'subcloud7', + 'region_name': '9fde6dca22fa422bb1e8cf03bedc18e4'} +SUBCLOUD_8 = {'name': 'subcloud8', + 'region_name': 'f3cb0b109c4543fda3ed50ed5783279d'} +SUBCLOUD_9 = {'name': 'subcloud9', + 'region_name': '1cfab1df7b444bb3bd562894d684f352'} +SUBCLOUD_10 = {'name': 'subcloud10', + 'region_name': '6d0040199b4f4a9fb4a1f2ed4d498159'} +SUBCLOUD_11 = {'name': 'subcloud11', + 'region_name': '169e6fc231e94959ad6ff0a66fbcb753'} + SUBCLOUD_SAMPLE_DATA_0 = [ 6, # id "subcloud-4", # name @@ -63,6 +86,7 @@ SUBCLOUD_SAMPLE_DATA_0 = [ 1, # group_id consts.DEPLOY_STATE_DONE, # deploy_status consts.ERROR_DESC_EMPTY, # error_description + SUBCLOUD_4['region_name'], # region_name json.dumps({'data_install': 'test data install values'}), # data_install ] 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 224fc2c1f..ccf78a804 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 @@ -17,6 +17,7 @@ from dcmanager.common import consts from dcmanager.db.sqlalchemy import api as db_api from dcmanager.rpc import client as rpc_client +from dcmanager.tests import base from dcmanager.tests.unit.api import test_root_controller as testroot from dcmanager.tests.unit.common import fake_subcloud from dcmanager.tests import utils @@ -1059,7 +1060,9 @@ class TestSubcloudRestore(testroot.DCManagerApiTest): test_group_id = 1 subcloud = fake_subcloud.create_fake_subcloud(self.ctx, group_id=test_group_id) - subcloud2 = fake_subcloud.create_fake_subcloud(self.ctx, group_id=test_group_id, name='subcloud2') + subcloud2 = fake_subcloud.create_fake_subcloud(self.ctx, group_id=test_group_id, + name=base.SUBCLOUD_2['name'], + region_name=base.SUBCLOUD_2['region_name']) # Valid subcloud, management state is 'unmanaged' db_api.subcloud_update(self.ctx, subcloud.id, diff --git a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_group.py b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_group.py index 628381def..6b61cf4b0 100644 --- a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_group.py +++ b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subcloud_group.py @@ -239,6 +239,7 @@ class TestSubcloudGroupGet(testroot.DCManagerApiTest, FAKE_SUBCLOUD_DATA.get('systemcontroller_gateway_ip'), 'deploy_status': FAKE_SUBCLOUD_DATA.get('deploy_status'), 'error_description': FAKE_SUBCLOUD_DATA.get('error_description'), + 'region_name': FAKE_SUBCLOUD_DATA.get('region_name'), 'openstack_installed': FAKE_SUBCLOUD_DATA.get('openstack_installed'), 'group_id': FAKE_SUBCLOUD_DATA.get('group_id', 1) 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 608ab4790..4095d360d 100644 --- a/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subclouds.py +++ b/distributedcloud/dcmanager/tests/unit/api/v1/controllers/test_subclouds.py @@ -1429,7 +1429,8 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest): data, headers=FAKE_HEADERS) self.mock_rpc_state_client().update_subcloud_endpoint_status.\ - assert_called_once_with(mock.ANY, subcloud.name, 'dc-cert', 'in-sync') + assert_called_once_with(mock.ANY, subcloud.name, subcloud.region_name, + 'dc-cert', 'in-sync') self.assertEqual(response.status_int, 200) diff --git a/distributedcloud/dcmanager/tests/unit/audit/test_firmware_audit_manager.py b/distributedcloud/dcmanager/tests/unit/audit/test_firmware_audit_manager.py index 8cad1b7bd..8eb5faad8 100644 --- a/distributedcloud/dcmanager/tests/unit/audit/test_firmware_audit_manager.py +++ b/distributedcloud/dcmanager/tests/unit/audit/test_firmware_audit_manager.py @@ -28,7 +28,6 @@ from dcmanager.audit import subcloud_audit_manager from dcmanager.tests import base from dcmanager.tests import utils - CONF = cfg.CONF @@ -462,11 +461,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -494,11 +496,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -525,11 +530,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -556,11 +564,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -587,11 +598,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -618,11 +632,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -649,11 +666,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -680,11 +700,14 @@ class TestFirmwareAudit(base.DCManagerTestCase): am.firmware_audit = fm firmware_audit_data = self.get_fw_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - fm.subcloud_firmware_audit(name, firmware_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + fm.subcloud_firmware_audit(name, region, firmware_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_FIRMWARE, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ diff --git a/distributedcloud/dcmanager/tests/unit/audit/test_kube_audit_manager.py b/distributedcloud/dcmanager/tests/unit/audit/test_kube_audit_manager.py index 1d55fd0a2..4e94c236b 100644 --- a/distributedcloud/dcmanager/tests/unit/audit/test_kube_audit_manager.py +++ b/distributedcloud/dcmanager/tests/unit/audit/test_kube_audit_manager.py @@ -24,7 +24,6 @@ from dcmanager.audit import subcloud_audit_manager from dcmanager.tests import base from dcmanager.tests import utils - PREVIOUS_KUBE_VERSION = 'v1.2.3' UPGRADED_KUBE_VERSION = 'v1.2.3-a' @@ -166,11 +165,14 @@ class TestKubernetesAudit(base.DCManagerTestCase): am.kubernetes_audit = audit kubernetes_audit_data = self.get_kube_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - audit.subcloud_kubernetes_audit(name, kubernetes_audit_data) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + audit.subcloud_kubernetes_audit(name, region, kubernetes_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_KUBERNETES, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -190,15 +192,18 @@ class TestKubernetesAudit(base.DCManagerTestCase): ] kubernetes_audit_data = self.get_kube_audit_data(am) - for name in ['subcloud1', 'subcloud2']: + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): # return different kube versions in the subclouds self.kube_sysinv_client.get_kube_versions.return_value = [ FakeKubeVersion(version=PREVIOUS_KUBE_VERSION), ] - audit.subcloud_kubernetes_audit(name, kubernetes_audit_data) + audit.subcloud_kubernetes_audit(name, region, kubernetes_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_KUBERNETES, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -218,15 +223,18 @@ class TestKubernetesAudit(base.DCManagerTestCase): ] kubernetes_audit_data = self.get_kube_audit_data(am) - for name in ['subcloud1', 'subcloud2']: + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): # return different kube versions in the subclouds self.kube_sysinv_client.get_kube_versions.return_value = [ FakeKubeVersion(version=UPGRADED_KUBE_VERSION), ] - audit.subcloud_kubernetes_audit(name, kubernetes_audit_data) + audit.subcloud_kubernetes_audit(name, region, kubernetes_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_KUBERNETES, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -247,15 +255,18 @@ class TestKubernetesAudit(base.DCManagerTestCase): ] kubernetes_audit_data = self.get_kube_audit_data(am) - for name in ['subcloud1', 'subcloud2']: + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): # return same kube versions in the subclouds self.kube_sysinv_client.get_kube_versions.return_value = [ FakeKubeVersion(version=UPGRADED_KUBE_VERSION), ] - audit.subcloud_kubernetes_audit(name, kubernetes_audit_data) + audit.subcloud_kubernetes_audit(name, region, kubernetes_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_KUBERNETES, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -282,15 +293,18 @@ class TestKubernetesAudit(base.DCManagerTestCase): ] kubernetes_audit_data = self.get_kube_audit_data(am) - for name in ['subcloud1', 'subcloud2']: + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): # return same kube versions in the subclouds self.kube_sysinv_client.get_kube_versions.return_value = [ FakeKubeVersion(version=UPGRADED_KUBE_VERSION), ] - audit.subcloud_kubernetes_audit(name, kubernetes_audit_data) + audit.subcloud_kubernetes_audit(name, region, kubernetes_audit_data) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_KUBERNETES, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ diff --git a/distributedcloud/dcmanager/tests/unit/audit/test_patch_audit_manager.py b/distributedcloud/dcmanager/tests/unit/audit/test_patch_audit_manager.py index 36d327982..53ae625f4 100644 --- a/distributedcloud/dcmanager/tests/unit/audit/test_patch_audit_manager.py +++ b/distributedcloud/dcmanager/tests/unit/audit/test_patch_audit_manager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2022 Wind River Systems, Inc. +# Copyright (c) 2017-2023 Wind River Systems, Inc. # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at @@ -27,7 +27,6 @@ from dcmanager.audit import subcloud_audit_manager from dcmanager.tests import base from dcmanager.tests import utils - CONF = cfg.CONF @@ -85,7 +84,8 @@ class FakePatchingClientInSync(object): 'repostate': 'Applied', 'patchstate': 'Applied'}, } - elif self.region in ['subcloud1', 'subcloud2']: + elif self.region in [base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['region_name']]: return {'DC.1': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}, @@ -117,25 +117,25 @@ class FakePatchingClientOutOfSync(object): 'DC.2': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}} - elif self.region == 'subcloud1': + elif self.region == base.SUBCLOUD_1['region_name']: return {'DC.1': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}, 'DC.2': {'sw_version': '17.07', 'repostate': 'Available', 'patchstate': 'Available'}} - elif self.region == 'subcloud2': + elif self.region == base.SUBCLOUD_2['region_name']: return {'DC.1': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}} - elif self.region == 'subcloud3': + elif self.region == base.SUBCLOUD_3['region_name']: return {'DC.1': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}, 'DC.2': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}} - elif self.region == 'subcloud4': + elif self.region == base.SUBCLOUD_4['region_name']: return {'DC.1': {'sw_version': '17.07', 'repostate': 'Applied', 'patchstate': 'Applied'}, @@ -219,7 +219,7 @@ class FakeSysinvClientOneLoadUnmatchedSoftwareVersion(object): return self.upgrades def get_system(self): - if self.region == 'subcloud2': + if self.region == base.SUBCLOUD_2['region_name']: return System('17.06') else: return self.system @@ -238,7 +238,7 @@ class FakeSysinvClientOneLoadUpgradeInProgress(object): return self.loads def get_upgrades(self): - if self.region == 'subcloud2': + if self.region == base.SUBCLOUD_2['region_name']: return [Upgrade('started')] else: return self.upgrades @@ -302,15 +302,19 @@ class TestPatchAudit(base.DCManagerTestCase): do_load_audit = True patch_audit_data = self.get_patch_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - pm.subcloud_patch_audit(name, patch_audit_data, do_load_audit) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + pm.subcloud_patch_audit(name, region, patch_audit_data, do_load_audit) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status. \ @@ -336,40 +340,52 @@ class TestPatchAudit(base.DCManagerTestCase): do_load_audit = True patch_audit_data = self.get_patch_audit_data(am) - for name in ['subcloud1', 'subcloud2', 'subcloud3', 'subcloud4']: - pm.subcloud_patch_audit(name, patch_audit_data, do_load_audit) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name'], + base.SUBCLOUD_3['name']: base.SUBCLOUD_3['region_name'], + base.SUBCLOUD_4['name']: base.SUBCLOUD_4['region_name']} + for name, region in subclouds.items(): + pm.subcloud_patch_audit(name, region, patch_audit_data, do_load_audit) expected_calls = [ mock.call(mock.ANY, - subcloud_name='subcloud1', + subcloud_name=base.SUBCLOUD_1['name'], + subcloud_region=base.SUBCLOUD_1['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud1', + subcloud_name=base.SUBCLOUD_1['name'], + subcloud_region=base.SUBCLOUD_1['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud2', + subcloud_name=base.SUBCLOUD_2['name'], + subcloud_region=base.SUBCLOUD_2['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud2', + subcloud_name=base.SUBCLOUD_2['name'], + subcloud_region=base.SUBCLOUD_2['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud3', + subcloud_name=base.SUBCLOUD_3['name'], + subcloud_region=base.SUBCLOUD_3['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud3', + subcloud_name=base.SUBCLOUD_3['name'], + subcloud_region=base.SUBCLOUD_3['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud4', + subcloud_name=base.SUBCLOUD_4['name'], + subcloud_region=base.SUBCLOUD_4['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud4', + subcloud_name=base.SUBCLOUD_4['name'], + subcloud_region=base.SUBCLOUD_4['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), ] @@ -397,15 +413,19 @@ class TestPatchAudit(base.DCManagerTestCase): do_load_audit = True patch_audit_data = self.get_patch_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - pm.subcloud_patch_audit(name, patch_audit_data, do_load_audit) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + pm.subcloud_patch_audit(name, region, patch_audit_data, do_load_audit) expected_calls = [ mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC), mock.call(mock.ANY, subcloud_name=name, + subcloud_region=region, endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC)] self.fake_dcmanager_state_api.update_subcloud_endpoint_status.\ @@ -431,24 +451,30 @@ class TestPatchAudit(base.DCManagerTestCase): do_load_audit = True patch_audit_data = self.get_patch_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - pm.subcloud_patch_audit(name, patch_audit_data, do_load_audit) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + pm.subcloud_patch_audit(name, region, patch_audit_data, do_load_audit) expected_calls = [ mock.call(mock.ANY, - subcloud_name='subcloud1', + subcloud_name=base.SUBCLOUD_1['name'], + subcloud_region=base.SUBCLOUD_1['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud1', + subcloud_name=base.SUBCLOUD_1['name'], + subcloud_region=base.SUBCLOUD_1['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud2', + subcloud_name=base.SUBCLOUD_2['name'], + subcloud_region=base.SUBCLOUD_2['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud2', + subcloud_name=base.SUBCLOUD_2['name'], + subcloud_region=base.SUBCLOUD_2['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC), ] @@ -475,24 +501,30 @@ class TestPatchAudit(base.DCManagerTestCase): do_load_audit = True patch_audit_data = self.get_patch_audit_data(am) - for name in ['subcloud1', 'subcloud2']: - pm.subcloud_patch_audit(name, patch_audit_data, do_load_audit) + subclouds = {base.SUBCLOUD_1['name']: base.SUBCLOUD_1['region_name'], + base.SUBCLOUD_2['name']: base.SUBCLOUD_2['region_name']} + for name, region in subclouds.items(): + pm.subcloud_patch_audit(name, region, patch_audit_data, do_load_audit) expected_calls = [ mock.call(mock.ANY, - subcloud_name='subcloud1', + subcloud_name=base.SUBCLOUD_1['name'], + subcloud_region=base.SUBCLOUD_1['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud1', + subcloud_name=base.SUBCLOUD_1['name'], + subcloud_region=base.SUBCLOUD_1['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud2', + subcloud_name=base.SUBCLOUD_2['name'], + subcloud_region=base.SUBCLOUD_2['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_PATCHING, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC), mock.call(mock.ANY, - subcloud_name='subcloud2', + subcloud_name=base.SUBCLOUD_2['name'], + subcloud_region=base.SUBCLOUD_2['region_name'], endpoint_type=dccommon_consts.ENDPOINT_TYPE_LOAD, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC), ] diff --git a/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_manager.py b/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_manager.py index 527696352..287dbc661 100644 --- a/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_manager.py +++ b/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_manager.py @@ -276,6 +276,7 @@ class TestAuditManager(base.DCManagerTestCase): 'systemcontroller_gateway_ip': "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': base.SUBCLOUD_1['region_name'], 'openstack_installed': False, 'group_id': 1, } diff --git a/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_worker_manager.py b/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_worker_manager.py index b537572b6..d9a084f5c 100644 --- a/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_worker_manager.py +++ b/distributedcloud/dcmanager/tests/unit/audit/test_subcloud_audit_worker_manager.py @@ -370,6 +370,7 @@ class TestAuditWorkerManager(base.DCManagerTestCase): 'systemcontroller_gateway_ip': "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': base.SUBCLOUD_1['region_name'], 'openstack_installed': False, 'group_id': 1, } @@ -429,8 +430,8 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify the subcloud was set to online self.fake_dcmanager_state_api.update_subcloud_availability.assert_called_with( - mock.ANY, subcloud.name, dccommon_consts.AVAILABILITY_ONLINE, - False, 0) + mock.ANY, subcloud.name, subcloud.region_name, + dccommon_consts.AVAILABILITY_ONLINE, False, 0) # Verify the _update_subcloud_audit_fail_count is not called with mock.patch.object(wm, '_update_subcloud_audit_fail_count') as \ @@ -447,19 +448,19 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify patch audit is called self.fake_patch_audit.subcloud_patch_audit.assert_called_with( - subcloud.name, patch_audit_data, do_load_audit) + subcloud.name, subcloud.region_name, patch_audit_data, do_load_audit) # Verify firmware audit is called self.fake_firmware_audit.subcloud_firmware_audit.assert_called_with( - subcloud.name, firmware_audit_data) + subcloud.name, subcloud.region_name, firmware_audit_data) # Verify kubernetes audit is called self.fake_kubernetes_audit.subcloud_kubernetes_audit.assert_called_with( - subcloud.name, kubernetes_audit_data) + subcloud.name, subcloud.region_name, kubernetes_audit_data) # Verify kube rootca update audit is called self.fake_kube_rootca_update_audit.subcloud_audit.assert_called_with( - subcloud.name, kube_rootca_update_audit_data) + subcloud.name, subcloud.region_name, kube_rootca_update_audit_data) def test_audit_subcloud_online_first_identity_sync_not_complete(self): @@ -506,8 +507,8 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify the subcloud was set to online self.fake_dcmanager_state_api.update_subcloud_availability.assert_called_with( - mock.ANY, subcloud.name, dccommon_consts.AVAILABILITY_ONLINE, - False, 0) + mock.ANY, subcloud.name, subcloud.region_name, + dccommon_consts.AVAILABILITY_ONLINE, False, 0) # Verify the _update_subcloud_audit_fail_count is not called with mock.patch.object(wm, '_update_subcloud_audit_fail_count') as \ @@ -573,8 +574,8 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify the subcloud was set to online self.fake_dcmanager_state_api.update_subcloud_availability.assert_called_with( - mock.ANY, subcloud.name, dccommon_consts.AVAILABILITY_ONLINE, - False, 0) + mock.ANY, subcloud.name, subcloud.region_name, + dccommon_consts.AVAILABILITY_ONLINE, False, 0) # Verify the _update_subcloud_audit_fail_count is not called with mock.patch.object(wm, '_update_subcloud_audit_fail_count') as \ @@ -669,8 +670,8 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify the subcloud state was updated even though no change self.fake_dcmanager_state_api.update_subcloud_availability.assert_called_with( - mock.ANY, subcloud.name, dccommon_consts.AVAILABILITY_ONLINE, - True, None) + mock.ANY, subcloud.name, subcloud.region_name, + dccommon_consts.AVAILABILITY_ONLINE, True, None) # Verify the _update_subcloud_audit_fail_count is not called with mock.patch.object(wm, '_update_subcloud_audit_fail_count') as \ @@ -785,19 +786,19 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify patch audit is called only once self.fake_patch_audit.subcloud_patch_audit.assert_called_once_with( - subcloud.name, mock.ANY, True) + subcloud.name, subcloud.region_name, mock.ANY, True) # Verify firmware audit is only called once self.fake_firmware_audit.subcloud_firmware_audit.assert_called_once_with( - subcloud.name, mock.ANY) + subcloud.name, subcloud.region_name, mock.ANY) # Verify kubernetes audit is only called once self.fake_kubernetes_audit.subcloud_kubernetes_audit.assert_called_once_with( - subcloud.name, mock.ANY) + subcloud.name, subcloud.region_name, mock.ANY) # Verify kube rootca update audit is only called once self.fake_kube_rootca_update_audit.subcloud_audit.assert_called_once_with( - subcloud.name, mock.ANY) + subcloud.name, subcloud.region_name, mock.ANY) def test_audit_subcloud_offline_no_change(self): subcloud = self.create_subcloud_static(self.ctx, name='subcloud1') @@ -1060,12 +1061,12 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify the openstack endpoints were removed self.fake_dcmanager_api.update_subcloud_sync_endpoint_type.\ - assert_called_with(mock.ANY, 'subcloud1', + assert_called_with(mock.ANY, subcloud.region_name, dccommon_consts.ENDPOINT_TYPES_LIST_OS, False) # Verify alarm update is called self.fake_alarm_aggr.update_alarm_summary.assert_called_once_with( - 'subcloud1', self.fake_openstack_client.fm_client) + subcloud.name, self.fake_openstack_client.fm_client) # Verify patch audit is not called self.fake_patch_audit.subcloud_patch_audit.assert_not_called() @@ -1122,7 +1123,7 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify the openstack endpoints were removed self.fake_dcmanager_api.update_subcloud_sync_endpoint_type.\ - assert_called_with(mock.ANY, 'subcloud1', + assert_called_with(mock.ANY, subcloud.region_name, dccommon_consts.ENDPOINT_TYPES_LIST_OS, False) # Verify alarm update is called @@ -1195,7 +1196,7 @@ class TestAuditWorkerManager(base.DCManagerTestCase): # Verify patch audit is called self.fake_patch_audit.subcloud_patch_audit.assert_called_with( - subcloud.name, patch_audit_data, do_load_audit) + subcloud.name, subcloud.region_name, patch_audit_data, do_load_audit) # Verify the _update_subcloud_audit_fail_count is not called with mock.patch.object(wm, '_update_subcloud_audit_fail_count') as \ diff --git a/distributedcloud/dcmanager/tests/unit/common/fake_subcloud.py b/distributedcloud/dcmanager/tests/unit/common/fake_subcloud.py index aac9d8cf3..37918fe4b 100644 --- a/distributedcloud/dcmanager/tests/unit/common/fake_subcloud.py +++ b/distributedcloud/dcmanager/tests/unit/common/fake_subcloud.py @@ -9,6 +9,7 @@ import base64 from dcmanager.common import consts from dcmanager.db.sqlalchemy import api as db_api +from dcmanager.tests import base from dcmanager.tests import utils FAKE_TENANT = utils.UUID1 @@ -33,6 +34,7 @@ FAKE_SUBCLOUD_DATA = {"id": FAKE_ID, "systemcontroller_gateway_address": "192.168.204.101", "deploy_status": consts.DEPLOY_STATE_DONE, 'error_description': consts.ERROR_DESC_EMPTY, + 'region_name': base.SUBCLOUD_1['region_name'], "external_oam_subnet": "10.10.10.0/24", "external_oam_gateway_address": "10.10.10.1", "external_oam_floating_address": "10.10.10.12", @@ -128,6 +130,7 @@ def create_fake_subcloud(ctxt, **kwargs): "systemcontroller_gateway_ip": "192.168.204.101", 'deploy_status': consts.DEPLOY_STATE_DONE, 'error_description': consts.ERROR_DESC_EMPTY, + 'region_name': base.SUBCLOUD_1['region_name'], 'openstack_installed': False, 'group_id': 1, 'data_install': 'data from install', diff --git a/distributedcloud/dcmanager/tests/unit/db/test_subcloud_audits.py b/distributedcloud/dcmanager/tests/unit/db/test_subcloud_audits.py index e4f06ddd4..7bff94a2d 100644 --- a/distributedcloud/dcmanager/tests/unit/db/test_subcloud_audits.py +++ b/distributedcloud/dcmanager/tests/unit/db/test_subcloud_audits.py @@ -15,6 +15,7 @@ import datetime from oslo_db import exception as db_exception +from oslo_utils import uuidutils from dcmanager.common import exceptions as exception from dcmanager.db import api as api @@ -40,6 +41,7 @@ class DBAPISubcloudAuditsTest(base.DCManagerTestCase): 'systemcontroller_gateway_ip': "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': uuidutils.generate_uuid().replace("-", ""), 'openstack_installed': False, 'group_id': 1, } diff --git a/distributedcloud/dcmanager/tests/unit/db/test_subcloud_db_api.py b/distributedcloud/dcmanager/tests/unit/db/test_subcloud_db_api.py index c37b76ac3..6ce5f05d6 100644 --- a/distributedcloud/dcmanager/tests/unit/db/test_subcloud_db_api.py +++ b/distributedcloud/dcmanager/tests/unit/db/test_subcloud_db_api.py @@ -57,6 +57,7 @@ class DBAPISubcloudTest(base.DCManagerTestCase): 'systemcontroller_gateway_ip': "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': base.SUBCLOUD_1['region_name'], 'openstack_installed': False, 'group_id': 1, } @@ -78,6 +79,7 @@ class DBAPISubcloudTest(base.DCManagerTestCase): 'systemcontroller_gateway_address'], 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': data['region_name'], 'openstack_installed': False, 'group_id': 1, } @@ -143,19 +145,26 @@ class DBAPISubcloudTest(base.DCManagerTestCase): def test_create_multiple_subclouds(self): name1 = 'testname1' + region1 = base.SUBCLOUD_1['region_name'] name2 = 'testname2' + region2 = base.SUBCLOUD_2['region_name'] name3 = 'testname3' - subcloud = self.create_subcloud_static(self.ctx, name=name1) + region3 = base.SUBCLOUD_3['region_name'] + subcloud = self.create_subcloud_static(self.ctx, + name=name1, + region_name=region1) self.assertIsNotNone(subcloud) subcloud2 = self.create_subcloud_static(self.ctx, name=name2, + region_name=region2, management_start_ip="2.3.4.6", management_end_ip="2.3.4.7") self.assertIsNotNone(subcloud2) subcloud3 = self.create_subcloud_static(self.ctx, name=name3, + region_name=region3, management_start_ip="3.3.4.6", management_end_ip="3.3.4.7") self.assertIsNotNone(subcloud3) diff --git a/distributedcloud/dcmanager/tests/unit/manager/test_service.py b/distributedcloud/dcmanager/tests/unit/manager/test_service.py index aebbd3b53..e122e8a62 100644 --- a/distributedcloud/dcmanager/tests/unit/manager/test_service.py +++ b/distributedcloud/dcmanager/tests/unit/manager/test_service.py @@ -22,6 +22,7 @@ from dcmanager.manager import service from dcmanager.tests import base from dcmanager.tests import utils from oslo_config import cfg +from oslo_utils import uuidutils CONF = cfg.CONF FAKE_USER = utils.UUID1 @@ -76,9 +77,11 @@ class TestDCManagerService(base.DCManagerTestCase): @mock.patch.object(service, 'SubcloudManager') def test_add_subcloud(self, mock_subcloud_manager): + payload = {'name': 'testname', + 'region_name': uuidutils.generate_uuid().replace("-", "")} self.service_obj.init_managers() self.service_obj.add_subcloud( - self.context, subcloud_id=1, payload={'name': 'testname'}) + self.context, subcloud_id=1, payload=payload) mock_subcloud_manager().add_subcloud.\ assert_called_once_with(self.context, 1, mock.ANY) diff --git a/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py b/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py index 4d8f1d2af..e0aedc52a 100644 --- a/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py +++ b/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py @@ -423,6 +423,7 @@ class TestSubcloudManager(base.DCManagerTestCase): "systemcontroller_gateway_ip": "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': "No errors present", + 'region_name': base.SUBCLOUD_1['region_name'], 'openstack_installed': False, 'group_id': 1, 'data_install': 'data from install', @@ -501,7 +502,8 @@ class TestSubcloudManager(base.DCManagerTestCase): values['deploy_status'] = consts.DEPLOY_STATE_NONE # dcmanager add_subcloud queries the data from the db - subcloud = self.create_subcloud_static(self.ctx, name=values['name']) + subcloud = self.create_subcloud_static(self.ctx, name=values['name'], + region_name=values['region_name']) values['id'] = subcloud.id mock_keystone_client().keystone_client = FakeKeystoneClient() @@ -535,7 +537,8 @@ class TestSubcloudManager(base.DCManagerTestCase): values['deploy_status'] = consts.DEPLOY_STATE_NONE # dcmanager add_subcloud queries the data from the db - subcloud = self.create_subcloud_static(self.ctx, name=values['name']) + subcloud = self.create_subcloud_static(self.ctx, name=values['name'], + region_name=values['region_name']) values['id'] = subcloud.id mock_keystone_client.side_effect = FakeException('boom') @@ -731,6 +734,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Create subcloud in DB subcloud = self.create_subcloud_static(self.ctx, name=payload['name']) + payload['region_name'] = subcloud.region_name # Mock return values mock_get_playbook_for_software_version.return_value = SW_VERSION @@ -790,7 +794,8 @@ class TestSubcloudManager(base.DCManagerTestCase): sysadmin_password = values['sysadmin_password'] # dcmanager add_subcloud queries the data from the db - subcloud = self.create_subcloud_static(self.ctx, name=values['name']) + subcloud = self.create_subcloud_static(self.ctx, name=values['name'], + region_name=values['region_name']) mock_keystone_client().keystone_client = FakeKeystoneClient() mock_keyring.get_password.return_value = sysadmin_password @@ -809,6 +814,7 @@ class TestSubcloudManager(base.DCManagerTestCase): mock_run_playbook.assert_called_once() mock_compose_rehome_command.assert_called_once_with( values['name'], + values['region_name'], sm._get_ansible_filename(values['name'], consts.INVENTORY_FILE_POSTFIX), subcloud['software_version']) @@ -836,7 +842,8 @@ class TestSubcloudManager(base.DCManagerTestCase): services = FAKE_SERVICES # dcmanager add_subcloud queries the data from the db - subcloud = self.create_subcloud_static(self.ctx, name=values['name']) + subcloud = self.create_subcloud_static(self.ctx, name=values['name'], + region_name=values['region_name']) self.fake_dcorch_api.add_subcloud.side_effect = FakeException('boom') mock_get_cached_regionone_data.return_value = FAKE_CACHED_REGIONONE_DATA @@ -865,7 +872,8 @@ class TestSubcloudManager(base.DCManagerTestCase): services = FAKE_SERVICES # dcmanager add_subcloud queries the data from the db - subcloud = self.create_subcloud_static(self.ctx, name=values['name']) + subcloud = self.create_subcloud_static(self.ctx, name=values['name'], + region_name=values['region_name']) self.fake_dcorch_api.add_subcloud.side_effect = FakeException('boom') mock_get_cached_regionone_data.return_value = FAKE_CACHED_REGIONONE_DATA @@ -933,7 +941,7 @@ class TestSubcloudManager(base.DCManagerTestCase): location="subcloud new location") fake_dcmanager_notification.subcloud_managed.assert_called_once_with( - self.ctx, subcloud.name) + self.ctx, subcloud.region_name) # Verify subcloud was updated with correct values updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name) @@ -1063,7 +1071,7 @@ class TestSubcloudManager(base.DCManagerTestCase): data_install="install values") fake_dcmanager_cermon_api.subcloud_managed.assert_called_once_with( - self.ctx, subcloud.name) + self.ctx, subcloud.region_name) # Verify subcloud was updated with correct values updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name) @@ -1190,7 +1198,7 @@ class TestSubcloudManager(base.DCManagerTestCase): group_id=2) fake_dcmanager_cermon_api.subcloud_managed.assert_called_once_with( - self.ctx, subcloud.name) + self.ctx, subcloud.region_name) # Verify subcloud was updated with correct values updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name) @@ -1234,7 +1242,7 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.ENDPOINT_TYPE_DC_CERT]: # Update ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint) # Verify @@ -1253,7 +1261,7 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.ENDPOINT_TYPE_NFV, dccommon_consts.ENDPOINT_TYPE_DC_CERT]: ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC) @@ -1267,7 +1275,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Attempt to update each status to be unknown for an offline/unmanaged # subcloud. This is allowed. ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_UNKNOWN) @@ -1286,7 +1294,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Attempt to update each status to be out-of-sync for an # offline/unmanaged subcloud. Exclude one endpoint. This is allowed. ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=None, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC, ignore_endpoints=[dccommon_consts.ENDPOINT_TYPE_DC_CERT]) @@ -1328,7 +1336,7 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.ENDPOINT_TYPE_FM, dccommon_consts.ENDPOINT_TYPE_NFV]: ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC) @@ -1343,7 +1351,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # online/unmanaged subcloud. This is allowed. Verify the change. endpoint = dccommon_consts.ENDPOINT_TYPE_DC_CERT ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC) @@ -1373,7 +1381,7 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.ENDPOINT_TYPE_NFV, dccommon_consts.ENDPOINT_TYPE_DC_CERT]: ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC) @@ -1393,11 +1401,11 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.ENDPOINT_TYPE_NFV, dccommon_consts.ENDPOINT_TYPE_DC_CERT]: ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=dccommon_consts.SYNC_STATUS_OUT_OF_SYNC) # Verify lock was called - mock_lock.assert_called_with(subcloud.name) + mock_lock.assert_called_with(subcloud.region_name) # Verify status was updated updated_subcloud_status = db_api.subcloud_status_get( @@ -1436,7 +1444,7 @@ class TestSubcloudManager(base.DCManagerTestCase): self.assertIsNotNone(status) self.assertEqual(status.sync_status, dccommon_consts.SYNC_STATUS_UNKNOWN) - ssm.update_subcloud_availability(self.ctx, subcloud.name, + ssm.update_subcloud_availability(self.ctx, subcloud.region_name, dccommon_consts.AVAILABILITY_ONLINE) updated_subcloud = db_api.subcloud_get_by_name(self.ctx, 'subcloud1') @@ -1445,13 +1453,14 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.AVAILABILITY_ONLINE) # Verify notifying dcorch self.fake_dcorch_api.update_subcloud_states.assert_called_once_with( - self.ctx, subcloud.name, updated_subcloud.management_state, + self.ctx, subcloud.region_name, updated_subcloud.management_state, dccommon_consts.AVAILABILITY_ONLINE) # Verify triggering audits self.fake_dcmanager_audit_api.trigger_subcloud_audits.\ assert_called_once_with(self.ctx, subcloud.id) - fake_dcmanager_cermon_api.subcloud_online.assert_called_once_with(self.ctx, subcloud.name) + fake_dcmanager_cermon_api.subcloud_online.\ + assert_called_once_with(self.ctx, subcloud.region_name) def test_update_subcloud_availability_go_online_unmanaged(self): # create a subcloud @@ -1483,7 +1492,7 @@ class TestSubcloudManager(base.DCManagerTestCase): self.assertIsNotNone(status) self.assertEqual(status.sync_status, dccommon_consts.SYNC_STATUS_UNKNOWN) - ssm.update_subcloud_availability(self.ctx, subcloud.name, + ssm.update_subcloud_availability(self.ctx, subcloud.region_name, dccommon_consts.AVAILABILITY_ONLINE) updated_subcloud = db_api.subcloud_get_by_name(self.ctx, 'subcloud1') @@ -1492,13 +1501,14 @@ class TestSubcloudManager(base.DCManagerTestCase): dccommon_consts.AVAILABILITY_ONLINE) # Verify notifying dcorch self.fake_dcorch_api.update_subcloud_states.assert_called_once_with( - self.ctx, subcloud.name, updated_subcloud.management_state, + self.ctx, subcloud.region_name, updated_subcloud.management_state, dccommon_consts.AVAILABILITY_ONLINE) # Verify triggering audits self.fake_dcmanager_audit_api.trigger_subcloud_audits.\ assert_called_once_with(self.ctx, subcloud.id) - fake_dcmanager_cermon_api.subcloud_online.assert_called_once_with(self.ctx, subcloud.name) + fake_dcmanager_cermon_api.subcloud_online.\ + assert_called_once_with(self.ctx, subcloud.region_name) def test_update_subcloud_availability_go_offline(self): subcloud = self.create_subcloud_static(self.ctx, name='subcloud1') @@ -1520,7 +1530,7 @@ class TestSubcloudManager(base.DCManagerTestCase): db_api.subcloud_status_create( self.ctx, subcloud.id, endpoint) ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=dccommon_consts.SYNC_STATUS_IN_SYNC) @@ -1531,7 +1541,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Audit fails once audit_fail_count = 1 - ssm.update_subcloud_availability(self.ctx, subcloud.name, + ssm.update_subcloud_availability(self.ctx, subcloud.region_name, availability_status=None, audit_fail_count=audit_fail_count) # Verify the subcloud availability was not updated @@ -1546,7 +1556,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Audit fails again audit_fail_count = audit_fail_count + 1 - ssm.update_subcloud_availability(self.ctx, subcloud.name, + ssm.update_subcloud_availability(self.ctx, subcloud.region_name, dccommon_consts.AVAILABILITY_OFFLINE, audit_fail_count=audit_fail_count) @@ -1557,7 +1567,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Verify notifying dcorch self.fake_dcorch_api.update_subcloud_states.assert_called_once_with( - self.ctx, subcloud.name, updated_subcloud.management_state, + self.ctx, subcloud.region_name, updated_subcloud.management_state, dccommon_consts.AVAILABILITY_OFFLINE) # Verify all endpoint statuses set to unknown @@ -1597,7 +1607,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Update identity to the original status ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=original_sync_status) @@ -1607,7 +1617,7 @@ class TestSubcloudManager(base.DCManagerTestCase): # Update identity to new status and get the count of the trigger again ssm.update_subcloud_endpoint_status( - self.ctx, subcloud_name=subcloud.name, + self.ctx, subcloud_region=subcloud.region_name, endpoint_type=endpoint, sync_status=new_sync_status) new_trigger_subcloud_audits = \ @@ -1634,13 +1644,13 @@ class TestSubcloudManager(base.DCManagerTestCase): # Test openstack app installed openstack_installed = True - sm.update_subcloud_sync_endpoint_type(self.ctx, subcloud.name, + sm.update_subcloud_sync_endpoint_type(self.ctx, subcloud.region_name, endpoint_type_list, openstack_installed) # Verify notifying dcorch to add subcloud sync endpoint type self.fake_dcorch_api.add_subcloud_sync_endpoint_type.\ - assert_called_once_with(self.ctx, subcloud.name, + assert_called_once_with(self.ctx, subcloud.region_name, endpoint_type_list) # Verify the subcloud status created for os endpoints @@ -1657,12 +1667,12 @@ class TestSubcloudManager(base.DCManagerTestCase): # Test openstack app removed openstack_installed = False - sm.update_subcloud_sync_endpoint_type(self.ctx, subcloud.name, + sm.update_subcloud_sync_endpoint_type(self.ctx, subcloud.region_name, endpoint_type_list, openstack_installed) # Verify notifying dcorch to remove subcloud sync endpoint type self.fake_dcorch_api.remove_subcloud_sync_endpoint_type.\ - assert_called_once_with(self.ctx, subcloud.name, + assert_called_once_with(self.ctx, subcloud.region_name, endpoint_type_list) # Verify the subcloud status is deleted for os endpoints @@ -1703,8 +1713,11 @@ class TestSubcloudManager(base.DCManagerTestCase): def test_compose_bootstrap_command(self, mock_isfile): mock_isfile.return_value = True sm = subcloud_manager.SubcloudManager() + subcloud_name = base.SUBCLOUD_1['name'] + subcloud_region = base.SUBCLOUD_1['region_name'] bootstrap_command = sm.compose_bootstrap_command( - 'subcloud1', + subcloud_name, + subcloud_region, f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_inventory.yml', FAKE_PREVIOUS_SW_VERSION) self.assertEqual( @@ -1715,8 +1728,9 @@ class TestSubcloudManager(base.DCManagerTestCase): subcloud_manager.ANSIBLE_SUBCLOUD_PLAYBOOK, FAKE_PREVIOUS_SW_VERSION), '-i', f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_inventory.yml', - '--limit', 'subcloud1', '-e', - f"override_files_dir='{dccommon_consts.ANSIBLE_OVERRIDES_PATH}' region_name=subcloud1", + '--limit', '%s' % subcloud_name, '-e', + str("override_files_dir='%s' region_name=%s") % + (dccommon_consts.ANSIBLE_OVERRIDES_PATH, subcloud_region), '-e', "install_release_version=%s" % FAKE_PREVIOUS_SW_VERSION ] ) @@ -1746,8 +1760,12 @@ class TestSubcloudManager(base.DCManagerTestCase): def test_compose_rehome_command(self, mock_isfile): mock_isfile.return_value = True sm = subcloud_manager.SubcloudManager() + subcloud_name = base.SUBCLOUD_1['name'] + subcloud_region = base.SUBCLOUD_1['region_name'] + rehome_command = sm.compose_rehome_command( - 'subcloud1', + subcloud_name, + subcloud_region, f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_inventory.yml', FAKE_PREVIOUS_SW_VERSION) self.assertEqual( @@ -1758,10 +1776,10 @@ class TestSubcloudManager(base.DCManagerTestCase): subcloud_manager.ANSIBLE_SUBCLOUD_REHOME_PLAYBOOK, FAKE_PREVIOUS_SW_VERSION), '-i', f'{dccommon_consts.ANSIBLE_OVERRIDES_PATH}/subcloud1_inventory.yml', - '--limit', 'subcloud1', + '--limit', subcloud_name, '--timeout', subcloud_manager.REHOME_PLAYBOOK_TIMEOUT, - '-e', - f"override_files_dir='{dccommon_consts.ANSIBLE_OVERRIDES_PATH}' region_name=subcloud1" + '-e', str("override_files_dir='%s' region_name=%s") % + (dccommon_consts.ANSIBLE_OVERRIDES_PATH, subcloud_region) ] ) @@ -1823,39 +1841,48 @@ class TestSubcloudManager(base.DCManagerTestCase): def test_handle_subcloud_operations_in_progress(self): subcloud1 = self.create_subcloud_static( self.ctx, - name='subcloud1', + name=base.SUBCLOUD_1['name'], + region_name=base.SUBCLOUD_1['region_name'], deploy_status=consts.DEPLOY_STATE_PRE_DEPLOY) subcloud2 = self.create_subcloud_static( self.ctx, - name='subcloud2', + name=base.SUBCLOUD_2['name'], + region_name=base.SUBCLOUD_2['region_name'], deploy_status=consts.DEPLOY_STATE_PRE_INSTALL) subcloud3 = self.create_subcloud_static( self.ctx, - name='subcloud3', + name=base.SUBCLOUD_3['name'], + region_name=base.SUBCLOUD_3['region_name'], deploy_status=consts.DEPLOY_STATE_INSTALLING) subcloud4 = self.create_subcloud_static( self.ctx, - name='subcloud4', + name=base.SUBCLOUD_4['name'], + region_name=base.SUBCLOUD_4['region_name'], deploy_status=consts.DEPLOY_STATE_BOOTSTRAPPING) subcloud5 = self.create_subcloud_static( self.ctx, - name='subcloud5', + name=base.SUBCLOUD_5['name'], + region_name=base.SUBCLOUD_5['region_name'], deploy_status=consts.DEPLOY_STATE_DEPLOYING) subcloud6 = self.create_subcloud_static( self.ctx, - name='subcloud6', + name=base.SUBCLOUD_6['name'], + region_name=base.SUBCLOUD_6['region_name'], deploy_status=consts.DEPLOY_STATE_MIGRATING_DATA) subcloud7 = self.create_subcloud_static( self.ctx, - name='subcloud7', + name=base.SUBCLOUD_7['name'], + region_name=base.SUBCLOUD_7['region_name'], deploy_status=consts.DEPLOY_STATE_PRE_RESTORE) subcloud8 = self.create_subcloud_static( self.ctx, - name='subcloud8', + name=base.SUBCLOUD_8['name'], + region_name=base.SUBCLOUD_8['region_name'], deploy_status=consts.DEPLOY_STATE_RESTORING) subcloud9 = self.create_subcloud_static( self.ctx, - name='subcloud9', + name=base.SUBCLOUD_9['name'], + region_name=base.SUBCLOUD_9['region_name'], deploy_status=consts.DEPLOY_STATE_NONE) subcloud10 = self.create_subcloud_static( self.ctx, @@ -1940,47 +1967,58 @@ class TestSubcloudManager(base.DCManagerTestCase): def test_handle_completed_subcloud_operations(self): subcloud1 = self.create_subcloud_static( self.ctx, - name='subcloud1', + name=base.SUBCLOUD_1['name'], + region_name=base.SUBCLOUD_1['region_name'], deploy_status=consts.DEPLOY_STATE_CREATE_FAILED) subcloud2 = self.create_subcloud_static( self.ctx, - name='subcloud2', + name=base.SUBCLOUD_2['name'], + region_name=base.SUBCLOUD_2['region_name'], deploy_status=consts.DEPLOY_STATE_PRE_INSTALL_FAILED) subcloud3 = self.create_subcloud_static( self.ctx, - name='subcloud3', + name=base.SUBCLOUD_3['name'], + region_name=base.SUBCLOUD_3['region_name'], deploy_status=consts.DEPLOY_STATE_INSTALL_FAILED) subcloud4 = self.create_subcloud_static( self.ctx, - name='subcloud4', + name=base.SUBCLOUD_4['name'], + region_name=base.SUBCLOUD_4['region_name'], deploy_status=consts.DEPLOY_STATE_INSTALLED) subcloud5 = self.create_subcloud_static( self.ctx, - name='subcloud5', + name=base.SUBCLOUD_5['name'], + region_name=base.SUBCLOUD_5['region_name'], deploy_status=consts.DEPLOY_STATE_BOOTSTRAP_FAILED) subcloud6 = self.create_subcloud_static( self.ctx, - name='subcloud6', + name=base.SUBCLOUD_6['name'], + region_name=base.SUBCLOUD_6['region_name'], deploy_status=consts.DEPLOY_STATE_CONFIG_FAILED) subcloud7 = self.create_subcloud_static( self.ctx, - name='subcloud7', + name=base.SUBCLOUD_7['name'], + region_name=base.SUBCLOUD_7['region_name'], deploy_status=consts.DEPLOY_STATE_DATA_MIGRATION_FAILED) subcloud8 = self.create_subcloud_static( self.ctx, - name='subcloud8', + name=base.SUBCLOUD_8['name'], + region_name=base.SUBCLOUD_8['region_name'], deploy_status=consts.DEPLOY_STATE_MIGRATED) subcloud9 = self.create_subcloud_static( self.ctx, - name='subcloud9', + name=base.SUBCLOUD_9['name'], + region_name=base.SUBCLOUD_9['region_name'], deploy_status=consts.DEPLOY_STATE_RESTORE_PREP_FAILED) subcloud10 = self.create_subcloud_static( self.ctx, - name='subcloud10', + name=base.SUBCLOUD_10['name'], + region_name=base.SUBCLOUD_10['region_name'], deploy_status=consts.DEPLOY_STATE_RESTORE_FAILED) subcloud11 = self.create_subcloud_static( self.ctx, - name='subcloud11', + name=base.SUBCLOUD_11['name'], + region_name=base.SUBCLOUD_11['region_name'], deploy_status=consts.DEPLOY_STATE_DONE) subcloud12 = self.create_subcloud_static( self.ctx, @@ -2792,7 +2830,8 @@ class TestSubcloudManager(base.DCManagerTestCase): values = { 'name': 'TestSubcloud', 'sysadmin_password': '123', - 'secondary': 'true' + 'secondary': 'true', + 'region_name': '2ec93dfb654846909efe61d1b39dd2ce' } # Create an instance of SubcloudManager diff --git a/distributedcloud/dcmanager/tests/unit/orchestrator/states/upgrade/test_pre_check.py b/distributedcloud/dcmanager/tests/unit/orchestrator/states/upgrade/test_pre_check.py index 97aad81ce..c3f68852c 100644 --- a/distributedcloud/dcmanager/tests/unit/orchestrator/states/upgrade/test_pre_check.py +++ b/distributedcloud/dcmanager/tests/unit/orchestrator/states/upgrade/test_pre_check.py @@ -8,6 +8,7 @@ import mock from dccommon import consts as dccommon_consts from dcmanager.common import consts from dcmanager.db.sqlalchemy import api as db_api +from dcmanager.tests import base from dcmanager.tests.unit.common import fake_strategy from dcmanager.tests.unit.common import fake_subcloud from dcmanager.tests.unit.orchestrator.states.fakes import FakeAlarm @@ -496,7 +497,8 @@ class TestSwUpgradePreCheckSimplexStage(TestSwUpgradePreCheckStage): # and no data install values self.subcloud = fake_subcloud.create_fake_subcloud( self.ctx, - name="subcloud2", + name=base.SUBCLOUD_2['name'], + region_name=base.SUBCLOUD_2['region_name'], data_install=None ) @@ -580,7 +582,8 @@ class TestSwUpgradePreCheckSimplexStage(TestSwUpgradePreCheckStage): # availability status as "offline" and no data install values self.subcloud = fake_subcloud.create_fake_subcloud( self.ctx, - name="subcloud2", + name=base.SUBCLOUD_2['name'], + region_name=base.SUBCLOUD_2['region_name'], data_install=None, deploy_status=consts.DEPLOY_STATE_INSTALL_FAILED ) diff --git a/distributedcloud/dcmanager/tests/unit/orchestrator/test_fw_orch_thread.py b/distributedcloud/dcmanager/tests/unit/orchestrator/test_fw_orch_thread.py index 26f546e66..b57feb933 100644 --- a/distributedcloud/dcmanager/tests/unit/orchestrator/test_fw_orch_thread.py +++ b/distributedcloud/dcmanager/tests/unit/orchestrator/test_fw_orch_thread.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 # import mock +from oslo_utils import uuidutils from dccommon import consts as dccommon_consts from dccommon.drivers.openstack import vim @@ -39,6 +40,7 @@ class TestFwOrchThread(TestSwUpdate): "systemcontroller_gateway_ip": "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': uuidutils.generate_uuid().replace("-", ""), 'openstack_installed': False, 'group_id': group_id, 'data_install': 'data from install', diff --git a/distributedcloud/dcmanager/tests/unit/orchestrator/test_sw_update_manager.py b/distributedcloud/dcmanager/tests/unit/orchestrator/test_sw_update_manager.py index 6d71ea06d..ccec7d14f 100644 --- a/distributedcloud/dcmanager/tests/unit/orchestrator/test_sw_update_manager.py +++ b/distributedcloud/dcmanager/tests/unit/orchestrator/test_sw_update_manager.py @@ -17,6 +17,7 @@ import copy import mock from oslo_config import cfg +from oslo_utils import uuidutils from dccommon import consts as dccommon_consts from dcmanager.common import consts @@ -117,6 +118,7 @@ class TestSwUpdateManager(base.DCManagerTestCase): "systemcontroller_gateway_ip": "192.168.204.101", 'deploy_status': "not-deployed", 'error_description': 'No errors present', + 'region_name': uuidutils.generate_uuid().replace("-", ""), 'openstack_installed': False, 'group_id': group_id, 'data_install': 'data from install', diff --git a/distributedcloud/dcmanager/tests/utils.py b/distributedcloud/dcmanager/tests/utils.py index 58e1ccbaa..4bc68da68 100644 --- a/distributedcloud/dcmanager/tests/utils.py +++ b/distributedcloud/dcmanager/tests/utils.py @@ -93,4 +93,5 @@ def create_subcloud_dict(data_list): 'group_id': data_list[23], 'deploy_status': data_list[24], 'error_description': data_list[25], - 'data_install': data_list[26]} + 'region_name': data_list[26], + 'data_install': data_list[27]} diff --git a/distributedcloud/dcorch/db/sqlalchemy/api.py b/distributedcloud/dcorch/db/sqlalchemy/api.py index 4597fb0c2..3e46a3274 100644 --- a/distributedcloud/dcorch/db/sqlalchemy/api.py +++ b/distributedcloud/dcorch/db/sqlalchemy/api.py @@ -377,12 +377,12 @@ def add_identity_filter(query, value, :return: Modified query. """ - if strutils.is_int_like(value): + if use_region_name: + return query.filter_by(region_name=value) + elif strutils.is_int_like(value): return query.filter_by(id=value) elif uuidutils.is_uuid_like(value): return query.filter_by(uuid=value) - elif use_region_name: - return query.filter_by(region_name=value) elif use_resource_type: return query.filter_by(resource_type=value) else: diff --git a/distributedcloud/dcorch/engine/sync_thread.py b/distributedcloud/dcorch/engine/sync_thread.py index 862c68caf..c2c2093e3 100644 --- a/distributedcloud/dcorch/engine/sync_thread.py +++ b/distributedcloud/dcorch/engine/sync_thread.py @@ -87,6 +87,7 @@ class SyncThread(object): self.log_extra = { "instance": self.subcloud_name + ": "} self.dcmanager_state_rpc_client = dcmanager_rpc_client.SubcloudStateClient() + self.dcmanager_rpc_client = dcmanager_rpc_client.ManagerClient() self.sc_admin_session = None self.admin_session = None @@ -298,15 +299,35 @@ class SyncThread(object): self.subcloud_name, sync_status, alarmable), extra=self.log_extra) - self.dcmanager_state_rpc_client.update_subcloud_endpoint_status( - self.ctxt, self.subcloud_name, - self.endpoint_type, sync_status, - alarmable=alarmable) + try: + # This block is required to get the real subcloud name + # dcorch uses the subcloud name as the region name. + # The region name cannot be changed, so at this point it + # is necessary to query the subcloud name as it is required + # for logging purposes. - db_api.subcloud_sync_update( - self.ctxt, self.subcloud_name, self.endpoint_type, - values={'sync_status_reported': sync_status, - 'sync_status_report_time': timeutils.utcnow()}) + # Save current subcloud name (region name from dcorch DB) + dcorch_subcloud_region = self.subcloud_name + + # Get the subcloud name from dcmanager database supplying + # the dcorch region name + subcloud_name = self.dcmanager_rpc_client \ + .get_subcloud_name_by_region_name(self.ctxt, + dcorch_subcloud_region) + + # Updates the endpoint status supplying the subcloud name and + # the region name + self.dcmanager_state_rpc_client.update_subcloud_endpoint_status( + self.ctxt, subcloud_name, dcorch_subcloud_region, + self.endpoint_type, sync_status, + alarmable=alarmable) + + db_api.subcloud_sync_update( + self.ctxt, dcorch_subcloud_region, self.endpoint_type, + values={'sync_status_reported': sync_status, + 'sync_status_report_time': timeutils.utcnow()}) + except Exception: + raise def sync(self, engine_id): LOG.debug("{}: starting sync routine".format(self.subcloud_name), diff --git a/doc/source/conf.py b/doc/source/conf.py index f866d7e17..f54033087 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -60,7 +60,7 @@ openstackdocs_auto_name = False # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files.