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