Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 1e47e49d

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_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 IllegalOperationError(NotAllowedError):
45
    pass
46

    
47

    
48
class QuotaError(Exception):
49
    pass
50

    
51

    
52
class AccountExists(NameError):
53
    pass
54

    
55

    
56
class ContainerExists(NameError):
57
    pass
58

    
59

    
60
class AccountNotEmpty(IndexError):
61
    pass
62

    
63

    
64
class ContainerNotEmpty(IndexError):
65
    pass
66

    
67

    
68
class ItemNotExists(NameError):
69
    pass
70

    
71

    
72
class VersionNotExists(IndexError):
73
    pass
74

    
75

    
76
class InvalidHash(TypeError):
77
    pass
78

    
79

    
80
class BaseBackend(object):
81
    """Abstract backend class.
82

83
    This class serves as a reference for actual implementations.
84

85
    The purpose of the backend is to provide the necessary functions
86
    for handling data and metadata.
87

88
    It is responsible for the actual storage and retrieval of information.
89

90
    Note that the account level is always valid as it is checked
91
    from another subsystem.
92

93
    When not replacing metadata/groups/policy, keys with empty values
94
    should be deleted.
95

96
    The following variables should be available:
97
        'hash_algorithm': Suggested is 'sha256'
98

99
        'block_size': Suggested is 4MB
100

101
        'default_account_policy': A dictionary with default account policy
102
                                  settings
103
        'default_container_policy': A dictionary with default container policy
104
                                    settings
105
    """
106

    
107
    def close(self):
108
        """Close the backend connection."""
109
        pass
110

    
111
    def list_accounts(self, user, marker=None, limit=10000):
112
        """Return a list of accounts the user can access.
113

114
        Keyword arguments:
115
            'marker': Start list from the next item after 'marker'
116

117
            'limit': Number of containers to return
118
        """
119
        return []
120

    
121
    def get_account_meta(self, user, account, domain, until=None,
122
                         include_user_defined=True, external_quota=None):
123
        """Return a dictionary with the account metadata for the domain.
124

125
        The keys returned are all user-defined, except:
126
            'name': The account name
127

128
            'count': The number of containers (or 0)
129

130
            'bytes': The total data size (or 0)
131

132
            'modified': Last modification timestamp (overall)
133

134
            'until_timestamp': Last modification until the timestamp provided
135

136
            'external_quota': The quota computed from external quota holder
137
                              mechanism
138

139
        Raises:
140
            NotAllowedError: Operation not permitted
141
        """
142
        return {}
143

    
144
    def update_account_meta(self, user, account, domain, meta, replace=False):
145
        """Update the metadata associated with the account for the domain.
146

147
        Parameters:
148
            'domain': Metadata domain
149

150
        Keyword arguments:
151
            'meta': Dictionary with metadata to update
152

153
            'replace': Replace instead of update
154

155
        Raises:
156
            NotAllowedError: Operation not permitted
157
        """
158
        return
159

    
160
    def get_account_groups(self, user, account):
161
        """Return a dictionary with the user groups defined for the account.
162

163
        Raises:
164
            NotAllowedError: Operation not permitted
165
        """
166
        return {}
167

    
168
    def update_account_groups(self, user, account, groups, replace=False):
169
        """Update the groups associated with the account.
170

171
        Raises:
172
            NotAllowedError: Operation not permitted
173

174
            ValueError: Invalid data in groups
175
        """
176
        return
177

    
178
    def get_account_policy(self, user, account):
179
        """Return a dictionary with the account policy.
180

181
        The keys returned are:
182
            'quota': The maximum bytes allowed (default is 0 - unlimited)
183

184
            'versioning': Can be 'auto', 'manual' or 'none' (default: 'manual')
185

186
        Raises:
187
            NotAllowedError: Operation not permitted
188
        """
189
        return {}
190

    
191
    def update_account_policy(self, user, account, policy, replace=False):
192
        """Update the policy associated with the account.
193

194
        Raises:
195
            NotAllowedError: Operation not permitted
196

197
            ValueError: Invalid policy defined
198
        """
199
        return
200

    
201
    def put_account(self, user, account, policy=None):
202
        """Create a new account with the given name.
203

204
        Raises:
205
            NotAllowedError: Operation not permitted
206

207
            ValueError: Invalid policy defined
208
        """
209
        return
210

    
211
    def delete_account(self, user, account):
212
        """Delete the account with the given name.
213

214
        Raises:
215
            NotAllowedError: Operation not permitted
216

217
            AccountNotEmpty: Account is not empty
218
        """
