Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / modular.py @ e492238f

History | View | Annotate | Download (80.3 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 78348987 Sofia Papagiannaki
        dest_meta = dest_meta or {}
1234 4d15c94e Sofia Papagiannaki
        dest_version_ids = []
1235 ebdbac7a Sofia Papagiannaki
        self._can_read_object(user, src_account, src_container, src_name)
1236 a06c276e Sofia Papagiannaki
1237 a06c276e Sofia Papagiannaki
        src_container_path = '/'.join((src_account, src_container))
1238 a06c276e Sofia Papagiannaki
        dest_container_path = '/'.join((dest_account, dest_container))
1239 a06c276e Sofia Papagiannaki
        # Lock container paths in alphabetical order
1240 a06c276e Sofia Papagiannaki
        if src_container_path < dest_container_path:
1241 e492238f Giorgos Korfiatis
            src_container_node = self._lookup_container(src_account,
1242 e492238f Giorgos Korfiatis
                                                        src_container)[-1]
1243 e492238f Giorgos Korfiatis
            dest_container_node = self._lookup_container(dest_account,
1244 e492238f Giorgos Korfiatis
                                                         dest_container)[-1]
1245 a06c276e Sofia Papagiannaki
        else:
1246 e492238f Giorgos Korfiatis
            dest_container_node = self._lookup_container(dest_account,
1247 e492238f Giorgos Korfiatis
                                                         dest_container)[-1]
1248 e492238f Giorgos Korfiatis
            src_container_node = self._lookup_container(src_account,
1249 e492238f Giorgos Korfiatis
                                                        src_container)[-1]
1250 e492238f Giorgos Korfiatis
1251 e492238f Giorgos Korfiatis
        cross_account = src_account != dest_account
1252 e492238f Giorgos Korfiatis
        cross_container = src_container != dest_container
1253 e492238f Giorgos Korfiatis
        if not cross_account and cross_container:
1254 e492238f Giorgos Korfiatis
            src_project = self._get_project(src_container_node)
1255 e492238f Giorgos Korfiatis
            dest_project = self._get_project(dest_container_node)
1256 e492238f Giorgos Korfiatis
            cross_project = src_project != dest_project
1257 e492238f Giorgos Korfiatis
        else:
1258 e492238f Giorgos Korfiatis
            cross_project = False
1259 e492238f Giorgos Korfiatis
        report_size_change = not is_move or cross_account or cross_project
1260 a06c276e Sofia Papagiannaki
1261 a06c276e Sofia Papagiannaki
        path, node = self._lookup_object(src_account, src_container, src_name)
1262 1730b3bf chazapis
        # TODO: Will do another fetch of the properties in duplicate version...
1263 2715ade4 Sofia Papagiannaki
        props = self._get_version(
1264 2715ade4 Sofia Papagiannaki
            node, src_version)  # Check to see if source exists.
1265 b9064632 Antony Chazapis
        src_version_id = props[self.SERIAL]
1266 b9064632 Antony Chazapis
        hash = props[self.HASH]
1267 b9064632 Antony Chazapis
        size = props[self.SIZE]
1268 2715ade4 Sofia Papagiannaki
        is_copy = not is_move and (src_account, src_container, src_name) != (
1269 2715ade4 Sofia Papagiannaki
            dest_account, dest_container, dest_name)  # New uuid.
1270 29148653 Sofia Papagiannaki
        dest_version_ids.append(self._update_object_hash(
1271 29148653 Sofia Papagiannaki
            user, dest_account, dest_container, dest_name, size, type, hash,
1272 29148653 Sofia Papagiannaki
            None, dest_domain, dest_meta, replace_meta, permissions,
1273 9e3a38bb Sofia Papagiannaki
            src_node=node, src_version_id=src_version_id, is_copy=is_copy,
1274 9e3a38bb Sofia Papagiannaki
            report_size_change=report_size_change))
1275 29148653 Sofia Papagiannaki
        if is_move and ((src_account, src_container, src_name) !=
1276 29148653 Sofia Papagiannaki
                        (dest_account, dest_container, dest_name)):
1277 9e3a38bb Sofia Papagiannaki
            self._delete_object(user, src_account, src_container, src_name,
1278 9e3a38bb Sofia Papagiannaki
                                report_size_change=report_size_change)
1279 2715ade4 Sofia Papagiannaki
1280 4d15c94e Sofia Papagiannaki
        if delimiter:
1281 29148653 Sofia Papagiannaki
            prefix = (src_name + delimiter if not
1282 29148653 Sofia Papagiannaki
                      src_name.endswith(delimiter) else src_name)
1283 29148653 Sofia Papagiannaki
            src_names = self._list_objects_no_limit(
1284 29148653 Sofia Papagiannaki
                user, src_account, src_container, prefix, delimiter=None,
1285 29148653 Sofia Papagiannaki
                virtual=False, domain=None, keys=[], shared=False, until=None,
1286 29148653 Sofia Papagiannaki
                size_range=None, all_props=True, public=False)
1287 2715ade4 Sofia Papagiannaki
            src_names.sort(key=lambda x: x[2])  # order by nodes
1288 4d15c94e Sofia Papagiannaki
            paths = [elem[0] for elem in src_names]
1289 4d15c94e Sofia Papagiannaki
            nodes = [elem[2] for elem in src_names]
1290 29148653 Sofia Papagiannaki
            # TODO: Will do another fetch of the properties
1291 29148653 Sofia Papagiannaki
            # in duplicate version...
1292 2715ade4 Sofia Papagiannaki
            props = self._get_versions(nodes)  # Check to see if source exists.
1293 2715ade4 Sofia Papagiannaki
1294 4d15c94e Sofia Papagiannaki
            for prop, path, node in zip(props, paths, nodes):
1295 4d15c94e Sofia Papagiannaki
                src_version_id = prop[self.SERIAL]
1296 4d15c94e Sofia Papagiannaki
                hash = prop[self.HASH]
1297 4d15c94e Sofia Papagiannaki
                vtype = prop[self.TYPE]
1298 07867f70 Sofia Papagiannaki
                size = prop[self.SIZE]
1299 2715ade4 Sofia Papagiannaki
                dest_prefix = dest_name + delimiter if not dest_name.endswith(
1300 2715ade4 Sofia Papagiannaki
                    delimiter) else dest_name
1301 4d15c94e Sofia Papagiannaki
                vdest_name = path.replace(prefix, dest_prefix, 1)
1302 683d4324 Sofia Papagiannaki
                # _update_object_hash() locks destination path
1303 29148653 Sofia Papagiannaki
                dest_version_ids.append(self._update_object_hash(
1304 29148653 Sofia Papagiannaki
                    user, dest_account, dest_container, vdest_name, size,
1305 29148653 Sofia Papagiannaki
                    vtype, hash, None, dest_domain, meta={},
1306 29148653 Sofia Papagiannaki
                    replace_meta=False, permissions=None, src_node=node,
1307 277faddf Sofia Papagiannaki
                    src_version_id=src_version_id, is_copy=is_copy,
1308 277faddf Sofia Papagiannaki
                    report_size_change=report_size_change))
1309 29148653 Sofia Papagiannaki
                if is_move and ((src_account, src_container, src_name) !=
1310 29148653 Sofia Papagiannaki
                                (dest_account, dest_container, dest_name)):
1311 277faddf Sofia Papagiannaki
                    self._delete_object(user, src_account, src_container, path,
1312 277faddf Sofia Papagiannaki
                                        report_size_change=report_size_change)
1313 29148653 Sofia Papagiannaki
        return (dest_version_ids[0] if len(dest_version_ids) == 1 else
1314 29148653 Sofia Papagiannaki
                dest_version_ids)
1315 2715ade4 Sofia Papagiannaki
1316 1f96b68d Sofia Papagiannaki
    @debug_method
1317 5d022141 Sofia Papagiannaki
    @backend_method
1318 29148653 Sofia Papagiannaki
    def copy_object(self, user, src_account, src_container, src_name,
1319 29148653 Sofia Papagiannaki
                    dest_account, dest_container, dest_name, type, domain,
1320 29148653 Sofia Papagiannaki
                    meta=None, replace_meta=False, permissions=None,
1321 29148653 Sofia Papagiannaki
                    src_version=None, delimiter=None):
1322 dff7b6f1 Sofia Papagiannaki
        """Copy an object's data and metadata."""
1323 2715ade4 Sofia Papagiannaki
1324 78348987 Sofia Papagiannaki
        meta = meta or {}
1325 29148653 Sofia Papagiannaki
        dest_version_id = self._copy_object(
1326 29148653 Sofia Papagiannaki
            user, src_account, src_container, src_name, dest_account,
1327 29148653 Sofia Papagiannaki
            dest_container, dest_name, type, domain, meta, replace_meta,
1328 29148653 Sofia Papagiannaki
            permissions, src_version, False, delimiter)
1329 46286f5f Antony Chazapis
        return dest_version_id
1330 2715ade4 Sofia Papagiannaki
1331 1f96b68d Sofia Papagiannaki
    @debug_method
1332 5d022141 Sofia Papagiannaki
    @backend_method
1333 29148653 Sofia Papagiannaki
    def move_object(self, user, src_account, src_container, src_name,
1334 29148653 Sofia Papagiannaki
                    dest_account, dest_container, dest_name, type, domain,
1335 29148653 Sofia Papagiannaki
                    meta=None, replace_meta=False, permissions=None,
1336 29148653 Sofia Papagiannaki
                    delimiter=None):
1337 a9b3f29d Antony Chazapis
        """Move an object's data and metadata."""
1338 2715ade4 Sofia Papagiannaki
1339 78348987 Sofia Papagiannaki
        meta = meta or {}
1340 79bb41b7 Antony Chazapis
        if user != src_account:
1341 79bb41b7 Antony Chazapis
            raise NotAllowedError
1342 9e3a38bb Sofia Papagiannaki
        dest_version_id = self._move_object(
1343 29148653 Sofia Papagiannaki
            user, src_account, src_container, src_name, dest_account,
1344 29148653 Sofia Papagiannaki
            dest_container, dest_name, type, domain, meta, replace_meta,
1345 9e3a38bb Sofia Papagiannaki
            permissions, None, delimiter=delimiter)
1346 02c4d2ba Antony Chazapis
        return dest_version_id
1347 2715ade4 Sofia Papagiannaki
1348 29148653 Sofia Papagiannaki
    def _delete_object(self, user, account, container, name, until=None,
1349 9e3a38bb Sofia Papagiannaki
                       delimiter=None, report_size_change=True):
1350 a9b3f29d Antony Chazapis
        if user != account:
1351 a9b3f29d Antony Chazapis
            raise NotAllowedError
1352 2715ade4 Sofia Papagiannaki
1353 78e1f8da Sofia Papagiannaki
        # lock container path
1354 78e1f8da Sofia Papagiannaki
        container_path, container_node = self._lookup_container(account,
1355 78e1f8da Sofia Papagiannaki
                                                                container)
1356 78e1f8da Sofia Papagiannaki
        project = self._get_project(container_node)
1357 78e1f8da Sofia Papagiannaki
        path, node = self._lookup_object(account, container, name)
1358 48bb9c89 Sofia Papagiannaki
1359 a9b3f29d Antony Chazapis
        if until is not None:
1360 c915d3bf Antony Chazapis
            if node is None:
1361 c915d3bf Antony Chazapis
                return
1362 813e42e5 Antony Chazapis
            hashes = []
1363 813e42e5 Antony Chazapis
            size = 0
1364 388ea25f Sofia Papagiannaki
            serials = []
1365 0f510652 Sofia Papagiannaki
            h, s, v = self.node.node_purge(node, until, CLUSTER_NORMAL,
1366 0f510652 Sofia Papagiannaki
                                           update_statistics_ancestors_depth=1)
1367 813e42e5 Antony Chazapis
            hashes += h
1368 813e42e5 Antony Chazapis
            size += s
1369 388ea25f Sofia Papagiannaki
            serials += v
1370 0f510652 Sofia Papagiannaki
            h, s, v = self.node.node_purge(node, until, CLUSTER_HISTORY,
1371 0f510652 Sofia Papagiannaki
                                           update_statistics_ancestors_depth=1)
1372 813e42e5 Antony Chazapis
            hashes += h
1373 0a92ff85 Sofia Papagiannaki
            if not self.free_versioning:
1374 0a92ff85 Sofia Papagiannaki
                size += s
1375 388ea25f Sofia Papagiannaki
            serials += v
1376 04230536 Antony Chazapis
            for h in hashes:
1377 04230536 Antony Chazapis
                self.store.map_delete(h)
1378 0f510652 Sofia Papagiannaki
            self.node.node_purge(node, until, CLUSTER_DELETED,
1379 0f510652 Sofia Papagiannaki
                                 update_statistics_ancestors_depth=1)
1380 a9b3f29d Antony Chazapis
            try:
1381 29148653 Sofia Papagiannaki
                self._get_version(node)
1382 a9b3f29d Antony Chazapis
            except NameError:
1383 0f9d752c Antony Chazapis
                self.permissions.access_clear(path)
1384 0a92ff85 Sofia Papagiannaki
            self._report_size_change(
1385 78e1f8da Sofia Papagiannaki
                user, account, -size, project, {
1386 0a92ff85 Sofia Papagiannaki
                    'action': 'object purge',
1387 0a92ff85 Sofia Papagiannaki
                    'path': path,
1388 0a92ff85 Sofia Papagiannaki
                    'versions': ','.join(str(i) for i in serials)
1389 0a92ff85 Sofia Papagiannaki
                }
1390 0a92ff85 Sofia Papagiannaki
            )
1391 a9b3f29d Antony Chazapis
            return
1392 2715ade4 Sofia Papagiannaki
1393 33af031c Sofia Papagiannaki
        if not self._exists(node):
1394 33af031c Sofia Papagiannaki
            raise ItemNotExists('Object is deleted.')
1395 ed2064f8 Christos Stavrakakis
1396 0f510652 Sofia Papagiannaki
        src_version_id, dest_version_id = self._put_version_duplicate(
1397 0f510652 Sofia Papagiannaki
            user, node, size=0, type='', hash=None, checksum='',
1398 0f510652 Sofia Papagiannaki
            cluster=CLUSTER_DELETED, update_statistics_ancestors_depth=1)
1399 0f510652 Sofia Papagiannaki
        del_size = self._apply_versioning(account, container, src_version_id,
1400 0f510652 Sofia Papagiannaki
                                          update_statistics_ancestors_depth=1)
1401 9e3a38bb Sofia Papagiannaki
        if report_size_change:
1402 9e3a38bb Sofia Papagiannaki
            self._report_size_change(
1403 78e1f8da Sofia Papagiannaki
                user, account, -del_size, project,
1404 9e3a38bb Sofia Papagiannaki
                {'action': 'object delete',
1405 9e3a38bb Sofia Papagiannaki
                 'path': path,
1406 9e3a38bb Sofia Papagiannaki
                 'versions': ','.join([str(dest_version_id)])})
1407 2715ade4 Sofia Papagiannaki
        self._report_object_change(
1408 2715ade4 Sofia Papagiannaki
            user, account, path, details={'action': 'object delete'})
1409 0f9d752c Antony Chazapis
        self.permissions.access_clear(path)
1410 2715ade4 Sofia Papagiannaki
1411 4d15c94e Sofia Papagiannaki
        if delimiter:
1412 4d15c94e Sofia Papagiannaki
            prefix = name + delimiter if not name.endswith(delimiter) else name
1413 29148653 Sofia Papagiannaki
            src_names = self._list_objects_no_limit(
1414 29148653 Sofia Papagiannaki
                user, account, container, prefix, delimiter=None,
1415 29148653 Sofia Papagiannaki
                virtual=False, domain=None, keys=[], shared=False, until=None,
1416 29148653 Sofia Papagiannaki
                size_range=None, all_props=True, public=False)
1417 4d15c94e Sofia Papagiannaki
            paths = []
1418 4d15c94e Sofia Papagiannaki
            for t in src_names:
1419 2715ade4 Sofia Papagiannaki
                path = '/'.join((account, container, t[0]))
1420 2715ade4 Sofia Papagiannaki
                node = t[2]
1421 33af031c Sofia Papagiannaki
                if not self._exists(node):
1422 33af031c Sofia Papagiannaki
                    continue
1423 0f510652 Sofia Papagiannaki
                src_version_id, dest_version_id = self._put_version_duplicate(
1424 0f510652 Sofia Papagiannaki
                    user, node, size=0, type='', hash=None, checksum='',
1425 0f510652 Sofia Papagiannaki
                    cluster=CLUSTER_DELETED,
1426 0f510652 Sofia Papagiannaki
                    update_statistics_ancestors_depth=1)
1427 2715ade4 Sofia Papagiannaki
                del_size = self._apply_versioning(
1428 0f510652 Sofia Papagiannaki
                    account, container, src_version_id,
1429 0f510652 Sofia Papagiannaki
                    update_statistics_ancestors_depth=1)
1430 9e3a38bb Sofia Papagiannaki
                if report_size_change:
1431 9e3a38bb Sofia Papagiannaki
                    self._report_size_change(
1432 78e1f8da Sofia Papagiannaki
                        user, account, -del_size, project,
1433 9e3a38bb Sofia Papagiannaki
                        {'action': 'object delete',
1434 9e3a38bb Sofia Papagiannaki
                         'path': path,
1435 9e3a38bb Sofia Papagiannaki
                         'versions': ','.join([str(dest_version_id)])})
1436 2715ade4 Sofia Papagiannaki
                self._report_object_change(
1437 2715ade4 Sofia Papagiannaki
                    user, account, path, details={'action': 'object delete'})
1438 4d15c94e Sofia Papagiannaki
                paths.append(path)
1439 4d15c94e Sofia Papagiannaki
            self.permissions.access_clear_bulk(paths)
1440 2715ade4 Sofia Papagiannaki
1441 ebdbac7a Sofia Papagiannaki
        # remove all the cached allowed paths
1442 ebdbac7a Sofia Papagiannaki
        # removing the specific path could be more expensive
1443 ebdbac7a Sofia Papagiannaki
        self._reset_allowed_paths()
1444 ebdbac7a Sofia Papagiannaki
1445 1f96b68d Sofia Papagiannaki
    @debug_method
1446 5d022141 Sofia Papagiannaki
    @backend_method
1447 29148653 Sofia Papagiannaki
    def delete_object(self, user, account, container, name, until=None,
1448 29148653 Sofia Papagiannaki
                      prefix='', delimiter=None):
1449 dff7b6f1 Sofia Papagiannaki
        """Delete/purge an object."""
1450 2715ade4 Sofia Papagiannaki
1451 4d15c94e Sofia Papagiannaki
        self._delete_object(user, account, container, name, until, delimiter)
1452 2715ade4 Sofia Papagiannaki
1453 1f96b68d Sofia Papagiannaki
    @debug_method
1454 5d022141 Sofia Papagiannaki
    @backend_method
1455 62f915a1 Antony Chazapis
    def list_versions(self, user, account, container, name):
1456 29148653 Sofia Papagiannaki
        """Return a list of all object (version, version_timestamp) tuples."""
1457 2715ade4 Sofia Papagiannaki
1458 ebdbac7a Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
1459 60b8a083 Antony Chazapis
        path, node = self._lookup_object(account, container, name)
1460 97d45f69 Antony Chazapis
        versions = self.node.node_get_versions(node)
1461 29148653 Sofia Papagiannaki
        return [[x[self.SERIAL], x[self.MTIME]] for x in versions if
1462 29148653 Sofia Papagiannaki
                x[self.CLUSTER] != CLUSTER_DELETED]
1463 2715ade4 Sofia Papagiannaki
1464 1f96b68d Sofia Papagiannaki
    @debug_method
1465 5d022141 Sofia Papagiannaki
    @backend_method
1466 91fc9266 Sofia Papagiannaki
    def get_uuid(self, user, uuid, check_permissions=True):
1467 37bee317 Antony Chazapis
        """Return the (account, container, name) for the UUID given."""
1468 2715ade4 Sofia Papagiannaki
1469 2bbf1544 Georgios D. Tsoukalas
        info = self.node.latest_uuid(uuid, CLUSTER_NORMAL)
1470 37bee317 Antony Chazapis
        if info is None:
1471 37bee317 Antony Chazapis
            raise NameError
1472 37bee317 Antony Chazapis
        path, serial = info
1473 37bee317 Antony Chazapis
        account, container, name = path.split('/', 2)
1474 91fc9266 Sofia Papagiannaki
        if check_permissions:
1475 ebdbac7a Sofia Papagiannaki
            self._can_read_object(user, account, container, name)
1476 37bee317 Antony Chazapis
        return (account, container, name)
1477 2715ade4 Sofia Papagiannaki
1478 1f96b68d Sofia Papagiannaki
    @debug_method
1479 5d022141 Sofia Papagiannaki
    @backend_method
1480 bb4eafc6 Antony Chazapis
    def get_public(self, user, public):
1481 bb4eafc6 Antony Chazapis
        """Return the (account, container, name) for the public id given."""
1482 2715ade4 Sofia Papagiannaki
1483 56f3c759 Sofia Papagiannaki
        path = self.permissions.public_path(public)
1484 37bee317 Antony Chazapis
        if path is None:
1485 37bee317 Antony Chazapis
            raise NameError
1486 bb4eafc6 Antony Chazapis
        account, container, name = path.split('/', 2)
1487 ebdbac7a Sofia Papagiannaki
        self._can_read_object(user, account, container, name)
1488 bb4eafc6 Antony Chazapis
        return (account, container, name)
1489 2715ade4 Sofia Papagiannaki
1490 a9b3f29d Antony Chazapis
    def get_block(self, hash):
1491 a9b3f29d Antony Chazapis
        """Return a block's data."""
1492 2715ade4 Sofia Papagiannaki
1493 b1aca3e6 Sofia Papagiannaki
        logger.debug("get_block: %s", hash)
1494 3a5994a8 Sofia Papagiannaki
        block = self.store.block_get(self._unhexlify_hash(hash))
1495 7ca7bb08 Antony Chazapis
        if not block:
1496 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Block does not exist')
1497 7ca7bb08 Antony Chazapis
        return block
1498 2715ade4 Sofia Papagiannaki
1499 a9b3f29d Antony Chazapis
    def put_block(self, data):
1500 60b8a083 Antony Chazapis
        """Store a block and return the hash."""
1501 2715ade4 Sofia Papagiannaki
1502 a9b3f29d Antony Chazapis
        logger.debug("put_block: %s", len(data))
1503 7ca7bb08 Antony Chazapis
        return binascii.hexlify(self.store.block_put(data))
1504 2715ade4 Sofia Papagiannaki
1505 a9b3f29d Antony Chazapis
    def update_block(self, hash, data, offset=0):
1506 a9b3f29d Antony Chazapis
        """Update a known block and return the hash."""
1507 2715ade4 Sofia Papagiannaki
1508 a9b3f29d Antony Chazapis
        logger.debug("update_block: %s %s %s", hash, len(data), offset)
1509 a9b3f29d Antony Chazapis
        if offset == 0 and len(data) == self.block_size:
1510 a9b3f29d Antony Chazapis
            return self.put_block(data)
1511 3a5994a8 Sofia Papagiannaki
        h = self.store.block_update(self._unhexlify_hash(hash), offset, data)
1512 a9b3f29d Antony Chazapis
        return binascii.hexlify(h)
1513 2715ade4 Sofia Papagiannaki
1514 44ad5860 Antony Chazapis
    # Path functions.
1515 2715ade4 Sofia Papagiannaki
1516 37bee317 Antony Chazapis
    def _generate_uuid(self):
1517 37bee317 Antony Chazapis
        return str(uuidlib.uuid4())
1518 2715ade4 Sofia Papagiannaki
1519 b9064632 Antony Chazapis
    def _put_object_node(self, path, parent, name):
1520 c915d3bf Antony Chazapis
        path = '/'.join((path, name))
1521 c915d3bf Antony Chazapis
        node = self.node.node_lookup(path)
1522 c915d3bf Antony Chazapis
        if node is None:
1523 2e8edd42 Sofia Papagiannaki
            node = self.node.node_create(parent, path)
1524 c915d3bf Antony Chazapis
        return path, node
1525 2715ade4 Sofia Papagiannaki
1526 0f510652 Sofia Papagiannaki
    def _put_path(self, user, parent, path,
1527 0f510652 Sofia Papagiannaki
                  update_statistics_ancestors_depth=None):
1528 62f915a1 Antony Chazapis
        node = self.node.node_create(parent, path)
1529 2715ade4 Sofia Papagiannaki
        self.node.version_create(node, None, 0, '', None, user,
1530 0f510652 Sofia Papagiannaki
                                 self._generate_uuid(), '', CLUSTER_NORMAL,
1531 0f510652 Sofia Papagiannaki
                                 update_statistics_ancestors_depth)
1532 62f915a1 Antony Chazapis
        return node
1533 2715ade4 Sofia Papagiannaki
1534 44ad5860 Antony Chazapis
    def _lookup_account(self, account, create=True):
1535 af395b9c Sofia Papagiannaki
        node = self.node.node_lookup(account)
1536 44ad5860 Antony Chazapis
        if node is None and create:
1537 2715ade4 Sofia Papagiannaki
            node = self._put_path(
1538 0f510652 Sofia Papagiannaki
                account, self.ROOTNODE, account,
1539 0f510652 Sofia Papagiannaki
                update_statistics_ancestors_depth=-1)  # User is account.
1540 c915d3bf Antony Chazapis
        return account, node
1541 2715ade4 Sofia Papagiannaki
1542 44ad5860 Antony Chazapis
    def _lookup_container(self, account, container):
1543 b90584d0 Sofia Papagiannaki
        for_update = True if self.lock_container_path else False
1544 c915d3bf Antony Chazapis
        path = '/'.join((account, container))
1545 b90584d0 Sofia Papagiannaki
        node = self.node.node_lookup(path, for_update)
1546 44ad5860 Antony Chazapis
        if node is None:
1547 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Container does not exist')
1548 c915d3bf Antony Chazapis
        return path, node
1549 2715ade4 Sofia Papagiannaki
1550 48bb9c89 Sofia Papagiannaki
    def _lookup_object(self, account, container, name, lock_container=False):
1551 48bb9c89 Sofia Papagiannaki
        if lock_container:
1552 48bb9c89 Sofia Papagiannaki
            self._lookup_container(account, container)
1553 48bb9c89 Sofia Papagiannaki
1554 c915d3bf Antony Chazapis
        path = '/'.join((account, container, name))
1555 c915d3bf Antony Chazapis
        node = self.node.node_lookup(path)
1556 44ad5860 Antony Chazapis
        if node is None:
1557 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Object does not exist')
1558 c915d3bf Antony Chazapis
        return path, node
1559 2715ade4 Sofia Papagiannaki
1560 cf4a7a7b Sofia Papagiannaki
    def _lookup_objects(self, paths):
1561 7efc9f86 Sofia Papagiannaki
        nodes = self.node.node_lookup_bulk(paths)
1562 cf4a7a7b Sofia Papagiannaki
        return paths, nodes
1563 2715ade4 Sofia Papagiannaki
1564 44ad5860 Antony Chazapis
    def _get_properties(self, node, until=None):
1565 44ad5860 Antony Chazapis
        """Return properties until the timestamp given."""
1566 2715ade4 Sofia Papagiannaki
1567 44ad5860 Antony Chazapis
        before = until if until is not None else inf
1568 44ad5860 Antony Chazapis
        props = self.node.version_lookup(node, before, CLUSTER_NORMAL)
1569 44ad5860 Antony Chazapis
        if props is None and until is not None:
1570 44ad5860 Antony Chazapis
            props = self.node.version_lookup(node, before, CLUSTER_HISTORY)
1571 44ad5860 Antony Chazapis
        if props is None:
1572 7efc9f86 Sofia Papagiannaki
            raise ItemNotExists('Path does not exist')
1573 44ad5860 Antony Chazapis
        return props
1574 2715ade4 Sofia Papagiannaki
1575 2e8edd42 Sofia Papagiannaki
    def _get_statistics(self, node, until=None, compute=False):
1576 29148653 Sofia Papagiannaki
        """Return (count, sum of size, timestamp) of everything under node."""
1577 2715ade4 Sofia Papagiannaki
1578 2e8edd42 Sofia Papagiannaki
        if until is not None:
1579 62f915a1 Antony Chazapis
            stats = self.node.statistics_latest(node, until, CLUSTER_DELETED)
1580 2e8edd42 Sofia Papagiannaki
        elif compute:
1581 29148653 Sofia Papagiannaki
            stats = self.node.statistics_latest(node,
1582 29148653 Sofia Papagiannaki
                                                except_cluster=CLUSTER_DELETED)
1583 2e8edd42 Sofia Papagiannaki
        else:
1584 2e8edd42 Sofia Papagiannaki
            stats = self.node.statistics_get(node, CLUSTER_NORMAL)
1585 62f915a1 Antony Chazapis
        if stats is None:
1586 62f915a1 Antony Chazapis
            stats = (0, 0, 0)
1587 62f915a1 Antony Chazapis
        return stats
1588 2715ade4 Sofia Papagiannaki
1589 44ad5860 Antony Chazapis
    def _get_version(self, node, version=None):
1590 44ad5860 Antony Chazapis
        if version is None:
1591 44ad5860 Antony Chazapis
            props = self.node.version_lookup(node, inf, CLUSTER_NORMAL)
1592 44ad5860 Antony Chazapis
            if props is None:
1593 7efc9f86 Sofia Papagiannaki
                raise ItemNotExists('Object does not exist')
1594 44ad5860 Antony Chazapis
        else:
1595 07afd277 Antony Chazapis
            try:
1596 07afd277 Antony Chazapis
                version = int(version)
1597 07afd277 Antony Chazapis
            except ValueError:
1598 7efc9f86 Sofia Papagiannaki
                raise VersionNotExists('Version does not exist')
1599 d2fc71c9 Sofia Papagiannaki
            props = self.node.version_get_properties(version, node=node)
1600 2c5363a0 Antony Chazapis
            if props is None or props[self.CLUSTER] == CLUSTER_DELETED:
1601 7efc9f86 Sofia Papagiannaki
                raise VersionNotExists('Version does not exist')
1602 44ad5860 Antony Chazapis
        return props
1603 4d15c94e Sofia Papagiannaki
1604 7efc9f86 Sofia Papagiannaki
    def _get_versions(self, nodes):
1605 7efc9f86 Sofia Papagiannaki
        return self.node.version_lookup_bulk(nodes, inf, CLUSTER_NORMAL)
1606 2715ade4 Sofia Papagiannaki
1607 0f510652 Sofia Papagiannaki
    def _put_version_duplicate(self, user, node, src_node=None, size=None,
1608 0f510652 Sofia Papagiannaki
                               type=None, hash=None, checksum=None,
1609 0f510652 Sofia Papagiannaki
                               cluster=CLUSTER_NORMAL, is_copy=False,
1610 0f510652 Sofia Papagiannaki
                               update_statistics_ancestors_depth=None):
1611 b9064632 Antony Chazapis
        """Create a new version of the node."""
1612 2715ade4 Sofia Papagiannaki
1613 2715ade4 Sofia Papagiannaki
        props = self.node.version_lookup(
1614 2715ade4 Sofia Papagiannaki
            node if src_node is None else src_node, inf, CLUSTER_NORMAL)
1615 b9064632 Antony Chazapis
        if props is not None:
1616 b9064632 Antony Chazapis
            src_version_id = props[self.SERIAL]
1617 b9064632 Antony Chazapis
            src_hash = props[self.HASH]
1618 b9064632 Antony Chazapis
            src_size = props[self.SIZE]
1619 66ce2ca5 Antony Chazapis
            src_type = props[self.TYPE]
1620 33b4e4a6 Antony Chazapis
            src_checksum = props[self.CHECKSUM]
1621 44ad5860 Antony Chazapis
        else:
1622 b9064632 Antony Chazapis
            src_version_id = None
1623 b9064632 Antony Chazapis
            src_hash = None
1624 b9064632 Antony Chazapis
            src_size = 0
1625 66ce2ca5 Antony Chazapis
            src_type = ''
1626 33b4e4a6 Antony Chazapis
            src_checksum = ''
1627 2715ade4 Sofia Papagiannaki
        if size is None:  # Set metadata.
1628 29148653 Sofia Papagiannaki
            hash = src_hash  # This way hash can be set to None
1629 29148653 Sofia Papagiannaki
                             # (account or container).
1630 b9064632 Antony Chazapis
            size = src_size
1631 66ce2ca5 Antony Chazapis
        if type is None:
1632 66ce2ca5 Antony Chazapis
            type = src_type
1633 33b4e4a6 Antony Chazapis
        if checksum is None:
1634 33b4e4a6 Antony Chazapis
            checksum = src_checksum
1635 2715ade4 Sofia Papagiannaki
        uuid = self._generate_uuid(
1636 2715ade4 Sofia Papagiannaki
        ) if (is_copy or src_version_id is None) else props[self.UUID]
1637 2715ade4 Sofia Papagiannaki
1638 1730b3bf chazapis
        if src_node is None:
1639 1730b3bf chazapis
            pre_version_id = src_version_id
1640 1730b3bf chazapis
        else:
1641 1730b3bf chazapis
            pre_version_id = None
1642 1730b3bf chazapis
            props = self.node.version_lookup(node, inf, CLUSTER_NORMAL)
1643 1730b3bf chazapis
            if props is not None:
1644 1730b3bf chazapis
                pre_version_id = props[self.SERIAL]
1645 1730b3bf chazapis
        if pre_version_id is not None:
1646 0f510652 Sofia Papagiannaki
            self.node.version_recluster(pre_version_id, CLUSTER_HISTORY,
1647 0f510652 Sofia Papagiannaki
                                        update_statistics_ancestors_depth)
1648 2715ade4 Sofia Papagiannaki
1649 0f510652 Sofia Papagiannaki
        dest_version_id, mtime = self.node.version_create(
1650 0f510652 Sofia Papagiannaki
            node, hash, size, type, src_version_id, user, uuid, checksum,
1651 0f510652 Sofia Papagiannaki
            cluster, update_statistics_ancestors_depth)
1652 ad9ada51 Sofia Papagiannaki
1653 ad9ada51 Sofia Papagiannaki
        self.node.attribute_unset_is_latest(node, dest_version_id)
1654 ad9ada51 Sofia Papagiannaki
1655 1730b3bf chazapis
        return pre_version_id, dest_version_id
1656 2715ade4 Sofia Papagiannaki
1657 ad9ada51 Sofia Papagiannaki
    def _put_metadata_duplicate(self, src_version_id, dest_version_id, domain,
1658 ad9ada51 Sofia Papagiannaki
                                node, meta, replace=False):
1659 4819d34f Antony Chazapis
        if src_version_id is not None:
1660 4819d34f Antony Chazapis
            self.node.attribute_copy(src_version_id, dest_version_id)
1661 4819d34f Antony Chazapis
        if not replace:
1662 2715ade4 Sofia Papagiannaki
            self.node.attribute_del(dest_version_id, domain, (
1663 2715ade4 Sofia Papagiannaki
                k for k, v in meta.iteritems() if v == ''))
1664 ad9ada51 Sofia Papagiannaki
            self.node.attribute_set(dest_version_id, domain, node, (
1665 2715ade4 Sofia Papagiannaki
                (k, v) for k, v in meta.iteritems() if v != ''))
1666 4819d34f Antony Chazapis
        else:
1667 4819d34f Antony Chazapis
            self.node.attribute_del(dest_version_id, domain)
1668 ad9ada51 Sofia Papagiannaki
            self.node.attribute_set(dest_version_id, domain, node, ((
1669 2715ade4 Sofia Papagiannaki
                k, v) for k, v in meta.iteritems()))
1670 2715ade4 Sofia Papagiannaki
1671 0f510652 Sofia Papagiannaki
    def _put_metadata(self, user, node, domain, meta, replace=False,
1672 0f510652 Sofia Papagiannaki
                      update_statistics_ancestors_depth=None):
1673 44ad5860 Antony Chazapis
        """Create a new version and store metadata."""
1674 2715ade4 Sofia Papagiannaki
1675 2715ade4 Sofia Papagiannaki
        src_version_id, dest_version_id = self._put_version_duplicate(
1676 0f510652 Sofia Papagiannaki
            user, node,
1677 29148653 Sofia Papagiannaki
            update_statistics_ancestors_depth=
1678 29148653 Sofia Papagiannaki
            update_statistics_ancestors_depth)
1679 2715ade4 Sofia Papagiannaki
        self._put_metadata_duplicate(
1680 ad9ada51 Sofia Papagiannaki
            src_version_id, dest_version_id, domain, node, meta, replace)
1681 5cc484e1 Antony Chazapis
        return src_version_id, dest_version_id
1682 2715ade4 Sofia Papagiannaki
1683 60b8a083 Antony Chazapis
    def _list_limits(self, listing, marker, limit):
1684 60b8a083 Antony Chazapis
        start = 0
1685 60b8a083 Antony Chazapis
        if marker:
1686 60b8a083 Antony Chazapis
            try:
1687 60b8a083 Antony Chazapis
                start = listing.index(marker) + 1
1688 60b8a083 Antony Chazapis
            except ValueError:
1689 60b8a083 Antony Chazapis
                pass
1690 60b8a083 Antony Chazapis
        if not limit or limit > 10000:
1691 60b8a083 Antony Chazapis
            limit = 10000
1692 60b8a083 Antony Chazapis
        return start, limit
1693 2715ade4 Sofia Papagiannaki
1694 29148653 Sofia Papagiannaki
    def _list_object_properties(self, parent, path, prefix='', delimiter=None,
1695 29148653 Sofia Papagiannaki
                                marker=None, limit=10000, virtual=True,
1696 29148653 Sofia Papagiannaki
                                domain=None, keys=None, until=None,
1697 29148653 Sofia Papagiannaki
                                size_range=None, allowed=None,
1698 29148653 Sofia Papagiannaki
                                all_props=False):
1699 78348987 Sofia Papagiannaki
        keys = keys or []
1700 78348987 Sofia Papagiannaki
        allowed = allowed or []
1701 60b8a083 Antony Chazapis
        cont_prefix = path + '/'
1702 60b8a083 Antony Chazapis
        prefix = cont_prefix + prefix
1703 60b8a083 Antony Chazapis
        start = cont_prefix + marker if marker else None
1704 60b8a083 Antony Chazapis
        before = until if until is not None else inf
1705 4819d34f Antony Chazapis
        filterq = keys if domain else []
1706 7ff57991 Antony Chazapis
        sizeq = size_range
1707 2715ade4 Sofia Papagiannaki
1708 29148653 Sofia Papagiannaki
        objects, prefixes = self.node.latest_version_list(
1709 29148653 Sofia Papagiannaki
            parent, prefix, delimiter, start, limit, before, CLUSTER_DELETED,
1710 29148653 Sofia Papagiannaki
            allowed, domain, filterq, sizeq, all_props)
1711 60b8a083 Antony Chazapis
        objects.extend([(p, None) for p in prefixes] if virtual else [])
1712 43be9afd Sofia Papagiannaki
        objects.sort(key=lambda x: x[0])
1713 371d907a Antony Chazapis
        objects = [(x[0][len(cont_prefix):],) + x[1:] for x in objects]
1714 cf4a7a7b Sofia Papagiannaki
        return objects
1715 2715ade4 Sofia Papagiannaki
1716 813e42e5 Antony Chazapis
    # Reporting functions.
1717 2715ade4 Sofia Papagiannaki
1718 1f96b68d Sofia Papagiannaki
    @debug_method
1719 5d022141 Sofia Papagiannaki
    @backend_method
1720 78e1f8da Sofia Papagiannaki
    def _report_size_change(self, user, account, size, source, details=None):
1721 78348987 Sofia Papagiannaki
        details = details or {}
1722 78348987 Sofia Papagiannaki
1723 8ed3f04c Sofia Papagiannaki
        if size == 0:
1724 8ed3f04c Sofia Papagiannaki
            return
1725 8ed3f04c Sofia Papagiannaki
1726 813e42e5 Antony Chazapis
        account_node = self._lookup_account(account, True)[1]
1727 2e8edd42 Sofia Papagiannaki
        total = self._get_statistics(account_node, compute=True)[1]
1728 813e42e5 Antony Chazapis
        details.update({'user': user, 'total': total})
1729 29148653 Sofia Papagiannaki
        self.messages.append(
1730 29148653 Sofia Papagiannaki
            (QUEUE_MESSAGE_KEY_PREFIX % ('resource.diskspace',),
1731 29148653 Sofia Papagiannaki
             account, QUEUE_INSTANCE_ID, 'diskspace', float(size), details))
1732 7ed99da8 root
1733 c846fad1 Sofia Papagiannaki
        if not self.using_external_quotaholder:
1734 73fbe301 Sofia Papagiannaki
            return
1735 7f1f0464 Georgios D. Tsoukalas
1736 ccfd4e44 Sofia Papagiannaki
        try:
1737 b17e5550 Giorgos Korfiatis
            name = details['path'] if 'path' in details else ''
1738 16f2673e Sofia Papagiannaki
            serial = self.astakosclient.issue_one_commission(
1739 b17e5550 Giorgos Korfiatis
                holder=account,
1740 78e1f8da Sofia Papagiannaki
                source=source,
1741 b17e5550 Giorgos Korfiatis
                provisions={'pithos.diskspace': size},
1742 29148653 Sofia Papagiannaki
                name=name)
1743 ccfd4e44 Sofia Papagiannaki
        except BaseException, e:
1744 ccfd4e44 Sofia Papagiannaki
            raise QuotaError(e)
1745 ccfd4e44 Sofia Papagiannaki
        else:
1746 ccfd4e44 Sofia Papagiannaki
            self.serials.append(serial)
1747 0307b47f Georgios D. Tsoukalas
1748 1f96b68d Sofia Papagiannaki
    @debug_method
1749 5d022141 Sofia Papagiannaki
    @backend_method
1750 78348987 Sofia Papagiannaki
    def _report_object_change(self, user, account, path, details=None):
1751 78348987 Sofia Papagiannaki
        details = details or {}
1752 b82d3277 Sofia Papagiannaki
        details.update({'user': user})
1753 f4fbb0fa Sofia Papagiannaki
        self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('object',),
1754 29148653 Sofia Papagiannaki
                              account, QUEUE_INSTANCE_ID, 'object', path,
1755 29148653 Sofia Papagiannaki
                              details))
