Merge "Prestaging support for --for-sw-deploy/--for-install"

This commit is contained in:
Zuul 2024-06-21 23:03:00 +00:00 committed by Gerrit Code Review
commit 9f90f52cfd
13 changed files with 286 additions and 53 deletions

View File

@ -216,3 +216,6 @@ ANSIBLE_SUBCLOUD_ENROLL_PLAYBOOK = \
# Sysinv client default timeout
SYSINV_CLIENT_REST_DEFAULT_TIMEOUT = 600
SUBCLOUD_ISO_PATH = '/opt/platform/iso'
SUBCLOUD_FEED_PATH = '/var/www/pages/feed'

View File

@ -8,6 +8,7 @@ import os
from oslo_log import log as logging
import sh
from dccommon import consts
from dcmanager.common import utils
# The 'sh' library is magical - it looks up CLI functions dynamically.
@ -53,15 +54,21 @@ def check_stale_bind_mount(mount_path, source_path):
# TODO(kmacleod): utils.synchronized should be moved into dccommon
@utils.synchronized("ostree-mount-subclouds", external=True)
def validate_ostree_iso_mount(www_iso_root, source_path):
def validate_ostree_iso_mount(software_version):
"""Ensure the ostree_repo is properly mounted under the iso path.
Validity check includes if the mount is stale.
If stale, the bind mount is recreated.
Note that ostree_repo is mounted in a location not specific to a subcloud.
"""
ostree_repo_mount_path = os.path.join(www_iso_root, "ostree_repo")
ostree_repo_source_path = os.path.join(source_path, "ostree_repo")
ostree_repo_mount_path = os.path.join(
consts.SUBCLOUD_ISO_PATH, software_version, "ostree_repo"
)
ostree_repo_source_path = os.path.join(
consts.SUBCLOUD_FEED_PATH,
"rel-{version}".format(version=software_version),
"ostree_repo",
)
LOG.debug(
"Checking ostree_repo mount: %s against %s",
ostree_repo_mount_path,
@ -78,7 +85,7 @@ def validate_ostree_iso_mount(www_iso_root, source_path):
os.makedirs(ostree_repo_mount_path, mode=0o755)
mount_args = (
"--bind",
"%s/ostree_repo" % source_path,
ostree_repo_source_path,
ostree_repo_mount_path,
)
try:

View File

@ -36,6 +36,7 @@ from dccommon.drivers.openstack.sysinv_v1 import SysinvClient
from dccommon import exceptions
from dccommon import ostree_mount
from dccommon import utils as dccommon_utils
from dcmanager.common import consts as dcmanager_consts
from dcmanager.common import utils
@ -45,9 +46,7 @@ LOG = logging.getLogger(__name__)
CONF = cfg.CONF
BOOT_MENU_TIMEOUT = '5'
SUBCLOUD_ISO_PATH = '/opt/platform/iso'
SUBCLOUD_ISO_DOWNLOAD_PATH = '/var/www/pages/iso'
SUBCLOUD_FEED_PATH = '/var/www/pages/feed'
DCVAULT_BOOTIMAGE_PATH = '/opt/dc-vault/loads/'
PACKAGE_LIST_PATH = '/usr/local/share/pkg-list'
GEN_ISO_COMMAND = '/usr/local/bin/gen-bootloader-iso.sh'
@ -510,16 +509,10 @@ class SubcloudInstall(object):
if not os.path.isdir(override_path):
os.mkdir(override_path, 0o755)
self.www_iso_root = os.path.join(SUBCLOUD_ISO_PATH, software_version)
feed_path_rel_version = os.path.join(SUBCLOUD_FEED_PATH,
"rel-{version}".format(
version=software_version))
self.www_iso_root = os.path.join(consts.SUBCLOUD_ISO_PATH, software_version)
if dccommon_utils.is_debian(software_version):
ostree_mount.validate_ostree_iso_mount(
self.www_iso_root, feed_path_rel_version
)
ostree_mount.validate_ostree_iso_mount(software_version)
# Clean up iso directory if it already exists
# This may happen if a previous installation attempt was abruptly
@ -571,7 +564,7 @@ class SubcloudInstall(object):
self.name,
software_version + "_packages_list.txt")
pkg_file_src = os.path.join(SUBCLOUD_FEED_PATH,
pkg_file_src = os.path.join(consts.SUBCLOUD_FEED_PATH,
"rel-{version}".format(
version=software_version),
'package_checksums')

View File

@ -12,6 +12,7 @@ from oslo_messaging import RemoteError
import pecan
from dcmanager.api.controllers import restcomm
from dcmanager.api.controllers.v1.subclouds import SubcloudsController
from dcmanager.api.policies import phased_subcloud_deploy as \
phased_subcloud_deploy_policy
from dcmanager.api import policy
@ -210,6 +211,8 @@ class PhasedSubcloudDeployController(object):
if not payload:
pecan.abort(400, _('Body required'))
SubcloudsController.validate_software_deploy_state()
if subcloud.deploy_status not in VALID_STATES_FOR_DEPLOY_INSTALL:
allowed_states_str = ', '.join(VALID_STATES_FOR_DEPLOY_INSTALL)
pecan.abort(400, _('Subcloud deploy status must be either: %s')
@ -471,6 +474,7 @@ class PhasedSubcloudDeployController(object):
# Consider the incoming release parameter only if install is one
# of the pending deploy states
if INSTALL in deploy_states_to_run:
SubcloudsController.validate_software_deploy_state()
unvalidated_sw_version = \
payload.get('release', subcloud.software_version)
else:

View File

@ -44,6 +44,7 @@ from dccommon.drivers.openstack.fm import FmClient
from dccommon.drivers.openstack.sdk_platform import (
OptimizedOpenStackDriver as OpenStackDriver
)
from dccommon.drivers.openstack import software_v1
from dccommon.drivers.openstack.sysinv_v1 import SysinvClient
from dccommon.drivers.openstack import vim
from dccommon import exceptions as dccommon_exceptions
@ -129,36 +130,54 @@ class SubcloudsController(object):
@staticmethod
def _get_prestage_payload(request):
fields = ['sysadmin_password', 'force', consts.PRESTAGE_REQUEST_RELEASE]
payload = {
'force': False
}
fields = [
"sysadmin_password",
"force",
consts.PRESTAGE_REQUEST_RELEASE,
consts.PRESTAGE_FOR_INSTALL,
consts.PRESTAGE_FOR_SW_DEPLOY,
]
payload = {"force": False}
try:
body = json.loads(request.body)
except Exception:
pecan.abort(400, _('Request body is malformed.'))
pecan.abort(400, _("Request body is malformed."))
for field in fields:
val = body.get(field)
if val is None:
if field == 'sysadmin_password':
if field == "sysadmin_password":
pecan.abort(400, _("%s is required." % field))
else:
if field == 'sysadmin_password':
if field == "sysadmin_password":
try:
base64.b64decode(val).decode('utf-8')
payload['sysadmin_password'] = val
base64.b64decode(val).decode("utf-8")
payload["sysadmin_password"] = val
except Exception:
pecan.abort(
400,
_('Failed to decode subcloud sysadmin_password, '
'verify the password is base64 encoded'))
elif field == 'force':
if val.lower() in ('true', 'false', 't', 'f'):
payload['force'] = val.lower() in ('true', 't')
_(
"Failed to decode subcloud sysadmin_password, "
"verify the password is base64 encoded"
),
)
elif field == "force":
if val.lower() in ("true", "false", "t", "f"):
payload["force"] = val.lower() in ("true", "t")
else:
pecan.abort(
400, _('Invalid value for force option: %s' % val))
400, _("Invalid value for force option: %s" % val)
)
elif field in (
consts.PRESTAGE_FOR_INSTALL,
consts.PRESTAGE_FOR_SW_DEPLOY
):
if val.lower() in ("true", "false", "t", "f"):
payload[field] = val.lower() in ("true", "t")
else:
errmsg = f"Invalid value for {field} option: {val}"
pecan.abort(400, _(errmsg))
elif field == consts.PRESTAGE_REQUEST_RELEASE:
payload[consts.PRESTAGE_REQUEST_RELEASE] = val
return payload
@ -522,6 +541,53 @@ class SubcloudsController(object):
subcloud_dict.update(extra_details)
return subcloud_dict
@staticmethod
def is_valid_software_deploy_state():
try:
m_os_ks_client = OpenStackDriver(
region_name=dccommon_consts.DEFAULT_REGION_NAME, region_clients=None
).keystone_client
software_endpoint = m_os_ks_client.endpoint_cache.get_endpoint(
dccommon_consts.ENDPOINT_TYPE_SOFTWARE
)
software_client = software_v1.SoftwareClient(
dccommon_consts.DEFAULT_REGION_NAME,
m_os_ks_client.session,
endpoint=software_endpoint,
)
software_list = software_client.list()
for release in software_list:
if release["state"] not in (
software_v1.AVAILABLE,
software_v1.COMMITTED,
software_v1.DEPLOYED,
software_v1.UNAVAILABLE,
):
LOG.info(
"is_valid_software_deploy_state, not valid for: %s",
software_list
)
return False
LOG.debug("is_valid_software_deploy_state, valid: %s", software_list)
except Exception:
LOG.exception("Failure initializing OS Client, disallowing.")
return False
return True
@staticmethod
def validate_software_deploy_state():
if not SubcloudsController.is_valid_software_deploy_state():
pecan.abort(
400,
_(
"A local software deployment operation is in progress. "
"Please finish the software deployment operation before "
"(re)installing/updating the subcloud."
),
)
@utils.synchronized(LOCK_NAME)
@index.when(method='POST', template='json')
def post(self):
@ -531,6 +597,18 @@ class SubcloudsController(object):
restcomm.extract_credentials_for_policy())
context = restcomm.extract_context_from_environ()
self.validate_software_deploy_state()
if not SubcloudsController.is_valid_software_deploy_state():
pecan.abort(
400,
_(
"A local software deployment operation is in progress. "
"Please finish the software deployment opearation before "
"(re)installing/updating the subcloud."
),
)
bootstrap_sc_name = psd_common.get_bootstrap_subcloud_name(request)
payload = psd_common.get_request_data(request, None,
@ -1003,6 +1081,7 @@ class SubcloudsController(object):
if utils.subcloud_is_secondary_state(subcloud.deploy_status):
pecan.abort(500, _("Cannot perform on %s "
"state subcloud" % subcloud.deploy_status))
self.validate_software_deploy_state()
config_file = psd_common.get_config_file_path(subcloud.name,
consts.DEPLOY_CONFIG)
has_bootstrap_values = consts.BOOTSTRAP_VALUES in request.POST
@ -1106,8 +1185,11 @@ class SubcloudsController(object):
LOG.exception("validate_prestage failed")
pecan.abort(400, _(str(exc)))
for_install = True
if consts.PRESTAGE_FOR_SW_DEPLOY in payload:
for_install = False
prestage_software_version = utils.get_sw_version(
payload.get(consts.PRESTAGE_REQUEST_RELEASE))
payload.get(consts.PRESTAGE_REQUEST_RELEASE), for_install)
try:
self.dcmanager_rpc_client.prestage_subcloud(context, payload)

