From 17661c3b2b086f3d926857cd1fdc6952d7be5690 Mon Sep 17 00:00:00 2001 From: RomilShah Date: Mon, 26 Jun 2023 11:25:13 +0530 Subject: [PATCH] feat(static_route): uses v2 static route APIs This commit introduces support for V2 static routes --- riocli/apply/resolver.py | 6 +- .../schemas/static_route-schema.yaml | 18 ++++ riocli/static_route/__init__.py | 2 +- riocli/static_route/create.py | 18 ++-- riocli/static_route/delete.py | 16 ++-- riocli/static_route/inspect.py | 28 ++---- riocli/static_route/list.py | 20 ++--- riocli/static_route/model.py | 19 ++-- riocli/static_route/open.py | 12 ++- riocli/static_route/util.py | 45 ++-------- riocli/v2client/client.py | 87 +++++++++++++++++++ 11 files changed, 164 insertions(+), 107 deletions(-) diff --git a/riocli/apply/resolver.py b/riocli/apply/resolver.py index 79fb9772..ac4c853f 100644 --- a/riocli/apply/resolver.py +++ b/riocli/apply/resolver.py @@ -122,7 +122,7 @@ def _guid_functor(self, kind): 'secret': lambda x: munchify(x).guid, "project": lambda x: munchify(x).metadata.guid, "package": lambda x: munchify(x)['id'], - "staticroute": lambda x: munchify(x)['guid'], + "staticroute": lambda x: munchify(x)['metadata']['guid'], "build": lambda x: munchify(x)['guid'], "deployment": lambda x: munchify(x)['deploymentId'], "network": lambda x: munchify(x).guid, @@ -139,7 +139,7 @@ def _list_functors(self, kind): 'secret': self.client.list_secrets, "project": self.v2client.list_projects, "package": self.client.get_all_packages, - "staticroute": self.client.get_all_static_routes, + "staticroute": self.v2client.list_static_routes, "build": self.client.list_builds, "deployment": functools.partial(self.client.get_all_deployments, phases=[DeploymentPhaseConstants.SUCCEEDED, @@ -159,7 +159,7 @@ def _find_functors(self, kind): "project": lambda name, projects: filter(lambda i: i.metadata.name == name, projects), "package": lambda name, obj_list, version: filter( lambda x: name == x.name and version == x['packageVersion'], obj_list), - "staticroute": lambda name, obj_list: filter(lambda x: name == '-'.join(x.urlPrefix.split('-')[:-1]), + "staticroute": lambda name, obj_list: filter(lambda x: name == '-'.join(x.spec.url.split('-')[:-1]), obj_list), "build": self._generate_find_guid_functor(name_field='buildName'), "deployment": self._generate_find_guid_functor(), diff --git a/riocli/jsonschema/schemas/static_route-schema.yaml b/riocli/jsonschema/schemas/static_route-schema.yaml index 7cc26515..a686e681 100644 --- a/riocli/jsonschema/schemas/static_route-schema.yaml +++ b/riocli/jsonschema/schemas/static_route-schema.yaml @@ -14,6 +14,10 @@ definitions: const: StaticRoute metadata: "$ref": "#/definitions/metadata" + spec: + "$ref": "#/definitions/staticRouteSpec" + status: + "$ref": "#/definitions/staticRouteStatus" required: - apiVersion - kind @@ -47,3 +51,17 @@ definitions: uuid: type: string pattern: "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + staticRouteSpec: + type: object + properties: + url: + type: string + staticRouteStatus: + type: object + properties: + status: + type: string + packageID: + type: string + deploymentID: + type: string diff --git a/riocli/static_route/__init__.py b/riocli/static_route/__init__.py index 490b728d..d14b22f3 100644 --- a/riocli/static_route/__init__.py +++ b/riocli/static_route/__init__.py @@ -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. diff --git a/riocli/static_route/create.py b/riocli/static_route/create.py index a70c0af5..d66fc266 100644 --- a/riocli/static_route/create.py +++ b/riocli/static_route/create.py @@ -14,30 +14,32 @@ import click from click_help_colors import HelpColorsCommand -from riocli.config import new_client +from riocli.config import new_v2_client from riocli.constants import Colors, Symbols from riocli.utils.spinner import with_spinner - @click.command( 'create', cls=HelpColorsCommand, help_headers_color=Colors.YELLOW, help_options_color=Colors.GREEN, ) -@click.argument('prefix', type=str) +@click.argument('name', type=str) @with_spinner(text="Creating static route...") -def create_static_route(prefix: str, spinner=None) -> None: +def create_static_route(name: str, spinner=None) -> None: """ Creates a new static route """ try: - client = new_client() - route = client.create_static_route(prefix) + client = new_v2_client(with_project=True) + payload = { + "metadata": {"name": name} + } + route = client.create_static_route(payload) spinner.text = click.style( - 'Static Route created successfully for URL {}'.format(route.urlString), fg=Colors.GREEN) + 'Static Route created successfully for URL {}'.format(route.spec.url), fg=Colors.GREEN) spinner.green.ok(Symbols.SUCCESS) except Exception as e: spinner.text = click.style('Failed to create static route: {}'.format(e), fg=Colors.RED) spinner.red.fail(Symbols.ERROR) - raise SystemExit(1) + raise SystemExit(1) from e diff --git a/riocli/static_route/delete.py b/riocli/static_route/delete.py index 45f39e95..6c549a01 100644 --- a/riocli/static_route/delete.py +++ b/riocli/static_route/delete.py @@ -14,12 +14,10 @@ import click from click_help_colors import HelpColorsCommand -from riocli.config import new_client +from riocli.config import new_v2_client from riocli.constants import Colors, Symbols -from riocli.static_route.util import name_to_guid from riocli.utils.spinner import with_spinner - @click.command( 'delete', cls=HelpColorsCommand, @@ -28,11 +26,9 @@ ) @click.option('--force', '-f', is_flag=True, default=False, help='Skip confirmation') @click.argument('static-route', type=str) -@name_to_guid @with_spinner(text="Deleting static route...") def delete_static_route( static_route: str, - static_route_guid: str, force: bool, spinner=None, ) -> None: @@ -42,16 +38,16 @@ def delete_static_route( with spinner.hidden(): if not force: click.confirm( - 'Deleting static route {} ({})'.format( - static_route, static_route_guid), abort=True) + 'Deleting static route {}'.format( + static_route), abort=True) try: - client = new_client() - client.delete_static_route(static_route_guid) + client = new_v2_client() + client.delete_static_route(static_route) spinner.text = click.style( 'Static Route deleted successfully ', fg=Colors.GREEN) spinner.green.ok(Symbols.SUCCESS) except Exception as e: spinner.text = click.style('Failed to delete static route: {}'.format(e), fg=Colors.RED) spinner.red.fail(Symbols.ERROR) - raise SystemExit(1) + raise SystemExit(1) from e diff --git a/riocli/static_route/inspect.py b/riocli/static_route/inspect.py index a6b10a20..3f8a4bb5 100644 --- a/riocli/static_route/inspect.py +++ b/riocli/static_route/inspect.py @@ -13,11 +13,10 @@ # limitations under the License. import click from click_help_colors import HelpColorsCommand -from rapyuta_io.clients.static_route import StaticRoute +from munch import unmunchify -from riocli.config import new_client +from riocli.config import new_v2_client from riocli.constants import Colors -from riocli.static_route.util import name_to_guid from riocli.utils import inspect_with_format @@ -31,34 +30,19 @@ type=click.Choice(['json', 'yaml'], case_sensitive=True), default='yaml') @click.argument('static-route', type=str) -@name_to_guid def inspect_static_route( format_type: str, static_route: str, - static_route_guid: str ) -> None: """ Inspect a static route """ try: - client = new_client() - route = client.get_static_route(static_route_guid) - data = make_static_route_inspectable(route) - inspect_with_format(data, format_type) + client = new_v2_client() + route = client.get_static_route(static_route) + inspect_with_format(unmunchify(route), format_type) except Exception as e: click.secho(str(e), fg=Colors.RED) - raise SystemExit(1) + raise SystemExit(1) from e -def make_static_route_inspectable(static_route_data: StaticRoute) -> dict: - return { - 'created_at': static_route_data.CreatedAt, - 'updated_at': static_route_data.UpdatedAt, - 'deleted_at': static_route_data.DeletedAt, - 'guid': static_route_data.guid, - 'url_prefix': static_route_data.urlPrefix, - 'url': static_route_data.urlString, - 'creator': static_route_data.creator, - 'project': static_route_data.projectGUID, - 'metadata': static_route_data.metadata.__dict__, - } diff --git a/riocli/static_route/list.py b/riocli/static_route/list.py index b4317fa4..35f886fd 100644 --- a/riocli/static_route/list.py +++ b/riocli/static_route/list.py @@ -17,11 +17,10 @@ from click_help_colors import HelpColorsCommand from rapyuta_io.clients.static_route import StaticRoute -from riocli.config import new_client +from riocli.config import new_v2_client from riocli.constants import Colors from riocli.utils import tabulate_data - @click.command( 'list', cls=HelpColorsCommand, @@ -33,13 +32,12 @@ def list_static_routes() -> None: List the static routes in the selected project """ try: - client = new_client() - routes = client.get_all_static_routes() + client = new_v2_client(with_project=True) + routes = client.list_static_routes() _display_routes_list(routes) except Exception as e: click.secho(str(e), fg=Colors.RED) - raise SystemExit(1) - + raise SystemExit(1) from e def _display_routes_list(routes: List[StaticRoute]) -> None: headers = ['Route ID', 'Name', 'URL', 'Creator', 'CreatedAt'] @@ -47,11 +45,11 @@ def _display_routes_list(routes: List[StaticRoute]) -> None: data = [] for route in routes: data.append([ - route.guid, - route.urlPrefix, - route.urlString, - route.creator, - route.CreatedAt, + route.metadata.guid, + route.metadata.name, + route.spec.url, + route.metadata.creatorGUID, + route.metadata.createdAt, ]) tabulate_data(data, headers) diff --git a/riocli/static_route/model.py b/riocli/static_route/model.py index 698b2001..90d82bb2 100644 --- a/riocli/static_route/model.py +++ b/riocli/static_route/model.py @@ -12,10 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import typing +from munch import unmunchify from rapyuta_io import Client -from rapyuta_io.clients.static_route import StaticRoute as v1StaticRoute +from riocli.config import new_v2_client from riocli.jsonschema.validate import load_schema from riocli.model import Model @@ -29,21 +30,27 @@ def find_object(self, client: Client) -> bool: 'kind': 'staticroute', 'nameOrGUID': self.metadata.name }) - if not static_route: return False return static_route - def create_object(self, client: Client, **kwargs) -> v1StaticRoute: - static_route = client.create_static_route(self.metadata.name) - return static_route + def create_object(self, client: Client, **kwargs) -> typing.Any: + client = new_v2_client() + + # convert to a dict and remove the ResolverCache + # field since it's not JSON serializable + self.pop("rc", None) + static_route = unmunchify(self) + r = client.create_static_route(static_route) + return unmunchify(r) def update_object(self, client: Client, obj: typing.Any) -> None: pass def delete_object(self, client: Client, obj: typing.Any): - client.delete_static_route(obj.guid) + client = new_v2_client() + client.delete_static_route(obj.name) @classmethod def pre_process(cls, client: Client, d: typing.Dict) -> None: diff --git a/riocli/static_route/open.py b/riocli/static_route/open.py index 3162ae0b..9f1fa082 100644 --- a/riocli/static_route/open.py +++ b/riocli/static_route/open.py @@ -14,9 +14,8 @@ import click from click_help_colors import HelpColorsCommand -from riocli.config import new_client +from riocli.config import new_v2_client from riocli.constants import Colors -from riocli.static_route.util import name_to_guid @click.command( @@ -26,15 +25,14 @@ help_options_color=Colors.GREEN, ) @click.argument('static-route', type=str) -@name_to_guid -def open_static_route(static_route, static_route_guid) -> None: +def open_static_route(static_route) -> None: """ Opens the static route in the default browser """ try: - client = new_client() - route = client.get_static_route(static_route_guid) - click.launch(url='https://{}'.format(route.urlString), wait=False) + client = new_v2_client() + route = client.get_static_route(static_route) + click.launch(url='https://{}'.format(route.spec.url), wait=False) except Exception as e: click.secho(str(e), fg=Colors.RED) raise SystemExit(1) diff --git a/riocli/static_route/util.py b/riocli/static_route/util.py index c0b702fb..ab7cc6b9 100644 --- a/riocli/static_route/util.py +++ b/riocli/static_route/util.py @@ -11,50 +11,17 @@ # 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 -import typing from rapyuta_io import Client - -from riocli.config import new_client - - -def name_to_guid(f: typing.Callable) -> typing.Callable: - @functools.wraps(f) - def decorated(**kwargs: typing.Any): - client = new_client() - name = kwargs.pop('static_route') - guid = None - - if name.startswith('staticroute-'): - guid = name - name = None - - if name is None: - name = get_static_route_name(client, guid) - - if guid is None: - guid = find_static_route_guid(client, name) - - kwargs['static_route'] = name - kwargs['static_route_guid'] = guid - f(**kwargs) - - return decorated - - -def get_static_route_name(client: Client, guid: str) -> str: - static_route = client.get_static_route(guid) - return static_route.urlPrefix.split("-")[0] +from riocli.config import new_v2_client def find_static_route_guid(client: Client, name: str) -> str: - routes = client.get_all_static_routes() - for route in routes: - if route.urlPrefix == name or route.urlString == name: - return route.guid - - raise StaticRouteNotFound() + client = new_v2_client(with_project=True) + static_route = client.get_static_route(name) + if not static_route: + raise StaticRouteNotFound() + return static_route.metadata.guid class StaticRouteNotFound(Exception): diff --git a/riocli/v2client/client.py b/riocli/v2client/client.py index 67644766..e44261a3 100644 --- a/riocli/v2client/client.py +++ b/riocli/v2client/client.py @@ -332,3 +332,90 @@ def delete_instance_binding(self, instance_name: str, binding_name: str) -> Munc raise Exception("managedservice: {}".format(err_msg)) return munchify(data) + + def list_static_routes( + self, + query: dict = None + ) -> Munch: + """ + List all static routes in a project + """ + url = "{}/v2/staticroutes/".format(self._host) + headers = self._config.get_auth_header() + + params = {} + params.update(query or {}) + + offset, result = 0, [] + while True: + params.update({ + "continue": offset, + "limit": 10, + }) + response = RestClient(url).method(HttpMethod.GET).query_param( + params).headers(headers).execute() + data = json.loads(response.text) + if not response.ok: + err_msg = data.get('error') + raise Exception("static routes: {}".format(err_msg)) + staticRoutes = data.get('items', []) + if not staticRoutes: + break + offset = data['metadata']['continue'] + result.extend(staticRoutes) + + return munchify(result) + + def get_static_route(self, name: str) -> Munch: + """ + Get a static route by its name + """ + url = "{}/v2/staticroutes/{}/".format(self._host, name) + headers = self._config.get_auth_header() + response = RestClient(url).method( + HttpMethod.GET).headers(headers).execute() + + handle_server_errors(response) + + data = json.loads(response.text) + if not response.ok: + err_msg = data.get('error') + raise Exception("static routes: {}".format(err_msg)) + + return munchify(data) + + def create_static_route(self, metadata: dict) -> Munch: + """ + Create a new static route + """ + url = "{}/v2/staticroutes/".format(self._host) + headers = self._config.get_auth_header() + response = RestClient(url).method(HttpMethod.POST).headers( + headers).execute(payload=metadata) + + handle_server_errors(response) + + data = json.loads(response.text) + if not response.ok: + err_msg = data.get('error') + raise Exception("static routes: {}".format(err_msg)) + + return munchify(data) + + def delete_static_route(self, name: str) -> Munch: + """ + Delete a static route by its name + """ + url = "{}/v2/staticroutes/{}/".format(self._host, name) + headers = self._config.get_auth_header() + response = RestClient(url).method( + HttpMethod.DELETE).headers(headers).execute() + + handle_server_errors(response) + + data = json.loads(response.text) + if not response.ok: + err_msg = data.get('error') + raise Exception("static routes: {}".format(err_msg)) + + return munchify(data)