Skip to content

Commit

Permalink
Allow to make buckets public (#2306)
Browse files Browse the repository at this point in the history
* WIP

* Add way to make bucket public

* Update .ref files

* Add changelog
  • Loading branch information
romasku authored Sep 14, 2021
1 parent 7646f40 commit cd7cbe3
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.D/2306.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added command `neuro blob set-bucket-publicity <bucket> <"public"|"private">` to make bucket accessible for unauthorized
users.
35 changes: 33 additions & 2 deletions neuro-cli/src/neuro_cli/blob_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ async def statbucket(
@argument("buckets", type=BUCKET, nargs=-1, required=True)
async def rmbucket(root: Root, cluster: Optional[str], buckets: Sequence[str]) -> None:
"""
Remove bucket DISK_ID.
Remove bucket BUCKET_ID.
"""
for bucket in buckets:
bucket_id = await resolve_bucket(
Expand All @@ -360,6 +360,37 @@ async def rmbucket(root: Root, cluster: Optional[str], buckets: Sequence[str]) -
root.print(f"Bucket with id '{bucket_id}' was successfully removed.")


@command()
@option(
"--cluster",
type=CLUSTER,
help="Perform on a specified cluster (the current cluster by default).",
)
@argument("bucket", type=BUCKET, required=True)
@argument(
"public_level",
type=click.Choice(["public", "private"], case_sensitive=False),
required=True,
)
async def set_bucket_publicity(
root: Root, cluster: Optional[str], bucket: str, public_level: str
) -> None:
"""
Change public access settings for bucket BUCKET.
Examples:
neuro blob set-bucket-publicity my-bucket public
neuro blob set-bucket-publicity my-bucket private
"""
public = public_level == "public"
await root.client.buckets.set_public_access(bucket, public, cluster_name=cluster)
if root.verbosity >= 0:
root.print(
f"Bucket '{bucket}' was made {'public' if public else 'non-public'}."
)


# Object level commands


Expand Down Expand Up @@ -958,7 +989,7 @@ async def rmcredentials(
blob_storage.add_command(importbucket)
blob_storage.add_command(statbucket)
blob_storage.add_command(rmbucket)

blob_storage.add_command(set_bucket_publicity)

blob_storage.add_command(lscredentials)
blob_storage.add_command(mkcredentials)
Expand Down
7 changes: 6 additions & 1 deletion neuro-cli/src/neuro_cli/formatters/buckets.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ def _bucket_to_table_row(self, bucket: Bucket) -> Sequence[str]:
self._uri_formatter(bucket.uri),
]
if self._long_format:
line += [self._datetime_formatter(bucket.created_at)]
line += [
self._datetime_formatter(bucket.created_at),
"√" if bucket.public else "×",
]
return line

def __call__(self, buckets: Sequence[Bucket]) -> RenderableType:
Expand All @@ -57,6 +60,7 @@ def __call__(self, buckets: Sequence[Bucket]) -> RenderableType:
table.add_column("Uri")
if self._long_format:
table.add_column("Created at")
table.add_column("Public")
for bucket in buckets:
table.add_row(*self._bucket_to_table_row(bucket))
return table
Expand Down Expand Up @@ -84,4 +88,5 @@ def __call__(self, bucket: Bucket) -> RenderableType:
table.add_row("Created at", self._datetime_formatter(bucket.created_at))
table.add_row("Provider", bucket.provider)
table.add_row("Imported", str(bucket.imported))
table.add_row("Public", str(bucket.public))
return table
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ Id bucket
Name test-bucket
Created at Mar 04 2017
Provider aws
Imported False
Imported False
Public False
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Id Name Provider Uri Created at
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
bucket-1 test-bucket aws blob://cluster/user/test-bucket Mar 04 2017
bucket-2 test-bucket-2 aws blob://cluster/user/test-bucket-2 Mar 04 2016
bucket-3 aws blob://cluster/user-2/bucket-3 Mar 04 2018
bucket-4 aws blob://cluster/user/bucket-4 Mar 04 2019
Id Name Provider Uri Created at Public
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
bucket-1 test-bucket aws blob://cluster/user/test-bucket Mar 04 2017 ×
bucket-2 test-bucket-2 aws blob://cluster/user/test-bucket-2 Mar 04 2016 ×
bucket-3 aws blob://cluster/user-2/bucket-3 Mar 04 2018 ×
bucket-4 aws blob://cluster/user/bucket-4 Mar 04 2019
1 change: 1 addition & 0 deletions neuro-cli/tests/unit/formatters/test_buckets.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def buckets_list() -> List[Bucket]:
created_at=isoparse("2019-03-04T12:28:59.759433+00:00"),
provider=Bucket.Provider.AWS,
imported=False,
public=True,
),
]

Expand Down
12 changes: 12 additions & 0 deletions neuro-sdk/docs/buckets_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ Buckets

:return: Bucket credentials info (:class:`BucketCredentials`)

.. comethod:: set_public_access(bucket_id_or_name: str, public_access: bool, cluster_name: Optional[str] = None) -> Bucket

Enable or disable public (anonymous) read access to bucket.

:param str bucket_id_or_name: bucket's id or name.

:param str public_access: New public access setting.

:param str cluster_name: cluster to look for a bucket. Default is current cluster.

:return: Bucket info (:class:`Bucket`)

.. comethod:: head_blob(bucket_id_or_name: str, key: str, cluster_name: Optional[str] = None) -> BucketEntry

Look up the blob and return it's metadata.
Expand Down
17 changes: 17 additions & 0 deletions neuro-sdk/src/neuro_sdk/buckets.py
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,7 @@ class Bucket:
provider: "Bucket.Provider"
created_at: datetime
imported: bool
public: bool = False
name: Optional[str] = None

@property
Expand Down Expand Up @@ -1024,6 +1025,7 @@ def _parse_bucket_payload(self, payload: Mapping[str, Any]) -> Bucket:
created_at=isoparse(payload["created_at"]),
provider=Bucket.Provider(payload["provider"]),
imported=payload.get("imported", False),
public=payload.get("public", False),
cluster_name=self._config.cluster_name,
)

