Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ 19ddd41b

History | View | Annotate | Download (19.8 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

    
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_account_policy': A dictionary with default account policy settings
89
        'default_container_policy': A dictionary with default container policy settings
90
    """
91

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

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

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

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

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

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

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

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

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

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

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

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

128
        Parameters:
129
            'domain': Metadata domain
130

131
            'meta': Dictionary with metadata to update
132

133
            'replace': Replace instead of update
134

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

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

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

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

151
        Raises:
152
            NotAllowedError: Operation not permitted
153

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

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

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

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

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

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

174
        Raises:
175
            NotAllowedError: Operation not permitted
176

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

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

184
        Raises:
185
            NotAllowedError: Operation not permitted
186

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

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

194
        Raises:
195
            NotAllowedError: Operation not permitted
196

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

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

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

207
            'limit': Number of containers to return
208

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

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

213

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

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

222
        Raises:
223
            NotAllowedError: Operation not permitted
224

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

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

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

235
            'count': The number of objects
236

237
            'bytes': The total data size
238

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

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

243
        Raises:
244
            NotAllowedError: Operation not permitted
245

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

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

253
        Parameters:
254
            'domain': Metadata domain
255

256
            'meta': Dictionary with metadata to update
257

258
            'replace': Replace instead of update
259

260
        Raises:
261
            NotAllowedError: Operation not permitted
262

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

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

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

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

275
        Raises:
276
            NotAllowedError: Operation not permitted
277

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

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

285
        Raises:
286
            NotAllowedError: Operation not permitted
287

288
            ItemNotExists: Container does not exist
289

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

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

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

300
        Raises:
301
            NotAllowedError: Operation not permitted
302

303
            ContainerExists: Container already exists
304

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

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

312
        Raises:
313
            NotAllowedError: Operation not permitted
314

315
            ItemNotExists: Container does not exist
316

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

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

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

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

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

331
            'limit': Number of objects to return
332

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

339
            'domain': Metadata domain for keys
340

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

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

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

350
            'public': Only list public objects
351

352

353
        Raises:
354
            NotAllowedError: Operation not permitted
355

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

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

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

366
        Raises:
367
            NotAllowedError: Operation not permitted
368

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

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

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

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

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

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

391
            'bytes': The total data size
392

393
            'type': The content type
394

395
            'hash': The hashmap hash
396

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

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

401
            'version': The version identifier
402

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

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

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

409
        Raises:
410
            NotAllowedError: Operation not permitted
411

412
            ItemNotExists: Container/object does not exist
413

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

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

421
        Parameters:
422
            'domain': Metadata domain
423

424
            'meta': Dictionary with metadata to update
425

426
            'replace': Replace instead of update
427

428
        Raises:
429
            NotAllowedError: Operation not permitted
430

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

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

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

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

445
        Raises:
446
            NotAllowedError: Operation not permitted
447

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

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

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

458
        Raises:
459
            NotAllowedError: Operation not permitted
460

461
            ItemNotExists: Container/object does not exist
462

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

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

470
        Raises:
471
            NotAllowedError: Operation not permitted
472

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

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

480
        Parameters:
481
            'public': Boolean value
482

483
        Raises:
484
            NotAllowedError: Operation not permitted
485

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

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

493
        Raises:
494
            NotAllowedError: Operation not permitted
495

496
            ItemNotExists: Container/object does not exist
497

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

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

505
        Parameters:
506
            'domain': Metadata domain
507

508
            'meta': Dictionary with metadata to change
509

510
            'replace_meta': Replace metadata instead of update
511

512
            'permissions': Updated object permissions
513

514
        Raises:
515
            NotAllowedError: Operation not permitted
516

517
            ItemNotExists: Container does not exist
518

519
            ValueError: Invalid users/groups in permissions
520

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

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

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

532
        Parameters:
533
            'domain': Metadata domain
534

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

537
            'replace_meta': Replace metadata instead of update
538

539
            'permissions': New object permissions
540

541
            'src_version': Copy from the version provided
542

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

545
        Raises:
546
            NotAllowedError: Operation not permitted
547

548
            ItemNotExists: Container/object does not exist
549

550
            VersionNotExists: Version does not exist
551

552
            ValueError: Invalid users/groups in permissions
553

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

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

561
        Parameters:
562
            'domain': Metadata domain
563

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

566
            'replace_meta': Replace metadata instead of update
567

568
            'permissions': New object permissions
569

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

572
        Raises:
573
            NotAllowedError: Operation not permitted
574

575
            ItemNotExists: Container/object does not exist
576

577
            ValueError: Invalid users/groups in permissions
578

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

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

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

589
        Raises:
590
            NotAllowedError: Operation not permitted
591

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

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

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

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

607
        Raises:
608
            NotAllowedError: Operation not permitted
609

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

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

617
        Raises:
618
            NotAllowedError: Operation not permitted
619

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

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

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

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

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

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