Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / base.py @ e647d184

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

    
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 BaseBackend(object):
72
    """Abstract backend class that serves as a reference for actual implementations.
73

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

77
    Note that the account level is always valid as it is checked from another subsystem.
78

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

81
    The following variables should be available:
82
        'hash_algorithm': Suggested is 'sha256'
83

84
        'block_size': Suggested is 4MB
85

86
        'default_policy': A dictionary with default policy settings
87
    """
88

    
89
    def close(self):
90
        """Close the backend connection."""
91
        pass
92

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

96
        Parameters:
97
            'marker': Start list from the next item after 'marker'
98

99
            'limit': Number of containers to return
100
        """
101
        return []
102

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

106
        The keys returned are all user-defined, except:
107
            'name': The account name
108

109
            'count': The number of containers (or 0)
110

111
            'bytes': The total data size (or 0)
112

113
            'modified': Last modification timestamp (overall)
114

115
            'until_timestamp': Last modification until the timestamp provided
116

117
        Raises:
118
            NotAllowedError: Operation not permitted
119
        """
120
        return {}
121

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

125
        Parameters:
126
            'domain': Metadata domain
127

128
            'meta': Dictionary with metadata to update
129

130
            'replace': Replace instead of update
131

132
        Raises:
133
            NotAllowedError: Operation not permitted
134
        """
135
        return
136

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

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

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

148
        Raises:
149
            NotAllowedError: Operation not permitted
150

151
            ValueError: Invalid data in groups
152
        """
153
        return
154

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

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

161
            'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
162

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

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

171
        Raises:
172
            NotAllowedError: Operation not permitted
173

174
            ValueError: Invalid policy defined
175
        """
176
        return
177

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

181
        Raises:
182
            NotAllowedError: Operation not permitted
183

184
            ValueError: Invalid policy defined
185
        """
186
        return
187

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

191
        Raises:
192
            NotAllowedError: Operation not permitted
193

194
            AccountNotEmpty: Account is not empty
195
        """
196
        return
197

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

201
        Parameters:
202
            'marker': Start list from the next item after 'marker'
203

204
            'limit': Number of containers to return
205

206
            'shared': Only list containers with permissions set
207

208
            'public': Only list containers containing public objects
209

210

211
        Raises:
212
            NotAllowedError: Operation not permitted
213
        """
214
        return []
215

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

219
        Raises:
220
            NotAllowedError: Operation not permitted
221

222
            ItemNotExists: Container does not exist
223
        """
224
        return []
225

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

229
        The keys returned are all user-defined, except:
230
            'name': The container name
231

232
            'count': The number of objects
233

234
            'bytes': The total data size
235

236
            'modified': Last modification timestamp (overall)
237

238
            'until_timestamp': Last modification until the timestamp provided
239

240
        Raises:
241
            NotAllowedError: Operation not permitted
242

243
            ItemNotExists: Container does not exist
244
        """
245
        return {}
246

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

250
        Parameters:
251
            'domain': Metadata domain
252

253
            'meta': Dictionary with metadata to update
254

255
            'replace': Replace instead of update
256

257
        Raises:
258
            NotAllowedError: Operation not permitted
259

260
            ItemNotExists: Container does not exist
261
        """
262
        return
263

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

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

270
            'versioning': Can be 'auto', 'manual' or 'none' (default is 'manual')
271

272
        Raises:
273
            NotAllowedError: Operation not permitted
274

275
            ItemNotExists: Container does not exist
276
        """
277
        return {}
278

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

282
        Raises:
283
            NotAllowedError: Operation not permitted
284

285
            ItemNotExists: Container does not exist
286

287
            ValueError: Invalid policy defined
288
        """
289
        return
290

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

294
        Parameters:
295
            'delimiter': If present deletes container contents instead of the container
296

297
        Raises:
298
            NotAllowedError: Operation not permitted
299

300
            ContainerExists: Container already exists
301

302
            ValueError: Invalid policy defined
303
        """
304
        return
305

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

309
        Raises:
310
            NotAllowedError: Operation not permitted
311

312
            ItemNotExists: Container does not exist
313

314
            ContainerNotEmpty: Container is not empty
315
        """
316
        return
317

    
318
    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):
319
        """Return a list of object (name, version_id) tuples existing under a container.
320

321
        Parameters:
322
            'prefix': List objects starting with 'prefix'
323

324
            'delimiter': Return unique names before 'delimiter' and after 'prefix'
325

326
            'marker': Start list from the next item after 'marker'
327

328
            'limit': Number of objects to return
329

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

336
            'domain': Metadata domain for keys
337

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

342
            'shared': Only list objects with permissions set
343

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

347
            'public': Only list public objects
348

349

350
        Raises:
351
            NotAllowedError: Operation not permitted
352

353
            ItemNotExists: Container does not exist
354
        """
355
        return []
356

    
357
    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):
358
        """Return a list of object metadata dicts existing under a container.
359

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

363
        Raises:
364
            NotAllowedError: Operation not permitted
365

366
            ItemNotExists: Container does not exist
