228 lines
7.9 KiB
Python
228 lines
7.9 KiB
Python
#
|
|
# Copyright (c) 2022-2024 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
import base64
|
|
import copy
|
|
import threading
|
|
|
|
import mock
|
|
|
|
from dccommon.utils import AnsiblePlaybook
|
|
from dcmanager.common import consts
|
|
from dcmanager.common.consts import STRATEGY_STATE_COMPLETE
|
|
from dcmanager.common.consts import STRATEGY_STATE_FAILED
|
|
from dcmanager.common.consts import STRATEGY_STATE_PRESTAGE_IMAGES
|
|
from dcmanager.common.consts import STRATEGY_STATE_PRESTAGE_PACKAGES
|
|
from dcmanager.common.consts import STRATEGY_STATE_PRESTAGE_PRE_CHECK
|
|
from dcmanager.common import exceptions
|
|
from dcmanager.db.sqlalchemy import api as db_api
|
|
from dcmanager.tests.unit.common import fake_strategy
|
|
from dcmanager.tests.unit.orchestrator.test_base import TestSwUpdate
|
|
|
|
FAKE_PASSWORD = (base64.b64encode('testpass'.encode('utf-8'))).decode('ascii')
|
|
OAM_FLOATING_IP = '10.10.10.12'
|
|
REQUIRED_EXTRA_ARGS = {
|
|
'sysadmin_password': FAKE_PASSWORD,
|
|
'force': False
|
|
}
|
|
|
|
|
|
class TestPrestage(TestSwUpdate):
|
|
# Setting DEFAULT_STRATEGY_TYPE to prestage will setup the prestage upgrade
|
|
# orchestration worker and will mock away the other orch threads
|
|
DEFAULT_STRATEGY_TYPE = consts.SW_UPDATE_TYPE_PRESTAGE
|
|
strategy_step = None
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self.strategy_step = None
|
|
# Add the subcloud being processed by this unit test
|
|
# The subcloud is online, managed with deploy_state 'installed'
|
|
self.subcloud = self.setup_subcloud(deploy_status=consts.DEPLOY_STATE_DONE)
|
|
|
|
self.required_extra_args_with_oam = copy.copy(REQUIRED_EXTRA_ARGS)
|
|
self.required_extra_args_with_oam["oam_floating_ip_dict"] = {
|
|
self.subcloud.name: OAM_FLOATING_IP
|
|
}
|
|
|
|
def _setup_strategy_step(self, strategy_step):
|
|
self.strategy_step = self.setup_strategy_step(
|
|
self.subcloud.id, strategy_step
|
|
)
|
|
|
|
def _setup_and_assert(self, next_state, extra_args=None):
|
|
self.strategy = fake_strategy.create_fake_strategy(
|
|
self.ctx, self.DEFAULT_STRATEGY_TYPE, extra_args=extra_args
|
|
)
|
|
|
|
# invoke the strategy state operation on the orch thread
|
|
self.worker.perform_state_action(self.strategy_step)
|
|
|
|
# Verify the transition to the expected next state
|
|
self.assert_step_updated(self.strategy_step.subcloud_id, next_state)
|
|
|
|
|
|
class TestPrestagePreCheckState(TestPrestage):
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self._setup_strategy_step(STRATEGY_STATE_PRESTAGE_PRE_CHECK)
|
|
|
|
self._mock_validate_prestage()
|
|
self._mock_threading_start()
|
|
|
|
def _mock_validate_prestage(self):
|
|
"""Mock dcmanager's common validate_prestage method
|
|
|
|
The validate_prestage method is mocked because the focus is on testing
|
|
the orchestrator logic only. Any specifc prestage functionality is covered on
|
|
individual tests.
|
|
"""
|
|
|
|
mock_class = mock.patch('dcmanager.common.prestage.validate_prestage')
|
|
self.mock_prestage_subcloud = mock_class.start()
|
|
self.mock_prestage_subcloud.return_value = OAM_FLOATING_IP
|
|
self.addCleanup(mock_class.stop)
|
|
|
|
def _mock_threading_start(self):
|
|
"""Mock threading's Thread.start"""
|
|
|
|
mock_thread = mock.patch.object(threading.Thread, 'start')
|
|
self.mock_thread_start = mock_thread.start()
|
|
self.addCleanup(mock_thread.stop)
|
|
|
|
def test_prestage_pre_check_without_extra_args(self):
|
|
"""Test prestage pre check without extra args"""
|
|
|
|
self._setup_and_assert(STRATEGY_STATE_FAILED)
|
|
|
|
def test_prestage_pre_check_validate_failed_with_orch_skip_false(self):
|
|
"""Test prestage pre check validate failed with orch skip as false"""
|
|
|
|
self.mock_prestage_subcloud.side_effect = \
|
|
exceptions.PrestagePreCheckFailedException(
|
|
subcloud=None, orch_skip=False, details='test'
|
|
)
|
|
|
|
self._setup_and_assert(STRATEGY_STATE_FAILED, extra_args=REQUIRED_EXTRA_ARGS)
|
|
|
|
new_strategy_step = db_api.strategy_step_get(
|
|
self.ctx, self.subcloud.id
|
|
)
|
|
|
|
# The strategy step details field should be updated with the Exception string
|
|
self.assertTrue('test' in str(new_strategy_step.details))
|
|
|
|
def test_prestage_pre_check_validate_failed_with_orch_skip_true(self):
|
|
"""Test prestage pre check validate failed with orch skip as true"""
|
|
|
|
self.mock_prestage_subcloud.side_effect = \
|
|
exceptions.PrestagePreCheckFailedException(
|
|
subcloud=None, orch_skip=True, details='test'
|
|
)
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_COMPLETE, extra_args=REQUIRED_EXTRA_ARGS
|
|
)
|
|
|
|
new_strategy_step = db_api.strategy_step_get(
|
|
self.ctx, self.subcloud.id
|
|
)
|
|
|
|
# The strategy step details field should be updated with the Exception string
|
|
self.assertTrue("test" in str(new_strategy_step.details))
|
|
|
|
def test_prestage_pre_check_fails_with_generic_exception(self):
|
|
"""Test prestage pre check fails with generic exception"""
|
|
|
|
self.mock_prestage_subcloud.side_effect = Exception()
|
|
|
|
self._setup_and_assert(STRATEGY_STATE_FAILED, extra_args=REQUIRED_EXTRA_ARGS)
|
|
|
|
def test_prestage_pre_check_succeeds(self):
|
|
"""Test prestage pre check succeeds"""
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_PRESTAGE_PACKAGES, extra_args=REQUIRED_EXTRA_ARGS
|
|
)
|
|
|
|
def test_prestage_pre_check_succeeds_with_oam_floating_ip_dict(self):
|
|
"""Test prestage pre check succeeds with oam floating ip dict"""
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_PRESTAGE_PACKAGES,
|
|
extra_args=self.required_extra_args_with_oam
|
|
)
|
|
|
|
def test_prestage_pre_check_succeds_with_prestage_software_version(self):
|
|
"""Test prestage pre check succeeds with prestage software version"""
|
|
|
|
extra_args = copy.copy(REQUIRED_EXTRA_ARGS)
|
|
extra_args['prestage-software-version'] = '22.3'
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_PRESTAGE_PACKAGES, extra_args=extra_args
|
|
)
|
|
|
|
|
|
class TestPrestagePackagesState(TestPrestage):
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self._setup_strategy_step(STRATEGY_STATE_PRESTAGE_PACKAGES)
|
|
|
|
self._mock_builtins_open()
|
|
self._mock_ansible_playbook()
|
|
|
|
def _mock_ansible_playbook(self):
|
|
mock_patch_object = mock.patch.object(AnsiblePlaybook, 'run_playbook')
|
|
self.mock_ansible_playbook = mock_patch_object.start()
|
|
self.addCleanup(mock_patch_object.stop)
|
|
|
|
def test_prestage_package_succeeds(self):
|
|
"""Test prestage package succeeds"""
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_PRESTAGE_IMAGES,
|
|
extra_args=self.required_extra_args_with_oam
|
|
)
|
|
|
|
def test_prestage_package_succeeds_with_prestage_software_version(self):
|
|
"""Test prestage package succeeds with prestage software version"""
|
|
|
|
extra_args = copy.copy(self.required_extra_args_with_oam)
|
|
extra_args['prestage-software-version'] = '22.3'
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_PRESTAGE_IMAGES, extra_args=extra_args
|
|
)
|
|
|
|
|
|
class TestPrestageImagesState(TestPrestage):
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self._setup_strategy_step(STRATEGY_STATE_PRESTAGE_IMAGES)
|
|
|
|
self._mock_os_path_isdir()
|
|
self.mock_os_path_isdir.return_value = False
|
|
|
|
def test_prestage_images_succeeds(self):
|
|
"""Test prestage images succeeds"""
|
|
|
|
self._setup_and_assert(
|
|
STRATEGY_STATE_COMPLETE, extra_args=self.required_extra_args_with_oam
|
|
)
|
|
|
|
def test_prestage_images_succeeds_with_prestage_software_version(self):
|
|
"""Test prestage images succeeds with prestage software version"""
|
|
|
|
extra_args = copy.copy(self.required_extra_args_with_oam)
|
|
extra_args['prestage-software-version'] = '22.3'
|
|
|
|
self._setup_and_assert(STRATEGY_STATE_COMPLETE, extra_args=extra_args)
|