Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 87835e94

History | View | Annotate | Download (21.1 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_ACCOUNT_QUOTA = 0  # No quota.
36
DEFAULT_CONTAINER_QUOTA = 0  # No quota.
37
DEFAULT_CONTAINER_VERSIONING = 'auto'
38

    
39

    
40
class NotAllowedError(Exception):
41
    pass
42

    
43

    
44
class QuotaError(Exception):
45
    pass
46

    
47

    
48
class AccountExists(NameError):
49
    pass
50

    
51

    
52
class ContainerExists(NameError):
53
    pass
54

    
55

    
56
class AccountNotEmpty(IndexError):
57
    pass
58

    
59

    
60
class ContainerNotEmpty(IndexError):
61
    pass
62

    
63

    
64
class ItemNotExists(NameError):
65
    pass
66

    
67

    
68
class VersionNotExists(IndexError):
69
    pass
70

    
71
class InvalidHash(TypeError):
72
    pass
73

    
74
class BaseBackend(object):
75
    """Abstract backend class.
76

77
    This class serves as a reference for actual implementations.
78

79
    The purpose of the backend is to provide the necessary functions
80
    for handling data and metadata.
81

82
    It is responsible for the actual storage and retrieval of information.
83

84
    Note that the account level is always valid as it is checked
85
    from another subsystem.
86

87
    When not replacing metadata/groups/policy, keys with empty values
88
    should be deleted.
89

90
    The following variables should be available:
91
        'hash_algorithm': Suggested is 'sha256'
92

93
        'block_size': Suggested is 4MB
94

95
        'default_account_policy': A dictionary with default account policy
96
                                  settings
97
        'default_container_policy': A dictionary with default container policy
98
                                    settings
99
    """
100

    
101
    def close(self):
102
        """Close the backend connection."""
103
        pass
104

    
105
    def list_accounts(self, user, marker=None, limit=10000):
106
        """Return a list of accounts the user can access.
107

108
        Keyword arguments:
109
            'marker': Start list from the next item after 'marker'
110

111
            'limit': Number of containers to return
112
        """
113
        return []
114

    
115
    def get_account_meta(self, user, account, domain, until=None,
116
                         include_user_defined=True, external_quota=None):
117
        """Return a dictionary with the account metadata for the domain.
118

119
        The keys returned are all user-defined, except:
120
            'name': The account name
121

122
            'count': The number of containers (or 0)
123

124
            'bytes': The total data size (or 0)
125

126
            'modified': Last modification timestamp (overall)
127

128
            'until_timestamp': Last modification until the timestamp provided
129

130
            'external_quota': The quota computed from external quota holder
131
                              mechanism
132

133
        Raises:
134
            NotAllowedError: Operation not permitted
135
        """
136
        return {}
137

    
138
    def update_account_meta(self, user, account, domain, meta, replace=False):
139
        """Update the metadata associated with the account for the domain.
140

141
        Parameters:
142
            'domain': Metadata domain
143

144
        Keyword arguments:
145
            'meta': Dictionary with metadata to update
146

147
            'replace': Replace instead of update
148

149
        Raises:
150
            NotAllowedError: Operation not permitted
151
        """
152
        return
153

    
154
    def get_account_groups(self, user, account):
155
        """Return a dictionary with the user groups defined for the account.
156

157
        Raises:
158
            NotAllowedError: Operation not permitted
159
        """
160
        return {}
161

    
162
    def update_account_groups(self, user, account, groups, replace=False):
163
        """Update the groups associated with the account.
164

165
        Raises:
166
            NotAllowedError: Operation not permitted
167

168
            ValueError: Invalid data in groups
169
        """
170
        return
171

    
172
    def get_account_policy(self, user, account):
173
        """Return a dictionary with the account policy.
174

175
        The keys returned are:
176
            'quota': The maximum bytes allowed (default is 0 - unlimited)
177

178
            'versioning': Can be 'auto', 'manual' or 'none' (default: 'manual')
179

180
        Raises:
181
            NotAllowedError: Operation not permitted
182
        """
183
        return {}
184

    
185
    def update_account_policy(self, user, account, policy, replace=False):
186
        """Update the policy associated with the account.
187

188
        Raises:
189
            NotAllowedError: Operation not permitted
190

191
            ValueError: Invalid policy defined
192
        """
193
        return
194

    
195
    def put_account(self, user, account, policy=None):
196
        """Create a new account with the given name.
197

198
        Raises:
199
            NotAllowedError: Operation not permitted
200

201
            ValueError: Invalid policy defined
202
        """
203
        return
204

    
205
    def delete_account(self, user, account):
206
        """Delete the account with the given name.
207

208
        Raises:
209
            NotAllowedError: Operation not permitted
210

211
            AccountNotEmpty: Account is not empty
212
        """
213
        return
214

    
215
    def list_containers(self, user, account, marker=None, limit=10000,
216
                        shared=False, until=None, public=False):
217
        """Return a list of container names existing under an account.
218

219
        Keyword arguments:
220
            'marker': Start list from the next item after 'marker'
221

222
            'limit': Number of containers to return
223

224
            'shared': Only list containers with permissions set
225

226
            'public': Only list containers containing public objects
227

228

229
        Raises:
230
            NotAllowedError: Operation not permitted
231
        """
232
        return []
233

    
234
    def list_container_meta(self, user, account, container, domain,
235
                            until=None):
236
        """Return a list of the container's object meta keys for a domain.
237

238
        Raises:
239
            NotAllowedError: Operation not permitted
240

241
            ItemNotExists: Container does not exist
242
        """
243
        return []
244

    
245
    def get_container_meta(self, user, account, container, domain, until=None,
246
                           include_user_defined=True):
247
        """Return a dictionary with the container metadata for the domain.
248

249
        The keys returned are all user-defined, except:
250
            'name': The container name
251

252
            'count': The number of objects
253

254
            'bytes': The total data size
255

256
            'modified': Last modification timestamp (overall)
257

258
            'until_timestamp': Last modification until the timestamp provided
259

260
        Raises:
261
            NotAllowedError: Operation not permitted
262

263
            ItemNotExists: Container does not exist
264
        """
265
        return {}
266

    
267
    def update_container_meta(self, user, account, container, domain, meta,
268
                              replace=False):
269
        """Update the metadata associated with the container for the domain.
270

271
        Parameters:
272
            'domain': Metadata domain
273

274
        Keyword arguments:
275
            'meta': Dictionary with metadata to update
276

277
            'replace': Replace instead of update
278

279
        Raises:
280
            NotAllowedError: Operation not permitted
281

282
            ItemNotExists: Container does not exist
283
        """
284
        return
285

    
286
    def get_container_policy(self, user, account, container):
287
        """Return a dictionary with the container policy.
288

289
        The keys returned are:
290
            'quota': The maximum bytes allowed (default is 0 - unlimited)
291

292
            'versioning': Can be 'auto', 'manual' or 'none' (default: 'manual')
293

294
        Raises:
295
            NotAllowedError: Operation not permitted
296

297
            ItemNotExists: Container does not exist
298
        """
299
        return {}
300

    
301
    def update_container_policy(self, user, account, container, policy,
302
                                replace=False):
303
        """Update the policy associated with the container.
304

305
        Raises:
306
            NotAllowedError: Operation not permitted
307

308
            ItemNotExists: Container does not exist
309

310
            ValueError: Invalid policy defined
311
        """
312
        return
313

    
314
    def put_container(self, user, account, container, policy=None):
315
        """Create a new container with the given name.
316

317
        Raises:
318
            NotAllowedError: Operation not permitted
319

320
            ContainerExists: Container already exists
321

322
            ValueError: Invalid policy defined
323
        """
324
        return
325

    
326
    def delete_container(self, user, account, container, until=None,
327
                         delimiter=None):
328
        """Delete/purge the container with the given name.
329

330
        Keyword arguments:
331
            'delimiter': If not None, deletes the container contents starting
332
                         with the delimiter
333

334
        Raises:
335
            NotAllowedError: Operation not permitted
336

337
            ItemNotExists: Container does not exist
338

339
            ContainerNotEmpty: Container is not empty
340
        """
341
        return
342

    
343
    def list_objects(self, user, account, container, prefix='', delimiter=None,
344
                     marker=None, limit=10000, virtual=True, domain=None,
345
                     keys=None, shared=False, until=None, size_range=None,
346
                     public=False):
347
        """List (object name, object version_id) under a container.
348

349
        Keyword arguments:
350
            'prefix': List objects starting with 'prefix'
351

352
            'delimiter': Return unique names before 'delimiter' and
353
                         after 'prefix'
354

355
            'marker': Start list from the next item after 'marker'
356

357
            'limit': Number of objects to return
358

359
            'virtual': If not set, the result will only include names starting
360
                       with 'prefix' and ending without a 'delimiter' or with
361
                       the first occurance of the 'delimiter' after 'prefix'.
362
                       If set, the result will include all names after 'prefix'
363
                       up to and including the 'delimiter' if it is found
364

365
            'domain': Metadata domain for keys
366

367
            'keys': Include objects that satisfy the key queries in the list.
368
                    Use 'key', '!key' for existence queries, 'key op value' for
369
                    value queries, where 'op' can be one of =, !=, <=, >=, <, >
370

371
            'shared': Only list objects with permissions set
372

373
            'size_range': Include objects with byte size in (from, to).
374
                          Use None to specify unlimited
375

376
            'public': Only list public objects
377

378

379
        Raises:
380
            NotAllowedError: Operation not permitted
381

382
            ItemNotExists: Container does not exist
383
        """
384
        return []
385

    
386
    def list_object_meta(self, user, account, container, prefix='',
387
                         delimiter=None, marker=None, limit=10000,
388
                         virtual=True, domain=None, keys=None, shared=False,
389
                         until=None, size_range=None, public=False):
390
        """Return a list of metadata dicts of objects under a container.
391

392
        Same parameters with list_objects. Returned dicts have no user-defined
393
        metadata and, if until is not None, a None 'modified' timestamp.
394

395
        Raises:
396
            NotAllowedError: Operation not permitted
397

398
            ItemNotExists: Container does not exist
399
        """
400
        return []
401

    
402
    def list_object_permissions(self, user, account, container, prefix=''):
403
        """Return a list of paths enforce permissions under a container.
404

405
        Raises:
406
            NotAllowedError: Operation not permitted
407
        """
408
        return []
409

    
410
    def list_object_public(self, user, account, container, prefix=''):
411
        """Return a mapping of object paths to public ids under a container."""
412
        return {}
413

    
414
    def get_object_meta(self, user, account, container, name, domain,
415
                        version=None, include_user_defined=True):
416
        """Return a dictionary with the object metadata for the domain.
417

418
        The keys returned are all user-defined, except:
419
            'name': The object name
420

421
            'bytes': The total data size
422

423
            'type': The content type
424

425
            'hash': The hashmap hash
426

427
            'modified': Last modification timestamp (overall)
428

429
            'modified_by': The user that committed the object
430
                           (version requested)
431

432
            'version': The version identifier
433

434
            'version_timestamp': The version's modification timestamp
435

436
            'uuid': A unique identifier that persists data or metadata updates
437
                    and renames
438

439
            'checksum': The MD5 sum of the object (may be empty)
440

441
        Raises:
442
            NotAllowedError: Operation not permitted
443

444
            ItemNotExists: Container/object does not exist
445

446
            VersionNotExists: Version does not exist
447
        """
448
        return {}
449

    
450
    def update_object_meta(self, user, account, container, name, domain, meta,
451
                           replace=False):
452
        """Update object metadata for a domain and return the new version.
453

454
        Parameters:
455
            'domain': Metadata domain
456

457
            'meta': Dictionary with metadata to update
458

459
            'replace': Replace instead of update
460

461
        Raises:
462
            NotAllowedError: Operation not permitted
463

464
            ItemNotExists: Container/object does not exist
465
        """
466
        return ''
467

    
468
    def get_object_permissions(self, user, account, container, name):
469
        """Return the action allowed on the object, the path
470
        from which the object gets its permissions from,
471
        along with a dictionary containing the permissions.
472

473
        The dictionary keys are (also used for defining the action):
474
            'read': The object is readable by the users/groups in the list
475

476
            'write': The object is writable by the users/groups in the list
477

478
        Raises:
479
            NotAllowedError: Operation not permitted
480

481
            ItemNotExists: Container/object does not exist
482
        """
483
        return {}
484

    
485
    def update_object_permissions(self, user, account, container, name,
486
                                  permissions):
487
        """Update (set) the permissions associated with the object.
488

489
        Parameters:
490
            'permissions': Dictionary with permissions to set
491

492
        Raises:
493
            NotAllowedError: Operation not permitted
494

495
            ItemNotExists: Container/object does not exist
496

497
            ValueError: Invalid users/groups in permissions
498
        """
499
        return
500

    
501
    def get_object_public(self, user, account, container, name):
502
        """Return the public id of the object if applicable.
503

504
        Raises:
505
            NotAllowedError: Operation not permitted
506

507
            ItemNotExists: Container/object does not exist
508
        """
509
        return None
510

    
511
    def update_object_public(self, user, account, container, name, public):
512
        """Update the public status of the object.
513

514
        Parameters:
515
            'public': Boolean value
516

517
        Raises:
518
            NotAllowedError: Operation not permitted
519

520
            ItemNotExists: Container/object does not exist
521
        """
522
        return
523

    
524
    def get_object_hashmap(self, user, account, container, name, version=None):
525
        """Return the object's size and a list with partial hashes.
526

527
        Raises:
528
            NotAllowedError: Operation not permitted
529

530
            ItemNotExists: Container/object does not exist
531

532
            VersionNotExists: Version does not exist
533
        """
534
        return 0, []
535

    
536
    def update_object_hashmap(self, user, account, container, name, size, type,
537
                              hashmap, checksum, domain, meta=None,
538
                              replace_meta=False, permissions=None):
539
        """Create/update an object's hashmap and return the new version.
540

541
        Parameters:
542
            'domain': Metadata domain
543

544
            'meta': Dictionary with metadata to change
545

546
            'replace_meta': Replace metadata instead of update
547

548
            'permissions': Updated object permissions
549

550
        Raises:
551
            NotAllowedError: Operation not permitted
552

553
            ItemNotExists: Container does not exist
554

555
            ValueError: Invalid users/groups in permissions
556

557
            QuotaError: Account or container quota exceeded
558
        """
559
        return ''
560

    
561
    def update_object_checksum(self, user, account, container, name, version,
562
                               checksum):
563
        """Update an object's checksum."""
564
        return
565

    
566
    def copy_object(self, user, src_account, src_container, src_name,
567
                    dest_account, dest_container, dest_name, type, domain,
568
                    meta=None, replace_meta=False, permissions=None,
569
                    src_version=None, delimiter=None):
570
        """Copy an object's data and metadata and return the new version.
571

572
        Parameters:
573
            'domain': Metadata domain
574

575
            'meta': Dictionary with metadata to change from source
576
                    to destination
577

578
            'replace_meta': Replace metadata instead of update
579

580
            'permissions': New object permissions
581

582
            'src_version': Copy from the version provided
583

584
            'delimiter': Copy objects whose path starts with
585
                         src_name + delimiter
586

587
        Raises:
588
            NotAllowedError: Operation not permitted
589

590
            ItemNotExists: Container/object does not exist
591

592
            VersionNotExists: Version does not exist
593

594
            ValueError: Invalid users/groups in permissions
595

596
            QuotaError: Account or container quota exceeded
597
        """
598
        return ''
599

    
600
    def move_object(self, user, src_account, src_container, src_name,
601
                    dest_account, dest_container, dest_name, type, domain,
602
                    meta=None, replace_meta=False, permissions=None,
603
                    delimiter=None):
604
        """Move an object's data and metadata and return the new version.
605

606
        Parameters:
607
            'domain': Metadata domain
608

609
            'meta': Dictionary with metadata to change from source
610
                    to destination
611

612
            'replace_meta': Replace metadata instead of update
613

614
            'permissions': New object permissions
615

616
            'delimiter': Move objects whose path starts with
617
                         src_name + delimiter
618

619
        Raises:
620
            NotAllowedError: Operation not permitted
621

622
            ItemNotExists: Container/object does not exist
623

624
            ValueError: Invalid users/groups in permissions
625

626
            QuotaError: Account or container quota exceeded
627
        """
628
        return ''
629

    
630
    def delete_object(self, user, account, container, name, until=None,
631
                      delimiter=None):
632
        """Delete/purge an object.
633

634
        Parameters:
635
            'delimiter': Delete objects whose path starting with
636
                         name + delimiter
637

638
        Raises:
639
            NotAllowedError: Operation not permitted
640

641
            ItemNotExists: Container/object does not exist
642
        """
643
        return
644

    
645
    def list_versions(self, user, account, container, name):
646
        """Return a list of all object (version, version_timestamp) tuples.
647

648
        Raises:
649
            NotAllowedError: Operation not permitted
650
        """
651
        return []
652

    
653
    def get_uuid(self, user, uuid):
654
        """Return the (account, container, name) for the UUID given.
655

656
        Raises:
657
            NotAllowedError: Operation not permitted
658

659
            NameError: UUID does not exist
660
        """
661
        return None
662

    
663
    def get_public(self, user, public):
664
        """Return the (account, container, name) for the public id given.
665

666
        Raises:
667
            NotAllowedError: Operation not permitted
668

669
            NameError: Public id does not exist
670
        """
671
        return None
672

    
673
    def get_block(self, hash):
674
        """Return a block's data.
675

676
        Raises:
677
            ItemNotExists: Block does not exist
678
        """
679
        return ''
680

    
681
    def put_block(self, data):
682
        """Store a block and return the hash."""
683
        return 0
684

    
685
    def update_block(self, hash, data, offset=0):
686
        """Update a known block and return the hash.
687

688
        Raises:
689
            IndexError: Offset or data outside block limits
690
        """
691
        return 0
692

    
693
    def get_domain_objects(self, domain, user=None):
694
        """Return a list of tuples for objects under the domain.
695

696
        Parameters:
697
            'user': return only objects accessible to the user.
698
        """