1756 2715ade4 Sofia Papagiannaki
1757 1f96b68d Sofia Papagiannaki
    @debug_method
1758 5d022141 Sofia Papagiannaki
    @backend_method
1759 78348987 Sofia Papagiannaki
    def _report_sharing_change(self, user, account, path, details=None):
1760 78348987 Sofia Papagiannaki
        details = details or {}
1761 a74ba506 Sofia Papagiannaki
        details.update({'user': user})
1762 f4fbb0fa Sofia Papagiannaki
        self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('sharing',),
1763 29148653 Sofia Papagiannaki
                              account, QUEUE_INSTANCE_ID, 'sharing', path,
1764 29148653 Sofia Papagiannaki
                              details))
1765 2715ade4 Sofia Papagiannaki
1766 60b8a083 Antony Chazapis
    # Policy functions.
1767 2715ade4 Sofia Papagiannaki
1768 78e1f8da Sofia Papagiannaki
    def _check_project(self, value):
1769 78e1f8da Sofia Papagiannaki
        # raise ValueError('Bad quota source policy')
1770 78e1f8da Sofia Papagiannaki
        pass
1771 78e1f8da Sofia Papagiannaki
1772 78e1f8da Sofia Papagiannaki
    def _check_policy(self, policy):
1773 60b8a083 Antony Chazapis
        for k, v in policy.iteritems():
1774 78e1f8da Sofia Papagiannaki
            if k == QUOTA_POLICY:
1775 2715ade4 Sofia Papagiannaki
                q = int(v)  # May raise ValueError.
1776 60b8a083 Antony Chazapis
                if q < 0:
1777 60b8a083 Antony Chazapis
                    raise ValueError
1778 78e1f8da Sofia Papagiannaki
            elif k == VERSIONING_POLICY:
1779 5cc484e1 Antony Chazapis
                if v not in ['auto', 'none']:
1780 60b8a083 Antony Chazapis
                    raise ValueError
1781 78e1f8da Sofia Papagiannaki
            elif k == PROJECT:
1782 78e1f8da Sofia Papagiannaki
                self._check_project(v)
1783 60b8a083 Antony Chazapis
            else:
1784 60b8a083 Antony Chazapis
                raise ValueError
1785 2715ade4 Sofia Papagiannaki
1786 78e1f8da Sofia Papagiannaki
    def _get_default_policy(self, node=None, is_account_policy=True,
1787 78e1f8da Sofia Papagiannaki
                            default_project=None):
1788 78e1f8da Sofia Papagiannaki
        if is_account_policy:
1789 78e1f8da Sofia Papagiannaki
            default_policy = self.default_account_policy
1790 78e1f8da Sofia Papagiannaki
        else:
1791 78e1f8da Sofia Papagiannaki
            default_policy = self.default_container_policy
1792 78e1f8da Sofia Papagiannaki
            if default_project is None and node is not None:
1793 78e1f8da Sofia Papagiannaki
                # set container's account as the default quota source
1794 78e1f8da Sofia Papagiannaki
                default_project = self.node.node_get_parent_path(node)
1795 78e1f8da Sofia Papagiannaki
            default_policy[PROJECT] = default_project
1796 78e1f8da Sofia Papagiannaki
        return default_policy
1797 78e1f8da Sofia Papagiannaki
1798 78e1f8da Sofia Papagiannaki
    def _put_policy(self, node, policy, replace,
1799 78e1f8da Sofia Papagiannaki
                    is_account_policy=True, default_project=None,
1800 78e1f8da Sofia Papagiannaki
                    check=True):
1801 78e1f8da Sofia Papagiannaki
        default_policy = self._get_default_policy(node,
1802 78e1f8da Sofia Papagiannaki
                                                  is_account_policy,
1803 78e1f8da Sofia Papagiannaki
                                                  default_project)
1804 b2832c6a Antony Chazapis
        if replace:
1805 19ddd41b Sofia Papagiannaki
            for k, v in default_policy.iteritems():
1806 b2832c6a Antony Chazapis
                if k not in policy:
