Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / modular.py @ 1ec05716

History | View | Annotate | Download (78 kB)

1 2e662088 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 2715ade4 Sofia Papagiannaki
#
3 a9b3f29d Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 a9b3f29d Antony Chazapis
# without modification, are permitted provided that the following
5 a9b3f29d Antony Chazapis
# conditions are met:
6 2715ade4 Sofia Papagiannaki
#
7 a9b3f29d Antony Chazapis
#   1. Redistributions of source code must retain the above
8 a9b3f29d Antony Chazapis
#      copyright notice, this list of conditions and the following
9 a9b3f29d Antony Chazapis
#      disclaimer.
10 2715ade4 Sofia Papagiannaki
#
11 7ff57991 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 7ff57991 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 a9b3f29d Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 a9b3f29d Antony Chazapis
#      provided with the distribution.
15 2715ade4 Sofia Papagiannaki
#
16 a9b3f29d Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a9b3f29d Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a9b3f29d Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a9b3f29d Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a9b3f29d Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a9b3f29d Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a9b3f29d Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a9b3f29d Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a9b3f29d Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a9b3f29d Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a9b3f29d Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a9b3f29d Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 2715ade4 Sofia Papagiannaki
#
29 a9b3f29d Antony Chazapis
# The views and conclusions contained in the software and
30 a9b3f29d Antony Chazapis
# documentation are those of the authors and should not be
31 a9b3f29d Antony Chazapis
# interpreted as representing official policies, either expressed
32 a9b3f29d Antony Chazapis
# or implied, of GRNET S.A.
33 a9b3f29d Antony Chazapis
34 2c5363a0 Antony Chazapis
import sys
35 37bee317 Antony Chazapis
import uuid as uuidlib
36 a9b3f29d Antony Chazapis
import logging
37 6e147ecc Antony Chazapis
import hashlib
38 a9b3f29d Antony Chazapis
import binascii
39 a9b3f29d Antony Chazapis
40 0d573e18 Sofia Papagiannaki
from collections import defaultdict
41 9e3a38bb Sofia Papagiannaki
from functools import wraps, partial
42 1f96b68d Sofia Papagiannaki
from traceback import format_exc
43 1f96b68d Sofia Papagiannaki
44 7ee27246 Georgios D. Tsoukalas
try:
45 7ee27246 Georgios D. Tsoukalas
    from astakosclient import AstakosClient
46 7ee27246 Georgios D. Tsoukalas
except ImportError:
47 7ee27246 Georgios D. Tsoukalas
    AstakosClient = None
48 0307b47f Georgios D. Tsoukalas
49 19ddd41b Sofia Papagiannaki
from base import (DEFAULT_ACCOUNT_QUOTA, DEFAULT_CONTAINER_QUOTA,
50 19ddd41b Sofia Papagiannaki
                  DEFAULT_CONTAINER_VERSIONING, NotAllowedError, QuotaError,
51 19ddd41b Sofia Papagiannaki
                  BaseBackend, AccountExists, ContainerExists, AccountNotEmpty,
52 3a5994a8 Sofia Papagiannaki
                  ContainerNotEmpty, ItemNotExists, VersionNotExists,
53 3a5994a8 Sofia Papagiannaki
                  InvalidHash)
54 a9b3f29d Antony Chazapis
55 7ee27246 Georgios D. Tsoukalas
56 7ee27246 Georgios D. Tsoukalas
class DisabledAstakosClient(object):
57 7ee27246 Georgios D. Tsoukalas
    def __init__(self, *args, **kwargs):
58 7ee27246 Georgios D. Tsoukalas
        self.args = args
59 7ee27246 Georgios D. Tsoukalas
        self.kwargs = kwargs
60 7ee27246 Georgios D. Tsoukalas
61 7ee27246 Georgios D. Tsoukalas
    def __getattr__(self, name):
62 7ee27246 Georgios D. Tsoukalas
        m = ("AstakosClient has been disabled, "
63 7ee27246 Georgios D. Tsoukalas
             "yet an attempt to access it was made")
64 7ee27246 Georgios D. Tsoukalas
        raise AssertionError(m)
65 7ee27246 Georgios D. Tsoukalas
66 7ee27246 Georgios D. Tsoukalas
67 6e147ecc Antony Chazapis
# Stripped-down version of the HashMap class found in tools.
68 2715ade4 Sofia Papagiannaki
69 6e147ecc Antony Chazapis
class HashMap(list):
70 6e147ecc Antony Chazapis
71 6e147ecc Antony Chazapis
    def __init__(self, blocksize, blockhash):
72 6e147ecc Antony Chazapis
        super(HashMap, self).__init__()
73 6e147ecc Antony Chazapis
        self.blocksize = blocksize
74 6e147ecc Antony Chazapis
        self.blockhash = blockhash
75 6e147ecc Antony Chazapis
76 6e147ecc Antony Chazapis
    def _hash_raw(self, v):
77 6e147ecc Antony Chazapis
        h = hashlib.new(self.blockhash)
78 6e147ecc Antony Chazapis
        h.update(v)
79 6e147ecc Antony Chazapis
        return h.digest()
80 6e147ecc Antony Chazapis
81 6e147ecc Antony Chazapis
    def hash(self):
82 6e147ecc Antony Chazapis
        if len(self) == 0:
83 6e147ecc Antony Chazapis
            return self._hash_raw('')
84 6e147ecc Antony Chazapis
        if len(self) == 1:
85 6e147ecc Antony Chazapis
            return self.__getitem__(0)
86 6e147ecc Antony Chazapis
87 6e147ecc Antony Chazapis
        h = list(self)
88 6e147ecc Antony Chazapis
        s = 2
89 6e147ecc Antony Chazapis
        while s < len(h):
90 6e147ecc Antony Chazapis
            s = s * 2
91 6e147ecc Antony Chazapis
        h += [('\x00' * len(h[0]))] * (s - len(h))
92 6e147ecc Antony Chazapis
        while len(h) > 1:
93 6e147ecc Antony Chazapis
            h = [self._hash_raw(h[x] + h[x + 1]) for x in range(0, len(h), 2)]
94 6e147ecc Antony Chazapis
        return h[0]
95 5a96180b Antony Chazapis
96 228de81b Antony Chazapis
# Default modules and settings.
97 228de81b Antony Chazapis
DEFAULT_DB_MODULE = 'pithos.backends.lib.sqlalchemy'
98 228de81b Antony Chazapis
DEFAULT_DB_CONNECTION = 'sqlite:///backend.db'
99 228de81b Antony Chazapis
DEFAULT_BLOCK_MODULE = 'pithos.backends.lib.hashfiler'
100 228de81b Antony Chazapis
DEFAULT_BLOCK_PATH = 'data/'
101 f3b65e8f Antony Chazapis
DEFAULT_BLOCK_UMASK = 0o022
102 369a7b41 Sofia Papagiannaki
DEFAULT_BLOCK_SIZE = 4 * 1024 * 1024  # 4MB
103 369a7b41 Sofia Papagiannaki
DEFAULT_HASH_ALGORITHM = 'sha256'
104 fa9cae7e Antony Chazapis
#DEFAULT_QUEUE_MODULE = 'pithos.backends.lib.rabbitmq'
105 29148653 Sofia Papagiannaki
DEFAULT_BLOCK_PARAMS = {'mappool': None, 'blockpool': None}
106 f4fbb0fa Sofia Papagiannaki
#DEFAULT_QUEUE_HOSTS = '[amqp://guest:guest@localhost:5672]'
107 f4fbb0fa Sofia Papagiannaki
#DEFAULT_QUEUE_EXCHANGE = 'pithos'
108 4a105ce2 Sofia Papagiannaki
DEFAULT_PUBLIC_URL_ALPHABET = ('0123456789'
109 4a105ce2 Sofia Papagiannaki
                               'abcdefghijklmnopqrstuvwxyz'
110 4a105ce2 Sofia Papagiannaki
                               'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
111 c77af544 Sofia Papagiannaki
DEFAULT_PUBLIC_URL_SECURITY = 16
112 fa9cae7e Antony Chazapis
113 8d9a3fbd Antony Chazapis
QUEUE_MESSAGE_KEY_PREFIX = 'pithos.%s'
114 39ef6f41 Antony Chazapis
QUEUE_CLIENT_ID = 'pithos'
115 73673127 Antony Chazapis
QUEUE_INSTANCE_ID = '1'
116 228de81b Antony Chazapis
117 2715ade4 Sofia Papagiannaki
(CLUSTER_NORMAL, CLUSTER_HISTORY, CLUSTER_DELETED) = range(3)
118 44ad5860 Antony Chazapis
119 44ad5860 Antony Chazapis
inf = float('inf')
120 44ad5860 Antony Chazapis
121 bb4eafc6 Antony Chazapis
ULTIMATE_ANSWER = 42
122 bb4eafc6 Antony Chazapis
123 b17e5550 Giorgos Korfiatis
DEFAULT_SOURCE = 'system'
124 ec6f741b Sofia Papagiannaki
DEFAULT_DISKSPACE_RESOURCE = 'pithos.diskspace'
125 a9b3f29d Antony Chazapis
126 a9b3f29d Antony Chazapis
logger = logging.getLogger(__name__)
127 a9b3f29d Antony Chazapis
128 1c2fc0ff Antony Chazapis
129 5d022141 Sofia Papagiannaki
def backend_method(func):
130 5d022141 Sofia Papagiannaki
    @wraps(func)
131 5d022141 Sofia Papagiannaki
    def wrapper(self, *args, **kw):
132 5d022141 Sofia Papagiannaki
        # if we are inside a database transaction
133 5d022141 Sofia Papagiannaki
        # just proceed with the method execution
134 5d022141 Sofia Papagiannaki
        # otherwise manage a new transaction
135 5d022141 Sofia Papagiannaki
        if self.in_transaction:
136 5d022141 Sofia Papagiannaki
            return func(self, *args, **kw)
137 5d022141 Sofia Papagiannaki
138 5d022141 Sofia Papagiannaki
        try:
139 5d022141 Sofia Papagiannaki
            self.pre_exec()
140 5d022141 Sofia Papagiannaki
            result = func(self, *args, **kw)
141 5d022141 Sofia Papagiannaki
            success_status = True
142 5d022141 Sofia Papagiannaki
            return result
143 5d022141 Sofia Papagiannaki
        except:
144 5d022141 Sofia Papagiannaki
            success_status = False
145 5d022141 Sofia Papagiannaki
            raise
146 5d022141 Sofia Papagiannaki
        finally:
147 5d022141 Sofia Papagiannaki
            self.post_exec(success_status)
148 5d022141 Sofia Papagiannaki
    return wrapper
149 5d022141 Sofia Papagiannaki
150 5d022141 Sofia Papagiannaki
151 1f96b68d Sofia Papagiannaki
def debug_method(func):
152 1f96b68d Sofia Papagiannaki
    @wraps(func)
153 1f96b68d Sofia Papagiannaki
    def wrapper(self, *args, **kw):
154 1f96b68d Sofia Papagiannaki
        try:
155 1f96b68d Sofia Papagiannaki
            result = func(self, *args, **kw)
156 1f96b68d Sofia Papagiannaki
            return result
157 1f96b68d Sofia Papagiannaki
        except:
158 1f96b68d Sofia Papagiannaki
            result = format_exc()
159 1f96b68d Sofia Papagiannaki
            raise
160 1f96b68d Sofia Papagiannaki
        finally:
161 b1aca3e6 Sofia Papagiannaki
            all_args = map(repr, args)
162 1f96b68d Sofia Papagiannaki
            map(all_args.append, ('%s=%s' % (k, v) for k, v in kw.iteritems()))
163 1f96b68d Sofia Papagiannaki
            logger.debug(">>> %s(%s) <<< %s" % (
164 1f96b68d Sofia Papagiannaki
                func.__name__, ', '.join(all_args).rstrip(', '), result))
165 1f96b68d Sofia Papagiannaki
    return wrapper
166 1f96b68d Sofia Papagiannaki
167 1f96b68d Sofia Papagiannaki
168 0d573e18 Sofia Papagiannaki
def check_allowed_paths(action):
169 0d573e18 Sofia Papagiannaki
    """Decorator for backend methods checking path access granted to user.
170 0d573e18 Sofia Papagiannaki

171 0d573e18 Sofia Papagiannaki
    The 1st argument of the decorated method is expected to be a
172 0d573e18 Sofia Papagiannaki
    ModularBackend instance, the 2nd the user performing the request and
173 0d573e18 Sofia Papagiannaki
    the path join of the rest arguments is supposed to be the requested path.
174 0d573e18 Sofia Papagiannaki

175 0d573e18 Sofia Papagiannaki
    The decorator checks whether the requested path is among the user's allowed
176 0d573e18 Sofia Papagiannaki
    cached paths.
177 0d573e18 Sofia Papagiannaki
    If this is the case, the decorator returns immediately to reduce the
178 0d573e18 Sofia Papagiannaki
    interactions with the database.
179 0d573e18 Sofia Papagiannaki
    Otherwise, it proceeds with the execution of the decorated method and if
180 0d573e18 Sofia Papagiannaki
    the method returns successfully (no exceptions are raised), the requested
181 0d573e18 Sofia Papagiannaki
    path is added to the user's cached allowed paths.
182 0d573e18 Sofia Papagiannaki

183 0d573e18 Sofia Papagiannaki
    :param action: (int) 0 for reads / 1 for writes
184 0d573e18 Sofia Papagiannaki
    :raises NotAllowedError: the user does not have access to the path
185 0d573e18 Sofia Papagiannaki
    """
186 0d573e18 Sofia Papagiannaki
    def decorator(func):
187 0d573e18 Sofia Papagiannaki
        @wraps(func)
188 0d573e18 Sofia Papagiannaki
        def wrapper(self, *args):
189 0d573e18 Sofia Papagiannaki
            user = args[0]
190 0d573e18 Sofia Papagiannaki
            if action == self.READ:
191 0d573e18 Sofia Papagiannaki
                d = self.read_allowed_paths
192 0d573e18 Sofia Papagiannaki
            else:
193 0d573e18 Sofia Papagiannaki
                d = self.write_allowed_paths
194 0d573e18 Sofia Papagiannaki
            path = '/'.join(args[1:])
195 0d573e18 Sofia Papagiannaki
            if path in d.get(user, []):
196 0d573e18 Sofia Papagiannaki
                return  # access is already checked
197 0d573e18 Sofia Papagiannaki
            else:
198 0d573e18 Sofia Papagiannaki
                func(self, *args)   # proceed with access check
199 0d573e18 Sofia Papagiannaki
                d[user].add(path)  # add path in the allowed user paths
200 0d573e18 Sofia Papagiannaki
        return wrapper
201 0d573e18 Sofia Papagiannaki
    return decorator
202 0d573e18 Sofia Papagiannaki
203 0d573e18 Sofia Papagiannaki
204 0d573e18 Sofia Papagiannaki
def list_method(func):
205 0d573e18 Sofia Papagiannaki
    @wraps(func)
206 0d573e18 Sofia Papagiannaki
    def wrapper(self, *args, **kw):
207 0d573e18 Sofia Papagiannaki
        marker = kw.get('marker')
208 0d573e18 Sofia Papagiannaki
        limit = kw.get('limit')
209 0d573e18 Sofia Papagiannaki
        result = func(self, *args, **kw)
210 0d573e18 Sofia Papagiannaki
        start, limit = self._list_limits(result, marker, limit)
211 0d573e18 Sofia Papagiannaki
        return result[start:start + limit]
212 0d573e18 Sofia Papagiannaki
    return wrapper
213 0d573e18 Sofia Papagiannaki
214 0d573e18 Sofia Papagiannaki
215 a9b3f29d Antony Chazapis
class ModularBackend(BaseBackend):
216 a9b3f29d Antony Chazapis
    """A modular backend.
217 2715ade4 Sofia Papagiannaki

218 e9363f82 Antony Chazapis
    Uses modules for SQL functions and storage.
219 a9b3f29d Antony Chazapis
    """
220 2715ade4 Sofia Papagiannaki
221 46286f5f Antony Chazapis
    def __init__(self, db_module=None, db_connection=None,
222 f3b65e8f Antony Chazapis
                 block_module=None, block_path=None, block_umask=None,
223 369a7b41 Sofia Papagiannaki
                 block_size=None, hash_algorithm=None,
224 3173699c Sofia Papagiannaki
                 queue_module=None, queue_hosts=None, queue_exchange=None,
225 f759041f Ilias Tsitsimpis
                 astakos_auth_url=None, service_token=None,
226 16f2673e Sofia Papagiannaki
                 astakosclient_poolsize=None,
227 56f3c759 Sofia Papagiannaki
                 free_versioning=True, block_params=None,
228 4a105ce2 Sofia Papagiannaki
                 public_url_security=None,
229 19ddd41b Sofia Papagiannaki
                 public_url_alphabet=None,
230 19ddd41b Sofia Papagiannaki
                 account_quota_policy=None,
231 19ddd41b Sofia Papagiannaki
                 container_quota_policy=None,
232 19ddd41b Sofia Papagiannaki
                 container_versioning_policy=None):
233 228de81b Antony Chazapis
        db_module = db_module or DEFAULT_DB_MODULE
234 228de81b Antony Chazapis
        db_connection = db_connection or DEFAULT_DB_CONNECTION
235 228de81b Antony Chazapis
        block_module = block_module or DEFAULT_BLOCK_MODULE
236 228de81b Antony Chazapis
        block_path = block_path or DEFAULT_BLOCK_PATH
237 f3b65e8f Antony Chazapis
        block_umask = block_umask or DEFAULT_BLOCK_UMASK
238 7f1f0464 Georgios D. Tsoukalas
        block_params = block_params or DEFAULT_BLOCK_PARAMS
239 369a7b41 Sofia Papagiannaki
        block_size = block_size or DEFAULT_BLOCK_SIZE
240 369a7b41 Sofia Papagiannaki
        hash_algorithm = hash_algorithm or DEFAULT_HASH_ALGORITHM
241 46286f5f Antony Chazapis
        #queue_module = queue_module or DEFAULT_QUEUE_MODULE
242 19ddd41b Sofia Papagiannaki
        account_quota_policy = account_quota_policy or DEFAULT_ACCOUNT_QUOTA
243 19ddd41b Sofia Papagiannaki
        container_quota_policy = container_quota_policy \
244 19ddd41b Sofia Papagiannaki
            or DEFAULT_CONTAINER_QUOTA
245 19ddd41b Sofia Papagiannaki
        container_versioning_policy = container_versioning_policy \
246 19ddd41b Sofia Papagiannaki
            or DEFAULT_CONTAINER_VERSIONING
247 19ddd41b Sofia Papagiannaki
248 19ddd41b Sofia Papagiannaki
        self.default_account_policy = {'quota': account_quota_policy}
249 19ddd41b Sofia Papagiannaki
        self.default_container_policy = {
250 19ddd41b Sofia Papagiannaki
            'quota': container_quota_policy,
251 19ddd41b Sofia Papagiannaki
            'versioning': container_versioning_policy
252 19ddd41b Sofia Papagiannaki
        }
253 f4fbb0fa Sofia Papagiannaki
        #queue_hosts = queue_hosts or DEFAULT_QUEUE_HOSTS
254 f4fbb0fa Sofia Papagiannaki
        #queue_exchange = queue_exchange or DEFAULT_QUEUE_EXCHANGE
255 7f1f0464 Georgios D. Tsoukalas
256 369a7b41 Sofia Papagiannaki
        self.public_url_security = (public_url_security or
257 29148653 Sofia Papagiannaki
                                    DEFAULT_PUBLIC_URL_SECURITY)
258 369a7b41 Sofia Papagiannaki
        self.public_url_alphabet = (public_url_alphabet or
259 29148653 Sofia Papagiannaki
                                    DEFAULT_PUBLIC_URL_ALPHABET)
260 56f3c759 Sofia Papagiannaki
261 369a7b41 Sofia Papagiannaki
        self.hash_algorithm = hash_algorithm
262 369a7b41 Sofia Papagiannaki
        self.block_size = block_size
263 b1dadd0e Sofia Papagiannaki
        self.free_versioning = free_versioning
264 2715ade4 Sofia Papagiannaki
265 46286f5f Antony Chazapis
        def load_module(m):
266 46286f5f Antony Chazapis
            __import__(m)
267 46286f5f Antony Chazapis
            return sys.modules[m]
268 2715ade4 Sofia Papagiannaki
269 46286f5f Antony Chazapis
        self.db_module = load_module(db_module)
270 46286f5f Antony Chazapis
        self.wrapper = self.db_module.DBWrapper(db_connection)
271 e9363f82 Antony Chazapis
        params = {'wrapper': self.wrapper}
272 e9363f82 Antony Chazapis
        self.permissions = self.db_module.Permissions(**params)
273 2c690fe9 Sofia Papagiannaki
        self.config = self.db_module.Config(**params)
274 16f2673e Sofia Papagiannaki
        self.commission_serials = self.db_module.QuotaholderSerial(**params)
275 e9363f82 Antony Chazapis
        for x in ['READ', 'WRITE']:
276 e9363f82 Antony Chazapis
            setattr(self, x, getattr(self.db_module, x))
277 e9363f82 Antony Chazapis
        self.node = self.db_module.Node(**params)
278 adce84cd Sofia Papagiannaki
        for x in ['ROOTNODE', 'SERIAL', 'NODE', 'HASH', 'SIZE', 'TYPE',
279 adce84cd Sofia Papagiannaki
                  'MTIME', 'MUSER', 'UUID', 'CHECKSUM', 'CLUSTER',
280 adce84cd Sofia Papagiannaki
                  'MATCH_PREFIX', 'MATCH_EXACT']:
281 e9363f82 Antony Chazapis
            setattr(self, x, getattr(self.db_module, x))
282 2715ade4 Sofia Papagiannaki
283 ace7592b Sofia Papagiannaki
        self.ALLOWED = ['read', 'write']
284 dc88754b Nanakos Chrysostomos
285 46286f5f Antony Chazapis
        self.block_module = load_module(block_module)
286 7f1f0464 Georgios D. Tsoukalas
        self.block_params = block_params
287 7ca7bb08 Antony Chazapis
        params = {'path': block_path,
288 7ca7bb08 Antony Chazapis
                  'block_size': self.block_size,
289 f3b65e8f Antony Chazapis
                  'hash_algorithm': self.hash_algorithm,
290 f3b65e8f Antony Chazapis
                  'umask': block_umask}
291 7f1f0464 Georgios D. Tsoukalas
        params.update(self.block_params)
292 7ca7bb08 Antony Chazapis
        self.store = self.block_module.Store(**params)
293 46286f5f Antony Chazapis
294 f4fbb0fa Sofia Papagiannaki
        if queue_module and queue_hosts:
295 46286f5f Antony Chazapis
            self.queue_module = load_module(queue_module)
296 f4fbb0fa Sofia Papagiannaki
            params = {'hosts': queue_hosts,
297 7f1f0464 Georgios D. Tsoukalas
                      'exchange': queue_exchange,
298 fa9cae7e Antony Chazapis
                      'client_id': QUEUE_CLIENT_ID}
299 46286f5f Antony Chazapis
            self.queue = self.queue_module.Queue(**params)
300 46286f5f Antony Chazapis
        else:
301 46286f5f Antony Chazapis
            class NoQueue:
302 1a239dc1 Sofia Papagiannaki
                def send(self, *args):
303 46286f5f Antony Chazapis
                    pass
304 2715ade4 Sofia Papagiannaki
305 b9a8feec root
                def close(self):
306 b9a8feec root
                    pass
307 2715ade4 Sofia Papagiannaki
308 46286f5f Antony Chazapis
            self.queue = NoQueue()
309 2715ade4 Sofia Papagiannaki
310 f759041f Ilias Tsitsimpis
        self.astakos_auth_url = astakos_auth_url
311 16f2673e Sofia Papagiannaki
        self.service_token = service_token
312 7ee27246 Georgios D. Tsoukalas
313 f759041f Ilias Tsitsimpis
        if not astakos_auth_url or not AstakosClient:
314 7ee27246 Georgios D. Tsoukalas
            self.astakosclient = DisabledAstakosClient(
315 f759041f Ilias Tsitsimpis
                service_token, astakos_auth_url,
316 7ee27246 Georgios D. Tsoukalas
                use_pool=True,
317 7ee27246 Georgios D. Tsoukalas
                pool_size=astakosclient_poolsize)
318 7ee27246 Georgios D. Tsoukalas
        else:
319 7ee27246 Georgios D. Tsoukalas
            self.astakosclient = AstakosClient(
320 f759041f Ilias Tsitsimpis
                service_token, astakos_auth_url,
321 7ee27246 Georgios D. Tsoukalas
                use_pool=True,
322 7ee27246 Georgios D. Tsoukalas
                pool_size=astakosclient_poolsize)
323 b336e6fa Georgios D. Tsoukalas
324 7ed99da8 root
        self.serials = []
325 a7f7699d root
        self.messages = []
326 0307b47f Georgios D. Tsoukalas
327 9e3a38bb Sofia Papagiannaki
        self._move_object = partial(self._copy_object, is_move=True)
328 9e3a38bb Sofia Papagiannaki
329 f6d499b0 Sofia Papagiannaki
        self.lock_container_path = False
330 f6d499b0 Sofia Papagiannaki
331 5d022141 Sofia Papagiannaki
        self.in_transaction = False
332 5d022141 Sofia Papagiannaki
333 0d573e18 Sofia Papagiannaki
        self._reset_allowed_paths()
334 0d573e18 Sofia Papagiannaki
335 d47565d8 Buildbot
    def pre_exec(self, lock_container_path=False):
336 d47565d8 Buildbot
        self.lock_container_path = lock_container_path
337 cc62d2ab Sofia Papagiannaki
        self.wrapper.execute()
338 5d022141 Sofia Papagiannaki
        self.serials = []
339 0d573e18 Sofia Papagiannaki
        self._reset_allowed_paths()
340 5d022141 Sofia Papagiannaki
        self.in_transaction = True
341 cc62d2ab Sofia Papagiannaki
342 d47565d8 Buildbot
    def post_exec(self, success_status=True):
343 cc62d2ab Sofia Papagiannaki
        if success_status:
344 cc62d2ab Sofia Papagiannaki
            # send messages produced
345 cc62d2ab Sofia Papagiannaki
            for m in self.messages:
346 cc62d2ab Sofia Papagiannaki
                self.queue.send(*m)
347 cc62d2ab Sofia Papagiannaki
348 cc62d2ab Sofia Papagiannaki
            # register serials
349 cc62d2ab Sofia Papagiannaki
            if self.serials:
350 cc62d2ab Sofia Papagiannaki
                self.commission_serials.insert_many(
351 cc62d2ab Sofia Papagiannaki
                    self.serials)
352 cc62d2ab Sofia Papagiannaki
353 cc62d2ab Sofia Papagiannaki
                # commit to ensure that the serials are registered
354 cc62d2ab Sofia Papagiannaki
                # even if resolve commission fails
355 cc62d2ab Sofia Papagiannaki
                self.wrapper.commit()
356 cc62d2ab Sofia Papagiannaki
357 cc62d2ab Sofia Papagiannaki
                # start new transaction
358 cc62d2ab Sofia Papagiannaki
                self.wrapper.execute()
359 cc62d2ab Sofia Papagiannaki
360 cc62d2ab Sofia Papagiannaki
                r = self.astakosclient.resolve_commissions(
361 29148653 Sofia Papagiannaki
                    accept_serials=self.serials,
362 29148653 Sofia Papagiannaki
                    reject_serials=[])
363 cc62d2ab Sofia Papagiannaki
                self.commission_serials.delete_many(
364 cc62d2ab Sofia Papagiannaki
                    r['accepted'])
365 cc62d2ab Sofia Papagiannaki
366 cc62d2ab Sofia Papagiannaki
            self.wrapper.commit()
367 cc62d2ab Sofia Papagiannaki
        else:
368 cc62d2ab Sofia Papagiannaki
            if self.serials:
369 135f864e Sofia Papagiannaki
                r = self.astakosclient.resolve_commissions(
370 cc62d2ab Sofia Papagiannaki
                    accept_serials=[],
371 cc62d2ab Sofia Papagiannaki
                    reject_serials=self.serials)
372 96f9f6fd Sofia Papagiannaki
                self.commission_serials.delete_many(
373 96f9f6fd Sofia Papagiannaki
                    r['rejected'])
374 cc62d2ab Sofia Papagiannaki
            self.wrapper.rollback()
375 5d022141 Sofia Papagiannaki
        self.in_transaction = False
376 cc62d2ab Sofia Papagiannaki
377 d14fe290 Antony Chazapis
    def close(self):
378 d14fe290 Antony Chazapis
        self.wrapper.close()
379 b9a8feec root
        self.queue.close()
380 2715ade4 Sofia Papagiannaki
381 c846fad1 Sofia Papagiannaki
    @property
382 c846fad1 Sofia Papagiannaki
    def using_external_quotaholder(self):
383 7ee27246 Georgios D. Tsoukalas
        return not isinstance(self.astakosclient, DisabledAstakosClient)
384 c846fad1 Sofia Papagiannaki
385 1f96b68d Sofia Papagiannaki
    @debug_method
386 5d022141 Sofia Papagiannaki
    @backend_method
387 a9b3f29d Antony Chazapis
    def list_accounts(self, user, marker=None, limit=10000):
388 a9b3f29d Antony Chazapis
        """Return a list of accounts the user can access."""
389 2715ade4 Sofia Papagiannaki
390 a9b3f29d Antony Chazapis
        allowed = self._allowed_accounts(user)
391 a9b3f29d Antony Chazapis
        start, limit = self._list_limits(allowed, marker, limit)
392 a9b3f29d Antony Chazapis
        return allowed[start:start + limit]
393 2715ade4 Sofia Papagiannaki
394 ec6f741b Sofia Papagiannaki
    def _get_account_quotas(self, account):
395 ec6f741b Sofia Papagiannaki
        """Get account usage from astakos."""
396 ec6f741b Sofia Papagiannaki
397 ec6f741b Sofia Papagiannaki
        quotas = self.astakosclient.service_get_quotas(account)[account]
398 ec6f741b Sofia Papagiannaki
        return quotas.get(DEFAULT_SOURCE, {}).get(DEFAULT_DISKSPACE_RESOURCE,
399 ec6f741b Sofia Papagiannaki
                                                  {})
400 ec6f741b Sofia Papagiannaki
401 1f96b68d Sofia Papagiannaki
    @debug_method
402 5d022141 Sofia Papagiannaki
    @backend_method
403 ec6f741b Sofia Papagiannaki
    def get_account_meta(self, user, account, domain, until=None,
404 ec6f741b Sofia Papagiannaki
                         include_user_defined=True):
405 cb69c154 Antony Chazapis
        """Return a dictionary with the account metadata for the domain."""
406 2715ade4 Sofia Papagiannaki
407 0d573e18 Sofia Papagiannaki
        self._can_read_account(user, account)
408 c915d3bf Antony Chazapis
        path, node = self._lookup_account(account, user == account)
409 a9b3f29d Antony Chazapis
        if user != account:
410 0d573e18 Sofia Papagiannaki
            if until or (node is None):
411 a9b3f29d Antony Chazapis
                raise NotAllowedError
412 a9b3f29d Antony Chazapis
        try:
413 44ad5860 Antony Chazapis
            props = self._get_properties(node, until)
414 2c5363a0 Antony Chazapis
            mtime = props[self.MTIME]
415 a9b3f29d Antony Chazapis
        except NameError:
416 62f915a1 Antony Chazapis
            props = None
417 a9b3f29d Antony Chazapis
            mtime = until
418 2e8edd42 Sofia Papagiannaki
        count, bytes, tstamp = self._get_statistics(node, until, compute=True)
419 62f915a1 Antony Chazapis
        tstamp = max(tstamp, mtime)
420 a9b3f29d Antony Chazapis
        if until is None:
421 a9b3f29d Antony Chazapis
            modified = tstamp
422 a9b3f29d Antony Chazapis
        else:
423 2715ade4 Sofia Papagiannaki
            modified = self._get_statistics(
424 2e8edd42 Sofia Papagiannaki
                node, compute=True)[2]  # Overall last modification.
425 62f915a1 Antony Chazapis
            modified = max(modified, mtime)
426 2715ade4 Sofia Papagiannaki
427 a9b3f29d Antony Chazapis
        if user != account:
428 a9b3f29d Antony Chazapis
            meta = {'name': account}
429 a9b3f29d Antony Chazapis
        else:
430 44ad5860 Antony Chazapis
            meta = {}
431 82482e2c Antony Chazapis
            if props is not None and include_user_defined:
432 2715ade4 Sofia Papagiannaki
                meta.update(
433 2715ade4 Sofia Papagiannaki
                    dict(self.node.attribute_get(props[self.SERIAL], domain)))
434 a9b3f29d Antony Chazapis
            if until is not None:
435 a9b3f29d Antony Chazapis
                meta.update({'until_timestamp': tstamp})
436 44ad5860 Antony Chazapis
            meta.update({'name': account, 'count': count, 'bytes': bytes})
437 0ed09c7c Sofia Papagiannaki
            if self.using_external_quotaholder:
438 ec6f741b Sofia Papagiannaki
                external_quota = self._get_account_quotas(account)
439 02de6286 Sofia Papagiannaki
                meta['bytes'] = external_quota.get('usage', 0)
440 a9b3f29d Antony Chazapis
        meta.update({'modified': modified})
441 a9b3f29d Antony Chazapis
        return meta
442 2715ade4 Sofia Papagiannaki
443 1f96b68d Sofia Papagiannaki
    @debug_method
444 5d022141 Sofia Papagiannaki
    @backend_method
445 cb69c154 Antony Chazapis
    def update_account_meta(self, user, account, domain, meta, replace=False):
446 cb69c154 Antony Chazapis
        """Update the metadata associated with the account for the domain."""
447 2715ade4 Sofia Papagiannaki
448 0d573e18 Sofia Papagiannaki
        self._can_write_account(user, account)
449 c915d3bf Antony Chazapis
        path, node = self._lookup_account(account, True)
450 0f510652 Sofia Papagiannaki
        self._put_metadata(user, node, domain, meta, replace,
451 0f510652 Sofia Papagiannaki
                           update_statistics_ancestors_depth=-1)
452 2715ade4 Sofia Papagiannaki
453 1f96b68d Sofia Papagiannaki
    @debug_method
454 5d022141 Sofia Papagiannaki
    @backend_method
455 a9b3f29d Antony Chazapis
    def get_account_groups(self, user, account):
456 29148653 Sofia Papagiannaki
        """Return a dictionary with the user groups defined for the account."""
457 2715ade4 Sofia Papagiannaki
458 0d573e18 Sofia Papagiannaki
        self._can_read_account(user, account)
459 a9b3f29d Antony Chazapis
        if user != account:
460 a9b3f29d Antony Chazapis
            return {}
461 44ad5860 Antony Chazapis
        self._lookup_account(account, True)
462 0f9d752c Antony Chazapis
        return self.permissions.group_dict(account)
463 2715ade4 Sofia Papagiannaki
464 1f96b68d Sofia Papagiannaki
    @debug_method
465 5d022141 Sofia Papagiannaki
    @backend_method
466 a9b3f29d Antony Chazapis
    def update_account_groups(self, user, account, groups, replace=False):
467 a9b3f29d Antony Chazapis
        """Update the groups associated with the account."""
468 2715ade4 Sofia Papagiannaki
469 0d573e18 Sofia Papagiannaki
        self._can_write_account(user, account)
470 44ad5860 Antony Chazapis
        self._lookup_account(account, True)
471 a9b3f29d Antony Chazapis
        self._check_groups(groups)
472 0f9d752c Antony Chazapis
        if replace:
473 0f9d752c Antony Chazapis
            self.permissions.group_destroy(account)
474 0f9d752c Antony Chazapis
        for k, v in groups.iteritems():
475 2715ade4 Sofia Papagiannaki
            if not replace:  # If not already deleted.
476 0f9d752c Antony Chazapis
                self.permissions.group_delete(account, k)
477 0f9d752c Antony Chazapis
            if v:
478 0f9d752c Antony Chazapis
                self.permissions.group_addmany(account, k, v)
479 2715ade4 Sofia Papagiannaki
480 1f96b68d Sofia Papagiannaki
    @debug_method
481 5d022141 Sofia Papagiannaki
    @backend_method
482 ec6f741b Sofia Papagiannaki
    def get_account_policy(self, user, account):
483 b2832c6a Antony Chazapis
        """Return a dictionary with the account policy."""
484 2715ade4 Sofia Papagiannaki
485 0d573e18 Sofia Papagiannaki
        self._can_read_account(user, account)
486 b2832c6a Antony Chazapis
        if user != account:
487 647a5f48 Antony Chazapis
            return {}
488 b2832c6a Antony Chazapis
        path, node = self._lookup_account(account, True)
489 19ddd41b Sofia Papagiannaki
        policy = self._get_policy(node, is_account_policy=True)
490 07fcdb96 Sofia Papagiannaki
        if self.using_external_quotaholder:
491 ec6f741b Sofia Papagiannaki
            external_quota = self._get_account_quotas(account)
492 02de6286 Sofia Papagiannaki
            policy['quota'] = external_quota.get('limit', 0)
493 c846fad1 Sofia Papagiannaki
        return policy
494 2715ade4 Sofia Papagiannaki
495 1f96b68d Sofia Papagiannaki
    @debug_method
496 5d022141 Sofia Papagiannaki
    @backend_method
497 b2832c6a Antony Chazapis
    def update_account_policy(self, user, account, policy, replace=False):
498 b2832c6a Antony Chazapis
        """Update the policy associated with the account."""
499 2715ade4 Sofia Papagiannaki
500 0d573e18 Sofia Papagiannaki
        self._can_write_account(user, account)
501 b2832c6a Antony Chazapis
        path, node = self._lookup_account(account, True)
502 19ddd41b Sofia Papagiannaki
        self._check_policy(policy, is_account_policy=True)
503 19ddd41b Sofia Papagiannaki
        self._put_policy(node, policy, replace, is_account_policy=True)
504 2715ade4 Sofia Papagiannaki
505 1f96b68d Sofia Papagiannaki
    @debug_method
506 5d022141 Sofia Papagiannaki
    @backend_method
507 78348987 Sofia Papagiannaki
    def put_account(self, user, account, policy=None):
508 a9b3f29d Antony Chazapis
        """Create a new account with the given name."""
509 2715ade4 Sofia Papagiannaki
510 78348987 Sofia Papagiannaki
        policy = policy or {}
511 0d573e18 Sofia Papagiannaki
        self._can_write_account(user, account)
512 44ad5860 Antony Chazapis
        node = self.node.node_lookup(account)
513 44ad5860 Antony Chazapis
        if node is not None:
514 7efc9f86 Sofia Papagiannaki
            raise AccountExists('Account already exists')
515 b2832c6a Antony Chazapis
        if policy:
516 19ddd41b Sofia Papagiannaki
            self._check_policy(policy, is_account_policy=True)
517 0f510652 Sofia Papagiannaki
        node = self._put_path(user, self.ROOTNODE, account,
518 0f510652 Sofia Papagiannaki
                              update_statistics_ancestors_depth=-1)
519 19ddd41b Sofia Papagiannaki
        self._put_policy(node, policy, True, is_account_policy=True)
520 2715ade4 Sofia Papagiannaki
521 1f96b68d Sofia Papagiannaki
    @debug_method
522 5d022141 Sofia Papagiannaki
    @backend_method
523 a9b3f29d Antony Chazapis
    def delete_account(self, user, account):
524 a9b3f29d Antony Chazapis
        """Delete the account with the given name."""
525 2715ade4 Sofia Papagiannaki
526 0d573e18 Sofia Papagiannaki
        self._can_write_account(user, account)
527 c915d3bf Antony Chazapis
        node = self.node.node_lookup(account)
528 c915d3bf Antony Chazapis
        if node is None:
529 c915d3bf Antony Chazapis
            return
530 0f510652 Sofia Papagiannaki
        if not self.node.node_remove(node,
531 0f510652 Sofia Papagiannaki
                                     update_statistics_ancestors_depth=-1):
532 7efc9f86 Sofia Papagiannaki
            raise AccountNotEmpty('Account is not empty')
533 0f9d752c Antony Chazapis
        self.permissions.group_destroy(account)
534 2715ade4 Sofia Papagiannaki
535 0d573e18 Sofia Papagiannaki
        # remove all the cached allowed paths
536 0d573e18 Sofia Papagiannaki
        # removing the specific path could be more expensive
537 0d573e18 Sofia Papagiannaki
        self._reset_allowed_paths()
538 0d573e18 Sofia Papagiannaki
539 1f96b68d Sofia Papagiannaki
    @debug_method
540 5d022141 Sofia Papagiannaki
    @backend_method
541 29148653 Sofia Papagiannaki
    def list_containers(self, user, account, marker=None, limit=10000,
542 29148653 Sofia Papagiannaki
                        shared=False, until=None, public=False):
543 62f915a1 Antony Chazapis
        """Return a list of containers existing under an account."""
544 2715ade4 Sofia Papagiannaki
545 0d573e18 Sofia Papagiannaki
        self._can_read_account(user, account)
546 62f915a1 Antony Chazapis
        if user != account:
547 0d573e18 Sofia Papagiannaki
            if until:
548 62f915a1 Antony Chazapis
                raise NotAllowedError
549 62f915a1 Antony Chazapis
            allowed = self._allowed_containers(user, account)
550 62f915a1 Antony Chazapis
            start, limit = self._list_limits(allowed, marker, limit)
551 62f915a1 Antony Chazapis
            return allowed[start:start + limit]
552 90ee1eb3 Sofia Papagiannaki
        if shared or public:
553 56ac7c81 Sofia Papagiannaki
            allowed = set()
554 90ee1eb3 Sofia Papagiannaki
            if shared:
555 29148653 Sofia Papagiannaki
                allowed.update([x.split('/', 2)[1] for x in
556 29148653 Sofia Papagiannaki
                               self.permissions.access_list_shared(account)])
557 90ee1eb3 Sofia Papagiannaki
            if public:
558 29148653 Sofia Papagiannaki
                allowed.update([x[0].split('/', 2)[1] for x in
559 29148653 Sofia Papagiannaki
                               self.permissions.public_list(account)])
560 56ac7c81 Sofia Papagiannaki
            allowed = sorted(allowed)
561 62f915a1 Antony Chazapis
            start, limit = self._list_limits(allowed, marker, limit)
562 62f915a1 Antony Chazapis
            return allowed[start:start + limit]
563 62f915a1 Antony Chazapis
        node = self.node.node_lookup(account)
564 2715ade4 Sofia Papagiannaki
        containers = [x[0] for x in self._list_object_properties(
565 2715ade4 Sofia Papagiannaki
            node, account, '', '/', marker, limit, False, None, [], until)]
566 2715ade4 Sofia Papagiannaki
        start, limit = self._list_limits(
567 2715ade4 Sofia Papagiannaki
            [x[0] for x in containers], marker, limit)
568 cf4a7a7b Sofia Papagiannaki
        return containers[start:start + limit]
569 2715ade4 Sofia Papagiannaki
570 1f96b68d Sofia Papagiannaki
    @debug_method
571 5d022141 Sofia Papagiannaki
    @backend_method
572 29148653 Sofia Papagiannaki
    def list_container_meta(self, user, account, container, domain,
573 29148653 Sofia Papagiannaki
                            until=None):
574 29148653 Sofia Papagiannaki
        """Return a list of the container's object meta keys for a domain."""
575 2715ade4 Sofia Papagiannaki
576 0d573e18 Sofia Papagiannaki
        self._can_read_container(user, account, container)
577 371d907a Antony Chazapis
        allowed = []
578 371d907a Antony Chazapis
        if user != account:
579 371d907a Antony Chazapis
            if until:
580 371d907a Antony Chazapis
                raise NotAllowedError
581 371d907a Antony Chazapis
        path, node = self._lookup_container(account, container)
582 371d907a Antony Chazapis
        before = until if until is not None else inf
583 371d907a Antony Chazapis
        allowed = self._get_formatted_paths(allowed)
584 29148653 Sofia Papagiannaki
        return self.node.latest_attribute_keys(node, domain, before,
585 29148653 Sofia Papagiannaki
                                               CLUSTER_DELETED, allowed)
586 2715ade4 Sofia Papagiannaki
587 1f96b68d Sofia Papagiannaki
    @debug_method
588 5d022141 Sofia Papagiannaki
    @backend_method
589 29148653 Sofia Papagiannaki
    def get_container_meta(self, user, account, container, domain, until=None,
590 29148653 Sofia Papagiannaki
                           include_user_defined=True):
591 cb69c154 Antony Chazapis
        """Return a dictionary with the container metadata for the domain."""
592 2715ade4 Sofia Papagiannaki
593 0d573e18 Sofia Papagiannaki
        self._can_read_container(user, account, container)
594 a9b3f29d Antony Chazapis
        if user != account:
595 0d573e18 Sofia Papagiannaki
            if until:
596 a9b3f29d Antony Chazapis
                raise NotAllowedError
597 c915d3bf Antony Chazapis
        path, node = self._lookup_container(account, container)
598 c915d3bf Antony Chazapis
        props = self._get_properties(node, until)
599 2c5363a0 Antony Chazapis
        mtime = props[self.MTIME]
600 62f915a1 Antony Chazapis
        count, bytes, tstamp = self._get_statistics(node, until)
601 62f915a1 Antony Chazapis
        tstamp = max(tstamp, mtime)
602 a9b3f29d Antony Chazapis
        if until is None:
603 a9b3f29d Antony Chazapis
            modified = tstamp
604 a9b3f29d Antony Chazapis
        else:
605 2715ade4 Sofia Papagiannaki
            modified = self._get_statistics(
606 2715ade4 Sofia Papagiannaki
                node)[2]  # Overall last modification.
607 62f915a1 Antony Chazapis
            modified = max(modified, mtime)
608 2715ade4 Sofia Papagiannaki
609 a9b3f29d Antony Chazapis
        if user != account:
610 c915d3bf Antony Chazapis
            meta = {'name': container}
611 a9b3f29d Antony Chazapis
        else:
612 82482e2c Antony Chazapis
            meta = {}
613 82482e2c Antony Chazapis
            if include_user_defined:
614 2715ade4 Sofia Papagiannaki
                meta.update(
615 2715ade4 Sofia Papagiannaki
                    dict(self.node.attribute_get(props[self.SERIAL], domain)))
616 a9b3f29d Antony Chazapis
            if until is not None:
617 a9b3f29d Antony Chazapis
                meta.update({'until_timestamp': tstamp})
618 c915d3bf Antony Chazapis
            meta.update({'name': container, 'count': count, 'bytes': bytes})
619 c915d3bf Antony Chazapis
        meta.update({'modified': modified})
620 a9b3f29d Antony Chazapis
        return meta
621 2715ade4 Sofia Papagiannaki
622 1f96b68d Sofia Papagiannaki
    @debug_method
623 5d022141 Sofia Papagiannaki
    @backend_method
624 29148653 Sofia Papagiannaki
    def update_container_meta(self, user, account, container, domain, meta,
625 29148653 Sofia Papagiannaki
                              replace=False):
626 cb69c154 Antony Chazapis
        """Update the metadata associated with the container for the domain."""
627 2715ade4 Sofia Papagiannaki
628 0d573e18 Sofia Papagiannaki
        self._can_write_container(user, account, container)
629 c915d3bf Antony Chazapis
        path, node = self._lookup_container(account, container)
630 2715ade4 Sofia Papagiannaki
        src_version_id, dest_version_id = self._put_metadata(
631 0f510652 Sofia Papagiannaki
            user, node, domain, meta, replace,
632 0f510652 Sofia Papagiannaki
            update_statistics_ancestors_depth=0)
633 f9ea264b Antony Chazapis
        if src_version_id is not None:
634 19ddd41b Sofia Papagiannaki
            versioning = self._get_policy(
635 19ddd41b Sofia Papagiannaki
                node, is_account_policy=False)['versioning']
636 f9ea264b Antony Chazapis
            if versioning != 'auto':
637 0f510652 Sofia Papagiannaki
                self.node.version_remove(src_version_id,
638 0f510652 Sofia Papagiannaki
                                         update_statistics_ancestors_depth=0)
639 2715ade4 Sofia Papagiannaki
640 1f96b68d Sofia Papagiannaki
    @debug_method
641 5d022141 Sofia Papagiannaki
    @backend_method
642 a9b3f29d Antony Chazapis
    def get_container_policy(self, user, account, container):
643 a9b3f29d Antony Chazapis
        """Return a dictionary with the container policy."""
644 2715ade4 Sofia Papagiannaki
645 0d573e18 Sofia Papagiannaki
        self._can_read_container(user, account, container)
646 a9b3f29d Antony Chazapis
        if user != account:
647 a9b3f29d Antony Chazapis
            return {}
648 5e7485da Antony Chazapis
        path, node = self._lookup_container(account, container)
649 19ddd41b Sofia Papagiannaki
        return self._get_policy(node, is_account_policy=False)
650 2715ade4 Sofia Papagiannaki
651 1f96b68d Sofia Papagiannaki
    @debug_method
652 5d022141 Sofia Papagiannaki
    @backend_method
653 29148653 Sofia Papagiannaki
    def update_container_policy(self, user, account, container, policy,
654 29148653 Sofia Papagiannaki
                                replace=False):
655 b2832c6a Antony Chazapis
        """Update the policy associated with the container."""
656 2715ade4 Sofia Papagiannaki
657 0d573e18 Sofia Papagiannaki
        self._can_write_container(user, account, container)
658 5e7485da Antony Chazapis
        path, node = self._lookup_container(account, container)
659 19ddd41b Sofia Papagiannaki
        self._check_policy(policy, is_account_policy=False)
660 19ddd41b Sofia Papagiannaki
        self._put_policy(node, policy, replace, is_account_policy=False)
661 2715ade4 Sofia Papagiannaki
662 1f96b68d Sofia Papagiannaki
    @debug_method
663 5d022141 Sofia Papagiannaki
    @backend_method
664 78348987 Sofia Papagiannaki
    def put_container(self, user, account, container, policy=None):
665 a9b3f29d Antony Chazapis
        """Create a new container with the given name."""
666 2715ade4 Sofia Papagiannaki
667 78348987 Sofia Papagiannaki
        policy = policy or {}
668 0d573e18 Sofia Papagiannaki
        self._can_write_container(user, account, container)
669 a9b3f29d Antony Chazapis
        try:
670 c915d3bf Antony Chazapis
            path, node = self._lookup_container(account, container)
671 a9b3f29d Antony Chazapis
        except NameError:
672 a9b3f29d Antony Chazapis
            pass
673 a9b3f29d Antony Chazapis
        else:
674 7efc9f86 Sofia Papagiannaki
            raise ContainerExists('Container already exists')
675 a9b3f29d Antony Chazapis
        if policy:
676 19ddd41b Sofia Papagiannaki
            self._check_policy(policy, is_account_policy=False)
677 a9b3f29d Antony Chazapis
        path = '/'.join((account, container))
678 2715ade4 Sofia Papagiannaki
        node = self._put_path(
679 0f510652 Sofia Papagiannaki
            user, self._lookup_account(account, True)[1], path,
680 0f510652 Sofia Papagiannaki
            update_statistics_ancestors_depth=-1)
681 19ddd41b Sofia Papagiannaki
        self._put_policy(node, policy, True, is_account_policy=False)
682 2715ade4 Sofia Papagiannaki
683 1f96b68d Sofia Papagiannaki
    @debug_method
684 5d022141 Sofia Papagiannaki
    @backend_method
685 29148653 Sofia Papagiannaki
    def delete_container(self, user, account, container, until=None, prefix='',
686 29148653 Sofia Papagiannaki
                         delimiter=None):
687 a9b3f29d Antony Chazapis
        """Delete/purge the container with the given name."""
688 2715ade4 Sofia Papagiannaki
689 0d573e18 Sofia Papagiannaki
        self._can_write_container(user, account, container)
690 c915d3bf Antony Chazapis
        path, node = self._lookup_container(account, container)
691 2715ade4 Sofia Papagiannaki
692 a9b3f29d Antony Chazapis
        if until is not None:
693 388ea25f Sofia Papagiannaki
            hashes, size, serials = self.node.node_purge_children(
694 0f510652 Sofia Papagiannaki
                node, until, CLUSTER_HISTORY,
695 0f510652 Sofia Papagiannaki
                update_statistics_ancestors_depth=0)
696 04230536 Antony Chazapis
            for h in hashes:
697 04230536 Antony Chazapis
                self.store.map_delete(h)
698 0f510652 Sofia Papagiannaki
            self.node.node_purge_children(node, until, CLUSTER_DELETED,
699 0f510652 Sofia Papagiannaki
                                          update_statistics_ancestors_depth=0)
700 0a92ff85 Sofia Papagiannaki
            if not self.free_versioning:
701 0a92ff85 Sofia Papagiannaki
                self._report_size_change(
702 0a92ff85 Sofia Papagiannaki
                    user, account, -size, {
703 29148653 Sofia Papagiannaki
                        'action': 'container purge',
704 0a92ff85 Sofia Papagiannaki
                        'path': path,
705 0a92ff85 Sofia Papagiannaki
                        'versions': ','.join(str(i) for i in serials)
706 0a92ff85 Sofia Papagiannaki
                    }
707 0a92ff85 Sofia Papagiannaki
                )
708 a9b3f29d Antony Chazapis
            return
709 2715ade4 Sofia Papagiannaki
710 e46b2bcf Sofia Papagiannaki
        if not delimiter:
711 e46b2bcf Sofia Papagiannaki
            if self._get_statistics(node)[0] > 0:
712 e46b2bcf Sofia Papagiannaki
                raise ContainerNotEmpty('Container is not empty')
713 388ea25f Sofia Papagiannaki
            hashes, size, serials = self.node.node_purge_children(
714 0f510652 Sofia Papagiannaki
                node, inf, CLUSTER_HISTORY,
715 0f510652 Sofia Papagiannaki
                update_statistics_ancestors_depth=0)
716 e46b2bcf Sofia Papagiannaki
            for h in hashes:
717 e46b2bcf Sofia Papagiannaki
                self.store.map_delete(h)
718 0f510652 Sofia Papagiannaki
            self.node.node_purge_children(node, inf, CLUSTER_DELETED,
719 0f510652 Sofia Papagiannaki
                                          update_statistics_ancestors_depth=0)
720 0f510652 Sofia Papagiannaki
            self.node.node_remove(node, update_statistics_ancestors_depth=0)
721 0a92ff85 Sofia Papagiannaki
            if not self.free_versioning:
722 0a92ff85 Sofia Papagiannaki
                self._report_size_change(
723 0a92ff85 Sofia Papagiannaki
                    user, account, -size, {
724 29148653 Sofia Papagiannaki
                        'action': 'container purge',
725 0a92ff85 Sofia Papagiannaki
                        'path': path,
726 0a92ff85 Sofia Papagiannaki
                        'versions': ','.join(str(i) for i in serials)
727 0a92ff85 Sofia Papagiannaki
                    }
728 0a92ff85 Sofia Papagiannaki
                )
729 e46b2bcf Sofia Papagiannaki
        else:
730 b1dadd0e Sofia Papagiannaki
            # remove only contents
731 29148653 Sofia Papagiannaki
            src_names = self._list_objects_no_limit(
732 29148653 Sofia Papagiannaki
                user, account, container, prefix='', delimiter=None,
733 29148653 Sofia Papagiannaki
                virtual=False, domain=None, keys=[], shared=False, until=None,
734 29148653 Sofia Papagiannaki
                size_range=None, all_props=True, public=False)
735 e46b2bcf Sofia Papagiannaki
            paths = []
736 e46b2bcf Sofia Papagiannaki
            for t in src_names:
737 e46b2bcf Sofia Papagiannaki
                path = '/'.join((account, container, t[0]))
738 e46b2bcf Sofia Papagiannaki
                node = t[2]
739 33af031c Sofia Papagiannaki
                if not self._exists(node):
740 33af031c Sofia Papagiannaki
                    continue
741 0f510652 Sofia Papagiannaki
                src_version_id, dest_version_id = self._put_version_duplicate(
742 0f510652 Sofia Papagiannaki
                    user, node, size=0, type='', hash=None, checksum='',
743 0f510652 Sofia Papagiannaki
                    cluster=CLUSTER_DELETED,
744 0f510652 Sofia Papagiannaki
                    update_statistics_ancestors_depth=1)
745 2715ade4 Sofia Papagiannaki
                del_size = self._apply_versioning(
746 0f510652 Sofia Papagiannaki
                    account, container, src_version_id,
747 0f510652 Sofia Papagiannaki
                    update_statistics_ancestors_depth=1)
748 b1dadd0e Sofia Papagiannaki
                self._report_size_change(
749 29148653 Sofia Papagiannaki
                    user, account, -del_size, {
750 29148653 Sofia Papagiannaki
                        'action': 'object delete',
751 29148653 Sofia Papagiannaki
                        'path': path,
752 29148653 Sofia Papagiannaki
                        'versions': ','.join([str(dest_version_id)])})
753 2715ade4 Sofia Papagiannaki
                self._report_object_change(
754 2715ade4 Sofia Papagiannaki
                    user, account, path, details={'action': 'object delete'})
755 e46b2bcf Sofia Papagiannaki
                paths.append(path)
756 e46b2bcf Sofia Papagiannaki
            self.permissions.access_clear_bulk(paths)
757 2715ade4 Sofia Papagiannaki
758 0d573e18 Sofia Papagiannaki
        # remove all the cached allowed paths
759 0d573e18 Sofia Papagiannaki
        # removing the specific path could be more expensive
760 0d573e18 Sofia Papagiannaki
        self._reset_allowed_paths()
761 0d573e18 Sofia Papagiannaki
762 29148653 Sofia Papagiannaki
    def _list_objects(self, user, account, container, prefix, delimiter,
763 29148653 Sofia Papagiannaki
                      marker, limit, virtual, domain, keys, shared, until,
764 29148653 Sofia Papagiannaki
                      size_range, all_props, public):
765 15a96c3e Antony Chazapis
        if user != account and until:
766 15a96c3e Antony Chazapis
            raise NotAllowedError
767 cf4a7a7b Sofia Papagiannaki
        if shared and public:
768 cf4a7a7b Sofia Papagiannaki
            # get shared first
769 5576e6dd Sofia Papagiannaki
            shared_paths = self._list_object_permissions(
770 2715ade4 Sofia Papagiannaki
                user, account, container, prefix, shared=True, public=False)
771 31e1acd3 Sofia Papagiannaki
            objects = set()
772 5576e6dd Sofia Papagiannaki
            if shared_paths:
773 cf4a7a7b Sofia Papagiannaki
                path, node = self._lookup_container(account, container)
774 5576e6dd Sofia Papagiannaki
                shared_paths = self._get_formatted_paths(shared_paths)
775 29148653 Sofia Papagiannaki
                objects |= set(self._list_object_properties(
776 29148653 Sofia Papagiannaki
                    node, path, prefix, delimiter, marker, limit, virtual,
777 29148653 Sofia Papagiannaki
                    domain, keys, until, size_range, shared_paths, all_props))
778 2715ade4 Sofia Papagiannaki
779 cf4a7a7b Sofia Papagiannaki
            # get public
780 2715ade4 Sofia Papagiannaki
            objects |= set(self._list_public_object_properties(
781 2715ade4 Sofia Papagiannaki
                user, account, container, prefix, all_props))
782 31e1acd3 Sofia Papagiannaki
            objects = list(objects)
783 2715ade4 Sofia Papagiannaki
784 cf4a7a7b Sofia Papagiannaki
            objects.sort(key=lambda x: x[0])
785 2715ade4 Sofia Papagiannaki
            start, limit = self._list_limits(
786 2715ade4 Sofia Papagiannaki
                [x[0] for x in objects], marker, limit)
787 cf4a7a7b Sofia Papagiannaki
            return objects[start:start + limit]
788 cf4a7a7b Sofia Papagiannaki
        elif public:
789 2715ade4 Sofia Papagiannaki
            objects = self._list_public_object_properties(
790 2715ade4 Sofia Papagiannaki
                user, account, container, prefix, all_props)
791 2715ade4 Sofia Papagiannaki
            start, limit = self._list_limits(
792 2715ade4 Sofia Papagiannaki
                [x[0] for x in objects], marker, limit)
793 cf4a7a7b Sofia Papagiannaki
            return objects[start:start + limit]
794 2715ade4 Sofia Papagiannaki
795 2715ade4 Sofia Papagiannaki
        allowed = self._list_object_permissions(
796 2715ade4 Sofia Papagiannaki
            user, account, container, prefix, shared, public)
797 cf4a7a7b Sofia Papagiannaki
        if shared and not allowed:
798 fcd37c40 Antony Chazapis
            return []
799 15a96c3e Antony Chazapis
        path, node = self._lookup_container(account, container)
800 15a96c3e Antony Chazapis
        allowed = self._get_formatted_paths(allowed)
801 29148653 Sofia Papagiannaki
        objects = self._list_object_properties(
802 29148653 Sofia Papagiannaki
            node, path, prefix, delimiter, marker, limit, virtual, domain,
803 29148653 Sofia Papagiannaki
            keys, until, size_range, allowed, all_props)
804 2715ade4 Sofia Papagiannaki
        start, limit = self._list_limits(
805 2715ade4 Sofia Papagiannaki
            [x[0] for x in objects], marker, limit)
806 cf4a7a7b Sofia Papagiannaki
        return objects[start:start + limit]
807 2715ade4 Sofia Papagiannaki
808 29148653 Sofia Papagiannaki
    def _list_public_object_properties(self, user, account, container, prefix,
809 29148653 Sofia Papagiannaki
                                       all_props):
810 2715ade4 Sofia Papagiannaki
        public = self._list_object_permissions(
811 2715ade4 Sofia Papagiannaki
            user, account, container, prefix, shared=False, public=True)
812 cf4a7a7b Sofia Papagiannaki
        paths, nodes = self._lookup_objects(public)
813 cf4a7a7b Sofia Papagiannaki
        path = '/'.join((account, container))
814 cf4a7a7b Sofia Papagiannaki
        cont_prefix = path + '/'
815 cf4a7a7b Sofia Papagiannaki
        paths = [x[len(cont_prefix):] for x in paths]
816 29148653 Sofia Papagiannaki
        objects = [(p,) + props for p, props in
817 29148653 Sofia Papagiannaki
                   zip(paths, self.node.version_lookup_bulk(
818 2c2513fc Sofia Papagiannaki
                       nodes, all_props=all_props, order_by_path=True))]
819 cf4a7a7b Sofia Papagiannaki
        return objects
820 2715ade4 Sofia Papagiannaki
821 29148653 Sofia Papagiannaki
    def _list_objects_no_limit(self, user, account, container, prefix,
822 29148653 Sofia Papagiannaki
                               delimiter, virtual, domain, keys, shared, until,
823 29148653 Sofia Papagiannaki
                               size_range, all_props, public):
824 4d15c94e Sofia Papagiannaki
        objects = []
825 4d15c94e Sofia Papagiannaki
        while True:
826 4d15c94e Sofia Papagiannaki
            marker = objects[-1] if objects else None
827 4d15c94e Sofia Papagiannaki
            limit = 10000
828 29148653 Sofia Papagiannaki
            l = self._list_objects(
829 29148653 Sofia Papagiannaki
                user, account, container, prefix, delimiter, marker, limit,
830 29148653 Sofia Papagiannaki
                virtual, domain, keys, shared, until, size_range, all_props,
831 29148653 Sofia Papagiannaki
                public)
832 4d15c94e Sofia Papagiannaki
            objects.extend(l)
833 4d15c94e Sofia Papagiannaki
            if not l or len(l) < limit:
834 4d15c94e Sofia Papagiannaki
                break
835 4d15c94e Sofia Papagiannaki
        return objects
836 2715ade4 Sofia Papagiannaki
837 29148653 Sofia Papagiannaki
    def _list_object_permissions(self, user, account, container, prefix,
838 29148653 Sofia Papagiannaki
                                 shared, public):
839 62f915a1 Antony Chazapis
        allowed = []
840 fcd37c40 Antony Chazapis
        path = '/'.join((account, container, prefix)).rstrip('/')
841 62f915a1 Antony Chazapis
        if user != account:
842 fcd37c40 Antony Chazapis
            allowed = self.permissions.access_list_paths(user, path)
843 62f915a1 Antony Chazapis
            if not allowed:
844 62f915a1 Antony Chazapis
                raise NotAllowedError
845 62f915a1 Antony Chazapis
        else:
846 56ac7c81 Sofia Papagiannaki
            allowed = set()
847 62f915a1 Antony Chazapis
            if shared:
848 56ac7c81 Sofia Papagiannaki
                allowed.update(self.permissions.access_list_shared(path))
849 c53c4def Sofia Papagiannaki
            if public:
850 2715ade4 Sofia Papagiannaki
                allowed.update(
851 2715ade4 Sofia Papagiannaki
                    [x[0] for x in self.permissions.public_list(path)])
852 56ac7c81 Sofia Papagiannaki
            allowed = sorted(allowed)
853 c53c4def Sofia Papagiannaki
            if not allowed:
854 c53c4def Sofia Papagiannaki
                return []
855 15a96c3e Antony Chazapis
        return allowed
856 2715ade4 Sofia Papagiannaki
857 1f96b68d Sofia Papagiannaki
    @debug_method
858 5d022141 Sofia Papagiannaki
    @backend_method
859 29148653 Sofia Papagiannaki
    def list_objects(self, user, account, container, prefix='', delimiter=None,
860 29148653 Sofia Papagiannaki
                     marker=None, limit=10000, virtual=True, domain=None,
861 29148653 Sofia Papagiannaki
                     keys=None, shared=False, until=None, size_range=None,
862 29148653 Sofia Papagiannaki
                     public=False):
863 29148653 Sofia Papagiannaki
        """List (object name, object version_id) under a container."""
864 2715ade4 Sofia Papagiannaki
865 78348987 Sofia Papagiannaki
        keys = keys or []
866 29148653 Sofia Papagiannaki
        return self._list_objects(
867 29148653 Sofia Papagiannaki
            user, account, container, prefix, delimiter, marker, limit,
868 29148653 Sofia Papagiannaki
            virtual, domain, keys, shared, until, size_range, False, public)
869 2715ade4 Sofia Papagiannaki
870 1f96b68d Sofia Papagiannaki
    @debug_method
871 5d022141 Sofia Papagiannaki
    @backend_method
872 29148653 Sofia Papagiannaki
    def list_object_meta(self, user, account, container, prefix='',
873 29148653 Sofia Papagiannaki
                         delimiter=None, marker=None, limit=10000,
874 29148653 Sofia Papagiannaki
                         virtual=True, domain=None, keys=None, shared=False,
875 29148653 Sofia Papagiannaki
                         until=None, size_range=None, public=False):
876 29148653 Sofia Papagiannaki
        """Return a list of metadata dicts of objects under a container."""
877 2715ade4 Sofia Papagiannaki
878 78348987 Sofia Papagiannaki
        keys = keys or []
879 29148653 Sofia Papagiannaki
        props = self._list_objects(
880 29148653 Sofia Papagiannaki
            user, account, container, prefix, delimiter, marker, limit,
881 29148653 Sofia Papagiannaki
            virtual, domain, keys, shared, until, size_range, True, public)
882 371d907a Antony Chazapis
        objects = []
883 371d907a Antony Chazapis
        for p in props:
884 371d907a Antony Chazapis
            if len(p) == 2:
885 371d907a Antony Chazapis
                objects.append({'subdir': p[0]})
886 371d907a Antony Chazapis
            else:
887 29148653 Sofia Papagiannaki
                objects.append({
888 29148653 Sofia Papagiannaki
                    'name': p[0],
889 29148653 Sofia Papagiannaki
                    'bytes': p[self.SIZE + 1],
890 29148653 Sofia Papagiannaki
                    'type': p[self.TYPE + 1],
891 29148653 Sofia Papagiannaki
                    'hash': p[self.HASH + 1],
892 29148653 Sofia Papagiannaki
                    'version': p[self.SERIAL + 1],
893 29148653 Sofia Papagiannaki
                    'version_timestamp': p[self.MTIME + 1],
894 29148653 Sofia Papagiannaki
                    'modified': p[self.MTIME + 1] if until is None else None,
895 29148653 Sofia Papagiannaki
                    'modified_by': p[self.MUSER + 1],
896 29148653 Sofia Papagiannaki
                    'uuid': p[self.UUID + 1],
897 29148653 Sofia Papagiannaki
                    'checksum': p[self.CHECKSUM + 1]})
898 371d907a Antony Chazapis
        return objects
899 2715ade4 Sofia Papagiannaki
900 1f96b68d Sofia Papagiannaki
    @debug_method
901 5d022141 Sofia Papagiannaki
    @backend_method
902 15a96c3e Antony Chazapis
    def list_object_permissions(self, user, account, container, prefix=''):
903 29148653 Sofia Papagiannaki
        """Return a list of paths enforce permissions under a container."""
904 2715ade4 Sofia Papagiannaki
905 29148653 Sofia Papagiannaki
        return self._list_object_permissions(user, account, container, prefix,
906 29148653 Sofia Papagiannaki
                                             True, False)
907 2715ade4 Sofia Papagiannaki
908 1f96b68d Sofia Papagiannaki
    @debug_method
909 5d022141 Sofia Papagiannaki
    @backend_method
910 15a96c3e Antony Chazapis
    def list_object_public(self, user, account, container, prefix=''):
911 29148653 Sofia Papagiannaki
        """Return a mapping of object paths to public ids under a container."""
912 2715ade4 Sofia Papagiannaki
913 15a96c3e Antony Chazapis
        public = {}
914 29148653 Sofia Papagiannaki
        for path, p in self.permissions.public_list('/'.join((account,
915 29148653 Sofia Papagiannaki
                                                              container,
916 29148653 Sofia Papagiannaki
                                                              prefix))):
917 56f3c759 Sofia Papagiannaki
            public[path] = p
918 15a96c3e Antony Chazapis
        return public
919 2715ade4 Sofia Papagiannaki
920 1f96b68d Sofia Papagiannaki
    @debug_method
921 5d022141 Sofia Papagiannaki
    @backend_method
922 29148653 Sofia Papagiannaki
    def get_object_meta(self, user, account, container, name, domain,
923 29148653 Sofia Papagiannaki
                        version=None, include_user_defined=True):
924 cb69c154 Antony Chazapis
        """Return a dictionary with the object metadata for the domain."""
925 2715ade4 Sofia Papagiannaki
926 0d573e18 Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
927 c915d3bf Antony Chazapis
        path, node = self._lookup_object(account, container, name)
928 c915d3bf Antony Chazapis
        props = self._get_version(node, version)
929 a9b3f29d Antony Chazapis
        if version is None:
930 2c5363a0 Antony Chazapis
            modified = props[self.MTIME]
931 a9b3f29d Antony Chazapis
        else:
932 97d45f69 Antony Chazapis
            try:
933 2715ade4 Sofia Papagiannaki
                modified = self._get_version(
934 2715ade4 Sofia Papagiannaki
                    node)[self.MTIME]  # Overall last modification.
935 2715ade4 Sofia Papagiannaki
            except NameError:  # Object may be deleted.
936 2715ade4 Sofia Papagiannaki
                del_props = self.node.version_lookup(
937 2715ade4 Sofia Papagiannaki
                    node, inf, CLUSTER_DELETED)
938 97d45f69 Antony Chazapis
                if del_props is None:
939 7efc9f86 Sofia Papagiannaki
                    raise ItemNotExists('Object does not exist')
940 97d45f69 Antony Chazapis
                modified = del_props[self.MTIME]
941 2715ade4 Sofia Papagiannaki
942 82482e2c Antony Chazapis
        meta = {}
943 82482e2c Antony Chazapis
        if include_user_defined:
944 2715ade4 Sofia Papagiannaki
            meta.update(
945 2715ade4 Sofia Papagiannaki
                dict(self.node.attribute_get(props[self.SERIAL], domain)))
946 33b4e4a6 Antony Chazapis
        meta.update({'name': name,
947 33b4e4a6 Antony Chazapis
                     'bytes': props[self.SIZE],
948 33b4e4a6 Antony Chazapis
                     'type': props[self.TYPE],
949 371d907a Antony Chazapis
                     'hash': props[self.HASH],
950 33b4e4a6 Antony Chazapis
                     'version': props[self.SERIAL],
951 33b4e4a6 Antony Chazapis
                     'version_timestamp': props[self.MTIME],
952 33b4e4a6 Antony Chazapis
                     'modified': modified,
953 33b4e4a6 Antony Chazapis
                     'modified_by': props[self.MUSER],
954 33b4e4a6 Antony Chazapis
                     'uuid': props[self.UUID],
955 33b4e4a6 Antony Chazapis
                     'checksum': props[self.CHECKSUM]})
956 a9b3f29d Antony Chazapis
        return meta
957 2715ade4 Sofia Papagiannaki
958 1f96b68d Sofia Papagiannaki
    @debug_method
959 5d022141 Sofia Papagiannaki
    @backend_method
960 29148653 Sofia Papagiannaki
    def update_object_meta(self, user, account, container, name, domain, meta,
961 29148653 Sofia Papagiannaki
                           replace=False):
962 29148653 Sofia Papagiannaki
        """Update object metadata for a domain and return the new version."""
963 2715ade4 Sofia Papagiannaki
964 0d573e18 Sofia Papagiannaki
        self._can_write_object(user, account, container, name)
965 48bb9c89 Sofia Papagiannaki
966 48bb9c89 Sofia Papagiannaki
        path, node = self._lookup_object(account, container, name,
967 48bb9c89 Sofia Papagiannaki
                                         lock_container=True)
968 2715ade4 Sofia Papagiannaki
        src_version_id, dest_version_id = self._put_metadata(
969 0f510652 Sofia Papagiannaki
            user, node, domain, meta, replace,
970 0f510652 Sofia Papagiannaki
            update_statistics_ancestors_depth=1)
971 0f510652 Sofia Papagiannaki
        self._apply_versioning(account, container, src_version_id,
972 0f510652 Sofia Papagiannaki
                               update_statistics_ancestors_depth=1)
973 5cc484e1 Antony Chazapis
        return dest_version_id
974 62e6d12e Nanakos Chrysostomos
975 dc88754b Nanakos Chrysostomos
    @debug_method
976 5d022141 Sofia Papagiannaki
    @backend_method
977 dc88754b Nanakos Chrysostomos
    def get_object_permissions_bulk(self, user, account, container, names):
978 dc88754b Nanakos Chrysostomos
        """Return the action allowed on the object, the path
979 dc88754b Nanakos Chrysostomos
        from which the object gets its permissions from,
980 dc88754b Nanakos Chrysostomos
        along with a dictionary containing the permissions."""
981 dc88754b Nanakos Chrysostomos
982 ace7592b Sofia Papagiannaki
        permissions_path = self._get_permissions_path_bulk(account, container,
983 ace7592b Sofia Papagiannaki
                                                           names)
984 dc88754b Nanakos Chrysostomos
        access_objects = self.permissions.access_check_bulk(permissions_path,
985 ace7592b Sofia Papagiannaki
                                                            user)
986 62e6d12e Nanakos Chrysostomos
        #group_parents = access_objects['group_parents']
987 dc88754b Nanakos Chrysostomos
        nobject_permissions = {}
988 e161c24f Sofia Papagiannaki
        cpath = '/'.join((account, container, ''))
989 e161c24f Sofia Papagiannaki
        cpath_idx = len(cpath)
990 dc88754b Nanakos Chrysostomos
        for path in permissions_path:
991 dc88754b Nanakos Chrysostomos
            allowed = 1
992 e161c24f Sofia Papagiannaki
            name = path[cpath_idx:]
993 dc88754b Nanakos Chrysostomos
            if user != account:
994 dc88754b Nanakos Chrysostomos
                try:
995 dc88754b Nanakos Chrysostomos
                    allowed = access_objects[path]
996 dc88754b Nanakos Chrysostomos
                except KeyError:
997 dc88754b Nanakos Chrysostomos
                    raise NotAllowedError
998 dc88754b Nanakos Chrysostomos
            access_dict, allowed = \
999 dc88754b Nanakos Chrysostomos
                self.permissions.access_get_for_bulk(access_objects[path])
1000 dc88754b Nanakos Chrysostomos
            nobject_permissions[name] = (self.ALLOWED[allowed], path,
1001 dc88754b Nanakos Chrysostomos
                                         access_dict)
1002 dc88754b Nanakos Chrysostomos
        self._lookup_objects(permissions_path)
1003 dc88754b Nanakos Chrysostomos
        return nobject_permissions
1004 dc88754b Nanakos Chrysostomos
1005 1f96b68d Sofia Papagiannaki
    @debug_method
1006 5d022141 Sofia Papagiannaki
    @backend_method
1007 a9b3f29d Antony Chazapis
    def get_object_permissions(self, user, account, container, name):
1008 067cf1fc Antony Chazapis
        """Return the action allowed on the object, the path
1009 067cf1fc Antony Chazapis
        from which the object gets its permissions from,
1010 a9b3f29d Antony Chazapis
        along with a dictionary containing the permissions."""
1011 2715ade4 Sofia Papagiannaki
1012 067cf1fc Antony Chazapis
        allowed = 'write'
1013 92da0e5a Antony Chazapis
        permissions_path = self._get_permissions_path(account, container, name)
1014 067cf1fc Antony Chazapis
        if user != account:
1015 29148653 Sofia Papagiannaki
            if self.permissions.access_check(permissions_path, self.WRITE,
1016 29148653 Sofia Papagiannaki
                                             user):
1017 067cf1fc Antony Chazapis
                allowed = 'write'
1018 29148653 Sofia Papagiannaki
            elif self.permissions.access_check(permissions_path, self.READ,
1019 29148653 Sofia Papagiannaki
                                               user):
1020 067cf1fc Antony Chazapis
                allowed = 'read'
1021 067cf1fc Antony Chazapis
            else:
1022 067cf1fc Antony Chazapis
                raise NotAllowedError
1023 92da0e5a Antony Chazapis
        self._lookup_object(account, container, name)
1024 29148653 Sofia Papagiannaki
        return (allowed,
1025 29148653 Sofia Papagiannaki
                permissions_path,
1026 29148653 Sofia Papagiannaki
                self.permissions.access_get(permissions_path))
1027 2715ade4 Sofia Papagiannaki
1028 1f96b68d Sofia Papagiannaki
    @debug_method
1029 5d022141 Sofia Papagiannaki
    @backend_method
1030 29148653 Sofia Papagiannaki
    def update_object_permissions(self, user, account, container, name,
1031 29148653 Sofia Papagiannaki
                                  permissions):
1032 a9b3f29d Antony Chazapis
        """Update the permissions associated with the object."""
1033 2715ade4 Sofia Papagiannaki
1034 a9b3f29d Antony Chazapis
        if user != account:
1035 a9b3f29d Antony Chazapis
            raise NotAllowedError
1036 48bb9c89 Sofia Papagiannaki
        path = self._lookup_object(account, container, name,
1037 48bb9c89 Sofia Papagiannaki
                                   lock_container=True)[0]
1038 6f4bce7b Antony Chazapis
        self._check_permissions(path, permissions)
1039 6c9df07c Sofia Papagiannaki
        try:
1040 6c9df07c Sofia Papagiannaki
            self.permissions.access_set(path, permissions)
1041 6c9df07c Sofia Papagiannaki
        except:
1042 6c9df07c Sofia Papagiannaki
            raise ValueError
1043 6c9df07c Sofia Papagiannaki
        else:
1044 6c9df07c Sofia Papagiannaki
            self._report_sharing_change(user, account, path, {'members':
1045 6c9df07c Sofia Papagiannaki
                                        self.permissions.access_members(path)})
1046 2715ade4 Sofia Papagiannaki
1047 0d573e18 Sofia Papagiannaki
        # remove all the cached allowed paths
1048 0d573e18 Sofia Papagiannaki
        # filtering out only those affected could be more expensive
1049 0d573e18 Sofia Papagiannaki
        self._reset_allowed_paths()
1050 0d573e18 Sofia Papagiannaki
1051 1f96b68d Sofia Papagiannaki
    @debug_method
1052 5d022141 Sofia Papagiannaki
    @backend_method
1053 a9b3f29d Antony Chazapis
    def get_object_public(self, user, account, container, name):
1054 bb4eafc6 Antony Chazapis
        """Return the public id of the object if applicable."""
1055 2715ade4 Sofia Papagiannaki
1056 0d573e18 Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
1057 c915d3bf Antony Chazapis
        path = self._lookup_object(account, container, name)[0]
1058 bb4eafc6 Antony Chazapis
        p = self.permissions.public_get(path)
1059 bb4eafc6 Antony Chazapis
        return p
1060 2715ade4 Sofia Papagiannaki
1061 1f96b68d Sofia Papagiannaki
    @debug_method
1062 5d022141 Sofia Papagiannaki
    @backend_method
1063 a9b3f29d Antony Chazapis
    def update_object_public(self, user, account, container, name, public):
1064 a9b3f29d Antony Chazapis
        """Update the public status of the object."""
1065 2715ade4 Sofia Papagiannaki
1066 0d573e18 Sofia Papagiannaki
        self._can_write_object(user, account, container, name)
1067 48bb9c89 Sofia Papagiannaki
        path = self._lookup_object(account, container, name,
1068 48bb9c89 Sofia Papagiannaki
                                   lock_container=True)[0]
1069 0f9d752c Antony Chazapis
        if not public:
1070 0f9d752c Antony Chazapis
            self.permissions.public_unset(path)
1071 0f9d752c Antony Chazapis
        else:
1072 56f3c759 Sofia Papagiannaki
            self.permissions.public_set(
1073 adce84cd Sofia Papagiannaki
                path, self.public_url_security, self.public_url_alphabet)
1074 2715ade4 Sofia Papagiannaki
1075 1f96b68d Sofia Papagiannaki
    @debug_method
1076 5d022141 Sofia Papagiannaki
    @backend_method
1077 a9b3f29d Antony Chazapis
    def get_object_hashmap(self, user, account, container, name, version=None):
1078 a9b3f29d Antony Chazapis
        """Return the object's size and a list with partial hashes."""
1079 2715ade4 Sofia Papagiannaki
1080 0d573e18 Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
1081 c915d3bf Antony Chazapis
        path, node = self._lookup_object(account, container, name)
1082 c915d3bf Antony Chazapis
        props = self._get_version(node, version)
1083 adce84cd Sofia Papagiannaki
        if props[self.HASH] is None:
1084 adce84cd Sofia Papagiannaki
            return 0, ()
1085 3a5994a8 Sofia Papagiannaki
        hashmap = self.store.map_get(self._unhexlify_hash(props[self.HASH]))
1086 2c5363a0 Antony Chazapis
        return props[self.SIZE], [binascii.hexlify(x) for x in hashmap]
1087 2715ade4 Sofia Papagiannaki
1088 29148653 Sofia Papagiannaki
    def _update_object_hash(self, user, account, container, name, size, type,
1089 29148653 Sofia Papagiannaki
                            hash, checksum, domain, meta, replace_meta,
1090 29148653 Sofia Papagiannaki
                            permissions, src_node=None, src_version_id=None,
1091 9e3a38bb Sofia Papagiannaki
                            is_copy=False, report_size_change=True):
1092 b9064632 Antony Chazapis
        if permissions is not None and user != account:
1093 b9064632 Antony Chazapis
            raise NotAllowedError
1094 0d573e18 Sofia Papagiannaki
        self._can_write_object(user, account, container, name)
1095 b9064632 Antony Chazapis
        if permissions is not None:
1096 b9064632 Antony Chazapis
            path = '/'.join((account, container, name))
1097 b9064632 Antony Chazapis
            self._check_permissions(path, permissions)
1098 2715ade4 Sofia Papagiannaki
1099 b9064632 Antony Chazapis
        account_path, account_node = self._lookup_account(account, True)
1100 2715ade4 Sofia Papagiannaki
        container_path, container_node = self._lookup_container(
1101 2715ade4 Sofia Papagiannaki
            account, container)
1102 fed9c5c7 Sofia Papagiannaki
1103 2715ade4 Sofia Papagiannaki
        path, node = self._put_object_node(
1104 2715ade4 Sofia Papagiannaki
            container_path, container_node, name)
1105 0f510652 Sofia Papagiannaki
        pre_version_id, dest_version_id = self._put_version_duplicate(
1106 0f510652 Sofia Papagiannaki
            user, node, src_node=src_node, size=size, type=type, hash=hash,
1107 0f510652 Sofia Papagiannaki
            checksum=checksum, is_copy=is_copy,
1108 0f510652 Sofia Papagiannaki
            update_statistics_ancestors_depth=1)
1109 2715ade4 Sofia Papagiannaki
1110 f9ea264b Antony Chazapis
        # Handle meta.
1111 f9ea264b Antony Chazapis
        if src_version_id is None:
1112 f9ea264b Antony Chazapis
            src_version_id = pre_version_id
1113 2715ade4 Sofia Papagiannaki
        self._put_metadata_duplicate(
1114 ad9ada51 Sofia Papagiannaki
            src_version_id, dest_version_id, domain, node, meta, replace_meta)
1115 2715ade4 Sofia Papagiannaki
1116 0f510652 Sofia Papagiannaki
        del_size = self._apply_versioning(account, container, pre_version_id,
1117 0f510652 Sofia Papagiannaki
                                          update_statistics_ancestors_depth=1)
1118 813e42e5 Antony Chazapis
        size_delta = size - del_size
1119 fed9c5c7 Sofia Papagiannaki
        if size_delta > 0:
1120 fed9c5c7 Sofia Papagiannaki
            # Check account quota.
1121 fed9c5c7 Sofia Papagiannaki
            if not self.using_external_quotaholder:
1122 29148653 Sofia Papagiannaki
                account_quota = long(self._get_policy(
1123 29148653 Sofia Papagiannaki
                    account_node, is_account_policy=True)['quota'])
1124 29148653 Sofia Papagiannaki
                account_usage = self._get_statistics(account_node,
1125 29148653 Sofia Papagiannaki
                                                     compute=True)[1]
1126 d3655326 Sofia Papagiannaki
                if (account_quota > 0 and account_usage > account_quota):
1127 fed9c5c7 Sofia Papagiannaki
                    raise QuotaError(
1128 fed9c5c7 Sofia Papagiannaki
                        'Account quota exceeded: limit: %s, usage: %s' % (
1129 29148653 Sofia Papagiannaki
                            account_quota, account_usage))
1130 fed9c5c7 Sofia Papagiannaki
1131 fed9c5c7 Sofia Papagiannaki
            # Check container quota.
1132 29148653 Sofia Papagiannaki
            container_quota = long(self._get_policy(
1133 29148653 Sofia Papagiannaki
                container_node, is_account_policy=False)['quota'])
1134 fed9c5c7 Sofia Papagiannaki
            container_usage = self._get_statistics(container_node)[1]
1135 fed9c5c7 Sofia Papagiannaki
            if (container_quota > 0 and container_usage > container_quota):
1136 fed9c5c7 Sofia Papagiannaki
                # This must be executed in a transaction, so the version is
1137 fed9c5c7 Sofia Papagiannaki
                # never created if it fails.
1138 fed9c5c7 Sofia Papagiannaki
                raise QuotaError(
1139 fed9c5c7 Sofia Papagiannaki
                    'Container quota exceeded: limit: %s, usage: %s' % (
1140 fed9c5c7 Sofia Papagiannaki
                        container_quota, container_usage
1141 fed9c5c7 Sofia Papagiannaki
                    )
1142 fed9c5c7 Sofia Papagiannaki
                )
1143 e20a751d Sofia Papagiannaki
1144 9e3a38bb Sofia Papagiannaki
        if report_size_change:
1145 9e3a38bb Sofia Papagiannaki
            self._report_size_change(
1146 9e3a38bb Sofia Papagiannaki
                user, account, size_delta,
1147 9e3a38bb Sofia Papagiannaki
                {'action': 'object update', 'path': path,
1148 9e3a38bb Sofia Papagiannaki
                 'versions': ','.join([str(dest_version_id)])})
1149 b9064632 Antony Chazapis
        if permissions is not None:
1150 b9064632 Antony Chazapis
            self.permissions.access_set(path, permissions)
1151 29148653 Sofia Papagiannaki
            self._report_sharing_change(
1152 29148653 Sofia Papagiannaki
                user, account, path,
1153 29148653 Sofia Papagiannaki
                {'members': self.permissions.access_members(path)})
1154 2715ade4 Sofia Papagiannaki
1155 29148653 Sofia Papagiannaki
        self._report_object_change(
1156 29148653 Sofia Papagiannaki
            user, account, path,
1157 29148653 Sofia Papagiannaki
            details={'version': dest_version_id, 'action': 'object update'})
1158 f9ea264b Antony Chazapis
        return dest_version_id
1159 2715ade4 Sofia Papagiannaki
1160 1f96b68d Sofia Papagiannaki
    @debug_method
1161 29148653 Sofia Papagiannaki
    def update_object_hashmap(self, user, account, container, name, size, type,
1162 29148653 Sofia Papagiannaki
                              hashmap, checksum, domain, meta=None,
1163 29148653 Sofia Papagiannaki
                              replace_meta=False, permissions=None):
1164 29148653 Sofia Papagiannaki
        """Create/update an object's hashmap and return the new version."""
1165 2715ade4 Sofia Papagiannaki
1166 78348987 Sofia Papagiannaki
        meta = meta or {}
1167 2715ade4 Sofia Papagiannaki
        if size == 0:  # No such thing as an empty hashmap.
1168 6d64339e Antony Chazapis
            hashmap = [self.put_block('')]
1169 1c2fc0ff Antony Chazapis
        map = HashMap(self.block_size, self.hash_algorithm)
1170 3a5994a8 Sofia Papagiannaki
        map.extend([self._unhexlify_hash(x) for x in hashmap])
1171 7ca7bb08 Antony Chazapis
        missing = self.store.block_search(map)
1172 a9b3f29d Antony Chazapis
        if missing:
1173 a9b3f29d Antony Chazapis
            ie = IndexError()
1174 dd71f493 Antony Chazapis
            ie.data = [binascii.hexlify(x) for x in missing]
1175 a9b3f29d Antony Chazapis
            raise ie
1176 2715ade4 Sofia Papagiannaki
1177 1c2fc0ff Antony Chazapis
        hash = map.hash()
1178 133e3fcf Sofia Papagiannaki
        hexlified = binascii.hexlify(hash)
1179 683d4324 Sofia Papagiannaki
        # _update_object_hash() locks destination path
1180 29148653 Sofia Papagiannaki
        dest_version_id = self._update_object_hash(
1181 29148653 Sofia Papagiannaki
            user, account, container, name, size, type, hexlified, checksum,
1182 29148653 Sofia Papagiannaki
            domain, meta, replace_meta, permissions)
1183 7ca7bb08 Antony Chazapis
        self.store.map_put(hash, map)
1184 133e3fcf Sofia Papagiannaki
        return dest_version_id, hexlified
1185 2715ade4 Sofia Papagiannaki
1186 1f96b68d Sofia Papagiannaki
    @debug_method
1187 5d022141 Sofia Papagiannaki
    @backend_method
1188 29148653 Sofia Papagiannaki
    def update_object_checksum(self, user, account, container, name, version,
1189 29148653 Sofia Papagiannaki
                               checksum):
1190 33b4e4a6 Antony Chazapis
        """Update an object's checksum."""
1191 2715ade4 Sofia Papagiannaki
1192 29148653 Sofia Papagiannaki
        # Update objects with greater version and same hashmap
1193 29148653 Sofia Papagiannaki
        # and size (fix metadata updates).
1194 0d573e18 Sofia Papagiannaki
        self._can_write_object(user, account, container, name)
1195 48bb9c89 Sofia Papagiannaki
        path, node = self._lookup_object(account, container, name,
1196 48bb9c89 Sofia Papagiannaki
                                         lock_container=True)
1197 33b4e4a6 Antony Chazapis
        props = self._get_version(node, version)
1198 33b4e4a6 Antony Chazapis
        versions = self.node.node_get_versions(node)
1199 33b4e4a6 Antony Chazapis
        for x in versions:
1200 29148653 Sofia Papagiannaki
            if (x[self.SERIAL] >= int(version) and
1201 29148653 Sofia Papagiannaki
                x[self.HASH] == props[self.HASH] and
1202 29148653 Sofia Papagiannaki
                    x[self.SIZE] == props[self.SIZE]):
1203 2715ade4 Sofia Papagiannaki
                self.node.version_put_property(
1204 2715ade4 Sofia Papagiannaki
                    x[self.SERIAL], 'checksum', checksum)
1205 2715ade4 Sofia Papagiannaki
1206 29148653 Sofia Papagiannaki
    def _copy_object(self, user, src_account, src_container, src_name,
1207 29148653 Sofia Papagiannaki
                     dest_account, dest_container, dest_name, type,
1208 29148653 Sofia Papagiannaki
                     dest_domain=None, dest_meta=None, replace_meta=False,
1209 29148653 Sofia Papagiannaki
                     permissions=None, src_version=None, is_move=False,
1210 29148653 Sofia Papagiannaki
                     delimiter=None):
1211 9e3a38bb Sofia Papagiannaki
1212 9e3a38bb Sofia Papagiannaki
        report_size_change = not is_move
1213 78348987 Sofia Papagiannaki
        dest_meta = dest_meta or {}
1214 4d15c94e Sofia Papagiannaki
        dest_version_ids = []
1215 0d573e18 Sofia Papagiannaki
        self._can_read_object(user, src_account, src_container, src_name)
1216 a06c276e Sofia Papagiannaki
1217 a06c276e Sofia Papagiannaki
        src_container_path = '/'.join((src_account, src_container))
1218 a06c276e Sofia Papagiannaki
        dest_container_path = '/'.join((dest_account, dest_container))
1219 a06c276e Sofia Papagiannaki
        # Lock container paths in alphabetical order
1220 a06c276e Sofia Papagiannaki
        if src_container_path < dest_container_path:
1221 a06c276e Sofia Papagiannaki
            self._lookup_container(src_account, src_container)
1222 a06c276e Sofia Papagiannaki
            self._lookup_container(dest_account, dest_container)
1223 a06c276e Sofia Papagiannaki
        else:
1224 a06c276e Sofia Papagiannaki
            self._lookup_container(dest_account, dest_container)
1225 a06c276e Sofia Papagiannaki
            self._lookup_container(src_account, src_container)
1226 a06c276e Sofia Papagiannaki
1227 a06c276e Sofia Papagiannaki
        path, node = self._lookup_object(src_account, src_container, src_name)
1228 1730b3bf chazapis
        # TODO: Will do another fetch of the properties in duplicate version...
1229 2715ade4 Sofia Papagiannaki
        props = self._get_version(
1230 2715ade4 Sofia Papagiannaki
            node, src_version)  # Check to see if source exists.
1231 b9064632 Antony Chazapis
        src_version_id = props[self.SERIAL]
1232 b9064632 Antony Chazapis
        hash = props[self.HASH]
1233 b9064632 Antony Chazapis
        size = props[self.SIZE]
1234 2715ade4 Sofia Papagiannaki
        is_copy = not is_move and (src_account, src_container, src_name) != (
1235 2715ade4 Sofia Papagiannaki
            dest_account, dest_container, dest_name)  # New uuid.
1236 29148653 Sofia Papagiannaki
        dest_version_ids.append(self._update_object_hash(
1237 29148653 Sofia Papagiannaki
            user, dest_account, dest_container, dest_name, size, type, hash,
1238 29148653 Sofia Papagiannaki
            None, dest_domain, dest_meta, replace_meta, permissions,
1239 9e3a38bb Sofia Papagiannaki
            src_node=node, src_version_id=src_version_id, is_copy=is_copy,
1240 9e3a38bb Sofia Papagiannaki
            report_size_change=report_size_change))
1241 29148653 Sofia Papagiannaki
        if is_move and ((src_account, src_container, src_name) !=
1242 29148653 Sofia Papagiannaki
                        (dest_account, dest_container, dest_name)):
1243 9e3a38bb Sofia Papagiannaki
            self._delete_object(user, src_account, src_container, src_name,
1244 9e3a38bb Sofia Papagiannaki
                                report_size_change=report_size_change)
1245 2715ade4 Sofia Papagiannaki
1246 4d15c94e Sofia Papagiannaki
        if delimiter:
1247 29148653 Sofia Papagiannaki
            prefix = (src_name + delimiter if not
1248 29148653 Sofia Papagiannaki
                      src_name.endswith(delimiter) else src_name)
1249 29148653 Sofia Papagiannaki
            src_names = self._list_objects_no_limit(
1250 29148653 Sofia Papagiannaki
                user, src_account, src_container, prefix, delimiter=None,
1251 29148653 Sofia Papagiannaki
                virtual=False, domain=None, keys=[], shared=False, until=None,
1252 29148653 Sofia Papagiannaki
                size_range=None, all_props=True, public=False)
1253 2715ade4 Sofia Papagiannaki
            src_names.sort(key=lambda x: x[2])  # order by nodes
1254 4d15c94e Sofia Papagiannaki
            paths = [elem[0] for elem in src_names]
1255 4d15c94e Sofia Papagiannaki
            nodes = [elem[2] for elem in src_names]
1256 29148653 Sofia Papagiannaki
            # TODO: Will do another fetch of the properties
1257 29148653 Sofia Papagiannaki
            # in duplicate version...
1258 2715ade4 Sofia Papagiannaki
            props = self._get_versions(nodes)  # Check to see if source exists.
1259 2715ade4 Sofia Papagiannaki
1260 4d15c94e Sofia Papagiannaki
            for prop, path, node in zip(props, paths, nodes):
1261 4d15c94e Sofia Papagiannaki
                src_version_id = prop[self.SERIAL]
1262 4d15c94e Sofia Papagiannaki
                hash = prop[self.HASH]
1263 4d15c94e Sofia Papagiannaki
                vtype = prop[self.TYPE]
1264 07867f70 Sofia Papagiannaki
                size = prop[self.SIZE]
1265 2715ade4 Sofia Papagiannaki
                dest_prefix = dest_name + delimiter if not dest_name.endswith(
1266 2715ade4 Sofia Papagiannaki
                    delimiter) else dest_name
1267 4d15c94e Sofia Papagiannaki
                vdest_name = path.replace(prefix, dest_prefix, 1)
1268 683d4324 Sofia Papagiannaki
                # _update_object_hash() locks destination path
1269 29148653 Sofia Papagiannaki
                dest_version_ids.append(self._update_object_hash(
1270 29148653 Sofia Papagiannaki
                    user, dest_account, dest_container, vdest_name, size,
1271 29148653 Sofia Papagiannaki
                    vtype, hash, None, dest_domain, meta={},
1272 29148653 Sofia Papagiannaki
                    replace_meta=False, permissions=None, src_node=node,
1273 277faddf Sofia Papagiannaki
                    src_version_id=src_version_id, is_copy=is_copy,
1274 277faddf Sofia Papagiannaki
                    report_size_change=report_size_change))
1275 29148653 Sofia Papagiannaki
                if is_move and ((src_account, src_container, src_name) !=
1276 29148653 Sofia Papagiannaki
                                (dest_account, dest_container, dest_name)):
1277 277faddf Sofia Papagiannaki
                    self._delete_object(user, src_account, src_container, path,
1278 277faddf Sofia Papagiannaki
                                        report_size_change=report_size_change)
1279 29148653 Sofia Papagiannaki
        return (dest_version_ids[0] if len(dest_version_ids) == 1 else
1280 29148653 Sofia Papagiannaki
                dest_version_ids)
1281 2715ade4 Sofia Papagiannaki
1282 1f96b68d Sofia Papagiannaki
    @debug_method
1283 5d022141 Sofia Papagiannaki
    @backend_method
1284 29148653 Sofia Papagiannaki
    def copy_object(self, user, src_account, src_container, src_name,
1285 29148653 Sofia Papagiannaki
                    dest_account, dest_container, dest_name, type, domain,
1286 29148653 Sofia Papagiannaki
                    meta=None, replace_meta=False, permissions=None,
1287 29148653 Sofia Papagiannaki
                    src_version=None, delimiter=None):
1288 dff7b6f1 Sofia Papagiannaki
        """Copy an object's data and metadata."""
1289 2715ade4 Sofia Papagiannaki
1290 78348987 Sofia Papagiannaki
        meta = meta or {}
1291 29148653 Sofia Papagiannaki
        dest_version_id = self._copy_object(
1292 29148653 Sofia Papagiannaki
            user, src_account, src_container, src_name, dest_account,
1293 29148653 Sofia Papagiannaki
            dest_container, dest_name, type, domain, meta, replace_meta,
1294 29148653 Sofia Papagiannaki
            permissions, src_version, False, delimiter)
1295 46286f5f Antony Chazapis
        return dest_version_id
1296 2715ade4 Sofia Papagiannaki
1297 1f96b68d Sofia Papagiannaki
    @debug_method
1298 5d022141 Sofia Papagiannaki
    @backend_method
1299 29148653 Sofia Papagiannaki
    def move_object(self, user, src_account, src_container, src_name,
1300 29148653 Sofia Papagiannaki
                    dest_account, dest_container, dest_name, type, domain,
1301 29148653 Sofia Papagiannaki
                    meta=None, replace_meta=False, permissions=None,
1302 29148653 Sofia Papagiannaki
                    delimiter=None):
1303 a9b3f29d Antony Chazapis
        """Move an object's data and metadata."""
1304 2715ade4 Sofia Papagiannaki
1305 78348987 Sofia Papagiannaki
        meta = meta or {}
1306 79bb41b7 Antony Chazapis
        if user != src_account:
1307 79bb41b7 Antony Chazapis
            raise NotAllowedError
1308 9e3a38bb Sofia Papagiannaki
        dest_version_id = self._move_object(
1309 29148653 Sofia Papagiannaki
            user, src_account, src_container, src_name, dest_account,
1310 29148653 Sofia Papagiannaki
            dest_container, dest_name, type, domain, meta, replace_meta,
1311 9e3a38bb Sofia Papagiannaki
            permissions, None, delimiter=delimiter)
1312 02c4d2ba Antony Chazapis
        return dest_version_id
1313 2715ade4 Sofia Papagiannaki
1314 29148653 Sofia Papagiannaki
    def _delete_object(self, user, account, container, name, until=None,
1315 9e3a38bb Sofia Papagiannaki
                       delimiter=None, report_size_change=True):
1316 a9b3f29d Antony Chazapis
        if user != account:
1317 a9b3f29d Antony Chazapis
            raise NotAllowedError
1318 2715ade4 Sofia Papagiannaki
1319 48bb9c89 Sofia Papagiannaki
        # lookup object and lock container path also
1320 48bb9c89 Sofia Papagiannaki
        path, node = self._lookup_object(account, container, name,
1321 48bb9c89 Sofia Papagiannaki
                                         lock_container=True)
1322 48bb9c89 Sofia Papagiannaki
1323 a9b3f29d Antony Chazapis
        if until is not None:
1324 c915d3bf Antony Chazapis
            if node is None:
1325 c915d3bf Antony Chazapis
                return
1326 813e42e5 Antony Chazapis
            hashes = []
1327 813e42e5 Antony Chazapis
            size = 0
1328 388ea25f Sofia Papagiannaki
            serials = []
1329 0f510652 Sofia Papagiannaki
            h, s, v = self.node.node_purge(node, until, CLUSTER_NORMAL,
1330 0f510652 Sofia Papagiannaki
                                           update_statistics_ancestors_depth=1)
1331 813e42e5 Antony Chazapis
            hashes += h
1332 813e42e5 Antony Chazapis
            size += s
1333 388ea25f Sofia Papagiannaki
            serials += v
1334 0f510652 Sofia Papagiannaki
            h, s, v = self.node.node_purge(node, until, CLUSTER_HISTORY,
1335 0f510652 Sofia Papagiannaki
                                           update_statistics_ancestors_depth=1)
1336 813e42e5 Antony Chazapis
            hashes += h
1337 0a92ff85 Sofia Papagiannaki
            if not self.free_versioning:
1338 0a92ff85 Sofia Papagiannaki
                size += s
1339 388ea25f Sofia Papagiannaki
            serials += v
1340 04230536 Antony Chazapis
            for h in hashes:
1341 04230536 Antony Chazapis
                self.store.map_delete(h)
1342 0f510652 Sofia Papagiannaki
            self.node.node_purge(node, until, CLUSTER_DELETED,
1343 0f510652 Sofia Papagiannaki
                                 update_statistics_ancestors_depth=1)
1344 a9b3f29d Antony Chazapis
            try:
1345 29148653 Sofia Papagiannaki
                self._get_version(node)
1346 a9b3f29d Antony Chazapis
            except NameError:
1347 0f9d752c Antony Chazapis
                self.permissions.access_clear(path)
1348 0a92ff85 Sofia Papagiannaki
            self._report_size_change(
1349 0a92ff85 Sofia Papagiannaki
                user, account, -size, {
1350 0a92ff85 Sofia Papagiannaki
                    'action': 'object purge',
1351 0a92ff85 Sofia Papagiannaki
                    'path': path,
1352 0a92ff85 Sofia Papagiannaki
                    'versions': ','.join(str(i) for i in serials)
1353 0a92ff85 Sofia Papagiannaki
                }
1354 0a92ff85 Sofia Papagiannaki
            )
1355 a9b3f29d Antony Chazapis
            return
1356 2715ade4 Sofia Papagiannaki
1357 33af031c Sofia Papagiannaki
        if not self._exists(node):
1358 33af031c Sofia Papagiannaki
            raise ItemNotExists('Object is deleted.')
1359 ed2064f8 Christos Stavrakakis
1360 0f510652 Sofia Papagiannaki
        src_version_id, dest_version_id = self._put_version_duplicate(
1361 0f510652 Sofia Papagiannaki
            user, node, size=0, type='', hash=None, checksum='',
1362 0f510652 Sofia Papagiannaki
            cluster=CLUSTER_DELETED, update_statistics_ancestors_depth=1)
1363 0f510652 Sofia Papagiannaki
        del_size = self._apply_versioning(account, container, src_version_id,
1364 0f510652 Sofia Papagiannaki
                                          update_statistics_ancestors_depth=1)
1365 9e3a38bb Sofia Papagiannaki
        if report_size_change:
1366 9e3a38bb Sofia Papagiannaki
            self._report_size_change(
1367 9e3a38bb Sofia Papagiannaki
                user, account, -del_size,
1368 9e3a38bb Sofia Papagiannaki
                {'action': 'object delete',
1369 9e3a38bb Sofia Papagiannaki
                 'path': path,
1370 9e3a38bb Sofia Papagiannaki
                 'versions': ','.join([str(dest_version_id)])})
1371 2715ade4 Sofia Papagiannaki
        self._report_object_change(
1372 2715ade4 Sofia Papagiannaki
            user, account, path, details={'action': 'object delete'})
1373 0f9d752c Antony Chazapis
        self.permissions.access_clear(path)
1374 2715ade4 Sofia Papagiannaki
1375 4d15c94e Sofia Papagiannaki
        if delimiter:
1376 4d15c94e Sofia Papagiannaki
            prefix = name + delimiter if not name.endswith(delimiter) else name
1377 29148653 Sofia Papagiannaki
            src_names = self._list_objects_no_limit(
1378 29148653 Sofia Papagiannaki
                user, account, container, prefix, delimiter=None,
1379 29148653 Sofia Papagiannaki
                virtual=False, domain=None, keys=[], shared=False, until=None,
1380 29148653 Sofia Papagiannaki
                size_range=None, all_props=True, public=False)
1381 4d15c94e Sofia Papagiannaki
            paths = []
1382 4d15c94e Sofia Papagiannaki
            for t in src_names:
1383 2715ade4 Sofia Papagiannaki
                path = '/'.join((account, container, t[0]))
1384 2715ade4 Sofia Papagiannaki
                node = t[2]
1385 33af031c Sofia Papagiannaki
                if not self._exists(node):
1386 33af031c Sofia Papagiannaki
                    continue
1387 0f510652 Sofia Papagiannaki
                src_version_id, dest_version_id = self._put_version_duplicate(
1388 0f510652 Sofia Papagiannaki
                    user, node, size=0, type='', hash=None, checksum='',
1389 0f510652 Sofia Papagiannaki
                    cluster=CLUSTER_DELETED,
1390 0f510652 Sofia Papagiannaki
                    update_statistics_ancestors_depth=1)
1391 2715ade4 Sofia Papagiannaki
                del_size = self._apply_versioning(
1392 0f510652 Sofia Papagiannaki
                    account, container, src_version_id,
1393 0f510652 Sofia Papagiannaki
                    update_statistics_ancestors_depth=1)
1394 9e3a38bb Sofia Papagiannaki
                if report_size_change:
1395 9e3a38bb Sofia Papagiannaki
                    self._report_size_change(
1396 9e3a38bb Sofia Papagiannaki
                        user, account, -del_size,
1397 9e3a38bb Sofia Papagiannaki
                        {'action': 'object delete',
1398 9e3a38bb Sofia Papagiannaki
                         'path': path,
1399 9e3a38bb Sofia Papagiannaki
                         'versions': ','.join([str(dest_version_id)])})
1400 2715ade4 Sofia Papagiannaki
                self._report_object_change(
1401 2715ade4 Sofia Papagiannaki
                    user, account, path, details={'action': 'object delete'})
1402 4d15c94e Sofia Papagiannaki
                paths.append(path)
1403 4d15c94e Sofia Papagiannaki
            self.permissions.access_clear_bulk(paths)
1404 2715ade4 Sofia Papagiannaki
1405 0d573e18 Sofia Papagiannaki
        # remove all the cached allowed paths
1406 0d573e18 Sofia Papagiannaki
        # removing the specific path could be more expensive
1407 0d573e18 Sofia Papagiannaki
        self._reset_allowed_paths()
1408 0d573e18 Sofia Papagiannaki
1409 1f96b68d Sofia Papagiannaki
    @debug_method
1410 5d022141 Sofia Papagiannaki
    @backend_method
1411 29148653 Sofia Papagiannaki
    def delete_object(self, user, account, container, name, until=None,
1412 29148653 Sofia Papagiannaki
                      prefix='', delimiter=None):
1413 dff7b6f1 Sofia Papagiannaki
        """Delete/purge an object."""
1414 2715ade4 Sofia Papagiannaki
1415 4d15c94e Sofia Papagiannaki
        self._delete_object(user, account, container, name, until, delimiter)
1416 2715ade4 Sofia Papagiannaki
1417 1f96b68d Sofia Papagiannaki
    @debug_method
1418 5d022141 Sofia Papagiannaki
    @backend_method
1419 62f915a1 Antony Chazapis
    def list_versions(self, user, account, container, name):
1420 29148653 Sofia Papagiannaki
        """Return a list of all object (version, version_timestamp) tuples."""
1421 2715ade4 Sofia Papagiannaki
1422 0d573e18 Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
1423 60b8a083 Antony Chazapis
        path, node = self._lookup_object(account, container, name)
1424 97d45f69 Antony Chazapis
        versions = self.node.node_get_versions(node)
1425 29148653 Sofia Papagiannaki
        return [[x[self.SERIAL], x[self.MTIME]] for x in versions if
1426 29148653 Sofia Papagiannaki
                x[self.CLUSTER] != CLUSTER_DELETED]
1427 2715ade4 Sofia Papagiannaki
1428 1f96b68d Sofia Papagiannaki
    @debug_method
1429 5d022141 Sofia Papagiannaki
    @backend_method
1430 91fc9266 Sofia Papagiannaki
    def get_uuid(self, user, uuid, check_permissions=True):
1431 37bee317 Antony Chazapis
        """Return the (account, container, name) for the UUID given."""
1432 2715ade4 Sofia Papagiannaki
1433 2bbf1544 Georgios D. Tsoukalas
        info = self.node.latest_uuid(uuid, CLUSTER_NORMAL)
1434 37bee317 Antony Chazapis
        if info is None:
1435 37bee317 Antony Chazapis
            raise NameError
1436 37bee317 Antony Chazapis
        path, serial = info
1437 37bee317 Antony Chazapis
        account, container, name = path.split('/', 2)
1438 91fc9266 Sofia Papagiannaki
        if check_permissions:
1439 0d573e18 Sofia Papagiannaki
            self._can_read_object(user, account, container, name)
1440 37bee317 Antony Chazapis
        return (account, container, name)
1441 2715ade4 Sofia Papagiannaki
1442 1f96b68d Sofia Papagiannaki
    @debug_method
1443 5d022141 Sofia Papagiannaki
    @backend_method
1444 bb4eafc6 Antony Chazapis
    def get_public(self, user, public):
1445 bb4eafc6 Antony Chazapis
        """Return the (account, container, name) for the public id given."""
1446 2715ade4 Sofia Papagiannaki
1447 56f3c759 Sofia Papagiannaki
        path = self.permissions.public_path(public)
1448 37bee317 Antony Chazapis
        if path is None:
1449 37bee317 Antony Chazapis
            raise NameError
1450 bb4eafc6 Antony Chazapis
        account, container, name = path.split('/', 2)
1451 0d573e18 Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
1452 bb4eafc6 Antony Chazapis
        return (account, container, name)
1453 2715ade4 Sofia Papagiannaki
1454 a9b3f29d Antony Chazapis
    def get_block(self, hash):
1455 a9b3f29d Antony Chazapis
        """Return a block's data."""
1456 2715ade4 Sofia Papagiannaki
1457 b1aca3e6 Sofia Papagiannaki
        logger.debug("get_block: %s", hash)
1458 3a5994a8 Sofia Papagiannaki
        block = self.store.block_get(self._unhexlify_hash(hash))
1459 7ca7bb08 Antony Chazapis
        if not block:
1460 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Block does not exist')
1461 7ca7bb08 Antony Chazapis
        return block
1462 2715ade4 Sofia Papagiannaki
1463 a9b3f29d Antony Chazapis
    def put_block(self, data):
1464 60b8a083 Antony Chazapis
        """Store a block and return the hash."""
1465 2715ade4 Sofia Papagiannaki
1466 a9b3f29d Antony Chazapis
        logger.debug("put_block: %s", len(data))
1467 7ca7bb08 Antony Chazapis
        return binascii.hexlify(self.store.block_put(data))
1468 2715ade4 Sofia Papagiannaki
1469 a9b3f29d Antony Chazapis
    def update_block(self, hash, data, offset=0):
1470 a9b3f29d Antony Chazapis
        """Update a known block and return the hash."""
1471 2715ade4 Sofia Papagiannaki
1472 a9b3f29d Antony Chazapis
        logger.debug("update_block: %s %s %s", hash, len(data), offset)
1473 a9b3f29d Antony Chazapis
        if offset == 0 and len(data) == self.block_size:
1474 a9b3f29d Antony Chazapis
            return self.put_block(data)
1475 3a5994a8 Sofia Papagiannaki
        h = self.store.block_update(self._unhexlify_hash(hash), offset, data)
1476 a9b3f29d Antony Chazapis
        return binascii.hexlify(h)
1477 2715ade4 Sofia Papagiannaki
1478 44ad5860 Antony Chazapis
    # Path functions.
1479 2715ade4 Sofia Papagiannaki
1480 37bee317 Antony Chazapis
    def _generate_uuid(self):
1481 37bee317 Antony Chazapis
        return str(uuidlib.uuid4())
1482 2715ade4 Sofia Papagiannaki
1483 b9064632 Antony Chazapis
    def _put_object_node(self, path, parent, name):
1484 c915d3bf Antony Chazapis
        path = '/'.join((path, name))
1485 c915d3bf Antony Chazapis
        node = self.node.node_lookup(path)
1486 c915d3bf Antony Chazapis
        if node is None:
1487 2e8edd42 Sofia Papagiannaki
            node = self.node.node_create(parent, path)
1488 c915d3bf Antony Chazapis
        return path, node
1489 2715ade4 Sofia Papagiannaki
1490 0f510652 Sofia Papagiannaki
    def _put_path(self, user, parent, path,
1491 0f510652 Sofia Papagiannaki
                  update_statistics_ancestors_depth=None):
1492 62f915a1 Antony Chazapis
        node = self.node.node_create(parent, path)
1493 2715ade4 Sofia Papagiannaki
        self.node.version_create(node, None, 0, '', None, user,
1494 0f510652 Sofia Papagiannaki
                                 self._generate_uuid(), '', CLUSTER_NORMAL,
1495 0f510652 Sofia Papagiannaki
                                 update_statistics_ancestors_depth)
1496 62f915a1 Antony Chazapis
        return node
1497 2715ade4 Sofia Papagiannaki
1498 44ad5860 Antony Chazapis
    def _lookup_account(self, account, create=True):
1499 af395b9c Sofia Papagiannaki
        node = self.node.node_lookup(account)
1500 44ad5860 Antony Chazapis
        if node is None and create:
1501 2715ade4 Sofia Papagiannaki
            node = self._put_path(
1502 0f510652 Sofia Papagiannaki
                account, self.ROOTNODE, account,
1503 0f510652 Sofia Papagiannaki
                update_statistics_ancestors_depth=-1)  # User is account.
1504 c915d3bf Antony Chazapis
        return account, node
1505 2715ade4 Sofia Papagiannaki
1506 44ad5860 Antony Chazapis
    def _lookup_container(self, account, container):
1507 b90584d0 Sofia Papagiannaki
        for_update = True if self.lock_container_path else False
1508 c915d3bf Antony Chazapis
        path = '/'.join((account, container))
1509 b90584d0 Sofia Papagiannaki
        node = self.node.node_lookup(path, for_update)
1510 44ad5860 Antony Chazapis
        if node is None:
1511 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Container does not exist')
1512 c915d3bf Antony Chazapis
        return path, node
1513 2715ade4 Sofia Papagiannaki
1514 48bb9c89 Sofia Papagiannaki
    def _lookup_object(self, account, container, name, lock_container=False):
1515 48bb9c89 Sofia Papagiannaki
        if lock_container:
1516 48bb9c89 Sofia Papagiannaki
            self._lookup_container(account, container)
1517 48bb9c89 Sofia Papagiannaki
1518 c915d3bf Antony Chazapis
        path = '/'.join((account, container, name))
1519 c915d3bf Antony Chazapis
        node = self.node.node_lookup(path)
1520 44ad5860 Antony Chazapis
        if node is None:
1521 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Object does not exist')
1522 c915d3bf Antony Chazapis
        return path, node
1523 2715ade4 Sofia Papagiannaki
1524 cf4a7a7b Sofia Papagiannaki
    def _lookup_objects(self, paths):
1525 7efc9f86 Sofia Papagiannaki
        nodes = self.node.node_lookup_bulk(paths)
1526 cf4a7a7b Sofia Papagiannaki
        return paths, nodes
1527 2715ade4 Sofia Papagiannaki
1528 44ad5860 Antony Chazapis
    def _get_properties(self, node, until=None):
1529 44ad5860 Antony Chazapis
        """Return properties until the timestamp given."""
1530 2715ade4 Sofia Papagiannaki
1531 44ad5860 Antony Chazapis
        before = until if until is not None else inf
1532 44ad5860 Antony Chazapis
        props = self.node.version_lookup(node, before, CLUSTER_NORMAL)
1533 44ad5860 Antony Chazapis
        if props is None and until is not None:
1534 44ad5860 Antony Chazapis
            props = self.node.version_lookup(node, before, CLUSTER_HISTORY)
1535 44ad5860 Antony Chazapis
        if props is None:
1536 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Path does not exist')
1537 44ad5860 Antony Chazapis
        return props
1538 2715ade4 Sofia Papagiannaki
1539 2e8edd42 Sofia Papagiannaki
    def _get_statistics(self, node, until=None, compute=False):
1540 29148653 Sofia Papagiannaki
        """Return (count, sum of size, timestamp) of everything under node."""
1541 2715ade4 Sofia Papagiannaki
1542 2e8edd42 Sofia Papagiannaki
        if until is not None:
1543 62f915a1 Antony Chazapis
            stats = self.node.statistics_latest(node, until, CLUSTER_DELETED)
1544 2e8edd42 Sofia Papagiannaki
        elif compute:
1545 29148653 Sofia Papagiannaki
            stats = self.node.statistics_latest(node,
1546 29148653 Sofia Papagiannaki
                                                except_cluster=CLUSTER_DELETED)
1547 2e8edd42 Sofia Papagiannaki
        else:
1548 2e8edd42 Sofia Papagiannaki
            stats = self.node.statistics_get(node, CLUSTER_NORMAL)
1549 62f915a1 Antony Chazapis
        if stats is None:
1550 62f915a1 Antony Chazapis
            stats = (0, 0, 0)
1551 62f915a1 Antony Chazapis
        return stats
1552 2715ade4 Sofia Papagiannaki
1553 44ad5860 Antony Chazapis
    def _get_version(self, node, version=None):
1554 44ad5860 Antony Chazapis
        if version is None:
1555 44ad5860 Antony Chazapis
            props = self.node.version_lookup(node, inf, CLUSTER_NORMAL)
1556 44ad5860 Antony Chazapis
            if props is None:
1557 7efc9f86 Sofia Papagiannaki
                raise ItemNotExists('Object does not exist')
1558 44ad5860 Antony Chazapis
        else:
1559 07afd277 Antony Chazapis
            try:
1560 07afd277 Antony Chazapis
                version = int(version)
1561 07afd277 Antony Chazapis
            except ValueError:
1562 7efc9f86 Sofia Papagiannaki
                raise VersionNotExists('Version does not exist')
1563 d2fc71c9 Sofia Papagiannaki
            props = self.node.version_get_properties(version, node=node)
1564 2c5363a0 Antony Chazapis
            if props is None or props[self.CLUSTER] == CLUSTER_DELETED:
1565 7efc9f86 Sofia Papagiannaki
                raise VersionNotExists('Version does not exist')
1566 44ad5860 Antony Chazapis
        return props
1567 4d15c94e Sofia Papagiannaki
1568 7efc9f86 Sofia Papagiannaki
    def _get_versions(self, nodes):
1569 7efc9f86 Sofia Papagiannaki
        return self.node.version_lookup_bulk(nodes, inf, CLUSTER_NORMAL)
1570 2715ade4 Sofia Papagiannaki
1571 0f510652 Sofia Papagiannaki
    def _put_version_duplicate(self, user, node, src_node=None, size=None,
1572 0f510652 Sofia Papagiannaki
                               type=None, hash=None, checksum=None,
1573 0f510652 Sofia Papagiannaki
                               cluster=CLUSTER_NORMAL, is_copy=False,
1574 0f510652 Sofia Papagiannaki
                               update_statistics_ancestors_depth=None):
1575 b9064632 Antony Chazapis
        """Create a new version of the node."""
1576 2715ade4 Sofia Papagiannaki
1577 2715ade4 Sofia Papagiannaki
        props = self.node.version_lookup(
1578 2715ade4 Sofia Papagiannaki
            node if src_node is None else src_node, inf, CLUSTER_NORMAL)
1579 b9064632 Antony Chazapis
        if props is not None:
1580 b9064632 Antony Chazapis
            src_version_id = props[self.SERIAL]
1581 b9064632 Antony Chazapis
            src_hash = props[self.HASH]
1582 b9064632 Antony Chazapis
            src_size = props[self.SIZE]
1583 66ce2ca5 Antony Chazapis
            src_type = props[self.TYPE]
1584 33b4e4a6 Antony Chazapis
            src_checksum = props[self.CHECKSUM]
1585 44ad5860 Antony Chazapis
        else:
1586 b9064632 Antony Chazapis
            src_version_id = None
1587 b9064632 Antony Chazapis
            src_hash = None
1588 b9064632 Antony Chazapis
            src_size = 0
1589 66ce2ca5 Antony Chazapis
            src_type = ''
1590 33b4e4a6 Antony Chazapis
            src_checksum = ''
1591 2715ade4 Sofia Papagiannaki
        if size is None:  # Set metadata.
1592 29148653 Sofia Papagiannaki
            hash = src_hash  # This way hash can be set to None
1593 29148653 Sofia Papagiannaki
                             # (account or container).
1594 b9064632 Antony Chazapis
            size = src_size
1595 66ce2ca5 Antony Chazapis
        if type is None:
1596 66ce2ca5 Antony Chazapis
            type = src_type
1597 33b4e4a6 Antony Chazapis
        if checksum is None:
1598 33b4e4a6 Antony Chazapis
            checksum = src_checksum
1599 2715ade4 Sofia Papagiannaki
        uuid = self._generate_uuid(
1600 2715ade4 Sofia Papagiannaki
        ) if (is_copy or src_version_id is None) else props[self.UUID]
1601 2715ade4 Sofia Papagiannaki
1602 1730b3bf chazapis
        if src_node is None:
1603 1730b3bf chazapis
            pre_version_id = src_version_id
1604 1730b3bf chazapis
        else:
1605 1730b3bf chazapis
            pre_version_id = None
1606 1730b3bf chazapis
            props = self.node.version_lookup(node, inf, CLUSTER_NORMAL)
1607 1730b3bf chazapis
            if props is not None:
1608 1730b3bf chazapis
                pre_version_id = props[self.SERIAL]
1609 1730b3bf chazapis
        if pre_version_id is not None:
1610 0f510652 Sofia Papagiannaki
            self.node.version_recluster(pre_version_id, CLUSTER_HISTORY,
1611 0f510652 Sofia Papagiannaki
                                        update_statistics_ancestors_depth)
1612 2715ade4 Sofia Papagiannaki
1613 0f510652 Sofia Papagiannaki
        dest_version_id, mtime = self.node.version_create(
1614 0f510652 Sofia Papagiannaki
            node, hash, size, type, src_version_id, user, uuid, checksum,
1615 0f510652 Sofia Papagiannaki
            cluster, update_statistics_ancestors_depth)
1616 ad9ada51 Sofia Papagiannaki
1617 ad9ada51 Sofia Papagiannaki
        self.node.attribute_unset_is_latest(node, dest_version_id)
1618 ad9ada51 Sofia Papagiannaki
1619 1730b3bf chazapis
        return pre_version_id, dest_version_id
1620 2715ade4 Sofia Papagiannaki
1621 ad9ada51 Sofia Papagiannaki
    def _put_metadata_duplicate(self, src_version_id, dest_version_id, domain,
1622 ad9ada51 Sofia Papagiannaki
                                node, meta, replace=False):
1623 4819d34f Antony Chazapis
        if src_version_id is not None:
1624 4819d34f Antony Chazapis
            self.node.attribute_copy(src_version_id, dest_version_id)
1625 4819d34f Antony Chazapis
        if not replace:
1626 2715ade4 Sofia Papagiannaki
            self.node.attribute_del(dest_version_id, domain, (
1627 2715ade4 Sofia Papagiannaki
                k for k, v in meta.iteritems() if v == ''))
1628 ad9ada51 Sofia Papagiannaki
            self.node.attribute_set(dest_version_id, domain, node, (
1629 2715ade4 Sofia Papagiannaki
                (k, v) for k, v in meta.iteritems() if v != ''))
1630 4819d34f Antony Chazapis
        else:
1631 4819d34f Antony Chazapis
            self.node.attribute_del(dest_version_id, domain)
1632 ad9ada51 Sofia Papagiannaki
            self.node.attribute_set(dest_version_id, domain, node, ((
1633 2715ade4 Sofia Papagiannaki
                k, v) for k, v in meta.iteritems()))
1634 2715ade4 Sofia Papagiannaki
1635 0f510652 Sofia Papagiannaki
    def _put_metadata(self, user, node, domain, meta, replace=False,
1636 0f510652 Sofia Papagiannaki
                      update_statistics_ancestors_depth=None):
1637 44ad5860 Antony Chazapis
        """Create a new version and store metadata."""
1638 2715ade4 Sofia Papagiannaki
1639 2715ade4 Sofia Papagiannaki
        src_version_id, dest_version_id = self._put_version_duplicate(
1640 0f510652 Sofia Papagiannaki
            user, node,
1641 29148653 Sofia Papagiannaki
            update_statistics_ancestors_depth=
1642 29148653 Sofia Papagiannaki
            update_statistics_ancestors_depth)
1643 2715ade4 Sofia Papagiannaki
        self._put_metadata_duplicate(
1644 ad9ada51 Sofia Papagiannaki
            src_version_id, dest_version_id, domain, node, meta, replace)
1645 5cc484e1 Antony Chazapis
        return src_version_id, dest_version_id
1646 2715ade4 Sofia Papagiannaki
1647 60b8a083 Antony Chazapis
    def _list_limits(self, listing, marker, limit):
1648 60b8a083 Antony Chazapis
        start = 0
1649 60b8a083 Antony Chazapis
        if marker:
1650 60b8a083 Antony Chazapis
            try:
1651 60b8a083 Antony Chazapis
                start = listing.index(marker) + 1
1652 60b8a083 Antony Chazapis
            except ValueError:
1653 60b8a083 Antony Chazapis
                pass
1654 60b8a083 Antony Chazapis
        if not limit or limit > 10000:
1655 60b8a083 Antony Chazapis
            limit = 10000
1656 60b8a083 Antony Chazapis
        return start, limit
1657 2715ade4 Sofia Papagiannaki
1658 29148653 Sofia Papagiannaki
    def _list_object_properties(self, parent, path, prefix='', delimiter=None,
1659 29148653 Sofia Papagiannaki
                                marker=None, limit=10000, virtual=True,
1660 29148653 Sofia Papagiannaki
                                domain=None, keys=None, until=None,
1661 29148653 Sofia Papagiannaki
                                size_range=None, allowed=None,
1662 29148653 Sofia Papagiannaki
                                all_props=False):
1663 78348987 Sofia Papagiannaki
        keys = keys or []
1664 78348987 Sofia Papagiannaki
        allowed = allowed or []
1665 60b8a083 Antony Chazapis
        cont_prefix = path + '/'
1666 60b8a083 Antony Chazapis
        prefix = cont_prefix + prefix
1667 60b8a083 Antony Chazapis
        start = cont_prefix + marker if marker else None
1668 60b8a083 Antony Chazapis
        before = until if until is not None else inf
1669 4819d34f Antony Chazapis
        filterq = keys if domain else []
1670 7ff57991 Antony Chazapis
        sizeq = size_range
1671 2715ade4 Sofia Papagiannaki
1672 29148653 Sofia Papagiannaki
        objects, prefixes = self.node.latest_version_list(
1673 29148653 Sofia Papagiannaki
            parent, prefix, delimiter, start, limit, before, CLUSTER_DELETED,
1674 29148653 Sofia Papagiannaki
            allowed, domain, filterq, sizeq, all_props)
1675 60b8a083 Antony Chazapis
        objects.extend([(p, None) for p in prefixes] if virtual else [])
1676 43be9afd Sofia Papagiannaki
        objects.sort(key=lambda x: x[0])
1677 371d907a Antony Chazapis
        objects = [(x[0][len(cont_prefix):],) + x[1:] for x in objects]
1678 cf4a7a7b Sofia Papagiannaki
        return objects
1679 2715ade4 Sofia Papagiannaki
1680 813e42e5 Antony Chazapis
    # Reporting functions.
1681 2715ade4 Sofia Papagiannaki
1682 1f96b68d Sofia Papagiannaki
    @debug_method
1683 5d022141 Sofia Papagiannaki
    @backend_method
1684 78348987 Sofia Papagiannaki
    def _report_size_change(self, user, account, size, details=None):
1685 78348987 Sofia Papagiannaki
        details = details or {}
1686 78348987 Sofia Papagiannaki
1687 8ed3f04c Sofia Papagiannaki
        if size == 0:
1688 8ed3f04c Sofia Papagiannaki
            return
1689 8ed3f04c Sofia Papagiannaki
1690 813e42e5 Antony Chazapis
        account_node = self._lookup_account(account, True)[1]
1691 2e8edd42 Sofia Papagiannaki
        total = self._get_statistics(account_node, compute=True)[1]
1692 813e42e5 Antony Chazapis
        details.update({'user': user, 'total': total})
1693 29148653 Sofia Papagiannaki
        self.messages.append(
1694 29148653 Sofia Papagiannaki
            (QUEUE_MESSAGE_KEY_PREFIX % ('resource.diskspace',),
1695 29148653 Sofia Papagiannaki
             account, QUEUE_INSTANCE_ID, 'diskspace', float(size), details))
1696 7ed99da8 root
1697 c846fad1 Sofia Papagiannaki
        if not self.using_external_quotaholder:
1698 73fbe301 Sofia Papagiannaki
            return
1699 7f1f0464 Georgios D. Tsoukalas
1700 ccfd4e44 Sofia Papagiannaki
        try:
1701 b17e5550 Giorgos Korfiatis
            name = details['path'] if 'path' in details else ''
1702 16f2673e Sofia Papagiannaki
            serial = self.astakosclient.issue_one_commission(
1703 b17e5550 Giorgos Korfiatis
                holder=account,
1704 b17e5550 Giorgos Korfiatis
                source=DEFAULT_SOURCE,
1705 b17e5550 Giorgos Korfiatis
                provisions={'pithos.diskspace': size},
1706 29148653 Sofia Papagiannaki
                name=name)
1707 ccfd4e44 Sofia Papagiannaki
        except BaseException, e:
1708 ccfd4e44 Sofia Papagiannaki
            raise QuotaError(e)
1709 ccfd4e44 Sofia Papagiannaki
        else:
1710 ccfd4e44 Sofia Papagiannaki
            self.serials.append(serial)
1711 0307b47f Georgios D. Tsoukalas
1712 1f96b68d Sofia Papagiannaki
    @debug_method
1713 5d022141 Sofia Papagiannaki
    @backend_method
1714 78348987 Sofia Papagiannaki
    def _report_object_change(self, user, account, path, details=None):
1715 78348987 Sofia Papagiannaki
        details = details or {}
1716 b82d3277 Sofia Papagiannaki
        details.update({'user': user})
1717 f4fbb0fa Sofia Papagiannaki
        self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('object',),
1718 29148653 Sofia Papagiannaki
                              account, QUEUE_INSTANCE_ID, 'object', path,
1719 29148653 Sofia Papagiannaki
                              details))