219
        return
220

    
221
    def list_containers(self, user, account, marker=None, limit=10000,
222
                        shared=False, until=None, public=False):
223
        """Return a list of container names existing under an account.
224

225
        Keyword arguments:
226
            'marker': Start list from the next item after 'marker'
227

228
            'limit': Number of containers to return
229

230
            'shared': Only list containers with permissions set
231

232
            'public': Only list containers containing public objects
233

234

235
        Raises:
236
            NotAllowedError: Operation not permitted
237
        """
238
        return []
239

    
240
    def list_container_meta(self, user, account, container, domain,
241
                            until=None):
242
        """Return a list of the container's object meta keys for a domain.
243

244
        Raises:
245
            NotAllowedError: Operation not permitted
246

247
            ItemNotExists: Container does not exist
248
        """
249
        return []
250

    
251
    def get_container_meta(self, user, account, container, domain, until=None,
252
                           include_user_defined=True):
253
        """Return a dictionary with the container metadata for the domain.
254

255
        The keys returned are all user-defined, except:
256
            'name': The container name
257

258
            'count': The number of objects
259

260
            'bytes': The total data size
261

262
            'modified': Last modification timestamp (overall)
263

264
            'until_timestamp': Last modification until the timestamp provided
265

266
        Raises:
267
            NotAllowedError: Operation not permitted
268

269
            ItemNotExists: Container does not exist
270
        """
271
        return {}
272

    
273
    def update_container_meta(self, user, account, container, domain, meta,
274
                              replace=False):
275
        """Update the metadata associated with the container for the domain.
276

277
        Parameters:
278
            'domain': Metadata domain
279

280
        Keyword arguments:
281
            'meta': Dictionary with metadata to update
282

283
            'replace': Replace instead of update
284

285
        Raises:
286
            NotAllowedError: Operation not permitted
287

288
            ItemNotExists: Container does not exist
289
        """
290
        return
291

    
292
    def get_container_policy(self, user, account, container):
293
        """Return a dictionary with the container policy.
294

295
        The keys returned are:
296
            'quota': The maximum bytes allowed (default is 0 - unlimited)
297

298
            'versioning': Can be 'auto', 'manual' or 'none' (default: 'manual')
299

300
        Raises:
301
            NotAllowedError: Operation not permitted
302

303
            ItemNotExists: Container does not exist
304
        """
305
        return {}
306

    
307
    def update_container_policy(self, user, account, container, policy,
308
                                replace=False):
309
        """Update the policy associated with the container.
310

311
        Raises:
312
            NotAllowedError: Operation not permitted
313

314
            ItemNotExists: Container does not exist
315

316
            ValueError: Invalid policy defined
317
        """
318
        return
319

    
320
    def put_container(self, user, account, container, policy=None):
321
        """Create a new container with the given name.
322

323
        Raises:
324
            NotAllowedError: Operation not permitted
325

326
            ContainerExists: Container already exists
327

328
            ValueError: Invalid policy defined
329
        """
330
        return
331

    
332
    def delete_container(self, user, account, container, until=None,
333
                         delimiter=None):
334
        """Delete/purge the container with the given name.
335

336
        Keyword arguments:
337
            'delimiter': If not None, deletes the container contents starting
338
                         with the delimiter
339

340
        Raises:
341
            NotAllowedError: Operation not permitted
342

343
            ItemNotExists: Container does not exist
344

345
            ContainerNotEmpty: Container is not empty
346
        """
347
        return
348

    
349
    def list_objects(self, user, account, container, prefix='', delimiter=None,
350
                     marker=None, limit=10000, virtual=True, domain=None,
351
                     keys=None, shared=False, until=None, size_range=None,
352
                     public=False):
353
        """List (object name, object version_id) under a container.
354

355
        Keyword arguments:
356
            'prefix': List objects starting with 'prefix'
357

358
            'delimiter': Return unique names before 'delimiter' and
359
                         after 'prefix'
360

361
            'marker': Start list from the next item after 'marker'
362

363
            'limit': Number of objects to return
364

365
            'virtual': If not set, the result will only include names starting
366
                       with 'prefix' and ending without a 'delimiter' or with
367
                       the first occurance of the 'delimiter' after 'prefix'.
368
                       If set, the result will include all names after 'prefix'
369
                       up to and including the 'delimiter' if it is found
370

371
            'domain': Metadata domain for keys
372

373
            'keys': Include objects that satisfy the key queries in the list.
374
                    Use 'key', '!key' for existence queries, 'key op value' for
375
                    value queries, where 'op' can be one of =, !=, <=, >=, <, >
376

377
            'shared': Only list objects with permissions set
378

379
            'size_range': Include objects with byte size in (from, to).
380
                          Use None to specify unlimited
381

382
            'public': Only list public objects
383

384

385
        Raises:
386
            NotAllowedError: Operation not permitted
387

388
            ItemNotExists: Container does not exist
389
        """
