Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 2715ade4

History | View | Annotate | Download (19.7 kB)

1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
# Default setting for new accounts.
35
DEFAULT_QUOTA = 0  # No quota.
36
DEFAULT_VERSIONING = 'auto'
37

    
38
from synnefo.lib.singleton import ArgBasedSingleton
39

    
40

    
41
class NotAllowedError(Exception):
42
    pass
43

    
44

    
45
class QuotaError(Exception):
46
    pass
47

    
48

    
49
class AccountExists(NameError):
50
    pass
51

    
52

    
53
class ContainerExists(NameError):
54
    pass
55

    
56

    
57
class AccountNotEmpty(IndexError):
58
    pass
59

    
60

    
61
class ContainerNotEmpty(IndexError):
62
    pass
63

    
64

    
65
class ItemNotExists(NameError):
66
    pass
67

    
68

    
69
class VersionNotExists(IndexError):
70
    pass
71

    
72

    
73
class BaseBackend(object):
74
    """Abstract backend class that serves as a reference for actual implementations.
75

76
    The purpose of the backend is to provide the necessary functions for handling data
77
    and metadata. It is responsible for the actual storage and retrieval of information.
78

79
    Note that the account level is always valid as it is checked from another subsystem.
80

81
    When not replacing metadata/groups/policy, keys with empty values should be deleted.
82

83
    The following variables should be available:
84
        'hash_algorithm': Suggested is 'sha256'
85

86
        'block_size': Suggested is 4MB
87

88
        'default_policy': A dictionary with default policy settings
89
    """
90

    
91
    def close(self):
92
        """Close the backend connection."""
93
        pass
94

    
95
    def list_accounts(self, user, marker=None, limit=10000):
96
        """Return a list of accounts the user can access.
97

98
        Parameters:
99
            'marker': Start list from the next item after 'marker'
100

101
            'limit': Number of containers to return
102
        """
103
        return []
104

    
105
    def get_account_meta(self, user, account, domain, until=None, include_user_defined=True):
106
        """Return a dictionary with the account metadata for the domain.
107

108
        The keys returned are all user-defined, except:
109
            'name': The account name
110

111
            'count': The number of containers (or 0)
112

113
            'bytes': The total data size (or 0)
114

115
            'modified': Last modification timestamp (overall)
116

117
            'until_timestamp': Last modification until the timestamp provided
118

119
        Raises:
120
            NotAllowedError: Operation not permitted
121
        """
122
        return {}
123

    
124
    def update_account_meta(self, user, account, domain, meta, replace=False):
125
        """Update the metadata associated with the account for the domain.
126

127
        Parameters:
128
            'domain': Metadata domain
129

130
            'meta': Dictionary with metadata to update
131

132
            'replace': Replace instead of update
133

134
        Raises:
135
            NotAllowedError: Operation not permitted
136
        """
137
        return
138

    
139
    def get_account_groups(self, user, account):
140
        """Return a dictionary with the user groups defined for this account.
141

142
        Raises:
143
            NotAllowedError: Operation not permitted
144
        """
145
        return {}
146

    
147
    def update_account_groups(self, user, account, groups, replace=False):
148
        """Update the groups associated with the account.
149

150
        Raises:
151
            NotAllowedError: Operation not permitted
152

153
            ValueError: Invalid data in groups
154
        """
155
        return
156

    
157
    def get_account_policy(self, user, account):
158
        """Return a dictionary with the account policy.
159

160
        The keys returned are:
161
            'quota': The maximum bytes allowed (default is 0 - unlimited)
162

163
            'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
164

165
        Raises:
166
            NotAllowedError: Operation not permitted
167
        """
168
        return {}
169

    
170
    def update_account_policy(self, user, account, policy, replace=False):
171
        """Update the policy associated with the account.
172

173
        Raises:
174
            NotAllowedError: Operation not permitted
175

176
            ValueError: Invalid policy defined
177
        """
178
        return
179

    
180
    def put_account(self, user, account, policy={}):
181
        """Create a new account with the given name.
182

183
        Raises:
184
            NotAllowedError: Operation not permitted
185

186
            ValueError: Invalid policy defined
187
        """