1720 2715ade4 Sofia Papagiannaki
1721 1f96b68d Sofia Papagiannaki
    @debug_method
1722 5d022141 Sofia Papagiannaki
    @backend_method
1723 78348987 Sofia Papagiannaki
    def _report_sharing_change(self, user, account, path, details=None):
1724 78348987 Sofia Papagiannaki
        details = details or {}
1725 a74ba506 Sofia Papagiannaki
        details.update({'user': user})
1726 f4fbb0fa Sofia Papagiannaki
        self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('sharing',),
1727 29148653 Sofia Papagiannaki
                              account, QUEUE_INSTANCE_ID, 'sharing', path,
1728 29148653 Sofia Papagiannaki
                              details))
1729 2715ade4 Sofia Papagiannaki
1730 60b8a083 Antony Chazapis
    # Policy functions.
1731 2715ade4 Sofia Papagiannaki
1732 19ddd41b Sofia Papagiannaki
    def _check_policy(self, policy, is_account_policy=True):
1733 19ddd41b Sofia Papagiannaki
        default_policy = self.default_account_policy \
1734 19ddd41b Sofia Papagiannaki
            if is_account_policy else self.default_container_policy
1735 60b8a083 Antony Chazapis
        for k in policy.keys():
1736 60b8a083 Antony Chazapis
            if policy[k] == '':
