
Makes PatchOrchThread a subclass of the OrchThread, following the same design used in the other types of orchestration. It also removes the strategy step to orchestrate the system controller patching, as it should be done separately, before initializing the patch orchestration to patch the subclouds. The alarm checks that were executed inside the 'updating' state are now part of a new 'pre-check' state that runs at the beggining of the orchestration process. It also refactors the unit tests to be in line with the unit tests of the other orchestrator types by using the TestSwUpdate base class. Test Plan: 1. PASS - Verify successfull patch orchestration by applying and removing a NRR patch; 2. PASS - Verify successfull patch orchestration by applying and removing a RR patch; 3. PASS - Induce a management affecting alarm in a subcloud and verify that orchestration fails for that subcloud; 4. PASS - Induce a 900.001 alarm by partially apply a patch in a subcloud beforehand and verify that orchestration completes successfully for that subcloud; 5. PASS - Create a DC orch patch strategy, then manually patch a subcloud using the sw-manager patch-strategy command and then apply the DC orch patch strategy, verifying if the state machine skips from the 'creating VIM patch strategy' state directly to the 'finishing patch strategy' state; 6. PASS - Verify that no strategy step is created for the system controller; 7. PASS - Execute another orchestration type (e.g. prestage) and verify that it still works as expected. Story: 2010584 Task: 47371 Co-Authored-By: Al Bailey <al.bailey@windriver.com> Signed-off-by: Gustavo Herzmann <gustavo.herzmann@windriver.com> Change-Id: I2c37bd59696e6f9e4fd706f3b3c97f8f9e4499b0
168 lines
6.0 KiB
Python
168 lines
6.0 KiB
Python
#
|
|
# Copyright (c) 2020-2023 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
import abc
|
|
import six
|
|
|
|
from oslo_log import log as logging
|
|
|
|
from dccommon import consts as dccommon_consts
|
|
from dccommon.drivers.openstack.barbican import BarbicanClient
|
|
from dccommon.drivers.openstack.fm import FmClient
|
|
from dccommon.drivers.openstack.patching_v1 import PatchingClient
|
|
from dccommon.drivers.openstack.sdk_platform import OpenStackDriver
|
|
from dccommon.drivers.openstack.sysinv_v1 import SysinvClient
|
|
from dccommon.drivers.openstack.vim import VimClient
|
|
from dcmanager.common import context
|
|
from dcmanager.common.exceptions import InvalidParameterValue
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
@six.add_metaclass(abc.ABCMeta)
|
|
class BaseState(object):
|
|
|
|
def __init__(self, next_state, region_name):
|
|
super(BaseState, self).__init__()
|
|
self.next_state = next_state
|
|
self.context = context.get_admin_context()
|
|
self._stop = None
|
|
self.region_name = region_name
|
|
self._shared_caches = None
|
|
self._job_data = None
|
|
|
|
def override_next_state(self, next_state):
|
|
self.next_state = next_state
|
|
|
|
def set_job_data(self, job_data):
|
|
"""Store an orch_thread job data object"""
|
|
self._job_data = job_data
|
|
|
|
def registerStopEvent(self, stop_event):
|
|
"""Store an orch_thread threading.Event to detect stop."""
|
|
self._stop = stop_event
|
|
|
|
def stopped(self):
|
|
"""Check if the threading.Event is set, otherwise return False."""
|
|
if self._stop is not None:
|
|
return self._stop.isSet()
|
|
else:
|
|
return False
|
|
|
|
def debug_log(self, strategy_step, details):
|
|
LOG.debug("Stage: %s, State: %s, Subcloud: %s, Details: %s"
|
|
% (strategy_step.stage,
|
|
strategy_step.state,
|
|
self.get_region_name(strategy_step),
|
|
details))
|
|
|
|
def info_log(self, strategy_step, details):
|
|
LOG.info("Stage: %s, State: %s, Subcloud: %s, Details: %s"
|
|
% (strategy_step.stage,
|
|
strategy_step.state,
|
|
self.get_region_name(strategy_step),
|
|
details))
|
|
|
|
def warn_log(self, strategy_step, details):
|
|
LOG.warn("Stage: %s, State: %s, Subcloud: %s, Details: %s"
|
|
% (strategy_step.stage,
|
|
strategy_step.state,
|
|
self.get_region_name(strategy_step),
|
|
details))
|
|
|
|
def error_log(self, strategy_step, details):
|
|
LOG.error("Stage: %s, State: %s, Subcloud: %s, Details: %s"
|
|
% (strategy_step.stage,
|
|
strategy_step.state,
|
|
self.get_region_name(strategy_step),
|
|
details))
|
|
|
|
def exception_log(self, strategy_step, details):
|
|
LOG.exception("Stage: %s, State: %s, Subcloud: %s, Details: %s"
|
|
% (strategy_step.stage,
|
|
strategy_step.state,
|
|
self.get_region_name(strategy_step),
|
|
details))
|
|
|
|
@staticmethod
|
|
def get_region_name(strategy_step):
|
|
"""Get the region name for a strategy step"""
|
|
if strategy_step.subcloud_id is None:
|
|
# This is the SystemController.
|
|
return dccommon_consts.DEFAULT_REGION_NAME
|
|
return strategy_step.subcloud.name
|
|
|
|
@staticmethod
|
|
def get_keystone_client(region_name=dccommon_consts.DEFAULT_REGION_NAME):
|
|
"""Construct a (cached) keystone client (and token)"""
|
|
|
|
try:
|
|
os_client = OpenStackDriver(region_name=region_name,
|
|
region_clients=['sysinv'])
|
|
return os_client.keystone_client
|
|
except Exception:
|
|
LOG.warning('Failure initializing KeystoneClient for region: %s'
|
|
% region_name)
|
|
raise
|
|
|
|
def get_sysinv_client(self, region_name):
|
|
"""construct a sysinv client
|
|
|
|
"""
|
|
keystone_client = self.get_keystone_client(region_name)
|
|
endpoint = keystone_client.endpoint_cache.get_endpoint('sysinv')
|
|
return SysinvClient(region_name, keystone_client.session,
|
|
endpoint=endpoint)
|
|
|
|
def get_fm_client(self, region_name):
|
|
keystone_client = self.get_keystone_client(region_name)
|
|
return FmClient(region_name, keystone_client.session)
|
|
|
|
def get_patching_client(self, region_name=dccommon_consts.DEFAULT_REGION_NAME):
|
|
keystone_client = self.get_keystone_client(region_name)
|
|
return PatchingClient(region_name, keystone_client.session)
|
|
|
|
@property
|
|
def local_sysinv(self):
|
|
return self.get_sysinv_client(dccommon_consts.DEFAULT_REGION_NAME)
|
|
|
|
@property
|
|
def subcloud_sysinv(self):
|
|
return self.get_sysinv_client(self.region_name)
|
|
|
|
def get_barbican_client(self, region_name):
|
|
"""construct a barbican client
|
|
|
|
"""
|
|
keystone_client = self.get_keystone_client(region_name)
|
|
|
|
return BarbicanClient(region_name, keystone_client.session)
|
|
|
|
def get_vim_client(self, region_name):
|
|
"""construct a vim client for a region."""
|
|
keystone_client = self.get_keystone_client(region_name)
|
|
return VimClient(region_name,
|
|
keystone_client.session)
|
|
|
|
def add_shared_caches(self, shared_caches):
|
|
# Shared caches not required by all states, so instantiate only if necessary
|
|
self._shared_caches = shared_caches
|
|
|
|
def _read_from_cache(self, cache_type, **filter_params):
|
|
if self._shared_caches is not None:
|
|
return self._shared_caches.read(cache_type, **filter_params)
|
|
else:
|
|
InvalidParameterValue(err="Specified cache type '%s' not "
|
|
"present" % cache_type)
|
|
|
|
@abc.abstractmethod
|
|
def perform_state_action(self, strategy_step):
|
|
"""Perform the action for this state on the strategy_step
|
|
|
|
Returns the next state in the state machine on success.
|
|
Any exceptions raised by this method set the strategy to FAILED.
|
|
"""
|
|
pass
|