Commit 71a2170b authored by Stavros Sachtouris's avatar Stavros Sachtouris Committed by Giorgos Korfiatis

Support uploading an object to different account

The term "different account" refers to a user account that is not
the same as the one running the request.

The most notable example is when user A uploads something to a
directory owned by user B, provided user B has granted write
permissions to user A.
parent 8133017b
# Copyright 2011-2014 GRNET S.A. All rights reserved.
# Copyright 2011-2015 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
......@@ -966,7 +966,10 @@ class file_upload(_PithosContainer):
def _check_container_limit(self, path):
cl_dict = self.client.get_container_limit()
container_limit = int(cl_dict['x-container-policy-quota'])
try:
container_limit = int(cl_dict['x-container-policy-quota'])
except KeyError:
container_limit = 0
r = self.client.container_get()
used_bytes = sum(int(o['bytes']) for o in r.json)
path_size = get_path_size(path)
......@@ -1069,7 +1072,7 @@ class file_upload(_PithosContainer):
sharing=self._sharing(),
public=self['public'])
container_info_cache = dict()
rpref = 'pithos://%s' if self['account'] else ''
rpref = ('pithos://%s' % self['account']) if self['account'] else ''
for f, rpath in self._src_dst(local_path, remote_path):
self.error('%s --> %s/%s/%s' % (
f.name, rpref, self.client.container, rpath))
......@@ -1092,6 +1095,11 @@ class file_upload(_PithosContainer):
'Calculating block hashes')
else:
hash_cb = None
caller_id = self.astakos.user_term('id')
if self.client.account != caller_id:
params['target_account'], self.client.account = (
self.client.account, caller_id)
self.client.upload_object(
rpath, f,
hash_cb=hash_cb,
......
......@@ -109,6 +109,19 @@ class PithosClient(PithosRestClient):
super(PithosClient, self).__init__(
endpoint_url, token, account, container)
def use_alternative_account(self, func, *args, **kwargs):
"""Run method with an alternative account UUID, as long as kwargs
contain a non-None "alternative_account" argument
"""
alternative_account = kwargs.pop('alternative_account', None)
bu_account = self.account
try:
if alternative_account and alternative_account != self.account:
self.account = alternative_account
return func(*args, **kwargs)
finally:
self.account = bu_account
def create_container(
self,
container=None, sizelimit=None, versioning=None, metadata=None,
......@@ -389,7 +402,8 @@ class PithosClient(PithosRestClient):
content_type=None,
sharing=None,
public=None,
container_info_cache=None):
container_info_cache=None,
target_account=None):
"""Upload an object using multiple connections (threads)
:param obj: (str) remote object path
......@@ -423,12 +437,18 @@ class PithosClient(PithosRestClient):
:param container_info_cache: (dict) if given, avoid redundant calls to
server for container info (block size and hash information)
:param target_account: (str) the UUID of the account the object will be
allocated at, if different to the client account (e.g., when
user A uploads something to a location owned by user B)
"""
self._assert_container()
block_info = (
blocksize, blockhash, size, nblocks) = self._get_file_block_info(
f, size, container_info_cache)
blocksize, blockhash, size, nblocks
) = self.use_alternative_account(
self._get_file_block_info, f, size, container_info_cache,
alternative_account=target_account)
(hashes, hmap, offset) = ([], {}, 0)
content_type = content_type or 'application/octet-stream'
......@@ -440,8 +460,8 @@ class PithosClient(PithosRestClient):
hash_cb=hash_cb)
hashmap = dict(bytes=size, hashes=hashes)
missing, obj_headers = self._create_object_or_get_missing_hashes(
obj, hashmap,
missing, obj_headers = self.use_alternative_account(
self._create_object_or_get_missing_hashes, obj, hashmap,
content_type=content_type,
size=size,
if_etag_match=if_etag_match,
......@@ -449,7 +469,8 @@ class PithosClient(PithosRestClient):
content_encoding=content_encoding,
content_disposition=content_disposition,
permissions=sharing,
public=public)
public=public,
alternative_account=target_account)
if missing is None:
return obj_headers
......@@ -487,7 +508,8 @@ class PithosClient(PithosRestClient):
'%s blocks failed to upload' % len(missing),
details=details)
r = self.object_put(
r = self.use_alternative_account(
self.object_put,
obj,
format='json',
hashmap=True,
......@@ -499,7 +521,8 @@ class PithosClient(PithosRestClient):
json=hashmap,
permissions=sharing,
public=public,
success=201)
success=201,
alternative_account=target_account)
return r.headers
def upload_from_string(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment