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