Skip to content

Commit

Permalink
Add cli commands for disk management
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Skurikhin committed Sep 3, 2020
1 parent 3948994 commit c476e5d
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 5 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.D/1716.feature
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Added persistent disks management subsystem to api.
Implemented disks management commands.
125 changes: 123 additions & 2 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
* [neuro secret ls](#neuro-secret-ls)
* [neuro secret add](#neuro-secret-add)
* [neuro secret rm](#neuro-secret-rm)
* [neuro disk](#neuro-disk)
* [neuro disk ls](#neuro-disk-ls)
* [neuro disk create](#neuro-disk-create)
* [neuro disk get](#neuro-disk-get)
* [neuro disk rm](#neuro-disk-rm)
* [neuro help](#neuro-help)
* [neuro run](#neuro-run)
* [neuro ps](#neuro-ps)
Expand Down Expand Up @@ -132,6 +137,7 @@ Name | Description|
| _[neuro acl](#neuro-acl)_| Access Control List management |
| _[neuro blob](#neuro-blob)_| Blob storage operations |
| _[neuro secret](#neuro-secret)_| Operations with secrets |
| _[neuro disk](#neuro-disk)_| Operations with disks |


**Commands:**
Expand Down Expand Up @@ -1808,7 +1814,7 @@ Name | Description|
|---|---|
| _[neuro secret ls](#neuro-secret-ls)_| List secrets |
| _[neuro secret add](#neuro-secret-add)_| Add secret KEY with data VALUE |
| _[neuro secret rm](#neuro-secret-rm)_| Add secret KEY |
| _[neuro secret rm](#neuro-secret-rm)_| Remove secret KEY |



Expand Down Expand Up @@ -1862,7 +1868,7 @@ Name | Description|

### neuro secret rm

Add secret KEY.
Remove secret KEY.

**Usage:**

Expand All @@ -1879,6 +1885,121 @@ Name | Description|



## neuro disk

Operations with disks.

**Usage:**

```bash
neuro disk [OPTIONS] COMMAND [ARGS]...
```

**Options:**

Name | Description|
|----|------------|
|_--help_|Show this message and exit.|


**Commands:**

|Usage|Description|
|---|---|
| _[neuro disk ls](#neuro-disk-ls)_| List disks |
| _[neuro disk create](#neuro-disk-create)_| Create disk with storage amount STORAGE |
| _[neuro disk get](#neuro-disk-get)_| Get disk DISK_ID |
| _[neuro disk rm](#neuro-disk-rm)_| Remove disk DISK_ID |




### neuro disk ls

List disks.

**Usage:**

```bash
neuro disk ls [OPTIONS]
```

**Options:**

Name | Description|
|----|------------|
|_--help_|Show this message and exit.|
|_\--full-uri_|Output full disk URI.|




### neuro disk create

Create disk with storage amount STORAGE.<br/>

**Usage:**

```bash
neuro disk create [OPTIONS] STORAGE
```

**Examples:**

```bash

neuro disk create 10Gi
neuro disk create 500Mi

```

**Options:**

Name | Description|
|----|------------|
|_--help_|Show this message and exit.|




### neuro disk get

Get disk DISK_ID.

**Usage:**

```bash
neuro disk get [OPTIONS] DISK_ID
```

**Options:**

Name | Description|
|----|------------|
|_--help_|Show this message and exit.|




### neuro disk rm

Remove disk DISK_ID.

**Usage:**

```bash
neuro disk rm [OPTIONS] DISK_ID
```

**Options:**

Name | Description|
|----|------------|
|_--help_|Show this message and exit.|




## neuro help

Get help on a command.
Expand Down
77 changes: 77 additions & 0 deletions neuromation/cli/disks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from .formatters.disks import DiskFormatter, DisksFormatter
from .formatters.utils import URIFormatter, uri_formatter
from .parse_utils import parse_memory
from .root import Root
from .utils import argument, command, group, option, pager_maybe


@group()
def disk() -> None:
"""
Operations with disks.
"""


@command()
@option("--full-uri", is_flag=True, help="Output full disk URI.")
async def ls(root: Root, full_uri: bool) -> None:
"""
List disks.
"""

if full_uri:
uri_fmtr: URIFormatter = str
else:
uri_fmtr = uri_formatter(
username=root.client.username, cluster_name=root.client.cluster_name
)
disks_fmtr = DisksFormatter(uri_fmtr)

disks = []
async for disk in root.client.disks.list():
disks.append(disk)

pager_maybe(disks_fmtr(disks), root.tty, root.terminal_size)


@command()
@argument("storage")
async def create(root: Root, storage: str) -> None:
"""
Create disk with storage amount STORAGE.
Examples:
neuro disk create 10Gi
neuro disk create 500Mi
"""
disk = await root.client.disks.create(parse_memory(storage))
disk_fmtr = DiskFormatter(str)
pager_maybe(disk_fmtr(disk), root.tty, root.terminal_size)


@command()
@argument("disk_id")
async def get(root: Root, disk_id: str) -> None:
"""
Get disk DISK_ID.
"""
disk = await root.client.disks.get(disk_id)
disk_fmtr = DiskFormatter(str)
pager_maybe(disk_fmtr(disk), root.tty, root.terminal_size)


@command()
@argument("disk_id")
async def rm(root: Root, disk_id: str) -> None:
"""
Remove disk DISK_ID.
"""

await root.client.disks.rm(disk_id)


disk.add_command(ls)
disk.add_command(create)
disk.add_command(get)
disk.add_command(rm)
44 changes: 44 additions & 0 deletions neuromation/cli/formatters/disks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import Iterator, Sequence

import click

from neuromation.api import Disk
from neuromation.cli.formatters.ftable import table
from neuromation.cli.formatters.utils import URIFormatter


class DisksFormatter:
_table_header = [
click.style("Id", bold=True),
click.style("Storage", bold=True),
click.style("Uri", bold=True),
]

def __init__(self, uri_formatter: URIFormatter):
self._uri_formatter = uri_formatter

def _disk_to_table_row(self, disk: Disk) -> Sequence[str]:
if disk.storage >= 1024 ** 3:
storage_str = f"{disk.storage / (1024 ** 3):.2f}Gi"
elif disk.storage >= 1024 ** 2:
storage_str = f"{disk.storage / (1024 ** 2):.2f}Mi"
elif disk.storage >= 1024:
storage_str = f"{disk.storage / 1024:.2f}Ki"
else:
storage_str = str(disk.storage)
return [disk.id, storage_str, self._uri_formatter(disk.uri)]

def __call__(self, disks: Sequence[Disk]) -> Iterator[str]:
disks_info = [
self._table_header,
*(self._disk_to_table_row(disk) for disk in disks),
]
return table(disks_info)


class DiskFormatter:
def __init__(self, uri_formatter: URIFormatter):
self._disks_formatter = DisksFormatter(uri_formatter)

def __call__(self, disk: Disk) -> Iterator[str]:
return self._disks_formatter([disk])
3 changes: 2 additions & 1 deletion neuromation/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
blob_storage,
completion,
config,
disks,
image,
job,
project,
Expand Down Expand Up @@ -483,8 +484,8 @@ def help(ctx: click.Context, command: Sequence[str]) -> None:
cli.add_command(completion.completion)
cli.add_command(share.acl)
cli.add_command(blob_storage.blob_storage)
cli.add_command(blob_storage.blob_storage)
cli.add_command(secrets.secret)
cli.add_command(disks.disk)

cli.add_command(DeprecatedGroup(storage.storage, name="store", hidden=True))

Expand Down
2 changes: 1 addition & 1 deletion neuromation/cli/secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def add(root: Root, key: str, value: str) -> None:
@argument("key")
async def rm(root: Root, key: str) -> None:
"""
Add secret KEY.
Remove secret KEY.
"""

await root.client.secrets.rm(key)
Expand Down
28 changes: 28 additions & 0 deletions tests/cli/formatters/test_disks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import click

from neuromation.api import Disk
from neuromation.cli.formatters.disks import DiskFormatter, DisksFormatter


def test_disk_formatter() -> None:
disk = Disk("disk", int(11.93 * (1024 ** 3)), "user", Disk.Status.READY, "cluster")
fmtr = DiskFormatter(str)
header_line, info_line = (click.unstyle(line).rstrip() for line in fmtr(disk))
assert header_line.split() == ["Id", "Storage", "Uri"]
assert info_line.split() == ["disk", "11.93Gi", "disk://cluster/user/disk-id"]


def test_disks_formatter() -> None:
disks = [
Disk("disk-1", 50 * (1024 ** 3), "user", Disk.Status.READY, "cluster"),
Disk("disk-2", 50 * (1024 ** 2), "user", Disk.Status.READY, "cluster"),
Disk("disk-3", 50 * (1024 ** 1), "user", Disk.Status.READY, "cluster"),
Disk("disk-4", 50, "user", Disk.Status.READY, "cluster"),
]
fmtr = DisksFormatter(str)
header_line, *info_lines = (click.unstyle(line).rstrip() for line in fmtr(disks))
assert header_line.split() == ["Id", "Storage", "Uri"]
assert info_lines[0].split() == ["disk-1", "50.00Gi", "disk://cluster/user/disk-1"]
assert info_lines[1].split() == ["disk-2", "50.00Mi", "disk://cluster/user/disk-2"]
assert info_lines[2].split() == ["disk-3", "50.00Ki", "disk://cluster/user/disk-3"]
assert info_lines[3].split() == ["disk-4", "50", "disk://cluster/user/disk-4"]
29 changes: 29 additions & 0 deletions tests/e2e/test_e2e_disks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pytest

from tests.e2e.conftest import Helper


@pytest.mark.e2e
def test_create_get_list_delete(helper: Helper) -> None:
cap = helper.run_cli(["disk", "ls"])
assert cap.err == ""

cap = helper.run_cli(["disk", "create", "2Gi"])
assert cap.err == ""
disk_id, *_ = cap.out.splitlines()[1].split()

cap = helper.run_cli(["disk", "ls"])
assert cap.err == ""
assert disk_id in cap.out

cap = helper.run_cli(["disk", "get", disk_id])
assert cap.err == ""
assert disk_id in cap.out
assert "2Gi" in cap.out

cap = helper.run_cli(["disk", "rm", disk_id])
assert cap.err == ""

cap = helper.run_cli(["disk", "ls"])
assert cap.err == ""
assert disk_id not in cap.out

0 comments on commit c476e5d

Please sign in to comment.