1737 19ddd41b Sofia Papagiannaki
                policy[k] = default_policy.get(k)
1738 60b8a083 Antony Chazapis
        for k, v in policy.iteritems():
1739 60b8a083 Antony Chazapis
            if k == 'quota':
1740 2715ade4 Sofia Papagiannaki
                q = int(v)  # May raise ValueError.
1741 60b8a083 Antony Chazapis
                if q < 0:
1742 60b8a083 Antony Chazapis
                    raise ValueError
1743 60b8a083 Antony Chazapis
            elif k == 'versioning':
1744 5cc484e1 Antony Chazapis
                if v not in ['auto', 'none']:
1745 60b8a083 Antony Chazapis
                    raise ValueError
1746 60b8a083 Antony Chazapis
            else:
1747 60b8a083 Antony Chazapis
                raise ValueError
1748 2715ade4 Sofia Papagiannaki
1749 19ddd41b Sofia Papagiannaki
    def _put_policy(self, node, policy, replace, is_account_policy=True):
1750 19ddd41b Sofia Papagiannaki
        default_policy = self.default_account_policy \
1751 19ddd41b Sofia Papagiannaki
            if is_account_policy else self.default_container_policy
1752 b2832c6a Antony Chazapis
        if replace:
1753 19ddd41b Sofia Papagiannaki
            for k, v in default_policy.iteritems():
