Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 6e0f3e65

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

    
72
class BaseBackend(object):
73
    """Abstract backend class.
74

75
    This class serves as a reference for actual implementations.
76

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

80
    It is responsible for the actual storage and retrieval of information.
81

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

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

88
    The following variables should be available:
89
        'hash_algorithm': Suggested is 'sha256'
90

91
        'block_size': Suggested is 4MB
92

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

    
99
    def close(self):
100
        """Close the backend connection."""
101
        pass
102

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

106
        Keyword arguments:
107
            'marker': Start list from the next item after 'marker'
108

109
            'limit': Number of containers to return
110
        """
111
        return []
112

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

117
        The keys returned are all user-defined, except:
118
            'name': The account name
119

120
            'count': The number of containers (or 0)
121

122
            'bytes': The total data size (or 0)
123

124
            'modified': Last modification timestamp (overall)
125

126
            'until_timestamp': Last modification until the timestamp provided
127

128
            'external_quota': The quota computed from external quota holder
129
                              mechanism
130

131
        Raises:
132
            NotAllowedError: Operation not permitted
133
        """
134
        return {}
135

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

139
        Parameters:
140
            'domain': Metadata domain
141

142
        Keyword arguments:
143
            'meta': Dictionary with metadata to update
144

145
            'replace': Replace instead of update
146

147
        Raises:
148
            NotAllowedError: Operation not permitted
149
        """
150
        return
151

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

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

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

163
        Raises:
164
            NotAllowedError: Operation not permitted
165

166
            ValueError: Invalid data in groups
167
        """
168
        return
169

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

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

176
            'versioning': Can be 'auto', 'manual' or 'none' (default: 'manual')
177

178
        Raises:
179
            NotAllowedError: Operation not permitted
180
        """
181
        return {}
182

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

186
        Raises:
187
            NotAllowedError: Operation not permitted
188

189
            ValueError: Invalid policy defined
190
        """
191
        return
192

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

196
        Raises:
197
            NotAllowedError: Operation not permitted
198

199
            ValueError: Invalid policy defined
200
        """
201
        return
202

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

206
        Raises:
207
            NotAllowedError: Operation not permitted
208

209
            AccountNotEmpty: Account is not empty
210
        """
211
        return
212

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

217
        Keyword arguments:
218
            'marker': Start list from the next item after 'marker'
219

220
            'limit': Number of containers to return
221

222
            'shared': Only list containers with permissions set
223

224
            'public': Only list containers containing public objects
225

226

227
        Raises:
228
            NotAllowedError: Operation not permitted
229
        """
230
        return []
231

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

236
        Raises:
237
            NotAllowedError: Operation not permitted
238

239
            ItemNotExists: Container does not exist
240
        """
241
        return []
242

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

247
        The keys returned are all user-defined, except:
248
            'name': The container name
249

250
            'count': The number of objects
251

252
            'bytes': The total data size
253

254
            'modified': Last modification timestamp (overall)
255

256
            'until_timestamp': Last modification until the timestamp provided
257

258
        Raises:
259
            NotAllowedError: Operation not permitted
260

261
            ItemNotExists: Container does not exist
262
        """
263
        return {}
264

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

269
        Parameters:
270
            'domain': Metadata domain
271

272
        Keyword arguments:
273
            'meta': Dictionary with metadata to update
274

275
            'replace': Replace instead of update
276

277
        Raises:
278
            NotAllowedError: Operation not permitted
279

280
            ItemNotExists: Container does not exist
281
        """
282
        return
283

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

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

290
            'versioning': Can be 'auto', 'manual' or 'none' (default: 'manual')
291

292
        Raises:
293
            NotAllowedError: Operation not permitted
294

295
            ItemNotExists: Container does not exist
296
        """
297
        return {}
298

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

303
        Raises:
304
            NotAllowedError: Operation not permitted
305

306
            ItemNotExists: Container does not exist
307

308
            ValueError: Invalid policy defined
309
        """
310
        return
311

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

315
        Raises:
316
            NotAllowedError: Operation not permitted
317

318
            ContainerExists: Container already exists
319

320
            ValueError: Invalid policy defined
321
        """
322
        return
323

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

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

332
        Raises:
333
            NotAllowedError: Operation not permitted
334

335
            ItemNotExists: Container does not exist
336

337
            ContainerNotEmpty: Container is not empty
338
        """
339
        return
340

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

347
        Keyword arguments:
348
            'prefix': List objects starting with 'prefix'
349

350
            'delimiter': Return unique names before 'delimiter' and
351
                         after 'prefix'
352

353
            'marker': Start list from the next item after 'marker'
354

355
            'limit': Number of objects to return
356

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

363
            'domain': Metadata domain for keys
364

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

369
            'shared': Only list objects with permissions set
370

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

374
            'public': Only list public objects
375

376

377
        Raises:
378
            NotAllowedError: Operation not permitted
379

380
            ItemNotExists: Container does not exist
381
        """
382
        return []
383

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

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

393
        Raises:
394
            NotAllowedError: Operation not permitted
395

396
            ItemNotExists: Container does not exist
