Add subcloud redeploy option to dcmanager
This commit adds the command "subcloud redeploy" to dcmanager. The redeploy operation is similar to "subcloud reinstall", performing a fresh install, bootstrapping and configuring the subcloud, but allowing the user to use either previously used install/bootstrap/config values stored on the system controller or new values from provided files. Since config is an optional phase, it will only be executed if respective parameters are provided in the current request or were provided in a previous deployment. Test Plan: Success cases: - PASS: Redeploy subcloud without passing any new files and verify the redeployment was successful and the final deploy state is "complete". - PASS: Redeploy subcloud passing new install/bootstrap/config files and verify the redeployment was successful and the final deploy state is "complete". - PASS: Redeploy a subcloud with a different management subnet and verify that the network reconfiguration was executed during the bootstrap phase and the redeployment completed successfully. - PASS: Redeploy a subcloud that wasn't configure by the "deploy config" command passing a config file and verify that the subcloud was redeploy and configured. - PASS: Redeploy a subcloud that wasn't configure by the "deploy config" command without passing a config file. and verify that the subcloud was redeployed and no configuration attempt was made. - PASS: Redeploy a subcloud passing a previous release (21.12) and verify the redeployment was successful and the final deploy state is "complete". - PASS: Abort each one of the three deployment phases. Verify the deployment was successfully aborted. - PASS: Resume the aborted deployment and verify the subcloud was successfully deployed. - PASS: Repeat previous tests but directly call the API (using CURL) instead of using the CLI. Failure cases: - PASS: Verify it's not possible to redeploy an online and/or managed subcloud. - PASS: Call the API directly, passing bmc-password and/or sysadmin-password as plain text as opposed to b64encoded and verify that the response contains the correct error code and message. Story: 2010756 Task: 48496 Change-Id: I6148096909adda2b95b6bb964bc7a749ac62c20c Signed-off-by: Victor Romano <victor.gluzromano@windriver.com>
This commit is contained in:
parent
8b2855a7d2
commit
528f90afec
|
@ -541,6 +541,78 @@ Response Example
|
|||
.. literalinclude:: samples/subclouds/subcloud-patch-reinstall-response.json
|
||||
:language: json
|
||||
|
||||
********************************
|
||||
Redeploy a specific subcloud
|
||||
********************************
|
||||
|
||||
.. rest_method:: PATCH /v1.0/subclouds/{subcloud}/redeploy
|
||||
|
||||
Redeploy and bootstrap a subcloud based on its previous install configurations.
|
||||
|
||||
**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
|
||||
- install_values: install_values
|
||||
- bootstrap_values: bootstrap_values
|
||||
- deploy_config: deploy_config
|
||||
- release: release
|
||||
- sysadmin_password: sysadmin_password
|
||||
- bmc_password: bmc_password
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
|
||||
.. literalinclude:: samples/subclouds/subcloud-patch-redeploy-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-redeploy-response.json
|
||||
:language: json
|
||||
|
||||
********************************
|
||||
Prestage a specific subcloud
|
||||
********************************
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"bmc_password": "YYYYYYY",
|
||||
"bootstrap_values": "content of bootstrap_values file",
|
||||
"deploy_config": "content of deploy_config file",
|
||||
"install_values": "content of install_values file",
|
||||
"release": "22.12",
|
||||
"sysadmin_password": "XXXXXXX"
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"id": 1,
|
||||
"name": "subcloud1",
|
||||
"created-at": "2021-11-08T18:41:19.530228",
|
||||
"updated-at": "2021-11-15T14:15:59.944851",
|
||||
"availability-status": "offline",
|
||||
"data_install": {
|
||||
"bootstrap_interface": "eno1"
|
||||
},
|
||||
"data_upgrade": null,
|
||||
"deploy-status": "pre-install",
|
||||
"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": "22.12",
|
||||
"systemcontroller-gateway-ip": "192.168.204.101"
|
||||
}
|
|
@ -23,6 +23,7 @@ from requests_toolbelt.multipart import decoder
|
|||
import base64
|
||||
import json
|
||||
import keyring
|
||||
import os
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_messaging import RemoteError
|
||||
|
@ -77,6 +78,12 @@ SUBCLOUD_ADD_GET_FILE_CONTENTS = [
|
|||
INSTALL_VALUES,
|
||||
]
|
||||
|
||||
SUBCLOUD_REDEPLOY_GET_FILE_CONTENTS = [
|
||||
INSTALL_VALUES,
|
||||
BOOTSTRAP_VALUES,
|
||||
consts.DEPLOY_CONFIG
|
||||
]
|
||||
|
||||
BOOTSTRAP_VALUES_ADDRESSES = [
|
||||
'bootstrap-address', 'management_start_address', 'management_end_address',
|
||||
'management_gateway_address', 'systemcontroller_gateway_address',
|
||||
|
@ -761,6 +768,70 @@ class SubcloudsController(object):
|
|||
except Exception:
|
||||
LOG.exception("Unable to reinstall subcloud %s" % subcloud.name)
|
||||
pecan.abort(500, _('Unable to reinstall subcloud'))
|
||||
elif verb == "redeploy":
|
||||
config_file = psd_common.get_config_file_path(subcloud.name,
|
||||
consts.DEPLOY_CONFIG)
|
||||
has_bootstrap_values = consts.BOOTSTRAP_VALUES in request.POST
|
||||
has_original_config_values = os.path.exists(config_file)
|
||||
has_new_config_values = consts.DEPLOY_CONFIG in request.POST
|
||||
has_config_values = has_original_config_values or has_new_config_values
|
||||
payload = psd_common.get_request_data(
|
||||
request, subcloud, SUBCLOUD_REDEPLOY_GET_FILE_CONTENTS)
|
||||
|
||||
if (subcloud.availability_status == dccommon_consts.AVAILABILITY_ONLINE or
|
||||
subcloud.management_state == dccommon_consts.MANAGEMENT_MANAGED):
|
||||
msg = _('Cannot re-deploy an online and/or managed subcloud')
|
||||
LOG.warning(msg)
|
||||
pecan.abort(400, msg)
|
||||
|
||||
# If a subcloud release is not passed, use the current
|
||||
# system controller software_version
|
||||
payload['software_version'] = payload.get('release', tsc.SW_VERSION)
|
||||
|
||||
# Don't load previously stored bootstrap_values if they are present in
|
||||
# the request, as this would override the already loaded values from it.
|
||||
# As config_values are optional, only attempt to load previously stored
|
||||
# values if this phase should be executed.
|
||||
files_for_redeploy = SUBCLOUD_REDEPLOY_GET_FILE_CONTENTS.copy()
|
||||
if has_bootstrap_values:
|
||||
files_for_redeploy.remove(BOOTSTRAP_VALUES)
|
||||
if not has_config_values:
|
||||
files_for_redeploy.remove(consts.DEPLOY_CONFIG)
|
||||
|
||||
psd_common.populate_payload_with_pre_existing_data(
|
||||
payload, subcloud, files_for_redeploy)
|
||||
|
||||
psd_common.validate_sysadmin_password(payload)
|
||||
psd_common.pre_deploy_install(payload, validate_password=False)
|
||||
psd_common.pre_deploy_bootstrap(context, payload, subcloud,
|
||||
has_bootstrap_values,
|
||||
validate_password=False)
|
||||
payload['bootstrap-address'] = \
|
||||
payload['install_values']['bootstrap_address']
|
||||
|
||||
try:
|
||||
# Align the software version of the subcloud with redeploy
|
||||
# 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'),
|
||||
location=payload.get('location'),
|
||||
software_version=payload['software_version'],
|
||||
deploy_status=consts.DEPLOY_STATE_PRE_INSTALL,
|
||||
first_identity_sync_complete=False,
|
||||
data_install=json.dumps(payload['install_values']))
|
||||
|
||||
self.dcmanager_rpc_client.redeploy_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 redeploy subcloud %s" % subcloud.name)
|
||||
pecan.abort(500, _('Unable to redeploy subcloud'))
|
||||
elif verb == "restore":
|
||||
pecan.abort(410, _('This API is deprecated. '
|
||||
'Please use /v1.0/subcloud-backup/restore'))
|
||||
|
|
|
@ -73,6 +73,10 @@ subclouds_rules = [
|
|||
'method': 'PATCH',
|
||||
'path': '/v1.0/subclouds/{subcloud}/reinstall'
|
||||
},
|
||||
{
|
||||
'method': 'PATCH',
|
||||
'path': '/v1.0/subclouds/{subcloud}/redeploy'
|
||||
},
|
||||
{
|
||||
'method': 'PATCH',
|
||||
'path': '/v1.0/subclouds/{subcloud}/restore'
|
||||
|
|
|
@ -491,9 +491,9 @@ def validate_install_values(payload, subcloud=None):
|
|||
if software_version and software_version != install_software_version:
|
||||
pecan.abort(400,
|
||||
_("The software_version value %s in the install values "
|
||||
"yaml file does not match with the specified/current "
|
||||
"software version of %s. Please correct or remove "
|
||||
"this parameter from the yaml file and try again.") %
|
||||
"yaml file does not match with the specified/current "
|
||||
"software version of %s. Please correct or remove "
|
||||
"this parameter from the yaml file and try again.") %
|
||||
(install_software_version, software_version))
|
||||
else:
|
||||
# Only install_values payload will be passed to the subcloud
|
||||
|
@ -959,7 +959,7 @@ def pre_deploy_install(payload: dict, validate_password=False):
|
|||
# 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.
|
||||
# will be installed using the image in dc_vault.
|
||||
if install_values.get(
|
||||
'software_version') != payload['software_version']:
|
||||
install_values['software_version'] = payload['software_version']
|
||||
|
|
|
@ -133,7 +133,8 @@ def validate_network_str(network_str, minimum_size, existing_networks=None,
|
|||
"least %d addresses" % minimum_size)
|
||||
elif network.version == 6 and network.prefixlen < 64:
|
||||
raise exceptions.ValidateFail("IPv6 minimum prefix length is 64")
|
||||
elif existing_networks and operation != 'reinstall':
|
||||
elif existing_networks and (operation != 'reinstall'
|
||||
and operation != 'redeploy'):
|
||||
if any(network.ip in subnet for subnet in existing_networks):
|
||||
raise exceptions.ValidateFail("Subnet overlaps with another "
|
||||
"configured subnet")
|
||||
|
@ -943,12 +944,14 @@ def has_network_reconfig(payload, subcloud):
|
|||
start_address = get_management_start_address(payload)
|
||||
end_address = get_management_end_address(payload)
|
||||
gateway_address = get_management_gateway_address(payload)
|
||||
sys_controller_gw_ip = payload.get("systemcontroller_gateway_address")
|
||||
|
||||
has_network_reconfig = any([
|
||||
management_subnet != subcloud.management_subnet,
|
||||
start_address != subcloud.management_start_ip,
|
||||
end_address != subcloud.management_end_ip,
|
||||
gateway_address != subcloud.management_gateway_ip
|
||||
gateway_address != subcloud.management_gateway_ip,
|
||||
sys_controller_gw_ip != subcloud.systemcontroller_gateway_ip
|
||||
])
|
||||
|
||||
return has_network_reconfig
|
||||
|
|
|
@ -144,11 +144,19 @@ class DCManagerService(service.Service):
|
|||
@request_context
|
||||
def reinstall_subcloud(self, context, subcloud_id, payload):
|
||||
# Reinstall a subcloud
|
||||
LOG.info("Handling reinstall_subcloud request for: %s" % subcloud_id)
|
||||
LOG.info("Handling reinstall_subcloud request for: %s" % payload.get('name'))
|
||||
return self.subcloud_manager.reinstall_subcloud(context,
|
||||
subcloud_id,
|
||||
payload)
|
||||
|
||||
@request_context
|
||||
def redeploy_subcloud(self, context, subcloud_id, payload):
|
||||
# Redeploy a subcloud
|
||||
LOG.info("Handling redeploy_subcloud request for: %s" % subcloud_id)
|
||||
return self.subcloud_manager.redeploy_subcloud(context,
|
||||
subcloud_id,
|
||||
payload)
|
||||
|
||||
@request_context
|
||||
def backup_subclouds(self, context, payload):
|
||||
# Backup a subcloud or group of subclouds
|
||||
|
|
|
@ -508,6 +508,35 @@ class SubcloudManager(manager.Manager):
|
|||
context, subcloud_id,
|
||||
deploy_status=consts.DEPLOY_STATE_PRE_INSTALL_FAILED)
|
||||
|
||||
def redeploy_subcloud(self, context, subcloud_id, payload):
|
||||
"""Redeploy subcloud
|
||||
|
||||
:param context: request context object
|
||||
:param subcloud_id: subcloud id from db
|
||||
:param payload: subcloud redeploy
|
||||
"""
|
||||
|
||||
# Retrieve the subcloud details from the database
|
||||
subcloud = db_api.subcloud_get(context, subcloud_id)
|
||||
|
||||
LOG.info("Redeploying subcloud %s." % subcloud.name)
|
||||
|
||||
# Define which deploy phases to run
|
||||
phases_to_run = [consts.DEPLOY_PHASE_INSTALL,
|
||||
consts.DEPLOY_PHASE_BOOTSTRAP]
|
||||
if consts.DEPLOY_CONFIG in payload:
|
||||
phases_to_run.append(consts.DEPLOY_PHASE_CONFIG)
|
||||
|
||||
succeeded = self.run_deploy_phases(context, subcloud_id, payload,
|
||||
phases_to_run)
|
||||
|
||||
if succeeded:
|
||||
db_api.subcloud_update(
|
||||
context, subcloud.id,
|
||||
deploy_status=consts.DEPLOY_STATE_DONE,
|
||||
error_description=consts.ERROR_DESC_EMPTY)
|
||||
LOG.info(f"Finished redeploying subcloud {subcloud['name']}.")
|
||||
|
||||
def create_subcloud_backups(self, context, payload):
|
||||
"""Backup subcloud or group of subclouds
|
||||
|
||||
|
@ -637,29 +666,18 @@ class SubcloudManager(manager.Manager):
|
|||
:param ansible_subcloud_inventory_file: the ansible inventory file path
|
||||
:return: ansible command needed to run the bootstrap playbook
|
||||
"""
|
||||
management_subnet = utils.get_management_subnet(payload)
|
||||
sys_controller_gw_ip = payload.get(
|
||||
"systemcontroller_gateway_address")
|
||||
|
||||
if (management_subnet != subcloud.management_subnet) or (
|
||||
sys_controller_gw_ip != subcloud.systemcontroller_gateway_ip):
|
||||
m_ks_client = OpenStackDriver(
|
||||
region_name=dccommon_consts.DEFAULT_REGION_NAME,
|
||||
region_clients=None).keystone_client
|
||||
# Create a new route
|
||||
self._create_subcloud_route(payload, m_ks_client,
|
||||
sys_controller_gw_ip)
|
||||
# Delete previous route
|
||||
self._delete_subcloud_routes(m_ks_client, subcloud)
|
||||
# Update endpoints
|
||||
self._update_services_endpoint(context, payload, subcloud.name,
|
||||
m_ks_client)
|
||||
network_reconfig = utils.has_network_reconfig(payload, subcloud)
|
||||
if network_reconfig:
|
||||
self._configure_system_controller_network(context, payload, subcloud,
|
||||
update_db=False)
|
||||
# Regenerate the addn_hosts_dc file
|
||||
self._create_addn_hosts_dc(context)
|
||||
|
||||
# Update subcloud
|
||||
subcloud = db_api.subcloud_update(
|
||||
context,
|
||||
subcloud.id,
|
||||
description=payload.get("description", None),
|
||||
description=payload.get("description"),
|
||||
management_subnet=utils.get_management_subnet(payload),
|
||||
management_gateway_ip=utils.get_management_gateway_address(
|
||||
payload),
|
||||
|
@ -667,8 +685,8 @@ class SubcloudManager(manager.Manager):
|
|||
payload),
|
||||
management_end_ip=utils.get_management_end_address(payload),
|
||||
systemcontroller_gateway_ip=payload.get(
|
||||
"systemcontroller_gateway_address", None),
|
||||
location=payload.get("location", None),
|
||||
"systemcontroller_gateway_address"),
|
||||
location=payload.get("location"),
|
||||
deploy_status=consts.DEPLOY_STATE_PRE_BOOTSTRAP)
|
||||
|
||||
# Populate payload with passwords
|
||||
|
@ -959,8 +977,7 @@ class SubcloudManager(manager.Manager):
|
|||
deploy_status=deploy_state)
|
||||
|
||||
# The RPC call must return the subcloud as a dictionary, otherwise it
|
||||
# should return the DB object for dcmanager internal use (subcloud add,
|
||||
# resume and redeploy)
|
||||
# should return the DB object for dcmanager internal use (subcloud add)
|
||||
if return_as_dict:
|
||||
subcloud = db_api.subcloud_db_model_to_dict(subcloud)
|
||||
|
||||
|
@ -2308,35 +2325,47 @@ class SubcloudManager(manager.Manager):
|
|||
# Regenerate the addn_hosts_dc file
|
||||
self._create_addn_hosts_dc(context)
|
||||
|
||||
def _configure_system_controller_network(self, context, payload, subcloud):
|
||||
def _configure_system_controller_network(self, context, payload, subcloud,
|
||||
update_db=True):
|
||||
"""Configure system controller network
|
||||
|
||||
:param context: request context object
|
||||
:param payload: subcloud bootstrap configuration
|
||||
:param subcloud: subcloud model object
|
||||
:param update_db: whether it should update the db on success/failure
|
||||
"""
|
||||
subcloud_name = subcloud.name
|
||||
subcloud_id = subcloud.id
|
||||
sys_controller_gw_ip = payload.get("systemcontroller_gateway_address",
|
||||
subcloud.systemcontroller_gateway_ip)
|
||||
|
||||
try:
|
||||
m_ks_client = OpenStackDriver(
|
||||
region_name=dccommon_consts.DEFAULT_REGION_NAME,
|
||||
region_clients=None).keystone_client
|
||||
self._create_subcloud_route(payload, m_ks_client,
|
||||
subcloud.systemcontroller_gateway_ip)
|
||||
sys_controller_gw_ip)
|
||||
except Exception:
|
||||
LOG.exception(
|
||||
"Failed to create route to subcloud %s." % subcloud_name)
|
||||
db_api.subcloud_update(
|
||||
context, subcloud_id,
|
||||
deploy_status=consts.DEPLOY_STATE_RECONFIGURING_NETWORK_FAILED,
|
||||
error_description=consts.ERROR_DESC_EMPTY
|
||||
)
|
||||
if update_db:
|
||||
db_api.subcloud_update(
|
||||
context, subcloud_id,
|
||||
deploy_status=consts.DEPLOY_STATE_RECONFIGURING_NETWORK_FAILED,
|
||||
error_description=consts.ERROR_DESC_EMPTY
|
||||
)
|
||||
return
|
||||
try:
|
||||
self._update_services_endpoint(
|
||||
context, payload, subcloud_name, m_ks_client)
|
||||
except Exception:
|
||||
LOG.exception("Failed to update subcloud %s endpoints" % subcloud_name)
|
||||
db_api.subcloud_update(
|
||||
context, subcloud_id,
|
||||
deploy_status=consts.DEPLOY_STATE_RECONFIGURING_NETWORK_FAILED,
|
||||
error_description=consts.ERROR_DESC_EMPTY
|
||||
)
|
||||
if update_db:
|
||||
db_api.subcloud_update(
|
||||
context, subcloud_id,
|
||||
deploy_status=consts.DEPLOY_STATE_RECONFIGURING_NETWORK_FAILED,
|
||||
error_description=consts.ERROR_DESC_EMPTY
|
||||
)
|
||||
return
|
||||
|
||||
# Delete old routes
|
||||
|
|
|
@ -160,6 +160,11 @@ class ManagerClient(RPCClient):
|
|||
subcloud_id=subcloud_id,
|
||||
payload=payload))
|
||||
|
||||
def redeploy_subcloud(self, ctxt, subcloud_id, payload):
|
||||
return self.cast(ctxt, self.make_msg('redeploy_subcloud',
|
||||
subcloud_id=subcloud_id,
|
||||
payload=payload))
|
||||
|
||||
def backup_subclouds(self, ctxt, payload):
|
||||
return self.cast(ctxt, self.make_msg('backup_subclouds',
|
||||
payload=payload))
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
# under the License.
|
||||
#
|
||||
|
||||
from oslo_utils import timeutils
|
||||
|
||||
import base64
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
|
||||
import keyring
|
||||
import mock
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
from six.moves import http_client
|
||||
from tsconfig.tsconfig import SW_VERSION
|
||||
import webtest
|
||||
|
||||
from dccommon import consts as dccommon_consts
|
||||
|
@ -34,15 +36,12 @@ from dcmanager.common import prestage
|
|||
from dcmanager.common import utils as cutils
|
||||
from dcmanager.db.sqlalchemy import api as db_api
|
||||
from dcmanager.rpc import client as rpc_client
|
||||
|
||||
from dcmanager.tests.unit.api import test_root_controller as testroot
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import APIMixin
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import PostMixin
|
||||
from dcmanager.tests.unit.common import fake_subcloud
|
||||
from dcmanager.tests import utils
|
||||
|
||||
from tsconfig.tsconfig import SW_VERSION
|
||||
|
||||
SAMPLE_SUBCLOUD_NAME = 'SubcloudX'
|
||||
SAMPLE_SUBCLOUD_DESCRIPTION = 'A Subcloud of mystery'
|
||||
|
||||
|
@ -1791,6 +1790,355 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest):
|
|||
headers=FAKE_HEADERS, params=reinstall_data)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
|
||||
@mock.patch.object(psd_common, 'upload_config_file')
|
||||
@mock.patch.object(psd_common.PatchingClient, 'query')
|
||||
@mock.patch.object(os.path, 'isdir')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
@mock.patch.object(cutils, 'get_vault_load_files')
|
||||
@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_redeploy_subcloud(
|
||||
self, mock_validate_bootstrap_values, mock_validate_subcloud_config,
|
||||
mock_validate_k8s_version, mock_get_vault_load_files,
|
||||
mock_os_listdir, mock_os_isdir, mock_query, mock_upload_config_file):
|
||||
|
||||
fake_bmc_password = base64.b64encode(
|
||||
'bmc_password'.encode("utf-8")).decode('utf-8')
|
||||
fake_sysadmin_password = base64.b64encode(
|
||||
'sysadmin_password'.encode("utf-8")).decode('utf-8')
|
||||
|
||||
install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
install_data.pop('software_version')
|
||||
bootstrap_data = copy.copy(fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA)
|
||||
config_data = {'deploy_config': 'deploy config values'}
|
||||
redeploy_data = {**install_data, **bootstrap_data, **config_data,
|
||||
'sysadmin_password': fake_sysadmin_password,
|
||||
'bmc_password': fake_bmc_password}
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=bootstrap_data["name"])
|
||||
|
||||
mock_query.return_value = {}
|
||||
mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path')
|
||||
mock_os_isdir.return_value = True
|
||||
mock_upload_config_file.return_value = True
|
||||
mock_os_listdir.return_value = ['deploy_chart_fake.tgz',
|
||||
'deploy_overrides_fake.yaml',
|
||||
'deploy_playbook_fake.yaml']
|
||||
|
||||
upload_files = [("install_values", "install_fake_filename",
|
||||
json.dumps(install_data).encode("utf-8")),
|
||||
("bootstrap_values", "bootstrap_fake_filename",
|
||||
json.dumps(bootstrap_data).encode("utf-8")),
|
||||
("deploy_config", "config_fake_filename",
|
||||
json.dumps(config_data).encode("utf-8"))]
|
||||
|
||||
response = self.app.patch(
|
||||
FAKE_URL + '/' + str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params=redeploy_data,
|
||||
upload_files=upload_files)
|
||||
|
||||
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().redeploy_subcloud.assert_called_once_with(
|
||||
mock.ANY,
|
||||
subcloud.id,
|
||||
mock.ANY)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual(SW_VERSION, response.json['software-version'])
|
||||
|
||||
@mock.patch.object(cutils, 'load_yaml_file')
|
||||
@mock.patch.object(psd_common.PatchingClient, 'query')
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
@mock.patch.object(os.path, 'isdir')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
@mock.patch.object(cutils, 'get_vault_load_files')
|
||||
@mock.patch.object(psd_common, 'validate_k8s_version')
|
||||
def test_redeploy_subcloud_no_request_data(
|
||||
self, mock_validate_k8s_version, mock_get_vault_load_files,
|
||||
mock_os_listdir, mock_os_isdir, mock_path_exists, mock_query,
|
||||
mock_load_yaml):
|
||||
|
||||
fake_bmc_password = base64.b64encode(
|
||||
'bmc_password'.encode("utf-8")).decode('utf-8')
|
||||
fake_sysadmin_password = base64.b64encode(
|
||||
'sysadmin_password'.encode("utf-8")).decode('utf-8')
|
||||
|
||||
install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
install_data.pop('software_version')
|
||||
install_data['bmc_password'] = fake_bmc_password
|
||||
redeploy_data = {'sysadmin_password': fake_sysadmin_password}
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA["name"],
|
||||
data_install=json.dumps(install_data))
|
||||
|
||||
config_file = psd_common.get_config_file_path(subcloud.name,
|
||||
consts.DEPLOY_CONFIG)
|
||||
mock_query.return_value = {}
|
||||
mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path')
|
||||
mock_os_isdir.return_value = True
|
||||
mock_os_listdir.return_value = ['deploy_chart_fake.tgz',
|
||||
'deploy_overrides_fake.yaml',
|
||||
'deploy_playbook_fake.yaml']
|
||||
mock_path_exists.side_effect = lambda x: True if x == config_file else False
|
||||
mock_load_yaml.return_value = {"software_version": SW_VERSION}
|
||||
|
||||
response = self.app.patch(
|
||||
FAKE_URL + '/' + str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params=redeploy_data)
|
||||
|
||||
mock_validate_k8s_version.assert_called_once()
|
||||
self.mock_rpc_client().redeploy_subcloud.assert_called_once_with(
|
||||
mock.ANY,
|
||||
subcloud.id,
|
||||
mock.ANY)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual(SW_VERSION, response.json['software-version'])
|
||||
|
||||
@mock.patch.object(psd_common, 'upload_config_file')
|
||||
@mock.patch.object(psd_common.PatchingClient, 'query')
|
||||
@mock.patch.object(os.path, 'isdir')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
@mock.patch.object(cutils, 'get_vault_load_files')
|
||||
@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_redeploy_subcloud_with_release_version(
|
||||
self, mock_validate_bootstrap_values, mock_validate_subcloud_config,
|
||||
mock_validate_k8s_version, mock_get_vault_load_files,
|
||||
mock_os_listdir, mock_os_isdir, mock_query, mock_upload_config_file):
|
||||
|
||||
fake_bmc_password = base64.b64encode(
|
||||
'bmc_password'.encode("utf-8")).decode('utf-8')
|
||||
fake_sysadmin_password = base64.b64encode(
|
||||
'sysadmin_password'.encode("utf-8")).decode('utf-8')
|
||||
|
||||
install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
install_data.pop('software_version')
|
||||
bootstrap_data = copy.copy(fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA)
|
||||
config_data = {'deploy_config': 'deploy config values'}
|
||||
redeploy_data = {**install_data, **bootstrap_data, **config_data,
|
||||
'sysadmin_password': fake_sysadmin_password,
|
||||
'bmc_password': fake_bmc_password,
|
||||
'release': fake_subcloud.FAKE_SOFTWARE_VERSION}
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=bootstrap_data["name"],
|
||||
software_version=SW_VERSION)
|
||||
|
||||
mock_query.return_value = {}
|
||||
mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path')
|
||||
mock_os_isdir.return_value = True
|
||||
mock_upload_config_file.return_value = True
|
||||
mock_os_listdir.return_value = ['deploy_chart_fake.tgz',
|
||||
'deploy_overrides_fake.yaml',
|
||||
'deploy_playbook_fake.yaml']
|
||||
|
||||
upload_files = [("install_values", "install_fake_filename",
|
||||
json.dumps(install_data).encode("utf-8")),
|
||||
("bootstrap_values", "bootstrap_fake_filename",
|
||||
json.dumps(bootstrap_data).encode("utf-8")),
|
||||
("deploy_config", "config_fake_filename",
|
||||
json.dumps(config_data).encode("utf-8"))]
|
||||
|
||||
response = self.app.patch(
|
||||
FAKE_URL + '/' + str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params=redeploy_data,
|
||||
upload_files=upload_files)
|
||||
|
||||
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().redeploy_subcloud.assert_called_once_with(
|
||||
mock.ANY,
|
||||
subcloud.id,
|
||||
mock.ANY)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual(fake_subcloud.FAKE_SOFTWARE_VERSION,
|
||||
response.json['software-version'])
|
||||
|
||||
@mock.patch.object(cutils, 'load_yaml_file')
|
||||
@mock.patch.object(psd_common.PatchingClient, 'query')
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
@mock.patch.object(os.path, 'isdir')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
@mock.patch.object(cutils, 'get_vault_load_files')
|
||||
def test_redeploy_subcloud_no_request_body(
|
||||
self, mock_get_vault_load_files, mock_os_listdir,
|
||||
mock_os_isdir, mock_path_exists, mock_query, mock_load_yaml):
|
||||
|
||||
fake_bmc_password = base64.b64encode(
|
||||
'bmc_password'.encode("utf-8")).decode('utf-8')
|
||||
|
||||
install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
install_data.pop('software_version')
|
||||
install_data['bmc_password'] = fake_bmc_password
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA["name"],
|
||||
data_install=json.dumps(install_data))
|
||||
|
||||
config_file = psd_common.get_config_file_path(subcloud.name,
|
||||
consts.DEPLOY_CONFIG)
|
||||
mock_query.return_value = {}
|
||||
mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path')
|
||||
mock_os_isdir.return_value = True
|
||||
mock_os_listdir.return_value = ['deploy_chart_fake.tgz',
|
||||
'deploy_overrides_fake.yaml',
|
||||
'deploy_playbook_fake.yaml']
|
||||
mock_path_exists.side_effect = lambda x: True if x == config_file else False
|
||||
mock_load_yaml.return_value = {"software_version": SW_VERSION}
|
||||
|
||||
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||
self.app.patch_json, FAKE_URL + '/' +
|
||||
str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params={})
|
||||
|
||||
def test_redeploy_online_subcloud(self):
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA["name"])
|
||||
db_api.subcloud_update(self.ctx, subcloud.id,
|
||||
availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
||||
|
||||
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||
self.app.patch_json, FAKE_URL + '/' +
|
||||
str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params={})
|
||||
self.mock_rpc_client().redeploy_subcloud.assert_not_called()
|
||||
|
||||
def test_redeploy_managed_subcloud(self):
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA["name"])
|
||||
db_api.subcloud_update(self.ctx, subcloud.id,
|
||||
management_state=dccommon_consts.MANAGEMENT_MANAGED)
|
||||
|
||||
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||
self.app.patch_json, FAKE_URL + '/' +
|
||||
str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params={})
|
||||
self.mock_rpc_client().redeploy_subcloud.assert_not_called()
|
||||
|
||||
@mock.patch.object(cutils, 'load_yaml_file')
|
||||
@mock.patch.object(psd_common.PatchingClient, 'query')
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
@mock.patch.object(os.path, 'isdir')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
@mock.patch.object(cutils, 'get_vault_load_files')
|
||||
@mock.patch.object(psd_common, 'validate_k8s_version')
|
||||
def test_redeploy_subcloud_missing_required_value(
|
||||
self, mock_validate_k8s_version, mock_get_vault_load_files,
|
||||
mock_os_listdir, mock_os_isdir, mock_path_exists, mock_query,
|
||||
mock_load_yaml):
|
||||
|
||||
fake_bmc_password = base64.b64encode(
|
||||
'bmc_password'.encode("utf-8")).decode('utf-8')
|
||||
fake_sysadmin_password = base64.b64encode(
|
||||
'sysadmin_password'.encode("utf-8")).decode('utf-8')
|
||||
|
||||
install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
install_data.pop('software_version')
|
||||
install_data['bmc_password'] = fake_bmc_password
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA["name"],
|
||||
data_install=json.dumps(install_data))
|
||||
|
||||
config_file = psd_common.get_config_file_path(subcloud.name,
|
||||
consts.DEPLOY_CONFIG)
|
||||
mock_query.return_value = {}
|
||||
mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path')
|
||||
mock_os_isdir.return_value = True
|
||||
mock_os_listdir.return_value = ['deploy_chart_fake.tgz',
|
||||
'deploy_overrides_fake.yaml',
|
||||
'deploy_playbook_fake.yaml']
|
||||
mock_path_exists.side_effect = lambda x: True if x == config_file else False
|
||||
mock_load_yaml.return_value = {"software_version": SW_VERSION}
|
||||
|
||||
for k in ['name', 'system_mode', 'external_oam_subnet',
|
||||
'external_oam_gateway_address', 'external_oam_floating_address',
|
||||
'sysadmin_password']:
|
||||
bootstrap_values = copy.copy(fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA)
|
||||
redeploy_data = {**bootstrap_values,
|
||||
'sysadmin_password': fake_sysadmin_password}
|
||||
del redeploy_data[k]
|
||||
upload_files = [("bootstrap_values", "bootstrap_fake_filename",
|
||||
json.dumps(redeploy_data).encode("utf-8"))]
|
||||
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||
self.app.patch_json, FAKE_URL + '/' +
|
||||
str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params=redeploy_data,
|
||||
upload_files=upload_files)
|
||||
|
||||
@mock.patch.object(psd_common, 'upload_config_file')
|
||||
@mock.patch.object(psd_common.PatchingClient, 'query')
|
||||
@mock.patch.object(os.path, 'isdir')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
@mock.patch.object(cutils, 'get_vault_load_files')
|
||||
@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_redeploy_subcloud_missing_stored_values(
|
||||
self, mock_validate_bootstrap_values, mock_validate_subcloud_config,
|
||||
mock_validate_k8s_version, mock_get_vault_load_files,
|
||||
mock_os_listdir, mock_os_isdir, mock_query, mock_upload_config_values):
|
||||
|
||||
fake_bmc_password = base64.b64encode(
|
||||
'bmc_password'.encode("utf-8")).decode('utf-8')
|
||||
fake_sysadmin_password = base64.b64encode(
|
||||
'sysadmin_password'.encode("utf-8")).decode('utf-8')
|
||||
|
||||
install_data = copy.copy(FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
install_data.pop('software_version')
|
||||
bootstrap_data = copy.copy(fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA)
|
||||
config_data = {'deploy_config': 'deploy config values'}
|
||||
|
||||
for k in ['management_subnet', 'management_start_address',
|
||||
'management_end_address', 'management_gateway_address',
|
||||
'systemcontroller_gateway_address']:
|
||||
del bootstrap_data[k]
|
||||
|
||||
redeploy_data = {**install_data, **bootstrap_data, **config_data,
|
||||
'sysadmin_password': fake_sysadmin_password,
|
||||
'bmc_password': fake_bmc_password}
|
||||
|
||||
subcloud = fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, name=bootstrap_data["name"])
|
||||
|
||||
mock_query.return_value = {}
|
||||
mock_get_vault_load_files.return_value = ('iso_file_path', 'sig_file_path')
|
||||
mock_os_isdir.return_value = True
|
||||
mock_upload_config_values.return_value = True
|
||||
mock_os_listdir.return_value = ['deploy_chart_fake.tgz',
|
||||
'deploy_overrides_fake.yaml',
|
||||
'deploy_playbook_fake.yaml']
|
||||
|
||||
upload_files = [("install_values", "install_fake_filename",
|
||||
json.dumps(install_data).encode("utf-8")),
|
||||
("bootstrap_values", "bootstrap_fake_filename",
|
||||
json.dumps(bootstrap_data).encode("utf-8")),
|
||||
("deploy_config", "config_fake_filename",
|
||||
json.dumps(config_data).encode("utf-8"))]
|
||||
|
||||
response = self.app.patch(
|
||||
FAKE_URL + '/' + str(subcloud.id) + '/redeploy',
|
||||
headers=FAKE_HEADERS, params=redeploy_data,
|
||||
upload_files=upload_files)
|
||||
|
||||
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().redeploy_subcloud.assert_called_once_with(
|
||||
mock.ANY,
|
||||
subcloud.id,
|
||||
mock.ANY)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual(SW_VERSION, response.json['software-version'])
|
||||
|
||||
@mock.patch.object(prestage, '_get_system_controller_upgrades')
|
||||
@mock.patch.object(prestage, '_get_prestage_subcloud_info')
|
||||
@mock.patch.object(subclouds.SubcloudsController, '_get_prestage_payload')
|
||||
|
|
|
@ -417,8 +417,8 @@ class TestSubcloudManager(base.DCManagerTestCase):
|
|||
'software_version': "18.03",
|
||||
"management_subnet": "192.168.101.0/24",
|
||||
"management_gateway_ip": "192.168.101.1",
|
||||
"management_start_ip": "192.168.101.3",
|
||||
"management_end_ip": "192.168.101.4",
|
||||
"management_start_ip": "192.168.101.2",
|
||||
"management_end_ip": "192.168.101.50",
|
||||
"systemcontroller_gateway_ip": "192.168.204.101",
|
||||
'deploy_status': "not-deployed",
|
||||
'error_description': "No errors present",
|
||||
|
@ -1826,6 +1826,61 @@ class TestSubcloudManager(base.DCManagerTestCase):
|
|||
FAKE_PREVIOUS_SW_VERSION)
|
||||
mock_thread_start.assert_called_once()
|
||||
|
||||
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||
'_run_subcloud_install')
|
||||
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||
'_prepare_for_deployment')
|
||||
@mock.patch.object(cutils, 'create_subcloud_inventory')
|
||||
@mock.patch.object(subcloud_manager, 'keyring')
|
||||
@mock.patch.object(cutils, 'get_playbook_for_software_version')
|
||||
@mock.patch.object(cutils, 'update_values_on_yaml_file')
|
||||
@mock.patch.object(RunAnsible, 'exec_playbook')
|
||||
def test_subcloud_redeploy(self, mock_exec_playbook, mock_update_yml,
|
||||
mock_get_playbook_for_software_version,
|
||||
mock_keyring, create_subcloud_inventory,
|
||||
mock_prepare_for_deployment,
|
||||
mock_run_subcloud_install):
|
||||
mock_get_playbook_for_software_version.return_value = "22.12"
|
||||
mock_keyring.get_password.return_value = "testpass"
|
||||
mock_exec_playbook.return_value = False
|
||||
mock_run_subcloud_install.return_value = True
|
||||
|
||||
subcloud = self.create_subcloud_static(
|
||||
self.ctx,
|
||||
name='subcloud1',
|
||||
deploy_status=consts.DEPLOY_STATE_CREATED)
|
||||
|
||||
fake_install_values = \
|
||||
copy.copy(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES)
|
||||
fake_install_values['software_version'] = SW_VERSION
|
||||
fake_payload_install = {'bmc_password': 'bmc_pass',
|
||||
'install_values': fake_install_values,
|
||||
'software_version': SW_VERSION,
|
||||
'sysadmin_password': 'sys_pass'}
|
||||
|
||||
fake_payload_bootstrap = {**fake_subcloud.FAKE_BOOTSTRAP_VALUE,
|
||||
**fake_subcloud.FAKE_BOOTSTRAP_FILE_DATA}
|
||||
fake_payload_bootstrap["sysadmin_password"] = "testpass"
|
||||
|
||||
fake_payload_config = {"sysadmin_password": "testpass",
|
||||
"deploy_playbook": "test_playbook.yaml",
|
||||
"deploy_overrides": "test_overrides.yaml",
|
||||
"deploy_chart": "test_chart.yaml",
|
||||
"deploy_config": "subcloud1.yaml"}
|
||||
|
||||
fake_payload = {**fake_payload_install,
|
||||
**fake_payload_bootstrap,
|
||||
**fake_payload_config}
|
||||
|
||||
sm = subcloud_manager.SubcloudManager()
|
||||
sm.redeploy_subcloud(self.ctx, subcloud.id, fake_payload)
|
||||
|
||||
# Verify subcloud was updated with correct values
|
||||
updated_subcloud = db_api.subcloud_get_by_name(self.ctx,
|
||||
subcloud.name)
|
||||
self.assertEqual(consts.DEPLOY_STATE_DONE,
|
||||
updated_subcloud.deploy_status)
|
||||
|
||||
def test_handle_subcloud_operations_in_progress(self):
|
||||
subcloud1 = self.create_subcloud_static(
|
||||
self.ctx,
|
||||
|
|
|
@ -30,7 +30,8 @@ class TestUtils(base.DCManagerTestCase):
|
|||
payload = {"management_subnet": "192.168.101.0/24",
|
||||
"management_gateway_address": "192.168.101.1",
|
||||
"management_start_address": "192.168.101.2",
|
||||
"management_end_address": "192.168.101.50"}
|
||||
"management_end_address": "192.168.101.50",
|
||||
"systemcontroller_gateway_address": "192.168.204.101"}
|
||||
result = utils.has_network_reconfig(payload, subcloud)
|
||||
self.assertFalse(result)
|
||||
|
||||
|
@ -51,3 +52,13 @@ class TestUtils(base.DCManagerTestCase):
|
|||
"management_end_address": "192.168.101.50"}
|
||||
result = utils.has_network_reconfig(payload, subcloud)
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_has_network_reconfig_different_sc_gateway(self):
|
||||
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
||||
payload = {"management_subnet": "192.168.101.0/24",
|
||||
"management_gateway_address": "192.168.101.1",
|
||||
"management_start_address": "192.168.101.2",
|
||||
"management_end_address": "192.168.101.50",
|
||||
"systemcontroller_gateway_address": "192.168.204.102"}
|
||||
result = utils.has_network_reconfig(payload, subcloud)
|
||||
self.assertTrue(result)
|
||||
|
|
Loading…
Reference in New Issue