s3api: Add basic support for ?tagging requests

https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html#cliv2-migration-s3-copy-metadata
AWS CLI version 2 improves Amazon S3 handling of file properties
and tags when performing multipart copies. We still don't supprt
object tagging hence the aws s3 cp command fails for mulitpart
copies with default options.

This way get tagging request will receive an empty tagset in
response and mulitpart copies will work fine

Change-Id: I1f031b05025cafac00e86966c240aa5f7258d0bf
This commit is contained in:
manuvakery1 2020-06-11 20:25:08 +05:30
parent 0b86f681f5
commit 6afefe1ad3
4 changed files with 83 additions and 3 deletions

View File

@ -31,6 +31,8 @@ from swift.common.middleware.s3api.controllers.logging import \
LoggingStatusController
from swift.common.middleware.s3api.controllers.versioning import \
VersioningController
from swift.common.middleware.s3api.controllers.tagging import \
TaggingController
__all__ = [
'Controller',
@ -47,6 +49,7 @@ __all__ = [
'LocationController',
'LoggingStatusController',
'VersioningController',
'TaggingController',
'UnsupportedController',
]

View File

@ -0,0 +1,57 @@
# Copyright (c) 2014 OpenStack Foundation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from swift.common.utils import public
from swift.common.middleware.s3api.controllers.base import Controller, \
S3NotImplemented
from swift.common.middleware.s3api.s3response import HTTPOk
from swift.common.middleware.s3api.etree import Element, tostring, \
SubElement
class TaggingController(Controller):
"""
Handles the following APIs:
* GET Bucket and Object tagging
* PUT Bucket and Object tagging
* DELETE Bucket and Object tagging
"""
@public
def GET(self, req):
"""
Handles GET Bucket and Object tagging.
"""
elem = Element('Tagging')
SubElement(elem, 'TagSet')
body = tostring(elem)
return HTTPOk(body=body, content_type=None)
@public
def PUT(self, req):
"""
Handles PUT Bucket and Object tagging.
"""
raise S3NotImplemented('The requested resource is not implemented')
@public
def DELETE(self, req):
"""
Handles DELETE Bucket and Object tagging.
"""
raise S3NotImplemented('The requested resource is not implemented')

View File

@ -45,7 +45,8 @@ from swift.common.middleware.s3api.controllers import ServiceController, \
ObjectController, AclController, MultiObjectDeleteController, \
LocationController, LoggingStatusController, PartController, \
UploadController, UploadsController, VersioningController, \
UnsupportedController, S3AclController, BucketController
UnsupportedController, S3AclController, BucketController, \
TaggingController
from swift.common.middleware.s3api.s3response import AccessDenied, \
InvalidArgument, InvalidDigest, BucketAlreadyOwnedByYou, \
RequestTimeTooSkewed, S3Response, SignatureDoesNotMatch, \
@ -1026,9 +1027,11 @@ class S3Request(swob.Request):
return UploadsController
if 'versioning' in self.params:
return VersioningController
if 'tagging' in self.params:
return TaggingController
unsupported = ('notification', 'policy', 'requestPayment', 'torrent',
'website', 'cors', 'tagging', 'restore')
'website', 'cors', 'restore')
if set(unsupported) & set(self.params):
return UnsupportedController

View File

@ -705,7 +705,24 @@ class TestS3ApiMiddleware(S3ApiTestCase):
self._test_unsupported_resource('cors')
def test_tagging(self):
self._test_unsupported_resource('tagging')
req = Request.blank('/bucket?tagging',
environ={'REQUEST_METHOD': 'GET'},
headers={'Authorization': 'AWS test:tester:hmac',
'Date': self.get_date_header()})
status, headers, body = self.call_s3api(req)
self.assertEqual(status.split()[0], '200')
req = Request.blank('/bucket?tagging',
environ={'REQUEST_METHOD': 'PUT'},
headers={'Authorization': 'AWS test:tester:hmac',
'Date': self.get_date_header()})
status, headers, body = self.call_s3api(req)
self.assertEqual(self._get_error_code(body), 'NotImplemented')
req = Request.blank('/bucket?tagging',
environ={'REQUEST_METHOD': 'DELETE'},
headers={'Authorization': 'AWS test:tester:hmac',
'Date': self.get_date_header()})
status, headers, body = self.call_s3api(req)
self.assertEqual(self._get_error_code(body), 'NotImplemented')
def test_restore(self):
self._test_unsupported_resource('restore')