View File

@ -399,6 +399,8 @@ EXTRA_ARGS_RELEASE = 'release'
# http request/response arguments for prestage
PRESTAGE_SOFTWARE_VERSION = 'prestage-software-version'
PRESTAGE_REQUEST_RELEASE = 'release'
PRESTAGE_FOR_INSTALL = 'for_install'
PRESTAGE_FOR_SW_DEPLOY = 'for_sw_deploy'
# Device Image Bitstream Types
BITSTREAM_TYPE_ROOT_KEY = 'root-key'

View File

@ -36,6 +36,7 @@ from dccommon.drivers.openstack.sdk_platform import (
from dccommon.drivers.openstack.sysinv_v1 import SysinvClient
from dccommon.exceptions import PlaybookExecutionFailed
from dccommon.exceptions import PlaybookExecutionTimeout
from dccommon import ostree_mount
from dccommon.utils import AnsiblePlaybook
from dcmanager.common import consts
@ -110,7 +111,12 @@ def global_prestage_validate(payload):
" Details: %s" % ex)
def initial_subcloud_validate(subcloud, installed_loads, software_version):
def initial_subcloud_validate(
subcloud,
installed_loads,
software_major_release, # format: YY.MM
for_sw_deploy,
):
"""Basic validation a subcloud prestage operation.
Raises a PrestageCheckFailedException on failure.
@ -158,14 +164,14 @@ def initial_subcloud_validate(subcloud, installed_loads, software_version):
# The request software version must be either the same as the software version
# of the subcloud or any active/inactive/imported load on the system controller
# (can be checked with "system load-list" command).
if software_version and \
software_version != subcloud.software_version and \
software_version not in installed_loads:
if not for_sw_deploy and software_major_release and \
software_major_release != subcloud.software_version and \
software_major_release not in installed_loads:
raise exceptions.PrestagePreCheckFailedException(
subcloud=subcloud.name,
orch_skip=True,
details="Specified release is not supported. "
"%s version must first be imported" % software_version)
f"{software_major_release} version must first be imported")
def validate_prestage(subcloud, payload):
@ -185,12 +191,21 @@ def validate_prestage(subcloud, payload):
installed_loads = []
software_version = None
software_major_release = None
if payload.get(consts.PRESTAGE_REQUEST_RELEASE):
software_version = payload.get(consts.PRESTAGE_REQUEST_RELEASE)
software_major_release = utils.get_major_release(software_version)
installed_loads = utils.get_systemcontroller_installed_loads()
for_sw_deploy = is_prestage_for_sw_deploy(payload)
# re-run the initial validation
initial_subcloud_validate(subcloud, installed_loads, software_version)
initial_subcloud_validate(
subcloud,
installed_loads,
software_major_release,
for_sw_deploy,
)
subcloud_type, system_health, oam_floating_ip = \
_get_prestage_subcloud_info(subcloud)
@ -238,6 +253,13 @@ def is_local(subcloud_version, specified_version):
return subcloud_version == specified_version
def is_prestage_for_sw_deploy(payload):
# The default is for_install, so we can simply check if the payload is
# tagged with for_sw_deploy
for_sw_deploy = payload.get(consts.PRESTAGE_FOR_SW_DEPLOY, False)
return for_sw_deploy
def prestage_subcloud(context, payload):
"""Subcloud prestaging
@ -253,8 +275,11 @@ def prestage_subcloud(context, payload):
- run prestage_images.yml ansible playbook
"""
subcloud_name = payload['subcloud_name']
LOG.info("Prestaging subcloud: %s, force=%s" % (subcloud_name,
payload['force']))
for_sw_deploy = is_prestage_for_sw_deploy(payload)
LOG.info(
f"Prestaging subcloud: {subcloud_name}, "
f"force={payload['force']}, for_sw_deploy={for_sw_deploy}"
)
try:
subcloud = db_api.subcloud_get_by_name(context, subcloud_name)
except exceptions.SubcloudNameNotFound:
@ -282,6 +307,7 @@ def prestage_subcloud(context, payload):
def _prestage_standalone_thread(context, subcloud, payload):
"""Run the prestage operations inside a separate thread"""
log_file = utils.get_subcloud_ansible_log_file(subcloud.name)
for_sw_deploy = is_prestage_for_sw_deploy(payload)
try:
prestage_packages(context, subcloud, payload)
# Get the prestage versions from the logs generated by
@ -289,11 +315,17 @@ def _prestage_standalone_thread(context, subcloud, payload):
prestage_versions = utils.get_msg_output_info(
log_file, PRINT_PRESTAGE_VERSIONS_TASK, PRESTAGE_VERSIONS_KEY_STR)
prestage_images(context, subcloud, payload)
# TODO(kmacleod) need to invoke this for retagging images
if not for_sw_deploy:
prestage_images(context, subcloud, payload)
prestage_complete(context, subcloud.id, prestage_versions)
LOG.info("Prestage complete: %s", subcloud.name)
except Exception:
LOG.exception(
f"Subcloud prestaging failed (in standalone thread) {subcloud.name}"
)
prestage_fail(context, subcloud.id)
raise
@ -382,8 +414,24 @@ def prestage_packages(context, subcloud, payload):
ANSIBLE_PRESTAGE_INVENTORY_SUFFIX)
prestage_software_version = payload.get(
consts.PRESTAGE_REQUEST_RELEASE, SW_VERSION)
extra_vars_str = "software_version=%s" % prestage_software_version
consts.PRESTAGE_REQUEST_RELEASE, SW_VERSION
)
prestage_major_release = utils.get_major_release(prestage_software_version)
extra_vars_str = f"software_version={prestage_software_version} "
extra_vars_str += f"software_major_release={prestage_major_release}"
if is_prestage_for_sw_deploy(payload):
extra_vars_str += (
f" prestage_install={consts.PRESTAGE_FOR_SW_DEPLOY}"
)
else:
# default
extra_vars_str += (
f" prestage_install={consts.PRESTAGE_FOR_INSTALL}"
)
ostree_mount.validate_ostree_iso_mount(prestage_major_release)
_run_ansible(context,
["ansible-playbook",
ANSIBLE_PRESTAGE_SUBCLOUD_PACKAGES_PLAYBOOK,
@ -414,10 +462,21 @@ def prestage_images(context, subcloud, payload):
"""
prestage_software_version = payload.get(
consts.PRESTAGE_REQUEST_RELEASE, SW_VERSION)
extra_vars_str = "software_version=%s" % prestage_software_version
prestage_major_release = utils.get_major_release(
prestage_software_version
)
extra_vars_str = f"software_version={prestage_software_version} "
extra_vars_str += f"software_major_release={prestage_major_release}"
# TODO(kmacleod) we may not need these if images are not prestaged
# if for_sw_deploy
if consts.PRESTAGE_FOR_INSTALL in payload:
extra_vars_str += f" for_install={payload[consts.PRESTAGE_FOR_INSTALL]}"
elif consts.PRESTAGE_FOR_SW_DEPLOY in payload:
extra_vars_str += f" for_sw_deploy={payload[consts.PRESTAGE_FOR_SW_DEPLOY]}"
image_list_filename = None
deploy_dir = os.path.join(DEPLOY_BASE_DIR, prestage_software_version)
deploy_dir = os.path.join(DEPLOY_BASE_DIR, prestage_major_release)
if os.path.isdir(deploy_dir):
image_list_filename = utils.get_filename_by_prefix(deploy_dir,
'prestage_images')
@ -428,14 +487,14 @@ def prestage_images(context, subcloud, payload):
LOG.debug("prestage images list file: %s", image_list_file)
else:
LOG.debug("prestage images list file does not exist")
if prestage_software_version != subcloud.software_version:
if prestage_major_release != subcloud.software_version:
# Prestage source is remote but there is no images list file so
# skip the images prestage.
LOG.info("Images prestage is skipped for %s as the prestage images "
"list for release %s has not been uploaded and the "
"subcloud is running a different load than %s."
% (subcloud.name, prestage_software_version,
prestage_software_version))
% (subcloud.name, prestage_major_release,
prestage_major_release))
return
# Ansible inventory filename for the specified subcloud

