Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 78e1f8da

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 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=None, until=None,
116
                         include_user_defined=True):
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
        Raises:
131
            NotAllowedError: Operation not permitted
132

133
            ValueError: if domain is None and include_user_defined==True
134
        """
135
        return {}
136

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

140
        Parameters:
141
            'domain': Metadata domain
142

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

146
            'replace': Replace instead of update
147

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

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

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

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

164
        Raises:
165
            NotAllowedError: Operation not permitted
166

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

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

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

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

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

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

187
        Raises:
188
            NotAllowedError: Operation not permitted
189

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

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

197
        Raises:
198
            NotAllowedError: Operation not permitted
199

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

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

207
        Raises:
208
            NotAllowedError: Operation not permitted
209

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

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

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

221
            'limit': Number of containers to return
222

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

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

227

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

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

237
        Raises:
238
            NotAllowedError: Operation not permitted
239

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

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

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

251
            'count': The number of objects
252

253
            'bytes': The total data size
254

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

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

259
        Raises:
260
            NotAllowedError: Operation not permitted
261

262
            ItemNotExists: Container does not exist
263

264
            ValueError: if domain is None and include_user_defined==True
265
        """
266
        return {}
267

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

272
        Parameters:
273
            'domain': Metadata domain
274

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

278
            'replace': Replace instead of update
279

280
        Raises:
281
            NotAllowedError: Operation not permitted
282

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

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

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

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

295
        Raises:
296
            NotAllowedError: Operation not permitted
297

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

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

306
        Raises:
307
            NotAllowedError: Operation not permitted
308

309
            ItemNotExists: Container does not exist
310

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

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

318
        Raises:
319
            NotAllowedError: Operation not permitted
320

321
            ContainerExists: Container already exists
322

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

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

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

335
        Raises:
336
            NotAllowedError: Operation not permitted
337

338
            ItemNotExists: Container does not exist
339

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

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

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

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

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

358
            'limit': Number of objects to return
359

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

366
            'domain': Metadata domain for keys
367

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

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

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

377
            'public': Only list public objects
378

379

380
        Raises:
381
            NotAllowedError: Operation not permitted
382

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

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

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

396
        Raises:
397
            NotAllowedError: Operation not permitted
398

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

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

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

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

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

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

422
            'bytes': The total data size
423

424
            'type': The content type
425

426
            'hash': The hashmap hash
427

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

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

433
            'version': The version identifier
434

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

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

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

442
        Raises:
443
            NotAllowedError: Operation not permitted
444

445
            ItemNotExists: Container/object does not exist
446

447
            VersionNotExists: Version does not exist
448

449
            ValueError: if domain is None and include_user_defined==True
450
        """
451
        return {}
452

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

457
        Parameters:
458
            'domain': Metadata domain
459

460
            'meta': Dictionary with metadata to update
461

462
            'replace': Replace instead of update
463

464
        Raises:
465
            NotAllowedError: Operation not permitted
466

467
            ItemNotExists: Container/object does not exist
468
        """
469
        return ''
470

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

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

479
            'write': The object is writable by the users/groups in the list
480

481
        Raises:
482
            NotAllowedError: Operation not permitted
483

484
            ItemNotExists: Container/object does not exist
485
        """
486
        return {}
487

    
488
    def update_object_permissions(self, user, account, container, name,
489
                                  permissions):
490
        """Update (set) the permissions associated with the object.
491

492
        Parameters:
493
            'permissions': Dictionary with permissions to set
494

495
        Raises:
496
            NotAllowedError: Operation not permitted
497

498
            ItemNotExists: Container/object does not exist
499

500
            ValueError: Invalid users/groups in permissions
501
        """
502
        return
503

    
504
    def get_object_public(self, user, account, container, name):
505
        """Return the public id of the object if applicable.
506

507
        Raises:
508
            NotAllowedError: Operation not permitted
509

510
            ItemNotExists: Container/object does not exist
511
        """
512
        return None
513

    
514
    def update_object_public(self, user, account, container, name, public):
515
        """Update the public status of the object.
516

517
        Parameters:
518
            'public': Boolean value
519