188
        return
189

    
190
    def delete_account(self, user, account):
191
        """Delete the account with the given name.
192

193
        Raises:
194
            NotAllowedError: Operation not permitted
195

196
            AccountNotEmpty: Account is not empty
197
        """
198
        return
199

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

203
        Parameters:
204
            'marker': Start list from the next item after 'marker'
205

206
            'limit': Number of containers to return
207

208
            'shared': Only list containers with permissions set
209

210
            'public': Only list containers containing public objects
211

212

213
        Raises:
214
            NotAllowedError: Operation not permitted
215
        """
216
        return []
217

    
218
    def list_container_meta(self, user, account, container, domain, until=None):
219
        """Return a list with all the container's object meta keys for the domain.
220

221
        Raises:
222
            NotAllowedError: Operation not permitted
223

224
            ItemNotExists: Container does not exist
225
        """
226
        return []
227

    
228
    def get_container_meta(self, user, account, container, domain, until=None, include_user_defined=True):
229
        """Return a dictionary with the container metadata for the domain.
230

231
        The keys returned are all user-defined, except:
232
            'name': The container name
233

234
            'count': The number of objects
235

236
            'bytes': The total data size
237

238
            'modified': Last modification timestamp (overall)
239

240
            'until_timestamp': Last modification until the timestamp provided
241

242
        Raises:
243
            NotAllowedError: Operation not permitted
244

245
            ItemNotExists: Container does not exist
246
        """
247
        return {}
248

    
249
    def update_container_meta(self, user, account, container, domain, meta, replace=False):
250
        """Update the metadata associated with the container for the domain.
251

252
        Parameters:
253
            'domain': Metadata domain
254

255
            'meta': Dictionary with metadata to update
256

257
            'replace': Replace instead of update
258

259
        Raises:
260
            NotAllowedError: Operation not permitted
261

262
            ItemNotExists: Container does not exist
263
        """
264
        return
265

    
266
    def get_container_policy(self, user, account, container):
267
        """Return a dictionary with the container policy.
268

269
        The keys returned are:
270
            'quota': The maximum bytes allowed (default is 0 - unlimited)
271

272
            'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
273

274
        Raises:
275
            NotAllowedError: Operation not permitted
276

277
            ItemNotExists: Container does not exist
278
        """
279
        return {}
280

    
281
    def update_container_policy(self, user, account, container, policy, replace=False):
282
        """Update the policy associated with the container.
283

284
        Raises:
285
            NotAllowedError: Operation not permitted
286

287
            ItemNotExists: Container does not exist
288

289
            ValueError: Invalid policy defined
290
        """
291
        return
292

    
293
    def put_container(self, user, account, container, policy={}, delimiter=None):
294
        """Create a new container with the given name.
295

296
        Parameters:
297
            'delimiter': If present deletes container contents instead of the container
298

299
        Raises:
300
            NotAllowedError: Operation not permitted
301

302
            ContainerExists: Container already exists
303

304
            ValueError: Invalid policy defined
305
        """
306
        return
307

    
308
    def delete_container(self, user, account, container, until=None):
309
        """Delete/purge the container with the given name.
310

311
        Raises:
312
            NotAllowedError: Operation not permitted
313

314
            ItemNotExists: Container does not exist
315

316
            ContainerNotEmpty: Container is not empty
317
        """
318
        return
319

    
320
    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=[], shared=False, until=None, size_range=None, public=False):
321
        """Return a list of object (name, version_id) tuples existing under a container.
322

323
        Parameters:
324
            'prefix': List objects starting with 'prefix'
325

326
            'delimiter': Return unique names before 'delimiter' and after 'prefix'
327

328
            'marker': Start list from the next item after 'marker'
329

330
            'limit': Number of objects to return
331

332
            'virtual': If not set, the result will only include names starting
333
                       with 'prefix' and ending without a 'delimiter' or with
334
                       the first occurance of the 'delimiter' after 'prefix'.
335
                       If set, the result will include all names after 'prefix',
336
                       up to and including the 'delimiter' if it is found
337

338
            'domain': Metadata domain for keys
339

