Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / modular.py @ 78e1f8da

History | View | Annotate | Download (79.7 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 ebdbac7a 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 78e1f8da Sofia Papagiannaki
QUOTA_POLICY = 'quota'
120 78e1f8da Sofia Papagiannaki
VERSIONING_POLICY = 'versioning'
121 78e1f8da Sofia Papagiannaki
PROJECT = 'project'
122 78e1f8da Sofia Papagiannaki
123 44ad5860 Antony Chazapis
inf = float('inf')
124 44ad5860 Antony Chazapis
125 bb4eafc6 Antony Chazapis
ULTIMATE_ANSWER = 42
126 bb4eafc6 Antony Chazapis
127 3b8f938b Sofia Papagiannaki
DEFAULT_DISKSPACE_RESOURCE = 'pithos.diskspace'
128 a9b3f29d Antony Chazapis
129 a9b3f29d Antony Chazapis
logger = logging.getLogger(__name__)
130 a9b3f29d Antony Chazapis
131 1c2fc0ff Antony Chazapis
132 5d022141 Sofia Papagiannaki
def backend_method(func):
133 5d022141 Sofia Papagiannaki
    @wraps(func)
134 5d022141 Sofia Papagiannaki
    def wrapper(self, *args, **kw):
135 5d022141 Sofia Papagiannaki
        # if we are inside a database transaction
136 5d022141 Sofia Papagiannaki
        # just proceed with the method execution
137 5d022141 Sofia Papagiannaki
        # otherwise manage a new transaction
138 5d022141 Sofia Papagiannaki
        if self.in_transaction:
139 5d022141 Sofia Papagiannaki
            return func(self, *args, **kw)
140 5d022141 Sofia Papagiannaki
141 5d022141 Sofia Papagiannaki
        try:
142 5d022141 Sofia Papagiannaki
            self.pre_exec()
143 5d022141 Sofia Papagiannaki
            result = func(self, *args, **kw)
144 5d022141 Sofia Papagiannaki
            success_status = True
145 5d022141 Sofia Papagiannaki
            return result
146 5d022141 Sofia Papagiannaki
        except:
147 5d022141 Sofia Papagiannaki
            success_status = False
148 5d022141 Sofia Papagiannaki
            raise
149 5d022141 Sofia Papagiannaki
        finally:
150 5d022141 Sofia Papagiannaki
            self.post_exec(success_status)
151 5d022141 Sofia Papagiannaki
    return wrapper
152 5d022141 Sofia Papagiannaki
153 5d022141 Sofia Papagiannaki
154 1f96b68d Sofia Papagiannaki
def debug_method(func):
155 1f96b68d Sofia Papagiannaki
    @wraps(func)
156 1f96b68d Sofia Papagiannaki
    def wrapper(self, *args, **kw):
157 1f96b68d Sofia Papagiannaki
        try:
158 1f96b68d Sofia Papagiannaki
            result = func(self, *args, **kw)
159 1f96b68d Sofia Papagiannaki
            return result
160 1f96b68d Sofia Papagiannaki
        except:
161 1f96b68d Sofia Papagiannaki
            result = format_exc()
162 1f96b68d Sofia Papagiannaki
            raise
163 1f96b68d Sofia Papagiannaki
        finally:
164 b1aca3e6 Sofia Papagiannaki
            all_args = map(repr, args)
165 1f96b68d Sofia Papagiannaki
            map(all_args.append, ('%s=%s' % (k, v) for k, v in kw.iteritems()))
166 1f96b68d Sofia Papagiannaki
            logger.debug(">>> %s(%s) <<< %s" % (
167 1f96b68d Sofia Papagiannaki
                func.__name__, ', '.join(all_args).rstrip(', '), result))
168 1f96b68d Sofia Papagiannaki
    return wrapper
169 1f96b68d Sofia Papagiannaki
170 1f96b68d Sofia Papagiannaki
171 ebdbac7a Sofia Papagiannaki
def check_allowed_paths(action):
172 ebdbac7a Sofia Papagiannaki
    """Decorator for backend methods checking path access granted to user.
173 ebdbac7a Sofia Papagiannaki

174 ebdbac7a Sofia Papagiannaki
    The 1st argument of the decorated method is expected to be a
175 ebdbac7a Sofia Papagiannaki
    ModularBackend instance, the 2nd the user performing the request and
176 ebdbac7a Sofia Papagiannaki
    the path join of the rest arguments is supposed to be the requested path.
177 ebdbac7a Sofia Papagiannaki

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

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

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