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