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 list_accounts(self, user, marker=None, limit=10000):
59 """Return a list of accounts the user can access.
62 'marker': Start list from the next item after 'marker'
64 'limit': Number of containers to return
68 def get_account_meta(self, user, account, until=None):
69 """Return a dictionary with the account metadata.
71 The keys returned are all user-defined, except:
72 'name': The account name
74 'count': The number of containers (or 0)
76 'bytes': The total data size (or 0)
78 'modified': Last modification timestamp (overall)
80 'until_timestamp': Last modification until the timestamp provided
83 NotAllowedError: Operation not permitted
87 def update_account_meta(self, user, account, meta, replace=False):
88 """Update the metadata associated with the account.
91 'meta': Dictionary with metadata to update
93 'replace': Replace instead of update
96 NotAllowedError: Operation not permitted
100 def get_account_groups(self, user, account):
101 """Return a dictionary with the user groups defined for this account.
104 NotAllowedError: Operation not permitted
108 def update_account_groups(self, user, account, groups, replace=False):
109 """Update the groups associated with the account.
112 NotAllowedError: Operation not permitted
114 ValueError: Invalid data in groups
118 def get_account_policy(self, user, account):
119 """Return a dictionary with the account policy.
121 The keys returned are:
122 'quota': The maximum bytes allowed (default is 0 - unlimited)
124 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
127 NotAllowedError: Operation not permitted
131 def update_account_policy(self, user, account, policy, replace=False):
132 """Update the policy associated with the account.
135 NotAllowedError: Operation not permitted
137 ValueError: Invalid policy defined
141 def put_account(self, user, account, policy={}):
142 """Create a new account with the given name.
145 NotAllowedError: Operation not permitted
147 ValueError: Invalid policy defined
151 def delete_account(self, user, account):
152 """Delete the account with the given name.
155 NotAllowedError: Operation not permitted
157 IndexError: Account is not empty
161 def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
162 """Return a list of container names existing under an account.
165 'marker': Start list from the next item after 'marker'
167 'limit': Number of containers to return
169 'shared': Only list containers with permissions set
173 NotAllowedError: Operation not permitted
177 def get_container_meta(self, user, account, container, until=None):
178 """Return a dictionary with the container metadata.
180 The keys returned are all user-defined, except:
181 'name': The container name
183 'count': The number of objects
185 'bytes': The total data size
187 'modified': Last modification timestamp (overall)
189 'until_timestamp': Last modification until the timestamp provided
192 NotAllowedError: Operation not permitted
194 NameError: Container does not exist
198 def update_container_meta(self, user, account, container, meta, replace=False):
199 """Update the metadata associated with the container.
202 'meta': Dictionary with metadata to update
204 'replace': Replace instead of update
207 NotAllowedError: Operation not permitted
209 NameError: Container does not exist
213 def get_container_policy(self, user, account, container):
214 """Return a dictionary with the container policy.
216 The keys returned are:
217 'quota': The maximum bytes allowed (default is 0 - unlimited)
219 'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
222 NotAllowedError: Operation not permitted
224 NameError: Container does not exist
228 def update_container_policy(self, user, account, container, policy, replace=False):
229 """Update the policy associated with the container.
232 NotAllowedError: Operation not permitted
234 NameError: Container does not exist
236 ValueError: Invalid policy defined
240 def put_container(self, user, account, container, policy={}):
241 """Create a new container with the given name.
244 NotAllowedError: Operation not permitted
246 NameError: Container already exists
248 ValueError: Invalid policy defined
252 def delete_container(self, user, account, container, until=None):
253 """Delete/purge the container with the given name.
256 NotAllowedError: Operation not permitted
258 NameError: Container does not exist
260 IndexError: Container is not empty
264 def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
265 """Return a list of object (name, version_id) tuples existing under a container.
268 'prefix': List objects starting with 'prefix'
270 'delimiter': Return unique names before 'delimiter' and after 'prefix'
272 'marker': Start list from the next item after 'marker'
274 'limit': Number of objects to return
276 'virtual': If not set, the result will only include names starting
277 with 'prefix' and ending without a 'delimiter' or with
278 the first occurance of the 'delimiter' after 'prefix'.
279 If set, the result will include all names after 'prefix',
280 up to and including the 'delimiter' if it is found
282 'keys': Include objects that have meta with the keys in the list
284 'shared': Only list objects with permissions set
287 NotAllowedError: Operation not permitted
289 NameError: Container does not exist
293 def list_object_meta(self, user, account, container, until=None):
294 """Return a list with all the container's object meta keys.
297 NotAllowedError: Operation not permitted
299 NameError: Container does not exist
303 def get_object_meta(self, user, account, container, name, version=None):
304 """Return a dictionary with the object metadata.
306 The keys returned are all user-defined, except:
307 'name': The object name
309 'bytes': The total data size
311 'modified': Last modification timestamp (overall)
313 'modified_by': The user that committed the object (version requested)
315 'version': The version identifier
317 'version_timestamp': The version's modification timestamp
320 NotAllowedError: Operation not permitted
322 NameError: Container/object does not exist
324 IndexError: Version does not exist
328 def update_object_meta(self, user, account, container, name, meta, replace=False):
329 """Update the metadata associated with the object and return the new version.
332 'meta': Dictionary with metadata to update
334 'replace': Replace instead of update
337 NotAllowedError: Operation not permitted
339 NameError: Container/object does not exist
343 def get_object_permissions(self, user, account, container, name):
344 """Return the action allowed on the object, the path
345 from which the object gets its permissions from,
346 along with a dictionary containing the permissions.
348 The dictionary keys are (also used for defining the action):
349 'read': The object is readable by the users/groups in the list
351 'write': The object is writable by the users/groups in the list
354 NotAllowedError: Operation not permitted
356 NameError: Container/object does not exist
360 def update_object_permissions(self, user, account, container, name, permissions):
361 """Update the permissions associated with the object.
364 'permissions': Dictionary with permissions to update
367 NotAllowedError: Operation not permitted
369 NameError: Container/object does not exist
371 ValueError: Invalid users/groups in permissions
373 AttributeError: Can not set permissions, as this object
374 is already shared/private by another object higher
375 in the hierarchy, or setting permissions here will
376 invalidate other permissions deeper in the hierarchy
380 def get_object_public(self, user, account, container, name):
381 """Return the public URL of the object if applicable.
384 NotAllowedError: Operation not permitted
386 NameError: Container/object does not exist
390 def update_object_public(self, user, account, container, name, public):
391 """Update the public status of the object.
394 'public': Boolean value
397 NotAllowedError: Operation not permitted
399 NameError: Container/object does not exist
403 def get_object_hashmap(self, user, account, container, name, version=None):
404 """Return the object's size and a list with partial hashes.
407 NotAllowedError: Operation not permitted
409 NameError: Container/object does not exist
411 IndexError: Version does not exist
415 def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions=None):
416 """Create/update an object with the specified size and partial hashes and return the new version.
419 'dest_meta': Dictionary with metadata to change
421 'replace_meta': Replace metadata instead of update
423 'permissions': Updated object permissions
426 NotAllowedError: Operation not permitted
428 NameError: Container does not exist
430 ValueError: Invalid users/groups in permissions
432 AttributeError: Can not set permissions
434 QuotaError: Account or container quota exceeded
438 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):
439 """Copy an object's data and metadata and return the new version.
442 'dest_meta': Dictionary with metadata to change from source to destination
444 'replace_meta': Replace metadata instead of update
446 'permissions': New object permissions
448 'src_version': Copy from the version provided
451 NotAllowedError: Operation not permitted
453 NameError: Container/object does not exist
455 IndexError: Version does not exist
457 ValueError: Invalid users/groups in permissions
459 AttributeError: Can not set permissions
461 QuotaError: Account or container quota exceeded
465 def move_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
466 """Move an object's data and metadata and return the new version.
469 'dest_meta': Dictionary with metadata to change from source to destination
471 'replace_meta': Replace metadata instead of update
473 'permissions': New object permissions
476 NotAllowedError: Operation not permitted
478 NameError: Container/object does not exist
480 ValueError: Invalid users/groups in permissions
482 AttributeError: Can not set permissions
484 QuotaError: Account or container quota exceeded
488 def delete_object(self, user, account, container, name, until=None):
489 """Delete/purge an object.
492 NotAllowedError: Operation not permitted
494 NameError: Container/object does not exist
498 def list_versions(self, user, account, container, name):
499 """Return a list of all (version, version_timestamp) tuples for an object.
502 NotAllowedError: Operation not permitted
506 def get_block(self, hash):
507 """Return a block's data.
510 NameError: Block does not exist
514 def put_block(self, data):
515 """Store a block and return the hash."""
518 def update_block(self, hash, data, offset=0):
519 """Update a known block and return the hash.
522 IndexError: Offset or data outside block limits