Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ d2869078

History | View | Annotate | Download (21.4 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
from synnefo.lib.singleton import ArgBasedSingleton
39

    
40
class NotAllowedError(Exception):
41
    pass
42

    
43
class QuotaError(Exception):
44
    pass
45

    
46
class AccountExists(NameError):
47
    pass
48
    
49
class ContainerExists(NameError):
50
    pass
51

    
52
class AccountNotEmpty(IndexError):
53
    pass
54

    
55
class ContainerNotEmpty(IndexError):
56
    pass
57

    
58
class ItemNotExists(NameError):
59
    pass
60

    
61
class VersionNotExists(IndexError):
62
    pass
63

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