1807 b2832c6a Antony Chazapis
                    policy[k] = v
1808 78e1f8da Sofia Papagiannaki
        if check:
1809 78e1f8da Sofia Papagiannaki
            self._check_policy(policy)
1810 78e1f8da Sofia Papagiannaki
1811 b2832c6a Antony Chazapis
        self.node.policy_set(node, policy)
1812 2715ade4 Sofia Papagiannaki
1813 78e1f8da Sofia Papagiannaki
    def _get_policy(self, node, is_account_policy=True,
1814 78e1f8da Sofia Papagiannaki
                    default_project=None):
1815 78e1f8da Sofia Papagiannaki
        default_policy = self._get_default_policy(node,
1816 78e1f8da Sofia Papagiannaki
                                                  is_account_policy,
1817 78e1f8da Sofia Papagiannaki
                                                  default_project)
1818 19ddd41b Sofia Papagiannaki
        policy = default_policy.copy()
1819 b9064632 Antony Chazapis
        policy.update(self.node.policy_get(node))
1820 b9064632 Antony Chazapis
        return policy
1821 2715ade4 Sofia Papagiannaki
1822 78e1f8da Sofia Papagiannaki
    def _get_project(self, node):
1823 78e1f8da Sofia Papagiannaki
        policy = self._get_policy(node, is_account_policy=False)
