149 lines
5.7 KiB
Python
149 lines
5.7 KiB
Python
#
|
|
# Copyright (c) 2023 Wind River Systems, Inc.
|
|
#
|
|
# 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
|
|
|
|
|
|
@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
|
|
|
|
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, 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
|
|
)
|
|
|
|
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")
|