Implement HTTP share listing endpoint.

This commit is contained in:
Itamar Turner-Trauring 2022-02-01 10:20:23 -05:00
parent 26f6d0036c
commit c72e7b0585
4 changed files with 72 additions and 8 deletions

View File

@ -630,8 +630,8 @@ Reading
``GET /v1/immutable/:storage_index/shares``
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Retrieve a list indicating all shares available for the indicated storage index.
For example::
Retrieve a list (semantically, a set) indicating all shares available for the
indicated storage index. For example::
[1, 5]

View File

@ -136,6 +136,7 @@ class UploadProgress(object):
"""
Progress of immutable upload, per the server.
"""
# True when upload has finished.
finished = attr.ib(type=bool)
# Remaining ranges to upload.
@ -221,7 +222,7 @@ class StorageClientImmutables(object):
headers=Headers(
{
"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",
url,
headers=Headers(
{
"range": [
Range("bytes", [(offset, offset + length)]).to_header()
]
}
{"range": [Range("bytes", [(offset, offset + length)]).to_header()]}
),
)
if response.code == http.PARTIAL_CONTENT:
@ -282,3 +279,23 @@ class StorageClientImmutables(object):
raise ClientException(
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,
)

View File

@ -255,6 +255,22 @@ class HTTPServer(object):
required.append({"begin": start, "end": end})
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(
_app,
set(),

View File

@ -382,6 +382,37 @@ class ImmutableHTTPAPITests(SyncTestCase):
)
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):
"""
If a storage index has multiple shares, uploads to different shares are