1824 78e1f8da Sofia Papagiannaki
        return policy[PROJECT]
1825 78e1f8da Sofia Papagiannaki
1826 0f510652 Sofia Papagiannaki
    def _apply_versioning(self, account, container, version_id,
1827 0f510652 Sofia Papagiannaki
                          update_statistics_ancestors_depth=None):
1828 813e42e5 Antony Chazapis
        """Delete the provided version if such is the policy.
1829 813e42e5 Antony Chazapis
           Return size of object removed.
1830 813e42e5 Antony Chazapis
        """
1831 2715ade4 Sofia Papagiannaki
1832 5cc484e1 Antony Chazapis
        if version_id is None:
1833 813e42e5 Antony Chazapis
            return 0
1834 5cc484e1 Antony Chazapis
        path, node = self._lookup_container(account, container)
1835 19ddd41b Sofia Papagiannaki
        versioning = self._get_policy(
1836 78e1f8da Sofia Papagiannaki
            node, is_account_policy=False)[VERSIONING_POLICY]
1837 1dd34bdd Sofia Papagiannaki
        if versioning != 'auto':
1838 0f510652 Sofia Papagiannaki
            hash, size = self.node.version_remove(
1839 0f510652 Sofia Papagiannaki
                version_id, update_statistics_ancestors_depth)
