Statistics
| Branch: | Tag: | Revision:

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

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

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

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

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

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

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

85
        'block_size': Suggested is 4MB
86

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

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

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

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

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

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

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

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

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

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

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

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

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

126
        Parameters:
127
            'domain': Metadata domain
128

129
            'meta': Dictionary with metadata to update
130

131
            'replace': Replace instead of update
132

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

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

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

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

149
        Raises:
150
            NotAllowedError: Operation not permitted
151

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

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

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

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

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

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

172
        Raises:
173
            NotAllowedError: Operation not permitted
174

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

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

182
        Raises:
183
            NotAllowedError: Operation not permitted
184

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

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

192
        Raises:
193
            NotAllowedError: Operation not permitted
194

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

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

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

205
            'limit': Number of containers to return
206

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

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

211

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

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

220
        Raises:
221
            NotAllowedError: Operation not permitted
222

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

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

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

233
            'count': The number of objects
234

235
            'bytes': The total data size
236

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

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

241
        Raises:
242
            NotAllowedError: Operation not permitted
243

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

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

251
        Parameters:
252
            'domain': Metadata domain
253

254
            'meta': Dictionary with metadata to update
255

256
            'replace': Replace instead of update
257

258
        Raises:
259
            NotAllowedError: Operation not permitted
260

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

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

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

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

273
        Raises:
274
            NotAllowedError: Operation not permitted
275

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

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

283
        Raises:
284
            NotAllowedError: Operation not permitted
285

286
            ItemNotExists: Container does not exist
287

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

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

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

298
        Raises:
299
            NotAllowedError: Operation not permitted
300

301
            ContainerExists: Container already exists
302

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

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

310
        Raises:
311
            NotAllowedError: Operation not permitted
312

313
            ItemNotExists: Container does not exist
314

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

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

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

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

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

329
            'limit': Number of objects to return
330

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

337
            'domain': Metadata domain for keys
338

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

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

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

348
            'public': Only list public objects
349

350

351
        Raises:
352
            NotAllowedError: Operation not permitted
353

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

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

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

364
        Raises:
365
            NotAllowedError: Operation not permitted
366

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

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

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

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

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

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

389
            'bytes': The total data size
390

391
            'type': The content type
392

393
            'hash': The hashmap hash
394

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

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

399
            'version': The version identifier
400

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

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

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

407
        Raises:
408
            NotAllowedError: Operation not permitted
409

410
            ItemNotExists: Container/object does not exist
411

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

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

419
        Parameters:
420
            'domain': Metadata domain
421

422
            'meta': Dictionary with metadata to update
423

424
            'replace': Replace instead of update
425

426
        Raises:
427
            NotAllowedError: Operation not permitted
428

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

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

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

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

443
        Raises:
444
            NotAllowedError: Operation not permitted
445

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

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

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

456
        Raises:
457
            NotAllowedError: Operation not permitted
458

459
            ItemNotExists: Container/object does not exist
460

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

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

468
        Raises:
469
            NotAllowedError: Operation not permitted
470

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

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

478
        Parameters:
479
            'public': Boolean value
480

481
        Raises:
482
            NotAllowedError: Operation not permitted
483

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

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

491
        Raises:
492
            NotAllowedError: Operation not permitted
493

494
            ItemNotExists: Container/object does not exist
495

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

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

503
        Parameters:
504
            'domain': Metadata domain
505

506
            'meta': Dictionary with metadata to change
507

508
            'replace_meta': Replace metadata instead of update
509

510
            'permissions': Updated object permissions
511

512
        Raises:
513
            NotAllowedError: Operation not permitted
514

515
            ItemNotExists: Container does not exist
516

517
            ValueError: Invalid users/groups in permissions
518

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

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

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

530
        Parameters:
531
            'domain': Metadata domain
532

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

535
            'replace_meta': Replace metadata instead of update
536

537
            'permissions': New object permissions
538

539
            'src_version': Copy from the version provided
540

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

543
        Raises:
544
            NotAllowedError: Operation not permitted
545

546
            ItemNotExists: Container/object does not exist
547

548
            VersionNotExists: Version does not exist
549

550
            ValueError: Invalid users/groups in permissions
551

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

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

559
        Parameters:
560
            'domain': Metadata domain
561

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

564
            'replace_meta': Replace metadata instead of update
565

566
            'permissions': New object permissions
567

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

570
        Raises:
571
            NotAllowedError: Operation not permitted
572

573
            ItemNotExists: Container/object does not exist
574

575
            ValueError: Invalid users/groups in permissions
576

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

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

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

587
        Raises:
588
            NotAllowedError: Operation not permitted
589

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

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

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

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

605
        Raises:
606
            NotAllowedError: Operation not permitted
607

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

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

615
        Raises:
616
            NotAllowedError: Operation not permitted
617

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

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

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

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

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

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