Revision 0c6ab9df
b/snf-pithos-app/pithos/api/functions.py | ||
---|---|---|
590 | 590 |
try: |
591 | 591 |
request.backend.delete_container( |
592 | 592 |
request.user_uniq, v_account, v_container, |
593 |
until, delimiter=delimiter) |
|
593 |
until, delimiter=delimiter, listing_limit=settings.API_LIST_LIMIT)
|
|
594 | 594 |
except NotAllowedError: |
595 | 595 |
raise faults.Forbidden('Not allowed') |
596 | 596 |
except ItemNotExists: |
... | ... | |
1037 | 1037 |
version_id = copy_or_move_object( |
1038 | 1038 |
request, src_account, src_container, src_name, |
1039 | 1039 |
v_account, v_container, v_object, |
1040 |
move=True, delimiter=delimiter) |
|
1040 |
move=True, delimiter=delimiter, |
|
1041 |
listing_limit=settings.API_LIST_LIMIT) |
|
1041 | 1042 |
else: |
1042 | 1043 |
try: |
1043 | 1044 |
src_container, src_name = split_container_object_string( |
... | ... | |
1047 | 1048 |
version_id = copy_or_move_object( |
1048 | 1049 |
request, src_account, src_container, src_name, |
1049 | 1050 |
v_account, v_container, v_object, |
1050 |
move=False, delimiter=delimiter) |
|
1051 |
move=False, delimiter=delimiter, |
|
1052 |
listing_limit=settings.API_LIST_LIMIT) |
|
1051 | 1053 |
response = HttpResponse(status=201) |
1052 | 1054 |
response['X-Object-Version'] = version_id |
1053 | 1055 |
return response |
... | ... | |
1229 | 1231 |
|
1230 | 1232 |
version_id = copy_or_move_object(request, v_account, v_container, v_object, |
1231 | 1233 |
dest_account, dest_container, dest_name, |
1232 |
move=False, delimiter=delimiter) |
|
1234 |
move=False, delimiter=delimiter, |
|
1235 |
listing_limit=settings.API_LIST_LIMIT) |
|
1233 | 1236 |
response = HttpResponse(status=201) |
1234 | 1237 |
response['X-Object-Version'] = version_id |
1235 | 1238 |
return response |
... | ... | |
1524 | 1527 |
try: |
1525 | 1528 |
request.backend.delete_object( |
1526 | 1529 |
request.user_uniq, v_account, v_container, |
1527 |
v_object, until, delimiter=delimiter) |
|
1530 |
v_object, until, delimiter=delimiter, |
|
1531 |
listing_limit=settings.API_LIST_LIMIT) |
|
1528 | 1532 |
except NotAllowedError: |
1529 | 1533 |
raise faults.Forbidden('Not allowed') |
1530 | 1534 |
except ItemNotExists: |
b/snf-pithos-app/pithos/api/test/containers.py | ||
---|---|---|
933 | 933 |
r = self.delete(url) |
934 | 934 |
self.assertEqual(r.status_code, 404) |
935 | 935 |
|
936 |
@pithos_test_settings(API_LIST_LIMIT=10) |
|
936 | 937 |
def test_delete_contents(self): |
937 | 938 |
folder = self.create_folder('c1')[0] |
938 |
descendant = strnextling(folder) |
|
939 |
self.upload_object('c1', descendant) |
|
939 |
for i in range(11): |
|
940 |
descendant = '%s_%d' % (strnextling(folder), i) |
|
941 |
self.upload_object('c1', descendant) |
|
940 | 942 |
self.create_folder('c1', '%s/%s' % (folder, get_random_data(5)))[0] |
941 | 943 |
|
942 |
self.delete('%s?delimiter=/' % join_urls( |
|
944 |
r = self.delete('%s?delimiter=/' % join_urls(
|
|
943 | 945 |
self.pithos_path, self.user, 'c1')) |
946 |
self.assertEqual(r.status_code, 204) |
|
944 | 947 |
self.assertEqual([], self.list_objects('c1')) |
945 | 948 |
self.assertTrue('c1' in self.list_containers(format=None)) |
b/snf-pithos-app/pithos/api/test/objects.py | ||
---|---|---|
41 | 41 |
from pithos.api.test import (PithosAPITest, pithos_settings, |
42 | 42 |
AssertMappingInvariant, AssertUUidInvariant, |
43 | 43 |
TEST_BLOCK_SIZE, TEST_HASH_ALGORITHM, |
44 |
DATE_FORMATS) |
|
44 |
DATE_FORMATS, pithos_test_settings)
|
|
45 | 45 |
from pithos.api.test.util import (md5_hash, merkle, strnextling, |
46 | 46 |
get_random_data, get_random_name) |
47 | 47 |
|
... | ... | |
924 | 924 |
get_random_name(), self.object)) |
925 | 925 |
self.assertEqual(r.status_code, 404) |
926 | 926 |
|
927 |
@pithos_test_settings(API_LIST_LIMIT=10) |
|
927 | 928 |
def test_copy_dir(self): |
928 | 929 |
folder = self.create_folder(self.container)[0] |
929 | 930 |
subfolder = self.create_folder( |
930 | 931 |
self.container, oname='%s/%s' % (folder, get_random_name()))[0] |
931 | 932 |
objects = [subfolder] |
932 | 933 |
append = objects.append |
933 |
append(self.upload_object(self.container, |
|
934 |
'%s/%s' % (folder, get_random_name()), |
|
935 |
depth='1')[0]) |
|
936 |
append(self.upload_object(self.container, |
|
937 |
'%s/%s' % (subfolder, get_random_name()), |
|
938 |
depth='2')[0]) |
|
934 |
for i in range(11): |
|
935 |
append(self.upload_object(self.container, |
|
936 |
'%s/%d' % (folder, i), |
|
937 |
depth='1')[0]) |
|
939 | 938 |
other = self.upload_object(self.container, strnextling(folder))[0] |
940 | 939 |
|
941 | 940 |
# copy dir |
... | ... | |
1006 | 1005 |
r = self.head(url) |
1007 | 1006 |
self.assertEqual(r.status_code, 404) |
1008 | 1007 |
|
1008 |
@pithos_test_settings(API_LIST_LIMIT=10) |
|
1009 | 1009 |
def test_move_dir(self): |
1010 | 1010 |
folder = self.create_folder(self.container)[0] |
1011 | 1011 |
subfolder = self.create_folder( |
1012 | 1012 |
self.container, oname='%s/%s' % (folder, get_random_name()))[0] |
1013 | 1013 |
objects = [subfolder] |
1014 | 1014 |
append = objects.append |
1015 |
append(self.upload_object(self.container, |
|
1016 |
'%s/%s' % (folder, get_random_name()), |
|
1017 |
depth='1')[0]) |
|
1018 |
append(self.upload_object(self.container, |
|
1019 |
'%s/%s' % (subfolder, get_random_name()), |
|
1020 |
depth='1')[0]) |
|
1015 |
for i in range(11): |
|
1016 |
append(self.upload_object(self.container, |
|
1017 |
'%s/%d' % (folder, i), |
|
1018 |
depth='1')[0]) |
|
1021 | 1019 |
other = self.upload_object(self.container, strnextling(folder))[0] |
1022 | 1020 |
|
1023 | 1021 |
# move dir |
... | ... | |
1212 | 1210 |
self.assertTrue('X-Object-Hash' in r) |
1213 | 1211 |
self.assertEqual(r['X-Object-Hash'], self.etag) |
1214 | 1212 |
|
1215 |
# assert source object still exists
|
|
1213 |
# assert source object still exists |
|
1216 | 1214 |
url = join_urls(self.pithos_path, self.user, self.container, |
1217 | 1215 |
self.object) |
1218 | 1216 |
r = self.head(url) |
... | ... | |
1229 | 1227 |
self.assertTrue('X-Object-Hash' in r) |
1230 | 1228 |
self.assertEqual(r['X-Object-Hash'], self.etag) |
1231 | 1229 |
|
1230 |
@pithos_test_settings(API_LIST_LIMIT=10) |
|
1231 |
def test_copy_dir_contents(self): |
|
1232 |
folder = self.create_folder(self.container)[0] |
|
1233 |
subfolder = self.create_folder( |
|
1234 |
self.container, oname='%s/%s' % (folder, get_random_name()))[0] |
|
1235 |
objects = [subfolder] |
|
1236 |
append = objects.append |
|
1237 |
for i in range(11): |
|
1238 |
append(self.upload_object(self.container, |
|
1239 |
'%s/%d' % (folder, i), |
|
1240 |
depth='1')[0]) |
|
1241 |
other = self.upload_object(self.container, strnextling(folder))[0] |
|
1242 |
|
|
1243 |
# copy dir |
|
1244 |
url = join_urls(self.pithos_path, self.user, self.container, |
|
1245 |
folder) |
|
1246 |
copy_folder = self.create_folder(self.container)[0] |
|
1247 |
r = self.copy('%s?delimiter=/' % url, |
|
1248 |
HTTP_X_OBJECT_META_TEST='testcopy', |
|
1249 |
HTTP_DESTINATION='/%s/%s' % (self.container, |
|
1250 |
copy_folder)) |
|
1251 |
self.assertEqual(r.status_code, 201) |
|
1252 |
|
|
1253 |
for obj in objects: |
|
1254 |
# assert object exists |
|
1255 |
url = join_urls(self.pithos_path, self.user, self.container, |
|
1256 |
obj.replace(folder, copy_folder)) |
|
1257 |
r = self.head(url) |
|
1258 |
self.assertEqual(r.status_code, 200) |
|
1259 |
|
|
1260 |
# assert other has not been created under copy folder |
|
1261 |
url = join_urls(self.pithos_path, self.user, self.container, |
|
1262 |
'%s/%s' % (copy_folder, |
|
1263 |
other.replace(folder, copy_folder))) |
|
1264 |
r = self.head(url) |
|
1265 |
self.assertEqual(r.status_code, 404) |
|
1266 |
|
|
1232 | 1267 |
def test_copy_to_other_account(self): |
1233 | 1268 |
# create a container under alice account |
1234 | 1269 |
cname = self.create_container(user='alice')[0] |
... | ... | |
1347 | 1382 |
r = self.head(url) |
1348 | 1383 |
self.assertEqual(r.status_code, 404) |
1349 | 1384 |
|
1385 |
@pithos_test_settings(API_LIST_LIMIT=10) |
|
1386 |
def test_move_dir_contents(self): |
|
1387 |
folder = self.create_folder(self.container)[0] |
|
1388 |
subfolder = self.create_folder( |
|
1389 |
self.container, oname='%s/%s' % (folder, get_random_name()))[0] |
|
1390 |
objects = [subfolder] |
|
1391 |
append = objects.append |
|
1392 |
for i in range(11): |
|
1393 |
append(self.upload_object(self.container, |
|
1394 |
'%s/%d' % (folder, i), |
|
1395 |
depth='1')[0]) |
|
1396 |
other = self.upload_object(self.container, strnextling(folder))[0] |
|
1397 |
|
|
1398 |
# copy dir |
|
1399 |
url = join_urls(self.pithos_path, self.user, self.container, folder) |
|
1400 |
copy_folder = self.create_folder(self.container)[0] |
|
1401 |
r = self.move('%s?delimiter=/' % url, |
|
1402 |
HTTP_X_OBJECT_META_TEST='testcopy', |
|
1403 |
HTTP_DESTINATION='/%s/%s' % (self.container, |
|
1404 |
copy_folder)) |
|
1405 |
self.assertEqual(r.status_code, 201) |
|
1406 |
|
|
1407 |
for obj in objects: |
|
1408 |
# assert object exists |
|
1409 |
url = join_urls(self.pithos_path, self.user, self.container, |
|
1410 |
obj.replace(folder, copy_folder)) |
|
1411 |
r = self.head(url) |
|
1412 |
self.assertEqual(r.status_code, 200) |
|
1413 |
|
|
1414 |
# assert other has not been created under copy folder |
|
1415 |
url = join_urls(self.pithos_path, self.user, self.container, |
|
1416 |
'%s/%s' % (copy_folder, |
|
1417 |
other.replace(folder, copy_folder))) |
|
1418 |
r = self.head(url) |
|
1419 |
self.assertEqual(r.status_code, 404) |
|
1420 |
|
|
1350 | 1421 |
def test_move_to_other_container(self): |
1351 | 1422 |
# move object to other container (not existing) |
1352 | 1423 |
cname = get_random_name() |
... | ... | |
1920 | 1991 |
r = self.delete(url) |
1921 | 1992 |
self.assertEqual(r.status_code, 404) |
1922 | 1993 |
|
1994 |
@pithos_test_settings(API_LIST_LIMIT=10) |
|
1923 | 1995 |
def test_delete_dir(self): |
1924 | 1996 |
folder = self.create_folder(self.container)[0] |
1925 | 1997 |
subfolder = self.create_folder( |
1926 | 1998 |
self.container, oname='%s/%s' % (folder, get_random_name()))[0] |
1927 | 1999 |
objects = [subfolder] |
1928 | 2000 |
append = objects.append |
1929 |
append(self.upload_object(self.container, |
|
1930 |
'%s/%s' % (folder, get_random_name()), |
|
1931 |
depth='1')[0]) |
|
1932 |
append(self.upload_object(self.container, |
|
1933 |
'%s/%s' % (subfolder, get_random_name()), |
|
1934 |
depth='2')[0]) |
|
2001 |
for i in range(11): |
|
2002 |
append(self.upload_object(self.container, |
|
2003 |
'%s/%d' % (folder, i), |
|
2004 |
depth='1')[0]) |
|
1935 | 2005 |
other = self.upload_object(self.container, strnextling(folder))[0] |
1936 | 2006 |
|
1937 | 2007 |
# move dir |
b/snf-pithos-app/pithos/api/util.py | ||
---|---|---|
482 | 482 |
|
483 | 483 |
def copy_or_move_object(request, src_account, src_container, src_name, |
484 | 484 |
dest_account, dest_container, dest_name, |
485 |
move=False, delimiter=None): |
|
485 |
move=False, delimiter=None, listing_limit=None):
|
|
486 | 486 |
"""Copy or move an object.""" |
487 | 487 |
|
488 | 488 |
if 'ignore_content_type' in request.GET and 'CONTENT_TYPE' in request.META: |
... | ... | |
494 | 494 |
version_id = request.backend.move_object( |
495 | 495 |
request.user_uniq, src_account, src_container, src_name, |
496 | 496 |
dest_account, dest_container, dest_name, |
497 |
content_type, 'pithos', meta, False, permissions, delimiter) |
|
497 |
content_type, 'pithos', meta, False, permissions, delimiter, |
|
498 |
listing_limit=listing_limit) |
|
498 | 499 |
else: |
499 | 500 |
version_id = request.backend.copy_object( |
500 | 501 |
request.user_uniq, src_account, src_container, src_name, |
501 | 502 |
dest_account, dest_container, dest_name, |
502 | 503 |
content_type, 'pithos', meta, False, permissions, |
503 |
src_version, delimiter) |
|
504 |
src_version, delimiter, listing_limit=listing_limit)
|
|
504 | 505 |
except NotAllowedError: |
505 | 506 |
raise faults.Forbidden('Not allowed') |
506 | 507 |
except (ItemNotExists, VersionNotExists): |
b/snf-pithos-backend/pithos/backends/modular.py | ||
---|---|---|
683 | 683 |
@debug_method |
684 | 684 |
@backend_method |
685 | 685 |
def delete_container(self, user, account, container, until=None, prefix='', |
686 |
delimiter=None): |
|
686 |
delimiter=None, listing_limit=None):
|
|
687 | 687 |
"""Delete/purge the container with the given name.""" |
688 | 688 |
|
689 | 689 |
self._can_write_container(user, account, container) |
... | ... | |
731 | 731 |
src_names = self._list_objects_no_limit( |
732 | 732 |
user, account, container, prefix='', delimiter=None, |
733 | 733 |
virtual=False, domain=None, keys=[], shared=False, until=None, |
734 |
size_range=None, all_props=True, public=False) |
|
734 |
size_range=None, all_props=True, public=False, |
|
735 |
listing_limit=listing_limit) |
|
735 | 736 |
paths = [] |
736 | 737 |
for t in src_names: |
737 | 738 |
path = '/'.join((account, container, t[0])) |
... | ... | |
820 | 821 |
|
821 | 822 |
def _list_objects_no_limit(self, user, account, container, prefix, |
822 | 823 |
delimiter, virtual, domain, keys, shared, until, |
823 |
size_range, all_props, public): |
|
824 |
size_range, all_props, public, |
|
825 |
listing_limit=10000): |
|
824 | 826 |
objects = [] |
825 | 827 |
while True: |
826 |
marker = objects[-1] if objects else None |
|
827 |
limit = 10000
|
|
828 |
marker = objects[-1][0] if objects else None
|
|
829 |
limit = listing_limit
|
|
828 | 830 |
l = self._list_objects( |
829 | 831 |
user, account, container, prefix, delimiter, marker, limit, |
830 | 832 |
virtual, domain, keys, shared, until, size_range, all_props, |
... | ... | |
1207 | 1209 |
dest_account, dest_container, dest_name, type, |
1208 | 1210 |
dest_domain=None, dest_meta=None, replace_meta=False, |
1209 | 1211 |
permissions=None, src_version=None, is_move=False, |
1210 |
delimiter=None): |
|
1212 |
delimiter=None, listing_limit=10000):
|
|
1211 | 1213 |
|
1212 | 1214 |
report_size_change = not is_move |
1213 | 1215 |
dest_meta = dest_meta or {} |
... | ... | |
1249 | 1251 |
src_names = self._list_objects_no_limit( |
1250 | 1252 |
user, src_account, src_container, prefix, delimiter=None, |
1251 | 1253 |
virtual=False, domain=None, keys=[], shared=False, until=None, |
1252 |
size_range=None, all_props=True, public=False) |
|
1254 |
size_range=None, all_props=True, public=False, |
|
1255 |
listing_limit=listing_limit) |
|
1253 | 1256 |
src_names.sort(key=lambda x: x[2]) # order by nodes |
1254 | 1257 |
paths = [elem[0] for elem in src_names] |
1255 | 1258 |
nodes = [elem[2] for elem in src_names] |
... | ... | |
1284 | 1287 |
def copy_object(self, user, src_account, src_container, src_name, |
1285 | 1288 |
dest_account, dest_container, dest_name, type, domain, |
1286 | 1289 |
meta=None, replace_meta=False, permissions=None, |
1287 |
src_version=None, delimiter=None): |
|
1290 |
src_version=None, delimiter=None, listing_limit=None):
|
|
1288 | 1291 |
"""Copy an object's data and metadata.""" |
1289 | 1292 |
|
1290 | 1293 |
meta = meta or {} |
1291 | 1294 |
dest_version_id = self._copy_object( |
1292 | 1295 |
user, src_account, src_container, src_name, dest_account, |
1293 | 1296 |
dest_container, dest_name, type, domain, meta, replace_meta, |
1294 |
permissions, src_version, False, delimiter) |
|
1297 |
permissions, src_version, False, delimiter, |
|
1298 |
listing_limit=listing_limit) |
|
1295 | 1299 |
return dest_version_id |
1296 | 1300 |
|
1297 | 1301 |
@debug_method |
... | ... | |
1299 | 1303 |
def move_object(self, user, src_account, src_container, src_name, |
1300 | 1304 |
dest_account, dest_container, dest_name, type, domain, |
1301 | 1305 |
meta=None, replace_meta=False, permissions=None, |
1302 |
delimiter=None): |
|
1306 |
delimiter=None, listing_limit=None):
|
|
1303 | 1307 |
"""Move an object's data and metadata.""" |
1304 | 1308 |
|
1305 | 1309 |
meta = meta or {} |
... | ... | |
1308 | 1312 |
dest_version_id = self._move_object( |
1309 | 1313 |
user, src_account, src_container, src_name, dest_account, |
1310 | 1314 |
dest_container, dest_name, type, domain, meta, replace_meta, |
1311 |
permissions, None, delimiter=delimiter) |
|
1315 |
permissions, None, delimiter=delimiter, |
|
1316 |
listing_limit=listing_limit) |
|
1312 | 1317 |
return dest_version_id |
1313 | 1318 |
|
1314 | 1319 |
def _delete_object(self, user, account, container, name, until=None, |
1315 |
delimiter=None, report_size_change=True): |
|
1320 |
delimiter=None, report_size_change=True, |
|
1321 |
listing_limit=None): |
|
1316 | 1322 |
if user != account: |
1317 | 1323 |
raise NotAllowedError |
1318 | 1324 |
|
... | ... | |
1377 | 1383 |
src_names = self._list_objects_no_limit( |
1378 | 1384 |
user, account, container, prefix, delimiter=None, |
1379 | 1385 |
virtual=False, domain=None, keys=[], shared=False, until=None, |
1380 |
size_range=None, all_props=True, public=False) |
|
1386 |
size_range=None, all_props=True, public=False, |
|
1387 |
listing_limit=listing_limit) |
|
1381 | 1388 |
paths = [] |
1382 | 1389 |
for t in src_names: |
1383 | 1390 |
path = '/'.join((account, container, t[0])) |
... | ... | |
1409 | 1416 |
@debug_method |
1410 | 1417 |
@backend_method |
1411 | 1418 |
def delete_object(self, user, account, container, name, until=None, |
1412 |
prefix='', delimiter=None): |
|
1419 |
prefix='', delimiter=None, listing_limit=None):
|
|
1413 | 1420 |
"""Delete/purge an object.""" |
1414 | 1421 |
|
1415 |
self._delete_object(user, account, container, name, until, delimiter) |
|
1422 |
self._delete_object(user, account, container, name, until, delimiter, |
|
1423 |
listing_limit=listing_limit) |
|
1416 | 1424 |
|
1417 | 1425 |
@debug_method |
1418 | 1426 |
@backend_method |
Also available in: Unified diff