397
        """
398
        return []
399

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

403
        Raises:
404
            NotAllowedError: Operation not permitted
405
        """
406
        return []
407

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

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

416
        The keys returned are all user-defined, except:
417
            'name': The object name
418

419
            'bytes': The total data size
420

421
            'type': The content type
422

423
            'hash': The hashmap hash
424

425
            'modified': Last modification timestamp (overall)
426

427
            'modified_by': The user that committed the object
428
                           (version requested)
429

430
            'version': The version identifier
431

432
            'version_timestamp': The version's modification timestamp
433

434
            'uuid': A unique identifier that persists data or metadata updates
435
                    and renames
436

437
            'checksum': The MD5 sum of the object (may be empty)
438

439
        Raises:
440
            NotAllowedError: Operation not permitted
441

442
            ItemNotExists: Container/object does not exist
443

444
            VersionNotExists: Version does not exist
445
        """
446
        return {}
447

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

452
        Parameters:
453
            'domain': Metadata domain
454

455
            'meta': Dictionary with metadata to update
456

457
            'replace': Replace instead of update
458

459
        Raises:
460
            NotAllowedError: Operation not permitted
461

462
            ItemNotExists: Container/object does not exist
463
        """
464
        return ''
465

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

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

474
            'write': The object is writable by the users/groups in the list
475

476
        Raises:
477
            NotAllowedError: Operation not permitted
478

479
            ItemNotExists: Container/object does not exist
480
        """
481
        return {}
482

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

487
        Parameters:
488
            'permissions': Dictionary with permissions to set
489

490
        Raises:
491
            NotAllowedError: Operation not permitted
492

493
            ItemNotExists: Container/object does not exist
494

495
            ValueError: Invalid users/groups in permissions
496
        """
497
        return
498

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

502
        Raises:
503
            NotAllowedError: Operation not permitted
504

505
            ItemNotExists: Container/object does not exist
506
        """
507
        return None
508

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

512
        Parameters:
513
            'public': Boolean value
514

515
        Raises:
516
            NotAllowedError: Operation not permitted
517

518
            ItemNotExists: Container/object does not exist
519
        """
520
        return
521

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

525
        Raises:
526
            NotAllowedError: Operation not permitted
527

528
            ItemNotExists: Container/object does not exist
529

530
            VersionNotExists: Version does not exist
531
        """
532
        return 0, []
533

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

539
        Parameters:
540
            'domain': Metadata domain
541

542
            'meta': Dictionary with metadata to change
543

544
            'replace_meta': Replace metadata instead of update
545

546
            'permissions': Updated object permissions
547

548
        Raises:
549
            NotAllowedError: Operation not permitted
550

551
            ItemNotExists: Container does not exist
552

553
            ValueError: Invalid users/groups in permissions
554

555
            QuotaError: Account or container quota exceeded
556
        """
557
        return ''
558

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

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

570
        Parameters:
571
            'domain': Metadata domain
572

573
            'meta': Dictionary with metadata to change from source
574
                    to destination
575

576
            'replace_meta': Replace metadata instead of update
577

578
            'permissions': New object permissions
579

580
            'src_version': Copy from the version provided
581

582
            'delimiter': Copy objects whose path starts with
583
                         src_name + delimiter
584

585
        Raises:
586
            NotAllowedError: Operation not permitted
587

588
            ItemNotExists: Container/object does not exist
589

590
            VersionNotExists: Version does not exist
591

592
            ValueError: Invalid users/groups in permissions
593

594
            QuotaError: Account or container quota exceeded
595
        """
596
        return ''
597

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

604
        Parameters:
605
            'domain': Metadata domain
606

607
            'meta': Dictionary with metadata to change from source
608
                    to destination
609

610
            'replace_meta': Replace metadata instead of update
611

612
            'permissions': New object permissions
613

614
            'delimiter': Move objects whose path starts with
615
                         src_name + delimiter
616

617
        Raises:
618
            NotAllowedError: Operation not permitted
619

620
            ItemNotExists: Container/object does not exist
621

622
            ValueError: Invalid users/groups in permissions
623

624
            QuotaError: Account or container quota exceeded
625
        """
626
        return ''
627

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

632
        Parameters:
633
            'delimiter': Delete objects whose path starting with
634
                         name + delimiter
635

636
        Raises:
637
            NotAllowedError: Operation not permitted
638

639
            ItemNotExists: Container/object does not exist
640
        """
641
        return
642

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

646
        Raises:
647
            NotAllowedError: Operation not permitted
648
        """
649
        return []
650

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

654
        Raises:
655
            NotAllowedError: Operation not permitted
656

657
            NameError: UUID does not exist
658
        """
659
        return None
660

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

664
        Raises:
665
            NotAllowedError: Operation not permitted
666

667
            NameError: Public id does not exist
668
        """
669
        return None
670

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

674
        Raises:
675
            ItemNotExists: Block does not exist
676
        """
677
        return ''
678

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

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

686
        Raises:
687
            IndexError: Offset or data outside block limits
688
        """
689
        return 0
690

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

694
        Parameters:
695
            'user': return only objects accessible to the user.
696
        """