390
        return []
391

    
392
    def list_object_meta(self, user, account, container, prefix='',
393
                         delimiter=None, marker=None, limit=10000,
394
                         virtual=True, domain=None, keys=None, shared=False,
395
                         until=None, size_range=None, public=False):
396
        """Return a list of metadata dicts of objects under a container.
397

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

401
        Raises:
402
            NotAllowedError: Operation not permitted
403

404
            ItemNotExists: Container does not exist
405
        """
406
        return []
407

    
408
    def list_object_permissions(self, user, account, container, prefix=''):
409
        """Return a list of paths enforce permissions under a container.
410

411
        Raises:
412
            NotAllowedError: Operation not permitted
413
        """
414
        return []
415

    
416
    def list_object_public(self, user, account, container, prefix=''):
417
        """Return a mapping of object paths to public ids under a container."""
418
        return {}
419

    
420
    def get_object_meta(self, user, account, container, name, domain,
421
                        version=None, include_user_defined=True):
422
        """Return a dictionary with the object metadata for the domain.
423

424
        The keys returned are all user-defined, except:
425
            'name': The object name
426

427
            'bytes': The total data size
428

429
            'type': The content type
430

431
            'hash': The hashmap hash
432

433
            'modified': Last modification timestamp (overall)
434

435
            'modified_by': The user that committed the object
436
                           (version requested)
437

438
            'version': The version identifier
439

440
            'version_timestamp': The version's modification timestamp
441

442
            'uuid': A unique identifier that persists data or metadata updates
443
                    and renames
444

445
            'checksum': The MD5 sum of the object (may be empty)
446

447
        Raises:
448
            NotAllowedError: Operation not permitted
449

450
            ItemNotExists: Container/object does not exist
451

452
            VersionNotExists: Version does not exist
453
        """
454
        return {}
455

    
456
    def update_object_meta(self, user, account, container, name, domain, meta,
457
                           replace=False):
458
        """Update object metadata for a domain and return the new version.
459

460
        Parameters:
461
            'domain': Metadata domain
462

463
            'meta': Dictionary with metadata to update
464

465
            'replace': Replace instead of update
466

467
        Raises:
468
            NotAllowedError: Operation not permitted
469

470
            ItemNotExists: Container/object does not exist
471
        """
472
        return ''
473

    
474
    def get_object_permissions(self, user, account, container, name):
475
        """Return the action allowed on the object, the path
476
        from which the object gets its permissions from,
477
        along with a dictionary containing the permissions.
478

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

482
            'write': The object is writable by the users/groups in the list
483

484
        Raises:
485
            NotAllowedError: Operation not permitted
486

487
            ItemNotExists: Container/object does not exist
488
        """
489
        return {}
490

    
491
    def update_object_permissions(self, user, account, container, name,
492
                                  permissions):
493
        """Update (set) the permissions associated with the object.
494

495
        Parameters:
496
            'permissions': Dictionary with permissions to set
497

498
        Raises:
499
            NotAllowedError: Operation not permitted
500

501
            ItemNotExists: Container/object does not exist
502

503
            ValueError: Invalid users/groups in permissions
504
        """
505
        return
506

    
507
    def get_object_public(self, user, account, container, name):
508
        """Return the public id of the object if applicable.
509

510
        Raises:
511
            NotAllowedError: Operation not permitted
512

513
            ItemNotExists: Container/object does not exist
514
        """
515
        return None
516

    
517
    def update_object_public(self, user, account, container, name, public):
518
        """Update the public status of the object.
519

520
        Parameters:
521
            'public': Boolean value
522

523
        Raises:
524
            NotAllowedError: Operation not permitted
525

526
            ItemNotExists: Container/object does not exist
527
        """
528
        return
529

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

533
        Raises:
534
            NotAllowedError: Operation not permitted
535

536
            ItemNotExists: Container/object does not exist
537

538
            VersionNotExists: Version does not exist
