From 487705dc54de4759b0843223bd6a032e2b4903ee Mon Sep 17 00:00:00 2001 From: Pallab Pain Date: Thu, 22 Aug 2024 15:18:56 +0530 Subject: [PATCH] refactor(apply): prints specific status messages --- riocli/apply/parse.py | 29 ++++++++++++++++++++--------- riocli/constants/__init__.py | 6 +++--- riocli/constants/status.py | 24 ++++++++++++++++++++++++ riocli/deployment/model.py | 7 ++++--- riocli/device/model.py | 13 ++++++++++--- riocli/disk/model.py | 6 ++++-- riocli/managedservice/model.py | 6 ++++-- riocli/model/base.py | 3 ++- riocli/network/model.py | 4 +++- riocli/package/model.py | 6 ++++-- riocli/project/model.py | 6 ++++-- riocli/secret/model.py | 3 +++ riocli/static_route/model.py | 5 ++++- riocli/usergroup/model.py | 6 ++++-- 14 files changed, 93 insertions(+), 31 deletions(-) diff --git a/riocli/apply/parse.py b/riocli/apply/parse.py index 8b614395..c39dbf3c 100644 --- a/riocli/apply/parse.py +++ b/riocli/apply/parse.py @@ -23,7 +23,7 @@ from riocli.apply.util import (get_model, init_jinja_environment, message_with_prompt, print_resolved_objects) from riocli.config import Configuration -from riocli.constants import Colors, Symbols +from riocli.constants import Colors, Symbols, ApplyResult from riocli.exceptions import ResourceNotFound from riocli.utils import dump_all_yaml, print_centered_text, run_bash from riocli.utils.graph import Graphviz @@ -81,10 +81,10 @@ def apply(self, *args, **kwargs): try: apply_func(*args, **kwargs) - spinner.text = 'Apply successful.' + spinner.text = click.style('Apply successful.', fg=Colors.BRIGHT_GREEN) spinner.green.ok(Symbols.SUCCESS) except Exception as e: - spinner.text = 'Apply failed. Error: {}'.format(e) + spinner.text = click.style('Apply failed. Error: {}'.format(e), fg=Colors.BRIGHT_RED) spinner.red.fail(Symbols.ERROR) raise SystemExit(1) from e @@ -135,10 +135,10 @@ def delete(self, *args, **kwargs): try: delete_func(*args, **kwargs) - spinner.text = 'Delete successful.' + spinner.text = click.style('Delete successful.', fg=Colors.BRIGHT_GREEN) spinner.green.ok(Symbols.SUCCESS) except Exception as e: - spinner.text = 'Delete failed. Error: {}'.format(e) + spinner.text = click.style('Delete failed. Error: {}'.format(e), fg=Colors.BRIGHT_RED) spinner.red.fail(Symbols.ERROR) raise SystemExit(1) from e @@ -253,15 +253,24 @@ def _apply_manifest(self, obj_key: str, *args, **kwargs) -> None: kls.validate(obj) ist = kls(munchify(obj)) + obj_key = click.style(obj_key, bold=True) + message_with_prompt("{} Applying {}...".format( Symbols.WAITING, obj_key), fg=Colors.CYAN, spinner=spinner) try: + result = ApplyResult.CREATED if not dryrun: - ist.apply(*args, **kwargs) + result = ist.apply(*args, **kwargs) - message_with_prompt("{} Applied {}".format( - Symbols.SUCCESS, obj_key), fg=Colors.GREEN, spinner=spinner) + if result == ApplyResult.EXISTS: + message_with_prompt("{} {} already exists".format( + Symbols.INFO, obj_key), fg=Colors.WHITE, spinner=spinner) + return + + message_with_prompt("{} {} {}".format( + Symbols.SUCCESS, result, obj_key), + fg=Colors.GREEN, spinner=spinner) except Exception as ex: message_with_prompt("{} Failed to apply {}. Error: {}".format( Symbols.ERROR, obj_key, str(ex)), fg=Colors.RED, spinner=spinner) @@ -277,6 +286,8 @@ def _delete_manifest(self, obj_key: str, *args, **kwargs) -> None: kls.validate(obj) ist = kls(munchify(obj)) + obj_key = click.style(obj_key, bold=True) + message_with_prompt("{} Deleting {}...".format( Symbols.WAITING, obj_key), fg=Colors.CYAN, spinner=spinner) @@ -289,7 +300,7 @@ def _delete_manifest(self, obj_key: str, *args, **kwargs) -> None: if not dryrun and can_delete: ist.delete(*args, **kwargs) - message_with_prompt("{} Deleted {}.".format( + message_with_prompt("{} Deleted {}".format( Symbols.SUCCESS, obj_key), fg=Colors.GREEN, spinner=spinner) except ResourceNotFound: message_with_prompt("{} {} not found".format( diff --git a/riocli/constants/__init__.py b/riocli/constants/__init__.py index b905f913..31975eff 100644 --- a/riocli/constants/__init__.py +++ b/riocli/constants/__init__.py @@ -13,8 +13,8 @@ # limitations under the License. from riocli.constants.colors import Colors -from riocli.constants.symbols import Symbols from riocli.constants.regions import Regions -from riocli.constants.status import Status +from riocli.constants.status import Status, ApplyResult +from riocli.constants.symbols import Symbols -__all__ = [Colors, Symbols, Regions, Status] +__all__ = [Colors, Symbols, Regions, Status, ApplyResult] diff --git a/riocli/constants/status.py b/riocli/constants/status.py index c3822076..8c66a560 100644 --- a/riocli/constants/status.py +++ b/riocli/constants/status.py @@ -1,3 +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. + from enum import Enum @@ -8,3 +22,13 @@ def __str__(self): RUNNING = 'Running' AVAILABLE = 'Available' + + +class ApplyResult(str, Enum): + + def __str__(self): + return str(self.value) + + CREATED = 'Created' + UPDATED = 'Updated' + EXISTS = 'Exists' diff --git a/riocli/deployment/model.py b/riocli/deployment/model.py index 2d69db58..22a9c97b 100644 --- a/riocli/deployment/model.py +++ b/riocli/deployment/model.py @@ -17,7 +17,7 @@ from munch import unmunchify from riocli.config import new_v2_client -from riocli.constants import Status +from riocli.constants import Status, ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.v2client import Client @@ -29,7 +29,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> typing.Any: + def apply(self, *args, **kwargs) -> ApplyResult: hard_dependencies = [d.nameOrGUID for d in self.spec.get('depends', []) if d.get('wait', False)] client = new_v2_client() @@ -43,8 +43,9 @@ def apply(self, *args, **kwargs) -> typing.Any: try: client.create_deployment(unmunchify(self)) + return ApplyResult.CREATED except HttpAlreadyExistsError: - pass + return ApplyResult.EXISTS def delete(self, *args, **kwargs): client = new_v2_client() diff --git a/riocli/device/model.py b/riocli/device/model.py index 5b950fad..7c1a0ece 100644 --- a/riocli/device/model.py +++ b/riocli/device/model.py @@ -15,6 +15,7 @@ from rapyuta_io.clients.device import Device as v1Device, DevicePythonVersion from riocli.config import new_client +from riocli.constants import ApplyResult from riocli.device.util import (DeviceNotFound, create_hwil_device, delete_hwil_device, execute_onboard_command, find_device_by_name, make_device_labels_from_hwil_device) from riocli.exceptions import ResourceNotFound @@ -25,7 +26,7 @@ class Device(Model): def __init__(self, *args, **kwargs): self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: client = new_client() device = None @@ -39,11 +40,15 @@ def apply(self, *args, **kwargs) -> None: if not self.spec.get('virtual', {}).get('enabled', False): if device is None: client.create_device(self.to_v1()) - return + return ApplyResult.CREATED + + return ApplyResult.EXISTS # Return if the device is already online or initializing. if device and device['status'] in ('ONLINE', 'INITIALIZING'): - return + return ApplyResult.EXISTS + + result = ApplyResult.CREATED if device is None else ApplyResult.UPDATED # Create the HWIL (virtual) device and then generate the labels # to store HWIL metadata in rapyuta.io device. @@ -74,6 +79,8 @@ def apply(self, *args, **kwargs) -> None: onboard_command = onboard_script.full_command() execute_onboard_command(hwil_response.id, onboard_command) + return result + def delete(self, *args, **kwargs) -> None: client = new_client() diff --git a/riocli/disk/model.py b/riocli/disk/model.py index 197e03c2..e4937a6b 100644 --- a/riocli/disk/model.py +++ b/riocli/disk/model.py @@ -15,6 +15,7 @@ from munch import unmunchify from riocli.config import new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.v2client.error import HttpAlreadyExistsError, HttpNotFoundError @@ -25,7 +26,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: client = new_v2_client() self.metadata.createdAt = None @@ -41,8 +42,9 @@ def apply(self, *args, **kwargs) -> None: retry_count=retry_count, sleep_interval=retry_interval, ) + return ApplyResult.CREATED except HttpAlreadyExistsError: - pass + return ApplyResult.EXISTS except Exception as e: raise e diff --git a/riocli/managedservice/model.py b/riocli/managedservice/model.py index b8b49164..c273089c 100644 --- a/riocli/managedservice/model.py +++ b/riocli/managedservice/model.py @@ -15,6 +15,7 @@ from munch import unmunchify from riocli.config import new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.v2client.error import HttpAlreadyExistsError, HttpNotFoundError @@ -25,13 +26,14 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: client = new_v2_client() try: client.create_instance(unmunchify(self)) + return ApplyResult.CREATED except HttpAlreadyExistsError: - pass + return ApplyResult.EXISTS def delete(self, *args, **kwargs) -> None: client = new_v2_client() diff --git a/riocli/model/base.py b/riocli/model/base.py index 16245725..42fbd07d 100644 --- a/riocli/model/base.py +++ b/riocli/model/base.py @@ -16,6 +16,7 @@ from munch import Munch +from riocli.constants import ApplyResult from riocli.jsonschema.validate import load_schema DELETE_POLICY_LABEL = 'rapyuta.io/deletionPolicy' @@ -41,7 +42,7 @@ def delete(self, *args, **kwargs): schema that are defined in the schema files. """ @abstractmethod - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: """Create or update the object. This method should be implemented by the subclasses. It should diff --git a/riocli/network/model.py b/riocli/network/model.py index 4255d63f..afb82fd1 100644 --- a/riocli/network/model.py +++ b/riocli/network/model.py @@ -15,6 +15,7 @@ from munch import unmunchify from riocli.config import new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.v2client.error import HttpAlreadyExistsError, HttpNotFoundError @@ -37,8 +38,9 @@ def apply(self, *args, **kwargs) -> None: try: r = client.create_network(unmunchify(self)) client.poll_network(r.metadata.name, retry_count=retry_count, sleep_interval=retry_interval) + return ApplyResult.CREATED except HttpAlreadyExistsError: - pass + return ApplyResult.EXISTS except Exception as e: raise e diff --git a/riocli/package/model.py b/riocli/package/model.py index 35bb7384..9ec4b204 100644 --- a/riocli/package/model.py +++ b/riocli/package/model.py @@ -16,6 +16,7 @@ from munch import unmunchify from riocli.config import new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.package.enum import RestartPolicy @@ -33,15 +34,16 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: client = new_v2_client() package = self._sanitize_package() try: client.create_package(package) + return ApplyResult.CREATED except HttpAlreadyExistsError: - pass + return ApplyResult.EXISTS def delete(self, *args, **kwargs) -> None: client = new_v2_client() diff --git a/riocli/project/model.py b/riocli/project/model.py index 62830cf0..d8b41de5 100644 --- a/riocli/project/model.py +++ b/riocli/project/model.py @@ -16,6 +16,7 @@ from waiting import wait from riocli.config import Configuration, new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.project.util import ProjectNotFound, find_project_guid @@ -30,7 +31,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: client = new_v2_client() project = unmunchify(self) @@ -42,10 +43,11 @@ def apply(self, *args, **kwargs) -> None: r = client.create_project(project) wait(self.is_ready, timeout_seconds=PROJECT_READY_TIMEOUT, sleep_seconds=(1, 30, 2)) + return ApplyResult.CREATED except HttpAlreadyExistsError: guid = find_project_guid(client, self.metadata.name, Configuration().organization_guid) client.update_project(guid, project) - return + return ApplyResult.UPDATED except Exception as e: raise e diff --git a/riocli/secret/model.py b/riocli/secret/model.py index 46dfe7e3..dd02111e 100644 --- a/riocli/secret/model.py +++ b/riocli/secret/model.py @@ -15,6 +15,7 @@ from munch import unmunchify from riocli.config import new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.v2client.error import HttpAlreadyExistsError, HttpNotFoundError @@ -32,8 +33,10 @@ def apply(self, *args, **kwargs) -> None: try: client.create_secret(unmunchify(self)) + return ApplyResult.CREATED except HttpAlreadyExistsError: client.update_secret(self.metadata.name, secret) + return ApplyResult.UPDATED def delete(self, *args, **kwargs) -> None: client = new_v2_client() diff --git a/riocli/static_route/model.py b/riocli/static_route/model.py index 13f3a1ad..af84a603 100644 --- a/riocli/static_route/model.py +++ b/riocli/static_route/model.py @@ -14,6 +14,7 @@ from munch import unmunchify from riocli.config import Configuration, new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.v2client.error import HttpAlreadyExistsError, HttpNotFoundError @@ -24,15 +25,17 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update(*args, **kwargs) - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: client = new_v2_client() static_route = unmunchify(self) try: client.create_static_route(static_route) + return ApplyResult.CREATED except HttpAlreadyExistsError: client.update_static_route(self.metadata.name, static_route) + return ApplyResult.UPDATED def delete(self, *args, **kwargs) -> None: client = new_v2_client() diff --git a/riocli/usergroup/model.py b/riocli/usergroup/model.py index ae1035dc..ff0b0a14 100644 --- a/riocli/usergroup/model.py +++ b/riocli/usergroup/model.py @@ -16,6 +16,7 @@ from munch import unmunchify from riocli.config import Configuration, new_client, new_v2_client +from riocli.constants import ApplyResult from riocli.exceptions import ResourceNotFound from riocli.model import Model from riocli.organization.utils import get_organization_details @@ -33,7 +34,7 @@ def __init__(self, *args, **kwargs): self.user_email_to_guid_map = {} self.project_name_to_guid_map = {} - def apply(self, *args, **kwargs) -> None: + def apply(self, *args, **kwargs) -> ApplyResult: v1client = new_client() v2client = new_v2_client() @@ -61,12 +62,13 @@ def apply(self, *args, **kwargs) -> None: try: payload['spec']['name'] = sanitized['metadata']['name'] v1client.create_usergroup(self.metadata.organization, payload['spec']) - return + return ApplyResult.CREATED except Exception as e: raise e payload = self._generate_update_payload(existing, payload) v1client.update_usergroup(organization_id, existing.guid, payload) + return ApplyResult.UPDATED def delete(self, *args, **kwargs) -> None: v1client = new_client()