diff --git a/.zuul.yaml b/.zuul.yaml index c32683de..700ec1c8 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -30,8 +30,10 @@ description: Run py39 for nfv nodeset: debian-bullseye required-projects: + - starlingx/config - starlingx/fault - starlingx/root + - starlingx/update vars: tox_extra_args: -c nfv/tox.ini tox_constraints_file: '{{ ansible_user_dir }}/src/opendev.org/starlingx/root/build-tools/requirements/debian/upper-constraints.txt' @@ -61,8 +63,10 @@ description: Run pylint for nfv nodeset: debian-bullseye required-projects: + - starlingx/config - starlingx/fault - starlingx/root + - starlingx/update vars: tox_envlist: pylint tox_extra_args: -c nfv/tox.ini diff --git a/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_deploy_strategy.py b/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_deploy_strategy.py index c6cc52d8..3356a2f6 100755 --- a/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_deploy_strategy.py +++ b/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_deploy_strategy.py @@ -20,6 +20,13 @@ from nfv_vim.strategy._strategy import SwUpgradeStrategy from nfv_unit_tests.tests import sw_update_testcase +INITIAL_RELEASE = "3.2.1" +PATCH_RELEASE_UPGRADE = "3.2.2" +# Minor and Major are both major release upgrades +MINOR_RELEASE_UPGRADE = "4.0.1" +MAJOR_RELEASE_UPGRADE = "4.0.1" + + # utility method for the formatting of unlock-hosts stage as dict # workers default to 5 retries with 120 second delay between attempts # std controllers and storage have 0 retries @@ -41,6 +48,7 @@ def _unlock_hosts_stage_as_dict(host_names, retry_count=5, retry_delay=120): sw_update_testcase.fake_timer) @mock.patch('nfv_vim.nfvi.nfvi_compute_plugin_disabled', sw_update_testcase.fake_nfvi_compute_plugin_disabled) +@mock.patch.object(nfvi.objects.v1.upgrade, 'SW_VERSION', INITIAL_RELEASE) class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): def create_sw_deploy_strategy(self, @@ -50,7 +58,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): max_parallel_worker_hosts=10, alarm_restrictions=SW_UPDATE_ALARM_RESTRICTION.STRICT, default_instance_action=SW_UPDATE_INSTANCE_ACTION.STOP_START, - release="123.1", + release=MAJOR_RELEASE_UPGRADE, rollback=False, nfvi_upgrade=None, single_controller=False @@ -179,6 +187,22 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): return controller_hosts, storage_hosts, worker_hosts, strategy + def test_is_major_release(self): + is_major_release = nfvi.objects.v1.is_major_release + assert is_major_release(INITIAL_RELEASE, MAJOR_RELEASE_UPGRADE) + assert is_major_release(INITIAL_RELEASE, MINOR_RELEASE_UPGRADE) + assert not is_major_release(INITIAL_RELEASE, PATCH_RELEASE_UPGRADE) + assert is_major_release("22.12", "24.09.1") + assert is_major_release("22.12", "24.09.1") + assert is_major_release("22.12", "24.09.1") + assert is_major_release("22.12", "24.09") + assert is_major_release("22.12.1", "24.09") + assert is_major_release("24.03", "24.09.1") + assert is_major_release("24.03", "24.09.1") + assert not is_major_release("22.12", "22.12") + assert not is_major_release("22.12", "22.12.1") + assert not is_major_release("22.12.2", "22.12.1") + @mock.patch('nfv_common.strategy._strategy.Strategy._build') def test_sw_deploy_strategy_build_steps(self, fake_build): """ @@ -233,6 +257,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -280,6 +305,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -310,8 +336,6 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): sw_update_testcase.validate_phase(apply_phase, expected_results) # pylint: disable=no-member - @mock.patch('nfv_vim.strategy._strategy.get_local_host_name', - sw_update_testcase.fake_host_name_flipper('controller-1', 'controller-0', n=2)) def test_sw_deploy_strategy_start_on_controller_1_aiodx(self): """ Test the sw_upgrade strategy start stages on controller-1: @@ -328,6 +352,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -342,7 +367,55 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_stages': 1, 'stages': [ {'name': 'sw-upgrade-start', - 'total_steps': 5, + 'total_steps': 3, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'start-upgrade', + 'release': release}, + {'name': 'system-stabilize', + 'timeout': 60}, + ] + } + ] + } + + sw_update_testcase.validate_strategy_persists(strategy) + sw_update_testcase.validate_phase(apply_phase, expected_results) + + # pylint: disable=no-member + def test_sw_deploy_strategy_start_on_controller_1_aiodx_major(self): + """ + Test the sw_upgrade strategy start stages on controller-1: + - dx + - major release + Verify: + - pass + """ + + release = "888.8" + _, strategy = self._gen_aiodx_hosts_and_strategy( + release=release, + nfvi_upgrade=nfvi.objects.v1.Upgrade( + release, + { + 'state': 'available', + 'reboot_required': True, + 'sw_version': MAJOR_RELEASE_UPGRADE, + }, + None, + None, + ) + ) + + strategy._add_upgrade_start_stage() + + apply_phase = strategy.apply_phase.as_dict() + + expected_results = { + 'total_stages': 1, + 'stages': [ + {'name': 'sw-upgrade-start', + 'total_steps': 4, 'steps': [ {'name': 'query-alarms'}, {'name': 'swact-hosts', @@ -351,8 +424,6 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'release': release}, {'name': 'system-stabilize', 'timeout': 60}, - {'name': 'swact-hosts', - 'entity_names': ['controller-0']}, ] } ] @@ -381,6 +452,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -430,6 +502,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -462,8 +535,6 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): sw_update_testcase.validate_phase(apply_phase, expected_results) # pylint: disable=no-member - @mock.patch('nfv_vim.strategy._strategy.get_local_host_name', - sw_update_testcase.fake_host_name_flipper('controller-1', 'controller-0', n=2)) def test_sw_deploy_strategy_complete_on_controller_1_aiodx(self): """ Test the sw_upgrade strategy complete stages on controller-1: @@ -480,6 +551,57 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, + }, + None, + None, + ) + ) + + strategy._add_upgrade_complete_stage() + + apply_phase = strategy.apply_phase.as_dict() + + expected_results = { + 'total_stages': 1, + 'stages': [ + {'name': 'sw-upgrade-complete', + 'total_steps': 4, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'activate-upgrade', + 'release': release}, + {'name': 'complete-upgrade', + 'release': release}, + {'name': 'system-stabilize', + 'timeout': 60}, + ] + } + ] + } + + sw_update_testcase.validate_strategy_persists(strategy) + sw_update_testcase.validate_phase(apply_phase, expected_results) + + # pylint: disable=no-member + def test_sw_deploy_strategy_complete_on_controller_1_aiodx_major(self): + """ + Test the sw_upgrade strategy complete stages on controller-1: + - dx + - major releasee + Verify: + - pass + """ + + release = "888.8" + _, strategy = self._gen_aiodx_hosts_and_strategy( + release=release, + nfvi_upgrade=nfvi.objects.v1.Upgrade( + release, + { + 'state': 'available', + 'reboot_required': True, + 'sw_version': MAJOR_RELEASE_UPGRADE, }, None, None, @@ -943,9 +1065,9 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): expected_reason = "Software release is already deployed or committed." bpr = strategy.build_phase - assert strategy._state == common_strategy.STRATEGY_STATE.BUILD_FAILED - assert bpr.result == common_strategy.STRATEGY_PHASE_RESULT.FAILED - assert bpr.result_reason == expected_reason, strategy.build_phase.result_reason + assert strategy._state == common_strategy.STRATEGY_STATE.BUILD_FAILED, strategy._state + assert bpr.result == common_strategy.STRATEGY_PHASE_RESULT.FAILED, bpr.result + assert bpr.result_reason == expected_reason, bpr.result_reason def test_sw_deploy_strategy_aiosx_already_committed(self): """ @@ -1158,6 +1280,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -1187,7 +1310,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_steps': 3, 'steps': [ {'name': 'query-alarms'}, - {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, {'name': 'system-stabilize', 'timeout': 30}, ] }, @@ -1196,7 +1319,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_steps': 3, 'steps': [ {'name': 'query-alarms'}, - {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, {'name': 'system-stabilize', 'timeout': 30}, ] }, @@ -1233,6 +1356,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': True, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -1262,12 +1386,12 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_steps': 7, 'steps': [ {'name': 'query-alarms'}, - {'name': 'swact-hosts', 'entity_names': ['controller-1']}, - {'name': 'lock-hosts', 'entity_names': ['controller-1']}, - {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, + {'name': 'swact-hosts', 'entity_names': ['controller-0']}, + {'name': 'lock-hosts', 'entity_names': ['controller-0']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, {'name': 'system-stabilize', 'timeout': 15}, {'name': 'unlock-hosts', - 'entity_names': ['controller-1'], 'retry_count': 0, 'retry_delay': 120}, + 'entity_names': ['controller-0'], 'retry_count': 0, 'retry_delay': 120}, {'name': 'wait-alarms-clear', 'timeout': 2400}, ] }, @@ -1276,12 +1400,12 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_steps': 7, 'steps': [ {'name': 'query-alarms'}, - {'name': 'swact-hosts', 'entity_names': ['controller-0']}, - {'name': 'lock-hosts', 'entity_names': ['controller-0']}, - {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, + {'name': 'swact-hosts', 'entity_names': ['controller-1']}, + {'name': 'lock-hosts', 'entity_names': ['controller-1']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, {'name': 'system-stabilize', 'timeout': 15}, {'name': 'unlock-hosts', - 'entity_names': ['controller-0'], 'retry_count': 0, 'retry_delay': 120}, + 'entity_names': ['controller-1'], 'retry_count': 0, 'retry_delay': 120}, {'name': 'wait-alarms-clear', 'timeout': 2400}, ] }, @@ -1320,6 +1444,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': False, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -1349,7 +1474,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_steps': 3, 'steps': [ {'name': 'query-alarms'}, - {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, {'name': 'system-stabilize', 'timeout': 30}, ] }, @@ -1358,7 +1483,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_steps': 3, 'steps': [ {'name': 'query-alarms'}, - {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, {'name': 'system-stabilize', 'timeout': 30}, ] }, @@ -1417,6 +1542,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': True, + 'sw_version': PATCH_RELEASE_UPGRADE, }, None, None, @@ -1441,6 +1567,128 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'system-stabilize', 'timeout': 60}, ], }, + { + 'name': 'sw-upgrade-controllers', + 'total_steps': 7, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'swact-hosts', 'entity_names': ['controller-0']}, + {'name': 'lock-hosts', 'entity_names': ['controller-0']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-0']}, + {'name': 'system-stabilize', 'timeout': 15}, + {'name': 'unlock-hosts', + 'entity_names': ['controller-0'], 'retry_count': 0, 'retry_delay': 120}, + {'name': 'wait-alarms-clear', 'timeout': 2400}, + ] + }, + { + 'name': 'sw-upgrade-controllers', + 'total_steps': 7, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'swact-hosts', 'entity_names': ['controller-1']}, + {'name': 'lock-hosts', 'entity_names': ['controller-1']}, + {'name': 'upgrade-hosts', 'entity_names': ['controller-1']}, + {'name': 'system-stabilize', 'timeout': 15}, + {'name': 'unlock-hosts', + 'entity_names': ['controller-1'], 'retry_count': 0, 'retry_delay': 120}, + {'name': 'wait-alarms-clear', 'timeout': 2400}, + ] + }, + { + 'name': 'sw-upgrade-storage-hosts', + 'total_steps': 6, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'lock-hosts', + 'entity_names': ['storage-0', 'storage-1', 'storage-2']}, + {'name': 'upgrade-hosts', + 'entity_names': ['storage-0', 'storage-1', 'storage-2']}, + {'name': 'system-stabilize', 'timeout': 15}, + {'name': 'unlock-hosts', + 'entity_names': ['storage-0', 'storage-1', 'storage-2']}, + {'name': 'wait-data-sync', 'timeout': 1800}, + ] + }, + { + 'name': 'sw-upgrade-worker-hosts', + 'total_steps': 6, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'lock-hosts', + 'entity_names': ['compute-0', 'compute-1', 'compute-2']}, + {'name': 'upgrade-hosts', + 'entity_names': ['compute-0', 'compute-1', 'compute-2']}, + {'name': 'system-stabilize', 'timeout': 15}, + {'name': 'unlock-hosts', + 'entity_names': ['compute-0', 'compute-1', 'compute-2']}, + {'name': 'wait-alarms-clear', 'timeout': 600}, + ] + }, + { + 'name': 'sw-upgrade-complete', + 'total_steps': 4, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'activate-upgrade', 'release': release}, + {'name': 'complete-upgrade', 'release': release}, + {'name': 'system-stabilize', 'timeout': 60}, + ], + }, + ], + } + + sw_update_testcase.validate_strategy_persists(strategy) + sw_update_testcase.validate_phase(apply_phase, expected_results) + + def test_sw_deploy_strategy_standard_apply_phase_rr_major(self): + """ + Test the sw_deploy strategy apply phase: + - standard + - rr + - parallel storage + - parallel workers + - major release + Verify: + - Pass + """ + + release = '888.8' + _, _, _, strategy = self._gen_standard_hosts_and_strategy( + release=release, + nfvi_upgrade=nfvi.objects.v1.Upgrade( + release, + { + 'state': 'available', + 'reboot_required': True, + 'sw_version': MAJOR_RELEASE_UPGRADE, + + }, + None, + None, + ) + ) + + fake_upgrade_obj = SwUpgrade() + strategy.sw_update_obj = fake_upgrade_obj + + strategy.build_complete(common_strategy.STRATEGY_RESULT.SUCCESS, "") + apply_phase = strategy.apply_phase.as_dict() + + expected_results = { + 'total_stages': 6, + 'stages': [ + { + 'name': 'sw-upgrade-start', + 'total_steps': 4, + 'steps': [ + {'name': 'query-alarms'}, + {'name': 'swact-hosts', + 'entity_names': ['controller-1']}, + {'name': 'start-upgrade', 'release': release}, + {'name': 'system-stabilize', 'timeout': 60}, + ], + }, { 'name': 'sw-upgrade-controllers', 'total_steps': 7, @@ -1501,9 +1749,11 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): }, { 'name': 'sw-upgrade-complete', - 'total_steps': 4, + 'total_steps': 5, 'steps': [ {'name': 'query-alarms'}, + {'name': 'swact-hosts', + 'entity_names': ['controller-1']}, {'name': 'activate-upgrade', 'release': release}, {'name': 'complete-upgrade', 'release': release}, {'name': 'system-stabilize', 'timeout': 60}, diff --git a/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_upgrade_strategy.py b/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_upgrade_strategy.py index 300e9b0f..2ec68f17 100755 --- a/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_upgrade_strategy.py +++ b/nfv/nfv-tests/nfv_unit_tests/tests/test_sw_upgrade_strategy.py @@ -21,6 +21,21 @@ from nfv_vim.strategy._strategy import SwUpgradeStrategy from nfv_unit_tests.tests import sw_update_testcase +INITIAL_RELEASE = "3.2.1" +PATCH_RELEASE_UPGRADE = "3.2.2" +# Minor and Major are both major release upgrades +MINOR_RELEASE_UPGRADE = "4.0.1" +MAJOR_RELEASE_UPGRADE = "4.0.1" + +IGNORE_ALARMS_LIST = [ + "900.005", + "900.201", + "750.006", + "100.119", + "900.701", + "900.231", +] + # TODO(jkraitbe): Update this when retry count is decicded. # utility method for the formatting of unlock-hosts stage as dict @@ -44,6 +59,7 @@ def _unlock_hosts_stage_as_dict(host_names, retry_count=5, retry_delay=120): sw_update_testcase.fake_timer) @mock.patch('nfv_vim.nfvi.nfvi_compute_plugin_disabled', sw_update_testcase.fake_nfvi_compute_plugin_disabled) +@mock.patch.object(nfvi.objects.v1.upgrade, 'SW_VERSION', INITIAL_RELEASE) class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): def create_sw_upgrade_strategy(self, @@ -81,6 +97,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): { 'state': 'available', 'reboot_required': True, + 'sw_version': MAJOR_RELEASE_UPGRADE, }, None, None, @@ -1162,7 +1179,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'system-stabilize', 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-0']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] } @@ -1212,7 +1229,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'system-stabilize', 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-0']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400}, ] }, @@ -1229,7 +1246,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'system-stabilize', 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-1']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400}, ] } @@ -1301,7 +1318,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'system-stabilize', 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-0']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] }, @@ -1318,7 +1335,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'system-stabilize', 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-1']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] }, @@ -1407,9 +1424,11 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_stages': 8, 'stages': [ {'name': 'sw-upgrade-start', - 'total_steps': 3, + 'total_steps': 4, 'steps': [ {'name': 'query-alarms'}, + {'name': 'swact-hosts', + 'entity_names': ['controller-1']}, {'name': 'start-upgrade', 'release': strategy.nfvi_upgrade.release}, {'name': 'system-stabilize', @@ -1430,7 +1449,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-1']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] }, @@ -1448,7 +1467,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-0']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] }, @@ -1465,7 +1484,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'unlock-hosts', 'entity_names': ['storage-0']}, {'name': 'wait-data-sync', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 1800} ] }, @@ -1482,7 +1501,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): {'name': 'unlock-hosts', 'entity_names': ['storage-1']}, {'name': 'wait-data-sync', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 1800} ] }, @@ -1522,9 +1541,11 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): ] }, {'name': 'sw-upgrade-complete', - 'total_steps': 4, + 'total_steps': 5, 'steps': [ {'name': 'query-alarms'}, + {'name': 'swact-hosts', + 'entity_names': ['controller-1']}, {'name': 'activate-upgrade', 'release': strategy.nfvi_upgrade.release}, {'name': 'complete-upgrade', @@ -1540,8 +1561,6 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): sw_update_testcase.validate_phase(apply_phase, expected_results) # pylint: disable=no-member - @mock.patch('nfv_vim.strategy._strategy.get_local_host_name', - sw_update_testcase.fake_host_name_flipper('controller-1', 'controller-0', n=2)) def test_sw_upgrade_strategy_build_complete_serial_migrate(self): """ Test the sw_upgrade strategy build_complete: @@ -1575,7 +1594,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'total_stages': 6, 'stages': [ {'name': 'sw-upgrade-start', - 'total_steps': 5, + 'total_steps': 4, 'steps': [ {'name': 'query-alarms'}, {'name': 'swact-hosts', @@ -1584,8 +1603,6 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'release': strategy.nfvi_upgrade.release}, {'name': 'system-stabilize', 'timeout': 60}, - {'name': 'swact-hosts', - 'entity_names': ['controller-0']}, ] }, {'name': 'sw-upgrade-controllers', @@ -1602,7 +1619,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-1']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] }, @@ -1620,7 +1637,7 @@ class TestSwUpgradeStrategy(sw_update_testcase.SwUpdateStrategyTestCase): 'timeout': 15}, _unlock_hosts_stage_as_dict(['controller-0']), {'name': 'wait-alarms-clear', - 'ignore_alarms': ['900.005', '900.201', '750.006', '100.119', '900.701'], + 'ignore_alarms': IGNORE_ALARMS_LIST, 'timeout': 2400} ] }, diff --git a/nfv/nfv-vim/nfv_vim/directors/_host_director.py b/nfv/nfv-vim/nfv_vim/directors/_host_director.py index 799df374..a6747079 100755 --- a/nfv/nfv-vim/nfv_vim/directors/_host_director.py +++ b/nfv/nfv-vim/nfv_vim/directors/_host_director.py @@ -7,6 +7,7 @@ import six from nfv_common import debug from nfv_common.helpers import coroutine +from nfv_common.helpers import get_local_host_name from nfv_common.helpers import Singleton from nfv_vim import nfvi @@ -716,6 +717,11 @@ class HostDirector(object): host_operation.operation_type)) self._host_operation = None + # We don't need to SWACT if we are already on the correct controller. + # This assumes that there will only ever two be controllers. + if len(host_names) == 1 and host_names[0] != get_local_host_name(): + return None + host_table = tables.tables_get_host_table() for host_name in host_names: host = host_table.get(host_name, None) diff --git a/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/__init__.py b/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/__init__.py index bcbd4b28..87f40869 100755 --- a/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/__init__.py +++ b/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/__init__.py @@ -1,8 +1,9 @@ # -# Copyright (c) 2015-2023 Wind River Systems, Inc. +# Copyright (c) 2015-2024 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # + from nfv_vim.nfvi.objects.v1._alarm import Alarm # noqa: F401 from nfv_vim.nfvi.objects.v1._alarm import ALARM_SEVERITY # noqa: F401 from nfv_vim.nfvi.objects.v1._guest_service import GUEST_SERVICE_ADMIN_STATE # noqa: F401 @@ -68,6 +69,8 @@ from nfv_vim.nfvi.objects.v1._subnet import Subnet # noqa: F401 from nfv_vim.nfvi.objects.v1._sw_patch import SwPatch # noqa: F401 from nfv_vim.nfvi.objects.v1._system import System # noqa: F401 from nfv_vim.nfvi.objects.v1._tenant import Tenant # noqa: F401 +from nfv_vim.nfvi.objects.v1._upgrade import is_major_release # noqa: F401 +import nfv_vim.nfvi.objects.v1._upgrade as upgrade # noqa: F401,H306 from nfv_vim.nfvi.objects.v1._upgrade import Upgrade # noqa: F401 from nfv_vim.nfvi.objects.v1._volume import Volume # noqa: F401 from nfv_vim.nfvi.objects.v1._volume import VOLUME_ACTION # noqa: F401 diff --git a/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/_upgrade.py b/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/_upgrade.py index f9444696..0d0ba8e7 100755 --- a/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/_upgrade.py +++ b/nfv/nfv-vim/nfv_vim/nfvi/objects/v1/_upgrade.py @@ -4,43 +4,19 @@ # SPDX-License-Identifier: Apache-2.0 # -from enum import Enum - from nfv_vim.nfvi.objects.v1._object import ObjectData +import software.states as usm_states +from tsconfig.tsconfig import SW_VERSION -# Enums from https://opendev.org/starlingx/update/src/branch/master/software/software/states.py -class RELEASE_STATES(Enum): - AVAILABLE = 'available' - UNAVAILABLE = 'unavailable' - DEPLOYING = 'deploying' - DEPLOYED = 'deployed' - REMOVING = 'removing' - COMMITTED = 'committed' +def is_major_release(to_release, from_release): + """Determine if this is a major release software deployment + Major release if major or minor version changed: + eg. 10.11.12 -> (11.1.1 or 10.12.1) + """ -class DEPLOY_STATES(Enum): - START = 'start' - START_DONE = 'start-done' - START_FAILED = 'start-failed' - - HOST = 'host' - HOST_DONE = 'host-done' - HOST_FAILED = 'host-failed' - - ACTIVATE = 'activate' - ACTIVATE_DONE = 'activate-done' - ACTIVATE_FAILED = 'activate-failed' - - ABORT = 'abort' - ABORT_DONE = 'abort-done' - - -class DEPLOY_HOST_STATES(Enum): - DEPLOYED = 'deployed' - DEPLOYING = 'deploying' - FAILED = 'failed' - PENDING = 'pending' + return to_release.split(".")[:2] != from_release.split(".")[:2] class Upgrade(ObjectData): @@ -75,50 +51,74 @@ class Upgrade(ObjectData): return self.release_info["reboot_required"] + @property + def sw_version(self): + if not self.release_info: + return None + + return self.release_info["sw_version"] + + @property + def major_release(self): + if not self.release_info: + return None + + return is_major_release(SW_VERSION, self.sw_version) + @property def is_available(self): - return self.release_state == RELEASE_STATES.AVAILABLE.value + return self.release_state == usm_states.AVAILABLE @property def is_deployed(self): - return self.release_state == RELEASE_STATES.DEPLOYED.value + return self.release_state == usm_states.DEPLOYED @property def is_committed(self): - return self.release_state == RELEASE_STATES.COMMITTED.value + return self.release_state == usm_states.COMMITTED @property def is_starting(self): - return self.deploy_state == DEPLOY_STATES.START.value + return self.deploy_state == usm_states.DEPLOY_STATES.START.value @property def is_start_done(self): - return self.deploy_state == DEPLOY_STATES.START_DONE.value + return self.deploy_state == usm_states.DEPLOY_STATES.START_DONE.value @property def is_start_failed(self): - return self.deploy_state == DEPLOY_STATES.START_FAILED.value + return self.deploy_state == usm_states.DEPLOY_STATES.START_FAILED.value @property def is_deploying_hosts(self): - return self.deploy_state == DEPLOY_STATES.HOST.value + return self.deploy_state == usm_states.DEPLOY_STATES.HOST.value @property def is_deploy_hosts_done(self): - return self.deploy_state == DEPLOY_STATES.HOST_DONE.value + return self.deploy_state == usm_states.DEPLOY_STATES.HOST_DONE.value @property def is_deploy_hosts_failed(self): - return self.deploy_state == DEPLOY_STATES.HOST_FAILED.value + return self.deploy_state == usm_states.DEPLOY_STATES.HOST_FAILED.value @property def is_activating(self): - return self.deploy_state == DEPLOY_STATES.ACTIVATE.value + return self.deploy_state == usm_states.DEPLOY_STATES.ACTIVATE.value @property def is_activate_done(self): - return self.deploy_state == DEPLOY_STATES.ACTIVATE_DONE.value + return self.deploy_state == usm_states.DEPLOY_STATES.ACTIVATE_DONE.value @property def is_activate_failed(self): - return self.deploy_state == DEPLOY_STATES.ACTIVATE_FAILED.value + return self.deploy_state == usm_states.DEPLOY_STATES.ACTIVATE_FAILED.value + + @property + def all_hosts_deployed(self): + if not self.hosts_info: + return None + + for v in self.hosts_info: + if v["host_state"] != usm_states.DEPLOY_HOST_STATES.DEPLOYED.value: + return False + return True diff --git a/nfv/nfv-vim/nfv_vim/strategy/_strategy.py b/nfv/nfv-vim/nfv_vim/strategy/_strategy.py index 6f5758fd..ce4019aa 100755 --- a/nfv/nfv-vim/nfv_vim/strategy/_strategy.py +++ b/nfv/nfv-vim/nfv_vim/strategy/_strategy.py @@ -1785,6 +1785,7 @@ class SwUpgradeStrategy( '750.006', # Configuration change requires reapply of cert-manager '100.119', # PTP alarm for SyncE '900.701', # Node tainted + '900.231', # Software deployment data is out of sync ] self._ignore_alarms += IGNORE_ALARMS self._single_controller = single_controller @@ -1864,12 +1865,9 @@ class SwUpgradeStrategy( Currently, certain steps during sw-deploy must be done on a specific controller. Here we insert arbitrary SWACTs to meet those requirements. - - If controller_name does not match the current active host we return because - we are already on ideal host. """ - if self._single_controller or controller_name != get_local_host_name(): + if self._single_controller or not self.nfvi_upgrade.major_release: return from nfv_vim import strategy @@ -1885,19 +1883,21 @@ class SwUpgradeStrategy( """ Add upgrade start strategy stage """ + from nfv_vim import strategy stage = strategy.StrategyStage(strategy.STRATEGY_STAGE_NAME.SW_UPGRADE_START) - stage.add_step(strategy.QueryAlarmsStep(True, ignore_alarms=self._ignore_alarms)) # If the release is not available the deployment is already started - # sw-deploy start must be done on controller-0 - self._swact_fix(stage, HOST_NAME.CONTROLLER_1) - stage.add_step(strategy.UpgradeStartStep(release=self._release, force=self._ignore_alarms)) - stage.add_step(strategy.SystemStabilizeStep()) - # TODO(jkraitbe): This SWACT should be part of deploy hosts logic - # sw-deploy host must first be on controller-1 - self._swact_fix(stage, HOST_NAME.CONTROLLER_0) + if self.nfvi_upgrade.is_available: + stage.add_step(strategy.QueryAlarmsStep(True, ignore_alarms=self._ignore_alarms)) + # sw-deploy start for major releases must be done on controller-0 + self._swact_fix(stage, HOST_NAME.CONTROLLER_1) + stage.add_step(strategy.UpgradeStartStep(release=self._release, force=self._ignore_alarms)) + stage.add_step(strategy.SystemStabilizeStep()) + else: + DLOG.info("Software deployment already inprogress, skipping start") + self.apply_phase.add_stage(stage) def _add_upgrade_complete_stage(self): @@ -1908,8 +1908,6 @@ class SwUpgradeStrategy( stage = strategy.StrategyStage(strategy.STRATEGY_STAGE_NAME.SW_UPGRADE_COMPLETE) stage.add_step(strategy.QueryAlarmsStep(ignore_alarms=self._ignore_alarms)) - # TODO(jkraitbe): This SWACT should be part of deploy hosts logic - # sw-deploy complete should be on controller-0 self._swact_fix(stage, HOST_NAME.CONTROLLER_1) stage.add_step(strategy.UpgradeActivateStep(release=self._release)) stage.add_step(strategy.UpgradeCompleteStep(release=self._release)) @@ -1988,13 +1986,6 @@ class SwUpgradeStrategy( self._add_upgrade_start_stage() - # TODO(jkraitbe): Exclude hosts that are already deployed. - # The hosts states are found in self.nfvi_upgrade.hosts_info. - # None means deployment hasn't started. - - # TODO(jkraitbe): SWACT to controller-1 should be - # here instead of in _add_upgrade_start_stage. - for host in host_table.values(): if HOST_PERSONALITY.CONTROLLER in host.personality: controllers_hosts.append(host) @@ -2020,8 +2011,12 @@ class SwUpgradeStrategy( self.save() return - # Reverse controller hosts so controller-1 is first - controllers_hosts = controllers_hosts[::-1] + if not self._single_controller and self.nfvi_upgrade.major_release: + # Reverse controller hosts so controller-1 is first + controllers_hosts = sorted( + controllers_hosts, + key=lambda x: x.name == HOST_NAME.CONTROLLER_0, + ) strategy_pairs = [ (controller_strategy, controllers_hosts), diff --git a/nfv/nfv-vim/nfv_vim/strategy/_strategy_steps.py b/nfv/nfv-vim/nfv_vim/strategy/_strategy_steps.py index e2acc27d..d9914a44 100755 --- a/nfv/nfv-vim/nfv_vim/strategy/_strategy_steps.py +++ b/nfv/nfv-vim/nfv_vim/strategy/_strategy_steps.py @@ -623,9 +623,12 @@ class SwactHostsStep(strategy.StrategyStep): DLOG.info("Step (%s) apply for hosts %s." % (self._name, self._host_names)) + host_director = directors.get_host_director() operation = host_director.swact_hosts(self._host_names) - if operation.is_inprogress(): + if operation is None: + return strategy.STRATEGY_STEP_RESULT.SUCCESS, "Already on correct host" + elif operation.is_inprogress(): return strategy.STRATEGY_STEP_RESULT.WAIT, "" elif operation.is_failed(): return strategy.STRATEGY_STEP_RESULT.FAILED, operation.reason diff --git a/nfv/tox.ini b/nfv/tox.ini index c21dcb7d..4fd3aa23 100644 --- a/nfv/tox.ini +++ b/nfv/tox.ini @@ -31,6 +31,8 @@ nfv_plugins_dir = ./nfv-plugins nfv_vim_dir = ./nfv-vim nfv_test_dir = ./nfv-tests stx_fault_dir = ../../fault +stx_tsconfig_dir = ../../config/tsconfig/tsconfig +stx_software_dir = ../../update/software nfv_client_src_dir = {[nfv]nfv_client_dir}/nfv_client nfv_common_src_dir = {[nfv]nfv_common_dir}/nfv_common @@ -43,6 +45,8 @@ deps = -e{[nfv]nfv_client_dir} -e{[nfv]nfv_plugins_dir} -e{[nfv]nfv_vim_dir} -e{[nfv]stx_fault_dir}/fm-api/source + -e{[nfv]stx_tsconfig_dir} + -e{[nfv]stx_software_dir} iso8601 keyring kombu