From 9ae409377ecf0b95668be7696a250262d81c60bf Mon Sep 17 00:00:00 2001 From: Andre Carneiro Date: Fri, 2 Dec 2022 09:10:12 -0300 Subject: [PATCH] Use multipart headers on subcloud-backup API This change replaces the subcloud-backup API endpoints to accept both multipart and JSON content types. Multipart is necessary to keep uniformity with all other endpoints with file data upload, whereas JSON should also be accepted to keep backwards compatibility with older versions of the CLI so as not to break Conductor. Test Plan: 1. PASS - Validate that the new API version works with older versions of the CLI, which use JSON content type. 2. PASS - Validate the the new API version works with the new version of CLI, which uses multipart content type. 3. PASS - Rerun steps 1 and 2 for backup create, delete and restore operations. Story: 2010116 Task: 47020 Signed-off-by: Andre Carneiro Change-Id: Ia1c53a691a854efac1fb9a5187260ca5d9291ab0 --- .../api/controllers/v1/subcloud_backup.py | 38 ++++++++++++++++--- .../dcmanager/manager/subcloud_manager.py | 4 ++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py b/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py index d74889991..7157abd1f 100644 --- a/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py +++ b/distributedcloud/dcmanager/api/controllers/v1/subcloud_backup.py @@ -8,11 +8,13 @@ import json from collections import namedtuple import base64 +import os from oslo_config import cfg from oslo_log import log as logging from oslo_messaging import RemoteError - import pecan +import yaml + from pecan import expose from pecan import request as pecan_request from pecan import response @@ -80,8 +82,34 @@ class SubcloudBackupController(object): else: pecan.abort(400, _("Unexpected verb received")) - return SubcloudBackupController._get_json_payload(request, - expected_params) + 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) + + @staticmethod + def _get_multipart_payload(request, expected_params): + payload = dict() + file_params = ['backup_values', 'restore_values'] + for param in file_params: + if param in request.POST: + file_item = request.POST[param] + file_item.file.seek(0, os.SEEK_SET) + data = yaml.safe_load(file_item.file.read().decode('utf8')) + payload.update({param: data}) + del request.POST[param] + + payload.update(request.POST) + + if not set(payload.keys()).issubset(expected_params.keys()): + LOG.info("Got an unexpected parameter in: %s" % payload) + pecan.abort(400, _("Unexpected parameter received")) + + return payload @staticmethod def _get_json_payload(request, expected_params): @@ -95,7 +123,7 @@ class SubcloudBackupController(object): if not isinstance(payload, dict): pecan.abort(400, _('Invalid request body format')) if not set(payload.keys()).issubset(expected_params.keys()): - LOG.info(payload.keys()) + LOG.info("Got an unexpected parameter in: %s" % payload) pecan.abort(400, _("Unexpected parameter received")) return payload @@ -217,13 +245,11 @@ class SubcloudBackupController(object): @index.when(method='POST', template='json') def post(self): """Create a new subcloud backup.""" - context = restcomm.extract_context_from_environ() payload = self._get_payload(pecan_request, 'create') policy.authorize(subcloud_backup_policy.POLICY_ROOT % "create", {}, restcomm.extract_credentials_for_policy()) - self._validate_and_decode_sysadmin_password(payload, 'sysadmin_password') if not payload.get('local_only') and payload.get('registry_images'): diff --git a/distributedcloud/dcmanager/manager/subcloud_manager.py b/distributedcloud/dcmanager/manager/subcloud_manager.py index 2095764f9..be3732e74 100644 --- a/distributedcloud/dcmanager/manager/subcloud_manager.py +++ b/distributedcloud/dcmanager/manager/subcloud_manager.py @@ -1029,9 +1029,13 @@ class SubcloudManager(manager.Manager): str(keyring.get_password('CGCS', 'admin')) if payload.get('backup_values'): + LOG.info('Backup create: Received backup_values for subcloud %s' + % subcloud_name) for key, value in payload.get('backup_values').items(): payload['override_values'][key] = value elif payload.get('restore_values'): + LOG.info('Backup restore: Received restore_values for subcloud %s' + % subcloud_name) for key, value in payload.get('restore_values').items(): payload['override_values'][key] = value