1 # Copyright 2011 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
11 # 2. Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following
13 # disclaimer in the documentation and/or other materials
14 # provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
34 class NotAllowedError(Exception):
37 class BaseBackend(object):
38 """Abstract backend class that serves as a reference for actual implementations.
40 The purpose of the backend is to provide the necessary functions for handling data
41 and metadata. It is responsible for the actual storage and retrieval of information.
43 Note that the account level is always valid as it is checked from another subsystem.
45 When not replacing metadata/groups/policy, keys with empty values should be deleted.
47 The following variables should be available:
48 'hash_algorithm': Suggested is 'sha256'
50 'block_size': Suggested is 4MB
53 def list_accounts(self, user, marker=None, limit=10000):
54 """Return a list of accounts the user can access.
57 'marker': Start list from the next item after 'marker'
59 'limit': Number of containers to return
63 def get_account_meta(self, user, account, until=None):
64 """Return a dictionary with the account metadata.
66 The keys returned are all user-defined, except:
67 'name': The account name
69 'count': The number of containers (or 0)
71 'bytes': The total data size (or 0)
73 'modified': Last modification timestamp (overall)
75 'until_timestamp': Last modification until the timestamp provided
78 NotAllowedError: Operation not permitted
82 def update_account_meta(self, user, account, meta, replace=False):
83 """Update the metadata associated with the account.
86 'meta': Dictionary with metadata to update
88 'replace': Replace instead of update
91 NotAllowedError: Operation not permitted
95 def get_account_groups(self, user, account):
96 """Return a dictionary with the user groups defined for this account.
99 NotAllowedError: Operation not permitted
103 def update_account_groups(self, user, account, groups, replace=False):
104 """Update the groups associated with the account.
107 NotAllowedError: Operation not permitted
109 ValueError: Invalid data in groups
113 def put_account(self, user, account):
114 """Create a new account with the given name.
117 NotAllowedError: Operation not permitted
121 def delete_account(self, user, account):
122 """Delete the account with the given name.
125 NotAllowedError: Operation not permitted
127 IndexError: Account is not empty
131 def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
132 """Return a list of container names existing under an account.
135 'marker': Start list from the next item after 'marker'
137 'limit': Number of containers to return
139 'shared': Only list containers with permissions set
143 NotAllowedError: Operation not permitted
147 def get_container_meta(self, user, account, container, until=None):
148 """Return a dictionary with the container metadata.
150 The keys returned are all user-defined, except:
151 'name': The container name
153 'count': The number of objects
155 'bytes': The total data size
157 'modified': Last modification timestamp (overall)
159 'until_timestamp': Last modification until the timestamp provided
162 NotAllowedError: Operation not permitted
164 NameError: Container does not exist
168 def update_container_meta(self, user, account, container, meta, replace=False):
169 """Update the metadata associated with the container.
172 'meta': Dictionary with metadata to update
174 'replace': Replace instead of update
177 NotAllowedError: Operation not permitted
179 NameError: Container does not exist
183 def get_container_policy(self, user, account, container):
184 """Return a dictionary with the container policy.
186 The keys returned are:
187 'quota': The maximum bytes allowed (default is 0 - unlimited)
189 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
192 NotAllowedError: Operation not permitted
194 NameError: Container does not exist
198 def update_container_policy(self, user, account, container, policy, replace=False):
199 """Update the policy associated with the account.
202 NotAllowedError: Operation not permitted
204 NameError: Container does not exist
206 ValueError: Invalid policy defined
210 def put_container(self, user, account, container, policy=None):
211 """Create a new container with the given name.
214 NotAllowedError: Operation not permitted
216 NameError: Container already exists
218 ValueError: Invalid policy defined
222 def delete_container(self, user, account, container, until=None):
223 """Delete/purge the container with the given name.
226 NotAllowedError: Operation not permitted
228 NameError: Container does not exist
230 IndexError: Container is not empty
234 def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
235 """Return a list of object (name, version_id) tuples existing under a container.
238 'prefix': List objects starting with 'prefix'
240 'delimiter': Return unique names before 'delimiter' and after 'prefix'
242 'marker': Start list from the next item after 'marker'
244 'limit': Number of objects to return
246 'virtual': If not set, the result will only include names starting
247 with 'prefix' and ending without a 'delimiter' or with
248 the first occurance of the 'delimiter' after 'prefix'.
249 If set, the result will include all names after 'prefix',
250 up to and including the 'delimiter' if it is found
252 'keys': Include objects that have meta with the keys in the list
254 'shared': Only list objects with permissions set
257 NotAllowedError: Operation not permitted
259 NameError: Container does not exist
263 def list_object_meta(self, user, account, container, until=None):
264 """Return a list with all the container's object meta keys.
267 NotAllowedError: Operation not permitted
269 NameError: Container does not exist
273 def get_object_meta(self, user, account, container, name, version=None):
274 """Return a dictionary with the object metadata.
276 The keys returned are all user-defined, except:
277 'name': The object name
279 'bytes': The total data size
281 'modified': Last modification timestamp (overall)
283 'modified_by': The user that committed the object (version requested)
285 'version': The version identifier
287 'version_timestamp': The version's modification timestamp
290 NotAllowedError: Operation not permitted
292 NameError: Container/object does not exist
294 IndexError: Version does not exist
298 def update_object_meta(self, user, account, container, name, meta, replace=False):
299 """Update the metadata associated with the object and return the new version.
302 'meta': Dictionary with metadata to update
304 'replace': Replace instead of update
307 NotAllowedError: Operation not permitted
309 NameError: Container/object does not exist
313 def get_object_permissions(self, user, account, container, name):
314 """Return the action allowed on the object, the path
315 from which the object gets its permissions from,
316 along with a dictionary containing the permissions.
318 The dictionary keys are (also used for defining the action):
319 'read': The object is readable by the users/groups in the list
321 'write': The object is writable by the users/groups in the list
324 NotAllowedError: Operation not permitted
326 NameError: Container/object does not exist
330 def update_object_permissions(self, user, account, container, name, permissions):
331 """Update the permissions associated with the object.
334 'permissions': Dictionary with permissions to update
337 NotAllowedError: Operation not permitted
339 NameError: Container/object does not exist
341 ValueError: Invalid users/groups in permissions
343 AttributeError: Can not set permissions, as this object
344 is already shared/private by another object higher
345 in the hierarchy, or setting permissions here will
346 invalidate other permissions deeper in the hierarchy
350 def get_object_public(self, user, account, container, name):
351 """Return the public URL of the object if applicable.
354 NotAllowedError: Operation not permitted
356 NameError: Container/object does not exist
360 def update_object_public(self, user, account, container, name, public):
361 """Update the public status of the object.
364 'public': Boolean value
367 NotAllowedError: Operation not permitted
369 NameError: Container/object does not exist
373 def get_object_hashmap(self, user, account, container, name, version=None):
374 """Return the object's size and a list with partial hashes.
377 NotAllowedError: Operation not permitted
379 NameError: Container/object does not exist
381 IndexError: Version does not exist
385 def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions=None):
386 """Create/update an object with the specified size and partial hashes and return the new version.
389 'dest_meta': Dictionary with metadata to change
391 'replace_meta': Replace metadata instead of update
393 'permissions': Updated object permissions
396 NotAllowedError: Operation not permitted
398 NameError: Container does not exist
400 ValueError: Invalid users/groups in permissions
402 AttributeError: Can not set permissions
406 def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None, src_version=None):
407 """Copy an object's data and metadata and return the new version.
410 'dest_meta': Dictionary with metadata to change from source to destination
412 'replace_meta': Replace metadata instead of update
414 'permissions': New object permissions
416 'src_version': Copy from the version provided
419 NotAllowedError: Operation not permitted
421 NameError: Container/object does not exist
423 IndexError: Version does not exist
425 ValueError: Invalid users/groups in permissions
427 AttributeError: Can not set permissions
431 def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
432 """Move an object's data and metadata and return the new version.
435 'dest_meta': Dictionary with metadata to change from source to destination
437 'replace_meta': Replace metadata instead of update
439 'permissions': New object permissions
442 NotAllowedError: Operation not permitted
444 NameError: Container/object does not exist
446 ValueError: Invalid users/groups in permissions
448 AttributeError: Can not set permissions
452 def delete_object(self, user, account, container, name, until=None):
453 """Delete/purge an object.
456 NotAllowedError: Operation not permitted
458 NameError: Container/object does not exist
462 def list_versions(self, user, account, container, name):
463 """Return a list of all (version, version_timestamp) tuples for an object.
466 NotAllowedError: Operation not permitted
470 def get_block(self, hash):
471 """Return a block's data.
474 NameError: Block does not exist
478 def put_block(self, data):
479 """Store a block and return the hash."""
482 def update_block(self, hash, data, offset=0):
483 """Update a known block and return the hash.
486 IndexError: Offset or data outside block limits