1754 b2832c6a Antony Chazapis
                if k not in policy:
1755 b2832c6a Antony Chazapis
                    policy[k] = v
1756 b2832c6a Antony Chazapis
        self.node.policy_set(node, policy)
1757 2715ade4 Sofia Papagiannaki
1758 19ddd41b Sofia Papagiannaki
    def _get_policy(self, node, is_account_policy=True):
1759 19ddd41b Sofia Papagiannaki
        default_policy = self.default_account_policy \
1760 19ddd41b Sofia Papagiannaki
            if is_account_policy else self.default_container_policy
1761 19ddd41b Sofia Papagiannaki
        policy = default_policy.copy()
1762 b9064632 Antony Chazapis
        policy.update(self.node.policy_get(node))
1763 b9064632 Antony Chazapis
        return policy
1764 2715ade4 Sofia Papagiannaki
1765 0f510652 Sofia Papagiannaki
    def _apply_versioning(self, account, container, version_id,
1766 0f510652 Sofia Papagiannaki
                          update_statistics_ancestors_depth=None):
1767 813e42e5 Antony Chazapis
        """Delete the provided version if such is the policy.
1768 813e42e5 Antony Chazapis
           Return size of object removed.
1769 813e42e5 Antony Chazapis
        """
1770 2715ade4 Sofia Papagiannaki
1771 5cc484e1 Antony Chazapis
        if version_id is None:
1772 813e42e5 Antony Chazapis
            return 0
1773 5cc484e1 Antony Chazapis
        path, node = self._lookup_container(account, container)
1774 19ddd41b Sofia Papagiannaki
        versioning = self._get_policy(
1775 19ddd41b Sofia Papagiannaki
            node, is_account_policy=False)['versioning']
1776 1dd34bdd Sofia Papagiannaki
        if versioning != 'auto':
1777 0f510652 Sofia Papagiannaki
            hash, size = self.node.version_remove(
1778 0f510652 Sofia Papagiannaki
                version_id, update_statistics_ancestors_depth)
1779 5161c672 Antony Chazapis
            self.store.map_delete(hash)
1780 813e42e5 Antony Chazapis
            return size
1781 1dd34bdd Sofia Papagiannaki
        elif self.free_versioning:
1782 fff37615 Sofia Papagiannaki
            return self.node.version_get_properties(
1783 fff37615 Sofia Papagiannaki
                version_id, keys=('size',))[0]
1784 813e42e5 Antony Chazapis
        return 0
1785 2715ade4 Sofia Papagiannaki
1786 a9b3f29d Antony Chazapis
    # Access control functions.
1787 2715ade4 Sofia Papagiannaki
1788 a9b3f29d Antony Chazapis
    def _check_groups(self, groups):
