Revision b1dadd0e
b/snf-pithos-app/README | ||
---|---|---|
42 | 42 |
PITHOS_BACKEND_QUEUE_EXCHANGE pithos |
43 | 43 |
PITHOS_BACKEND_QUOTA 50 GB (50 * 1024 ** 3) Default user quota |
44 | 44 |
PITHOS_BACKEND_VERSIONING auto Default versioning policy for containers |
45 |
PITHOS_BACKEND_FREE_VERSIONING True Default versioning debit policy (default free) |
|
45 | 46 |
PITHOS_UPDATE_MD5 True Update object checksums when using hashmaps |
46 | 47 |
PITHOS_SERVICE_TOKEN '' Service token acquired by the identity provider (astakos) |
47 | 48 |
=============================== ================================================ ============================================================ |
b/snf-pithos-app/conf/20-snf-pithos-app-settings.conf | ||
---|---|---|
28 | 28 |
# Default setting for new accounts. |
29 | 29 |
#PITHOS_BACKEND_QUOTA = 50 * 1024 * 1024 * 1024 |
30 | 30 |
#PITHOS_BACKEND_VERSIONING = 'auto' |
31 |
#PITHOS_BACKEND_FREE_VERSIONING = True |
|
31 | 32 |
|
32 | 33 |
# Disable if checksums are not required or are computed asynchronously by an external process. |
33 | 34 |
#PITHOS_UPDATE_MD5 = True |
b/snf-pithos-app/pithos/api/dispatch.py | ||
---|---|---|
1 |
from pithos.api.settings import (BACKEND_DB_MODULE, BACKEND_DB_CONNECTION, |
|
2 |
BACKEND_BLOCK_MODULE, BACKEND_BLOCK_PATH, |
|
3 |
BACKEND_BLOCK_UMASK, |
|
4 |
BACKEND_QUEUE_MODULE, BACKEND_QUEUE_HOSTS, |
|
5 |
BACKEND_QUEUE_EXCHANGE, |
|
6 |
BACKEND_QUOTA, BACKEND_VERSIONING) |
|
7 |
from pithos.backends import connect_backend |
|
8 |
from pithos.api.util import hashmap_md5 |
|
1 |
# from pithos.api.settings import (BACKEND_DB_MODULE, BACKEND_DB_CONNECTION, |
|
2 |
# BACKEND_BLOCK_MODULE, BACKEND_BLOCK_PATH, |
|
3 |
# BACKEND_BLOCK_UMASK, |
|
4 |
# BACKEND_QUEUE_MODULE, BACKEND_QUEUE_HOSTS, |
|
5 |
# BACKEND_QUEUE_EXCHANGE, |
|
6 |
# BACKEND_QUOTA, BACKEND_VERSIONING, |
|
7 |
# BACKEND_FREE_VERSIONING) |
|
8 |
from pithos.api.settings import (BACKEND_QUOTA, BACKEND_VERSIONING) |
|
9 |
|
|
10 |
#from pithos.backends import connect_backend |
|
11 |
from pithos.api.util import hashmap_md5, get_backend |
|
9 | 12 |
|
10 | 13 |
from django.core.mail import send_mail |
11 | 14 |
from django.utils.translation import ugettext as _ |
... | ... | |
20 | 23 |
if m['resource'] != 'object' or m['details']['action'] != 'object update': |
21 | 24 |
return |
22 | 25 |
|
23 |
backend = connect_backend(db_module=BACKEND_DB_MODULE, |
|
24 |
db_connection=BACKEND_DB_CONNECTION, |
|
25 |
block_module=BACKEND_BLOCK_MODULE, |
|
26 |
block_path=BACKEND_BLOCK_PATH, |
|
27 |
block_umask=BACKEND_BLOCK_UMASK, |
|
28 |
queue_module=BACKEND_QUEUE_MODULE, |
|
29 |
queue_hosts=BACKEND_QUEUE_HOSTS, |
|
30 |
queue_exchange=BACKEND_QUEUE_EXHANGE) |
|
26 |
# backend = connect_backend(db_module=BACKEND_DB_MODULE, |
|
27 |
# db_connection=BACKEND_DB_CONNECTION, |
|
28 |
# block_module=BACKEND_BLOCK_MODULE, |
|
29 |
# block_path=BACKEND_BLOCK_PATH, |
|
30 |
# block_umask=BACKEND_BLOCK_UMASK, |
|
31 |
# queue_module=BACKEND_QUEUE_MODULE, |
|
32 |
# queue_hosts=BACKEND_QUEUE_HOSTS, |
|
33 |
# queue_exchange=BACKEND_QUEUE_EXHANGE |
|
34 |
# free_versioning=BACKEND_FREE_VERSIONING) |
|
35 |
backend = get_backend() |
|
31 | 36 |
backend.default_policy['quota'] = BACKEND_QUOTA |
32 | 37 |
backend.default_policy['versioning'] = BACKEND_VERSIONING |
33 | 38 |
|
b/snf-pithos-app/pithos/api/management/commands/storagequota.py | ||
---|---|---|
35 | 35 |
|
36 | 36 |
from django.core.management.base import BaseCommand, CommandError |
37 | 37 |
|
38 |
from pithos.api.settings import (BACKEND_DB_MODULE, BACKEND_DB_CONNECTION, |
|
39 |
BACKEND_BLOCK_MODULE, BACKEND_BLOCK_PATH, |
|
40 |
BACKEND_BLOCK_UMASK, |
|
41 |
BACKEND_QUEUE_MODULE, BACKEND_QUEUE_HOSTS, |
|
42 |
BACKEND_QUEUE_EXCHANGE, |
|
43 |
BACKEND_QUOTA, BACKEND_VERSIONING) |
|
44 |
from pithos.backends import connect_backend |
|
38 |
from pithos.api.settings import (BACKEND_QUOTA, BACKEND_VERSIONING) |
|
45 | 39 |
|
40 |
from pithos.api.util import get_backend |
|
46 | 41 |
|
47 | 42 |
class Command(BaseCommand): |
48 | 43 |
args = "<user>" |
... | ... | |
67 | 62 |
except ValueError: |
68 | 63 |
raise CommandError("Invalid quota") |
69 | 64 |
|
70 |
backend = connect_backend(db_module=BACKEND_DB_MODULE, |
|
71 |
db_connection=BACKEND_DB_CONNECTION, |
|
72 |
block_module=BACKEND_BLOCK_MODULE, |
|
73 |
block_path=BACKEND_BLOCK_PATH, |
|
74 |
block_umask=BACKEND_BLOCK_UMASK, |
|
75 |
queue_module=BACKEND_QUEUE_MODULE, |
|
76 |
queue_connection=BACKEND_QUEUE_HOSTS, |
|
77 |
queue_exchange=BACKEND_QUEUE_EXCHANGE) |
|
65 |
backend = get_backend() |
|
78 | 66 |
backend.default_policy['quota'] = BACKEND_QUOTA |
79 | 67 |
backend.default_policy['versioning'] = BACKEND_VERSIONING |
80 | 68 |
if quota is not None: |
b/snf-pithos-app/pithos/api/settings.py | ||
---|---|---|
44 | 44 |
BACKEND_QUOTA = getattr( |
45 | 45 |
settings, 'PITHOS_BACKEND_QUOTA', 50 * 1024 * 1024 * 1024) |
46 | 46 |
BACKEND_VERSIONING = getattr(settings, 'PITHOS_BACKEND_VERSIONING', 'auto') |
47 |
BACKEND_FREE_VERSIONING = getattr(settings, 'PITHOS_BACKEND_FREE_VERSIONING', True) |
|
47 | 48 |
|
48 | 49 |
# Update object checksums when using hashmaps. |
49 | 50 |
UPDATE_MD5 = getattr(settings, 'PITHOS_UPDATE_MD5', True) |
b/snf-pithos-app/pithos/api/util.py | ||
---|---|---|
62 | 62 |
BACKEND_QUEUE_MODULE, BACKEND_QUEUE_HOSTS, |
63 | 63 |
BACKEND_QUEUE_EXCHANGE, |
64 | 64 |
BACKEND_QUOTA, BACKEND_VERSIONING, |
65 |
BACKEND_FREE_VERSIONING, |
|
65 | 66 |
AUTHENTICATION_URL, AUTHENTICATION_USERS, |
66 | 67 |
SERVICE_TOKEN, COOKIE_NAME) |
67 | 68 |
|
... | ... | |
860 | 861 |
block_path=BACKEND_BLOCK_PATH, |
861 | 862 |
block_umask=BACKEND_BLOCK_UMASK, |
862 | 863 |
queue_module=BACKEND_QUEUE_MODULE, |
863 |
queue_connection=BACKEND_QUEUE_CONNECTION) |
|
864 |
queue_hosts=BACKEND_QUEUE_HOSTS, |
|
865 |
queue_exchange=BACKEND_QUEUE_EXCHANGE, |
|
866 |
free_versioning=BACKEND_FREE_VERSIONING) |
|
864 | 867 |
|
865 | 868 |
|
866 | 869 |
def get_backend(): |
b/snf-pithos-backend/pithos/backends/modular.py | ||
---|---|---|
129 | 129 |
def __init__(self, db_module=None, db_connection=None, |
130 | 130 |
block_module=None, block_path=None, block_umask=None, |
131 | 131 |
queue_module=None, queue_hosts=None, |
132 |
queue_exchange=None): |
|
132 |
queue_exchange=None, |
|
133 |
free_versioning=True): |
|
133 | 134 |
db_module = db_module or DEFAULT_DB_MODULE |
134 | 135 |
db_connection = db_connection or DEFAULT_DB_CONNECTION |
135 | 136 |
block_module = block_module or DEFAULT_BLOCK_MODULE |
... | ... | |
138 | 139 |
#queue_module = queue_module or DEFAULT_QUEUE_MODULE |
139 | 140 |
#queue_hosts = queue_hosts or DEFAULT_QUEUE_HOSTS |
140 | 141 |
#queue_exchange = queue_exchange or DEFAULT_QUEUE_EXCHANGE |
141 |
|
|
142 |
|
|
142 | 143 |
self.hash_algorithm = 'sha256' |
143 | 144 |
self.block_size = 4 * 1024 * 1024 # 4MB |
145 |
self.free_versioning = free_versioning |
|
144 | 146 |
|
145 | 147 |
self.default_policy = {'quota': DEFAULT_QUOTA, |
146 | 148 |
'versioning': DEFAULT_VERSIONING} |
... | ... | |
171 | 173 |
if queue_module and queue_hosts: |
172 | 174 |
self.queue_module = load_module(queue_module) |
173 | 175 |
params = {'hosts': queue_hosts, |
174 |
'exchange': queue_exchange,
|
|
176 |
'exchange': queue_exchange,
|
|
175 | 177 |
'client_id': QUEUE_CLIENT_ID} |
176 | 178 |
self.queue = self.queue_module.Queue(**params) |
177 | 179 |
else: |
... | ... | |
489 | 491 |
self.store.map_delete(h) |
490 | 492 |
self.node.node_purge_children(node, until, CLUSTER_DELETED) |
491 | 493 |
self._report_size_change(user, account, -size, |
492 |
{'action':'container purge', 'path': path,
|
|
493 |
'versions': ','.join(str(i) for i in serials)})
|
|
494 |
{'action':'container purge', 'path': path,
|
|
495 |
'versions': ','.join(str(i) for i in serials)})
|
|
494 | 496 |
return |
495 | 497 |
|
496 | 498 |
if not delimiter: |
... | ... | |
503 | 505 |
self.node.node_purge_children(node, inf, CLUSTER_DELETED) |
504 | 506 |
self.node.node_remove(node) |
505 | 507 |
self._report_size_change(user, account, -size, |
506 |
{'action': 'container delete',
|
|
507 |
'path': path,
|
|
508 |
'versions': ','.join(str(i) for i in serials)})
|
|
508 |
{'action': 'container delete',
|
|
509 |
'path': path,
|
|
510 |
'versions': ','.join(str(i) for i in serials)})
|
|
509 | 511 |
else: |
510 |
# remove only contents
|
|
512 |
# remove only contents |
|
511 | 513 |
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) |
512 | 514 |
paths = [] |
513 | 515 |
for t in src_names: |
... | ... | |
516 | 518 |
src_version_id, dest_version_id = self._put_version_duplicate(user, node, size=0, type='', hash=None, checksum='', cluster=CLUSTER_DELETED) |
517 | 519 |
del_size = self._apply_versioning( |
518 | 520 |
account, container, src_version_id) |
519 |
if del_size: |
|
520 |
self._report_size_change(user, account, -del_size, |
|
521 |
{'action': 'object delete', |
|
522 |
'path': path, |
|
523 |
'versions': ','.join([str(dest_version_id)])}) |
|
521 |
self._report_size_change( |
|
522 |
user, account, -del_size, { |
|
523 |
'action': 'object delete', |
|
524 |
'path': path, |
|
525 |
'versions': ','.join([str(dest_version_id)]) |
|
526 |
} |
|
527 |
) |
|
524 | 528 |
self._report_object_change( |
525 | 529 |
user, account, path, details={'action': 'object delete'}) |
526 | 530 |
paths.append(path) |
... | ... | |
800 | 804 |
self._put_metadata_duplicate( |
801 | 805 |
src_version_id, dest_version_id, domain, meta, replace_meta) |
802 | 806 |
|
803 |
# Check quota. |
|
804 | 807 |
del_size = self._apply_versioning(account, container, pre_version_id) |
805 | 808 |
size_delta = size - del_size |
806 |
if size_delta > 0: |
|
807 |
account_quota = long(self._get_policy(account_node)['quota']) |
|
808 |
container_quota = long(self._get_policy(container_node)['quota']) |
|
809 |
if (account_quota > 0 and self._get_statistics(account_node)[1] + size_delta > account_quota) or \ |
|
810 |
(container_quota > 0 and self._get_statistics(container_node)[1] + size_delta > container_quota): |
|
811 |
# This must be executed in a transaction, so the version is never created if it fails. |
|
812 |
raise QuotaError |
|
809 |
# # Check quota. |
|
810 |
# if size_delta > 0: |
|
811 |
# account_quota = long(self._get_policy(account_node)['quota']) |
|
812 |
# container_quota = long(self._get_policy(container_node)['quota']) |
|
813 |
# if (account_quota > 0 and self._get_statistics(account_node)[1] + size_delta > account_quota) or \ |
|
814 |
# (container_quota > 0 and self._get_statistics(container_node)[1] + size_delta > container_quota): |
|
815 |
# # This must be executed in a transaction, so the version is never created if it fails. |
|
816 |
# raise QuotaError |
|
813 | 817 |
self._report_size_change(user, account, size_delta, |
814 |
{'action': 'object update', 'path': path,
|
|
815 |
'versions': ','.join([str(dest_version_id)])})
|
|
818 |
{'action': 'object update', 'path': path,
|
|
819 |
'versions': ','.join([str(dest_version_id)])})
|
|
816 | 820 |
|
817 | 821 |
if permissions is not None: |
818 | 822 |
self.permissions.access_set(path, permissions) |
... | ... | |
943 | 947 |
except NameError: |
944 | 948 |
self.permissions.access_clear(path) |
945 | 949 |
self._report_size_change(user, account, -size, |
946 |
{'action': 'object purge', 'path': path,
|
|
947 |
'versions': ','.join(str(i) for i in serials)})
|
|
950 |
{'action': 'object purge', 'path': path,
|
|
951 |
'versions': ','.join(str(i) for i in serials)})
|
|
948 | 952 |
return |
949 | 953 |
|
950 | 954 |
path, node = self._lookup_object(account, container, name) |
951 | 955 |
src_version_id, dest_version_id = self._put_version_duplicate(user, node, size=0, type='', hash=None, checksum='', cluster=CLUSTER_DELETED) |
952 | 956 |
del_size = self._apply_versioning(account, container, src_version_id) |
953 |
if del_size: |
|
954 |
self._report_size_change(user, account, -del_size, |
|
955 |
{'action': 'object delete', 'path': path, |
|
956 |
'versions': ','.join([str(dest_version_id)])}) |
|
957 |
self._report_size_change(user, account, -del_size, |
|
958 |
{'action': 'object delete', 'path': path, |
|
959 |
'versions': ','.join([str(dest_version_id)])}) |
|
957 | 960 |
self._report_object_change( |
958 | 961 |
user, account, path, details={'action': 'object delete'}) |
959 | 962 |
self.permissions.access_clear(path) |
... | ... | |
968 | 971 |
src_version_id, dest_version_id = self._put_version_duplicate(user, node, size=0, type='', hash=None, checksum='', cluster=CLUSTER_DELETED) |
969 | 972 |
del_size = self._apply_versioning( |
970 | 973 |
account, container, src_version_id) |
971 |
if del_size: |
|
972 |
self._report_size_change(user, account, -del_size, |
|
973 |
{'action': 'object delete', |
|
974 |
'path': path, |
|
975 |
'versions': ','.join([str(dest_version_id)])}) |
|
974 |
self._report_size_change(user, account, -del_size, |
|
975 |
{'action': 'object delete', |
|
976 |
'path': path, |
|
977 |
'versions': ','.join([str(dest_version_id)])}) |
|
976 | 978 |
self._report_object_change( |
977 | 979 |
user, account, path, details={'action': 'object delete'}) |
978 | 980 |
paths.append(path) |
... | ... | |
1230 | 1232 |
logger.debug( |
1231 | 1233 |
"_report_size_change: %s %s %s %s", user, account, size, details) |
1232 | 1234 |
self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('resource.diskspace',), |
1233 |
account, QUEUE_INSTANCE_ID, 'diskspace',
|
|
1234 |
float(size), details))
|
|
1235 |
account, QUEUE_INSTANCE_ID, 'diskspace',
|
|
1236 |
float(size), details))
|
|
1235 | 1237 |
|
1236 | 1238 |
def _report_object_change(self, user, account, path, details={}): |
1237 | 1239 |
details.update({'user': user}) |
1238 | 1240 |
logger.debug("_report_object_change: %s %s %s %s", user, |
1239 | 1241 |
account, path, details) |
1240 | 1242 |
self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('object',), |
1241 |
account, QUEUE_INSTANCE_ID, 'object', path, details))
|
|
1243 |
account, QUEUE_INSTANCE_ID, 'object', path, details))
|
|
1242 | 1244 |
|
1243 | 1245 |
def _report_sharing_change(self, user, account, path, details={}): |
1244 | 1246 |
logger.debug("_report_permissions_change: %s %s %s %s", |
1245 | 1247 |
user, account, path, details) |
1246 | 1248 |
details.update({'user': user}) |
1247 | 1249 |
self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('sharing',), |
1248 |
account, QUEUE_INSTANCE_ID, 'sharing', path, details))
|
|
1250 |
account, QUEUE_INSTANCE_ID, 'sharing', path, details))
|
|
1249 | 1251 |
|
1250 | 1252 |
# Policy functions. |
1251 | 1253 |
|
... | ... | |
1285 | 1287 |
return 0 |
1286 | 1288 |
path, node = self._lookup_container(account, container) |
1287 | 1289 |
versioning = self._get_policy(node)['versioning'] |
1288 |
if versioning != 'auto': |
|
1290 |
if versioning != 'auto' or self.free_versioning:
|
|
1289 | 1291 |
hash, size = self.node.version_remove(version_id) |
1290 | 1292 |
self.store.map_delete(hash) |
1291 | 1293 |
return size |
b/snf-pithos-backend/pithos/backends/util.py | ||
---|---|---|
43 | 43 |
class PithosBackendPool(ObjectPool): |
44 | 44 |
def __init__(self, size=None, db_module=None, db_connection=None, |
45 | 45 |
block_module=None, block_path=None, block_umask=None, |
46 |
queue_module=None, queue_connection=None): |
|
46 |
queue_module=None, queue_hosts=None, |
|
47 |
queue_exchange=None, |
|
48 |
free_versioning=True): |
|
47 | 49 |
super(PithosBackendPool, self).__init__(size=size) |
48 | 50 |
self.db_module = db_module |
49 | 51 |
self.db_connection = db_connection |
... | ... | |
51 | 53 |
self.block_path = block_path |
52 | 54 |
self.block_umask = block_umask |
53 | 55 |
self.queue_module = queue_module |
54 |
self.queue_connection = queue_connection |
|
55 |
|
|
56 |
self.queue_hosts = queue_hosts |
|
57 |
self.queue_exchange = queue_exchange |
|
58 |
self.free_versioning = free_versioning |
|
59 |
|
|
56 | 60 |
def _pool_create(self): |
57 | 61 |
backend = connect_backend(db_module=self.db_module, |
58 | 62 |
db_connection=self.db_connection, |
... | ... | |
60 | 64 |
block_path=self.block_path, |
61 | 65 |
block_umask=self.block_umask, |
62 | 66 |
queue_module=self.queue_module, |
63 |
queue_connection=self.queue_connection) |
|
67 |
queue_hosts=self.queue_hosts, |
|
68 |
queue_exchange=self.queue_exchange, |
|
69 |
free_versioning=self.free_versioning) |
|
64 | 70 |
|
65 | 71 |
backend._real_close = backend.close |
66 | 72 |
backend.close = instancemethod(_pooled_backend_close, backend, |
Also available in: Unified diff