Skip to content

Commit

Permalink
feat(deployment): supports deleting multiple deployments
Browse files Browse the repository at this point in the history
This commit introduces the support for deleting one or more deployments
either by name or a regex.
  • Loading branch information
pallabpain committed Jan 24, 2024
1 parent 911c22d commit 2dd2789
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 43 deletions.
101 changes: 84 additions & 17 deletions riocli/deployment/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@
# 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 functools
from concurrent.futures import ThreadPoolExecutor
from queue import Queue

import click
from click_help_colors import HelpColorsCommand
from rapyuta_io.clients.deployment import Deployment

from riocli.config import new_client
from riocli.constants import Colors, Symbols
from riocli.deployment.util import name_to_guid
from riocli.deployment.util import fetch_deployments
from riocli.deployment.util import print_deployments_for_confirmation
from riocli.utils import tabulate_data
from riocli.utils.spinner import with_spinner


Expand All @@ -28,33 +35,93 @@
)
@click.option('--force', '-f', '--silent', is_flag=True, default=False,
help='Skip confirmation')
@click.argument('deployment-name', type=str)
@name_to_guid
@click.option('--all', 'delete_all', is_flag=True, default=False,
help='Deletes all deployments in the project')
@click.option('--workers', '-w',
help="Number of parallel workers while running delete deployment "
"command. Defaults to 10.", type=int, default=10)
@click.argument('deployment-name-or-regex', type=str, default="")
@with_spinner(text="Deleting deployment...")
def delete_deployment(
force: bool,
deployment_name: str,
deployment_guid: str,
deployment_name_or_regex: str,
delete_all: bool = False,
workers: int = 10,
spinner=None,
) -> None:
"""
Deletes a deployment
Deletes one or more deployments given a name or a pattern
"""
client = new_client()

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

try:
deployments = fetch_deployments(
client, deployment_name_or_regex, delete_all)
except Exception as e:
spinner.text = click.style(
'Failed to delete deployment(s): {}'.format(e), Colors.RED)
spinner.red.fail(Symbols.ERROR)
raise SystemExit(1) from e

if not deployments:
spinner.text = "Nothing to delete"
spinner.ok(Symbols.SUCCESS)
return

with spinner.hidden():
if not force:
click.confirm(
'Deleting {} ({}) deployment'.format(
deployment_name, deployment_guid), abort=True)
print_deployments_for_confirmation(deployments)

spinner.write('')

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

try:
client = new_client()
deployment = client.get_deployment(deployment_guid)
deployment.deprovision()
result = Queue()
func = functools.partial(_apply_delete, result)
with ThreadPoolExecutor(max_workers=workers) as executor:
executor.map(func, deployments)

result = sorted(list(result.queue), 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
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.write('')
spinner.text = click.style(
'Deployment deleted successfully.', fg=Colors.GREEN)
spinner.green.ok(Symbols.SUCCESS)
'Deployment(s) deleted {}.'.format(text), fg)
spinner.ok(click.style(icon, fg))
except Exception as e:
spinner.text = click.style(
'Failed to delete deployment: {}'.format(e), Colors.RED)
'Failed to delete deployment(s): {}'.format(e), Colors.RED)
spinner.red.fail(Symbols.ERROR)
raise SystemExit(1)
raise SystemExit(1) from e


def _apply_delete(result: Queue, deployment: Deployment) -> None:
try:
deployment.deprovision()
result.put((deployment.name, True))
except Exception:
result.put((deployment.name, False))
29 changes: 4 additions & 25 deletions riocli/deployment/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@
# limitations under the License.

import functools
import re
from concurrent.futures import ThreadPoolExecutor
from queue import Queue
from typing import List

import click
from click_help_colors import HelpColorsCommand
from rapyuta_io import Client, DeploymentPhaseConstants
from rapyuta_io import Client
from rapyuta_io.clients.deployment import Deployment
from yaspin.api import Yaspin

from riocli.config import new_client
from riocli.constants import Symbols, Colors
from riocli.deployment.util import fetch_deployments
from riocli.deployment.util import print_deployments_for_confirmation
from riocli.utils import tabulate_data
from riocli.utils.spinner import with_spinner

Expand Down Expand Up @@ -75,11 +75,8 @@ def update_deployment(
spinner.ok(Symbols.SUCCESS)
return

headers = ['Name', 'GUID', 'Phase', 'Status']
data = [[d.name, d.deploymentId, d.phase, d.status] for d in deployments]

with spinner.hidden():
tabulate_data(data, headers)
print_deployments_for_confirmation(deployments)

spinner.write('')

Expand Down Expand Up @@ -125,24 +122,6 @@ def update_deployment(
raise SystemExit(1) from e


def fetch_deployments(
client: Client,
deployment_name_or_regex: str,
update_all: bool,
) -> List[Deployment]:
deployments = client.get_all_deployments(
phases=[DeploymentPhaseConstants.SUCCEEDED,
DeploymentPhaseConstants.PROVISIONING])
result = []
for deployment in deployments:
if (update_all or deployment.name == deployment_name_or_regex or
(deployment_name_or_regex not in deployment.name and
re.search(deployment_name_or_regex, deployment.name))):
result.append(deployment)

return result


def get_component_context(component_info) -> dict:
result = {}

Expand Down
31 changes: 30 additions & 1 deletion riocli/deployment/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2021 Rapyuta Robotics
# Copyright 2023 Rapyuta Robotics
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -13,17 +13,21 @@
# limitations under the License.
import copy
import functools
import re
import typing
from typing import List

import click
from rapyuta_io import Client, DeploymentPhaseConstants
from rapyuta_io.clients import Device
from rapyuta_io.clients.deployment import Deployment
from rapyuta_io.clients.package import ExecutableMount
from rapyuta_io.utils import InvalidParameterException, OperationNotAllowedError
from rapyuta_io.utils.constants import DEVICE_ID

from riocli.config import new_client
from riocli.constants import Colors
from riocli.utils import tabulate_data
from riocli.utils.selector import show_selection


Expand Down Expand Up @@ -155,3 +159,28 @@ def add_mount_volume_provision_config(provision_config, component_name, device,
provision_config.context['diskMountInfo'].append(tmp_info)

return provision_config


def fetch_deployments(
client: Client,
deployment_name_or_regex: str,
include_all: bool,
) -> List[Deployment]:
deployments = client.get_all_deployments(
phases=[DeploymentPhaseConstants.SUCCEEDED,
DeploymentPhaseConstants.PROVISIONING])
result = []
for deployment in deployments:
if (include_all or
deployment_name_or_regex == deployment.deploymentId or
re.search(deployment_name_or_regex, deployment.name)):
result.append(deployment)

return result


def print_deployments_for_confirmation(deployments: List[Deployment]):
headers = ['Name', 'GUID', 'Phase', 'Status']
data = [[d.name, d.deploymentId, d.phase, d.status] for d in deployments]

tabulate_data(data, headers)

0 comments on commit 2dd2789

Please sign in to comment.