Fix prestage orchestration details for skipped subclouds

Ensure that the 'details' field reflects the reason a subcloud is
skipped during prestage orchestration.

We use a new exception, StrategySkippedException, to signal the
OrchThread that a subcloud is being skipped. This immediately
transitions the subcloud strategy to complete, while preserving
the reason for skipping in the strategy_step details.

NOTE: this update also includes a minor update
to the API parameters file, which was missed in the
original feature commit (api-ref/source/parameters.yaml)

Test Plan:

PASS:
- normal prestage orchestration
- prestage orchestration with non-AIO-SX subcloud
    - subcloud is skipped
    - details populated and reported in details column
      of 'dcmanager strategy-step list'
    - subcloud deploy_status is returned to 'complete'
- verify feature logging

Closes-Bug: 1963967
Signed-off-by: Kyle MacLeod <kyle.macleod@windriver.com>
Change-Id: I3408f274e3e04410872716b718130a3a27006c36
This commit is contained in:
Kyle MacLeod 2022-03-07 11:34:00 -05:00
parent 66e5517513
commit 9c4d1e9965
4 changed files with 41 additions and 17 deletions

View File

@ -22,7 +22,8 @@ subcloud_uri:
sw_update_strategy_type:
description: |
Filter to query a particular type of update strategy if it exists.
One of: `firmware`, `kube-rootca-update`, `kubernetes`, `patch`, `upgrade`
One of: `firmware`, `kube-rootca-update`, `kubernetes`, `patch`,
`prestage`, or `upgrade`.
in: path
required: false
type: string

View File

@ -229,5 +229,12 @@ class StrategyStepNameNotFound(NotFound):
message = _("StrategyStep with name %(name)s doesn't exist.")
class StrategySkippedException(DCManagerException):
def __init__(self, details):
self.details = details
self.message = _(details)
super(StrategySkippedException, self).__init__()
class StrategyStoppedException(DCManagerException):
message = _("Strategy has been stopped")

View File

@ -122,8 +122,12 @@ class OrchThread(threading.Thread):
@staticmethod
def format_update_details(last_state, info):
# include the last state, since the current state is likely 'failed'
details = "%s: %s" % (last_state, info)
# Optionally include the last state, since the current state
# is likely 'failed'
if last_state:
details = "%s: %s" % (last_state, info)
else:
details = str(info)
# details cannot exceed 255 chars. truncate and add '..'
if len(details) > 255:
details = details[:253] + '..'
@ -535,14 +539,26 @@ class OrchThread(threading.Thread):
self.strategy_step_update(strategy_step.subcloud_id,
state=next_state,
details="")
except Exception as e:
except exceptions.StrategySkippedException as ex:
LOG.info("(%s) Skipping subcloud, Stage: %s, State: %s, Subcloud: %s"
% (self.update_type,
strategy_step.stage,
strategy_step.state,
self.get_region_name(strategy_step)))
# Transition immediately to complete. Update the details to show
# that this subcloud has been skipped
details = self.format_update_details(None, str(ex))
self.strategy_step_update(strategy_step.subcloud_id,
state=consts.STRATEGY_STATE_COMPLETE,
details=details)
except Exception as ex:
# Catch ALL exceptions and set the strategy to failed
LOG.exception("(%s) Failed! Stage: %s, State: %s, Subcloud: %s"
% (self.update_type,
strategy_step.stage,
strategy_step.state,
self.get_region_name(strategy_step)))
details = self.format_update_details(strategy_step.state, str(e))
details = self.format_update_details(strategy_step.state, str(ex))
self.strategy_step_update(strategy_step.subcloud_id,
state=consts.STRATEGY_STATE_FAILED,
details=details)

View File

@ -32,7 +32,12 @@ class PrestageState(BaseState):
"""Wrapper to ensure proper error handling"""
try:
self._do_state_action(strategy_step)
except exceptions.StrategySkippedException:
# Move deploy_status back to complete (nothing has changed)
db_api.subcloud_update(
self.context, strategy_step.subcloud.id,
deploy_status=consts.DEPLOY_STATE_DONE)
raise
except Exception:
prestage.prestage_fail(self.context, strategy_step.subcloud.id)
raise
@ -95,19 +100,14 @@ class PrestagePreCheckState(PrestageState):
prestage.prestage_start(self.context, strategy_step.subcloud.id)
except exceptions.PrestagePreCheckFailedException as ex:
# We've either failed precheck or we want to skip this subcloud.
# Either way, we'll re-raise up to the base class for status
# update, and then let OrchThread take it from here
if ex.orch_skip:
self.info_log(strategy_step,
"Pre-check: skipping subcloud: %s" % ex)
raise exceptions.StrategySkippedException(details=str(ex))
# Update the details to show that this subcloud has been skipped
db_api.strategy_step_update(self.context,
strategy_step.subcloud.id,
details=str(ex))
self.override_next_state(consts.STRATEGY_STATE_COMPLETE)
else:
self.info_log(strategy_step, "Pre-check failed: %s" % ex)
raise
self.error_log(strategy_step, "Pre-check failed: %s" % ex)
raise
else:
self.info_log(strategy_step, "Pre-check pass")