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 QuotaError(Exception):
40 class BaseBackend(object):
41 """Abstract backend class that serves as a reference for actual implementations.
43 The purpose of the backend is to provide the necessary functions for handling data
44 and metadata. It is responsible for the actual storage and retrieval of information.
46 Note that the account level is always valid as it is checked from another subsystem.
48 When not replacing metadata/groups/policy, keys with empty values should be deleted.
50 The following variables should be available:
51 'hash_algorithm': Suggested is 'sha256'
53 'block_size': Suggested is 4MB
55 'default_policy': A dictionary with default policy settings
58 def __init__(self, db_module, db_connection, block_module, block_path):
59 """Initialize backend with supplied modules and options."""
63 """Close the backend connection."""
66 def list_accounts(self, user, marker=None, limit=10000):
67 """Return a list of accounts the user can access.
70 'marker': Start list from the next item after 'marker'
72 'limit': Number of containers to return
76 def get_account_meta(self, user, account, until=None):
77 """Return a dictionary with the account metadata.
79 The keys returned are all user-defined, except:
80 'name': The account name
82 'count': The number of containers (or 0)
84 'bytes': The total data size (or 0)
86 'modified': Last modification timestamp (overall)
88 'until_timestamp': Last modification until the timestamp provided
91 NotAllowedError: Operation not permitted
95 def update_account_meta(self, user, account, meta, replace=False):
96 """Update the metadata associated with the account.
99 'meta': Dictionary with metadata to update
101 'replace': Replace instead of update
104 NotAllowedError: Operation not permitted
108 def get_account_groups(self, user, account):
109 """Return a dictionary with the user groups defined for this account.
112 NotAllowedError: Operation not permitted
116 def update_account_groups(self, user, account, groups, replace=False):
117 """Update the groups associated with the account.
120 NotAllowedError: Operation not permitted
122 ValueError: Invalid data in groups
126 def get_account_policy(self, user, account):
127 """Return a dictionary with the account policy.
129 The keys returned are:
130 'quota': The maximum bytes allowed (default is 0 - unlimited)
132 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
135 NotAllowedError: Operation not permitted
139 def update_account_policy(self, user, account, policy, replace=False):
140 """Update the policy associated with the account.
143 NotAllowedError: Operation not permitted
145 ValueError: Invalid policy defined
149 def put_account(self, user, account, policy={}):
150 """Create a new account with the given name.
153 NotAllowedError: Operation not permitted
155 ValueError: Invalid policy defined
159 def delete_account(self, user, account):
160 """Delete the account with the given name.
163 NotAllowedError: Operation not permitted
165 IndexError: Account is not empty
169 def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
170 """Return a list of container names existing under an account.
173 'marker': Start list from the next item after 'marker'
175 'limit': Number of containers to return
177 'shared': Only list containers with permissions set
181 NotAllowedError: Operation not permitted
185 def get_container_meta(self, user, account, container, until=None):
186 """Return a dictionary with the container metadata.
188 The keys returned are all user-defined, except:
189 'name': The container name
191 'count': The number of objects
193 'bytes': The total data size
195 'modified': Last modification timestamp (overall)
197 'until_timestamp': Last modification until the timestamp provided
200 NotAllowedError: Operation not permitted
202 NameError: Container does not exist
206 def update_container_meta(self, user, account, container, meta, replace=False):
207 """Update the metadata associated with the container.
210 'meta': Dictionary with metadata to update
212 'replace': Replace instead of update
215 NotAllowedError: Operation not permitted
217 NameError: Container does not exist
221 def get_container_policy(self, user, account, container):
222 """Return a dictionary with the container policy.
224 The keys returned are:
225 'quota': The maximum bytes allowed (default is 0 - unlimited)
227 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
230 NotAllowedError: Operation not permitted
232 NameError: Container does not exist
236 def update_container_policy(self, user, account, container, policy, replace=False):
237 """Update the policy associated with the container.
240 NotAllowedError: Operation not permitted
242 NameError: Container does not exist
244 ValueError: Invalid policy defined
248 def put_container(self, user, account, container, policy={}):
249 """Create a new container with the given name.
252 NotAllowedError: Operation not permitted
254 NameError: Container already exists
256 ValueError: Invalid policy defined
260 def delete_container(self, user, account, container, until=None):
261 """Delete/purge the container with the given name.
264 NotAllowedError: Operation not permitted
266 NameError: Container does not exist
268 IndexError: Container is not empty
272 def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
273 """Return a list of object (name, version_id) tuples existing under a container.
276 'prefix': List objects starting with 'prefix'
278 'delimiter': Return unique names before 'delimiter' and after 'prefix'
280 'marker': Start list from the next item after 'marker'
282 'limit': Number of objects to return
284 'virtual': If not set, the result will only include names starting
285 with 'prefix' and ending without a 'delimiter' or with
286 the first occurance of the 'delimiter' after 'prefix'.
287 If set, the result will include all names after 'prefix',
288 up to and including the 'delimiter' if it is found
290 'keys': Include objects that have meta with the keys in the list
292 'shared': Only list objects with permissions set
295 NotAllowedError: Operation not permitted
297 NameError: Container does not exist
301 def list_object_meta(self, user, account, container, until=None):
302 """Return a list with all the container's object meta keys.
305 NotAllowedError: Operation not permitted
307 NameError: Container does not exist
311 def get_object_meta(self, user, account, container, name, version=None):
312 """Return a dictionary with the object metadata.
314 The keys returned are all user-defined, except:
315 'name': The object name
317 'bytes': The total data size
319 'hash': The hashmap hash
321 'modified': Last modification timestamp (overall)
323 'modified_by': The user that committed the object (version requested)
325 'version': The version identifier
327 'version_timestamp': The version's modification timestamp
330 NotAllowedError: Operation not permitted
332 NameError: Container/object does not exist
334 IndexError: Version does not exist
338 def update_object_meta(self, user, account, container, name, meta, replace=False):
339 """Update the metadata associated with the object and return the new version.
342 'meta': Dictionary with metadata to update
344 'replace': Replace instead of update
347 NotAllowedError: Operation not permitted
349 NameError: Container/object does not exist
353 def get_object_permissions(self, user, account, container, name):
354 """Return the action allowed on the object, the path
355 from which the object gets its permissions from,
356 along with a dictionary containing the permissions.
358 The dictionary keys are (also used for defining the action):
359 'read': The object is readable by the users/groups in the list
361 'write': The object is writable by the users/groups in the list
364 NotAllowedError: Operation not permitted
366 NameError: Container/object does not exist
370 def update_object_permissions(self, user, account, container, name, permissions):
371 """Update the permissions associated with the object.
374 'permissions': Dictionary with permissions to update
377 NotAllowedError: Operation not permitted
379 NameError: Container/object does not exist
381 ValueError: Invalid users/groups in permissions
383 AttributeError: Can not set permissions, as this object
384 is already shared/private by another object higher
385 in the hierarchy, or setting permissions here will
386 invalidate other permissions deeper in the hierarchy
390 def get_object_public(self, user, account, container, name):
391 """Return the public id of the object if applicable.
394 NotAllowedError: Operation not permitted
396 NameError: Container/object does not exist
400 def update_object_public(self, user, account, container, name, public):
401 """Update the public status of the object.
404 'public': Boolean value
407 NotAllowedError: Operation not permitted
409 NameError: Container/object does not exist
413 def get_object_hashmap(self, user, account, container, name, version=None):
414 """Return the object's size and a list with partial hashes.
417 NotAllowedError: Operation not permitted
419 NameError: Container/object does not exist
421 IndexError: Version does not exist
425 def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions=None):
426 """Create/update an object with the specified size and partial hashes and return the new version.
429 'dest_meta': Dictionary with metadata to change
431 'replace_meta': Replace metadata instead of update
433 'permissions': Updated object permissions
436 NotAllowedError: Operation not permitted
438 NameError: Container does not exist
440 ValueError: Invalid users/groups in permissions
442 AttributeError: Can not set permissions
444 QuotaError: Account or container quota exceeded
448 def copy_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None, src_version=None):
449 """Copy an object's data and metadata and return the new version.
452 'dest_meta': Dictionary with metadata to change from source to destination
454 'replace_meta': Replace metadata instead of update
456 'permissions': New object permissions
458 'src_version': Copy from the version provided
461 NotAllowedError: Operation not permitted
463 NameError: Container/object does not exist
465 IndexError: Version does not exist
467 ValueError: Invalid users/groups in permissions
469 AttributeError: Can not set permissions
471 QuotaError: Account or container quota exceeded
475 def move_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
476 """Move an object's data and metadata and return the new version.
479 'dest_meta': Dictionary with metadata to change from source to destination
481 'replace_meta': Replace metadata instead of update
483 'permissions': New object permissions
486 NotAllowedError: Operation not permitted
488 NameError: Container/object does not exist
490 ValueError: Invalid users/groups in permissions
492 AttributeError: Can not set permissions
494 QuotaError: Account or container quota exceeded
498 def delete_object(self, user, account, container, name, until=None):
499 """Delete/purge an object.
502 NotAllowedError: Operation not permitted
504 NameError: Container/object does not exist
508 def list_versions(self, user, account, container, name):
509 """Return a list of all (version, version_timestamp) tuples for an object.
512 NotAllowedError: Operation not permitted
516 def get_public(self, user, public):
517 """Return the (account, container, name) for the public id given.
520 NotAllowedError: Operation not permitted
522 NameError: Public id does not exist
526 def get_block(self, hash):
527 """Return a block's data.
530 NameError: Block does not exist
534 def put_block(self, data):
535 """Store a block and return the hash."""
538 def update_block(self, hash, data, offset=0):
539 """Update a known block and return the hash.
542 IndexError: Offset or data outside block limits