340
            'keys': Include objects that satisfy the key queries in the list.
341
                    Use 'key', '!key' for existence queries, 'key op value' for
342
                    value queries, where 'op' can be one of =, !=, <=, >=, <, >
343

344
            'shared': Only list objects with permissions set
345

346
            'size_range': Include objects with byte size in (from, to).
347
                          Use None to specify unlimited
348

349
            'public': Only list public objects
350

351

352
        Raises:
353
            NotAllowedError: Operation not permitted
354

355
            ItemNotExists: Container does not exist
356
        """
357
        return []
358

    
359
    def list_object_meta(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=[], shared=False, until=None, size_range=None):
360
        """Return a list of object metadata dicts existing under a container.
361

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

365
        Raises:
366
            NotAllowedError: Operation not permitted
367

368
            ItemNotExists: Container does not exist
369
        """
370
        return []
371

    
372
    def list_object_permissions(self, user, account, container, prefix=''):
373
        """Return a list of paths that enforce permissions under a container.
374

375
        Raises:
376
            NotAllowedError: Operation not permitted
377
        """
378
        return []
379

    
380
    def list_object_public(self, user, account, container, prefix=''):
381
        """Return a dict mapping paths to public ids for objects that are public under a container."""
382
        return {}
383

    
384
    def get_object_meta(self, user, account, container, name, domain, version=None, include_user_defined=True):
385
        """Return a dictionary with the object metadata for the domain.
386

387
        The keys returned are all user-defined, except:
388
            'name': The object name
389

390
            'bytes': The total data size
391

392
            'type': The content type
393

394
            'hash': The hashmap hash
395

396
            'modified': Last modification timestamp (overall)
397

398
            'modified_by': The user that committed the object (version requested)
399

400
            'version': The version identifier
401

402
            'version_timestamp': The version's modification timestamp
403

404
            'uuid': A unique identifier that persists data or metadata updates and renames
405

406
            'checksum': The MD5 sum of the object (may be empty)
407

408
        Raises:
409
            NotAllowedError: Operation not permitted
410

411
            ItemNotExists: Container/object does not exist
412

413
            VersionNotExists: Version does not exist
414
        """
415
        return {}
416

    
417
    def update_object_meta(self, user, account, container, name, domain, meta, replace=False):
418
        """Update the metadata associated with the object for the domain and return the new version.
419

420
        Parameters:
421
            'domain': Metadata domain
422

423
            'meta': Dictionary with metadata to update
424

425
            'replace': Replace instead of update
426

427
        Raises:
428
            NotAllowedError: Operation not permitted
429

430
            ItemNotExists: Container/object does not exist
431
        """
432
        return ''
433

    
434
    def get_object_permissions(self, user, account, container, name):
435
        """Return the action allowed on the object, the path
436
        from which the object gets its permissions from,
437
        along with a dictionary containing the permissions.
438

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

442
            'write': The object is writable by the users/groups in the list
443

444
        Raises:
445
            NotAllowedError: Operation not permitted
446

447
            ItemNotExists: Container/object does not exist
448
        """
449
        return {}
450

    
451
    def update_object_permissions(self, user, account, container, name, permissions):
452
        """Update (set) the permissions associated with the object.
453

454
        Parameters:
455
            'permissions': Dictionary with permissions to set
456

457
        Raises:
458
            NotAllowedError: Operation not permitted
459

460
            ItemNotExists: Container/object does not exist
461

462
            ValueError: Invalid users/groups in permissions
463
        """
464
        return
465

    
466
    def get_object_public(self, user, account, container, name):
467
        """Return the public id of the object if applicable.
468

469
        Raises:
470
            NotAllowedError: Operation not permitted
471

472
            ItemNotExists: Container/object does not exist
473
        """
474
        return None
475

    
476
    def update_object_public(self, user, account, container, name, public):
477
        """Update the public status of the object.
478

479
        Parameters:
480
            'public': Boolean value
481

482
        Raises:
483
            NotAllowedError: Operation not permitted
484

485
            ItemNotExists: Container/object does not exist
486
        """
487
        return
488

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

492
        Raises:
493
            NotAllowedError: Operation not permitted
494

495
            ItemNotExists: Container/object does not exist
496

497
            VersionNotExists: Version does not exist
498
        """
