Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to make buckets public #2306

Merged
merged 4 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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