Revision 29148653 snf-pithos-backend/pithos/backends/modular.py
b/snf-pithos-backend/pithos/backends/modular.py | ||
---|---|---|
97 | 97 |
DEFAULT_BLOCK_SIZE = 4 * 1024 * 1024 # 4MB |
98 | 98 |
DEFAULT_HASH_ALGORITHM = 'sha256' |
99 | 99 |
#DEFAULT_QUEUE_MODULE = 'pithos.backends.lib.rabbitmq' |
100 |
DEFAULT_BLOCK_PARAMS = { 'mappool': None, 'blockpool': None }
|
|
100 |
DEFAULT_BLOCK_PARAMS = {'mappool': None, 'blockpool': None}
|
|
101 | 101 |
#DEFAULT_QUEUE_HOSTS = '[amqp://guest:guest@localhost:5672]' |
102 | 102 |
#DEFAULT_QUEUE_EXCHANGE = 'pithos' |
103 | 103 |
DEFAULT_PUBLIC_URL_ALPHABET = ('0123456789' |
... | ... | |
162 | 162 |
#queue_exchange = queue_exchange or DEFAULT_QUEUE_EXCHANGE |
163 | 163 |
|
164 | 164 |
self.public_url_security = (public_url_security or |
165 |
DEFAULT_PUBLIC_URL_SECURITY) |
|
165 |
DEFAULT_PUBLIC_URL_SECURITY)
|
|
166 | 166 |
self.public_url_alphabet = (public_url_alphabet or |
167 |
DEFAULT_PUBLIC_URL_ALPHABET) |
|
167 |
DEFAULT_PUBLIC_URL_ALPHABET)
|
|
168 | 168 |
|
169 | 169 |
self.hash_algorithm = hash_algorithm |
170 | 170 |
self.block_size = block_size |
... | ... | |
183 | 183 |
for x in ['READ', 'WRITE']: |
184 | 184 |
setattr(self, x, getattr(self.db_module, x)) |
185 | 185 |
self.node = self.db_module.Node(**params) |
186 |
for x in ['ROOTNODE', 'SERIAL', 'HASH', 'SIZE', 'TYPE', 'MTIME', 'MUSER', 'UUID', 'CHECKSUM', 'CLUSTER', 'MATCH_PREFIX', 'MATCH_EXACT']: |
|
186 |
for x in ['ROOTNODE', 'SERIAL', 'HASH', 'SIZE', 'TYPE', 'MTIME', |
|
187 |
'MUSER', 'UUID', 'CHECKSUM', 'CLUSTER', 'MATCH_PREFIX', |
|
188 |
'MATCH_EXACT']: |
|
187 | 189 |
setattr(self, x, getattr(self.db_module, x)) |
188 | 190 |
|
189 | 191 |
self.block_module = load_module(block_module) |
... | ... | |
251 | 253 |
self.wrapper.execute() |
252 | 254 |
|
253 | 255 |
r = self.astakosclient.resolve_commissions( |
254 |
token=self.service_token,
|
|
255 |
accept_serials=self.serials,
|
|
256 |
reject_serials=[])
|
|
256 |
token=self.service_token, |
|
257 |
accept_serials=self.serials, |
|
258 |
reject_serials=[]) |
|
257 | 259 |
self.commission_serials.delete_many( |
258 | 260 |
r['accepted']) |
259 | 261 |
|
... | ... | |
291 | 293 |
"get_account_meta: %s %s %s %s", user, account, domain, until) |
292 | 294 |
path, node = self._lookup_account(account, user == account) |
293 | 295 |
if user != account: |
294 |
if until or node is None or account not in self._allowed_accounts(user): |
|
296 |
if until or (node is None) or (account not |
|
297 |
in self._allowed_accounts(user)): |
|
295 | 298 |
raise NotAllowedError |
296 | 299 |
try: |
297 | 300 |
props = self._get_properties(node, until) |
... | ... | |
336 | 339 |
update_statistics_ancestors_depth=-1) |
337 | 340 |
|
338 | 341 |
def get_account_groups(self, user, account): |
339 |
"""Return a dictionary with the user groups defined for this account."""
|
|
342 |
"""Return a dictionary with the user groups defined for the account."""
|
|
340 | 343 |
|
341 | 344 |
logger.debug("get_account_groups: %s %s", user, account) |
342 | 345 |
if user != account: |
... | ... | |
419 | 422 |
raise AccountNotEmpty('Account is not empty') |
420 | 423 |
self.permissions.group_destroy(account) |
421 | 424 |
|
422 |
def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None, public=False): |
|
425 |
def list_containers(self, user, account, marker=None, limit=10000, |
|
426 |
shared=False, until=None, public=False): |
|
423 | 427 |
"""Return a list of containers existing under an account.""" |
424 | 428 |
|
425 | 429 |
logger.debug("list_containers: %s %s %s %s %s %s %s", user, |
... | ... | |
433 | 437 |
if shared or public: |
434 | 438 |
allowed = set() |
435 | 439 |
if shared: |
436 |
allowed.update([x.split('/', 2)[1] for x in self.permissions.access_list_shared(account)]) |
|
440 |
allowed.update([x.split('/', 2)[1] for x in |
|
441 |
self.permissions.access_list_shared(account)]) |
|
437 | 442 |
if public: |
438 |
allowed.update([x[0].split('/', 2)[1] for x in self.permissions.public_list(account)]) |
|
443 |
allowed.update([x[0].split('/', 2)[1] for x in |
|
444 |
self.permissions.public_list(account)]) |
|
439 | 445 |
allowed = sorted(allowed) |
440 | 446 |
start, limit = self._list_limits(allowed, marker, limit) |
441 | 447 |
return allowed[start:start + limit] |
... | ... | |
446 | 452 |
[x[0] for x in containers], marker, limit) |
447 | 453 |
return containers[start:start + limit] |
448 | 454 |
|
449 |
def list_container_meta(self, user, account, container, domain, until=None): |
|
450 |
"""Return a list with all the container's object meta keys for the domain.""" |
|
455 |
def list_container_meta(self, user, account, container, domain, |
|
456 |
until=None): |
|
457 |
"""Return a list of the container's object meta keys for a domain.""" |
|
451 | 458 |
|
452 | 459 |
logger.debug("list_container_meta: %s %s %s %s %s", user, |
453 | 460 |
account, container, domain, until) |
... | ... | |
462 | 469 |
path, node = self._lookup_container(account, container) |
463 | 470 |
before = until if until is not None else inf |
464 | 471 |
allowed = self._get_formatted_paths(allowed) |
465 |
return self.node.latest_attribute_keys(node, domain, before, CLUSTER_DELETED, allowed) |
|
472 |
return self.node.latest_attribute_keys(node, domain, before, |
|
473 |
CLUSTER_DELETED, allowed) |
|
466 | 474 |
|
467 |
def get_container_meta(self, user, account, container, domain, until=None, include_user_defined=True): |
|
475 |
def get_container_meta(self, user, account, container, domain, until=None, |
|
476 |
include_user_defined=True): |
|
468 | 477 |
"""Return a dictionary with the container metadata for the domain.""" |
469 | 478 |
|
470 | 479 |
logger.debug("get_container_meta: %s %s %s %s %s", user, |
471 | 480 |
account, container, domain, until) |
472 | 481 |
if user != account: |
473 |
if until or container not in self._allowed_containers(user, account): |
|
482 |
if until or container not in self._allowed_containers(user, |
|
483 |
account): |
|
474 | 484 |
raise NotAllowedError |
475 | 485 |
path, node = self._lookup_container(account, container) |
476 | 486 |
props = self._get_properties(node, until) |
... | ... | |
497 | 507 |
meta.update({'modified': modified}) |
498 | 508 |
return meta |
499 | 509 |
|
500 |
def update_container_meta(self, user, account, container, domain, meta, replace=False): |
|
510 |
def update_container_meta(self, user, account, container, domain, meta, |
|
511 |
replace=False): |
|
501 | 512 |
"""Update the metadata associated with the container for the domain.""" |
502 | 513 |
|
503 | 514 |
logger.debug("update_container_meta: %s %s %s %s %s %s", |
... | ... | |
527 | 538 |
path, node = self._lookup_container(account, container) |
528 | 539 |
return self._get_policy(node, is_account_policy=False) |
529 | 540 |
|
530 |
def update_container_policy(self, user, account, container, policy, replace=False): |
|
541 |
def update_container_policy(self, user, account, container, policy, |
|
542 |
replace=False): |
|
531 | 543 |
"""Update the policy associated with the container.""" |
532 | 544 |
|
533 | 545 |
logger.debug("update_container_policy: %s %s %s %s %s", |
... | ... | |
560 | 572 |
update_statistics_ancestors_depth=-1) |
561 | 573 |
self._put_policy(node, policy, True, is_account_policy=False) |
562 | 574 |
|
563 |
def delete_container(self, user, account, container, until=None, prefix='', delimiter=None): |
|
575 |
def delete_container(self, user, account, container, until=None, prefix='', |
|
576 |
delimiter=None): |
|
564 | 577 |
"""Delete/purge the container with the given name.""" |
565 | 578 |
|
566 | 579 |
logger.debug("delete_container: %s %s %s %s %s %s", user, |
... | ... | |
580 | 593 |
if not self.free_versioning: |
581 | 594 |
self._report_size_change( |
582 | 595 |
user, account, -size, { |
583 |
'action':'container purge', |
|
596 |
'action': 'container purge',
|
|
584 | 597 |
'path': path, |
585 | 598 |
'versions': ','.join(str(i) for i in serials) |
586 | 599 |
} |
... | ... | |
601 | 614 |
if not self.free_versioning: |
602 | 615 |
self._report_size_change( |
603 | 616 |
user, account, -size, { |
604 |
'action':'container purge', |
|
617 |
'action': 'container purge',
|
|
605 | 618 |
'path': path, |
606 | 619 |
'versions': ','.join(str(i) for i in serials) |
607 | 620 |
} |
608 | 621 |
) |
609 | 622 |
else: |
610 | 623 |
# remove only contents |
611 |
src_names = self._list_objects_no_limit(user, account, container, prefix='', delimiter=None, virtual=False, domain=None, keys=[], shared=False, until=None, size_range=None, all_props=True, public=False) |
|
624 |
src_names = self._list_objects_no_limit( |
|
625 |
user, account, container, prefix='', delimiter=None, |
|
626 |
virtual=False, domain=None, keys=[], shared=False, until=None, |
|
627 |
size_range=None, all_props=True, public=False) |
|
612 | 628 |
paths = [] |
613 | 629 |
for t in src_names: |
614 | 630 |
path = '/'.join((account, container, t[0])) |
... | ... | |
621 | 637 |
account, container, src_version_id, |
622 | 638 |
update_statistics_ancestors_depth=1) |
623 | 639 |
self._report_size_change( |
624 |
user, account, -del_size, { |
|
625 |
'action': 'object delete', |
|
626 |
'path': path, |
|
627 |
'versions': ','.join([str(dest_version_id)]) |
|
628 |
} |
|
629 |
) |
|
640 |
user, account, -del_size, { |
|
641 |
'action': 'object delete', |
|
642 |
'path': path, |
|
643 |
'versions': ','.join([str(dest_version_id)])}) |
|
630 | 644 |
self._report_object_change( |
631 | 645 |
user, account, path, details={'action': 'object delete'}) |
632 | 646 |
paths.append(path) |
633 | 647 |
self.permissions.access_clear_bulk(paths) |
634 | 648 |
|
635 |
def _list_objects(self, user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, all_props, public): |
|
649 |
def _list_objects(self, user, account, container, prefix, delimiter, |
|
650 |
marker, limit, virtual, domain, keys, shared, until, |
|
651 |
size_range, all_props, public): |
|
636 | 652 |
if user != account and until: |
637 | 653 |
raise NotAllowedError |
638 | 654 |
if shared and public: |
... | ... | |
643 | 659 |
if shared_paths: |
644 | 660 |
path, node = self._lookup_container(account, container) |
645 | 661 |
shared_paths = self._get_formatted_paths(shared_paths) |
646 |
objects |= set(self._list_object_properties(node, path, prefix, delimiter, marker, limit, virtual, domain, keys, until, size_range, shared_paths, all_props)) |
|
662 |
objects |= set(self._list_object_properties( |
|
663 |
node, path, prefix, delimiter, marker, limit, virtual, |
|
664 |
domain, keys, until, size_range, shared_paths, all_props)) |
|
647 | 665 |
|
648 | 666 |
# get public |
649 | 667 |
objects |= set(self._list_public_object_properties( |
... | ... | |
667 | 685 |
return [] |
668 | 686 |
path, node = self._lookup_container(account, container) |
669 | 687 |
allowed = self._get_formatted_paths(allowed) |
670 |
objects = self._list_object_properties(node, path, prefix, delimiter, marker, limit, virtual, domain, keys, until, size_range, allowed, all_props) |
|
688 |
objects = self._list_object_properties( |
|
689 |
node, path, prefix, delimiter, marker, limit, virtual, domain, |
|
690 |
keys, until, size_range, allowed, all_props) |
|
671 | 691 |
start, limit = self._list_limits( |
672 | 692 |
[x[0] for x in objects], marker, limit) |
673 | 693 |
return objects[start:start + limit] |
674 | 694 |
|
675 |
def _list_public_object_properties(self, user, account, container, prefix, all_props): |
|
695 |
def _list_public_object_properties(self, user, account, container, prefix, |
|
696 |
all_props): |
|
676 | 697 |
public = self._list_object_permissions( |
677 | 698 |
user, account, container, prefix, shared=False, public=True) |
678 | 699 |
paths, nodes = self._lookup_objects(public) |
679 | 700 |
path = '/'.join((account, container)) |
680 | 701 |
cont_prefix = path + '/' |
681 | 702 |
paths = [x[len(cont_prefix):] for x in paths] |
682 |
props = self.node.version_lookup_bulk(nodes, all_props=all_props) |
|
683 |
objects = [(path,) + props for path, props in zip(paths, props)] |
|
703 |
objects = [(p,) + props for p, props in |
|
704 |
zip(paths, self.node.version_lookup_bulk( |
|
705 |
nodes, all_props=all_props))] |
|
684 | 706 |
return objects |
685 | 707 |
|
686 |
def _list_objects_no_limit(self, user, account, container, prefix, delimiter, virtual, domain, keys, shared, until, size_range, all_props, public): |
|
708 |
def _list_objects_no_limit(self, user, account, container, prefix, |
|
709 |
delimiter, virtual, domain, keys, shared, until, |
|
710 |
size_range, all_props, public): |
|
687 | 711 |
objects = [] |
688 | 712 |
while True: |
689 | 713 |
marker = objects[-1] if objects else None |
690 | 714 |
limit = 10000 |
691 |
l = self._list_objects(user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, all_props, public) |
|
715 |
l = self._list_objects( |
|
716 |
user, account, container, prefix, delimiter, marker, limit, |
|
717 |
virtual, domain, keys, shared, until, size_range, all_props, |
|
718 |
public) |
|
692 | 719 |
objects.extend(l) |
693 | 720 |
if not l or len(l) < limit: |
694 | 721 |
break |
695 | 722 |
return objects |
696 | 723 |
|
697 |
def _list_object_permissions(self, user, account, container, prefix, shared, public): |
|
724 |
def _list_object_permissions(self, user, account, container, prefix, |
|
725 |
shared, public): |
|
698 | 726 |
allowed = [] |
699 | 727 |
path = '/'.join((account, container, prefix)).rstrip('/') |
700 | 728 |
if user != account: |
... | ... | |
713 | 741 |
return [] |
714 | 742 |
return allowed |
715 | 743 |
|
716 |
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): |
|
717 |
"""Return a list of object (name, version_id) tuples existing under a container.""" |
|
744 |
def list_objects(self, user, account, container, prefix='', delimiter=None, |
|
745 |
marker=None, limit=10000, virtual=True, domain=None, |
|
746 |
keys=None, shared=False, until=None, size_range=None, |
|
747 |
public=False): |
|
748 |
"""List (object name, object version_id) under a container.""" |
|
718 | 749 |
|
719 |
logger.debug("list_objects: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, public) |
|
750 |
logger.debug("list_objects: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", |
|
751 |
user, account, container, prefix, delimiter, marker, |
|
752 |
limit, virtual, domain, keys, shared, until, size_range, |
|
753 |
public) |
|
720 | 754 |
keys = keys or [] |
721 |
return self._list_objects(user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, False, public) |
|
755 |
return self._list_objects( |
|
756 |
user, account, container, prefix, delimiter, marker, limit, |
|
757 |
virtual, domain, keys, shared, until, size_range, False, public) |
|
722 | 758 |
|
723 |
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, public=False): |
|
724 |
"""Return a list of object metadata dicts existing under a container.""" |
|
759 |
def list_object_meta(self, user, account, container, prefix='', |
|
760 |
delimiter=None, marker=None, limit=10000, |
|
761 |
virtual=True, domain=None, keys=None, shared=False, |
|
762 |
until=None, size_range=None, public=False): |
|
763 |
"""Return a list of metadata dicts of objects under a container.""" |
|
725 | 764 |
|
726 |
logger.debug("list_object_meta: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, public) |
|
765 |
logger.debug( |
|
766 |
"list_object_meta: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", |
|
767 |
user, account, container, prefix, delimiter, marker, limit, |
|
768 |
virtual, domain, keys, shared, until, size_range, public) |
|
727 | 769 |
keys = keys or [] |
728 |
props = self._list_objects(user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, True, public) |
|
770 |
props = self._list_objects( |
|
771 |
user, account, container, prefix, delimiter, marker, limit, |
|
772 |
virtual, domain, keys, shared, until, size_range, True, public) |
|
729 | 773 |
objects = [] |
730 | 774 |
for p in props: |
731 | 775 |
if len(p) == 2: |
732 | 776 |
objects.append({'subdir': p[0]}) |
733 | 777 |
else: |
734 |
objects.append({'name': p[0], |
|
735 |
'bytes': p[self.SIZE + 1], |
|
736 |
'type': p[self.TYPE + 1], |
|
737 |
'hash': p[self.HASH + 1], |
|
738 |
'version': p[self.SERIAL + 1], |
|
739 |
'version_timestamp': p[self.MTIME + 1], |
|
740 |
'modified': p[self.MTIME + 1] if until is None else None, |
|
741 |
'modified_by': p[self.MUSER + 1], |
|
742 |
'uuid': p[self.UUID + 1], |
|
743 |
'checksum': p[self.CHECKSUM + 1]}) |
|
778 |
objects.append({ |
|
779 |
'name': p[0], |
|
780 |
'bytes': p[self.SIZE + 1], |
|
781 |
'type': p[self.TYPE + 1], |
|
782 |
'hash': p[self.HASH + 1], |
|
783 |
'version': p[self.SERIAL + 1], |
|
784 |
'version_timestamp': p[self.MTIME + 1], |
|
785 |
'modified': p[self.MTIME + 1] if until is None else None, |
|
786 |
'modified_by': p[self.MUSER + 1], |
|
787 |
'uuid': p[self.UUID + 1], |
|
788 |
'checksum': p[self.CHECKSUM + 1]}) |
|
744 | 789 |
return objects |
745 | 790 |
|
746 | 791 |
def list_object_permissions(self, user, account, container, prefix=''): |
747 |
"""Return a list of paths that enforce permissions under a container."""
|
|
792 |
"""Return a list of paths enforce permissions under a container.""" |
|
748 | 793 |
|
749 | 794 |
logger.debug("list_object_permissions: %s %s %s %s", user, |
750 | 795 |
account, container, prefix) |
751 |
return self._list_object_permissions(user, account, container, prefix, True, False) |
|
796 |
return self._list_object_permissions(user, account, container, prefix, |
|
797 |
True, False) |
|
752 | 798 |
|
753 | 799 |
def list_object_public(self, user, account, container, prefix=''): |
754 |
"""Return a dict mapping paths to public ids for objects that are public under a container."""
|
|
800 |
"""Return a mapping of object paths to public ids under a container."""
|
|
755 | 801 |
|
756 | 802 |
logger.debug("list_object_public: %s %s %s %s", user, |
757 | 803 |
account, container, prefix) |
758 | 804 |
public = {} |
759 |
for path, p in self.permissions.public_list('/'.join((account, container, prefix))): |
|
805 |
for path, p in self.permissions.public_list('/'.join((account, |
|
806 |
container, |
|
807 |
prefix))): |
|
760 | 808 |
public[path] = p |
761 | 809 |
return public |
762 | 810 |
|
763 |
def get_object_meta(self, user, account, container, name, domain, version=None, include_user_defined=True): |
|
811 |
def get_object_meta(self, user, account, container, name, domain, |
|
812 |
version=None, include_user_defined=True): |
|
764 | 813 |
"""Return a dictionary with the object metadata for the domain.""" |
765 | 814 |
|
766 | 815 |
logger.debug("get_object_meta: %s %s %s %s %s %s", user, |
... | ... | |
797 | 846 |
'checksum': props[self.CHECKSUM]}) |
798 | 847 |
return meta |
799 | 848 |
|
800 |
def update_object_meta(self, user, account, container, name, domain, meta, replace=False): |
|
801 |
"""Update the metadata associated with the object for the domain and return the new version.""" |
|
849 |
def update_object_meta(self, user, account, container, name, domain, meta, |
|
850 |
replace=False): |
|
851 |
"""Update object metadata for a domain and return the new version.""" |
|
802 | 852 |
|
803 | 853 |
logger.debug("update_object_meta: %s %s %s %s %s %s %s", |
804 | 854 |
user, account, container, name, domain, meta, replace) |
... | ... | |
821 | 871 |
allowed = 'write' |
822 | 872 |
permissions_path = self._get_permissions_path(account, container, name) |
823 | 873 |
if user != account: |
824 |
if self.permissions.access_check(permissions_path, self.WRITE, user): |
|
874 |
if self.permissions.access_check(permissions_path, self.WRITE, |
|
875 |
user): |
|
825 | 876 |
allowed = 'write' |
826 |
elif self.permissions.access_check(permissions_path, self.READ, user): |
|
877 |
elif self.permissions.access_check(permissions_path, self.READ, |
|
878 |
user): |
|
827 | 879 |
allowed = 'read' |
828 | 880 |
else: |
829 | 881 |
raise NotAllowedError |
830 | 882 |
self._lookup_object(account, container, name) |
831 |
return (allowed, permissions_path, self.permissions.access_get(permissions_path)) |
|
883 |
return (allowed, |
|
884 |
permissions_path, |
|
885 |
self.permissions.access_get(permissions_path)) |
|
832 | 886 |
|
833 |
def update_object_permissions(self, user, account, container, name, permissions): |
|
887 |
def update_object_permissions(self, user, account, container, name, |
|
888 |
permissions): |
|
834 | 889 |
"""Update the permissions associated with the object.""" |
835 | 890 |
|
836 | 891 |
logger.debug("update_object_permissions: %s %s %s %s %s", |
... | ... | |
878 | 933 |
hashmap = self.store.map_get(binascii.unhexlify(props[self.HASH])) |
879 | 934 |
return props[self.SIZE], [binascii.hexlify(x) for x in hashmap] |
880 | 935 |
|
881 |
def _update_object_hash(self, user, account, container, name, size, type, hash, checksum, domain, meta, replace_meta, permissions, src_node=None, src_version_id=None, is_copy=False): |
|
936 |
def _update_object_hash(self, user, account, container, name, size, type, |
|
937 |
hash, checksum, domain, meta, replace_meta, |
|
938 |
permissions, src_node=None, src_version_id=None, |
|
939 |
is_copy=False): |
|
882 | 940 |
if permissions is not None and user != account: |
883 | 941 |
raise NotAllowedError |
884 | 942 |
self._can_write(user, account, container, name) |
... | ... | |
909 | 967 |
if size_delta > 0: |
910 | 968 |
# Check account quota. |
911 | 969 |
if not self.using_external_quotaholder: |
912 |
account_quota = long( |
|
913 |
self._get_policy(account_node, is_account_policy=True |
|
914 |
)['quota'] |
|
915 |
) |
|
916 |
account_usage = self._get_statistics(account_node, compute=True)[1] |
|
970 |
account_quota = long(self._get_policy( |
|
971 |
account_node, is_account_policy=True)['quota']) |
|
972 |
account_usage = self._get_statistics(account_node, |
|
973 |
compute=True)[1] |
|
917 | 974 |
if (account_quota > 0 and account_usage > account_quota): |
918 | 975 |
raise QuotaError( |
919 | 976 |
'Account quota exceeded: limit: %s, usage: %s' % ( |
920 |
account_quota, account_usage |
|
921 |
) |
|
922 |
) |
|
977 |
account_quota, account_usage)) |
|
923 | 978 |
|
924 | 979 |
# Check container quota. |
925 |
container_quota = long( |
|
926 |
self._get_policy(container_node, is_account_policy=False |
|
927 |
)['quota'] |
|
928 |
) |
|
980 |
container_quota = long(self._get_policy( |
|
981 |
container_node, is_account_policy=False)['quota']) |
|
929 | 982 |
container_usage = self._get_statistics(container_node)[1] |
930 | 983 |
if (container_quota > 0 and container_usage > container_quota): |
931 | 984 |
# This must be executed in a transaction, so the version is |
... | ... | |
936 | 989 |
) |
937 | 990 |
) |
938 | 991 |
|
939 |
self._report_size_change(user, account, size_delta, |
|
940 |
{'action': 'object update', 'path': path, |
|
941 |
'versions': ','.join([str(dest_version_id)])}) |
|
992 |
self._report_size_change( |
|
993 |
user, account, size_delta, |
|
994 |
{'action': 'object update', 'path': path, |
|
995 |
'versions': ','.join([str(dest_version_id)])}) |
|
942 | 996 |
if permissions is not None: |
943 | 997 |
self.permissions.access_set(path, permissions) |
944 |
self._report_sharing_change(user, account, path, {'members': self.permissions.access_members(path)}) |
|
998 |
self._report_sharing_change( |
|
999 |
user, account, path, |
|
1000 |
{'members': self.permissions.access_members(path)}) |
|
945 | 1001 |
|
946 |
self._report_object_change(user, account, path, details={'version': dest_version_id, 'action': 'object update'}) |
|
1002 |
self._report_object_change( |
|
1003 |
user, account, path, |
|
1004 |
details={'version': dest_version_id, 'action': 'object update'}) |
|
947 | 1005 |
return dest_version_id |
948 | 1006 |
|
949 |
def update_object_hashmap(self, user, account, container, name, size, type, hashmap, checksum, domain, meta=None, replace_meta=False, permissions=None): |
|
950 |
"""Create/update an object with the specified size and partial hashes.""" |
|
1007 |
def update_object_hashmap(self, user, account, container, name, size, type, |
|
1008 |
hashmap, checksum, domain, meta=None, |
|
1009 |
replace_meta=False, permissions=None): |
|
1010 |
"""Create/update an object's hashmap and return the new version.""" |
|
951 | 1011 |
|
952 | 1012 |
logger.debug("update_object_hashmap: %s %s %s %s %s %s %s %s", user, |
953 | 1013 |
account, container, name, size, type, hashmap, checksum) |
... | ... | |
964 | 1024 |
|
965 | 1025 |
hash = map.hash() |
966 | 1026 |
hexlified = binascii.hexlify(hash) |
967 |
dest_version_id = self._update_object_hash(user, account, container, name, size, type, hexlified, checksum, domain, meta, replace_meta, permissions) |
|
1027 |
dest_version_id = self._update_object_hash( |
|
1028 |
user, account, container, name, size, type, hexlified, checksum, |
|
1029 |
domain, meta, replace_meta, permissions) |
|
968 | 1030 |
self.store.map_put(hash, map) |
969 | 1031 |
return dest_version_id, hexlified |
970 | 1032 |
|
971 |
def update_object_checksum(self, user, account, container, name, version, checksum): |
|
1033 |
def update_object_checksum(self, user, account, container, name, version, |
|
1034 |
checksum): |
|
972 | 1035 |
"""Update an object's checksum.""" |
973 | 1036 |
|
974 | 1037 |
logger.debug("update_object_checksum: %s %s %s %s %s %s", |
975 | 1038 |
user, account, container, name, version, checksum) |
976 |
# Update objects with greater version and same hashmap and size (fix metadata updates). |
|
1039 |
# Update objects with greater version and same hashmap |
|
1040 |
# and size (fix metadata updates). |
|
977 | 1041 |
self._can_write(user, account, container, name) |
978 | 1042 |
path, node = self._lookup_object(account, container, name) |
979 | 1043 |
props = self._get_version(node, version) |
980 | 1044 |
versions = self.node.node_get_versions(node) |
981 | 1045 |
for x in versions: |
982 |
if x[self.SERIAL] >= int(version) and x[self.HASH] == props[self.HASH] and x[self.SIZE] == props[self.SIZE]: |
|
1046 |
if (x[self.SERIAL] >= int(version) and |
|
1047 |
x[self.HASH] == props[self.HASH] and |
|
1048 |
x[self.SIZE] == props[self.SIZE]): |
|
983 | 1049 |
self.node.version_put_property( |
984 | 1050 |
x[self.SERIAL], 'checksum', checksum) |
985 | 1051 |
|
986 |
def _copy_object(self, user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, dest_domain=None, dest_meta=None, replace_meta=False, permissions=None, src_version=None, is_move=False, delimiter=None): |
|
1052 |
def _copy_object(self, user, src_account, src_container, src_name, |
|
1053 |
dest_account, dest_container, dest_name, type, |
|
1054 |
dest_domain=None, dest_meta=None, replace_meta=False, |
|
1055 |
permissions=None, src_version=None, is_move=False, |
|
1056 |
delimiter=None): |
|
987 | 1057 |
dest_meta = dest_meta or {} |
988 | 1058 |
dest_version_ids = [] |
989 | 1059 |
self._can_read(user, src_account, src_container, src_name) |
... | ... | |
996 | 1066 |
size = props[self.SIZE] |
997 | 1067 |
is_copy = not is_move and (src_account, src_container, src_name) != ( |
998 | 1068 |
dest_account, dest_container, dest_name) # New uuid. |
999 |
dest_version_ids.append(self._update_object_hash(user, dest_account, dest_container, dest_name, size, type, hash, None, dest_domain, dest_meta, replace_meta, permissions, src_node=node, src_version_id=src_version_id, is_copy=is_copy)) |
|
1000 |
if is_move and (src_account, src_container, src_name) != (dest_account, dest_container, dest_name): |
|
1069 |
dest_version_ids.append(self._update_object_hash( |
|
1070 |
user, dest_account, dest_container, dest_name, size, type, hash, |
|
1071 |
None, dest_domain, dest_meta, replace_meta, permissions, |
|
1072 |
src_node=node, src_version_id=src_version_id, is_copy=is_copy)) |
|
1073 |
if is_move and ((src_account, src_container, src_name) != |
|
1074 |
(dest_account, dest_container, dest_name)): |
|
1001 | 1075 |
self._delete_object(user, src_account, src_container, src_name) |
1002 | 1076 |
|
1003 | 1077 |
if delimiter: |
1004 |
prefix = src_name + \ |
|
1005 |
delimiter if not src_name.endswith(delimiter) else src_name |
|
1006 |
src_names = self._list_objects_no_limit(user, src_account, src_container, prefix, delimiter=None, virtual=False, domain=None, keys=[], shared=False, until=None, size_range=None, all_props=True, public=False) |
|
1078 |
prefix = (src_name + delimiter if not |
|
1079 |
src_name.endswith(delimiter) else src_name) |
|
1080 |
src_names = self._list_objects_no_limit( |
|
1081 |
user, src_account, src_container, prefix, delimiter=None, |
|
1082 |
virtual=False, domain=None, keys=[], shared=False, until=None, |
|
1083 |
size_range=None, all_props=True, public=False) |
|
1007 | 1084 |
src_names.sort(key=lambda x: x[2]) # order by nodes |
1008 | 1085 |
paths = [elem[0] for elem in src_names] |
1009 | 1086 |
nodes = [elem[2] for elem in src_names] |
1010 |
# TODO: Will do another fetch of the properties in duplicate version... |
|
1087 |
# TODO: Will do another fetch of the properties |
|
1088 |
# in duplicate version... |
|
1011 | 1089 |
props = self._get_versions(nodes) # Check to see if source exists. |
1012 | 1090 |
|
1013 | 1091 |
for prop, path, node in zip(props, paths, nodes): |
... | ... | |
1018 | 1096 |
dest_prefix = dest_name + delimiter if not dest_name.endswith( |
1019 | 1097 |
delimiter) else dest_name |
1020 | 1098 |
vdest_name = path.replace(prefix, dest_prefix, 1) |
1021 |
dest_version_ids.append(self._update_object_hash(user, dest_account, dest_container, vdest_name, size, vtype, hash, None, dest_domain, meta={}, replace_meta=False, permissions=None, src_node=node, src_version_id=src_version_id, is_copy=is_copy)) |
|
1022 |
if is_move and (src_account, src_container, src_name) != (dest_account, dest_container, dest_name): |
|
1099 |
dest_version_ids.append(self._update_object_hash( |
|
1100 |
user, dest_account, dest_container, vdest_name, size, |
|
1101 |
vtype, hash, None, dest_domain, meta={}, |
|
1102 |
replace_meta=False, permissions=None, src_node=node, |
|
1103 |
src_version_id=src_version_id, is_copy=is_copy)) |
|
1104 |
if is_move and ((src_account, src_container, src_name) != |
|
1105 |
(dest_account, dest_container, dest_name)): |
|
1023 | 1106 |
self._delete_object(user, src_account, src_container, path) |
1024 |
return dest_version_ids[0] if len(dest_version_ids) == 1 else dest_version_ids |
|
1107 |
return (dest_version_ids[0] if len(dest_version_ids) == 1 else |
|
1108 |
dest_version_ids) |
|
1025 | 1109 |
|
1026 |
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): |
|
1110 |
def copy_object(self, user, src_account, src_container, src_name, |
|
1111 |
dest_account, dest_container, dest_name, type, domain, |
|
1112 |
meta=None, replace_meta=False, permissions=None, |
|
1113 |
src_version=None, delimiter=None): |
|
1027 | 1114 |
"""Copy an object's data and metadata.""" |
1028 | 1115 |
|
1029 |
logger.debug("copy_object: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta, replace_meta, permissions, src_version, delimiter) |
|
1116 |
logger.debug("copy_object: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", |
|
1117 |
user, src_account, src_container, src_name, dest_account, |
|
1118 |
dest_container, dest_name, type, domain, meta, |
|
1119 |
replace_meta, permissions, src_version, delimiter) |
|
1030 | 1120 |
meta = meta or {} |
1031 |
dest_version_id = self._copy_object(user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta, replace_meta, permissions, src_version, False, delimiter) |
|
1121 |
dest_version_id = self._copy_object( |
|
1122 |
user, src_account, src_container, src_name, dest_account, |
|
1123 |
dest_container, dest_name, type, domain, meta, replace_meta, |
|
1124 |
permissions, src_version, False, delimiter) |
|
1032 | 1125 |
return dest_version_id |
1033 | 1126 |
|
1034 |
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): |
|
1127 |
def move_object(self, user, src_account, src_container, src_name, |
|
1128 |
dest_account, dest_container, dest_name, type, domain, |
|
1129 |
meta=None, replace_meta=False, permissions=None, |
|
1130 |
delimiter=None): |
|
1035 | 1131 |
"""Move an object's data and metadata.""" |
1036 | 1132 |
|
1037 |
logger.debug("move_object: %s %s %s %s %s %s %s %s %s %s %s %s %s", user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta, replace_meta, permissions, delimiter) |
|
1133 |
logger.debug("move_object: %s %s %s %s %s %s %s %s %s %s %s %s %s", |
|
1134 |
user, src_account, src_container, src_name, dest_account, |
|
1135 |
dest_container, dest_name, type, domain, meta, |
|
1136 |
replace_meta, permissions, delimiter) |
|
1038 | 1137 |
meta = meta or {} |
1039 | 1138 |
if user != src_account: |
1040 | 1139 |
raise NotAllowedError |
1041 |
dest_version_id = self._copy_object(user, src_account, src_container, src_name, dest_account, dest_container, dest_name, type, domain, meta, replace_meta, permissions, None, True, delimiter) |
|
1140 |
dest_version_id = self._copy_object( |
|
1141 |
user, src_account, src_container, src_name, dest_account, |
|
1142 |
dest_container, dest_name, type, domain, meta, replace_meta, |
|
1143 |
permissions, None, True, delimiter) |
|
1042 | 1144 |
return dest_version_id |
1043 | 1145 |
|
1044 |
def _delete_object(self, user, account, container, name, until=None, delimiter=None): |
|
1146 |
def _delete_object(self, user, account, container, name, until=None, |
|
1147 |
delimiter=None): |
|
1045 | 1148 |
if user != account: |
1046 | 1149 |
raise NotAllowedError |
1047 | 1150 |
|
... | ... | |
1069 | 1172 |
self.node.node_purge(node, until, CLUSTER_DELETED, |
1070 | 1173 |
update_statistics_ancestors_depth=1) |
1071 | 1174 |
try: |
1072 |
props = self._get_version(node)
|
|
1175 |
self._get_version(node) |
|
1073 | 1176 |
except NameError: |
1074 | 1177 |
self.permissions.access_clear(path) |
1075 | 1178 |
self._report_size_change( |
... | ... | |
1087 | 1190 |
cluster=CLUSTER_DELETED, update_statistics_ancestors_depth=1) |
1088 | 1191 |
del_size = self._apply_versioning(account, container, src_version_id, |
1089 | 1192 |
update_statistics_ancestors_depth=1) |
1090 |
self._report_size_change(user, account, -del_size, |
|
1091 |
{'action': 'object delete', 'path': path, |
|
1092 |
'versions': ','.join([str(dest_version_id)])}) |
|
1193 |
self._report_size_change( |
|
1194 |
user, account, -del_size, |
|
1195 |
{'action': 'object delete', |
|
1196 |
'path': path, |
|
1197 |
'versions': ','.join([str(dest_version_id)])}) |
|
1093 | 1198 |
self._report_object_change( |
1094 | 1199 |
user, account, path, details={'action': 'object delete'}) |
1095 | 1200 |
self.permissions.access_clear(path) |
1096 | 1201 |
|
1097 | 1202 |
if delimiter: |
1098 | 1203 |
prefix = name + delimiter if not name.endswith(delimiter) else name |
1099 |
src_names = self._list_objects_no_limit(user, account, container, prefix, delimiter=None, virtual=False, domain=None, keys=[], shared=False, until=None, size_range=None, all_props=True, public=False) |
|
1204 |
src_names = self._list_objects_no_limit( |
|
1205 |
user, account, container, prefix, delimiter=None, |
|
1206 |
virtual=False, domain=None, keys=[], shared=False, until=None, |
|
1207 |
size_range=None, all_props=True, public=False) |
|
1100 | 1208 |
paths = [] |
1101 | 1209 |
for t in src_names: |
1102 | 1210 |
path = '/'.join((account, container, t[0])) |
... | ... | |
1108 | 1216 |
del_size = self._apply_versioning( |
1109 | 1217 |
account, container, src_version_id, |
1110 | 1218 |
update_statistics_ancestors_depth=1) |
1111 |
self._report_size_change(user, account, -del_size, |
|
1112 |
{'action': 'object delete', |
|
1113 |
'path': path, |
|
1114 |
'versions': ','.join([str(dest_version_id)])}) |
|
1219 |
self._report_size_change( |
|
1220 |
user, account, -del_size, |
|
1221 |
{'action': 'object delete', |
|
1222 |
'path': path, |
|
1223 |
'versions': ','.join([str(dest_version_id)])}) |
|
1115 | 1224 |
self._report_object_change( |
1116 | 1225 |
user, account, path, details={'action': 'object delete'}) |
1117 | 1226 |
paths.append(path) |
1118 | 1227 |
self.permissions.access_clear_bulk(paths) |
1119 | 1228 |
|
1120 |
def delete_object(self, user, account, container, name, until=None, prefix='', delimiter=None): |
|
1229 |
def delete_object(self, user, account, container, name, until=None, |
|
1230 |
prefix='', delimiter=None): |
|
1121 | 1231 |
"""Delete/purge an object.""" |
1122 | 1232 |
|
1123 | 1233 |
logger.debug("delete_object: %s %s %s %s %s %s %s", user, |
... | ... | |
1125 | 1235 |
self._delete_object(user, account, container, name, until, delimiter) |
1126 | 1236 |
|
1127 | 1237 |
def list_versions(self, user, account, container, name): |
1128 |
"""Return a list of all (version, version_timestamp) tuples for an object."""
|
|
1238 |
"""Return a list of all object (version, version_timestamp) tuples."""
|
|
1129 | 1239 |
|
1130 | 1240 |
logger.debug( |
1131 | 1241 |
"list_versions: %s %s %s %s", user, account, container, name) |
1132 | 1242 |
self._can_read(user, account, container, name) |
1133 | 1243 |
path, node = self._lookup_object(account, container, name) |
1134 | 1244 |
versions = self.node.node_get_versions(node) |
1135 |
return [[x[self.SERIAL], x[self.MTIME]] for x in versions if x[self.CLUSTER] != CLUSTER_DELETED] |
|
1245 |
return [[x[self.SERIAL], x[self.MTIME]] for x in versions if |
|
1246 |
x[self.CLUSTER] != CLUSTER_DELETED] |
|
1136 | 1247 |
|
1137 | 1248 |
def get_uuid(self, user, uuid): |
1138 | 1249 |
"""Return the (account, container, name) for the UUID given.""" |
... | ... | |
1241 | 1352 |
return props |
1242 | 1353 |
|
1243 | 1354 |
def _get_statistics(self, node, until=None, compute=False): |
1244 |
"""Return count, sum of size and latest timestamp of everything under node."""
|
|
1355 |
"""Return (count, sum of size, timestamp) of everything under node."""
|
|
1245 | 1356 |
|
1246 | 1357 |
if until is not None: |
1247 | 1358 |
stats = self.node.statistics_latest(node, until, CLUSTER_DELETED) |
1248 | 1359 |
elif compute: |
1249 |
stats = self.node.statistics_latest(node, except_cluster=CLUSTER_DELETED) |
|
1360 |
stats = self.node.statistics_latest(node, |
|
1361 |
except_cluster=CLUSTER_DELETED) |
|
1250 | 1362 |
else: |
1251 | 1363 |
stats = self.node.statistics_get(node, CLUSTER_NORMAL) |
1252 | 1364 |
if stats is None: |
... | ... | |
1292 | 1404 |
src_type = '' |
1293 | 1405 |
src_checksum = '' |
1294 | 1406 |
if size is None: # Set metadata. |
1295 |
hash = src_hash # This way hash can be set to None (account or container). |
|
1407 |
hash = src_hash # This way hash can be set to None |
|
1408 |
# (account or container). |
|
1296 | 1409 |
size = src_size |
1297 | 1410 |
if type is None: |
1298 | 1411 |
type = src_type |
... | ... | |
1340 | 1453 |
|
1341 | 1454 |
src_version_id, dest_version_id = self._put_version_duplicate( |
1342 | 1455 |
user, node, |
1343 |
update_statistics_ancestors_depth=update_statistics_ancestors_depth) |
|
1456 |
update_statistics_ancestors_depth= |
|
1457 |
update_statistics_ancestors_depth) |
|
1344 | 1458 |
self._put_metadata_duplicate( |
1345 | 1459 |
src_version_id, dest_version_id, domain, node, meta, replace) |
1346 | 1460 |
return src_version_id, dest_version_id |
... | ... | |
1356 | 1470 |
limit = 10000 |
1357 | 1471 |
return start, limit |
1358 | 1472 |
|
1359 |
def _list_object_properties(self, parent, path, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=None, until=None, size_range=None, allowed=None, all_props=False): |
|
1473 |
def _list_object_properties(self, parent, path, prefix='', delimiter=None, |
|
1474 |
marker=None, limit=10000, virtual=True, |
|
1475 |
domain=None, keys=None, until=None, |
|
1476 |
size_range=None, allowed=None, |
|
1477 |
all_props=False): |
|
1360 | 1478 |
keys = keys or [] |
1361 | 1479 |
allowed = allowed or [] |
1362 | 1480 |
cont_prefix = path + '/' |
... | ... | |
1366 | 1484 |
filterq = keys if domain else [] |
1367 | 1485 |
sizeq = size_range |
1368 | 1486 |
|
1369 |
objects, prefixes = self.node.latest_version_list(parent, prefix, delimiter, start, limit, before, CLUSTER_DELETED, allowed, domain, filterq, sizeq, all_props) |
|
1487 |
objects, prefixes = self.node.latest_version_list( |
|
1488 |
parent, prefix, delimiter, start, limit, before, CLUSTER_DELETED, |
|
1489 |
allowed, domain, filterq, sizeq, all_props) |
|
1370 | 1490 |
objects.extend([(p, None) for p in prefixes] if virtual else []) |
1371 | 1491 |
objects.sort(key=lambda x: x[0]) |
1372 | 1492 |
objects = [(x[0][len(cont_prefix):],) + x[1:] for x in objects] |
... | ... | |
1385 | 1505 |
details.update({'user': user, 'total': total}) |
1386 | 1506 |
logger.debug( |
1387 | 1507 |
"_report_size_change: %s %s %s %s", user, account, size, details) |
1388 |
self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('resource.diskspace',),
|
|
1389 |
account, QUEUE_INSTANCE_ID, 'diskspace',
|
|
1390 |
float(size), details))
|
|
1508 |
self.messages.append( |
|
1509 |
(QUEUE_MESSAGE_KEY_PREFIX % ('resource.diskspace',),
|
|
1510 |
account, QUEUE_INSTANCE_ID, 'diskspace', float(size), details))
|
|
1391 | 1511 |
|
1392 | 1512 |
if not self.using_external_quotaholder: |
1393 | 1513 |
return |
... | ... | |
1399 | 1519 |
holder=account, |
1400 | 1520 |
source=DEFAULT_SOURCE, |
1401 | 1521 |
provisions={'pithos.diskspace': size}, |
1402 |
name=name |
|
1403 |
) |
|
1522 |
name=name) |
|
1404 | 1523 |
except BaseException, e: |
1405 | 1524 |
raise QuotaError(e) |
1406 | 1525 |
else: |
... | ... | |
1412 | 1531 |
logger.debug("_report_object_change: %s %s %s %s", user, |
1413 | 1532 |
account, path, details) |
1414 | 1533 |
self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('object',), |
1415 |
account, QUEUE_INSTANCE_ID, 'object', path, details)) |
|
1534 |
account, QUEUE_INSTANCE_ID, 'object', path, |
|
1535 |
details)) |
|
1416 | 1536 |
|
1417 | 1537 |
def _report_sharing_change(self, user, account, path, details=None): |
1418 | 1538 |
logger.debug("_report_permissions_change: %s %s %s %s", |
... | ... | |
1420 | 1540 |
details = details or {} |
1421 | 1541 |
details.update({'user': user}) |
1422 | 1542 |
self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('sharing',), |
1423 |
account, QUEUE_INSTANCE_ID, 'sharing', path, details)) |
|
1543 |
account, QUEUE_INSTANCE_ID, 'sharing', path, |
|
1544 |
details)) |
|
1424 | 1545 |
|
1425 | 1546 |
# Policy functions. |
1426 | 1547 |
|
... | ... | |
1496 | 1617 |
if node is not None: |
1497 | 1618 |
props = self.node.version_lookup(node, inf, CLUSTER_NORMAL) |
1498 | 1619 |
if props is not None: |
1499 |
if props[self.TYPE].split(';', 1)[0].strip() in ('application/directory', 'application/folder'): |
|
1620 |
if props[self.TYPE].split(';', 1)[0].strip() in ( |
|
1621 |
'application/directory', 'application/folder'): |
|
1500 | 1622 |
formatted.append((p.rstrip('/') + '/', self.MATCH_PREFIX)) |
1501 | 1623 |
formatted.append((p, self.MATCH_EXACT)) |
1502 | 1624 |
return formatted |
... | ... | |
1517 | 1639 |
if node is not None: |
1518 | 1640 |
props = self.node.version_lookup(node, inf, CLUSTER_NORMAL) |
1519 | 1641 |
if props is not None: |
1520 |
if props[self.TYPE].split(';', 1)[0].strip() in ('application/directory', 'application/folder'): |
|
1642 |
if props[self.TYPE].split(';', 1)[0].strip() in ( |
|
1643 |
'application/directory', 'application/folder'): |
|
1521 | 1644 |
return p |
1522 | 1645 |
return None |
1523 | 1646 |
|
... | ... | |
1530 | 1653 |
path = self._get_permissions_path(account, container, name) |
1531 | 1654 |
if not path: |
1532 | 1655 |
raise NotAllowedError |
1533 |
if not self.permissions.access_check(path, self.READ, user) and not self.permissions.access_check(path, self.WRITE, user): |
|
1656 |
if (not self.permissions.access_check(path, self.READ, user) and not |
|
1657 |
self.permissions.access_check(path, self.WRITE, user)): |
|
1534 | 1658 |
raise NotAllowedError |
1535 | 1659 |
|
1536 | 1660 |
def _can_write(self, user, account, container, name): |
... | ... | |
1581 | 1705 |
'modified_by': props[self.MUSER], |
1582 | 1706 |
'uuid': props[self.UUID], |
1583 | 1707 |
'checksum': props[self.CHECKSUM]} |
1584 |
if include_user_defined and user_defined != None:
|
|
1708 |
if include_user_defined and user_defined is not None:
|
|
1585 | 1709 |
meta.update(user_defined) |
1586 | 1710 |
return meta |
1587 | 1711 |
|
Also available in: Unified diff