Clean software orchestration states
The VIM orchestration will handle the following commands for USM: - software deploy precheck - software deploy start <release> - software deploy host <hostname> - every lock/unlock/swact needed - software deploy activate - software deploy complete Now, the DC orchestration doesn't need the states to handle the operations above. This commit deletes all unneeded states. Test Plan: PASS: Execute the software orchestration successfully: - Enable the USM orchestration (set use_usm parameter to True) - dcorch configuration file - dcmanager configuration file - Create and apply an upgrade-strategy - Check that 5 states were executed PASS. Tox test successful. Story: 2010676 Task: 49555 Change-Id: I67db35b6807f9ddcedab7c9742816c782daecd68 Signed-off-by: Hugo Brito <hugo.brito@windriver.com>
This commit is contained in:
parent
30812c4411
commit
9e42f10470
@ -154,16 +154,6 @@ STRATEGY_STATE_DELETING_LOAD = "deleting load"
|
|||||||
# Software orchestration states
|
# Software orchestration states
|
||||||
STRATEGY_STATE_SW_PRE_CHECK = "software pre check"
|
STRATEGY_STATE_SW_PRE_CHECK = "software pre check"
|
||||||
STRATEGY_STATE_SW_INSTALL_LICENSE = "software install license"
|
STRATEGY_STATE_SW_INSTALL_LICENSE = "software install license"
|
||||||
STRATEGY_STATE_SW_UPLOAD = "software upload"
|
|
||||||
STRATEGY_STATE_SW_DEPLOY_PRE_CHECK = "software deploy pre check"
|
|
||||||
STRATEGY_STATE_SW_DEPLOY_START = "software deploy start"
|
|
||||||
STRATEGY_STATE_SW_LOCK_CONTROLLER = "software lock controller"
|
|
||||||
STRATEGY_STATE_SW_UNLOCK_CONTROLLER = "software unlock controller"
|
|
||||||
STRATEGY_STATE_SW_SWACT_CONTROLLER_0 = "software swact controller-0"
|
|
||||||
STRATEGY_STATE_SW_SWACT_CONTROLLER_1 = "software swact controller-1"
|
|
||||||
STRATEGY_STATE_SW_DEPLOY_HOST = "software deploy host"
|
|
||||||
STRATEGY_STATE_SW_DEPLOY_ACTIVATE = "software deploy activate"
|
|
||||||
STRATEGY_STATE_SW_DEPLOY_COMPLETE = "software deploy complete"
|
|
||||||
STRATEGY_STATE_SW_CREATE_VIM_STRATEGY = "create VIM software strategy"
|
STRATEGY_STATE_SW_CREATE_VIM_STRATEGY = "create VIM software strategy"
|
||||||
STRATEGY_STATE_SW_APPLY_VIM_STRATEGY = "apply VIM software strategy"
|
STRATEGY_STATE_SW_APPLY_VIM_STRATEGY = "apply VIM software strategy"
|
||||||
STRATEGY_STATE_SW_FINISH_STRATEGY = "finish software strategy"
|
STRATEGY_STATE_SW_FINISH_STRATEGY = "finish software strategy"
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
from dccommon.drivers.openstack import vim
|
from dccommon.drivers.openstack import vim
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
from dcmanager.orchestrator.orch_thread import OrchThread
|
from dcmanager.orchestrator.orch_thread import OrchThread
|
||||||
@ -15,34 +13,11 @@ from dcmanager.orchestrator.states.software.cache.shared_cache_repository import
|
|||||||
SharedCacheRepository
|
SharedCacheRepository
|
||||||
from dcmanager.orchestrator.states.software.create_vim_software_strategy \
|
from dcmanager.orchestrator.states.software.create_vim_software_strategy \
|
||||||
import CreateVIMSoftwareStrategyState
|
import CreateVIMSoftwareStrategyState
|
||||||
from dcmanager.orchestrator.states.software.deploy_activate \
|
|
||||||
import DeployActivateState
|
|
||||||
from dcmanager.orchestrator.states.software.deploy_complete \
|
|
||||||
import DeployCompleteState
|
|
||||||
from dcmanager.orchestrator.states.software.deploy_host \
|
|
||||||
import DeployHostState
|
|
||||||
from dcmanager.orchestrator.states.software.deploy_pre_check \
|
|
||||||
import DeployPreCheckState
|
|
||||||
from dcmanager.orchestrator.states.software.deploy_start \
|
|
||||||
import DeployStartState
|
|
||||||
from dcmanager.orchestrator.states.software.finish_strategy \
|
from dcmanager.orchestrator.states.software.finish_strategy \
|
||||||
import FinishStrategyState
|
import FinishStrategyState
|
||||||
from dcmanager.orchestrator.states.software.install_license \
|
from dcmanager.orchestrator.states.software.install_license \
|
||||||
import InstallLicenseState
|
import InstallLicenseState
|
||||||
from dcmanager.orchestrator.states.software.lock_controller \
|
from dcmanager.orchestrator.states.software.pre_check import PreCheckState
|
||||||
import LockControllerState
|
|
||||||
from dcmanager.orchestrator.states.software.pre_check \
|
|
||||||
import PreCheckState
|
|
||||||
from dcmanager.orchestrator.states.software.swact_controller0 \
|
|
||||||
import SwactController0State
|
|
||||||
from dcmanager.orchestrator.states.software.swact_controller1 \
|
|
||||||
import SwactController1State
|
|
||||||
from dcmanager.orchestrator.states.software.unlock_controller \
|
|
||||||
import UnlockControllerState
|
|
||||||
from dcmanager.orchestrator.states.software.upload \
|
|
||||||
import UploadState
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class SoftwareOrchThread(OrchThread):
|
class SoftwareOrchThread(OrchThread):
|
||||||
@ -66,26 +41,16 @@ class SoftwareOrchThread(OrchThread):
|
|||||||
STATE_OPERATORS = {
|
STATE_OPERATORS = {
|
||||||
consts.STRATEGY_STATE_SW_PRE_CHECK: PreCheckState,
|
consts.STRATEGY_STATE_SW_PRE_CHECK: PreCheckState,
|
||||||
consts.STRATEGY_STATE_SW_INSTALL_LICENSE: InstallLicenseState,
|
consts.STRATEGY_STATE_SW_INSTALL_LICENSE: InstallLicenseState,
|
||||||
consts.STRATEGY_STATE_SW_UPLOAD: UploadState,
|
|
||||||
consts.STRATEGY_STATE_SW_DEPLOY_PRE_CHECK: DeployPreCheckState,
|
|
||||||
consts.STRATEGY_STATE_SW_DEPLOY_START: DeployStartState,
|
|
||||||
consts.STRATEGY_STATE_SW_LOCK_CONTROLLER: LockControllerState,
|
|
||||||
consts.STRATEGY_STATE_SW_DEPLOY_HOST: DeployHostState,
|
|
||||||
consts.STRATEGY_STATE_SW_UNLOCK_CONTROLLER: UnlockControllerState,
|
|
||||||
consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_0: SwactController0State,
|
|
||||||
consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY: CreateVIMSoftwareStrategyState,
|
consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY: CreateVIMSoftwareStrategyState,
|
||||||
consts.STRATEGY_STATE_SW_APPLY_VIM_STRATEGY: ApplyVIMSoftwareStrategyState,
|
consts.STRATEGY_STATE_SW_APPLY_VIM_STRATEGY: ApplyVIMSoftwareStrategyState,
|
||||||
consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_1: SwactController1State,
|
|
||||||
consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE: DeployActivateState,
|
|
||||||
consts.STRATEGY_STATE_SW_DEPLOY_COMPLETE: DeployCompleteState,
|
|
||||||
consts.STRATEGY_STATE_SW_FINISH_STRATEGY: FinishStrategyState,
|
consts.STRATEGY_STATE_SW_FINISH_STRATEGY: FinishStrategyState,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, strategy_lock, audit_rpc_client):
|
def __init__(self, strategy_lock, audit_rpc_client):
|
||||||
super(SoftwareOrchThread, self).__init__(
|
super().__init__(
|
||||||
strategy_lock,
|
strategy_lock,
|
||||||
audit_rpc_client,
|
audit_rpc_client,
|
||||||
consts.SW_UPDATE_TYPE_UPGRADE, # software update strategy type
|
consts.SW_UPDATE_TYPE_SOFTWARE, # software update strategy type
|
||||||
vim.STRATEGY_NAME_SW_UPGRADE, # strategy type used by vim
|
vim.STRATEGY_NAME_SW_UPGRADE, # strategy type used by vim
|
||||||
consts.STRATEGY_STATE_SW_PRE_CHECK) # starting state
|
consts.STRATEGY_STATE_SW_PRE_CHECK) # starting state
|
||||||
|
|
||||||
@ -100,10 +65,9 @@ class SoftwareOrchThread(OrchThread):
|
|||||||
def pre_apply_setup(self):
|
def pre_apply_setup(self):
|
||||||
# Restart caches for next strategy
|
# Restart caches for next strategy
|
||||||
self._shared_caches.initialize_caches()
|
self._shared_caches.initialize_caches()
|
||||||
super(SoftwareOrchThread, self).pre_apply_setup()
|
super().pre_apply_setup()
|
||||||
|
|
||||||
def determine_state_operator(self, strategy_step):
|
def determine_state_operator(self, strategy_step):
|
||||||
state = super(SoftwareOrchThread, self).determine_state_operator(
|
state = super().determine_state_operator(strategy_step)
|
||||||
strategy_step)
|
|
||||||
state.add_shared_caches(self._shared_caches)
|
state.add_shared_caches(self._shared_caches)
|
||||||
return state
|
return state
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -12,8 +12,8 @@ class ApplyVIMSoftwareStrategyState(BaseState):
|
|||||||
"""Apply VIM Software Strategy software orchestration state"""
|
"""Apply VIM Software Strategy software orchestration state"""
|
||||||
|
|
||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
super(ApplyVIMSoftwareStrategyState, self).__init__(
|
super().__init__(
|
||||||
next_state=consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_1,
|
next_state=consts.STRATEGY_STATE_SW_FINISH_STRATEGY,
|
||||||
region_name=region_name
|
region_name=region_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
|
|
||||||
|
|
||||||
class DeployActivateState(BaseState):
|
|
||||||
"""Deploy activate software orchestration state"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(DeployActivateState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_COMPLETE,
|
|
||||||
region_name=region_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Deploy Activate region status"""
|
|
||||||
return self.next_state
|
|
@ -1,22 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
|
|
||||||
|
|
||||||
class DeployCompleteState(BaseState):
|
|
||||||
"""Deploy complete software orchestration state"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(DeployCompleteState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_FINISH_STRATEGY,
|
|
||||||
region_name=region_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Deploy complete region status"""
|
|
||||||
return self.next_state
|
|
@ -1,22 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
|
|
||||||
|
|
||||||
class DeployHostState(BaseState):
|
|
||||||
"""Deploy host software orchestration state"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(DeployHostState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_UNLOCK_CONTROLLER,
|
|
||||||
region_name=region_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Deploy host region status"""
|
|
||||||
return self.next_state
|
|
@ -1,22 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
|
|
||||||
|
|
||||||
class DeployPreCheckState(BaseState):
|
|
||||||
"""Deploy pre check software orchestration state"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(DeployPreCheckState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_START,
|
|
||||||
region_name=region_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Deploy pre check region status"""
|
|
||||||
return self.next_state
|
|
@ -1,94 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dccommon.drivers.openstack import software_v1
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
from dcmanager.orchestrator.states.software.cache.cache_specifications import \
|
|
||||||
REGION_ONE_RELEASE_USM_CACHE_TYPE
|
|
||||||
|
|
||||||
# Max time: 1 minute = 6 queries x 10 seconds between
|
|
||||||
DEFAULT_MAX_QUERIES = 6
|
|
||||||
DEFAULT_SLEEP_DURATION = 10
|
|
||||||
|
|
||||||
|
|
||||||
class DeployStartState(BaseState):
|
|
||||||
"""Software orchestration state for deploy start releases"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(DeployStartState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_HOST,
|
|
||||||
region_name=region_name)
|
|
||||||
self.max_queries = DEFAULT_MAX_QUERIES
|
|
||||||
self.sleep_duration = DEFAULT_SLEEP_DURATION
|
|
||||||
|
|
||||||
def _get_deployed_controller_patches(self):
|
|
||||||
regionone_releases = self._read_from_cache(REGION_ONE_RELEASE_USM_CACHE_TYPE)
|
|
||||||
deployed_releases = {}
|
|
||||||
for release_id, release_info in regionone_releases.items():
|
|
||||||
if release_info['state'] == software_v1.DEPLOYED:
|
|
||||||
deployed_releases[release_id] = release_info
|
|
||||||
return deployed_releases
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Deploy start releases in this subcloud"""
|
|
||||||
self.info_log(strategy_step, "Applying releases")
|
|
||||||
deployed_releases = self._get_deployed_controller_patches()
|
|
||||||
self.debug_log(strategy_step,
|
|
||||||
f"SystemController deployed releases: {deployed_releases}")
|
|
||||||
|
|
||||||
# Find the max version deployed on the SystemController
|
|
||||||
max_version = None
|
|
||||||
for deployed_releases_values in deployed_releases.values():
|
|
||||||
release_sw_version = deployed_releases_values['sw_version']
|
|
||||||
if max_version is None or release_sw_version > max_version:
|
|
||||||
max_version = release_sw_version
|
|
||||||
|
|
||||||
# Retrieve all subcloud releases
|
|
||||||
try:
|
|
||||||
subcloud_releases = self.get_software_client(self.region_name).query()
|
|
||||||
self.debug_log(strategy_step,
|
|
||||||
f"Subcloud releases: {subcloud_releases}")
|
|
||||||
except Exception:
|
|
||||||
message = ("Cannot retrieve subcloud releases. Please see logs for "
|
|
||||||
"details.")
|
|
||||||
self.exception_log(strategy_step, message)
|
|
||||||
raise Exception(message)
|
|
||||||
|
|
||||||
deploy_start_release = None
|
|
||||||
|
|
||||||
for release_id in subcloud_releases:
|
|
||||||
is_reboot_required = subcloud_releases[release_id][
|
|
||||||
'reboot_required'] == "Y"
|
|
||||||
is_available = subcloud_releases[release_id]['state'] == (
|
|
||||||
software_v1.AVAILABLE)
|
|
||||||
is_deployed = subcloud_releases[release_id]['state'] == (
|
|
||||||
software_v1.DEPLOYED)
|
|
||||||
release_sw_version = subcloud_releases[release_id]['sw_version']
|
|
||||||
|
|
||||||
# Check if any release is reboot required
|
|
||||||
if deployed_releases.get(
|
|
||||||
release_id) and is_available and is_reboot_required:
|
|
||||||
self.override_next_state(consts.STRATEGY_STATE_SW_LOCK_CONTROLLER)
|
|
||||||
|
|
||||||
# Get the only release needed to be deployed
|
|
||||||
if (is_deployed and release_sw_version == max_version) or (
|
|
||||||
is_available and release_sw_version == max_version):
|
|
||||||
deploy_start_release = release_id
|
|
||||||
|
|
||||||
if deploy_start_release:
|
|
||||||
self.info_log(strategy_step,
|
|
||||||
f"Deploy start release {deploy_start_release} to subcloud")
|
|
||||||
try:
|
|
||||||
self.get_software_client(self.region_name).deploy_start(
|
|
||||||
deploy_start_release)
|
|
||||||
except Exception:
|
|
||||||
message = (
|
|
||||||
"Cannot deploy start releases to subcloud. Please see logs "
|
|
||||||
"for details.")
|
|
||||||
self.exception_log(strategy_step, message)
|
|
||||||
raise Exception(message)
|
|
||||||
return self.next_state
|
|
@ -15,7 +15,7 @@ class FinishStrategyState(BaseState):
|
|||||||
"""Finish Software Strategy software orchestration state"""
|
"""Finish Software Strategy software orchestration state"""
|
||||||
|
|
||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
super(FinishStrategyState, self).__init__(
|
super().__init__(
|
||||||
next_state=consts.STRATEGY_STATE_COMPLETE,
|
next_state=consts.STRATEGY_STATE_COMPLETE,
|
||||||
region_name=region_name,
|
region_name=region_name,
|
||||||
)
|
)
|
||||||
@ -32,20 +32,20 @@ class FinishStrategyState(BaseState):
|
|||||||
|
|
||||||
self.debug_log(
|
self.debug_log(
|
||||||
strategy_step,
|
strategy_step,
|
||||||
"regionone_committed_releases: %s" % regionone_committed_releases
|
f"regionone_committed_releases: {regionone_committed_releases}"
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
software_client = self.get_software_client(self.region_name)
|
software_client = self.get_software_client(self.region_name)
|
||||||
subcloud_releases = software_client.query()
|
subcloud_releases = software_client.query()
|
||||||
except Exception:
|
except Exception:
|
||||||
message = ("Cannot retrieve subcloud releases. Please see logs for"
|
message = ("Cannot retrieve subcloud releases. Please see logs for "
|
||||||
" details.")
|
"details.")
|
||||||
self.exception_log(strategy_step, message)
|
self.exception_log(strategy_step, message)
|
||||||
raise Exception(message)
|
raise Exception(message)
|
||||||
|
|
||||||
self.debug_log(strategy_step,
|
self.debug_log(strategy_step,
|
||||||
"Releases for subcloud: %s" % subcloud_releases)
|
f"Releases for subcloud: {subcloud_releases}")
|
||||||
|
|
||||||
releases_to_commit = list()
|
releases_to_commit = list()
|
||||||
releases_to_delete = list()
|
releases_to_delete = list()
|
||||||
@ -58,13 +58,13 @@ class FinishStrategyState(BaseState):
|
|||||||
subcloud_releases[release_id]['state'] ==
|
subcloud_releases[release_id]['state'] ==
|
||||||
software_v1.UNAVAILABLE):
|
software_v1.UNAVAILABLE):
|
||||||
releases_to_delete.append(release_id)
|
releases_to_delete.append(release_id)
|
||||||
elif subcloud_releases[release_id]['state'] == \
|
elif (subcloud_releases[release_id]['state'] ==
|
||||||
software_v1.DEPLOYED:
|
software_v1.DEPLOYED):
|
||||||
if release_id in regionone_committed_releases:
|
if release_id in regionone_committed_releases:
|
||||||
releases_to_commit.append(release_id)
|
releases_to_commit.append(release_id)
|
||||||
|
|
||||||
if releases_to_delete:
|
if releases_to_delete:
|
||||||
self.info_log(strategy_step, "Deleting releases %s" % releases_to_delete)
|
self.info_log(strategy_step, f"Deleting releases {releases_to_delete}")
|
||||||
try:
|
try:
|
||||||
software_client.delete(releases_to_delete)
|
software_client.delete(releases_to_delete)
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -78,12 +78,12 @@ class FinishStrategyState(BaseState):
|
|||||||
|
|
||||||
if releases_to_commit:
|
if releases_to_commit:
|
||||||
self.info_log(strategy_step,
|
self.info_log(strategy_step,
|
||||||
"Committing releases %s to subcloud" % releases_to_commit)
|
f"Committing releases {releases_to_commit} to subcloud")
|
||||||
try:
|
try:
|
||||||
software_client.commit_patch(releases_to_commit)
|
software_client.commit_patch(releases_to_commit)
|
||||||
except Exception:
|
except Exception:
|
||||||
message = ("Cannot commit releases to subcloud. Please see logs for"
|
message = ("Cannot commit releases to subcloud. Please see logs for "
|
||||||
" details.")
|
"details.")
|
||||||
self.exception_log(strategy_step, message)
|
self.exception_log(strategy_step, message)
|
||||||
raise Exception(message)
|
raise Exception(message)
|
||||||
|
|
||||||
|
@ -1,22 +1,102 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2020-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from dccommon import consts as dccommon_consts
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
|
from dcmanager.common import exceptions
|
||||||
|
from dcmanager.db import api as db_api
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
from dcmanager.orchestrator.states.base import BaseState
|
||||||
|
from dcmanager.orchestrator.states.software.cache.cache_specifications import \
|
||||||
|
REGION_ONE_LICENSE_CACHE_TYPE
|
||||||
|
|
||||||
|
# When a license is not installed, this will be part of the API error string
|
||||||
|
LICENSE_FILE_NOT_FOUND_SUBSTRING = "License file not found"
|
||||||
|
|
||||||
|
|
||||||
class InstallLicenseState(BaseState):
|
class InstallLicenseState(BaseState):
|
||||||
"""Install license software orchestration state"""
|
"""Software orchestration state action for installing a license"""
|
||||||
|
|
||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
super(InstallLicenseState, self).__init__(
|
super().__init__(
|
||||||
next_state=consts.STRATEGY_STATE_SW_UPLOAD,
|
next_state=consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY,
|
||||||
region_name=region_name,
|
region_name=region_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def license_up_to_date(target_license, existing_license):
|
||||||
|
return target_license == existing_license
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
def perform_state_action(self, strategy_step):
|
||||||
"""Install license region status"""
|
"""Install the License for a software deploy in this subcloud
|
||||||
|
|
||||||
|
Returns the next state in the state machine on success.
|
||||||
|
Any exceptions raised by this method set the strategy to FAILED.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# check if the system controller has a license
|
||||||
|
system_controller_license = self._read_from_cache(
|
||||||
|
REGION_ONE_LICENSE_CACHE_TYPE)
|
||||||
|
# get_license returns a dictionary with keys: content and error
|
||||||
|
# 'content' can be an empty string in success or failure case.
|
||||||
|
# 'error' is an empty string only in success case.
|
||||||
|
target_license = system_controller_license.get('content')
|
||||||
|
target_error = system_controller_license.get('error')
|
||||||
|
|
||||||
|
# If the system controller does not have a license, do not attempt
|
||||||
|
# to install licenses on subclouds, simply proceed to the next stage
|
||||||
|
if len(target_error) != 0:
|
||||||
|
if LICENSE_FILE_NOT_FOUND_SUBSTRING in target_error:
|
||||||
|
self.info_log(strategy_step,
|
||||||
|
f"System Controller License missing: {target_error}.")
|
||||||
|
return self.next_state
|
||||||
|
else:
|
||||||
|
# An unexpected error occurred querying the license
|
||||||
|
message = ('An unexpected error occurred querying the license '
|
||||||
|
f'{dccommon_consts.SYSTEM_CONTROLLER_NAME}. '
|
||||||
|
f'Detail: {target_error}')
|
||||||
|
db_api.subcloud_update(
|
||||||
|
self.context, strategy_step.subcloud_id,
|
||||||
|
error_description=message[0:consts.ERROR_DESCRIPTION_LENGTH])
|
||||||
|
raise exceptions.LicenseInstallError(
|
||||||
|
subcloud_id=dccommon_consts.SYSTEM_CONTROLLER_NAME,
|
||||||
|
error_message=target_error)
|
||||||
|
|
||||||
|
# retrieve the keystone session for the subcloud and query its license
|
||||||
|
subcloud_sysinv_client = self.get_sysinv_client(
|
||||||
|
strategy_step.subcloud.region_name)
|
||||||
|
subcloud_license_response = subcloud_sysinv_client.get_license()
|
||||||
|
subcloud_license = subcloud_license_response.get('content')
|
||||||
|
subcloud_error = subcloud_license_response.get('error')
|
||||||
|
|
||||||
|
# Skip license install if the license is already up to date
|
||||||
|
# If there was not an error, there might be a license
|
||||||
|
if len(subcloud_error) == 0:
|
||||||
|
if self.license_up_to_date(target_license, subcloud_license):
|
||||||
|
self.info_log(strategy_step, "License up to date.")
|
||||||
|
return self.next_state
|
||||||
|
else:
|
||||||
|
self.debug_log(strategy_step, "License mismatch. Updating.")
|
||||||
|
else:
|
||||||
|
self.debug_log(strategy_step, "License missing. Installing.")
|
||||||
|
|
||||||
|
# Install the license
|
||||||
|
install_rc = subcloud_sysinv_client.install_license(target_license)
|
||||||
|
install_error = install_rc.get('error')
|
||||||
|
if len(install_error) != 0:
|
||||||
|
# Save error response from sysinv into subcloud error description.
|
||||||
|
# Provide exception with sysinv error response to strategy_step details
|
||||||
|
message = ('Error installing license on subcloud '
|
||||||
|
f'{strategy_step.subcloud.name}. Detail: {install_error}')
|
||||||
|
db_api.subcloud_update(
|
||||||
|
self.context, strategy_step.subcloud_id,
|
||||||
|
error_description=message[0:consts.ERROR_DESCRIPTION_LENGTH])
|
||||||
|
raise exceptions.LicenseInstallError(
|
||||||
|
subcloud_id=strategy_step.subcloud_id,
|
||||||
|
error_message=install_error)
|
||||||
|
|
||||||
|
# The license has been successfully installed. Move to the next stage
|
||||||
|
self.info_log(strategy_step, "License installed.")
|
||||||
return self.next_state
|
return self.next_state
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.lock_host import LockHostState
|
|
||||||
|
|
||||||
|
|
||||||
class LockControllerState(LockHostState):
|
|
||||||
"""Lock controller software orchestration state"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(LockControllerState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_HOST,
|
|
||||||
region_name=region_name,
|
|
||||||
hostname=self.get_hostname(region_name)
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_hostname(self, region_name):
|
|
||||||
subcloud_type = self.get_sysinv_client(
|
|
||||||
region_name).get_system().system_mode
|
|
||||||
if subcloud_type == consts.SYSTEM_MODE_SIMPLEX:
|
|
||||||
return "controller-0"
|
|
||||||
else:
|
|
||||||
return "controller-1"
|
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -12,7 +12,7 @@ class PreCheckState(BaseState):
|
|||||||
"""Pre check software orchestration state"""
|
"""Pre check software orchestration state"""
|
||||||
|
|
||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
super(PreCheckState, self).__init__(
|
super().__init__(
|
||||||
next_state=consts.STRATEGY_STATE_SW_INSTALL_LICENSE,
|
next_state=consts.STRATEGY_STATE_SW_INSTALL_LICENSE,
|
||||||
region_name=region_name,
|
region_name=region_name,
|
||||||
)
|
)
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.swact_host import SwactHostState
|
|
||||||
|
|
||||||
|
|
||||||
class SwactController0State(SwactHostState):
|
|
||||||
"""Software orchestration state to swact away from controller-0"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(SwactController0State, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY,
|
|
||||||
region_name=region_name,
|
|
||||||
active="controller-1",
|
|
||||||
standby="controller-0",)
|
|
@ -1,18 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.swact_host import SwactHostState
|
|
||||||
|
|
||||||
|
|
||||||
class SwactController1State(SwactHostState):
|
|
||||||
"""Software orchestration state to swact away from controller-1"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(SwactController1State, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE,
|
|
||||||
region_name=region_name,
|
|
||||||
active="controller-0",
|
|
||||||
standby="controller-1")
|
|
@ -1,22 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
|
|
||||||
|
|
||||||
class UnlockControllerState(BaseState):
|
|
||||||
"""Unlock controller software orchestration state"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(UnlockControllerState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE,
|
|
||||||
region_name=region_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Unlock controller region status"""
|
|
||||||
return self.next_state
|
|
@ -1,155 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
|
|
||||||
from dccommon.drivers.openstack import software_v1
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.common.exceptions import StrategyStoppedException
|
|
||||||
from dcmanager.common import utils
|
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
|
||||||
from dcmanager.orchestrator.states.software.cache.cache_specifications import \
|
|
||||||
REGION_ONE_RELEASE_USM_CACHE_TYPE
|
|
||||||
|
|
||||||
# Max time: 30 minutes = 180 queries x 10 seconds between
|
|
||||||
DEFAULT_MAX_QUERIES = 180
|
|
||||||
DEFAULT_SLEEP_DURATION = 10
|
|
||||||
|
|
||||||
|
|
||||||
class UploadState(BaseState):
|
|
||||||
"""Software orchestration state for uploading releases"""
|
|
||||||
|
|
||||||
def __init__(self, region_name):
|
|
||||||
super(UploadState, self).__init__(
|
|
||||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_PRE_CHECK,
|
|
||||||
region_name=region_name)
|
|
||||||
self.sleep_duration = DEFAULT_SLEEP_DURATION
|
|
||||||
self.max_queries = DEFAULT_MAX_QUERIES
|
|
||||||
|
|
||||||
def _get_major_minor_versions(self, release_sw_version):
|
|
||||||
return release_sw_version.rsplit('.', 1)
|
|
||||||
|
|
||||||
def _find_missing_patches(self, subcloud_releases,
|
|
||||||
potential_missing_patches):
|
|
||||||
|
|
||||||
return [potential_missing_patch for potential_missing_patch
|
|
||||||
in potential_missing_patches
|
|
||||||
if potential_missing_patch not in subcloud_releases]
|
|
||||||
|
|
||||||
def perform_state_action(self, strategy_step):
|
|
||||||
"""Upload releases in this subcloud"""
|
|
||||||
self.info_log(strategy_step, "Uploading releases")
|
|
||||||
|
|
||||||
regionone_releases = self._read_from_cache(REGION_ONE_RELEASE_USM_CACHE_TYPE)
|
|
||||||
applied_releases_ids = list()
|
|
||||||
for release_id in regionone_releases:
|
|
||||||
if regionone_releases[release_id]['state'] in [
|
|
||||||
software_v1.DEPLOYED,
|
|
||||||
software_v1.COMMITTED]:
|
|
||||||
applied_releases_ids.append(release_id)
|
|
||||||
|
|
||||||
# Retrieve all subcloud releases
|
|
||||||
try:
|
|
||||||
subcloud_releases = self.get_software_client(
|
|
||||||
self.region_name).query()
|
|
||||||
except Exception:
|
|
||||||
message = ("Cannot retrieve subcloud releases. Please "
|
|
||||||
"see /var/log/software.log for details.")
|
|
||||||
self.exception_log(strategy_step, message)
|
|
||||||
raise Exception(message)
|
|
||||||
|
|
||||||
releases_to_upload = []
|
|
||||||
|
|
||||||
# RegionOne applied releases not present on the subcloud needs to be uploaded
|
|
||||||
for release_id in applied_releases_ids:
|
|
||||||
if release_id not in subcloud_releases:
|
|
||||||
self.info_log(strategy_step, (f"Release {release_id} missing from "
|
|
||||||
"subloud"))
|
|
||||||
releases_to_upload.append(release_id)
|
|
||||||
|
|
||||||
if releases_to_upload:
|
|
||||||
self.info_log(strategy_step,
|
|
||||||
f"Uploading releases {releases_to_upload} to subcloud")
|
|
||||||
|
|
||||||
files_to_upload = []
|
|
||||||
potential_missing_patches = []
|
|
||||||
iso_release = None
|
|
||||||
for release in releases_to_upload:
|
|
||||||
major_sw_version, minor_sw_version = self._get_major_minor_versions(
|
|
||||||
regionone_releases[release]['sw_version'])
|
|
||||||
|
|
||||||
# when minor is 0, it means that the release is an iso
|
|
||||||
if minor_sw_version == consts.ISO_VERSION:
|
|
||||||
iso_path, sig_path = utils.get_vault_load_files(major_sw_version)
|
|
||||||
files_to_upload.extend([iso_path, sig_path])
|
|
||||||
iso_release = release
|
|
||||||
else:
|
|
||||||
patch_path = (f"{consts.RELEASE_VAULT_DIR}/"
|
|
||||||
f"{major_sw_version}/{release}.patch")
|
|
||||||
if not os.path.isfile(patch_path):
|
|
||||||
# patch wasn't found but it may be included in an iso
|
|
||||||
potential_missing_patches.append(release)
|
|
||||||
else:
|
|
||||||
files_to_upload.append(patch_path)
|
|
||||||
if files_to_upload:
|
|
||||||
try:
|
|
||||||
self.get_software_client(
|
|
||||||
self.region_name).upload(files_to_upload)
|
|
||||||
except Exception:
|
|
||||||
message = ("Cannot upload releases to subcloud. Please "
|
|
||||||
"see /var/log/software.log for details.")
|
|
||||||
self.exception_log(strategy_step, message)
|
|
||||||
raise Exception(message)
|
|
||||||
|
|
||||||
if self.stopped():
|
|
||||||
self.info_log(strategy_step, "Exiting because task was stopped")
|
|
||||||
raise StrategyStoppedException()
|
|
||||||
|
|
||||||
if iso_release:
|
|
||||||
audit_counter = 0
|
|
||||||
while True:
|
|
||||||
time.sleep(self.sleep_duration)
|
|
||||||
|
|
||||||
if self.stopped():
|
|
||||||
raise StrategyStoppedException()
|
|
||||||
|
|
||||||
try:
|
|
||||||
subcloud_releases = self.get_software_client(
|
|
||||||
self.region_name).query()
|
|
||||||
except Exception:
|
|
||||||
self.debug_log(strategy_step, "failed to retrieve releases.")
|
|
||||||
|
|
||||||
if iso_release in subcloud_releases:
|
|
||||||
if potential_missing_patches:
|
|
||||||
# Retrieve patches that are present in the system
|
|
||||||
# controller and not in the subcloud after uploading
|
|
||||||
# load to the subcloud.
|
|
||||||
missing_patches = self. \
|
|
||||||
_find_missing_patches(subcloud_releases,
|
|
||||||
potential_missing_patches)
|
|
||||||
|
|
||||||
if missing_patches:
|
|
||||||
message = (f"Release files {missing_patches} "
|
|
||||||
"are missing")
|
|
||||||
self.error_log(strategy_step, message)
|
|
||||||
raise Exception(message)
|
|
||||||
break
|
|
||||||
audit_counter += 1
|
|
||||||
if audit_counter >= self.max_queries:
|
|
||||||
details = ("Timeout waiting for load import to complete. "
|
|
||||||
"Please check software.log on the subcloud.")
|
|
||||||
self.exception_log(strategy_step, details)
|
|
||||||
raise Exception(details)
|
|
||||||
else:
|
|
||||||
# No load was uploaded therefore the patches are really missing.
|
|
||||||
if potential_missing_patches:
|
|
||||||
message = (f"Release files {potential_missing_patches} "
|
|
||||||
"are missing")
|
|
||||||
self.error_log(strategy_step, message)
|
|
||||||
raise Exception(message)
|
|
||||||
|
|
||||||
return self.next_state
|
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -11,9 +11,9 @@ from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|||||||
|
|
||||||
class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestApplyVIMSoftwareStrategyState, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_1
|
self.on_success_state = consts.STRATEGY_STATE_SW_FINISH_STRATEGY
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
# Add the subcloud being processed by this unit test
|
||||||
self.subcloud = self.setup_subcloud()
|
self.subcloud = self.setup_subcloud()
|
||||||
@ -28,5 +28,5 @@ class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
|||||||
self.worker.perform_state_action(self.strategy_step)
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
# On success, the state should transition to the next state
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
self.assert_step_updated(
|
||||||
self.on_success_state)
|
self.strategy_step.subcloud_id, self.on_success_state)
|
||||||
|
@ -18,15 +18,15 @@ class TestSoftwareOrchestrator(TestSwUpdate):
|
|||||||
DEFAULT_STRATEGY_TYPE = consts.SW_UPDATE_TYPE_SOFTWARE
|
DEFAULT_STRATEGY_TYPE = consts.SW_UPDATE_TYPE_SOFTWARE
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestSoftwareOrchestrator, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
# Modify cache helpers to return client mocks
|
# Modify cache helpers to return client mocks
|
||||||
self.software_cache_client_mock = mock.patch(
|
self.software_cache_client_mock = mock.patch(
|
||||||
"%s.get_software_client" % CACHE_CLIENT_PATH,
|
f"{CACHE_CLIENT_PATH}.get_software_client",
|
||||||
return_value=self.software_client,
|
return_value=self.software_client,
|
||||||
)
|
)
|
||||||
self.sysinv_cache_client_mock = mock.patch(
|
self.sysinv_cache_client_mock = mock.patch(
|
||||||
"%s.get_sysinv_client" % CACHE_CLIENT_PATH,
|
f"{CACHE_CLIENT_PATH}.get_sysinv_client",
|
||||||
return_value=self.sysinv_client
|
return_value=self.sysinv_client
|
||||||
)
|
)
|
||||||
self.software_cache_client_mock.start()
|
self.software_cache_client_mock.start()
|
||||||
@ -35,4 +35,4 @@ class TestSoftwareOrchestrator(TestSwUpdate):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.software_cache_client_mock.stop()
|
self.software_cache_client_mock.stop()
|
||||||
self.sysinv_cache_client_mock.stop()
|
self.sysinv_cache_client_mock.stop()
|
||||||
super(TestSoftwareOrchestrator, self).tearDown()
|
super().tearDown()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -11,7 +11,7 @@ from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|||||||
|
|
||||||
class TestCreateVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
class TestCreateVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCreateVIMSoftwareStrategyState, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_APPLY_VIM_STRATEGY
|
self.on_success_state = consts.STRATEGY_STATE_SW_APPLY_VIM_STRATEGY
|
||||||
|
|
||||||
@ -28,5 +28,5 @@ class TestCreateVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
|||||||
self.worker.perform_state_action(self.strategy_step)
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
# On success, the state should transition to the next state
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
self.assert_step_updated(
|
||||||
self.on_success_state)
|
self.strategy_step.subcloud_id, self.on_success_state)
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
class TestDeployActivateState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDeployActivateState, self).setUp()
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_COMPLETE
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE)
|
|
||||||
|
|
||||||
def test_deploy_activate_success(self):
|
|
||||||
"""Test deploy activate when the API call succeeds."""
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
@ -1,32 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
class TestDeployCompleteState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDeployCompleteState, self).setUp()
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_FINISH_STRATEGY
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_DEPLOY_COMPLETE)
|
|
||||||
|
|
||||||
def test_deploy_complete_success(self):
|
|
||||||
"""Test deploy complete when the API call succeeds."""
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
@ -1,32 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
class TestDeployHostState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDeployHostState, self).setUp()
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_UNLOCK_CONTROLLER
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_DEPLOY_HOST)
|
|
||||||
|
|
||||||
def test_deploy_host_success(self):
|
|
||||||
"""Test deploy host when the API call succeeds."""
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
@ -1,32 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
class TestDeployPreCheckState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDeployPreCheckState, self).setUp()
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_START
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_DEPLOY_PRE_CHECK)
|
|
||||||
|
|
||||||
def test_deploy_pre_check_success(self):
|
|
||||||
"""Test deploy pre check when the API call succeeds."""
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
@ -1,133 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.software.deploy_start import DeployStartState
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.fakes import FakeSystem
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
REGION_ONE_RR_RELEASES = {
|
|
||||||
"stx_23.09.0": {
|
|
||||||
"sw_version": "23.09.0",
|
|
||||||
"state": "deployed",
|
|
||||||
"reboot_required": "Y",
|
|
||||||
},
|
|
||||||
"stx_23.09.1": {
|
|
||||||
"sw_version": "23.09.1",
|
|
||||||
"state": "deployed",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
"stx_23.09.2": {
|
|
||||||
"sw_version": "23.09.1",
|
|
||||||
"state": "deployed",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
REGION_ONE_NRR_RELEASES = {
|
|
||||||
"stx_23.09.0": {
|
|
||||||
"sw_version": "23.09.0",
|
|
||||||
"state": "deployed",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
"stx_23.09.1": {
|
|
||||||
"sw_version": "23.09.1",
|
|
||||||
"state": "deployed",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCLOUD_RR_RELEASES = {
|
|
||||||
"stx_23.09.0": {
|
|
||||||
"sw_version": "23.09.0",
|
|
||||||
"state": "available",
|
|
||||||
"reboot_required": "Y",
|
|
||||||
},
|
|
||||||
"stx_23.09.1": {
|
|
||||||
"sw_version": "23.09.1",
|
|
||||||
"state": "available",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
"stx_23.09.2": {
|
|
||||||
"sw_version": "23.09.1",
|
|
||||||
"state": "available",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
SUBCLOUD_NRR_RELEASES = {
|
|
||||||
"stx_23.09.0": {
|
|
||||||
"sw_version": "23.09.0",
|
|
||||||
"state": "available",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
"stx_23.09.1": {
|
|
||||||
"sw_version": "23.09.1",
|
|
||||||
"state": "available",
|
|
||||||
"reboot_required": "N",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestDeployStartState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestDeployStartState, self).setUp()
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_HOST
|
|
||||||
self.on_success_lock_state = consts.STRATEGY_STATE_SW_LOCK_CONTROLLER
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_DEPLOY_START
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add mock API endpoints for sysinv client calls invoked by this state
|
|
||||||
self.sysinv_client.get_system = mock.MagicMock()
|
|
||||||
system_values = FakeSystem()
|
|
||||||
system_values.system_mode = consts.SYSTEM_MODE_SIMPLEX
|
|
||||||
self.sysinv_client.get_system.return_value = system_values
|
|
||||||
|
|
||||||
# Add mock API endpoints for software client calls invoked by this state
|
|
||||||
self.software_client.query = mock.MagicMock()
|
|
||||||
self.software_client.deploy_start = mock.MagicMock()
|
|
||||||
|
|
||||||
self._read_from_cache = mock.MagicMock()
|
|
||||||
|
|
||||||
@mock.patch.object(DeployStartState, "_read_from_cache")
|
|
||||||
def test_deploy_start_nrr_success(self, mock_read_from_cache):
|
|
||||||
"""Test deploy start when the API call succeeds."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_NRR_RELEASES
|
|
||||||
self.software_client.query.side_effect = [SUBCLOUD_NRR_RELEASES]
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.deploy_start.assert_called_once_with("stx_23.09.1")
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(
|
|
||||||
self.strategy_step.subcloud_id, self.on_success_state
|
|
||||||
)
|
|
||||||
|
|
||||||
@mock.patch.object(DeployStartState, "_read_from_cache")
|
|
||||||
def test_deploy_start_rr_success(self, mock_read_from_cache):
|
|
||||||
"""Test deploy start when the API call succeeds."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RR_RELEASES
|
|
||||||
self.software_client.query.side_effect = [SUBCLOUD_RR_RELEASES]
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.deploy_start.assert_called_once_with("stx_23.09.2")
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(
|
|
||||||
self.strategy_step.subcloud_id, self.on_success_lock_state
|
|
||||||
)
|
|
@ -1,9 +1,10 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
@ -38,7 +39,7 @@ class TestFinishStrategyState(TestSoftwareOrchestrator):
|
|||||||
self.mock_use_usm = p.start()
|
self.mock_use_usm = p.start()
|
||||||
self.mock_use_usm.return_value = True
|
self.mock_use_usm.return_value = True
|
||||||
self.addCleanup(p.stop)
|
self.addCleanup(p.stop)
|
||||||
super(TestFinishStrategyState, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_COMPLETE
|
self.on_success_state = consts.STRATEGY_STATE_COMPLETE
|
||||||
|
|
||||||
|
@ -1,35 +1,165 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
||||||
TestSoftwareOrchestrator
|
TestSoftwareOrchestrator
|
||||||
|
|
||||||
|
MISSING_LICENSE_RESPONSE = {
|
||||||
|
"content": "",
|
||||||
|
"error": "License file not found. A license may not have been installed.",
|
||||||
|
}
|
||||||
|
|
||||||
|
LICENSE_VALID_RESPONSE = {"content": "A valid license", "error": ""}
|
||||||
|
|
||||||
|
ALTERNATE_LICENSE_RESPONSE = {"content": "A different valid license", "error": ""}
|
||||||
|
|
||||||
|
|
||||||
class TestInstallLicenseState(TestSoftwareOrchestrator):
|
class TestInstallLicenseState(TestSoftwareOrchestrator):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestInstallLicenseState, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
# next state after install a license is 'upload'
|
# next state after install a license is 'upload'
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_UPLOAD
|
self.on_success_state = consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
# Add the subcloud being processed by this unit test
|
||||||
self.subcloud = self.setup_subcloud()
|
self.subcloud = self.setup_subcloud()
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
# Add the strategy_step state being processed by this unit test
|
||||||
self.strategy_step = self.setup_strategy_step(
|
self.strategy_step = self.setup_strategy_step(
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_INSTALL_LICENSE)
|
self.subcloud.id, consts.STRATEGY_STATE_SW_INSTALL_LICENSE
|
||||||
|
)
|
||||||
|
|
||||||
def test_upgrade_subcloud_license_install_success(self):
|
# Add mock API endpoints for sysinv client calls invoked by this state
|
||||||
"""Test the install license step succeeds."""
|
self.sysinv_client.get_license = mock.MagicMock()
|
||||||
|
self.sysinv_client.install_license = mock.MagicMock()
|
||||||
|
|
||||||
|
def test_install_license_failure(self):
|
||||||
|
"""Test the installing license step where the install fails.
|
||||||
|
|
||||||
|
The system controller has a license, but the API call to install on the
|
||||||
|
subcloud fails.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Order of get_license calls:
|
||||||
|
# first license query is to system controller
|
||||||
|
# second license query is to subcloud (should be missing)
|
||||||
|
self.sysinv_client.get_license.side_effect = [
|
||||||
|
LICENSE_VALID_RESPONSE,
|
||||||
|
MISSING_LICENSE_RESPONSE,
|
||||||
|
]
|
||||||
|
|
||||||
|
# Simulate a license install failure on the subcloud
|
||||||
|
self.sysinv_client.install_license.return_value = MISSING_LICENSE_RESPONSE
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
# invoke the strategy state operation on the orch thread
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# verify the license install was invoked
|
||||||
|
self.sysinv_client.install_license.assert_called()
|
||||||
|
|
||||||
|
# Verify a install_license failure leads to a state failure
|
||||||
|
self.assert_step_updated(
|
||||||
|
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_install_license_success(self):
|
||||||
|
"""Test the install license step succeeds.
|
||||||
|
|
||||||
|
The license will be installed on the subcloud when system controller
|
||||||
|
has a license, the subcloud does not have a license, and the API call
|
||||||
|
succeeds.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Order of get_license calls:
|
||||||
|
# first license query is to system controller
|
||||||
|
# second license query is to subcloud (should be missing)
|
||||||
|
self.sysinv_client.get_license.side_effect = [
|
||||||
|
LICENSE_VALID_RESPONSE,
|
||||||
|
MISSING_LICENSE_RESPONSE,
|
||||||
|
]
|
||||||
|
|
||||||
|
# A license install should return a success
|
||||||
|
self.sysinv_client.install_license.return_value = LICENSE_VALID_RESPONSE
|
||||||
|
|
||||||
|
# invoke the strategy state operation on the orch thread
|
||||||
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# verify the license install was invoked
|
||||||
|
self.sysinv_client.install_license.assert_called()
|
||||||
|
|
||||||
# On success, the next state after installing license is importing load
|
# On success, the next state after installing license is importing load
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
self.assert_step_updated(
|
||||||
self.on_success_state)
|
self.strategy_step.subcloud_id, self.on_success_state
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_install_license_skip_existing(self):
|
||||||
|
"""Test the install license step skipped due to license up to date"""
|
||||||
|
|
||||||
|
# Order of get_license calls:
|
||||||
|
# first license query is to system controller
|
||||||
|
# second license query is to subcloud
|
||||||
|
self.sysinv_client.get_license.side_effect = [
|
||||||
|
LICENSE_VALID_RESPONSE,
|
||||||
|
LICENSE_VALID_RESPONSE,
|
||||||
|
]
|
||||||
|
|
||||||
|
# invoke the strategy state operation on the orch thread
|
||||||
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# A license install should not have been attempted due to the license
|
||||||
|
# already being up to date
|
||||||
|
self.sysinv_client.install_license.assert_not_called()
|
||||||
|
|
||||||
|
# On success, the next state after installing license is importing load
|
||||||
|
self.assert_step_updated(
|
||||||
|
self.strategy_step.subcloud_id, self.on_success_state
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_install_license_overrides_mismatched_license(self):
|
||||||
|
"""Test the install license overrides a mismatched license"""
|
||||||
|
|
||||||
|
# Order of get_license calls:
|
||||||
|
# first license query is to system controller
|
||||||
|
# second license query is to subcloud (should be valid but different)
|
||||||
|
self.sysinv_client.get_license.side_effect = [
|
||||||
|
LICENSE_VALID_RESPONSE,
|
||||||
|
ALTERNATE_LICENSE_RESPONSE,
|
||||||
|
]
|
||||||
|
|
||||||
|
# A license install should return a success
|
||||||
|
self.sysinv_client.install_license.return_value = LICENSE_VALID_RESPONSE
|
||||||
|
|
||||||
|
# invoke the strategy state operation on the orch thread
|
||||||
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# verify the license install was invoked
|
||||||
|
self.sysinv_client.install_license.assert_called()
|
||||||
|
|
||||||
|
# Verify it successfully moves to the next step
|
||||||
|
self.assert_step_updated(
|
||||||
|
self.strategy_step.subcloud_id, self.on_success_state
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_install_license_skip_when_no_sys_controller_lic(self):
|
||||||
|
"""Test license install skipped when no license on system controller."""
|
||||||
|
|
||||||
|
# Only makes one query: to system controller
|
||||||
|
self.sysinv_client.get_license.return_value = MISSING_LICENSE_RESPONSE
|
||||||
|
|
||||||
|
# invoke the strategy state operation on the orch thread
|
||||||
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# Should skip install_license API call
|
||||||
|
self.sysinv_client.install_license.assert_not_called()
|
||||||
|
|
||||||
|
# Verify it successfully moves to the next step
|
||||||
|
self.assert_step_updated(
|
||||||
|
self.strategy_step.subcloud_id, self.on_success_state
|
||||||
|
)
|
||||||
|
@ -1,181 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
import itertools
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states import lock_host
|
|
||||||
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.fakes import FakeController
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.fakes import FakeSystem
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.lock_host.DEFAULT_MAX_QUERIES", 3)
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.lock_host.DEFAULT_SLEEP_DURATION", 1)
|
|
||||||
class TestSwLockSimplexStage(TestSoftwareOrchestrator):
|
|
||||||
|
|
||||||
state = consts.STRATEGY_STATE_SW_LOCK_CONTROLLER
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestSwLockSimplexStage, self).setUp()
|
|
||||||
|
|
||||||
# next state after a successful lock is deploy host
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_HOST
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(self.subcloud.id, self.state)
|
|
||||||
|
|
||||||
# Add mock API endpoints for sysinv client calls invoked by this state
|
|
||||||
self.sysinv_client.get_host = mock.MagicMock()
|
|
||||||
self.sysinv_client.lock_host = mock.MagicMock()
|
|
||||||
self.sysinv_client.get_system = mock.MagicMock()
|
|
||||||
system_values = FakeSystem()
|
|
||||||
system_values.system_mode = consts.SYSTEM_MODE_SIMPLEX
|
|
||||||
self.sysinv_client.get_system.return_value = system_values
|
|
||||||
self.setup_fake_controllers('controller-0')
|
|
||||||
|
|
||||||
def setup_fake_controllers(self, host_name):
|
|
||||||
self.CONTROLLER_UNLOCKED = FakeController(
|
|
||||||
hostname=host_name, administrative=consts.ADMIN_UNLOCKED
|
|
||||||
)
|
|
||||||
self.CONTROLLER_LOCKED = FakeController(hostname=host_name,
|
|
||||||
administrative=consts.ADMIN_LOCKED)
|
|
||||||
self.CONTROLLER_LOCKING = FakeController(
|
|
||||||
hostname=host_name,
|
|
||||||
administrative=consts.ADMIN_UNLOCKED,
|
|
||||||
ihost_action='lock',
|
|
||||||
task='Locking'
|
|
||||||
)
|
|
||||||
self.CONTROLLER_LOCKING_FAILED = \
|
|
||||||
FakeController(hostname=host_name,
|
|
||||||
administrative=consts.ADMIN_UNLOCKED,
|
|
||||||
ihost_action='force-swact',
|
|
||||||
task='Swacting')
|
|
||||||
|
|
||||||
def test_lock_success(self):
|
|
||||||
"""Test the lock command returns a success"""
|
|
||||||
|
|
||||||
# mock the controller host queries
|
|
||||||
# first query is the starting state
|
|
||||||
# query 2,3 are are during the lock phase
|
|
||||||
# query 4 : the host is now locked
|
|
||||||
self.sysinv_client.get_host.side_effect = [self.CONTROLLER_UNLOCKED,
|
|
||||||
self.CONTROLLER_LOCKING,
|
|
||||||
self.CONTROLLER_LOCKING,
|
|
||||||
self.CONTROLLER_LOCKED]
|
|
||||||
|
|
||||||
# mock the API call as failed on the subcloud
|
|
||||||
self.sysinv_client.lock_host.return_value = self.CONTROLLER_LOCKING
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the lock command was actually attempted
|
|
||||||
self.sysinv_client.lock_host.assert_called()
|
|
||||||
|
|
||||||
# verify that the API moved to the next state on success
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
||||||
|
|
||||||
def test_lock_skipped_when_already_locked(self):
|
|
||||||
"""Test the lock command skips if host is already locked"""
|
|
||||||
|
|
||||||
# mock the controller host query as being already locked
|
|
||||||
self.sysinv_client.get_host.return_value = self.CONTROLLER_LOCKED
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the lock command was never attempted
|
|
||||||
self.sysinv_client.lock_host.assert_not_called()
|
|
||||||
|
|
||||||
# verify that the state moves to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
||||||
|
|
||||||
def test_lock_attempt_timeout(self):
|
|
||||||
"""Test lock invoked and fails if timeout before host becomes locked"""
|
|
||||||
|
|
||||||
# mock the get_host queries
|
|
||||||
# first query is the starting state
|
|
||||||
# all remaining queries, the host returns 'locking'
|
|
||||||
self.sysinv_client.get_host.side_effect = itertools.chain(
|
|
||||||
[self.CONTROLLER_UNLOCKED, ],
|
|
||||||
itertools.repeat(self.CONTROLLER_LOCKING))
|
|
||||||
|
|
||||||
# mock the API call as successful on the subcloud
|
|
||||||
self.sysinv_client.lock_host.return_value = self.CONTROLLER_LOCKING
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the lock command was actually attempted
|
|
||||||
self.sysinv_client.lock_host.assert_called()
|
|
||||||
|
|
||||||
# verify the query was invoked: 1 + max_attempts times
|
|
||||||
self.assertEqual(lock_host.DEFAULT_MAX_QUERIES + 1,
|
|
||||||
self.sysinv_client.get_host.call_count)
|
|
||||||
|
|
||||||
# verify that state failed due to subcloud never finishing the lock
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
consts.STRATEGY_STATE_FAILED)
|
|
||||||
|
|
||||||
def test_lock_failure(self):
|
|
||||||
"""Test the lock command returns a failure"""
|
|
||||||
|
|
||||||
# mock the controller get_host query
|
|
||||||
self.sysinv_client.get_host.return_value = self.CONTROLLER_UNLOCKED
|
|
||||||
|
|
||||||
# mock the API call as failed on the subcloud
|
|
||||||
self.sysinv_client.lock_host.return_value = self.CONTROLLER_LOCKING_FAILED
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the lock command was actually attempted
|
|
||||||
self.sysinv_client.lock_host.assert_called()
|
|
||||||
|
|
||||||
# verify that the API error for the lock leads to a failed state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
consts.STRATEGY_STATE_FAILED)
|
|
||||||
|
|
||||||
def test_lock_fails_when_host_query_fails(self):
|
|
||||||
"""Test the lock command fails when it cannot get the controllers"""
|
|
||||||
|
|
||||||
# mock the get_host query is empty and raises an exception
|
|
||||||
self.sysinv_client.get_host.side_effect = \
|
|
||||||
Exception("Unable to find host controller-0")
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the lock command was never attempted
|
|
||||||
self.sysinv_client.lock_host.assert_not_called()
|
|
||||||
|
|
||||||
# verify that the state moves to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
consts.STRATEGY_STATE_FAILED)
|
|
||||||
|
|
||||||
|
|
||||||
class TestSwLockDuplexStage(TestSwLockSimplexStage):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.state = consts.STRATEGY_STATE_SW_LOCK_CONTROLLER
|
|
||||||
super(TestSwLockDuplexStage, self).setUp()
|
|
||||||
system_values = FakeSystem()
|
|
||||||
system_values.system_mode = consts.SYSTEM_MODE_DUPLEX
|
|
||||||
self.sysinv_client.get_system.return_value = system_values
|
|
||||||
# next state after a successful lock is deploy host
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_HOST
|
|
||||||
|
|
||||||
# Add mock API endpoints for sysinv client calls invoked by this state
|
|
||||||
self.setup_fake_controllers('controller-1')
|
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -11,7 +11,7 @@ from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|||||||
|
|
||||||
class TestPreCheckState(TestSoftwareOrchestrator):
|
class TestPreCheckState(TestSoftwareOrchestrator):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestPreCheckState, self).setUp()
|
super().setUp()
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_INSTALL_LICENSE
|
self.on_success_state = consts.STRATEGY_STATE_SW_INSTALL_LICENSE
|
||||||
|
|
||||||
|
@ -1,148 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
import itertools
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states import swact_host
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.fakes import FakeController
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.swact_host.DEFAULT_SWACT_SLEEP", 1)
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.swact_host.DEFAULT_MAX_QUERIES", 3)
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.swact_host.DEFAULT_SLEEP_DURATION", 1)
|
|
||||||
class TestSwactController0State(TestSoftwareOrchestrator):
|
|
||||||
state = consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_0
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestSwactController0State, self).setUp()
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(self.subcloud.id, self.state)
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY
|
|
||||||
|
|
||||||
# Add mock API endpoints for sysinv client calls invoked by this state
|
|
||||||
self.sysinv_client.get_host = mock.MagicMock()
|
|
||||||
self.sysinv_client.swact_host = mock.MagicMock()
|
|
||||||
|
|
||||||
# In order to swact to controller-1, we run "system host-swact controller-0"
|
|
||||||
self.setup_fake_controllers("controller-0")
|
|
||||||
|
|
||||||
def setup_fake_controllers(self, host_name):
|
|
||||||
self.CONTROLLER_ACTIVE = FakeController(hostname=host_name)
|
|
||||||
self.CONTROLLER_STANDBY = FakeController(
|
|
||||||
hostname=host_name, capabilities={"Personality": "Controller-Standby"}
|
|
||||||
)
|
|
||||||
self.CONTROLLER_SWACTING = FakeController(
|
|
||||||
hostname=host_name, task="Swacting"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_swact_controller_success(self):
|
|
||||||
"""Test swact controller when the API call succeeds."""
|
|
||||||
|
|
||||||
# mock the controller host queries
|
|
||||||
# first query is the starting state
|
|
||||||
# query 2 is during the ongoing swact phase
|
|
||||||
# query 3 is after successful host swact
|
|
||||||
self.sysinv_client.get_host.side_effect = [
|
|
||||||
self.CONTROLLER_STANDBY,
|
|
||||||
self.CONTROLLER_STANDBY,
|
|
||||||
self.CONTROLLER_ACTIVE,
|
|
||||||
]
|
|
||||||
|
|
||||||
# mock the API call as failed on the subcloud
|
|
||||||
self.sysinv_client.swact_host.return_value = self.CONTROLLER_SWACTING
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the swact command was actually attempted
|
|
||||||
self.sysinv_client.swact_host.assert_called()
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(
|
|
||||||
self.strategy_step.subcloud_id, self.on_success_state
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_swact_skipped_when_already_active(self):
|
|
||||||
"""Test the swact command skips if host is already active controller"""
|
|
||||||
# mock the controller host query as being already Controller-Active
|
|
||||||
self.sysinv_client.get_host.return_value = self.CONTROLLER_ACTIVE
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the swact command was never attempted
|
|
||||||
self.sysinv_client.swact_host.assert_not_called()
|
|
||||||
|
|
||||||
# verify that the state moves to the next state
|
|
||||||
self.assert_step_updated(
|
|
||||||
self.strategy_step.subcloud_id, self.on_success_state
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_swact_attempt_timeout(self):
|
|
||||||
"""Test swact invoked and fails if timeout"""
|
|
||||||
# mock the get_host queries
|
|
||||||
# all remaining queries, the host returns 'Controller-Standby'
|
|
||||||
self.sysinv_client.get_host.side_effect = itertools.chain(
|
|
||||||
itertools.repeat(self.CONTROLLER_STANDBY)
|
|
||||||
)
|
|
||||||
|
|
||||||
# mock the API call as successful on the subcloud
|
|
||||||
self.sysinv_client.swact_host.return_value = self.CONTROLLER_SWACTING
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the swact command was actually attempted
|
|
||||||
self.sysinv_client.swact_host.assert_called()
|
|
||||||
|
|
||||||
# verify the query was invoked: 1 + max_attempts times
|
|
||||||
self.assertEqual(
|
|
||||||
swact_host.DEFAULT_MAX_QUERIES + 2,
|
|
||||||
self.sysinv_client.get_host.call_count,
|
|
||||||
)
|
|
||||||
|
|
||||||
# verify that state failed due to subcloud never finishing the swact
|
|
||||||
self.assert_step_updated(
|
|
||||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_swact_fails_when_host_query_fails(self):
|
|
||||||
"""Test the swact command fails when it cannot get the controllers"""
|
|
||||||
|
|
||||||
# mock the get_host query is empty and raises an exception
|
|
||||||
self.sysinv_client.get_host.side_effect = Exception("Unable to find host")
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# verify the swact command was never attempted
|
|
||||||
self.sysinv_client.swact_host.assert_not_called()
|
|
||||||
|
|
||||||
# verify that the state moves to the next state
|
|
||||||
self.assert_step_updated(
|
|
||||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestSwactController1State(TestSwactController0State):
|
|
||||||
def setUp(self):
|
|
||||||
self.state = consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_1
|
|
||||||
super(TestSwactController1State, self).setUp()
|
|
||||||
|
|
||||||
# next state after a successful swact controller-1 is deploy activate
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE
|
|
||||||
|
|
||||||
# In order to swact to controller-0, we run "system host-swact controller-1"
|
|
||||||
self.setup_fake_controllers("controller-1")
|
|
@ -1,32 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
|
||||||
TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
|
|
||||||
class TestUnlockControllerState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestUnlockControllerState, self).setUp()
|
|
||||||
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_UNLOCK_CONTROLLER)
|
|
||||||
|
|
||||||
def test_unlock_controller_success(self):
|
|
||||||
"""Test unlock controller when the API call succeeds."""
|
|
||||||
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
@ -1,205 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2023-2024 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
from dcmanager.common import consts
|
|
||||||
from dcmanager.orchestrator.states.software.upload import UploadState
|
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base \
|
|
||||||
import TestSoftwareOrchestrator
|
|
||||||
|
|
||||||
REGION_ONE_RELEASES = {"DC_20.12.1": {"sw_version": "20.12.1",
|
|
||||||
"state": "deployed"},
|
|
||||||
"DC_20.12.2": {"sw_version": "20.12.2",
|
|
||||||
"state": "deployed"},
|
|
||||||
"DC_20.12.3": {"sw_version": "20.12.3",
|
|
||||||
"state": "committed"},
|
|
||||||
"DC_20.12.4": {"sw_version": "20.12.4",
|
|
||||||
"state": "committed"}}
|
|
||||||
|
|
||||||
|
|
||||||
REGION_ONE_RELEASES_2 = {"DC_20.12.1": {"sw_version": "20.12.1",
|
|
||||||
"state": "deployed"},
|
|
||||||
"DC_22.12.0": {"sw_version": "22.12.0",
|
|
||||||
"state": "deployed"},
|
|
||||||
"DC_20.12.2": {"sw_version": "20.12.2",
|
|
||||||
"state": "deployed"}}
|
|
||||||
|
|
||||||
REGION_ONE_RELEASES_3 = {"DC_22.12.1": {"sw_version": "22.12.1",
|
|
||||||
"state": "deployed"},
|
|
||||||
"DC_22.12.0": {"sw_version": "22.12.0",
|
|
||||||
"state": "deployed"}}
|
|
||||||
|
|
||||||
SUBCLOUD_RELEASES = {"DC_20.12.1": {"sw_version": "20.12.1",
|
|
||||||
"state": "deployed"},
|
|
||||||
"DC_20.12.2": {"sw_version": "20.12.2",
|
|
||||||
"state": "deployed"}}
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.software.upload."
|
|
||||||
"DEFAULT_MAX_QUERIES", 3)
|
|
||||||
@mock.patch("dcmanager.orchestrator.states.software.upload"
|
|
||||||
".DEFAULT_SLEEP_DURATION", 1)
|
|
||||||
class TestUploadState(TestSoftwareOrchestrator):
|
|
||||||
def setUp(self):
|
|
||||||
p = mock.patch.object(cfg.CONF, 'use_usm')
|
|
||||||
self.mock_use_usm = p.start()
|
|
||||||
self.mock_use_usm.return_value = True
|
|
||||||
self.addCleanup(p.stop)
|
|
||||||
super(TestUploadState, self).setUp()
|
|
||||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_PRE_CHECK
|
|
||||||
|
|
||||||
# Add the subcloud being processed by this unit test
|
|
||||||
self.subcloud = self.setup_subcloud()
|
|
||||||
|
|
||||||
# Add the strategy_step state being processed by this unit test
|
|
||||||
self.strategy_step = self.setup_strategy_step(
|
|
||||||
self.subcloud.id, consts.STRATEGY_STATE_SW_UPLOAD)
|
|
||||||
|
|
||||||
# Add mock API endpoints for software client calls
|
|
||||||
# invoked by this state
|
|
||||||
self.software_client.query = mock.MagicMock()
|
|
||||||
self.software_client.upload = mock.MagicMock()
|
|
||||||
self._read_from_cache = mock.MagicMock()
|
|
||||||
|
|
||||||
@mock.patch.object(UploadState, '_read_from_cache')
|
|
||||||
@mock.patch.object(os.path, 'isfile')
|
|
||||||
def test_software_upload_strategy_success(self, mock_is_file,
|
|
||||||
mock_read_from_cache):
|
|
||||||
"""Test software upload when the API call succeeds."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
|
||||||
mock_is_file.return_value = True
|
|
||||||
|
|
||||||
self.software_client.query.side_effect = [SUBCLOUD_RELEASES]
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.upload.assert_called_once_with([
|
|
||||||
consts.RELEASE_VAULT_DIR + '/20.12/DC_20.12.3.patch',
|
|
||||||
consts.RELEASE_VAULT_DIR + '/20.12/DC_20.12.4.patch'
|
|
||||||
])
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
||||||
|
|
||||||
@mock.patch.object(UploadState, '_read_from_cache')
|
|
||||||
def test_software_upload_strategy_no_operation_required(self,
|
|
||||||
mock_read_from_cache):
|
|
||||||
"""Test software upload when no software operation is required."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
|
||||||
|
|
||||||
self.software_client.query.side_effect = [REGION_ONE_RELEASES]
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.upload.assert_not_called()
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
||||||
|
|
||||||
@mock.patch.object(UploadState, '_read_from_cache')
|
|
||||||
@mock.patch.object(os, 'listdir')
|
|
||||||
@mock.patch.object(os.path, 'isdir')
|
|
||||||
def test_software_upload_strategy_missing_sig(self, mock_is_dir, mock_listdir,
|
|
||||||
mock_read_from_cache):
|
|
||||||
"""Test software upload when release is missing signature"""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES_2
|
|
||||||
mock_is_dir.return_value = True
|
|
||||||
mock_listdir.return_value = ["DC_22.12.0.iso"]
|
|
||||||
self.software_client.query.side_effect = [SUBCLOUD_RELEASES]
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.upload.assert_not_called()
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
consts.STRATEGY_STATE_FAILED)
|
|
||||||
|
|
||||||
@mock.patch.object(UploadState, '_read_from_cache')
|
|
||||||
@mock.patch.object(os, 'listdir')
|
|
||||||
@mock.patch.object(os.path, 'isdir')
|
|
||||||
def test_software_upload_strategy_success_load(self, mock_is_dir, mock_listdir,
|
|
||||||
mock_read_from_cache):
|
|
||||||
"""Test software upload when the API call succeeds."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES_2
|
|
||||||
mock_is_dir.return_value = True
|
|
||||||
mock_listdir.return_value = ["DC_22.12.0.iso", "DC_22.12.0.sig"]
|
|
||||||
self.software_client.query.side_effect = [
|
|
||||||
SUBCLOUD_RELEASES, REGION_ONE_RELEASES_2]
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.upload.assert_called_once_with([
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.0.iso',
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.0.sig'
|
|
||||||
])
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
||||||
|
|
||||||
@mock.patch.object(UploadState, '_read_from_cache')
|
|
||||||
@mock.patch.object(os, 'listdir')
|
|
||||||
@mock.patch.object(os.path, 'isdir')
|
|
||||||
@mock.patch.object(os.path, 'isfile')
|
|
||||||
def test_software_upload_prepatched_load(self, mock_isfile,
|
|
||||||
mock_is_dir, mock_listdir,
|
|
||||||
mock_read_from_cache):
|
|
||||||
"""Test software upload when release is a prepatched iso."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES_3
|
|
||||||
mock_is_dir.return_value = True
|
|
||||||
mock_isfile.return_value = False
|
|
||||||
mock_listdir.return_value = ["DC_22.12.0.iso", "DC_22.12.0.sig"]
|
|
||||||
self.software_client.query.side_effect = [{}, REGION_ONE_RELEASES_3]
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.upload.assert_called_once_with([
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.0.iso',
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.0.sig'
|
|
||||||
])
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
||||||
|
|
||||||
@mock.patch.object(UploadState, '_read_from_cache')
|
|
||||||
@mock.patch.object(os, 'listdir')
|
|
||||||
@mock.patch.object(os.path, 'isdir')
|
|
||||||
@mock.patch.object(os.path, 'isfile')
|
|
||||||
def test_software_upload_patch_and_load(self, mock_isfile,
|
|
||||||
mock_is_dir, mock_listdir,
|
|
||||||
mock_read_from_cache):
|
|
||||||
"""Test software upload when both patch and load is uploaded."""
|
|
||||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES_3
|
|
||||||
mock_is_dir.return_value = True
|
|
||||||
mock_isfile.return_value = True
|
|
||||||
mock_listdir.return_value = ["DC_22.12.0.iso", "DC_22.12.0.sig"]
|
|
||||||
self.software_client.query.side_effect = [{}, REGION_ONE_RELEASES_3]
|
|
||||||
|
|
||||||
# invoke the strategy state operation on the orch thread
|
|
||||||
self.worker.perform_state_action(self.strategy_step)
|
|
||||||
|
|
||||||
self.software_client.upload.assert_called_once_with([
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.1.patch',
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.0.iso',
|
|
||||||
consts.RELEASE_VAULT_DIR + '/22.12/DC_22.12.0.sig'
|
|
||||||
])
|
|
||||||
|
|
||||||
# On success, the state should transition to the next state
|
|
||||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
|
||||||
self.on_success_state)
|
|
Loading…
Reference in New Issue
Block a user