Expand Down Expand Up @@ -1109,6 +1111,21 @@ async def rm(
async with self._core.request("DELETE", url, auth=auth):
pass

async def set_public_access(
self,
bucket_id_or_name: str,
public_access: bool,
cluster_name: Optional[str] = None,
) -> Bucket:
url = self._get_buckets_url(cluster_name) / bucket_id_or_name
auth = await self._config._api_auth()
data = {
"public": public_access,
}
async with self._core.request("PATCH", url, auth=auth, json=data) as resp:
payload = await resp.json()
return self._parse_bucket_payload(payload)

async def request_tmp_credentials(
self, bucket_id_or_name: str, cluster_name: Optional[str] = None
) -> BucketCredentials:
Expand Down
32 changes: 32 additions & 0 deletions neuro-sdk/tests/test_buckets.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,38 @@ async def handler(request: web.Request) -> web.Response:
)


async def test_set_public(
aiohttp_server: _TestServerFactory,
make_client: _MakeClient,
cluster_config: Cluster,
) -> None:
created_at = datetime.now()

async def handler(request: web.Request) -> web.Response:
assert request.match_info["key"] == "name"
data = await request.json()
assert data == {"public": True}
return web.json_response(
{
"id": "bucket-1",
"owner": "user",
"name": "name",
"provider": "aws",
"created_at": created_at.isoformat(),
"public": True,
}
)

app = web.Application()
app.router.add_patch("/buckets/buckets/{key}", handler)

srv = await aiohttp_server(app)

async with make_client(srv.make_url("/")) as client:
bucket = await client.buckets.set_public_access("name", True)
assert bucket.public


async def test_rm(aiohttp_server: _TestServerFactory, make_client: _MakeClient) -> None:
async def handler(request: web.Request) -> web.Response:
assert request.match_info["key"] == "name"
Expand Down

0 comments on commit cd7cbe3

Please sign in to comment.