Update default config file and Changelog
[pithos] / snf-pithos-backend / pithos / backends / base.py
1 # Copyright 2011-2012 GRNET S.A. All rights reserved.
2
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
5 # conditions are met:
6
7 #   1. Redistributions of source code must retain the above
8 #      copyright notice, this list of conditions and the following
9 #      disclaimer.
10
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.
15
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.
28
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.
33
34 # Default setting for new accounts.
35 DEFAULT_QUOTA = 0 # No quota.
36 DEFAULT_VERSIONING = 'auto'
37
38
39 class NotAllowedError(Exception):
40     pass
41
42 class QuotaError(Exception):
43     pass
44
45 class BaseBackend(object):
46     """Abstract backend class that serves as a reference for actual implementations.
47     
48     The purpose of the backend is to provide the necessary functions for handling data
49     and metadata. It is responsible for the actual storage and retrieval of information.
50     
51     Note that the account level is always valid as it is checked from another subsystem.
52     
53     When not replacing metadata/groups/policy, keys with empty values should be deleted.
54     
55     The following variables should be available:
56         'hash_algorithm': Suggested is 'sha256'
57         
58         'block_size': Suggested is 4MB
59         
60         'default_policy': A dictionary with default policy settings
61     """
62     
63     def close(self):
64         """Close the backend connection."""
65         pass
66     
67     def list_accounts(self, user, marker=None, limit=10000):
68         """Return a list of accounts the user can access.
69         
70         Parameters:
71             'marker': Start list from the next item after 'marker'
72             
73             'limit': Number of containers to return
74         """
75         return []
76     
77     def get_account_meta(self, user, account, domain, until=None, include_user_defined=True):
78         """Return a dictionary with the account metadata for the domain.
79         
80         The keys returned are all user-defined, except:
81             'name': The account name
82             
83             'count': The number of containers (or 0)
84             
85             'bytes': The total data size (or 0)
86             
87             'modified': Last modification timestamp (overall)
88             
89             'until_timestamp': Last modification until the timestamp provided
90         
91         Raises:
92             NotAllowedError: Operation not permitted
93         """
94         return {}
95     
96     def update_account_meta(self, user, account, domain, meta, replace=False):
97         """Update the metadata associated with the account for the domain.
98         
99         Parameters:
100             'domain': Metadata domain
101             
102             'meta': Dictionary with metadata to update
103             
104             'replace': Replace instead of update
105         
106         Raises:
107             NotAllowedError: Operation not permitted
108         """
109         return
110     
111     def get_account_groups(self, user, account):
112         """Return a dictionary with the user groups defined for this account.
113         
114         Raises:
115             NotAllowedError: Operation not permitted
116         """
117         return {}
118     
119     def update_account_groups(self, user, account, groups, replace=False):
120         """Update the groups associated with the account.
121         
122         Raises:
123             NotAllowedError: Operation not permitted
124             
125             ValueError: Invalid data in groups
126         """
127         return
128     
129     def get_account_policy(self, user, account):
130         """Return a dictionary with the account policy.
131         
132         The keys returned are:
133             'quota': The maximum bytes allowed (default is 0 - unlimited)
134             
135             'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
136         
137         Raises:
138             NotAllowedError: Operation not permitted
139         """
140         return {}
141     
142     def update_account_policy(self, user, account, policy, replace=False):
143         """Update the policy associated with the account.
144         
145         Raises:
146             NotAllowedError: Operation not permitted
147             
148             ValueError: Invalid policy defined
149         """
150         return
151     
152     def put_account(self, user, account, policy={}):
153         """Create a new account with the given name.
154         
155         Raises:
156             NotAllowedError: Operation not permitted
157             
158             ValueError: Invalid policy defined
159         """
160         return
161     
162     def delete_account(self, user, account):
163         """Delete the account with the given name.
164         
165         Raises:
166             NotAllowedError: Operation not permitted
167             
168             IndexError: Account is not empty
169         """
170         return
171     
172     def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
173         """Return a list of container names existing under an account.
174         
175         Parameters:
176             'marker': Start list from the next item after 'marker'
177             
178             'limit': Number of containers to return
179             
180             'shared': Only list containers with permissions set
181             
182         
183         Raises:
184             NotAllowedError: Operation not permitted
185         """
186         return []
187     
188     def list_container_meta(self, user, account, container, domain, until=None):
189         """Return a list with all the container's object meta keys for the domain.
190         
191         Raises:
192             NotAllowedError: Operation not permitted
193             
194             NameError: Container does not exist
195         """
196         return []
197     
198     def get_container_meta(self, user, account, container, domain, until=None, include_user_defined=True):
199         """Return a dictionary with the container metadata for the domain.
200         
201         The keys returned are all user-defined, except:
202             'name': The container name
203             
204             'count': The number of objects
205             
206             'bytes': The total data size
207             
208             'modified': Last modification timestamp (overall)
209             
210             'until_timestamp': Last modification until the timestamp provided
211         
212         Raises:
213             NotAllowedError: Operation not permitted
214             
215             NameError: Container does not exist
216         """
217         return {}
218     
219     def update_container_meta(self, user, account, container, domain, meta, replace=False):
220         """Update the metadata associated with the container for the domain.
221         
222         Parameters:
223             'domain': Metadata domain
224             
225             'meta': Dictionary with metadata to update
226             
227             'replace': Replace instead of update
228         
229         Raises:
230             NotAllowedError: Operation not permitted
231             
232             NameError: Container does not exist
233         """
234         return
235     
236     def get_container_policy(self, user, account, container):
237         """Return a dictionary with the container policy.
238         
239         The keys returned are:
240             'quota': The maximum bytes allowed (default is 0 - unlimited)
241             
242             'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
243         
244         Raises:
245             NotAllowedError: Operation not permitted
246             
247             NameError: Container does not exist
248         """
249         return {}
250     
251     def update_container_policy(self, user, account, container, policy, replace=False):
252         """Update the policy associated with the container.
253         
254         Raises:
255             NotAllowedError: Operation not permitted
256             
257             NameError: Container does not exist
258             
259             ValueError: Invalid policy defined
260         """
261         return
262     
263     def put_container(self, user, account, container, policy={}):
264         """Create a new container with the given name.
265         
266         Raises:
267             NotAllowedError: Operation not permitted
268             
269             NameError: Container already exists
270             
271             ValueError: Invalid policy defined
272         """
273         return
274     
275     def delete_container(self, user, account, container, until=None):
276         """Delete/purge the container with the given name.
277         
278         Raises:
279             NotAllowedError: Operation not permitted
280             
281             NameError: Container does not exist
282             
283             IndexError: Container is not empty
284         """
285         return
286     
287     def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=[], shared=False, until=None, size_range=None):
288         """Return a list of object (name, version_id) tuples existing under a container.
289         
290         Parameters:
291             'prefix': List objects starting with 'prefix'
292             
293             'delimiter': Return unique names before 'delimiter' and after 'prefix'
294             
295             'marker': Start list from the next item after 'marker'
296             
297             'limit': Number of objects to return
298             
299             'virtual': If not set, the result will only include names starting
300                        with 'prefix' and ending without a 'delimiter' or with
301                        the first occurance of the 'delimiter' after 'prefix'.
302                        If set, the result will include all names after 'prefix',
303                        up to and including the 'delimiter' if it is found
304             
305             'domain': Metadata domain for keys
306             
307             'keys': Include objects that satisfy the key queries in the list.
308                     Use 'key', '!key' for existence queries, 'key op value' for
309                     value queries, where 'op' can be one of =, !=, <=, >=, <, >
310             
311             'shared': Only list objects with permissions set
312              
313             'size_range': Include objects with byte size in (from, to).
314                           Use None to specify unlimited
315         
316         Raises:
317             NotAllowedError: Operation not permitted
318             
319             NameError: Container does not exist
320         """
321         return []
322     
323     def list_object_meta(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=[], shared=False, until=None, size_range=None):
324         """Return a list of object metadata dicts existing under a container.
325         
326         Same parameters with list_objects. Returned dicts have no user-defined
327         metadata and, if until is not None, a None 'modified' timestamp.
328         
329         Raises:
330             NotAllowedError: Operation not permitted
331             
332             NameError: Container does not exist
333         """
334         return []
335     
336     def list_object_permissions(self, user, account, container, prefix=''):
337         """Return a list of paths that enforce permissions under a container.
338         
339         Raises:
340             NotAllowedError: Operation not permitted
341         """
342         return []
343     
344     def list_object_public(self, user, account, container, prefix=''):
345         """Return a dict mapping paths to public ids for objects that are public under a container."""
346         return {}
347     
348     def get_object_meta(self, user, account, container, name, domain, version=None, include_user_defined=True):
349         """Return a dictionary with the object metadata for the domain.
350         
351         The keys returned are all user-defined, except:
352             'name': The object name
353             
354             'bytes': The total data size
355             
356             'type': The content type
357             
358             'hash': The hashmap hash
359             
360             'modified': Last modification timestamp (overall)
361             
362             'modified_by': The user that committed the object (version requested)
363             
364             'version': The version identifier
365             
366             'version_timestamp': The version's modification timestamp
367             
368             'uuid': A unique identifier that persists data or metadata updates and renames
369             
370             'checksum': The MD5 sum of the object (may be empty)
371         
372         Raises:
373             NotAllowedError: Operation not permitted
374             
375             NameError: Container/object does not exist
376             
377             IndexError: Version does not exist
378         """
379         return {}
380     
381     def update_object_meta(self, user, account, container, name, domain, meta, replace=False):
382         """Update the metadata associated with the object for the domain and return the new version.
383         
384         Parameters:
385             'domain': Metadata domain
386             
387             'meta': Dictionary with metadata to update
388             
389             'replace': Replace instead of update
390         
391         Raises:
392             NotAllowedError: Operation not permitted
393             
394             NameError: Container/object does not exist
395         """
396         return ''
397     
398     def get_object_permissions(self, user, account, container, name):
399         """Return the action allowed on the object, the path
400         from which the object gets its permissions from,
401         along with a dictionary containing the permissions.
402         
403         The dictionary keys are (also used for defining the action):
404             'read': The object is readable by the users/groups in the list
405             
406             'write': The object is writable by the users/groups in the list
407         
408         Raises:
409             NotAllowedError: Operation not permitted
410             
411             NameError: Container/object does not exist
412         """
413         return {}
414     
415     def update_object_permissions(self, user, account, container, name, permissions):
416         """Update (set) the permissions associated with the object.
417         
418         Parameters:
419             'permissions': Dictionary with permissions to set
420         
421         Raises:
422             NotAllowedError: Operation not permitted
423             
424             NameError: Container/object does not exist
425             
426             ValueError: Invalid users/groups in permissions
427         """
428         return
429     
430     def get_object_public(self, user, account, container, name):
431         """Return the public id of the object if applicable.
432         
433         Raises:
434             NotAllowedError: Operation not permitted
435             
436             NameError: Container/object does not exist
437         """
438         return None
439     
440     def update_object_public(self, user, account, container, name, public):
441         """Update the public status of the object.
442         
443         Parameters:
444             'public': Boolean value
445         
446         Raises:
447             NotAllowedError: Operation not permitted
448             
449             NameError: Container/object does not exist
450         """
451         return
452     
453     def get_object_hashmap(self, user, account, container, name, version=None):
454         """Return the object's size and a list with partial hashes.
455         
456         Raises:
457             NotAllowedError: Operation not permitted
458             
459             NameError: Container/object does not exist
460             
461             IndexError: Version does not exist
462         """
463         return 0, []
464     
465     def update_object_hashmap(self, user, account, container, name, size, type, hashmap, checksum, domain, meta={}, replace_meta=False, permissions=None):
466         """Create/update an object with the specified size and partial hashes and return the new version.
467         
468         Parameters:
469             'domain': Metadata domain
470             
471             'meta': Dictionary with metadata to change
472             
473             'replace_meta': Replace metadata instead of update
474             
475             'permissions': Updated object permissions
476         
477         Raises:
478             NotAllowedError: Operation not permitted
479             
480             NameError: Container does not exist
481             
482             ValueError: Invalid users/groups in permissions
483             
484             QuotaError: Account or container quota exceeded
485         """
486         return ''
487     
488     def update_object_checksum(self, user, account, container, name, version, checksum):
489         """Update an object's checksum."""
490         return
491     
492     def copy_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta={}, replace_meta=False, permissions=None, src_version=None):
493         """Copy an object's data and metadata and return the new version.
494         
495         Parameters:
496             'domain': Metadata domain
497             
498             'meta': Dictionary with metadata to change from source to destination
499             
500             'replace_meta': Replace metadata instead of update
501             
502             'permissions': New object permissions
503             
504             'src_version': Copy from the version provided
505         
506         Raises:
507             NotAllowedError: Operation not permitted
508             
509             NameError: Container/object does not exist
510             
511             IndexError: Version does not exist
512             
513             ValueError: Invalid users/groups in permissions
514             
515             QuotaError: Account or container quota exceeded
516         """
517         return ''
518     
519     def move_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta={}, replace_meta=False, permissions=None):
520         """Move an object's data and metadata and return the new version.
521         
522         Parameters:
523             'domain': Metadata domain
524             
525             'meta': Dictionary with metadata to change from source to destination
526             
527             'replace_meta': Replace metadata instead of update
528             
529             'permissions': New object permissions
530         
531         Raises:
532             NotAllowedError: Operation not permitted
533             
534             NameError: Container/object does not exist
535             
536             ValueError: Invalid users/groups in permissions
537             
538             QuotaError: Account or container quota exceeded
539         """
540         return ''
541     
542     def delete_object(self, user, account, container, name, until=None):
543         """Delete/purge an object.
544         
545         Raises:
546             NotAllowedError: Operation not permitted
547             
548             NameError: Container/object does not exist
549         """
550         return
551     
552     def list_versions(self, user, account, container, name):
553         """Return a list of all (version, version_timestamp) tuples for an object.
554         
555         Raises:
556             NotAllowedError: Operation not permitted
557         """
558         return []
559     
560     def get_uuid(self, user, uuid):
561         """Return the (account, container, name) for the UUID given.
562         
563         Raises:
564             NotAllowedError: Operation not permitted
565             
566             NameError: UUID does not exist
567         """
568         return None
569     
570     def get_public(self, user, public):
571         """Return the (account, container, name) for the public id given.
572         
573         Raises:
574             NotAllowedError: Operation not permitted
575             
576             NameError: Public id does not exist
577         """
578         return None
579     
580     def get_block(self, hash):
581         """Return a block's data.
582         
583         Raises:
584             NameError: Block does not exist
585         """
586         return ''
587     
588     def put_block(self, data):
589         """Store a block and return the hash."""
590         return 0
591     
592     def update_block(self, hash, data, offset=0):
593         """Update a known block and return the hash.
594         
595         Raises:
596             IndexError: Offset or data outside block limits
597         """
598         return 0