1840 5161c672 Antony Chazapis
            self.store.map_delete(hash)
1841 813e42e5 Antony Chazapis
            return size
1842 1dd34bdd Sofia Papagiannaki
        elif self.free_versioning:
1843 fff37615 Sofia Papagiannaki
            return self.node.version_get_properties(
1844 fff37615 Sofia Papagiannaki
                version_id, keys=('size',))[0]
1845 813e42e5 Antony Chazapis
        return 0
1846 2715ade4 Sofia Papagiannaki
1847 a9b3f29d Antony Chazapis
    # Access control functions.
1848 2715ade4 Sofia Papagiannaki
1849 a9b3f29d Antony Chazapis
    def _check_groups(self, groups):
1850 0f9d752c Antony Chazapis
        # raise ValueError('Bad characters in groups')
1851 a9b3f29d Antony Chazapis
        pass
1852 2715ade4 Sofia Papagiannaki
1853 a9b3f29d Antony Chazapis
    def _check_permissions(self, path, permissions):
1854 0f9d752c Antony Chazapis
        # raise ValueError('Bad characters in permissions')
1855 5e068361 Antony Chazapis
        pass
1856 2715ade4 Sofia Papagiannaki
1857 dc88754b Nanakos Chrysostomos
    def _get_formatted_paths(self, paths):
1858 dc88754b Nanakos Chrysostomos
        formatted = []
1859 ace7592b Sofia Papagiannaki
        if len(paths) == 0:
1860 dc88754b Nanakos Chrysostomos
            return formatted
1861 dc88754b Nanakos Chrysostomos
        props = self.node.get_props(paths)
1862 dc88754b Nanakos Chrysostomos
        if props:
1863 dc88754b Nanakos Chrysostomos
            for prop in props:
1864 dc88754b Nanakos Chrysostomos
                if prop[1].split(';', 1)[0].strip() in (
1865 dc88754b Nanakos Chrysostomos
                        'application/directory', 'application/folder'):
1866 ace7592b Sofia Papagiannaki
                    formatted.append((prop[0].rstrip('/') + '/',
1867 ace7592b Sofia Papagiannaki
                                      self.MATCH_PREFIX))
1868 dc88754b Nanakos Chrysostomos
                formatted.append((prop[0], self.MATCH_EXACT))
1869 dc88754b Nanakos Chrysostomos
        return formatted
1870 dc88754b Nanakos Chrysostomos
1871 16b0ed4a Nanakos Chrysostomos
    def _get_permissions_path(self, account, container, name):
1872 16b0ed4a Nanakos Chrysostomos
        path = '/'.join((account, container, name))
1873 16b0ed4a Nanakos Chrysostomos
        permission_paths = self.permissions.access_inherit(path)
1874 16b0ed4a Nanakos Chrysostomos
        permission_paths.sort()
1875 16b0ed4a Nanakos Chrysostomos
        permission_paths.reverse()
1876 16b0ed4a Nanakos Chrysostomos
        for p in permission_paths:
1877 16b0ed4a Nanakos Chrysostomos
            if p == path:
1878 16b0ed4a Nanakos Chrysostomos
                return p
1879 16b0ed4a Nanakos Chrysostomos
            else:
1880 16b0ed4a Nanakos Chrysostomos
                if p.count('/') < 2:
1881 16b0ed4a Nanakos Chrysostomos
                    continue
1882 16b0ed4a Nanakos Chrysostomos
                node = self.node.node_lookup(p)
1883 16b0ed4a Nanakos Chrysostomos
                props = None
1884 16b0ed4a Nanakos Chrysostomos
                if node is not None:
1885 16b0ed4a Nanakos Chrysostomos
                    props = self.node.version_lookup(node, inf, CLUSTER_NORMAL)
1886 16b0ed4a Nanakos Chrysostomos
                if props is not None:
1887 ace7592b Sofia Papagiannaki
                    if props[self.TYPE].split(';', 1)[0].strip() in (
1888 ace7592b Sofia Papagiannaki
                            'application/directory', 'application/folder'):
1889 16b0ed4a Nanakos Chrysostomos
                        return p
1890 16b0ed4a Nanakos Chrysostomos
        return None
1891 16b0ed4a Nanakos Chrysostomos
1892 dc88754b Nanakos Chrysostomos
    def _get_permissions_path_bulk(self, account, container, names):
1893 dc88754b Nanakos Chrysostomos
        formatted_paths = []
1894 dc88754b Nanakos Chrysostomos
        for name in names:
1895 dc88754b Nanakos Chrysostomos
            path = '/'.join((account, container, name))
1896 dc88754b Nanakos Chrysostomos
            formatted_paths.append(path)
1897 ace7592b Sofia Papagiannaki
        permission_paths = self.permissions.access_inherit_bulk(
1898 ace7592b Sofia Papagiannaki
            formatted_paths)
1899 5e068361 Antony Chazapis
        permission_paths.sort()
1900 5e068361 Antony Chazapis
        permission_paths.reverse()
1901 dc88754b Nanakos Chrysostomos
        permission_paths_list = []
1902 dc88754b Nanakos Chrysostomos
        lookup_list = []
1903 5e068361 Antony Chazapis
        for p in permission_paths:
1904 dc88754b Nanakos Chrysostomos
            if p in formatted_paths:
1905 dc88754b Nanakos Chrysostomos
                permission_paths_list.append(p)
1906 5e068361 Antony Chazapis
            else:
1907 71dbc012 Antony Chazapis
                if p.count('/') < 2:
1908 71dbc012 Antony Chazapis
                    continue
1909 dc88754b Nanakos Chrysostomos
                lookup_list.append(p)
1910 dc88754b Nanakos Chrysostomos
1911 dc88754b Nanakos Chrysostomos
        if len(lookup_list) > 0:
1912 62e6d12e Nanakos Chrysostomos
            props = self.node.get_props(lookup_list)
1913 dc88754b Nanakos Chrysostomos
            if props:
1914 dc88754b Nanakos Chrysostomos
                for prop in props:
1915 dc88754b Nanakos Chrysostomos
                    if prop[1].split(';', 1)[0].strip() in (
1916 29148653 Sofia Papagiannaki
                            'application/directory', 'application/folder'):
1917 e161c24f Sofia Papagiannaki
                        permission_paths_list.append(prop[0])
1918 dc88754b Nanakos Chrysostomos
1919 dc88754b Nanakos Chrysostomos
        if len(permission_paths_list) > 0:
1920 dc88754b Nanakos Chrysostomos
            return permission_paths_list
1921 dc88754b Nanakos Chrysostomos
1922 5e068361 Antony Chazapis
        return None
1923 2715ade4 Sofia Papagiannaki
1924 ebdbac7a Sofia Papagiannaki
    def _reset_allowed_paths(self):
1925 ebdbac7a Sofia Papagiannaki
        self.read_allowed_paths = defaultdict(set)
1926 ebdbac7a Sofia Papagiannaki
        self.write_allowed_paths = defaultdict(set)
1927 ebdbac7a Sofia Papagiannaki
1928 ebdbac7a Sofia Papagiannaki
    @check_allowed_paths(action=0)
1929 ebdbac7a Sofia Papagiannaki
    def _can_read_account(self, user, account):
1930 ebdbac7a Sofia Papagiannaki
        if user != account:
1931 ebdbac7a Sofia Papagiannaki
            if account not in self._allowed_accounts(user):
1932 ebdbac7a Sofia Papagiannaki
                raise NotAllowedError