View File

@ -1406,7 +1406,7 @@ def create_subcloud_rehome_data_template():
return {'saved_payload': {}}
def get_sw_version(release=None):
def get_sw_version(release=None, for_install=True):
"""Get the sw_version to be used.
Return the sw_version by first validating a set release version.
@ -1416,7 +1416,10 @@ def get_sw_version(release=None):
if release:
try:
validate_release_version_supported(release)
if for_install:
validate_major_release_version_supported(release)
else:
validate_minor_release_version_exists(release)
return release
except exceptions.ValidateFail as e:
pecan.abort(400,
@ -1428,7 +1431,7 @@ def get_sw_version(release=None):
return tsc.SW_VERSION
def validate_release_version_supported(release_version_to_check):
def validate_major_release_version_supported(release_version_to_check):
"""Check if a release version is supported by the current active version.
:param release_version_to_check: version string to validate
@ -1452,6 +1455,37 @@ def validate_release_version_supported(release_version_to_check):
return True
def is_major_release(version):
return not is_minor_release(version)
def is_minor_release(version):
split_version = version.split('.')
if len(split_version) == 2:
return False
if len(split_version) == 3:
if split_version[2] == '0':
return False
return True
LOG.error(f"Unexpected release version found: {version}, assuming major release")
return False
def get_major_release(version):
"""Returns the YY.MM portion of the given version string"""
split_version = version.split('.')
return '.'.join(split_version[0:2])
def validate_minor_release_version_exists(release_version_to_check):
# TODO(kmacleod): For minor releases (for_sw_deploy) we need to
# validate the given minor release
# This should lookup all the minor releases and validate the input version
# exists
LOG.warn("TODO: validate_minor_release_version_exists")
def get_current_supported_upgrade_versions():
"""Parse the upgrades metadata file to build a list of supported versions.

View File

@ -340,9 +340,16 @@ class SwUpdateManager(manager.Manager):
patch_file = payload.get('patch')
installed_loads = []
software_version = None
software_major_release = None
for_sw_deploy = False
if payload.get(consts.PRESTAGE_REQUEST_RELEASE):
software_version = payload.get(consts.PRESTAGE_REQUEST_RELEASE)
software_major_release = utils.get_major_release(software_version)
installed_loads = utils.get_systemcontroller_installed_loads()
# TODO(kmacleod): Hugo: we need to say whether this is a
# for-install or for-fw-deploy prestaging operation Setting this to
# a for-install operation for now (since that is the default)
for_sw_deploy = False
# Has the user specified a specific subcloud?
# todo(abailey): refactor this code to use classes
@ -426,8 +433,13 @@ class SwUpdateManager(manager.Manager):
try:
prestage.global_prestage_validate(payload)
prestage_global_validated = True
installed_loads = utils.get_systemcontroller_installed_loads()
prestage.initial_subcloud_validate(
subcloud, installed_loads, software_version)
subcloud,
installed_loads,
software_major_release,
for_sw_deploy
)
except exceptions.PrestagePreCheckFailedException as ex:
raise exceptions.BadRequest(resource='strategy',
msg=str(ex))
@ -597,7 +609,11 @@ class SwUpdateManager(manager.Manager):
# Do initial validation for subcloud
try:
prestage.initial_subcloud_validate(
subcloud, installed_loads, software_version)
subcloud,
installed_loads,
software_major_release,
for_sw_deploy,
)
except exceptions.PrestagePreCheckFailedException:
LOG.warn("Excluding subcloud from prestage strategy: %s",
subcloud.name)

View File

@ -31,6 +31,7 @@ from sqlalchemy.engine import Engine
from sqlalchemy import event
from dccommon.utils import AnsiblePlaybook
from dcmanager.api.controllers.v1.subclouds import SubcloudsController
from dcmanager.audit import rpcapi
from dcmanager.audit import subcloud_audit_manager
from dcmanager.common import consts
@ -382,3 +383,11 @@ class DCManagerTestCase(base.BaseTestCase):
mock_patch_object = mock.patch.object(AnsiblePlaybook, 'run_playbook')
self.mock_ansible_run_playbook = mock_patch_object.start()
self.addCleanup(mock_patch_object.stop)
def _mock_valid_software_deploy_state(self, return_value=True):
mock_patch_object = mock.patch.object(
SubcloudsController, "is_valid_software_deploy_state"
)
self.mock_valid_software_deploy_state = mock_patch_object.start()
self.addCleanup(mock_patch_object.stop)
self.mock_valid_software_deploy_state.return_value = return_value

View File

@ -14,6 +14,7 @@ from tsconfig.tsconfig import SW_VERSION
from dccommon import consts as dccommon_consts
from dcmanager.api.controllers.v1 import phased_subcloud_deploy as psd_api
from dcmanager.api.controllers.v1.subclouds import SubcloudsController
from dcmanager.common import consts
from dcmanager.common import phased_subcloud_deploy as psd_common
from dcmanager.common import utils as dutils
@ -66,6 +67,13 @@ class BaseTestPhasedSubcloudDeployController(DCManagerApiTest):
self.mock_is_initial_deployment = mock_patch_object.start()
self.addCleanup(mock_patch_object.stop)
def _mock_is_valid_software_deploy_state(self):
mock_patch_object = mock.patch.object(
SubcloudsController, "is_valid_software_deploy_state"
)
self.mock_is_valid_software_deploy_state = mock_patch_object.start()
self.addCleanup(mock_patch_object.stop)
class TestPhasedSubcloudDeployController(BaseTestPhasedSubcloudDeployController):
"""Test class for PhasedSubcloudDeployController"""
@ -197,6 +205,7 @@ class BaseTestPhasedSubcloudDeployPatch(BaseTestPhasedSubcloudDeployController):
self._mock_get_vault_load_files()
self._mock_is_initial_deployment()
self._mock_is_valid_software_deploy_state()
self._mock_get_network_address_pool()
self.mock_get_vault_load_files.return_value = \

View File

@ -230,6 +230,7 @@ class BaseTestSubcloudsController(DCManagerApiTest, SubcloudAPIMixin):
self._mock_rpc_subcloud_state_client()
self._mock_get_ks_client()
self._mock_query()
self._mock_valid_software_deploy_state()
def _update_subcloud(self, **kwargs):
self.subcloud = sql_api.subcloud_update(self.ctx, self.subcloud.id, **kwargs)

View File

@ -370,6 +370,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
for index, strategy_step in enumerate(strategy_step_list):
self.assertEqual(subcloud_ids[index], strategy_step.subcloud_id)
@mock.patch.object(cutils, "get_systemcontroller_installed_loads")
@mock.patch.object(prestage, "initial_subcloud_validate")
@mock.patch.object(prestage, "global_prestage_validate")
@mock.patch.object(sw_update_manager, "PatchOrchThread")
@ -378,6 +379,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
mock_patch_orch_thread,
mock_global_prestage_validate,
mock_initial_subcloud_validate,
mock_installed_loads,
):
# Create fake subclouds and respective status
fake_subcloud1 = self.create_subcloud(
@ -404,6 +406,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
mock_global_prestage_validate.return_value = None
mock_initial_subcloud_validate.return_value = None
mock_installed_loads.return_value = ['24.09']
data = copy.copy(FAKE_SW_PRESTAGE_DATA)
fake_password = (base64.b64encode("testpass".encode("utf-8"))).decode(
@ -428,6 +431,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
for index, strategy_step in enumerate(strategy_step_list):
self.assertEqual(subcloud_ids[index], strategy_step.subcloud_id)
@mock.patch.object(cutils, "get_systemcontroller_installed_loads")
@mock.patch.object(prestage, "initial_subcloud_validate")
@mock.patch.object(prestage, "global_prestage_validate")
@mock.patch.object(sw_update_manager, "PatchOrchThread")
@ -436,6 +440,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
mock_patch_orch_thread,
mock_global_prestage_validate,
mock_initial_subcloud_validate,
mock_installed_loads,
):
# Create fake subclouds and respective status
# Subcloud1 will be prestaged load in sync
@ -481,6 +486,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
mock_global_prestage_validate.return_value = None
mock_initial_subcloud_validate.return_value = None
mock_installed_loads.return_value = ['24.09']
data = copy.copy(FAKE_SW_PRESTAGE_DATA)
fake_password = (base64.b64encode("testpass".encode("utf-8"))).decode(
@ -504,6 +510,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
for index, strategy_step in enumerate(strategy_step_list):
self.assertEqual(subcloud_ids[index], strategy_step.subcloud_id)
@mock.patch.object(cutils, "get_systemcontroller_installed_loads")
@mock.patch.object(prestage, "initial_subcloud_validate")
@mock.patch.object(prestage, "_get_system_controller_upgrades")
@mock.patch.object(sw_update_manager, "PatchOrchThread")
@ -512,6 +519,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
mock_patch_orch_thread,
mock_controller_upgrade,
mock_initial_subcloud_validate,
mock_installed_loads,
):
# Create fake subclouds and respective status
fake_subcloud1 = self.create_subcloud(
@ -538,6 +546,7 @@ class TestSwUpdateManager(base.DCManagerTestCase):
mock_initial_subcloud_validate.return_value = None
mock_controller_upgrade.return_value = list()
mock_installed_loads.return_value = ['24.09']
data = copy.copy(FAKE_SW_PRESTAGE_DATA)
data["sysadmin_password"] = ""
@ -551,12 +560,17 @@ class TestSwUpdateManager(base.DCManagerTestCase):
payload=data,
)
@mock.patch.object(cutils, "get_systemcontroller_installed_loads")
@mock.patch.object(prestage, "_get_system_controller_upgrades")
@mock.patch.object(sw_update_manager, "PatchOrchThread")
def test_create_sw_prestage_strategy_backup_in_progress(
self, mock_patch_orch_thread, mock_controller_upgrade
self,
mock_patch_orch_thread,
mock_controller_upgrade,
mock_installed_loads,
):
mock_controller_upgrade.return_value = list()
mock_installed_loads.return_value = ['24.09']
# Create fake subcloud and respective status (managed & online)
fake_subcloud1 = self.create_subcloud(