From 8f8c7d3abbc2611853914f226bed040a942071c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20de=20Ara=C3=BAjo=20Cabral?= Date: Mon, 27 Mar 2023 14:57:31 -0400 Subject: [PATCH] Add validation to AIO-SX to AIO-DX migration command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In an SX with ceph backend configured and platform-integ-apps not applied, an unhandled error shows when the command "system modify --system_mode=duplex" is executed. After this error, the system_mode in sysinv db is changed to "duplex" and cannot change back to simplex, blocking further system CLI operation. It is necessary for an SX with the ceph backend configured to have platform-integ-apps applied to migrate to DX. With the fix, there is a validation checking that the system storage backend is able for a migration, raising a proper error if not. In addition, if the system is not ready, there are no changes in the sysinv db. Test-Plan: PASS: AIO-SX fresh install with ceph backend PASS: Use system modify --system_mode=duplex with platform-integ-apps not applied (uploaded or not) PASS: Verify the error message "Cannot modify system mode..." is printed on CLI PASS: Verify system_mode is still 'simplex' in the sysinv db PASS: Apply platform-integ-apps, use the same command, proceed with the migration and validate that it was successful PASS: AIO-SX fresh install without Ceph backend + successful migration to DX Closes-Bug: 2013069 Signed-off-by: Gabriel de Araújo Cabral Change-Id: Ib05c675b54c2b9fcfa3e7f92affec9ca37245df2 --- .../sysinv/api/controllers/v1/system.py | 17 +++++++ .../sysinv/sysinv/tests/api/test_system.py | 44 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py index c5af251a3c..6805585bf5 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/system.py @@ -334,6 +334,20 @@ class SystemController(rest.RestController): "locked." % controller.hostname) raise wsme.exc.ClientSideError(msg) + def _check_storage_backend_ready_for_migration(self): + ceph_backend = pecan.request.dbapi.storage_backend_get_list_by_type( + backend_type=constants.SB_TYPE_CEPH) + if ceph_backend: + msg = _("Cannot modify system mode to %s, %s must be " + "applied when ceph storage is configured as backend." % + (constants.SYSTEM_MODE_DUPLEX, constants.HELM_APP_PLATFORM)) + try: + helm_app = pecan.request.dbapi.kube_app_get(constants.HELM_APP_PLATFORM) + if helm_app.status != constants.APP_APPLY_SUCCESS: + raise wsme.exc.ClientSideError(msg) + except exception.KubeAppNotFound: + raise wsme.exc.ClientSideError(msg) + def _get_isystem_collection(self, marker, limit, sort_key, sort_dir, expand=False, resource_url=None): limit = api_utils.validate_limit(limit) @@ -461,6 +475,9 @@ class SystemController(rest.RestController): self._check_controller_locked() if new_system_mode != constants.SYSTEM_MODE_SIMPLEX: self._check_interfaces(new_system_mode) + if rpc_isystem.system_mode == constants.SYSTEM_MODE_SIMPLEX and \ + new_system_mode == constants.SYSTEM_MODE_DUPLEX: + self._check_storage_backend_ready_for_migration() if p['path'] == '/timezone': timezone = p['value'] diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_system.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_system.py index 6d81b89f72..a750095a6a 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_system.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_system.py @@ -233,6 +233,20 @@ class TestNetworkSetup(object): network_id=self.admin_network.id) +class TestStorageBackend(object): + def __init__(self, system, dbapi): + self.system = system + self.dbapi = dbapi + + def _create_ceph_storage_backend(self, backend_type=constants.SB_TYPE_CEPH): + backend = dbutils.get_test_ceph_storage_backend(backend=backend_type) + self.dbapi.storage_ceph_create(backend) + + def _create_helm_app(self, app_status, app_name=constants.HELM_APP_PLATFORM): + self.helm_app = dbutils.create_test_app(name=app_name, + status=app_status) + + @mock.patch('socket.gethostname', return_value='controller-0') class TestSystemUpdateModeFromSimplex(TestSystem): @@ -243,6 +257,7 @@ class TestSystemUpdateModeFromSimplex(TestSystem): system_mode=constants.SYSTEM_MODE_SIMPLEX) self.test_network = TestNetworkSetup(self.system, controller_administrative_status=constants.ADMIN_LOCKED) + self.test_storage_backend = TestStorageBackend(self.system, self.dbapi) @mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True) @@ -254,6 +269,35 @@ class TestSystemUpdateModeFromSimplex(TestSystem): self._patch_and_check(self._get_path(self.system.uuid), update) + @mock.patch('sysinv.common.utils.is_initial_config_complete', + return_value=True) + def test_update_system_mode_simplex_to_duplex_with_ceph_and_helm_app_applied(self, + mock_init_config, + mock_controller): + self.test_network._create_mgmt_interface_network() + self.test_network._create_cluster_host_interface_network() + self.test_storage_backend._create_ceph_storage_backend() + self.test_storage_backend._create_helm_app(app_status=constants.APP_APPLY_SUCCESS) + update = {"system_mode": constants.SYSTEM_MODE_DUPLEX} + self._patch_and_check(self._get_path(self.system.uuid), + update) + + @mock.patch('sysinv.common.utils.is_initial_config_complete', + return_value=True) + def test_update_system_mode_simplex_to_duplex_with_ceph_and_no_helm_app_applied(self, + mock_init_config, + mock_controller): + self.test_network._create_mgmt_interface_network() + self.test_network._create_cluster_host_interface_network() + self.test_storage_backend._create_ceph_storage_backend() + update = {"system_mode": constants.SYSTEM_MODE_DUPLEX} + msg = ("Cannot modify system mode to %s, %s must be " + "applied when ceph storage is configured as backend." % + (constants.SYSTEM_MODE_DUPLEX, constants.HELM_APP_PLATFORM)) + self._patch_and_check(self._get_path(self.system.uuid), + update, expect_errors=True, + expected_error_message=msg) + @mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True) def test_update_system_mode_simplex_to_duplex_mgmt_on_lo(self,