1933 ebdbac7a Sofia Papagiannaki
1934 ebdbac7a Sofia Papagiannaki
    @check_allowed_paths(action=1)
1935 ebdbac7a Sofia Papagiannaki
    def _can_write_account(self, user, account):
1936 ebdbac7a Sofia Papagiannaki
        if user != account:
1937 ebdbac7a Sofia Papagiannaki
            raise NotAllowedError
1938 ebdbac7a Sofia Papagiannaki
1939 ebdbac7a Sofia Papagiannaki
    @check_allowed_paths(action=0)
1940 ebdbac7a Sofia Papagiannaki
    def _can_read_container(self, user, account, container):
1941 ebdbac7a Sofia Papagiannaki
        if user != account:
1942 ebdbac7a Sofia Papagiannaki
            if container not in self._allowed_containers(user, account):
1943 ebdbac7a Sofia Papagiannaki
                raise NotAllowedError
1944 ebdbac7a Sofia Papagiannaki
1945 ebdbac7a Sofia Papagiannaki
    @check_allowed_paths(action=1)
1946 ebdbac7a Sofia Papagiannaki
    def _can_write_container(self, user, account, container):
1947 ebdbac7a Sofia Papagiannaki
        if user != account:
1948 ebdbac7a Sofia Papagiannaki
            raise NotAllowedError
1949 ebdbac7a Sofia Papagiannaki
1950 ebdbac7a Sofia Papagiannaki
    @check_allowed_paths(action=0)
1951 ebdbac7a Sofia Papagiannaki
    def _can_read_object(self, user, account, container, name):
1952 a9b3f29d Antony Chazapis
        if user == account:
1953 a9b3f29d Antony Chazapis
            return True
1954 a9b3f29d Antony Chazapis
        path = '/'.join((account, container, name))
1955 aeb2b64f Antony Chazapis
        if self.permissions.public_get(path) is not None:
1956 71dbc012 Antony Chazapis
            return True
1957 5e068361 Antony Chazapis
        path = self._get_permissions_path(account, container, name)
1958 71dbc012 Antony Chazapis
        if not path:
1959 71dbc012 Antony Chazapis
            raise NotAllowedError
1960 29148653 Sofia Papagiannaki
        if (not self.permissions.access_check(path, self.READ, user) and not
1961 29148653 Sofia Papagiannaki
                self.permissions.access_check(path, self.WRITE, user)):
1962 a9b3f29d Antony Chazapis
            raise NotAllowedError
1963 2715ade4 Sofia Papagiannaki
1964 ebdbac7a Sofia Papagiannaki
    @check_allowed_paths(action=1)
1965 ebdbac7a Sofia Papagiannaki
    def _can_write_object(self, user, account, container, name):
1966 6f4bce7b Antony Chazapis
        if user == account:
1967 6f4bce7b Antony Chazapis
            return True
1968 6f4bce7b Antony Chazapis
        path = '/'.join((account, container, name))
1969 71dbc012 Antony Chazapis
        path = self._get_permissions_path(account, container, name)
1970 71dbc012 Antony Chazapis
        if not path:
1971 71dbc012 Antony Chazapis
            raise NotAllowedError
1972 2c5363a0 Antony Chazapis
        if not self.permissions.access_check(path, self.WRITE, user):
1973 a9b3f29d Antony Chazapis
            raise NotAllowedError
1974 2715ade4 Sofia Papagiannaki
1975 a9b3f29d Antony Chazapis
    def _allowed_accounts(self, user):
1976 a9b3f29d Antony Chazapis
        allow = set()
1977 0f9d752c Antony Chazapis
        for path in self.permissions.access_list_paths(user):
1978 ebdbac7a Sofia Papagiannaki
            p = path.split('/', 1)[0]
1979 ebdbac7a Sofia Papagiannaki
            allow.add(p)
1980 ebdbac7a Sofia Papagiannaki
        self.read_allowed_paths[user] |= allow
1981 a9b3f29d Antony Chazapis
        return sorted(allow)
1982 2715ade4 Sofia Papagiannaki
1983 a9b3f29d Antony Chazapis
    def _allowed_containers(self, user, account):
1984 a9b3f29d Antony Chazapis
        allow = set()
1985 0f9d752c Antony Chazapis
        for path in self.permissions.access_list_paths(user, account):
1986 ebdbac7a Sofia Papagiannaki
            p = path.split('/', 2)[1]
1987 ebdbac7a Sofia Papagiannaki
            allow.add(p)
1988 ebdbac7a Sofia Papagiannaki
        self.read_allowed_paths[user] |= allow
1989 a9b3f29d Antony Chazapis
        return sorted(allow)
1990 5576e6dd Sofia Papagiannaki
1991 5576e6dd Sofia Papagiannaki
    # Domain functions
1992 5576e6dd Sofia Papagiannaki
1993 1f96b68d Sofia Papagiannaki
    @debug_method
1994 5d022141 Sofia Papagiannaki
    @backend_method
1995 e77b7a99 Sofia Papagiannaki
    def get_domain_objects(self, domain, user=None):
1996 a63f36a2 Sofia Papagiannaki
        allowed_paths = self.permissions.access_list_paths(
1997 a63f36a2 Sofia Papagiannaki
            user, include_owned=user is not None, include_containers=False)
1998 7736e11a Sofia Papagiannaki
        if not allowed_paths:
1999 7736e11a Sofia Papagiannaki
            return []
2000 7736e11a Sofia Papagiannaki
        obj_list = self.node.domain_object_list(
2001 7736e11a Sofia Papagiannaki
            domain, allowed_paths, CLUSTER_NORMAL)
2002 5576e6dd Sofia Papagiannaki
        return [(path,
2003 5576e6dd Sofia Papagiannaki
                 self._build_metadata(props, user_defined_meta),
2004 7736e11a Sofia Papagiannaki
                 self.permissions.access_get(path)) for
2005 7736e11a Sofia Papagiannaki
                path, props, user_defined_meta in obj_list]
2006 5576e6dd Sofia Papagiannaki
2007 5576e6dd Sofia Papagiannaki
    # util functions
2008 5576e6dd Sofia Papagiannaki
2009 5576e6dd Sofia Papagiannaki
    def _build_metadata(self, props, user_defined=None,
2010 5576e6dd Sofia Papagiannaki
                        include_user_defined=True):
2011 5576e6dd Sofia Papagiannaki
        meta = {'bytes': props[self.SIZE],
2012 5576e6dd Sofia Papagiannaki
                'type': props[self.TYPE],
2013 5576e6dd Sofia Papagiannaki
                'hash': props[self.HASH],
2014 5576e6dd Sofia Papagiannaki
                'version': props[self.SERIAL],
2015 5576e6dd Sofia Papagiannaki
                'version_timestamp': props[self.MTIME],
2016 5576e6dd Sofia Papagiannaki
                'modified_by': props[self.MUSER],
2017 5576e6dd Sofia Papagiannaki
                'uuid': props[self.UUID],
2018 5576e6dd Sofia Papagiannaki
                'checksum': props[self.CHECKSUM]}
2019 29148653 Sofia Papagiannaki
        if include_user_defined and user_defined is not None:
2020 5576e6dd Sofia Papagiannaki
            meta.update(user_defined)
2021 5576e6dd Sofia Papagiannaki
        return meta
2022 5576e6dd Sofia Papagiannaki
2023 33af031c Sofia Papagiannaki
    def _exists(self, node):
2024 33af031c Sofia Papagiannaki
        try:
2025 33af031c Sofia Papagiannaki
            self._get_version(node)
2026 33af031c Sofia Papagiannaki
        except ItemNotExists:
2027 33af031c Sofia Papagiannaki
            return False
2028 33af031c Sofia Papagiannaki
        else:
2029 33af031c Sofia Papagiannaki
            return True
2030 3a5994a8 Sofia Papagiannaki
2031 3a5994a8 Sofia Papagiannaki
    def _unhexlify_hash(self, hash):
2032 3a5994a8 Sofia Papagiannaki
        try:
2033 3a5994a8 Sofia Papagiannaki
            return binascii.unhexlify(hash)
2034 3a5994a8 Sofia Papagiannaki
        except TypeError:
2035 3a5994a8 Sofia Papagiannaki
            raise InvalidHash(hash)