539
        """
540
        return 0, []
541

    
542
    def update_object_hashmap(self, user, account, container, name, size, type,
543
                              hashmap, checksum, domain, meta=None,
544
                              replace_meta=False, permissions=None):
545
        """Create/update an object's hashmap and return the new version.
546

547
        Parameters:
548
            'domain': Metadata domain
549

550
            'meta': Dictionary with metadata to change
551

552
            'replace_meta': Replace metadata instead of update
553

554
            'permissions': Updated object permissions
555

556
        Raises:
557
            NotAllowedError: Operation not permitted
558

559
            ItemNotExists: Container does not exist
560

561
            ValueError: Invalid users/groups in permissions
562

563
            QuotaError: Account or container quota exceeded
564
        """
565
        return ''
566

    
567
    def update_object_checksum(self, user, account, container, name, version,
568
                               checksum):
569
        """Update an object's checksum."""
570
        return
571

    
572
    def copy_object(self, user, src_account, src_container, src_name,
573
                    dest_account, dest_container, dest_name, type, domain,
574
                    meta=None, replace_meta=False, permissions=None,
575
                    src_version=None, delimiter=None):
576
        """Copy an object's data and metadata and return the new version.
577

578
        Parameters:
579
            'domain': Metadata domain
580

581
            'meta': Dictionary with metadata to change from source
582
                    to destination
583

584
            'replace_meta': Replace metadata instead of update
585

586
            'permissions': New object permissions
587

588
            'src_version': Copy from the version provided
589

590
            'delimiter': Copy objects whose path starts with
591
                         src_name + delimiter
592

593
        Raises:
594
            NotAllowedError: Operation not permitted
595

596
            ItemNotExists: Container/object does not exist
597

598
            VersionNotExists: Version does not exist
599

600
            ValueError: Invalid users/groups in permissions
601

602
            QuotaError: Account or container quota exceeded
603
        """
604
        return ''
605

    
606
    def move_object(self, user, src_account, src_container, src_name,
607
                    dest_account, dest_container, dest_name, type, domain,
608
                    meta=None, replace_meta=False, permissions=None,
609
                    delimiter=None):
610
        """Move an object's data and metadata and return the new version.
611

612
        Parameters:
613
            'domain': Metadata domain
614

615
            'meta': Dictionary with metadata to change from source
616
                    to destination
617

618
            'replace_meta': Replace metadata instead of update
619

620
            'permissions': New object permissions
621

622
            'delimiter': Move objects whose path starts with
623
                         src_name + delimiter
624

625
        Raises:
626
            NotAllowedError: Operation not permitted
627

628
            ItemNotExists: Container/object does not exist
629

630
            ValueError: Invalid users/groups in permissions
631

632
            QuotaError: Account or container quota exceeded
633
        """
634
        return ''
635

    
636
    def delete_object(self, user, account, container, name, until=None,
637
                      delimiter=None):
638
        """Delete/purge an object.
639

640
        Parameters:
641
            'delimiter': Delete objects whose path starting with
642
                         name + delimiter
643

644
        Raises:
645
            NotAllowedError: Operation not permitted
646

647
            ItemNotExists: Container/object does not exist
648
        """
649
        return
650

    
651
    def list_versions(self, user, account, container, name):
652
        """Return a list of all object (version, version_timestamp) tuples.
653

654
        Raises:
655
            NotAllowedError: Operation not permitted
656
        """
657
        return []
658

    
659
    def get_uuid(self, user, uuid):
660
        """Return the (account, container, name) for the UUID given.
661

662
        Raises:
663
            NotAllowedError: Operation not permitted
664

665
            NameError: UUID does not exist
666
        """
667
        return None
668

    
669
    def get_public(self, user, public):
670
        """Return the (account, container, name) for the public id given.
671

672
        Raises:
673
            NotAllowedError: Operation not permitted
674

675
            NameError: Public id does not exist
676
        """
677
        return None
678

    
679
    def get_block(self, hash):
680
        """Return a block's data.
681

682
        Raises:
683
            ItemNotExists: Block does not exist
684
        """
685
        return ''
686

    
687
    def put_block(self, data):
688
        """Store a block and return the hash."""
689
        return 0
690

    
691
    def update_block(self, hash, data, offset=0):
692
        """Update a known block and return the hash.
693

694
        Raises:
695
            IndexError: Offset or data outside block limits
696
        """
697
        return 0
698

    
699
    def get_domain_objects(self, domain, user=None):
700
        """Return a list of tuples for objects under the domain.
701

702
        Parameters:
703
            'user': return only objects accessible to the user.
704
        """