Allow users to extract tars to containers with ACLs set
This fixes bug: https://bugs.launchpad.net/swift/+bug/1203182 (well it should :) I don't have keystone installed but the same issue existed with tempauth). Change-Id: I6f4045f484b27c0153a9244e0dbf2641cbc9e84e
This commit is contained in:
parent
4beb674adc
commit
4893aacc67
@ -196,20 +196,31 @@ class Bulk(object):
|
||||
|
||||
def create_container(self, req, container_path):
|
||||
"""
|
||||
Makes a subrequest to create a new container.
|
||||
Checks if the container exists and if not try to create it.
|
||||
:params container_path: an unquoted path to a container to be created
|
||||
:returns: None on success
|
||||
:raises: CreateContainerError on creation error
|
||||
:returns: True if created container, False if container exists
|
||||
:raises: CreateContainerError when unable to create container
|
||||
"""
|
||||
new_env = req.environ.copy()
|
||||
new_env['PATH_INFO'] = container_path
|
||||
new_env['swift.source'] = 'EA'
|
||||
create_cont_req = Request.blank(container_path, environ=new_env)
|
||||
resp = create_cont_req.get_response(self.app)
|
||||
if resp.status_int // 100 != 2:
|
||||
raise CreateContainerError(
|
||||
"Create Container Failed: " + container_path,
|
||||
resp.status_int, resp.status)
|
||||
new_env['REQUEST_METHOD'] = 'HEAD'
|
||||
head_cont_req = Request.blank(container_path, environ=new_env)
|
||||
resp = head_cont_req.get_response(self.app)
|
||||
if resp.is_success:
|
||||
return False
|
||||
if resp.status_int == 404:
|
||||
new_env = req.environ.copy()
|
||||
new_env['PATH_INFO'] = container_path
|
||||
new_env['swift.source'] = 'EA'
|
||||
new_env['REQUEST_METHOD'] = 'PUT'
|
||||
create_cont_req = Request.blank(container_path, environ=new_env)
|
||||
resp = create_cont_req.get_response(self.app)
|
||||
if resp.is_success:
|
||||
return True
|
||||
raise CreateContainerError(
|
||||
"Create Container Failed: " + container_path,
|
||||
resp.status_int, resp.status)
|
||||
|
||||
def get_objs_to_delete(self, req):
|
||||
"""
|
||||
@ -361,7 +372,7 @@ class Bulk(object):
|
||||
failed_files = []
|
||||
last_yield = time()
|
||||
separator = ''
|
||||
existing_containers = set()
|
||||
containers_accessed = set()
|
||||
try:
|
||||
if not out_content_type:
|
||||
raise HTTPNotAcceptable(request=req)
|
||||
@ -382,6 +393,7 @@ class Bulk(object):
|
||||
fileobj=req.body_file)
|
||||
failed_response_type = HTTPBadRequest
|
||||
req.environ['eventlet.minimum_write_chunk_size'] = 0
|
||||
containers_created = 0
|
||||
while True:
|
||||
if last_yield + self.yield_frequency < time():
|
||||
separator = '\r\n\r\n'
|
||||
@ -414,30 +426,33 @@ class Bulk(object):
|
||||
quote(obj_path[:MAX_PATH_LENGTH]),
|
||||
HTTPRequestEntityTooLarge().status])
|
||||
continue
|
||||
if container not in existing_containers:
|
||||
container_failure = None
|
||||
if container not in containers_accessed:
|
||||
cont_path = '/'.join(['', vrs, account, container])
|
||||
try:
|
||||
self.create_container(
|
||||
req, '/'.join(['', vrs, account, container]))
|
||||
existing_containers.add(container)
|
||||
if self.create_container(req, cont_path):
|
||||
containers_created += 1
|
||||
if containers_created > self.max_containers:
|
||||
raise HTTPBadRequest(
|
||||
'More than %d containers to create '
|
||||
'from tar.' % self.max_containers)
|
||||
except CreateContainerError, err:
|
||||
failed_files.append([
|
||||
quote(obj_path[:MAX_PATH_LENGTH]),
|
||||
err.status])
|
||||
# the object PUT to this container still may
|
||||
# succeed if acls are set
|
||||
container_failure = [
|
||||
quote(cont_path[:MAX_PATH_LENGTH]),
|
||||
err.status]
|
||||
if err.status_int == HTTP_UNAUTHORIZED:
|
||||
raise HTTPUnauthorized(request=req)
|
||||
continue
|
||||
except ValueError:
|
||||
failed_files.append([
|
||||
quote(obj_path[:MAX_PATH_LENGTH]),
|
||||
HTTPBadRequest().status])
|
||||
continue
|
||||
if len(existing_containers) > self.max_containers:
|
||||
raise HTTPBadRequest(
|
||||
'More than %d base level containers in tar.' %
|
||||
self.max_containers)
|
||||
|
||||
tar_file = tar.extractfile(tar_info)
|
||||
new_env = req.environ.copy()
|
||||
new_env['REQUEST_METHOD'] = 'PUT'
|
||||
new_env['wsgi.input'] = tar_file
|
||||
new_env['PATH_INFO'] = destination
|
||||
new_env['CONTENT_LENGTH'] = tar_info.size
|
||||
@ -446,9 +461,12 @@ class Bulk(object):
|
||||
'%s BulkExpand' % req.environ.get('HTTP_USER_AGENT')
|
||||
create_obj_req = Request.blank(destination, new_env)
|
||||
resp = create_obj_req.get_response(self.app)
|
||||
if resp.status_int // 100 == 2:
|
||||
containers_accessed.add(container)
|
||||
if resp.is_success:
|
||||
resp_dict['Number Files Created'] += 1
|
||||
else:
|
||||
if container_failure:
|
||||
failed_files.append(container_failure)
|
||||
if resp.status_int == HTTP_UNAUTHORIZED:
|
||||
failed_files.append([
|
||||
quote(obj_path[:MAX_PATH_LENGTH]),
|
||||
|
@ -37,8 +37,12 @@ class FakeApp(object):
|
||||
if env['PATH_INFO'].startswith('/unauth/'):
|
||||
return Response(status=401)(env, start_response)
|
||||
if env['PATH_INFO'].startswith('/create_cont/'):
|
||||
if env['REQUEST_METHOD'] == 'HEAD':
|
||||
return Response(status='404 Not Found')(env, start_response)
|
||||
return Response(status='201 Created')(env, start_response)
|
||||
if env['PATH_INFO'].startswith('/create_cont_fail/'):
|
||||
if env['REQUEST_METHOD'] == 'HEAD':
|
||||
return Response(status='403 Forbidden')(env, start_response)
|
||||
return Response(status='404 Not Found')(env, start_response)
|
||||
if env['PATH_INFO'].startswith('/create_obj_unauth/'):
|
||||
if env['PATH_INFO'].endswith('/cont'):
|
||||
@ -48,6 +52,12 @@ class FakeApp(object):
|
||||
if len(env['PATH_INFO']) > self.max_pathlen:
|
||||
return Response(status='400 Bad Request')(env, start_response)
|
||||
return Response(status='201 Created')(env, start_response)
|
||||
if env['PATH_INFO'].startswith('/tar_works_cont_head_fail/'):
|
||||
if env['REQUEST_METHOD'] == 'HEAD':
|
||||
return Response(status='404 Not Found')(env, start_response)
|
||||
if len(env['PATH_INFO']) > 100:
|
||||
return Response(status='400 Bad Request')(env, start_response)
|
||||
return Response(status='201 Created')(env, start_response)
|
||||
if env['PATH_INFO'].startswith('/delete_works/'):
|
||||
self.delete_paths.append(env['PATH_INFO'])
|
||||
if len(env['PATH_INFO']) > self.max_pathlen:
|
||||
@ -122,11 +132,13 @@ class TestUntar(unittest.TestCase):
|
||||
req = Request.blank('/')
|
||||
self.assertEquals(
|
||||
self.bulk.create_container(req, '/create_cont/acc/cont'),
|
||||
None)
|
||||
True)
|
||||
self.assertEquals(self.app.calls, 2)
|
||||
self.assertRaises(
|
||||
bulk.CreateContainerError,
|
||||
self.bulk.create_container,
|
||||
req, '/create_cont_fail/acc/cont')
|
||||
self.assertEquals(self.app.calls, 3)
|
||||
|
||||
def test_extract_tar_works(self):
|
||||
# On systems where $TMPDIR is long (like OS X), we need to do this
|
||||
@ -295,9 +307,7 @@ class TestUntar(unittest.TestCase):
|
||||
self.assertEquals(self.app.calls, 1)
|
||||
resp_data = json.loads(resp_body)
|
||||
self.assertEquals(resp_data['Response Status'], '401 Unauthorized')
|
||||
self.assertEquals(
|
||||
resp_data['Errors'],
|
||||
[['base_fails1/sub_dir1/sub1_file1', '401 Unauthorized']])
|
||||
self.assertEquals(resp_data['Errors'], [])
|
||||
|
||||
def test_extract_tar_fail_obj_401(self):
|
||||
self.build_tar()
|
||||
@ -392,16 +402,16 @@ class TestUntar(unittest.TestCase):
|
||||
with patch.object(self.bulk, 'max_containers', 1):
|
||||
self.app.calls = 0
|
||||
body = open(os.path.join(self.testdir, 'tar_fails.tar')).read()
|
||||
req = Request.blank('/tar_works/acc/', body=body,
|
||||
req = Request.blank('/tar_works_cont_head_fail/acc/', body=body,
|
||||
headers={'Accept': 'application/json'})
|
||||
req.headers['transfer-encoding'] = 'chunked'
|
||||
resp_body = self.handle_extract_and_iter(req, '')
|
||||
self.assertEquals(self.app.calls, 3)
|
||||
self.assertEquals(self.app.calls, 5)
|
||||
resp_data = json.loads(resp_body)
|
||||
self.assertEquals(resp_data['Response Status'], '400 Bad Request')
|
||||
self.assertEquals(
|
||||
resp_data['Response Body'],
|
||||
'More than 1 base level containers in tar.')
|
||||
'More than 1 containers to create from tar.')
|
||||
|
||||
def test_extract_tar_fail_create_cont(self):
|
||||
dir_tree = [{'base_fails1': [
|
||||
@ -416,8 +426,8 @@ class TestUntar(unittest.TestCase):
|
||||
req.headers['transfer-encoding'] = 'chunked'
|
||||
resp_body = self.handle_extract_and_iter(req, '')
|
||||
resp_data = json.loads(resp_body)
|
||||
self.assertEquals(self.app.calls, 4)
|
||||
self.assertEquals(len(resp_data['Errors']), 4)
|
||||
self.assertEquals(self.app.calls, 5)
|
||||
self.assertEquals(len(resp_data['Errors']), 5)
|
||||
|
||||
def test_extract_tar_fail_create_cont_value_err(self):
|
||||
self.build_tar()
|
||||
|
Loading…
x
Reference in New Issue
Block a user