Skip to content

Commit

Permalink
feat(disks): use v2 APIs for Disk operations
Browse files Browse the repository at this point in the history
  • Loading branch information
ankitrgadiya authored and pallabpain committed Sep 4, 2024
1 parent 9bd00c6 commit 3ddb694
Show file tree
Hide file tree
Showing 9 changed files with 588 additions and 208 deletions.
18 changes: 2 additions & 16 deletions riocli/apply/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def _guid_functor(self, kind):
"deployment": lambda x: munchify(x)['deploymentId'],
"network": lambda x: munchify(x).guid,
# This is only temporarily like this
"disk": lambda x: munchify(x)['internalDeploymentGUID'],
"disk": lambda x: munchify(x)['metadata']['guid'],
"device": lambda x: munchify(x)['uuid'],
"managedservice": lambda x: munchify(x)['metadata']['name'],
"usergroup": lambda x: munchify(x).guid
Expand All @@ -140,7 +140,7 @@ def _list_functors(self, kind):
phases=[DeploymentPhaseConstants.SUCCEEDED,
DeploymentPhaseConstants.PROVISIONING]),
"network": self._list_networks,
"disk": self._list_disks,
"disk": self.v2client.list_disks,
"device": self.client.get_all_devices,
"managedservice": self._list_managedservices,
"usergroup": self.client.list_usergroups
Expand Down Expand Up @@ -182,20 +182,6 @@ def _list_networks(self):

return networks

def _list_disks(self):
config = Configuration()
catalog_host = config.data.get(
'catalog_host', 'https://gacatalog.apps.okd4v2.prod.rapyuta.io')
url = '{}/disk'.format(catalog_host)
headers = config.get_auth_header()
response = RestClient(url).method(
HttpMethod.GET).headers(headers).execute()
data = json.loads(response.text)
if not response.ok:
err_msg = data.get('error')
raise Exception(err_msg)
return munchify(data)

def _list_managedservices(self):
instances = ManagedService.list_instances()
return munchify(instances)
Expand Down
3 changes: 2 additions & 1 deletion riocli/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@

from riocli.constants.colors import Colors
from riocli.constants.symbols import Symbols
from riocli.constants.regions import Regions

__all__ = [Colors, Symbols]
__all__ = [Colors, Symbols, Regions]
17 changes: 17 additions & 0 deletions riocli/constants/regions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 Rapyuta Robotics
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

class Regions:
JP = 'jp'
US = 'us'
37 changes: 31 additions & 6 deletions riocli/disk/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import click
import time

from click_help_colors import HelpColorsCommand
from rapyuta_io.clients.persistent_volumes import DiskCapacity

from riocli.constants import Colors, Symbols
from riocli.disk.util import create_cloud_disk
from riocli.constants import Colors, Symbols, Regions
from riocli.disk.util import is_disk_ready
from riocli.utils.spinner import with_spinner
from riocli.config import new_v2_client

SUPPORTED_CAPACITIES = [
DiskCapacity.GiB_4.value,
Expand All @@ -30,6 +33,10 @@
DiskCapacity.GiB_512.value,
]

SUPPORTED_REGIONS = [
Regions.JP,
Regions.US,
]

@click.command(
'create',
Expand All @@ -40,21 +47,39 @@
@click.argument('disk-name', type=str)
@click.option('--capacity', 'capacity', type=click.Choice(SUPPORTED_CAPACITIES),
default=DiskCapacity.GiB_4.value, help='Disk size in GiB')
@click.option('--region', 'region', type=click.Choice(SUPPORTED_REGIONS),
default=Regions.JP, help='Region to create the disk in')

@with_spinner(text="Creating a new disk...")
def create_disk(
disk_name: str,
capacity: int = 4,
region: str = 'jp',
spinner=None,
) -> None:
"""
Creates a new disk
"""
try:
disk = create_cloud_disk(disk_name, capacity)

client = new_v2_client()
payload = {
"metadata": {
"name": disk_name,
"region": region
},
"spec": {
"capacity": capacity,
"runtime": "cloud"
}
}

client.create_disk(payload)
while not is_disk_ready(client, disk_name):
time.sleep(3)

spinner.text = click.style(
'Disk {} ({}) created successfully.'.
format(disk['name'], disk['guid']), fg=Colors.GREEN)
'Disk {} created successfully.'.
format(disk_name), fg=Colors.GREEN)
spinner.green.ok(Symbols.SUCCESS)
except Exception as e:
spinner.text = click.style('Failed to create disk: {}'.format(e), fg=Colors.RED)
Expand Down
103 changes: 85 additions & 18 deletions riocli/disk/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,27 @@
import click
from click_help_colors import HelpColorsCommand
from rapyuta_io.utils.rest_client import HttpMethod
from yaspin.api import Yaspin
from queue import Queue
import functools

from riocli.config import new_v2_client
from riocli.constants import Symbols, Colors
from riocli.disk.util import name_to_guid, _api_call
from riocli.disk.model import Disk
from riocli.disk.util import fetch_disks, display_disk_list
from riocli.utils.spinner import with_spinner
from riocli.utils.execute import apply_func_with_result
from riocli.utils import tabulate_data

