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
59 """Close the backend connection."""
62 def list_accounts(self, user, marker=None, limit=10000):
63 """Return a list of accounts the user can access.
66 'marker': Start list from the next item after 'marker'
68 'limit': Number of containers to return
72 def get_account_meta(self, user, account, until=None):
73 """Return a dictionary with the account metadata.
75 The keys returned are all user-defined, except:
76 'name': The account name
78 'count': The number of containers (or 0)
80 'bytes': The total data size (or 0)
82 'modified': Last modification timestamp (overall)
84 'until_timestamp': Last modification until the timestamp provided
87 NotAllowedError: Operation not permitted
91 def update_account_meta(self, user, account, meta, replace=False):
92 """Update the metadata associated with the account.
95 'meta': Dictionary with metadata to update
97 'replace': Replace instead of update
100 NotAllowedError: Operation not permitted
104 def get_account_groups(self, user, account):
105 """Return a dictionary with the user groups defined for this account.
108 NotAllowedError: Operation not permitted
112 def update_account_groups(self, user, account, groups, replace=False):
113 """Update the groups associated with the account.
116 NotAllowedError: Operation not permitted
118 ValueError: Invalid data in groups
122 def get_account_policy(self, user, account):
123 """Return a dictionary with the account policy.
125 The keys returned are:
126 'quota': The maximum bytes allowed (default is 0 - unlimited)
128 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
131 NotAllowedError: Operation not permitted
135 def update_account_policy(self, user, account, policy, replace=False):
136 """Update the policy associated with the account.
139 NotAllowedError: Operation not permitted
141 ValueError: Invalid policy defined
145 def put_account(self, user, account, policy={}):
146 """Create a new account with the given name.
149 NotAllowedError: Operation not permitted
151 ValueError: Invalid policy defined
155 def delete_account(self, user, account):
156 """Delete the account with the given name.
159 NotAllowedError: Operation not permitted
161 IndexError: Account is not empty
165 def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
166 """Return a list of container names existing under an account.
169 'marker': Start list from the next item after 'marker'
171 'limit': Number of containers to return
173 'shared': Only list containers with permissions set
177 NotAllowedError: Operation not permitted
181 def get_container_meta(self, user, account, container, until=None):
182 """Return a dictionary with the container metadata.
184 The keys returned are all user-defined, except:
185 'name': The container name
187 'count': The number of objects
189 'bytes': The total data size
191 'modified': Last modification timestamp (overall)
193 'until_timestamp': Last modification until the timestamp provided
196 NotAllowedError: Operation not permitted
198 NameError: Container does not exist
202 def update_container_meta(self, user, account, container, meta, replace=False):
203 """Update the metadata associated with the container.
206 'meta': Dictionary with metadata to update
208 'replace': Replace instead of update
211 NotAllowedError: Operation not permitted
213 NameError: Container does not exist
217 def get_container_policy(self, user, account, container):
218 """Return a dictionary with the container policy.
220 The keys returned are:
221 'quota': The maximum bytes allowed (default is 0 - unlimited)
223 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
226 NotAllowedError: Operation not permitted
228 NameError: Container does not exist
232 def update_container_policy(self, user, account, container, policy, replace=False):
233 """Update the policy associated with the container.
236 NotAllowedError: Operation not permitted
238 NameError: Container does not exist
240 ValueError: Invalid policy defined
244 def put_container(self, user, account, container, policy={}):
245 """Create a new container with the given name.
248 NotAllowedError: Operation not permitted
250 NameError: Container already exists
252 ValueError: Invalid policy defined
256 def delete_container(self, user, account, container, until=None):
257 """Delete/purge the container with the given name.
260 NotAllowedError: Operation not permitted
262 NameError: Container does not exist
264 IndexError: Container is not empty
268 def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
269 """Return a list of object (name, version_id) tuples existing under a container.
272 'prefix': List objects starting with 'prefix'
274 'delimiter': Return unique names before 'delimiter' and after 'prefix'
276 'marker': Start list from the next item after 'marker'
278 'limit': Number of objects to return
280 'virtual': If not set, the result will only include names starting
281 with 'prefix' and ending without a 'delimiter' or with
282 the first occurance of the 'delimiter' after 'prefix'.
283 If set, the result will include all names after 'prefix',
284 up to and including the 'delimiter' if it is found
286 'keys': Include objects that have meta with the keys in the list
288 'shared': Only list objects with permissions set
291 NotAllowedError: Operation not permitted
293 NameError: Container does not exist
297 def list_object_meta(self, user, account, container, until=None):
298 """Return a list with all the container's object meta keys.
301 NotAllowedError: Operation not permitted
303 NameError: Container does not exist
307 def get_object_meta(self, user, account, container, name, version=None):
308 """Return a dictionary with the object metadata.
310 The keys returned are all user-defined, except:
311 'name': The object name
313 'bytes': The total data size
315 'modified': Last modification timestamp (overall)
317 'modified_by': The user that committed the object (version requested)
319 'version': The version identifier
321 'version_timestamp': The version's modification timestamp
324 NotAllowedError: Operation not permitted
326 NameError: Container/object does not exist
328 IndexError: Version does not exist
332 def update_object_meta(self, user, account, container, name, meta, replace=False):
333 """Update the metadata associated with the object and return the new version.
336 'meta': Dictionary with metadata to update
338 'replace': Replace instead of update
341 NotAllowedError: Operation not permitted
343 NameError: Container/object does not exist
347 def get_object_permissions(self, user, account, container, name):
348 """Return the action allowed on the object, the path
349 from which the object gets its permissions from,
350 along with a dictionary containing the permissions.
352 The dictionary keys are (also used for defining the action):
353 'read': The object is readable by the users/groups in the list
355 'write': The object is writable by the users/groups in the list
358 NotAllowedError: Operation not permitted
360 NameError: Container/object does not exist
364 def update_object_permissions(self, user, account, container, name, permissions):
365 """Update the permissions associated with the object.
368 'permissions': Dictionary with permissions to update
371 NotAllowedError: Operation not permitted
373 NameError: Container/object does not exist
375 ValueError: Invalid users/groups in permissions
377 AttributeError: Can not set permissions, as this object
378 is already shared/private by another object higher
379 in the hierarchy, or setting permissions here will
380 invalidate other permissions deeper in the hierarchy
384 def get_object_public(self, user, account, container, name):
385 """Return the public URL of the object if applicable.
388 NotAllowedError: Operation not permitted
390 NameError: Container/object does not exist
394 def update_object_public(self, user, account, container, name, public):
395 """Update the public status of the object.
398 'public': Boolean value
401 NotAllowedError: Operation not permitted
403 NameError: Container/object does not exist
407 def get_object_hashmap(self, user, account, container, name, version=None):
408 """Return the object's size and a list with partial hashes.
411 NotAllowedError: Operation not permitted
413 NameError: Container/object does not exist
415 IndexError: Version does not exist
419 def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions=None):
420 """Create/update an object with the specified size and partial hashes and return the new version.
423 'dest_meta': Dictionary with metadata to change
425 'replace_meta': Replace metadata instead of update
427 'permissions': Updated object permissions
430 NotAllowedError: Operation not permitted
432 NameError: Container does not exist
434 ValueError: Invalid users/groups in permissions
436 AttributeError: Can not set permissions
438 QuotaError: Account or container quota exceeded
442 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):
443 """Copy an object's data and metadata and return the new version.
446 'dest_meta': Dictionary with metadata to change from source to destination
448 'replace_meta': Replace metadata instead of update
450 'permissions': New object permissions
452 'src_version': Copy from the version provided
455 NotAllowedError: Operation not permitted
457 NameError: Container/object does not exist
459 IndexError: Version does not exist
461 ValueError: Invalid users/groups in permissions
463 AttributeError: Can not set permissions
465 QuotaError: Account or container quota exceeded
469 def move_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
470 """Move an object's data and metadata and return the new version.
473 'dest_meta': Dictionary with metadata to change from source to destination
475 'replace_meta': Replace metadata instead of update
477 'permissions': New object permissions
480 NotAllowedError: Operation not permitted
482 NameError: Container/object does not exist
484 ValueError: Invalid users/groups in permissions
486 AttributeError: Can not set permissions
488 QuotaError: Account or container quota exceeded
492 def delete_object(self, user, account, container, name, until=None):
493 """Delete/purge an object.
496 NotAllowedError: Operation not permitted
498 NameError: Container/object does not exist
502 def list_versions(self, user, account, container, name):
503 """Return a list of all (version, version_timestamp) tuples for an object.
506 NotAllowedError: Operation not permitted
510 def get_block(self, hash):
511 """Return a block's data.
514 NameError: Block does not exist
518 def put_block(self, data):
519 """Store a block and return the hash."""
522 def update_block(self, hash, data, offset=0):
523 """Update a known block and return the hash.
526 IndexError: Offset or data outside block limits