Add size queries in backend object lists.
[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 # 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):
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 get_container_meta(self, user, account, container, domain, until=None):
189         """Return a dictionary with the container metadata for the domain.
190         
191         The keys returned are all user-defined, except:
192             'name': The container name
193             
194             'count': The number of objects
195             
196             'bytes': The total data size
197             
198             'modified': Last modification timestamp (overall)
199             
200             'until_timestamp': Last modification until the timestamp provided
201         
202         Raises:
203             NotAllowedError: Operation not permitted
204             
205             NameError: Container does not exist
206         """
207         return {}
208     
209     def update_container_meta(self, user, account, container, domain, meta, replace=False):
210         """Update the metadata associated with the container for the domain.
211         
212         Parameters:
213             'domain': Metadata domain
214             
215             'meta': Dictionary with metadata to update
216             
217             'replace': Replace instead of update
218         
219         Raises:
220             NotAllowedError: Operation not permitted
221             
222             NameError: Container does not exist
223         """
224         return
225     
226     def get_container_policy(self, user, account, container):
227         """Return a dictionary with the container policy.
228         
229         The keys returned are:
230             'quota': The maximum bytes allowed (default is 0 - unlimited)
231             
232             'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
233         
234         Raises:
235             NotAllowedError: Operation not permitted
236             
237             NameError: Container does not exist
238         """
239         return {}
240     
241     def update_container_policy(self, user, account, container, policy, replace=False):
242         """Update the policy associated with the container.
243         
244         Raises:
245             NotAllowedError: Operation not permitted
246             
247             NameError: Container does not exist
248             
249             ValueError: Invalid policy defined
250         """
251         return
252     
253     def put_container(self, user, account, container, policy={}):
254         """Create a new container with the given name.
255         
256         Raises:
257             NotAllowedError: Operation not permitted
258             
259             NameError: Container already exists
260             
261             ValueError: Invalid policy defined
262         """
263         return
264     
265     def delete_container(self, user, account, container, until=None):
266         """Delete/purge the container with the given name.
267         
268         Raises:
269             NotAllowedError: Operation not permitted
270             
271             NameError: Container does not exist
272             
273             IndexError: Container is not empty
274         """
275         return
276     
277     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):
278         """Return a list of object (name, version_id) tuples existing under a container.
279         
280         Parameters:
281             'prefix': List objects starting with 'prefix'
282             
283             'delimiter': Return unique names before 'delimiter' and after 'prefix'
284             
285             'marker': Start list from the next item after 'marker'
286             
287             'limit': Number of objects to return
288             
289             'virtual': If not set, the result will only include names starting
290                        with 'prefix' and ending without a 'delimiter' or with
291                        the first occurance of the 'delimiter' after 'prefix'.
292                        If set, the result will include all names after 'prefix',
293                        up to and including the 'delimiter' if it is found
294             
295             'domain': Metadata domain for keys
296             
297             'keys': Include objects that satisfy the key queries in the list.
298                     Use 'key', '!key' for existence queries, 'key op value' for
299                     value queries, where 'op' can be one of =, !=, <=, >=, <, >
300             
301             'shared': Only list objects with permissions set
302              
303             'size_range': Include objects with byte size in (from, to).
304                           Use None to specify unlimited
305         
306         Raises:
307             NotAllowedError: Operation not permitted
308             
309             NameError: Container does not exist
310         """
311         return []
312     
313     def list_object_meta(self, user, account, container, domain, until=None):
314         """Return a list with all the container's object meta keys for the domain.
315         
316         Raises:
317             NotAllowedError: Operation not permitted
318             
319             NameError: Container does not exist
320         """
321         return []
322     
323     def get_object_meta(self, user, account, container, name, domain, version=None):
324         """Return a dictionary with the object metadata for the domain.
325         
326         The keys returned are all user-defined, except:
327             'name': The object name
328             
329             'bytes': The total data size
330             
331             'hash': The hashmap hash
332             
333             'modified': Last modification timestamp (overall)
334             
335             'modified_by': The user that committed the object (version requested)
336             
337             'version': The version identifier
338             
339             'version_timestamp': The version's modification timestamp
340             
341             'uuid': A unique identifier that persists data or metadata updates and renames
342         
343         Raises:
344             NotAllowedError: Operation not permitted
345             
346             NameError: Container/object does not exist
347             
348             IndexError: Version does not exist
349         """
350         return {}
351     
352     def update_object_meta(self, user, account, container, name, domain, meta, replace=False):
353         """Update the metadata associated with the object for the domain and return the new version.
354         
355         Parameters:
356             'domain': Metadata domain
357             
358             'meta': Dictionary with metadata to update
359             
360             'replace': Replace instead of update
361         
362         Raises:
363             NotAllowedError: Operation not permitted
364             
365             NameError: Container/object does not exist
366         """
367         return ''
368     
369     def get_object_permissions(self, user, account, container, name):
370         """Return the action allowed on the object, the path
371         from which the object gets its permissions from,
372         along with a dictionary containing the permissions.
373         
374         The dictionary keys are (also used for defining the action):
375             'read': The object is readable by the users/groups in the list
376             
377             'write': The object is writable by the users/groups in the list
378         
379         Raises:
380             NotAllowedError: Operation not permitted
381             
382             NameError: Container/object does not exist
383         """
384         return {}
385     
386     def update_object_permissions(self, user, account, container, name, permissions):
387         """Update the permissions associated with the object.
388         
389         Parameters:
390             'permissions': Dictionary with permissions to update
391         
392         Raises:
393             NotAllowedError: Operation not permitted
394             
395             NameError: Container/object does not exist
396             
397             ValueError: Invalid users/groups in permissions
398             
399             AttributeError: Can not set permissions, as this object
400                 is already shared/private by another object higher
401                 in the hierarchy, or setting permissions here will
402                 invalidate other permissions deeper in the hierarchy
403         """
404         return
405     
406     def get_object_public(self, user, account, container, name):
407         """Return the public id of the object if applicable.
408         
409         Raises:
410             NotAllowedError: Operation not permitted
411             
412             NameError: Container/object does not exist
413         """
414         return None
415     
416     def update_object_public(self, user, account, container, name, public):
417         """Update the public status of the object.
418         
419         Parameters:
420             'public': Boolean value
421         
422         Raises:
423             NotAllowedError: Operation not permitted
424             
425             NameError: Container/object does not exist
426         """
427         return
428     
429     def get_object_hashmap(self, user, account, container, name, version=None):
430         """Return the object's size and a list with partial hashes.
431         
432         Raises:
433             NotAllowedError: Operation not permitted
434             
435             NameError: Container/object does not exist
436             
437             IndexError: Version does not exist
438         """
439         return 0, []
440     
441     def update_object_hashmap(self, user, account, container, name, size, hashmap, domain, meta={}, replace_meta=False, permissions=None):
442         """Create/update an object with the specified size and partial hashes and return the new version.
443         
444         Parameters:
445             'domain': Metadata domain
446             
447             'meta': Dictionary with metadata to change
448             
449             'replace_meta': Replace metadata instead of update
450             
451             'permissions': Updated object permissions
452         
453         Raises:
454             NotAllowedError: Operation not permitted
455             
456             NameError: Container does not exist
457             
458             ValueError: Invalid users/groups in permissions
459             
460             AttributeError: Can not set permissions
461             
462             QuotaError: Account or container quota exceeded
463         """
464         return ''
465     
466     def copy_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, domain, meta={}, replace_meta=False, permissions=None, src_version=None):
467         """Copy an object's data and metadata and return the new version.
468         
469         Parameters:
470             'domain': Metadata domain
471             
472             'meta': Dictionary with metadata to change from source to destination
473             
474             'replace_meta': Replace metadata instead of update
475             
476             'permissions': New object permissions
477             
478             'src_version': Copy from the version provided
479         
480         Raises:
481             NotAllowedError: Operation not permitted
482             
483             NameError: Container/object does not exist
484             
485             IndexError: Version does not exist
486             
487             ValueError: Invalid users/groups in permissions
488             
489             AttributeError: Can not set permissions
490             
491             QuotaError: Account or container quota exceeded
492         """
493         return ''
494     
495     def move_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, domain, meta={}, replace_meta=False, permissions=None):
496         """Move an object's data and metadata and return the new version.
497         
498         Parameters:
499             'domain': Metadata domain
500             
501             'meta': Dictionary with metadata to change from source to destination
502             
503             'replace_meta': Replace metadata instead of update
504             
505             'permissions': New object permissions
506         
507         Raises:
508             NotAllowedError: Operation not permitted
509             
510             NameError: Container/object does not exist
511             
512             ValueError: Invalid users/groups in permissions
513             
514             AttributeError: Can not set permissions
515             
516             QuotaError: Account or container quota exceeded
517         """
518         return ''
519     
520     def delete_object(self, user, account, container, name, until=None):
521         """Delete/purge an object.
522         
523         Raises:
524             NotAllowedError: Operation not permitted
525             
526             NameError: Container/object does not exist
527         """
528         return
529     
530     def list_versions(self, user, account, container, name):
531         """Return a list of all (version, version_timestamp) tuples for an object.
532         
533         Raises:
534             NotAllowedError: Operation not permitted
535         """
536         return []
537     
538     def get_uuid(self, user, uuid):
539         """Return the (account, container, name) for the UUID given.
540         
541         Raises:
542             NotAllowedError: Operation not permitted
543             
544             NameError: UUID does not exist
545         """
546         return None
547     
548     def get_public(self, user, public):
549         """Return the (account, container, name) for the public id given.
550         
551         Raises:
552             NotAllowedError: Operation not permitted
553             
554             NameError: Public id does not exist
555         """
556         return None
557     
558     def get_block(self, hash):
559         """Return a block's data.
560         
561         Raises:
562             NameError: Block does not exist
563         """
564         return ''
565     
566     def put_block(self, data):
567         """Store a block and return the hash."""
568         return 0
569     
570     def update_block(self, hash, data, offset=0):
571         """Update a known block and return the hash.
572         
573         Raises:
574             IndexError: Offset or data outside block limits
575         """
576         return 0