from rapyuta_io import Client


def _apply_delete(client: Client, result: Queue, disk: Disk) -> None:
try:
client.delete_disk(name = disk.metadata.name)
result.put((disk.metadata.name, True))
except Exception as e:
result.put((disk.metadata.name, False))


@click.command(
Expand All @@ -26,31 +43,81 @@
help_headers_color=Colors.YELLOW,
help_options_color=Colors.GREEN,
)
@click.option('--force', '-f', 'force', is_flag=True, default=False,
help='Skip confirmation')
@click.argument('disk-name', required=True, type=str)
@name_to_guid
@with_spinner(text="Deleting disk...")
@click.option('--force', '-f', is_flag=True, default=False,
help='Skip confirmation', type=bool)
@click.option('--workers', '-w',
help="Number of parallel workers while running deleting disks. Defaults to 10",
type=int, default=10)
@click.argument('disk-name-or-regex', type=str)
@with_spinner(text='Deleting disk...')
def delete_disk(
disk_name: str,
disk_guid: str,
force: bool,
spinner=None
disk_name_or_regex: str,
delete_all: bool = False,
workers: int = 10,
spinner: Yaspin = None
) -> None:
"""
Delete a disk
Deletes a disk
"""
client = new_v2_client()

if not (disk_name_or_regex or delete_all):
spinner.text = "Nothing to delete"
spinner.green.ok(Symbols.SUCCESS)
return

try:
disks = fetch_disks(client, disk_name_or_regex, delete_all)
except Exception as e:
spinner.text = click.style(
'Failed to find disk(s): {}'.format(e), Colors.RED)
spinner.red.fail(Symbols.ERROR)
raise SystemExit(1) from e

if not disks:
spinner.text = click.style("Disk(s) not found", Colors.RED)
spinner.red.fail(Symbols.ERROR)
raise SystemExit(1)

with spinner.hidden():
if not force:
click.confirm(
'Deleting disk {} ({})'.format(disk_name, disk_guid), abort=True)
display_disk_list(disks)

spinner.write('')

if not force:
with spinner.hidden():
click.confirm('Do you want to delete the above disk(s)?', default=True, abort=True)

try:
_api_call(HttpMethod.DELETE, guid=disk_guid, load_response=False)
f = functools.partial(_apply_delete, client)
result = apply_func_with_result(
f=f, items=disks,
workers=workers, key=lambda x: x[0]
)
data, statuses = [], []
for name, status in result:
fg = Colors.GREEN if status else Colors.RED
icon = Symbols.SUCCESS if status else Symbols.ERROR

spinner.text = click.style('Disk deleted successfully.', fg=Colors.GREEN)
spinner.green.ok(Symbols.SUCCESS)
statuses.append(status)
data.append([
click.style(name, fg),
click.style(icon, fg)
])

with spinner.hidden():
tabulate_data(data, headers=['Name', 'Status'])

icon = Symbols.SUCCESS if all(statuses) else Symbols.WARNING
fg = Colors.GREEN if all(statuses) else Colors.YELLOW
text = "successfully" if all(statuses) else "partially"

spinner.text = click.style(
'Disk(s) deleted {}.'.format(text), fg)
spinner.ok(click.style(icon, fg))
except Exception as e:
spinner.text = click.style('Failed to delete disk: {}'.format(str(e)), fg=Colors.RED)
spinner.text = click.style(
'Failed to delete disk(s): {}'.format(e), Colors.RED)
spinner.red.fail(Symbols.ERROR)
raise SystemExit(1)
raise SystemExit(1) from e
36 changes: 6 additions & 30 deletions riocli/disk/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,21 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import typing

import click
from rapyuta_io.utils.rest_client import HttpMethod

from riocli.constants import Colors
from riocli.disk.util import _api_call
from riocli.utils import tabulate_data

from riocli.config import new_v2_client
from riocli.disk.util import display_disk_list

@click.command('list')
def list_disks() -> None:
"""
List the disks in the selected project
"""
try:
disks = _api_call(HttpMethod.GET)
disks = sorted(disks, key=lambda d: d['name'].lower())
_display_disk_list(disks, show_header=True)
client = new_v2_client(with_project=True)
disks = client.list_disks()
display_disk_list(disks, show_header=True)
except Exception as e:
click.secho(str(e), fg=Colors.RED)
raise SystemExit(1)


def _display_disk_list(disks: typing.Any, show_header: bool = True):
headers = []
if show_header:
headers = (
'Disk ID', 'Name', 'Status', 'Capacity',
'Used', 'Available', 'Used By',
)

data = [[d['guid'],
d['name'],
d['status'],
d['capacity'],
d.get('used', 'NA'),
d.get('available', 'NA'),
d['usedBy']]
for d in disks]

tabulate_data(data, headers)
raise SystemExit(1)
Loading

0 comments on commit 3ddb694

Please sign in to comment.