1789 0f9d752c Antony Chazapis
        # raise ValueError('Bad characters in groups')
1790 a9b3f29d Antony Chazapis
        pass
1791 2715ade4 Sofia Papagiannaki
1792 a9b3f29d Antony Chazapis
    def _check_permissions(self, path, permissions):
1793 0f9d752c Antony Chazapis
        # raise ValueError('Bad characters in permissions')
1794 5e068361 Antony Chazapis
        pass
1795 2715ade4 Sofia Papagiannaki
1796 dc88754b Nanakos Chrysostomos
    def _get_formatted_paths(self, paths):
1797 dc88754b Nanakos Chrysostomos
        formatted = []
1798 ace7592b Sofia Papagiannaki
        if len(paths) == 0:
1799 dc88754b Nanakos Chrysostomos
            return formatted
1800 dc88754b Nanakos Chrysostomos
        props = self.node.get_props(paths)
1801 dc88754b Nanakos Chrysostomos
        if props:
1802 dc88754b Nanakos Chrysostomos
            for prop in props:
1803 dc88754b Nanakos Chrysostomos
                if prop[1].split(';', 1)[0].strip() in (
1804 dc88754b Nanakos Chrysostomos
                        'application/directory', 'application/folder'):
1805 ace7592b Sofia Papagiannaki
                    formatted.append((prop[0].rstrip('/') + '/',
1806 ace7592b Sofia Papagiannaki
                                      self.MATCH_PREFIX))
