Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 7efc9f86

History | View | Annotate | Download (21.2 kB)

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 AccountExists(NameError):
46
    pass
47
    
48
class ContainerExists(NameError):
49
    pass
50

    
51
class AccountNotEmpty(IndexError):
52
    pass
53

    
54
class ContainerNotEmpty(IndexError):
55
    pass
56

    
57
class ItemNotExists(NameError):
58
    pass
59

    
60
class VersionNotExists(IndexError):
61
    pass
62

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