520
        Raises:
521
            NotAllowedError: Operation not permitted
522

523
            ItemNotExists: Container/object does not exist
524
        """
525
        return
526

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

530
        Raises:
531
            NotAllowedError: Operation not permitted
532

533
            ItemNotExists: Container/object does not exist
534

535
            VersionNotExists: Version does not exist
536
        """
537
        return 0, []
538

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

544
        Parameters:
545
            'domain': Metadata domain
546

547
            'meta': Dictionary with metadata to change
548

549
            'replace_meta': Replace metadata instead of update
550

551
            'permissions': Updated object permissions
552

553
        Raises:
554
            NotAllowedError: Operation not permitted
555

556
            ItemNotExists: Container does not exist
557

558
            ValueError: Invalid users/groups in permissions
559

560
            QuotaError: Account or container quota exceeded
561
        """
562
        return ''
563

    
564
    def update_object_checksum(self, user, account, container, name, version,
565
                               checksum):
566
        """Update an object's checksum."""
567
        return
568

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

575
        Parameters:
576
            'domain': Metadata domain
577

578
            'meta': Dictionary with metadata to change from source
579
                    to destination
580

581
            'replace_meta': Replace metadata instead of update
582

583
            'permissions': New object permissions
584

585
            'src_version': Copy from the version provided
586

587
            'delimiter': Copy objects whose path starts with
588
                         src_name + delimiter
589

590
        Raises:
591
            NotAllowedError: Operation not permitted
592

593
            ItemNotExists: Container/object does not exist
594

595
            VersionNotExists: Version does not exist
596

597
            ValueError: Invalid users/groups in permissions
598

599
            QuotaError: Account or container quota exceeded
600
        """
601
        return ''
602

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

609
        Parameters:
610
            'domain': Metadata domain
611

612
            'meta': Dictionary with metadata to change from source
613
                    to destination
614

615
            'replace_meta': Replace metadata instead of update
616

617
            'permissions': New object permissions
618

619
            'delimiter': Move objects whose path starts with
620
                         src_name + delimiter
621

622
        Raises:
623
            NotAllowedError: Operation not permitted
624

625
            ItemNotExists: Container/object does not exist
626

627
            ValueError: Invalid users/groups in permissions
628

629
            QuotaError: Account or container quota exceeded
630
        """
631
        return ''
632

    
633
    def delete_object(self, user, account, container, name, until=None,
634
                      delimiter=None):
635
        """Delete/purge an object.
636

637
        Parameters:
638
            'delimiter': Delete objects whose path starting with
639
                         name + delimiter
640

641
        Raises:
642
            NotAllowedError: Operation not permitted
643

644
            ItemNotExists: Container/object does not exist
645
        """
646
        return
647

    
648
    def list_versions(self, user, account, container, name):
649
        """Return a list of all object (version, version_timestamp) tuples.
650

651
        Raises:
652
            NotAllowedError: Operation not permitted
653
        """
654
        return []
655

    
656
    def get_uuid(self, user, uuid):
657
        """Return the (account, container, name) for the UUID given.
658

659
        Raises:
660
            NotAllowedError: Operation not permitted
661

662
            NameError: UUID does not exist
663
        """
664
        return None
665

    
666
    def get_public(self, user, public):
667
        """Return the (account, container, name) for the public id given.
668

669
        Raises:
670
            NotAllowedError: Operation not permitted
671

672
            NameError: Public id does not exist
673
        """
674
        return None
675

    
676
    def get_block(self, hash):
677
        """Return a block's data.
678

679
        Raises:
680
            ItemNotExists: Block does not exist
681
        """
682
        return ''
683

    
684
    def put_block(self, data):
685
        """Store a block and return the hash."""
686
        return 0
687

    
688
    def update_block(self, hash, data, offset=0):
689
        """Update a known block and return the hash.
690

691
        Raises:
692
            IndexError: Offset or data outside block limits
693
        """
694
        return 0
695

    
696
    def get_domain_objects(self, domain, user=None):
697
        """Return a list of tuples for objects under the domain.
698

699
        Parameters:
700
            'user': return only objects accessible to the user.
701
        """