1807 dc88754b Nanakos Chrysostomos
                formatted.append((prop[0], self.MATCH_EXACT))
1808 dc88754b Nanakos Chrysostomos
        return formatted
1809 dc88754b Nanakos Chrysostomos
1810 16b0ed4a Nanakos Chrysostomos
    def _get_permissions_path(self, account, container, name):
1811 16b0ed4a Nanakos Chrysostomos
        path = '/'.join((account, container, name))
1812 16b0ed4a Nanakos Chrysostomos
        permission_paths = self.permissions.access_inherit(path)
1813 16b0ed4a Nanakos Chrysostomos
        permission_paths.sort()
1814 16b0ed4a Nanakos Chrysostomos
        permission_paths.reverse()
1815 16b0ed4a Nanakos Chrysostomos
        for p in permission_paths:
1816 16b0ed4a Nanakos Chrysostomos
            if p == path:
1817 16b0ed4a Nanakos Chrysostomos
                return p
1818 16b0ed4a Nanakos Chrysostomos
            else:
1819 16b0ed4a Nanakos Chrysostomos
                if p.count('/') < 2:
1820 16b0ed4a Nanakos Chrysostomos
                    continue
1821 16b0ed4a Nanakos Chrysostomos
                node = self.node.node_lookup(p)
1822 16b0ed4a Nanakos Chrysostomos
                props = None
1823 16b0ed4a Nanakos Chrysostomos
                if node is not None:
1824 16b0ed4a Nanakos Chrysostomos
                    props = self.node.version_lookup(node, inf, CLUSTER_NORMAL)
1825 16b0ed4a Nanakos Chrysostomos
                if props is not None:
1826 ace7592b Sofia Papagiannaki
                    if props[self.TYPE].split(';', 1)[0].strip() in (
1827 ace7592b Sofia Papagiannaki
                            'application/directory', 'application/folder'):
1828 16b0ed4a Nanakos Chrysostomos
                        return p
1829 16b0ed4a Nanakos Chrysostomos
        return None
1830 16b0ed4a Nanakos Chrysostomos
1831 dc88754b Nanakos Chrysostomos
    def _get_permissions_path_bulk(self, account, container, names):
1832 dc88754b Nanakos Chrysostomos
        formatted_paths = []
1833 dc88754b Nanakos Chrysostomos
        for name in names:
1834 dc88754b Nanakos Chrysostomos
            path = '/'.join((account, container, name))
1835 dc88754b Nanakos Chrysostomos
            formatted_paths.append(path)
1836 ace7592b Sofia Papagiannaki
        permission_paths = self.permissions.access_inherit_bulk(
1837 ace7592b Sofia Papagiannaki
            formatted_paths)
1838 5e068361 Antony Chazapis
        permission_paths.sort()
1839 5e068361 Antony Chazapis
        permission_paths.reverse()
1840 dc88754b Nanakos Chrysostomos
        permission_paths_list = []
1841 dc88754b Nanakos Chrysostomos
        lookup_list = []
1842 5e068361 Antony Chazapis
        for p in permission_paths:
1843 dc88754b Nanakos Chrysostomos
            if p in formatted_paths:
1844 dc88754b Nanakos Chrysostomos
                permission_paths_list.append(p)
1845 5e068361 Antony Chazapis
            else:
1846 71dbc012 Antony Chazapis
                if p.count('/') < 2:
1847 71dbc012 Antony Chazapis
                    continue
1848 dc88754b Nanakos Chrysostomos
                lookup_list.append(p)
1849 dc88754b Nanakos Chrysostomos
1850 dc88754b Nanakos Chrysostomos
        if len(lookup_list) > 0:
1851 62e6d12e Nanakos Chrysostomos
            props = self.node.get_props(lookup_list)
1852 dc88754b Nanakos Chrysostomos
            if props:
1853 dc88754b Nanakos Chrysostomos
                for prop in props:
1854 dc88754b Nanakos Chrysostomos
                    if prop[1].split(';', 1)[0].strip() in (
1855 29148653 Sofia Papagiannaki
                            'application/directory', 'application/folder'):
1856 e161c24f Sofia Papagiannaki
                        permission_paths_list.append(prop[0])
1857 dc88754b Nanakos Chrysostomos
1858 dc88754b Nanakos Chrysostomos
        if len(permission_paths_list) > 0:
1859 dc88754b Nanakos Chrysostomos
            return permission_paths_list
1860 dc88754b Nanakos Chrysostomos
1861 5e068361 Antony Chazapis
        return None
1862 2715ade4 Sofia Papagiannaki
1863 0d573e18 Sofia Papagiannaki
    def _reset_allowed_paths(self):
1864 0d573e18 Sofia Papagiannaki
        self.read_allowed_paths = defaultdict(set)
1865 0d573e18 Sofia Papagiannaki
        self.write_allowed_paths = defaultdict(set)
1866 0d573e18 Sofia Papagiannaki
1867 0d573e18 Sofia Papagiannaki
    @check_allowed_paths(action=0)
1868 0d573e18 Sofia Papagiannaki
    def _can_read_account(self, user, account):
1869 0d573e18 Sofia Papagiannaki
        if user != account:
1870 0d573e18 Sofia Papagiannaki
            if account not in self._allowed_accounts(user):
1871 0d573e18 Sofia Papagiannaki
                raise NotAllowedError
1872 0d573e18 Sofia Papagiannaki
1873 0d573e18 Sofia Papagiannaki
    @check_allowed_paths(action=1)
1874 0d573e18 Sofia Papagiannaki
    def _can_write_account(self, user, account):
1875 0d573e18 Sofia Papagiannaki
        if user != account:
1876 0d573e18 Sofia Papagiannaki
            raise NotAllowedError
1877 0d573e18 Sofia Papagiannaki
1878 0d573e18 Sofia Papagiannaki
    @check_allowed_paths(action=0)
1879 0d573e18 Sofia Papagiannaki
    def _can_read_container(self, user, account, container):
1880 0d573e18 Sofia Papagiannaki
        if user != account:
1881 0d573e18 Sofia Papagiannaki
            if container not in self._allowed_containers(user, account):
1882 0d573e18 Sofia Papagiannaki
                raise NotAllowedError
1883 0d573e18 Sofia Papagiannaki
1884 0d573e18 Sofia Papagiannaki
    @check_allowed_paths(action=1)
1885 0d573e18 Sofia Papagiannaki
    def _can_write_container(self, user, account, container):
1886 0d573e18 Sofia Papagiannaki
        if user != account:
1887 0d573e18 Sofia Papagiannaki
            raise NotAllowedError
1888 0d573e18 Sofia Papagiannaki
1889 0d573e18 Sofia Papagiannaki
    @check_allowed_paths(action=0)
1890 0d573e18 Sofia Papagiannaki
    def _can_read_object(self, user, account, container, name):
1891 a9b3f29d Antony Chazapis
        if user == account:
1892 a9b3f29d Antony Chazapis
            return True
1893 a9b3f29d Antony Chazapis
        path = '/'.join((account, container, name))
1894 aeb2b64f Antony Chazapis
        if self.permissions.public_get(path) is not None:
1895 71dbc012 Antony Chazapis
            return True
1896 5e068361 Antony Chazapis
        path = self._get_permissions_path(account, container, name)
1897 71dbc012 Antony Chazapis
        if not path:
1898 71dbc012 Antony Chazapis
            raise NotAllowedError
1899 29148653 Sofia Papagiannaki
        if (not self.permissions.access_check(path, self.READ, user) and not
1900 29148653 Sofia Papagiannaki
                self.permissions.access_check(path, self.WRITE, user)):
1901 a9b3f29d Antony Chazapis
            raise NotAllowedError
1902 2715ade4 Sofia Papagiannaki
1903 0d573e18 Sofia Papagiannaki
    @check_allowed_paths(action=1)
1904 0d573e18 Sofia Papagiannaki
    def _can_write_object(self, user, account, container, name):
1905 6f4bce7b Antony Chazapis
        if user == account:
1906 6f4bce7b Antony Chazapis
            return True
1907 6f4bce7b Antony Chazapis
        path = '/'.join((account, container, name))
1908 71dbc012 Antony Chazapis
        path = self._get_permissions_path(account, container, name)
1909 71dbc012 Antony Chazapis
        if not path:
1910 71dbc012 Antony Chazapis
            raise NotAllowedError
1911 2c5363a0 Antony Chazapis
        if not self.permissions.access_check(path, self.WRITE, user):
1912 a9b3f29d Antony Chazapis
            raise NotAllowedError
1913 2715ade4 Sofia Papagiannaki
1914 a9b3f29d Antony Chazapis
    def _allowed_accounts(self, user):
1915 a9b3f29d Antony Chazapis
        allow = set()
1916 0f9d752c Antony Chazapis
        for path in self.permissions.access_list_paths(user):
1917 0d573e18 Sofia Papagiannaki
            p = path.split('/', 1)[0]
1918 0d573e18 Sofia Papagiannaki
            allow.add(p)
1919 0d573e18 Sofia Papagiannaki
        self.read_allowed_paths[user] |= allow
1920 a9b3f29d Antony Chazapis
        return sorted(allow)
1921 2715ade4 Sofia Papagiannaki
1922 a9b3f29d Antony Chazapis
    def _allowed_containers(self, user, account):
1923 a9b3f29d Antony Chazapis
        allow = set()
1924 0f9d752c Antony Chazapis
        for path in self.permissions.access_list_paths(user, account):
1925 0d573e18 Sofia Papagiannaki
            p = path.split('/', 2)[1]
1926 0d573e18 Sofia Papagiannaki
            allow.add(p)
1927 0d573e18 Sofia Papagiannaki
        self.read_allowed_paths[user] |= allow
1928 a9b3f29d Antony Chazapis
        return sorted(allow)
1929 5576e6dd Sofia Papagiannaki
1930 5576e6dd Sofia Papagiannaki
    # Domain functions
1931 5576e6dd Sofia Papagiannaki
1932 1f96b68d Sofia Papagiannaki
    @debug_method
1933 5d022141 Sofia Papagiannaki
    @backend_method
1934 e77b7a99 Sofia Papagiannaki
    def get_domain_objects(self, domain, user=None):
1935 a63f36a2 Sofia Papagiannaki
        allowed_paths = self.permissions.access_list_paths(
1936 a63f36a2 Sofia Papagiannaki
            user, include_owned=user is not None, include_containers=False)
1937 7736e11a Sofia Papagiannaki
        if not allowed_paths:
1938 7736e11a Sofia Papagiannaki
            return []
1939 7736e11a Sofia Papagiannaki
        obj_list = self.node.domain_object_list(
1940 7736e11a Sofia Papagiannaki
            domain, allowed_paths, CLUSTER_NORMAL)
1941 5576e6dd Sofia Papagiannaki
        return [(path,
1942 5576e6dd Sofia Papagiannaki
                 self._build_metadata(props, user_defined_meta),
1943 7736e11a Sofia Papagiannaki
                 self.permissions.access_get(path)) for
1944 7736e11a Sofia Papagiannaki
                path, props, user_defined_meta in obj_list]
1945 5576e6dd Sofia Papagiannaki
1946 5576e6dd Sofia Papagiannaki
    # util functions
1947 5576e6dd Sofia Papagiannaki
1948 5576e6dd Sofia Papagiannaki
    def _build_metadata(self, props, user_defined=None,
1949 5576e6dd Sofia Papagiannaki
                        include_user_defined=True):
1950 5576e6dd Sofia Papagiannaki
        meta = {'bytes': props[self.SIZE],
1951 5576e6dd Sofia Papagiannaki
                'type': props[self.TYPE],
1952 5576e6dd Sofia Papagiannaki
                'hash': props[self.HASH],
1953 5576e6dd Sofia Papagiannaki
                'version': props[self.SERIAL],
1954 5576e6dd Sofia Papagiannaki
                'version_timestamp': props[self.MTIME],
1955 5576e6dd Sofia Papagiannaki
                'modified_by': props[self.MUSER],
1956 5576e6dd Sofia Papagiannaki
                'uuid': props[self.UUID],
1957 5576e6dd Sofia Papagiannaki
                'checksum': props[self.CHECKSUM]}
1958 29148653 Sofia Papagiannaki
        if include_user_defined and user_defined is not None:
1959 5576e6dd Sofia Papagiannaki
            meta.update(user_defined)
1960 5576e6dd Sofia Papagiannaki
        return meta
1961 5576e6dd Sofia Papagiannaki
1962 33af031c Sofia Papagiannaki
    def _exists(self, node):
1963 33af031c Sofia Papagiannaki
        try:
1964 33af031c Sofia Papagiannaki
            self._get_version(node)
1965 33af031c Sofia Papagiannaki
        except ItemNotExists:
1966 33af031c Sofia Papagiannaki
            return False
1967 33af031c Sofia Papagiannaki
        else:
1968 33af031c Sofia Papagiannaki
            return True
1969 3a5994a8 Sofia Papagiannaki
1970 3a5994a8 Sofia Papagiannaki
    def _unhexlify_hash(self, hash):
1971 3a5994a8 Sofia Papagiannaki
        try:
1972 3a5994a8 Sofia Papagiannaki
            return binascii.unhexlify(hash)
1973 3a5994a8 Sofia Papagiannaki
        except TypeError:
1974 3a5994a8 Sofia Papagiannaki
            raise InvalidHash(hash)