fix quota bug
[pithos] / pithos / backends / base.py
1 # Copyright 2011 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 class NotAllowedError(Exception):
35     pass
36
37 class QuotaError(Exception):
38     pass
39
40 class BaseBackend(object):
41     """Abstract backend class that serves as a reference for actual implementations.
42     
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.
45     
46     Note that the account level is always valid as it is checked from another subsystem.
47     
48     When not replacing metadata/groups/policy, keys with empty values should be deleted.
49     
50     The following variables should be available:
51         'hash_algorithm': Suggested is 'sha256'
52         
53         'block_size': Suggested is 4MB
54         
55         'default_policy': A dictionary with default policy settings
56     """
57     
58     def list_accounts(self, user, marker=None, limit=10000):
59         """Return a list of accounts the user can access.
60         
61         Parameters:
62             'marker': Start list from the next item after 'marker'
63             
64             'limit': Number of containers to return
65         """
66         return []
67     
68     def get_account_meta(self, user, account, until=None):
69         """Return a dictionary with the account metadata.
70         
71         The keys returned are all user-defined, except:
72             'name': The account name
73             
74             'count': The number of containers (or 0)
75             
76             'bytes': The total data size (or 0)
77             
78             'modified': Last modification timestamp (overall)
79             
80             'until_timestamp': Last modification until the timestamp provided
81         
82         Raises:
83             NotAllowedError: Operation not permitted
84         """
85         return {}
86     
87     def update_account_meta(self, user, account, meta, replace=False):
88         """Update the metadata associated with the account.
89         
90         Parameters:
91             'meta': Dictionary with metadata to update
92             
93             'replace': Replace instead of update
94         
95         Raises:
96             NotAllowedError: Operation not permitted
97         """
98         return
99     
100     def get_account_groups(self, user, account):
101         """Return a dictionary with the user groups defined for this account.
102         
103         Raises:
104             NotAllowedError: Operation not permitted
105         """
106         return {}
107     
108     def update_account_groups(self, user, account, groups, replace=False):
109         """Update the groups associated with the account.
110         
111         Raises:
112             NotAllowedError: Operation not permitted
113             
114             ValueError: Invalid data in groups
115         """
116         return
117     
118     def get_account_policy(self, user, account):
119         """Return a dictionary with the account policy.
120         
121         The keys returned are:
122             'quota': The maximum bytes allowed (default is 0 - unlimited)
123             
124             'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
125         
126         Raises:
127             NotAllowedError: Operation not permitted
128         """
129         return {}
130     
131     def update_account_policy(self, user, account, policy, replace=False):
132         """Update the policy associated with the account.
133         
134         Raises:
135             NotAllowedError: Operation not permitted
136             
137             ValueError: Invalid policy defined
138         """
139         return
140     
141     def put_account(self, user, account, policy={}):
142         """Create a new account with the given name.
143         
144         Raises:
145             NotAllowedError: Operation not permitted
146             
147             ValueError: Invalid policy defined
148         """
149         return
150     
151     def delete_account(self, user, account):
152         """Delete the account with the given name.
153         
154         Raises:
155             NotAllowedError: Operation not permitted
156             
157             IndexError: Account is not empty
158         """
159         return
160     
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.
163         
164         Parameters:
165             'marker': Start list from the next item after 'marker'
166             
167             'limit': Number of containers to return
168             
169             'shared': Only list containers with permissions set
170             
171         
172         Raises:
173             NotAllowedError: Operation not permitted
174         """
175         return []
176     
177     def get_container_meta(self, user, account, container, until=None):
178         """Return a dictionary with the container metadata.
179         
180         The keys returned are all user-defined, except:
181             'name': The container name
182             
183             'count': The number of objects
184             
185             'bytes': The total data size
186             
187             'modified': Last modification timestamp (overall)
188             
189             'until_timestamp': Last modification until the timestamp provided
190         
191         Raises:
192             NotAllowedError: Operation not permitted
193             
194             NameError: Container does not exist
195         """
196         return {}
197     
198     def update_container_meta(self, user, account, container, meta, replace=False):
199         """Update the metadata associated with the container.
200         
201         Parameters:
202             'meta': Dictionary with metadata to update
203             
204             'replace': Replace instead of update
205         
206         Raises:
207             NotAllowedError: Operation not permitted
208             
209             NameError: Container does not exist
210         """
211         return
212     
213     def get_container_policy(self, user, account, container):
214         """Return a dictionary with the container policy.
215         
216         The keys returned are:
217             'quota': The maximum bytes allowed (default is 0 - unlimited)
218             
219             'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
220         
221         Raises:
222             NotAllowedError: Operation not permitted
223             
224             NameError: Container does not exist
225         """
226         return {}
227     
228     def update_container_policy(self, user, account, container, policy, replace=False):
229         """Update the policy associated with the container.
230         
231         Raises:
232             NotAllowedError: Operation not permitted
233             
234             NameError: Container does not exist
235             
236             ValueError: Invalid policy defined
237         """
238         return
239     
240     def put_container(self, user, account, container, policy={}):
241         """Create a new container with the given name.
242         
243         Raises:
244             NotAllowedError: Operation not permitted
245             
246             NameError: Container already exists
247             
248             ValueError: Invalid policy defined
249         """
250         return
251     
252     def delete_container(self, user, account, container, until=None):
253         """Delete/purge the container with the given name.
254         
255         Raises:
256             NotAllowedError: Operation not permitted
257             
258             NameError: Container does not exist
259             
260             IndexError: Container is not empty
261         """
262         return
263     
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.
266         
267         Parameters:
268             'prefix': List objects starting with 'prefix'
269             
270             'delimiter': Return unique names before 'delimiter' and after 'prefix'
271             
272             'marker': Start list from the next item after 'marker'
273             
274             'limit': Number of objects to return
275             
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
281             
282             'keys': Include objects that have meta with the keys in the list
283             
284             'shared': Only list objects with permissions set
285         
286         Raises:
287             NotAllowedError: Operation not permitted
288             
289             NameError: Container does not exist
290         """
291         return []
292     
293     def list_object_meta(self, user, account, container, until=None):
294         """Return a list with all the container's object meta keys.
295         
296         Raises:
297             NotAllowedError: Operation not permitted
298             
299             NameError: Container does not exist
300         """
301         return []
302     
303     def get_object_meta(self, user, account, container, name, version=None):
304         """Return a dictionary with the object metadata.
305         
306         The keys returned are all user-defined, except:
307             'name': The object name
308             
309             'bytes': The total data size
310             
311             'modified': Last modification timestamp (overall)
312             
313             'modified_by': The user that committed the object (version requested)
314             
315             'version': The version identifier
316             
317             'version_timestamp': The version's modification timestamp
318         
319         Raises:
320             NotAllowedError: Operation not permitted
321             
322             NameError: Container/object does not exist
323             
324             IndexError: Version does not exist
325         """
326         return {}
327     
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.
330         
331         Parameters:
332             'meta': Dictionary with metadata to update
333             
334             'replace': Replace instead of update
335         
336         Raises:
337             NotAllowedError: Operation not permitted
338             
339             NameError: Container/object does not exist
340         """
341         return ''
342     
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.
347         
348         The dictionary keys are (also used for defining the action):
349             'read': The object is readable by the users/groups in the list
350             
351             'write': The object is writable by the users/groups in the list
352         
353         Raises:
354             NotAllowedError: Operation not permitted
355             
356             NameError: Container/object does not exist
357         """
358         return {}
359     
360     def update_object_permissions(self, user, account, container, name, permissions):
361         """Update the permissions associated with the object.
362         
363         Parameters:
364             'permissions': Dictionary with permissions to update
365         
366         Raises:
367             NotAllowedError: Operation not permitted
368             
369             NameError: Container/object does not exist
370             
371             ValueError: Invalid users/groups in permissions
372             
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
377         """
378         return
379     
380     def get_object_public(self, user, account, container, name):
381         """Return the public URL of the object if applicable.
382         
383         Raises:
384             NotAllowedError: Operation not permitted
385             
386             NameError: Container/object does not exist
387         """
388         return None
389     
390     def update_object_public(self, user, account, container, name, public):
391         """Update the public status of the object.
392         
393         Parameters:
394             'public': Boolean value
395         
396         Raises:
397             NotAllowedError: Operation not permitted
398             
399             NameError: Container/object does not exist
400         """
401         return
402     
403     def get_object_hashmap(self, user, account, container, name, version=None):
404         """Return the object's size and a list with partial hashes.
405         
406         Raises:
407             NotAllowedError: Operation not permitted
408             
409             NameError: Container/object does not exist
410             
411             IndexError: Version does not exist
412         """
413         return 0, []
414     
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.
417         
418         Parameters:
419             'dest_meta': Dictionary with metadata to change
420             
421             'replace_meta': Replace metadata instead of update
422             
423             'permissions': Updated object permissions
424         
425         Raises:
426             NotAllowedError: Operation not permitted
427             
428             NameError: Container does not exist
429             
430             ValueError: Invalid users/groups in permissions
431             
432             AttributeError: Can not set permissions
433             
434             QuotaError: Account or container quota exceeded
435         """
436         return ''
437     
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.
440         
441         Parameters:
442             'dest_meta': Dictionary with metadata to change from source to destination
443             
444             'replace_meta': Replace metadata instead of update
445             
446             'permissions': New object permissions
447             
448             'src_version': Copy from the version provided
449         
450         Raises:
451             NotAllowedError: Operation not permitted
452             
453             NameError: Container/object does not exist
454             
455             IndexError: Version does not exist
456             
457             ValueError: Invalid users/groups in permissions
458             
459             AttributeError: Can not set permissions
460             
461             QuotaError: Account or container quota exceeded
462         """
463         return ''
464     
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.
467         
468         Parameters:
469             'dest_meta': Dictionary with metadata to change from source to destination
470             
471             'replace_meta': Replace metadata instead of update
472             
473             'permissions': New object permissions
474         
475         Raises:
476             NotAllowedError: Operation not permitted
477             
478             NameError: Container/object does not exist
479             
480             ValueError: Invalid users/groups in permissions
481             
482             AttributeError: Can not set permissions
483             
484             QuotaError: Account or container quota exceeded
485         """
486         return ''
487     
488     def delete_object(self, user, account, container, name, until=None):
489         """Delete/purge an object.
490         
491         Raises:
492             NotAllowedError: Operation not permitted
493             
494             NameError: Container/object does not exist
495         """
496         return
497     
498     def list_versions(self, user, account, container, name):
499         """Return a list of all (version, version_timestamp) tuples for an object.
500         
501         Raises:
502             NotAllowedError: Operation not permitted
503         """
504         return []
505     
506     def get_block(self, hash):
507         """Return a block's data.
508         
509         Raises:
510             NameError: Block does not exist
511         """
512         return ''
513     
514     def put_block(self, data):
515         """Store a block and return the hash."""
516         return 0
517     
518     def update_block(self, hash, data, offset=0):
519         """Update a known block and return the hash.
520         
521         Raises:
522             IndexError: Offset or data outside block limits
523         """
524         return 0