Create finish software strategy

Create finish software strategy for the upgrade orchestrator,
this state will commit the patches from the subcloud that are committed
in systemcontroller and it will delete releases from the subcloud that
are available or unavailable and not present in the systemcontroller.

Story: 2010676
Task: 48825

Test Case (Patching only):
PASS: Apply and commit a patch to the systemcontroller and apply the
same patch to the subcloud and run the upgrade orchestration and
verify that the patch from the subcloud is committed.
PASS: Upload a patch to the subcloud and run the upgrade orchestration
and verify that the patch is deleted from the subcloud.
PASS: Upload a patch to subcloud, protect the patch metadata file
with chattr +i, create and apply a upgrade strategy and verify
that the orchestrator failed to delete that patch and the correct
error message is presented.

Signed-off-by: Christopher Souza <Christopher.DeOliveiraSouza@windriver.com>
Change-Id: I2dae16800235891fc863151b307313732e8d49cd
This commit is contained in:
Christopher Souza
2023-09-25 08:01:31 -03:00
committed by Christopher de Oliveira Souza
parent 2438807fc8
commit e741c5d131
2 changed files with 134 additions and 5 deletions

View File

@@ -3,13 +3,16 @@
#
# SPDX-License-Identifier: Apache-2.0
#
from dccommon.drivers.openstack import software_v1
from dcmanager.common import consts
from dcmanager.common.exceptions import StrategyStoppedException
from dcmanager.orchestrator.states.base import BaseState
from dcmanager.orchestrator.states.software.cache.cache_specifications import \
REGION_ONE_RELEASE_USM_CACHE_TYPE
class FinishStrategyState(BaseState):
"""Finish Strategy software orchestration state"""
"""Finish Software Strategy software orchestration state"""
def __init__(self, region_name):
super(FinishStrategyState, self).__init__(
@@ -18,5 +21,68 @@ class FinishStrategyState(BaseState):
)
def perform_state_action(self, strategy_step):
"""Finish Strategy region status"""
"""Finish Software Strategy"""
self.info_log(strategy_step, "Finishing software strategy")
regionone_committed_releases = self._read_from_cache(
REGION_ONE_RELEASE_USM_CACHE_TYPE,
state=software_v1.COMMITTED
)
self.debug_log(strategy_step,
"regionone_committed_releases: %s" % regionone_committed_releases)
try:
software_client = self.get_software_client(self.region_name)
subcloud_releases = software_client.query()
except Exception:
message = ("Cannot retrieve subcloud releases. Please see logs for"
" details.")
self.exception_log(strategy_step, message)
raise Exception(message)
self.debug_log(strategy_step,
"Releases for subcloud: %s" % subcloud_releases)
releases_to_commit = list()
releases_to_delete = list()
# For this subcloud, determine which releases should be committed and
# which should be deleted.
for release_id in subcloud_releases:
if (subcloud_releases[release_id]['state'] ==
software_v1.AVAILABLE or
subcloud_releases[release_id]['state'] ==
software_v1.UNAVAILABLE):
releases_to_delete.append(release_id)
elif subcloud_releases[release_id]['state'] == \
software_v1.DEPLOYED:
if release_id in regionone_committed_releases:
releases_to_commit.append(release_id)
if releases_to_delete:
self.info_log(strategy_step, "Deleting releases %s" % releases_to_delete)
try:
software_client.delete(releases_to_delete)
except Exception:
message = ("Cannot delete releases from subcloud. Please see logs for"
" details.")
self.exception_log(strategy_step, message)
raise Exception(message)
if self.stopped():
raise StrategyStoppedException()
if releases_to_commit:
self.info_log(strategy_step,
"Committing releases %s to subcloud" % releases_to_commit)
try:
software_client.commit_patch(releases_to_commit)
except Exception:
message = ("Cannot commit releases to subcloud. Please see logs for"
" details.")
self.exception_log(strategy_step, message)
raise Exception(message)
return self.next_state

View File

@@ -3,14 +3,41 @@
#
# SPDX-License-Identifier: Apache-2.0
#
import mock
from oslo_config import cfg
from dcmanager.common import consts
from dcmanager.orchestrator.states.software.finish_strategy import \
FinishStrategyState
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
TestSoftwareOrchestrator
REGION_ONE_RELEASES = {"DC.1": {"sw_version": "20.12",
"state": "committed"},
"DC.2": {"sw_version": "20.12",
"state": "committed"},
"DC.3": {"sw_version": "20.12",
"state": "committed"},
"DC.8": {"sw_version": "20.12",
"state": "committed"}}
SUBCLOUD_RELEASES = {"DC.1": {"sw_version": "20.12",
"state": "committed"},
"DC.2": {"sw_version": "20.12",
"state": "committed"},
"DC.3": {"sw_version": "20.12",
"state": "deployed"},
"DC.9": {"sw_version": "20.12",
"state": "available"}}
class TestFinishStrategyState(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(TestFinishStrategyState, self).setUp()
self.on_success_state = consts.STRATEGY_STATE_COMPLETE
@@ -22,11 +49,47 @@ class TestFinishStrategyState(TestSoftwareOrchestrator):
self.strategy_step = self.setup_strategy_step(
self.subcloud.id, consts.STRATEGY_STATE_SW_FINISH_STRATEGY)
def test_finish_strategy_success(self):
"""Test finish strategy when the API call succeeds."""
# Add mock API endpoints for software client calls
# invoked by this state
self.software_client.query = mock.MagicMock()
self.software_client.delete = mock.MagicMock()
self.software_client.commit_patch = mock.MagicMock()
self._read_from_cache = mock.MagicMock()
@mock.patch.object(FinishStrategyState, '_read_from_cache')
def test_finish_strategy_success(self, mock_read_from_cache):
"""Test software finish strategy when the API call succeeds."""
mock_read_from_cache.return_value = REGION_ONE_RELEASES
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)
call_args, _ = self.software_client.delete.call_args_list[0]
self.assertItemsEqual(['DC.9'], call_args[0])
call_args, _ = self.software_client.commit_patch.call_args_list[0]
self.assertItemsEqual(['DC.3'], call_args[0])
# 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(FinishStrategyState, '_read_from_cache')
def test_finish_strategy_no_operation_required(self, mock_read_from_cache):
"""Test software finish strategy when no 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.delete.assert_not_called()
self.software_client.commit_patch.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)