367
        """
368
        return []
369

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

373
        Raises:
374
            NotAllowedError: Operation not permitted
375
        """
376
        return []
377

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

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

385
        The keys returned are all user-defined, except:
386
            'name': The object name
387

388
            'bytes': The total data size
389

390
            'type': The content type
391

392
            'hash': The hashmap hash
393

394
            'modified': Last modification timestamp (overall)
395

396
            'modified_by': The user that committed the object (version requested)
397

398
            'version': The version identifier
399

400
            'version_timestamp': The version's modification timestamp
401

402
            'uuid': A unique identifier that persists data or metadata updates and renames
403

404
            'checksum': The MD5 sum of the object (may be empty)
405

406
        Raises:
407
            NotAllowedError: Operation not permitted
408

409
            ItemNotExists: Container/object does not exist
410

411
            VersionNotExists: Version does not exist
412
        """
413
        return {}
414

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

418
        Parameters:
419
            'domain': Metadata domain
420

421
            'meta': Dictionary with metadata to update
422

423
            'replace': Replace instead of update
424

425
        Raises:
426
            NotAllowedError: Operation not permitted
427

428
            ItemNotExists: Container/object does not exist
429
        """
430
        return ''
431

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

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

440
            'write': The object is writable by the users/groups in the list
441

442
        Raises:
443
            NotAllowedError: Operation not permitted
444

445
            ItemNotExists: Container/object does not exist
446
        """
447
        return {}
448

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

452
        Parameters:
453
            'permissions': Dictionary with permissions to set
454

455
        Raises:
456
            NotAllowedError: Operation not permitted
457

458
            ItemNotExists: Container/object does not exist
459

460
            ValueError: Invalid users/groups in permissions
461
        """
462
        return
463

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

467
        Raises:
468
            NotAllowedError: Operation not permitted
469

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

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

477
        Parameters:
478
            'public': Boolean value
479

480
        Raises:
481
            NotAllowedError: Operation not permitted
482

483
            ItemNotExists: Container/object does not exist
484
        """
485
        return
486

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

490
        Raises:
491
            NotAllowedError: Operation not permitted
492

493
            ItemNotExists: Container/object does not exist
494

495
            VersionNotExists: Version does not exist
496
        """
497
        return 0, []
498

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

502
        Parameters:
503
            'domain': Metadata domain
504

505
            'meta': Dictionary with metadata to change
506

507
            'replace_meta': Replace metadata instead of update
508

509
            'permissions': Updated object permissions
510

511
        Raises:
512
            NotAllowedError: Operation not permitted
513

514
            ItemNotExists: Container does not exist
515

516
            ValueError: Invalid users/groups in permissions
517

518
            QuotaError: Account or container quota exceeded
519
        """
520
        return ''
521

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

    
526
    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):
527
        """Copy an object's data and metadata and return the new version.
528

529
        Parameters:
530
            'domain': Metadata domain
531

532
            'meta': Dictionary with metadata to change from source to destination
533

534
            'replace_meta': Replace metadata instead of update
535

536
            'permissions': New object permissions
537

538
            'src_version': Copy from the version provided
539

540
            'delimiter': Copy objects whose path starts with src_name + delimiter
541

542
        Raises:
543
            NotAllowedError: Operation not permitted
544

545
            ItemNotExists: Container/object does not exist
546

547
            VersionNotExists: Version does not exist
548

549
            ValueError: Invalid users/groups in permissions
550

551
            QuotaError: Account or container quota exceeded
552
        """
553
        return ''
554

    
555
    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):
556
        """Move an object's data and metadata and return the new version.
557

558
        Parameters:
559
            'domain': Metadata domain
560

561
            'meta': Dictionary with metadata to change from source to destination
562

563
            'replace_meta': Replace metadata instead of update
564

565
            'permissions': New object permissions
566

567
            'delimiter': Move objects whose path starts with src_name + delimiter
568

569
        Raises:
570
            NotAllowedError: Operation not permitted
571

572
            ItemNotExists: Container/object does not exist
573

574
            ValueError: Invalid users/groups in permissions
575

576
            QuotaError: Account or container quota exceeded
577
        """
578
        return ''
579

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

583
        Parameters:
584
            'delimiter': Delete objects whose path starting with name + delimiter
585

586
        Raises:
587
            NotAllowedError: Operation not permitted
588

589
            ItemNotExists: Container/object does not exist
590
        """
591
        return
592

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

596
        Raises:
597
            NotAllowedError: Operation not permitted
598
        """
599
        return []
600

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

604
        Raises:
605
            NotAllowedError: Operation not permitted
606

607
            NameError: UUID does not exist
608
        """
609
        return None
610

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

614
        Raises:
615
            NotAllowedError: Operation not permitted
616

617
            NameError: Public id does not exist
618
        """
619
        return None
620

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

624
        Raises:
625
            ItemNotExists: Block does not exist
626
        """
627
        return ''
628

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

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

636
        Raises:
637
            IndexError: Offset or data outside block limits
638
        """
639
        return 0