mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-18 10:46:24 +00:00
Implement HTTP share listing endpoint.
This commit is contained in:
parent
26f6d0036c
commit
c72e7b0585
@ -630,8 +630,8 @@ Reading
|
|||||||
``GET /v1/immutable/:storage_index/shares``
|
``GET /v1/immutable/:storage_index/shares``
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
Retrieve a list indicating all shares available for the indicated storage index.
|
Retrieve a list (semantically, a set) indicating all shares available for the
|
||||||
For example::
|
indicated storage index. For example::
|
||||||
|
|
||||||
[1, 5]
|
[1, 5]
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ class UploadProgress(object):
|
|||||||
"""
|
"""
|
||||||
Progress of immutable upload, per the server.
|
Progress of immutable upload, per the server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# True when upload has finished.
|
# True when upload has finished.
|
||||||
finished = attr.ib(type=bool)
|
finished = attr.ib(type=bool)
|
||||||
# Remaining ranges to upload.
|
# Remaining ranges to upload.
|
||||||
@ -221,7 +222,7 @@ class StorageClientImmutables(object):
|
|||||||
headers=Headers(
|
headers=Headers(
|
||||||
{
|
{
|
||||||
"content-range": [
|
"content-range": [
|
||||||
ContentRange("bytes", offset, offset+len(data)).to_header()
|
ContentRange("bytes", offset, offset + len(data)).to_header()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@ -268,11 +269,7 @@ class StorageClientImmutables(object):
|
|||||||
"GET",
|
"GET",
|
||||||
url,
|
url,
|
||||||
headers=Headers(
|
headers=Headers(
|
||||||
{
|
{"range": [Range("bytes", [(offset, offset + length)]).to_header()]}
|
||||||
"range": [
|
|
||||||
Range("bytes", [(offset, offset + length)]).to_header()
|
|
||||||
]
|
|
||||||
}
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if response.code == http.PARTIAL_CONTENT:
|
if response.code == http.PARTIAL_CONTENT:
|
||||||
@ -282,3 +279,23 @@ class StorageClientImmutables(object):
|
|||||||
raise ClientException(
|
raise ClientException(
|
||||||
response.code,
|
response.code,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@inlineCallbacks
|
||||||
|
def list_shares(self, storage_index): # type: (bytes,) -> Deferred[Set[int]]
|
||||||
|
"""
|
||||||
|
Return the set of shares for a given storage index.
|
||||||
|
"""
|
||||||
|
url = self._client._url(
|
||||||
|
"/v1/immutable/{}/shares".format(_encode_si(storage_index))
|
||||||
|
)
|
||||||
|
response = yield self._client._request(
|
||||||
|
"GET",
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
if response.code == http.OK:
|
||||||
|
body = yield response.content()
|
||||||
|
returnValue(set(loads(body)))
|
||||||
|
else:
|
||||||
|
raise ClientException(
|
||||||
|
response.code,
|
||||||
|
)
|
||||||
|
@ -255,6 +255,22 @@ class HTTPServer(object):
|
|||||||
required.append({"begin": start, "end": end})
|
required.append({"begin": start, "end": end})
|
||||||
return self._cbor(request, {"required": required})
|
return self._cbor(request, {"required": required})
|
||||||
|
|
||||||
|
@_authorized_route(
|
||||||
|
_app,
|
||||||
|
set(),
|
||||||
|
"/v1/immutable/<string:storage_index>/shares",
|
||||||
|
methods=["GET"],
|
||||||
|
)
|
||||||
|
def list_shares(self, request, authorization, storage_index):
|
||||||
|
"""
|
||||||
|
List shares for the given storage index.
|
||||||
|
"""
|
||||||
|
storage_index = si_a2b(storage_index.encode("ascii"))
|
||||||
|
|
||||||
|
# TODO in future ticket, handle KeyError as 404
|
||||||
|
share_numbers = list(self._storage_server.get_buckets(storage_index).keys())
|
||||||
|
return self._cbor(request, share_numbers)
|
||||||
|
|
||||||
@_authorized_route(
|
@_authorized_route(
|
||||||
_app,
|
_app,
|
||||||
set(),
|
set(),
|
||||||
|
@ -382,6 +382,37 @@ class ImmutableHTTPAPITests(SyncTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(downloaded, expected_data[offset : offset + length])
|
self.assertEqual(downloaded, expected_data[offset : offset + length])
|
||||||
|
|
||||||
|
def test_list_shares(self):
|
||||||
|
"""
|
||||||
|
Once a share is finished uploading, it's possible to list it.
|
||||||
|
"""
|
||||||
|
im_client = StorageClientImmutables(self.http.client)
|
||||||
|
upload_secret = urandom(32)
|
||||||
|
lease_secret = urandom(32)
|
||||||
|
storage_index = b"".join(bytes([i]) for i in range(16))
|
||||||
|
result_of(
|
||||||
|
im_client.create(
|
||||||
|
storage_index, {1, 2, 3}, 10, upload_secret, lease_secret, lease_secret
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initially there are no shares:
|
||||||
|
self.assertEqual(result_of(im_client.list_shares(storage_index)), set())
|
||||||
|
|
||||||
|
# Upload shares 1 and 3:
|
||||||
|
for share_number in [1, 3]:
|
||||||
|
progress = result_of(im_client.write_share_chunk(
|
||||||
|
storage_index,
|
||||||
|
share_number,
|
||||||
|
upload_secret,
|
||||||
|
0,
|
||||||
|
b"0123456789",
|
||||||
|
))
|
||||||
|
self.assertTrue(progress.finished)
|
||||||
|
|
||||||
|
# Now shares 1 and 3 exist:
|
||||||
|
self.assertEqual(result_of(im_client.list_shares(storage_index)), {1, 3})
|
||||||
|
|
||||||
def test_multiple_shares_uploaded_to_different_place(self):
|
def test_multiple_shares_uploaded_to_different_place(self):
|
||||||
"""
|
"""
|
||||||
If a storage index has multiple shares, uploads to different shares are
|
If a storage index has multiple shares, uploads to different shares are
|
||||||
|
Loading…
Reference in New Issue
Block a user