499
        return 0, []
500

    
501
    def update_object_hashmap(self, user, account, container, name, size, type, hashmap, checksum, domain, meta={}, replace_meta=False, permissions=None):
502
        """Create/update an object with the specified size and partial hashes and return the new version.
503

504
        Parameters:
505
            'domain': Metadata domain
506

507
            'meta': Dictionary with metadata to change
508

509
            'replace_meta': Replace metadata instead of update
510

511
            'permissions': Updated object permissions
512

513
        Raises:
514
            NotAllowedError: Operation not permitted
515

516
            ItemNotExists: Container does not exist
517

518
            ValueError: Invalid users/groups in permissions
519

520
            QuotaError: Account or container quota exceeded
521
        """
522
        return ''
523

    
524
    def update_object_checksum(self, user, account, container, name, version, checksum):
525
        """Update an object's checksum."""
526
        return
527

    
528
    def copy_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta={}, replace_meta=False, permissions=None, src_version=None, delimiter=None):
529
        """Copy an object's data and metadata and return the new version.
530

531
        Parameters:
532
            'domain': Metadata domain
533

534
            'meta': Dictionary with metadata to change from source to destination
535

536
            'replace_meta': Replace metadata instead of update
537

538
            'permissions': New object permissions
539

540
            'src_version': Copy from the version provided
541

542
            'delimiter': Copy objects whose path starts with src_name + delimiter
543

544
        Raises:
545
            NotAllowedError: Operation not permitted
546

547
            ItemNotExists: Container/object does not exist
548

549
            VersionNotExists: Version does not exist
550

551
            ValueError: Invalid users/groups in permissions
552

553
            QuotaError: Account or container quota exceeded
554
        """
555
        return ''
556

    
557
    def move_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta={}, replace_meta=False, permissions=None, delimiter=None):
558
        """Move an object's data and metadata and return the new version.
559

560
        Parameters:
561
            'domain': Metadata domain
562

563
            'meta': Dictionary with metadata to change from source to destination
564

565
            'replace_meta': Replace metadata instead of update
566

567
            'permissions': New object permissions
568

569
            'delimiter': Move objects whose path starts with src_name + delimiter
570

571
        Raises:
572
            NotAllowedError: Operation not permitted
573

574
            ItemNotExists: Container/object does not exist
575

576
            ValueError: Invalid users/groups in permissions
577

578
            QuotaError: Account or container quota exceeded
579
        """
580
        return ''
581

    
582
    def delete_object(self, user, account, container, name, until=None, delimiter=None):
583
        """Delete/purge an object.
584

585
        Parameters:
586
            'delimiter': Delete objects whose path starting with name + delimiter
587

588
        Raises:
589
            NotAllowedError: Operation not permitted
590

591
            ItemNotExists: Container/object does not exist
592
        """
593
        return
594

    
595
    def list_versions(self, user, account, container, name):
596
        """Return a list of all (version, version_timestamp) tuples for an object.
597

598
        Raises:
599
            NotAllowedError: Operation not permitted
600
        """
601
        return []
602

    
603
    def get_uuid(self, user, uuid):
604
        """Return the (account, container, name) for the UUID given.
605

606
        Raises:
607
            NotAllowedError: Operation not permitted
608

609
            NameError: UUID does not exist
610
        """
611
        return None
612

    
613
    def get_public(self, user, public):
614
        """Return the (account, container, name) for the public id given.
615

616
        Raises:
617
            NotAllowedError: Operation not permitted
618

619
            NameError: Public id does not exist
620
        """
621
        return None
622

    
623
    def get_block(self, hash):
624
        """Return a block's data.
625

626
        Raises:
627
            ItemNotExists: Block does not exist
628
        """
629
        return ''
630

    
631
    def put_block(self, data):
632
        """Store a block and return the hash."""
633
        return 0
634

    
635
    def update_block(self, hash, data, offset=0):
636
        """Update a known block and return the hash.
637

638
        Raises:
639
            IndexError: Offset or data outside block limits
640
        """
641
        return 0