Improve DC VIM strategy create/apply error handling
This commit updates subcloud's error_description with the error returned by the software API during VIM strategy create and apply. - Created two custom exceptions for handling these errors. - Clean up error_description in strategy creation. Note: This also updated the timeout values of software API. Test Plan: PASS - Apply a sw-deploy-strategy and force an error in the deploy precheck command. - Apply should fail in the `create VIM strategy` state - dcmanager subcloud errors should be updated PASS - Apply a sw-deploy-strategy and force an error in the deploy start command. - Apply should fail in `apply VIM strategy` state - dcmanager subcloud errors should be updated PASS - Create a dcmanager sw-deploy-strategy with subcloud errors. - Strategy created and subcloud errors should be `No errors present`. Story: 2010676 Task: 50644 Change-Id: Ib0b0b586d90093088a6af96e5d630e3fe04fd3f7 Signed-off-by: Hugo Brito <hugo.brito@windriver.com>
This commit is contained in:
parent
30df79b36a
commit
b3d206781b
@ -23,6 +23,8 @@ REMOVING = "removing"
|
|||||||
UNAVAILABLE = "unavailable"
|
UNAVAILABLE = "unavailable"
|
||||||
|
|
||||||
REST_DEFAULT_TIMEOUT = 900
|
REST_DEFAULT_TIMEOUT = 900
|
||||||
|
REST_SHOW_TIMEOUT = 150
|
||||||
|
REST_DELETE_TIMEOUT = 300
|
||||||
|
|
||||||
|
|
||||||
class SoftwareClient(base.DriverBase):
|
class SoftwareClient(base.DriverBase):
|
||||||
@ -58,13 +60,13 @@ class SoftwareClient(base.DriverBase):
|
|||||||
response = requests.get(url, headers=self.headers, timeout=timeout)
|
response = requests.get(url, headers=self.headers, timeout=timeout)
|
||||||
return self._handle_response(response, operation="List")
|
return self._handle_response(response, operation="List")
|
||||||
|
|
||||||
def show(self, release, timeout=REST_DEFAULT_TIMEOUT):
|
def show(self, release, timeout=REST_SHOW_TIMEOUT):
|
||||||
"""Show release"""
|
"""Show release"""
|
||||||
url = self.endpoint + f"/release/{release}"
|
url = self.endpoint + f"/release/{release}"
|
||||||
response = requests.get(url, headers=self.headers, timeout=timeout)
|
response = requests.get(url, headers=self.headers, timeout=timeout)
|
||||||
return self._handle_response(response, operation="Show")
|
return self._handle_response(response, operation="Show")
|
||||||
|
|
||||||
def delete(self, releases, timeout=REST_DEFAULT_TIMEOUT):
|
def delete(self, releases, timeout=REST_DELETE_TIMEOUT):
|
||||||
"""Delete release"""
|
"""Delete release"""
|
||||||
release_str = "/".join(releases)
|
release_str = "/".join(releases)
|
||||||
url = self.endpoint + f"/release/{release_str}"
|
url = self.endpoint + f"/release/{release_str}"
|
||||||
@ -77,7 +79,7 @@ class SoftwareClient(base.DriverBase):
|
|||||||
response = requests.post(url, headers=self.headers, timeout=timeout)
|
response = requests.post(url, headers=self.headers, timeout=timeout)
|
||||||
return self._handle_response(response, operation="Deploy precheck")
|
return self._handle_response(response, operation="Deploy precheck")
|
||||||
|
|
||||||
def deploy_delete(self, timeout=REST_DEFAULT_TIMEOUT):
|
def deploy_delete(self, timeout=REST_DELETE_TIMEOUT):
|
||||||
"""Deploy delete"""
|
"""Deploy delete"""
|
||||||
url = self.endpoint + "/deploy"
|
url = self.endpoint + "/deploy"
|
||||||
response = requests.delete(url, headers=self.headers, timeout=timeout)
|
response = requests.delete(url, headers=self.headers, timeout=timeout)
|
||||||
|
@ -262,6 +262,20 @@ class SoftwarePreCheckFailedException(DCManagerException):
|
|||||||
message = _("Subcloud %(subcloud)s software deploy precheck failed: %(details)s")
|
message = _("Subcloud %(subcloud)s software deploy precheck failed: %(details)s")
|
||||||
|
|
||||||
|
|
||||||
|
class CreateVIMStrategyFailedException(DCManagerException):
|
||||||
|
message = _(
|
||||||
|
"Subcloud %(subcloud)s create VIM %(name)s strategy "
|
||||||
|
"failed. State: %(state)s Details: %(details)s"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ApplyVIMStrategyFailedException(DCManagerException):
|
||||||
|
message = _(
|
||||||
|
"Subcloud %(subcloud)s apply VIM %(name)s strategy "
|
||||||
|
"failed. State: %(state)s Details: %(details)s"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SoftwareListFailedException(DCManagerException):
|
class SoftwareListFailedException(DCManagerException):
|
||||||
message = _("Subcloud %(subcloud)s software list failed: %(details)s")
|
message = _("Subcloud %(subcloud)s software list failed: %(details)s")
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from dccommon.drivers.openstack import vim
|
from dccommon.drivers.openstack import vim
|
||||||
from dcmanager.common.exceptions import StrategyStoppedException
|
from dcmanager.common import exceptions
|
||||||
from dcmanager.db import api as db_api
|
from dcmanager.db import api as db_api
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
from dcmanager.orchestrator.states.base import BaseState
|
||||||
|
|
||||||
@ -64,7 +64,13 @@ class ApplyingVIMStrategyState(BaseState):
|
|||||||
# Do not raise the default exception if there is no strategy
|
# Do not raise the default exception if there is no strategy
|
||||||
# because the default exception is unclear: ie: "Get strategy failed"
|
# because the default exception is unclear: ie: "Get strategy failed"
|
||||||
if subcloud_strategy is None:
|
if subcloud_strategy is None:
|
||||||
raise Exception("(%s) VIM Strategy not found." % self.strategy_name)
|
message = "VIM Strategy not found."
|
||||||
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
|
)
|
||||||
|
|
||||||
# We have a VIM strategy, but need to check if it is ready to apply
|
# We have a VIM strategy, but need to check if it is ready to apply
|
||||||
elif subcloud_strategy.state == vim.STATE_READY_TO_APPLY:
|
elif subcloud_strategy.state == vim.STATE_READY_TO_APPLY:
|
||||||
@ -87,20 +93,20 @@ class ApplyingVIMStrategyState(BaseState):
|
|||||||
vim.STATE_APPLY_FAILED,
|
vim.STATE_APPLY_FAILED,
|
||||||
vim.STATE_APPLY_TIMEOUT,
|
vim.STATE_APPLY_TIMEOUT,
|
||||||
]:
|
]:
|
||||||
# Explicit known failure states
|
message = "VIM strategy apply failed: "
|
||||||
raise Exception(
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
"(%s) VIM strategy apply failed. %s. %s"
|
subcloud=strategy_step.subcloud.name,
|
||||||
% (
|
name=self.strategy_name,
|
||||||
self.strategy_name,
|
state=subcloud_strategy.state,
|
||||||
subcloud_strategy.state,
|
details=message + subcloud_strategy.apply_phase.reason,
|
||||||
subcloud_strategy.apply_phase.reason,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Other states are bad
|
message = "VIM strategy unexpected apply state."
|
||||||
raise Exception(
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
"(%s) VIM strategy apply failed. Unexpected State: %s."
|
subcloud=strategy_step.subcloud.name,
|
||||||
% (self.strategy_name, subcloud_strategy.state)
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
)
|
)
|
||||||
|
|
||||||
# wait for new strategy to apply or the existing strategy to complete.
|
# wait for new strategy to apply or the existing strategy to complete.
|
||||||
@ -117,14 +123,19 @@ class ApplyingVIMStrategyState(BaseState):
|
|||||||
# which would allow the longer 60 second sleep to be broken into
|
# which would allow the longer 60 second sleep to be broken into
|
||||||
# multiple smaller sleep calls
|
# multiple smaller sleep calls
|
||||||
|
|
||||||
|
error_message = None
|
||||||
# If event handler stop has been triggered, fail the state
|
# If event handler stop has been triggered, fail the state
|
||||||
if self.stopped():
|
if self.stopped():
|
||||||
raise StrategyStoppedException()
|
raise exceptions.StrategyStoppedException()
|
||||||
# break out of the loop if the max number of attempts is reached
|
# break out of the loop if the max number of attempts is reached
|
||||||
wait_count += 1
|
wait_count += 1
|
||||||
if wait_count >= self.wait_attempts:
|
if wait_count >= self.wait_attempts:
|
||||||
raise Exception(
|
message = "Timeout applying vim strategy."
|
||||||
"Timeout applying (%s) vim strategy." % self.strategy_name
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
)
|
)
|
||||||
# every loop we wait, even the first one
|
# every loop we wait, even the first one
|
||||||
time.sleep(self.wait_interval)
|
time.sleep(self.wait_interval)
|
||||||
@ -143,9 +154,12 @@ class ApplyingVIMStrategyState(BaseState):
|
|||||||
get_fail_count += 1
|
get_fail_count += 1
|
||||||
if get_fail_count >= self.max_failed_queries:
|
if get_fail_count >= self.max_failed_queries:
|
||||||
# We have waited too long.
|
# We have waited too long.
|
||||||
raise Exception(
|
message = "Timeout during recovery of VIM strategy."
|
||||||
"Timeout during recovery of apply (%s) Vim strategy."
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
% self.strategy_name
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
)
|
)
|
||||||
self.debug_log(
|
self.debug_log(
|
||||||
strategy_step,
|
strategy_step,
|
||||||
@ -156,8 +170,12 @@ class ApplyingVIMStrategyState(BaseState):
|
|||||||
# If an external actor has deleted the strategy, the only option
|
# If an external actor has deleted the strategy, the only option
|
||||||
# is to fail this state.
|
# is to fail this state.
|
||||||
if subcloud_strategy is None:
|
if subcloud_strategy is None:
|
||||||
raise Exception(
|
message = "VIM Strategy no longer exists."
|
||||||
"(%s) VIM Strategy no longer exists." % self.strategy_name
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
)
|
)
|
||||||
|
|
||||||
elif subcloud_strategy.state == vim.STATE_APPLYING:
|
elif subcloud_strategy.state == vim.STATE_APPLYING:
|
||||||
@ -186,22 +204,26 @@ class ApplyingVIMStrategyState(BaseState):
|
|||||||
vim.STATE_APPLY_FAILED,
|
vim.STATE_APPLY_FAILED,
|
||||||
vim.STATE_APPLY_TIMEOUT,
|
vim.STATE_APPLY_TIMEOUT,
|
||||||
]:
|
]:
|
||||||
# Explicit known failure states
|
error_message = "VIM strategy apply failed: "
|
||||||
raise Exception(
|
|
||||||
"(%s) Vim strategy apply failed. %s. %s"
|
|
||||||
% (
|
|
||||||
self.strategy_name,
|
|
||||||
subcloud_strategy.state,
|
|
||||||
subcloud_strategy.apply_phase.reason,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# Other states are bad
|
error_message = "VIM strategy unexpected apply state."
|
||||||
raise Exception(
|
|
||||||
"(%s) Vim strategy apply failed. Unexpected State: %s."
|
if error_message:
|
||||||
% (self.strategy_name, subcloud_strategy.state)
|
apply_error = subcloud_strategy.apply_phase.response
|
||||||
|
# If response is None, use the reason
|
||||||
|
if not apply_error:
|
||||||
|
apply_error = subcloud_strategy.apply_phase.reason
|
||||||
|
db_api.subcloud_update(
|
||||||
|
self.context,
|
||||||
|
strategy_step.subcloud_id,
|
||||||
|
error_description=apply_error,
|
||||||
|
)
|
||||||
|
raise exceptions.ApplyVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=error_message + apply_error,
|
||||||
)
|
)
|
||||||
# end of loop
|
|
||||||
|
|
||||||
# Success, state machine can proceed to the next state
|
# Success, state machine can proceed to the next state
|
||||||
return self.next_state
|
return self.next_state
|
||||||
|
@ -8,8 +8,9 @@ import time
|
|||||||
|
|
||||||
from dccommon.drivers.openstack import vim
|
from dccommon.drivers.openstack import vim
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
from dcmanager.common.exceptions import StrategyStoppedException
|
from dcmanager.common import exceptions
|
||||||
from dcmanager.common import utils
|
from dcmanager.common import utils
|
||||||
|
from dcmanager.db import api as db_api
|
||||||
from dcmanager.orchestrator.states.base import BaseState
|
from dcmanager.orchestrator.states.base import BaseState
|
||||||
|
|
||||||
# Max time: 30 minutes = 180 queries x 10 seconds between
|
# Max time: 30 minutes = 180 queries x 10 seconds between
|
||||||
@ -59,8 +60,12 @@ class CreatingVIMStrategyState(BaseState):
|
|||||||
|
|
||||||
# a successful API call to create MUST set the state be 'building'
|
# a successful API call to create MUST set the state be 'building'
|
||||||
if subcloud_strategy.state != vim.STATE_BUILDING:
|
if subcloud_strategy.state != vim.STATE_BUILDING:
|
||||||
raise Exception(
|
message = "Unexpected VIM strategy build state."
|
||||||
"Unexpected VIM strategy build state: %s" % subcloud_strategy.state
|
raise exceptions.CreateVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
)
|
)
|
||||||
return subcloud_strategy
|
return subcloud_strategy
|
||||||
|
|
||||||
@ -91,9 +96,9 @@ class CreatingVIMStrategyState(BaseState):
|
|||||||
strategy_step,
|
strategy_step,
|
||||||
"VIM strategy exists with state: %s" % subcloud_strategy.state,
|
"VIM strategy exists with state: %s" % subcloud_strategy.state,
|
||||||
)
|
)
|
||||||
# if a strategy exists in any type of failed state or aborted
|
# if a strategy exists in any type of failed state or aborted state it
|
||||||
# state it should be deleted.
|
# should be deleted. Applied state should also be deleted from previous
|
||||||
# applied state should also be deleted from previous success runs.
|
# success runs.
|
||||||
if subcloud_strategy.state in [
|
if subcloud_strategy.state in [
|
||||||
vim.STATE_BUILDING,
|
vim.STATE_BUILDING,
|
||||||
vim.STATE_APPLYING,
|
vim.STATE_APPLYING,
|
||||||
@ -101,12 +106,16 @@ class CreatingVIMStrategyState(BaseState):
|
|||||||
]:
|
]:
|
||||||
# Can't delete a strategy in these states
|
# Can't delete a strategy in these states
|
||||||
message = (
|
message = (
|
||||||
"Failed to create a VIM strategy for %s. "
|
"Failed to create a VIM strategy. There already is an existing "
|
||||||
"There already is an existing strategy in %s state"
|
"strategy in this state."
|
||||||
% (region, subcloud_strategy.state)
|
|
||||||
)
|
)
|
||||||
self.warn_log(strategy_step, message)
|
self.warn_log(strategy_step, message)
|
||||||
raise Exception(message)
|
raise exceptions.CreateVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=message,
|
||||||
|
)
|
||||||
|
|
||||||
# if strategy exists in any other type of state, delete and create
|
# if strategy exists in any other type of state, delete and create
|
||||||
self.info_log(strategy_step, "Deleting existing VIM strategy")
|
self.info_log(strategy_step, "Deleting existing VIM strategy")
|
||||||
@ -120,12 +129,17 @@ class CreatingVIMStrategyState(BaseState):
|
|||||||
# Loop until the strategy is done building Repeatedly query the API
|
# Loop until the strategy is done building Repeatedly query the API
|
||||||
counter = 0
|
counter = 0
|
||||||
while True:
|
while True:
|
||||||
|
error_message = None
|
||||||
# If event handler stop has been triggered, fail the state
|
# If event handler stop has been triggered, fail the state
|
||||||
if self.stopped():
|
if self.stopped():
|
||||||
raise StrategyStoppedException()
|
raise exceptions.StrategyStoppedException()
|
||||||
if counter >= self.max_queries:
|
if counter >= self.max_queries:
|
||||||
raise Exception(
|
details = "Timeout building VIM strategy."
|
||||||
"Timeout building vim strategy. state: %s" % subcloud_strategy.state
|
raise exceptions.CreateVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=details,
|
||||||
)
|
)
|
||||||
counter += 1
|
counter += 1
|
||||||
time.sleep(self.sleep_duration)
|
time.sleep(self.sleep_duration)
|
||||||
@ -151,17 +165,26 @@ class CreatingVIMStrategyState(BaseState):
|
|||||||
# This is the expected state while creating the strategy
|
# This is the expected state while creating the strategy
|
||||||
pass
|
pass
|
||||||
elif subcloud_strategy.state == vim.STATE_BUILD_FAILED:
|
elif subcloud_strategy.state == vim.STATE_BUILD_FAILED:
|
||||||
raise Exception(
|
error_message = "VIM strategy build failed: "
|
||||||
"VIM strategy build failed: %s. %s."
|
|
||||||
% (subcloud_strategy.state, subcloud_strategy.build_phase.reason)
|
|
||||||
)
|
|
||||||
elif subcloud_strategy.state == vim.STATE_BUILD_TIMEOUT:
|
elif subcloud_strategy.state == vim.STATE_BUILD_TIMEOUT:
|
||||||
raise Exception(
|
error_message = "VIM strategy build timed out: "
|
||||||
"VIM strategy build timed out: %s." % subcloud_strategy.state
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
error_message = "VIM strategy unexpected build state."
|
||||||
"VIM strategy unexpected build state: %s" % subcloud_strategy.state
|
if error_message:
|
||||||
|
build_error = subcloud_strategy.build_phase.response
|
||||||
|
# If response is None, use the reason
|
||||||
|
if not build_error:
|
||||||
|
build_error = subcloud_strategy.build_phase.reason
|
||||||
|
db_api.subcloud_update(
|
||||||
|
self.context,
|
||||||
|
strategy_step.subcloud_id,
|
||||||
|
error_description=build_error,
|
||||||
|
)
|
||||||
|
raise exceptions.CreateVIMStrategyFailedException(
|
||||||
|
subcloud=strategy_step.subcloud.name,
|
||||||
|
name=self.strategy_name,
|
||||||
|
state=subcloud_strategy.state,
|
||||||
|
details=error_message + build_error,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Success, state machine can proceed to the next state
|
# Success, state machine can proceed to the next state
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
from dccommon.drivers.openstack import software_v1
|
from dccommon.drivers.openstack import software_v1
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
from dcmanager.common import exceptions
|
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 (
|
from dcmanager.orchestrator.states.software.cache.cache_specifications import (
|
||||||
REGION_ONE_RELEASE_USM_CACHE_TYPE,
|
REGION_ONE_RELEASE_USM_CACHE_TYPE,
|
||||||
@ -28,8 +27,6 @@ class FinishStrategyState(BaseState):
|
|||||||
|
|
||||||
self.info_log(strategy_step, "Finishing software strategy")
|
self.info_log(strategy_step, "Finishing software strategy")
|
||||||
|
|
||||||
subcloud = db_api.subcloud_get(self.context, strategy_step.subcloud.id)
|
|
||||||
|
|
||||||
regionone_deployed_releases = self._read_from_cache(
|
regionone_deployed_releases = self._read_from_cache(
|
||||||
REGION_ONE_RELEASE_USM_CACHE_TYPE, state=software_v1.DEPLOYED
|
REGION_ONE_RELEASE_USM_CACHE_TYPE, state=software_v1.DEPLOYED
|
||||||
)
|
)
|
||||||
@ -46,7 +43,7 @@ class FinishStrategyState(BaseState):
|
|||||||
message = "Cannot retrieve subcloud releases. Please see logs for details."
|
message = "Cannot retrieve subcloud releases. Please see logs for details."
|
||||||
self.exception_log(strategy_step, message)
|
self.exception_log(strategy_step, message)
|
||||||
raise exceptions.SoftwareListFailedException(
|
raise exceptions.SoftwareListFailedException(
|
||||||
subcloud=subcloud.name,
|
subcloud=strategy_step.subcloud.name,
|
||||||
details=message,
|
details=message,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -72,7 +69,7 @@ class FinishStrategyState(BaseState):
|
|||||||
|
|
||||||
if releases_to_delete:
|
if releases_to_delete:
|
||||||
self._handle_release_delete(
|
self._handle_release_delete(
|
||||||
strategy_step, software_client, subcloud, releases_to_delete
|
strategy_step, software_client, releases_to_delete
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.stopped():
|
if self.stopped():
|
||||||
@ -80,14 +77,13 @@ class FinishStrategyState(BaseState):
|
|||||||
|
|
||||||
if releases_to_commit:
|
if releases_to_commit:
|
||||||
self._handle_deploy_commit(
|
self._handle_deploy_commit(
|
||||||
strategy_step, software_client, subcloud, releases_to_commit
|
strategy_step, software_client, releases_to_commit
|
||||||
)
|
)
|
||||||
|
|
||||||
if releases_to_deploy_delete:
|
if releases_to_deploy_delete:
|
||||||
self._handle_deploy_delete(
|
self._handle_deploy_delete(
|
||||||
strategy_step,
|
strategy_step,
|
||||||
software_client,
|
software_client,
|
||||||
subcloud,
|
|
||||||
releases_to_deploy_delete,
|
releases_to_deploy_delete,
|
||||||
regionone_deployed_releases,
|
regionone_deployed_releases,
|
||||||
)
|
)
|
||||||
@ -95,7 +91,7 @@ class FinishStrategyState(BaseState):
|
|||||||
return self.next_state
|
return self.next_state
|
||||||
|
|
||||||
def _handle_release_delete(
|
def _handle_release_delete(
|
||||||
self, strategy_step, software_client, subcloud, releases_to_delete
|
self, strategy_step, software_client, releases_to_delete
|
||||||
):
|
):
|
||||||
self.info_log(strategy_step, f"Deleting releases {releases_to_delete}")
|
self.info_log(strategy_step, f"Deleting releases {releases_to_delete}")
|
||||||
try:
|
try:
|
||||||
@ -106,13 +102,11 @@ class FinishStrategyState(BaseState):
|
|||||||
)
|
)
|
||||||
self.exception_log(strategy_step, message)
|
self.exception_log(strategy_step, message)
|
||||||
raise exceptions.SoftwareDeleteFailedException(
|
raise exceptions.SoftwareDeleteFailedException(
|
||||||
subcloud=subcloud.name,
|
subcloud=strategy_step.subcloud.name,
|
||||||
details=message,
|
details=message,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _handle_deploy_commit(
|
def _handle_deploy_commit(self, strategy_step, software_client, releases_to_commit):
|
||||||
self, strategy_step, software_client, subcloud, releases_to_commit
|
|
||||||
):
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
# If there are releases in deploying state and it's deployed in the regionone,
|
# If there are releases in deploying state and it's deployed in the regionone,
|
||||||
@ -121,7 +115,6 @@ class FinishStrategyState(BaseState):
|
|||||||
self,
|
self,
|
||||||
strategy_step,
|
strategy_step,
|
||||||
software_client,
|
software_client,
|
||||||
subcloud,
|
|
||||||
releases_to_deploy_delete,
|
releases_to_deploy_delete,
|
||||||
regionone_deployed_releases,
|
regionone_deployed_releases,
|
||||||
):
|
):
|
||||||
@ -131,12 +124,12 @@ class FinishStrategyState(BaseState):
|
|||||||
for release_regionone in regionone_deployed_releases
|
for release_regionone in regionone_deployed_releases
|
||||||
):
|
):
|
||||||
message = (
|
message = (
|
||||||
f"There is a deploying release on subcloud {subcloud.name} "
|
f"Deploying release found on subcloud {strategy_step.subcloud.name} "
|
||||||
"that is not deployed in System Controller. Aborting."
|
"and is not deployed in System Controller. Aborting."
|
||||||
)
|
)
|
||||||
self.error_log(strategy_step, message)
|
self.error_log(strategy_step, message)
|
||||||
raise exceptions.SoftwareDeployDeleteFailedException(
|
raise exceptions.SoftwareDeployDeleteFailedException(
|
||||||
subcloud=subcloud.name,
|
subcloud=strategy_step.subcloud.name,
|
||||||
details=message,
|
details=message,
|
||||||
)
|
)
|
||||||
self.info_log(
|
self.info_log(
|
||||||
@ -151,6 +144,6 @@ class FinishStrategyState(BaseState):
|
|||||||
)
|
)
|
||||||
self.exception_log(strategy_step, message)
|
self.exception_log(strategy_step, message)
|
||||||
raise exceptions.SoftwareDeployDeleteFailedException(
|
raise exceptions.SoftwareDeployDeleteFailedException(
|
||||||
subcloud=subcloud.name,
|
subcloud=strategy_step.subcloud.name,
|
||||||
details=message,
|
details=message,
|
||||||
)
|
)
|
||||||
|
@ -462,6 +462,14 @@ class SwUpdateManager(manager.Manager):
|
|||||||
state=consts.STRATEGY_STATE_INITIAL,
|
state=consts.STRATEGY_STATE_INITIAL,
|
||||||
details="",
|
details="",
|
||||||
)
|
)
|
||||||
|
# Clear the error_description field for all subclouds that will
|
||||||
|
# perform orchestration.
|
||||||
|
update_form = {"error_description": consts.ERROR_DESC_EMPTY}
|
||||||
|
db_api.subcloud_bulk_update_by_ids(
|
||||||
|
context,
|
||||||
|
[subcloud.id for subcloud, _ in valid_subclouds],
|
||||||
|
update_form,
|
||||||
|
)
|
||||||
|
|
||||||
LOG.info(
|
LOG.info(
|
||||||
f"Finished creating software update strategy of type {payload['type']}."
|
f"Finished creating software update strategy of type {payload['type']}."
|
||||||
|
@ -65,6 +65,17 @@ class FakeVimStrategy(object):
|
|||||||
self.abort_phase = abort_phase
|
self.abort_phase = abort_phase
|
||||||
|
|
||||||
|
|
||||||
|
class FakeVimStrategyPhase(object):
|
||||||
|
"""Represents a VIM StrategyPhase object defined in:
|
||||||
|
|
||||||
|
starlingx/nfv/nfv-client/nfv_client/openstack/sw_update.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, response=None, reason=None):
|
||||||
|
self.response = response
|
||||||
|
self.reason = reason
|
||||||
|
|
||||||
|
|
||||||
class SwUpdateStrategy(object):
|
class SwUpdateStrategy(object):
|
||||||
def __init__(self, id, data):
|
def __init__(self, id, data):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
@ -8,14 +8,20 @@ import mock
|
|||||||
|
|
||||||
from dccommon.drivers.openstack import vim
|
from dccommon.drivers.openstack import vim
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
|
from dcmanager.common import exceptions
|
||||||
from dcmanager.tests.unit.common import fake_strategy
|
from dcmanager.tests.unit.common import fake_strategy
|
||||||
from dcmanager.tests.unit.fakes import FakeVimStrategy
|
from dcmanager.tests.unit import fakes
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
from dcmanager.tests.unit.orchestrator.states.software.test_base import (
|
||||||
TestSoftwareOrchestrator
|
TestSoftwareOrchestrator,
|
||||||
|
)
|
||||||
|
|
||||||
STRATEGY_READY_TO_APPLY = FakeVimStrategy(state=vim.STATE_READY_TO_APPLY)
|
STRATEGY_READY_TO_APPLY = fakes.FakeVimStrategy(state=vim.STATE_READY_TO_APPLY)
|
||||||
STRATEGY_APPLYING = FakeVimStrategy(state=vim.STATE_APPLYING)
|
STRATEGY_APPLYING = fakes.FakeVimStrategy(state=vim.STATE_APPLYING)
|
||||||
STRATEGY_APPLIED = FakeVimStrategy(state=vim.STATE_APPLIED)
|
STRATEGY_APPLIED = fakes.FakeVimStrategy(state=vim.STATE_APPLIED)
|
||||||
|
APPLY_PHASE_ERROR = fakes.FakeVimStrategyPhase(response="Deploy Start Failed")
|
||||||
|
STRATEGY_APPLY_FAILED = fakes.FakeVimStrategy(
|
||||||
|
state=vim.STATE_APPLY_FAILED, apply_phase=APPLY_PHASE_ERROR
|
||||||
|
)
|
||||||
RELEASE_ID = "starlingx-9.0.1"
|
RELEASE_ID = "starlingx-9.0.1"
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +42,8 @@ class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
|||||||
|
|
||||||
# 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_APPLY_VIM_STRATEGY)
|
self.subcloud.id, consts.STRATEGY_STATE_SW_APPLY_VIM_STRATEGY
|
||||||
|
)
|
||||||
|
|
||||||
# Mock the API calls made by the state
|
# Mock the API calls made by the state
|
||||||
self.vim_client.get_strategy = mock.MagicMock()
|
self.vim_client.get_strategy = mock.MagicMock()
|
||||||
@ -52,9 +59,7 @@ class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
|||||||
"DEFAULT_MAX_WAIT_ATTEMPTS",
|
"DEFAULT_MAX_WAIT_ATTEMPTS",
|
||||||
3,
|
3,
|
||||||
)
|
)
|
||||||
@mock.patch(
|
@mock.patch("dcmanager.orchestrator.states.applying_vim_strategy.WAIT_INTERVAL", 1)
|
||||||
"dcmanager.orchestrator.states.applying_vim_strategy.WAIT_INTERVAL", 1
|
|
||||||
)
|
|
||||||
@mock.patch(
|
@mock.patch(
|
||||||
"dcmanager.orchestrator.states.applying_vim_strategy."
|
"dcmanager.orchestrator.states.applying_vim_strategy."
|
||||||
"ApplyingVIMStrategyState.__init__.__defaults__",
|
"ApplyingVIMStrategyState.__init__.__defaults__",
|
||||||
@ -80,5 +85,44 @@ class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
|||||||
self.vim_client.apply_strategy.assert_called_with(strategy_name="sw-upgrade")
|
self.vim_client.apply_strategy.assert_called_with(strategy_name="sw-upgrade")
|
||||||
|
|
||||||
# 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.assert_step_updated(self.strategy_step.subcloud_id, self.on_success_state)
|
||||||
self.strategy_step.subcloud_id, self.on_success_state)
|
|
||||||
|
@mock.patch(
|
||||||
|
"dcmanager.orchestrator.states.applying_vim_strategy."
|
||||||
|
"DEFAULT_MAX_FAILED_QUERIES",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
@mock.patch(
|
||||||
|
"dcmanager.orchestrator.states.applying_vim_strategy."
|
||||||
|
"DEFAULT_MAX_WAIT_ATTEMPTS",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
@mock.patch("dcmanager.orchestrator.states.applying_vim_strategy.WAIT_INTERVAL", 1)
|
||||||
|
@mock.patch(
|
||||||
|
"dcmanager.orchestrator.states.applying_vim_strategy."
|
||||||
|
"ApplyingVIMStrategyState.__init__.__defaults__",
|
||||||
|
(3, 1),
|
||||||
|
)
|
||||||
|
@mock.patch.object(exceptions, "ApplyVIMStrategyFailedException")
|
||||||
|
def test_apply_vim_software_strategy_apply_failed(self, mock_exception):
|
||||||
|
"""Test apply vim software strategy apply failed"""
|
||||||
|
|
||||||
|
self.vim_client.get_strategy.side_effect = [
|
||||||
|
STRATEGY_READY_TO_APPLY,
|
||||||
|
STRATEGY_APPLYING,
|
||||||
|
STRATEGY_APPLY_FAILED,
|
||||||
|
]
|
||||||
|
|
||||||
|
# API calls acts as expected
|
||||||
|
self.vim_client.apply_strategy.return_value = STRATEGY_APPLYING
|
||||||
|
|
||||||
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# Assert ApplyVIMStrategyFailedException is called with the correct parameters
|
||||||
|
expected_message = f"VIM strategy apply failed: {APPLY_PHASE_ERROR.response}"
|
||||||
|
mock_exception.assert_called_once_with(
|
||||||
|
subcloud=self.subcloud.name,
|
||||||
|
name=vim.STRATEGY_NAME_SW_USM,
|
||||||
|
state=vim.STATE_APPLY_FAILED,
|
||||||
|
details=expected_message,
|
||||||
|
)
|
||||||
|
@ -8,14 +8,21 @@ import mock
|
|||||||
|
|
||||||
from dccommon.drivers.openstack import vim
|
from dccommon.drivers.openstack import vim
|
||||||
from dcmanager.common import consts
|
from dcmanager.common import consts
|
||||||
|
from dcmanager.common import exceptions
|
||||||
from dcmanager.tests.unit.common import fake_strategy
|
from dcmanager.tests.unit.common import fake_strategy
|
||||||
from dcmanager.tests.unit.fakes import FakeVimStrategy
|
from dcmanager.tests.unit import fakes
|
||||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import (
|
from dcmanager.tests.unit.orchestrator.states.software.test_base import (
|
||||||
TestSoftwareOrchestrator,
|
TestSoftwareOrchestrator,
|
||||||
)
|
)
|
||||||
|
|
||||||
STRATEGY_BUILDING = FakeVimStrategy(state=vim.STATE_BUILDING)
|
STRATEGY_BUILDING = fakes.FakeVimStrategy(state=vim.STATE_BUILDING)
|
||||||
STRATEGY_DONE_BUILDING = FakeVimStrategy(state=vim.STATE_READY_TO_APPLY)
|
BUILD_PHASE_ERROR = fakes.FakeVimStrategyPhase(
|
||||||
|
response="Installed license is valid: [FAIL]"
|
||||||
|
)
|
||||||
|
STRATEGY_BUILDING_FAILED = fakes.FakeVimStrategy(
|
||||||
|
state=vim.STATE_BUILD_FAILED, build_phase=BUILD_PHASE_ERROR
|
||||||
|
)
|
||||||
|
STRATEGY_DONE_BUILDING = fakes.FakeVimStrategy(state=vim.STATE_READY_TO_APPLY)
|
||||||
RELEASE_ID = "starlingx-9.0.1"
|
RELEASE_ID = "starlingx-9.0.1"
|
||||||
|
|
||||||
|
|
||||||
@ -72,3 +79,26 @@ class TestCreateVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
|||||||
|
|
||||||
# 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.on_success_state)
|
self.assert_step_updated(self.strategy_step.subcloud_id, self.on_success_state)
|
||||||
|
|
||||||
|
@mock.patch.object(exceptions, "CreateVIMStrategyFailedException")
|
||||||
|
def test_create_vim_software_strategy_build_failed(self, mock_exception):
|
||||||
|
"""Test create vim software strategy build failed"""
|
||||||
|
|
||||||
|
self.vim_client.get_strategy.side_effect = [
|
||||||
|
None,
|
||||||
|
STRATEGY_BUILDING_FAILED,
|
||||||
|
]
|
||||||
|
|
||||||
|
# API calls acts as expected
|
||||||
|
self.vim_client.create_strategy.return_value = STRATEGY_BUILDING
|
||||||
|
|
||||||
|
self.worker.perform_state_action(self.strategy_step)
|
||||||
|
|
||||||
|
# Assert ApplyVIMStrategyFailedException is called with the correct parameters
|
||||||
|
expected_message = f"VIM strategy build failed: {BUILD_PHASE_ERROR.response}"
|
||||||
|
mock_exception.assert_called_once_with(
|
||||||
|
subcloud=self.subcloud.name,
|
||||||
|
name=vim.STRATEGY_NAME_SW_USM,
|
||||||
|
state=vim.STATE_BUILD_FAILED,
|
||||||
|
details=expected_message,
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user