From 5463c223af8d9554ea44959f81c248d3809b74ef Mon Sep 17 00:00:00 2001 From: Gustavo Pereira Date: Wed, 5 Feb 2025 00:48:22 -0300 Subject: [PATCH] Subcloud restore backup yaml error handling This commit handles the exception raised when passing an invalid YAML file to subcloud backup restore command. Test Plan: PASS: Provision a subcloud and create its backup. Create an invalid backup YAML file for restore. Run subcloud backup restore command and verify that the error "Invalid type for . Expected dict got ." message is displayed. PASS: Provision a subcloud. Run backup creation command passing a int as value for all parameters that expects string(subcloud, group, sysadmin_password). Verify that the backup creation fails with "Invalid type for . Expected str got int". PASS: Provision a subcloud. Run backup creation command passing a string as value for backup_values. Verify that the backup creation fails with "Invalid type for . Expected dict got str". PASS: Provision and backup a subcloud. Attempt to delete its backup passing an int as parameters values for --subcloud, --group, sysadmin_password. Verify that the deletion fails with "Invalid type for . Expected str got int". Closes-bug: 2097402 Change-Id: Ief35656a5517f9ed8260658f992a2e1239c8bfcb Signed-off-by: Gustavo Pereira --- .../api/controllers/v1/subcloud_backup.py | 54 ++++++++++++------- .../controllers/v1/test_subcloud_backup.py | 7 ++- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py b/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py index 98b7f24b7..bec5ad1ab 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py +++ b/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py @@ -54,31 +54,31 @@ class SubcloudBackupController(object): expected_params = dict() if verb == "create": expected_params = { - "subcloud": "text", - "group": "text", - "local_only": "text", - "registry_images": "text", - "backup_values": "yaml", - "sysadmin_password": "text", + "subcloud": str, + "group": str, + "local_only": str, + "registry_images": str, + "backup_values": dict, + "sysadmin_password": str, } elif verb == "delete": expected_params = { - "release": "text", - "subcloud": "text", - "group": "text", - "local_only": "text", - "sysadmin_password": "text", + "release": str, + "subcloud": str, + "group": str, + "local_only": str, + "sysadmin_password": str, } elif verb == "restore": expected_params = { - "with_install": "text", - "release": "text", - "local_only": "text", - "registry_images": "text", - "sysadmin_password": "text", - "restore_values": "text", - "subcloud": "text", - "group": "text", + "with_install": str, + "release": str, + "local_only": str, + "registry_images": str, + "sysadmin_password": str, + "restore_values": dict, + "subcloud": str, + "group": str, } else: pecan.abort(400, _("Unexpected verb received")) @@ -86,9 +86,11 @@ class SubcloudBackupController(object): content_type = request.headers.get("content-type") LOG.info("Request content-type: %s" % content_type) if "multipart/form-data" in content_type.lower(): + return SubcloudBackupController._get_multipart_payload( request, expected_params ) + else: return SubcloudBackupController._get_json_payload(request, expected_params) @@ -110,6 +112,20 @@ class SubcloudBackupController(object): LOG.info("Got an unexpected parameter in: %s" % payload) pecan.abort(400, _("Unexpected parameter received")) + for key, value in payload.items(): + expected_type = expected_params[key] + + if key == "sysadmin_password": + # Do nothing, let _validate_and_decode_sysadmin_password + # handle this case + continue + if not isinstance(value, expected_type): + _msg = ( + f"Invalid type for {key}: Expected " + f"{expected_type.__name__}, got {type(value).__name__}" + ) + pecan.abort(400, _msg) + return payload @staticmethod diff --git a/distributedcloud/dcmanager/tests/unit/api/controllers/v1/test_subcloud_backup.py b/distributedcloud/dcmanager/tests/unit/api/controllers/v1/test_subcloud_backup.py index 29eca661f..ab6501276 100644 --- a/distributedcloud/dcmanager/tests/unit/api/controllers/v1/test_subcloud_backup.py +++ b/distributedcloud/dcmanager/tests/unit/api/controllers/v1/test_subcloud_backup.py @@ -185,8 +185,13 @@ class TestSubcloudBackupPost(BaseTestSubcloudBackupPost): def test_post_fails_without_sysadmin_password_in_multipart_payload(self): """Test post fails without sysadmin password in multipart payload""" + self.params = { + "subcloud": str(self.subcloud.id), + } + + fake_restore_values = json.dumps(FAKE_RESTORE_VALUES_VALID_IP).encode() self.upload_files = [ - ("subcloud", "fake_subcloud", json.dumps(self.subcloud.id).encode()), + ("backup_values", "fake_backup_values", fake_restore_values) ] self._update_subcloud()