Create software swact controller state
This updates the upgrade orchestration swact state to the software orchestration. Perform swact to standby host after release installation. Test Plan: 1. Enable USM for dcmanager and dcorch by setting use_usm: True in their configuration files. 2. Upload and install the patch on the System Controller, then activate/complete. 3. Execute Software Subcloud Orchestration. - Ensure the successful swact of hosts. Story: 2010676 Task: 49053 Change-Id: I0dcee6bf38f1f77e63a426160a5da8c0089e4641 Signed-off-by: Hugo Brito <hugo.brito@windriver.com>
This commit is contained in:
parent
64febc50fb
commit
5494dc88a8
@ -153,7 +153,8 @@ 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 = "software swact 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"
|
||||
|
@ -33,8 +33,10 @@ from dcmanager.orchestrator.states.software.lock_controller \
|
||||
import LockControllerState
|
||||
from dcmanager.orchestrator.states.software.pre_check \
|
||||
import PreCheckState
|
||||
from dcmanager.orchestrator.states.software.swact_controller \
|
||||
import SwactControllerState
|
||||
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 \
|
||||
@ -70,9 +72,10 @@ class SoftwareOrchThread(OrchThread):
|
||||
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: SwactControllerState,
|
||||
consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_0: SwactController0State,
|
||||
consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY: CreateVIMSoftwareStrategyState,
|
||||
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,
|
||||
|
@ -13,7 +13,7 @@ class ApplyVIMSoftwareStrategyState(BaseState):
|
||||
|
||||
def __init__(self, region_name):
|
||||
super(ApplyVIMSoftwareStrategyState, self).__init__(
|
||||
next_state=consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE,
|
||||
next_state=consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_1,
|
||||
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 SwactControllerState(BaseState):
|
||||
"""Swact controller software orchestration state"""
|
||||
|
||||
def __init__(self, region_name):
|
||||
super(SwactControllerState, self).__init__(
|
||||
next_state=consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY,
|
||||
region_name=region_name,
|
||||
)
|
||||
|
||||
def perform_state_action(self, strategy_step):
|
||||
"""Swact controller region status"""
|
||||
return self.next_state
|
@ -0,0 +1,19 @@
|
||||
#
|
||||
# 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",)
|
@ -0,0 +1,18 @@
|
||||
#
|
||||
# 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")
|
@ -13,7 +13,7 @@ class TestApplyVIMSoftwareStrategyState(TestSoftwareOrchestrator):
|
||||
def setUp(self):
|
||||
super(TestApplyVIMSoftwareStrategyState, self).setUp()
|
||||
|
||||
self.on_success_state = consts.STRATEGY_STATE_SW_DEPLOY_ACTIVATE
|
||||
self.on_success_state = consts.STRATEGY_STATE_SW_SWACT_CONTROLLER_1
|
||||
|
||||
# Add the subcloud being processed by this unit test
|
||||
self.subcloud = self.setup_subcloud()
|
||||
|
@ -4,29 +4,145 @@
|
||||
# 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
|
||||
|
||||
|
||||
class TestSwactControllerState(TestSoftwareOrchestrator):
|
||||
def setUp(self):
|
||||
super(TestSwactControllerState, self).setUp()
|
||||
@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
|
||||
|
||||
self.on_success_state = consts.STRATEGY_STATE_SW_CREATE_VIM_STRATEGY
|
||||
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, consts.STRATEGY_STATE_SW_SWACT_CONTROLLER)
|
||||
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)
|
||||
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")
|
||||
|
@ -213,6 +213,9 @@ class TestSwUpdate(base.DCManagerTestCase):
|
||||
management_state=dccommon_consts.MANAGEMENT_MANAGED,
|
||||
availability_status=dccommon_consts.AVAILABILITY_ONLINE)
|
||||
|
||||
def delete_subcloud(self, subcloud_id):
|
||||
return db_api.subcloud_destroy(self.ctx, subcloud_id)
|
||||
|
||||
def setup_strategy_step(self, subcloud_id, strategy_state):
|
||||
fake_strategy.create_fake_strategy_step(
|
||||
self.ctx,
|
||||
@ -220,6 +223,9 @@ class TestSwUpdate(base.DCManagerTestCase):
|
||||
state=strategy_state)
|
||||
return db_api.strategy_step_get(self.ctx, subcloud_id)
|
||||
|
||||
def clean_strategy_steps(self):
|
||||
return db_api.strategy_step_destroy_all(self.ctx)
|
||||
|
||||
def assert_step_updated(self, subcloud_id, update_state):
|
||||
step = db_api.strategy_step_get(self.ctx, subcloud_id)
|
||||
self.assertEqual(update_state, step.state)
|
||||
|
Loading…
Reference in New Issue
Block a user