From 14c7d7c2c7211af251115396ca44f83681708ebd Mon Sep 17 00:00:00 2001 From: Fabio Verboso Date: Thu, 6 Dec 2018 12:22:01 +0100 Subject: [PATCH] WebServices Client can manage the Iotronic WebServices Change-Id: I93c9992023ffb4c82c24bb368998398a80ddcd40 --- iotronicclient/v1/client.py | 6 + iotronicclient/v1/resource_fields.py | 54 +++- iotronicclient/v1/shell.py | 2 + iotronicclient/v1/webservice.py | 256 +++++++++++++++++ iotronicclient/v1/webservice_shell.py | 379 ++++++++++++++++++++++++++ 5 files changed, 695 insertions(+), 2 deletions(-) create mode 100644 iotronicclient/v1/webservice.py create mode 100644 iotronicclient/v1/webservice_shell.py diff --git a/iotronicclient/v1/client.py b/iotronicclient/v1/client.py index 3f6e9ce..3545141 100644 --- a/iotronicclient/v1/client.py +++ b/iotronicclient/v1/client.py @@ -25,6 +25,7 @@ from iotronicclient.v1 import plugin from iotronicclient.v1 import plugin_injection from iotronicclient.v1 import port from iotronicclient.v1 import service +from iotronicclient.v1 import webservice class Client(object): @@ -73,3 +74,8 @@ class Client(object): self.portonboard = port.PortOnBoardManager( self.http_client) self.fleet = fleet.FleetManager(self.http_client) + self.webservice = webservice.WebServiceManager(self.http_client) + self.webserviceonboard = webservice.WebServiceOnBoardManager( + self.http_client) + self.enabledwebservice = webservice.EnabledWebserviceManager( + self.http_client) diff --git a/iotronicclient/v1/resource_fields.py b/iotronicclient/v1/resource_fields.py index 2bfb152..26d68fe 100644 --- a/iotronicclient/v1/resource_fields.py +++ b/iotronicclient/v1/resource_fields.py @@ -48,7 +48,7 @@ class Resource(object): 'callable': 'Callable', 'public': 'Public', 'onboot': 'On Boot', - 'board_uuid': 'Board uuid', + 'board_uuid': 'Board', 'plugin_uuid': 'Plugin uuid', 'service_uuid': 'Service uuid', 'plugin': 'Plugin', @@ -64,6 +64,12 @@ class Resource(object): 'ip': 'ip', 'description': 'Description', 'fleet': 'Fleet', + 'secure': 'Sercure', + 'http_port': 'HTTP Port', + 'https_port': 'HTTPS Port', + 'zone': 'Zone', + 'dns': 'DNS', + # # 'address': 'Address', # 'async': 'Async', @@ -160,7 +166,6 @@ BOARD_DETAILED_RESOURCE = Resource( 'session', 'mobile', 'extra', - 'created_at', 'updated_at', 'location', @@ -308,3 +313,48 @@ FLEET_RESOURCE = Resource( 'project', 'description' ]) + +# WebService +WEBSERVICE_DETAILED_RESOURCE = Resource( + ['uuid', + 'name', + 'port', + 'secure', + 'board_uuid', + 'extra', + 'created_at', + 'updated_at', + ], + sort_excluded=[ + 'extra', + ]) + +WEBSERVICE_RESOURCE = Resource( + ['uuid', + 'name', + 'port', + 'board_uuid', + ]) + +# WebService +EXPWEBSERVICE_DETAILED_RESOURCE = Resource( + ['board_uuid', + 'http_port', + 'https_port', + 'dns', + 'zone', + 'extra', + 'created_at', + 'updated_at', + ], + sort_excluded=[ + 'extra', + ]) + +EXPWEBSERVICE_RESOURCE = Resource( + ['board_uuid', + 'http_port', + 'https_port', + 'dns', + 'zone', + ]) diff --git a/iotronicclient/v1/shell.py b/iotronicclient/v1/shell.py index b0fbac0..a82ec72 100644 --- a/iotronicclient/v1/shell.py +++ b/iotronicclient/v1/shell.py @@ -19,6 +19,7 @@ from iotronicclient.v1 import plugin_injection_shell from iotronicclient.v1 import plugin_shell from iotronicclient.v1 import port_shell from iotronicclient.v1 import service_shell +from iotronicclient.v1 import webservice_shell COMMAND_MODULES = [ board_shell, @@ -28,6 +29,7 @@ COMMAND_MODULES = [ exposed_service_shell, port_shell, fleet_shell, + webservice_shell, ] diff --git a/iotronicclient/v1/webservice.py b/iotronicclient/v1/webservice.py new file mode 100644 index 0000000..1ff54f0 --- /dev/null +++ b/iotronicclient/v1/webservice.py @@ -0,0 +1,256 @@ +# 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. + +import logging + +from iotronicclient.common import base +from iotronicclient.common.i18n import _ +from iotronicclient.common import utils +from iotronicclient import exc + +LOG = logging.getLogger(__name__) +_DEFAULT_POLL_INTERVAL = 2 + + +class WebService(base.Resource): + def __repr__(self): + return "" % self._info + + +class WebServiceManager(base.CreateManager): + resource_class = WebService + _creation_attributes = ['name', 'port', 'protocol', 'secure', 'extra'] + + _resource_name = 'webservices' + + def list(self, marker=None, limit=None, + detail=False, sort_key=None, sort_dir=None, fields=None): + """Retrieve a list of webservices. + + :param marker: Optional, the UUID of a webservice, eg the last + webservice from a previous result set. Return + the next result set. + :param limit: The maximum number of results to return per + request, if: + + 1) limit > 0, the maximum number of webservices to return. + 2) limit == 0, return the entire list of webservices. + 3) limit param is NOT specified (None), the number of items + returned respect the maximum imposed by the Iotronic API + (see Iotronic's api.max_limit option). + + :param detail: Optional, boolean whether to return detailed information + about webservices. + + :param sort_key: Optional, field used for sorting. + + :param sort_dir: Optional, direction of sorting, either 'asc' (the + default) or 'desc'. + + :param fields: Optional, a list with a specified set of fields + of the resource to be returned. Can not be used + when 'detail' is set. + + :returns: A list of webservices. + + """ + if limit is not None: + limit = int(limit) + + if detail and fields: + raise exc.InvalidAttribute(_("Can't fetch a subset of fields " + "with 'detail' set")) + + filters = utils.common_filters(marker, limit, sort_key, sort_dir, + fields) + path = '' + + if detail: + path += 'detail' + + if filters: + path += '?' + '&'.join(filters) + + if limit is None: + return self._list(self._path(path), "webservices") + else: + return self._list_pagination(self._path(path), "webservices", + limit=limit) + + def get(self, webservice_id, fields=None): + return self._get(resource_id=webservice_id, fields=fields) + + def delete(self, webservice_id): + return self._delete(resource_id=webservice_id) + # + # def update(self, webservice_id, patch, http_method='PATCH'): + # return self._update(resource_id=webservice_id, patch=patch, + # method=http_method) + + +class WebServiceOnBoardManager(base.CreateManager): + resource_class = WebService + _creation_attributes = ['name', 'port', 'protocol', 'extra'] + + _resource_name = 'boards' + + def list(self, board_ident, marker=None, limit=None, + detail=False, sort_key=None, sort_dir=None, fields=None): + """Retrieve a list of webservices on a board. + + :param marker: Optional, the UUID of a webservice, eg the last + webservice from a previous result set. Return + the next result set. + :param limit: The maximum number of results to return per + request, if: + + 1) limit > 0, the maximum number of webservices to return. + 2) limit == 0, return the entire list of webservices. + 3) limit param is NOT specified (None), the number of items + returned respect the maximum imposed by the Iotronic API + (see Iotronic's api.max_limit option). + + :param detail: Optional, boolean whether to return detailed information + about webservices. + + :param sort_key: Optional, field used for sorting. + + :param sort_dir: Optional, direction of sorting, either 'asc' (the + default) or 'desc'. + + :param fields: Optional, a list with a specified set of fields + of the resource to be returned. Can not be used + when 'detail' is set. + + :returns: A list of webservices. + + """ + if limit is not None: + limit = int(limit) + + if detail and fields: + raise exc.InvalidAttribute(_("Can't fetch a subset of fields " + "with 'detail' set")) + + filters = utils.common_filters(marker, limit, sort_key, sort_dir, + fields) + + path = "%s/webservices" % board_ident + + if detail: + path += 'detail' + + if filters: + path += '?' + '&'.join(filters) + + if limit is None: + return self._list(self._path(path), "webservices") + else: + return self._list_pagination(self._path(path), "webservices", + limit=limit) + + def expose(self, board_ident, name, port, secure): + path = "%s/webservices" % board_ident + + body = { + "name": name, + "port": port, + "secure": secure + } + resp, body = self.api.json_request('PUT', self._path(path), body=body) + return WebService(self, body) + + def enable_webservice(self, board_ident, dns, zone, email, + http_method='POST'): + path = "%s/webservices/enable" % board_ident + + body = { + "dns": dns, + "zone": zone, + "email": email + } + resp, body = self.api.json_request(http_method, self._path(path), + body=body) + return EnabledWebservice(self, body) + + def disable_webservice(self, board_ident): + path = "%s/webservices/disable" % board_ident + + return self.api.raw_request('DELETE', self._path(path)) + + +class EnabledWebservice(base.Resource): + def __repr__(self): + return "" % self._info + + +class EnabledWebserviceManager(base.CreateManager): + resource_class = EnabledWebservice + _creation_attributes = ['board_uuid', 'https_port', 'http_port', 'dns', + 'zone', 'extra'] + + _resource_name = 'enabledwebservices' + + def list(self, marker=None, limit=None, + detail=False, sort_key=None, sort_dir=None, fields=None): + """Retrieve a list of enabledenabledwebservices on a board. + + :param marker: Optional, the UUID of a enabledwebservice, eg the last + enabledwebservice from a previous result set. Return + the next result set. + :param limit: The maximum number of results to return per + request, if: + + 1) limit > 0, the maximum number of enabledwebservices to return. + 2) limit == 0, return the entire list of enabledwebservices. + 3) limit param is NOT specified (None), the number of items + returned respect the maximum imposed by the Iotronic API + (see Iotronic's api.max_limit option). + + :param detail: Optional, boolean whether to return detailed information + about enabledwebservices. + + :param sort_key: Optional, field used for sorting. + + :param sort_dir: Optional, direction of sorting, either 'asc' (the + default) or 'desc'. + + :param fields: Optional, a list with a specified set of fields + of the resource to be returned. Can not be used + when 'detail' is set. + + :returns: A list of enabledwebservices. + + """ + if limit is not None: + limit = int(limit) + + if detail and fields: + raise exc.InvalidAttribute(_("Can't fetch a subset of fields " + "with 'detail' set")) + + filters = utils.common_filters(marker, limit, sort_key, sort_dir, + fields) + path = '' + + if detail: + path += 'detail' + + if filters: + path += '?' + '&'.join(filters) + + if limit is None: + return self._list(self._path(path), "EnabledWebservices") + else: + return self._list_pagination(self._path(path), + "EnabledWebservices", + limit=limit) diff --git a/iotronicclient/v1/webservice_shell.py b/iotronicclient/v1/webservice_shell.py new file mode 100644 index 0000000..64aba1c --- /dev/null +++ b/iotronicclient/v1/webservice_shell.py @@ -0,0 +1,379 @@ +# 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 iotronicclient.common.apiclient import exceptions +from iotronicclient.common import cliutils +from iotronicclient.common.i18n import _ +from iotronicclient.common import utils +from iotronicclient.v1 import resource_fields as res_fields + + +def _print_webservice_enabled_show(expwebservice, fields=None, json=False): + print(expwebservice) + + if fields is None: + fields = res_fields.EXPWEBSERVICE_DETAILED_RESOURCE.fields + + data = dict( + [(f, getattr(expwebservice, f, '')) for f in fields]) + cliutils.print_dict(data, wrap=72, json_flag=json) + + +def _print_webservice_show(webservice, fields=None, json=False): + if fields is None: + fields = res_fields.WEBSERVICE_DETAILED_RESOURCE.fields + + data = dict( + [(f, getattr(webservice, f, '')) for f in fields]) + cliutils.print_dict(data, wrap=72, json_flag=json) + + +@cliutils.arg( + 'webservice', + metavar='', + help="Name or UUID of the webservice ") +@cliutils.arg( + '--fields', + nargs='+', + dest='fields', + metavar='', + action='append', + default=[], + help="One or more webservice fields. Only these fields will be fetched " + "from the server.") +def do_webservice_show(cc, args): + """Show detailed information about a webservice.""" + fields = args.fields[0] if args.fields else None + utils.check_empty_arg(args.webservice, '') + utils.check_for_invalid_fields( + fields, res_fields.WEBSERVICE_DETAILED_RESOURCE.fields) + webservice = cc.webservice.get(args.webservice, fields=fields) + _print_webservice_show(webservice, fields=fields, json=args.json) + + +@cliutils.arg( + '--limit', + metavar='', + type=int, + help='Maximum number of webservices to return per request, ' + '0 for no limit. Default is the maximum number used ' + 'by the Iotronic API WebService.') +@cliutils.arg( + '--marker', + metavar='', + help='WebService UUID (for example, of the last webservice in the list ' + 'from a previous request). ' + 'Returns the list of webservices after this UUID.') +@cliutils.arg( + '--sort-key', + metavar='', + help='WebService field that will be used for sorting.') +@cliutils.arg( + '--sort-dir', + metavar='', + choices=['asc', 'desc'], + help='Sort direction: "asc" (the default) or "desc".') +@cliutils.arg( + '--detail', + dest='detail', + action='store_true', + default=False, + help="Show detailed information about the webservices.") +@cliutils.arg( + '--fields', + nargs='+', + dest='fields', + metavar='', + action='append', + default=[], + help="One or more webservice fields. Only these fields will be fetched " + "from the server. Can not be used when '--detail' is specified.") +def do_webservice_list(cc, args): + """List the webservices which are registered with the + Iotronic webservice. + + """ + params = {} + + if args.detail: + fields = res_fields.WEBSERVICE_DETAILED_RESOURCE.fields + field_labels = res_fields.WEBSERVICE_DETAILED_RESOURCE.labels + elif args.fields: + utils.check_for_invalid_fields( + args.fields[0], res_fields.WEBSERVICE_DETAILED_RESOURCE.fields) + resource = res_fields.Resource(args.fields[0]) + fields = resource.fields + field_labels = resource.labels + else: + fields = res_fields.WEBSERVICE_RESOURCE.fields + field_labels = res_fields.WEBSERVICE_RESOURCE.labels + + sort_fields = res_fields.WEBSERVICE_DETAILED_RESOURCE.sort_fields + sort_field_labels = res_fields.WEBSERVICE_DETAILED_RESOURCE.sort_labels + + params.update(utils.common_params_for_list(args, + sort_fields, + sort_field_labels)) + + webservices = cc.webservice.list(**params) + cliutils.print_list(webservices, fields, + field_labels=field_labels, + sortby_index=None, + json_flag=args.json) + + +@cliutils.arg( + 'board', + metavar='', + help="Name or UUID of the board ") +@cliutils.arg( + 'name', + metavar='', + help="Name of the webservice ") +@cliutils.arg( + 'port', + metavar='', + help="Port of the webservice") +@cliutils.arg( + '--secure', + dest='secure', + action='store_true', + default=True, + help="Set a secure webservice") +def do_expose_webservice(cc, args): + """Register a new webservice with the Iotronic webservice.""" + + webservice = cc.webserviceonboard.expose(args.board, + args.name, + args.port, + args.secure) + + data = dict([(f, getattr(webservice, f, '')) for f in + res_fields.WEBSERVICE_DETAILED_RESOURCE.fields]) + + cliutils.print_dict(data, wrap=72, json_flag=args.json) + + +# + +@cliutils.arg('webservice', + metavar='', + nargs='+', + help="Name or UUID of the webservice.") +def do_unexpose_webservice(cc, args): + """Unregister webservice(s) from the Iotronic webservice. + + Returns errors for any webservices that could not be unregistered. + """ + + failures = [] + for n in args.webservice: + try: + cc.webservice.delete(n) + print(_('Deleted webservice %s') % n) + except exceptions.ClientException as e: + failures.append( + _("Failed to delete webservice %(webservice)s: %(error)s") + % {'webservice': n, 'error': e}) + if failures: + raise exceptions.ClientException("\n".join(failures)) + + +# @cliutils.arg('webservice', metavar='', +# help="Name or UUID of the webservice.") +# @cliutils.arg( +# 'attributes', +# metavar='', +# nargs='+', +# action='append', +# default=[], +# help="Values to be changed.") +# def do_webservice_update(cc, args): +# """Update information about a registered webservice.""" +# +# patch = {k: v for k, v in (x.split('=') for x in args.attributes[0])} +# +# webservice = cc.webservice.update(args.webservice, patch) +# _print_webservice_show(webservice, json=args.json) + +@cliutils.arg( + 'board', + metavar='', + help="UUID or name of the board ") +@cliutils.arg( + '--limit', + metavar='', + type=int, + help='Maximum number of webservices to return per request, ' + '0 for no limit. Default is the maximum number used ' + 'by the Iotronic API WebService.') +@cliutils.arg( + '--marker', + metavar='', + help='WebService UUID (for example, of the last webservice in the list ' + 'from a previous request). Returns the list of webservices ' + 'after this UUID.') +@cliutils.arg( + '--sort-key', + metavar='', + help='WebService field that will be used for sorting.') +@cliutils.arg( + '--sort-dir', + metavar='', + choices=['asc', 'desc'], + help='Sort direction: "asc" (the default) or "desc".') +@cliutils.arg( + '--detail', + dest='detail', + action='store_true', + default=False, + help="Show detailed information about the webservices.") +@cliutils.arg( + '--fields', + nargs='+', + dest='fields', + metavar='', + action='append', + default=[], + help="One or more webservice fields. Only these fields will be fetched " + "from the server. Can not be used when '--detail' is specified.") +def do_webservices_on_board(cc, args): + """List the webservices which are registered + with the Iotronic webservice. + + """ + params = {} + + if args.detail: + fields = res_fields.WEBSERVICE_DETAILED_RESOURCE.fields + field_labels = res_fields.WEBSERVICE_DETAILED_RESOURCE.labels + elif args.fields: + utils.check_for_invalid_fields( + args.fields[0], res_fields.WEBSERVICE_DETAILED_RESOURCE.fields) + resource = res_fields.Resource(args.fields[0]) + fields = resource.fields + field_labels = resource.labels + else: + fields = res_fields.WEBSERVICE_RESOURCE.fields + field_labels = res_fields.WEBSERVICE_RESOURCE.labels + + sort_fields = res_fields.WEBSERVICE_DETAILED_RESOURCE.sort_fields + sort_field_labels = res_fields.WEBSERVICE_DETAILED_RESOURCE.sort_labels + + params.update(utils.common_params_for_list(args, + sort_fields, + sort_field_labels)) + + webservices = cc.webserviceonboard.list(args.board, **params) + cliutils.print_list(webservices, fields, + field_labels=field_labels, + sortby_index=None, + json_flag=args.json) + + +@cliutils.arg( + 'board', + metavar='', + help="UUID or name of the board ") +@cliutils.arg( + 'dns', + metavar='', + help="UUID of the webservice ") +@cliutils.arg( + 'zone', + metavar='', + help="UUID of the board ") +@cliutils.arg( + 'email', + metavar='', + help="UUID of the webservice ") +def do_enable_webservices(cc, args): + webservices = cc.webserviceonboard.enable_webservice(args.board, + args.dns, + args.zone, + args.email) + _print_webservice_enabled_show(webservices, json=args.json) + + +@cliutils.arg( + 'board', + metavar='', + help="UUID of the board ") +def do_disable_webservices(cc, args): + cc.webserviceonboard.disable_webservice(args.board) + + +@cliutils.arg( + '--limit', + metavar='', + type=int, + help='Maximum number of services to return per request, ' + '0 for no limit. Default is the maximum number used ' + 'by the Iotronic API Service.') +@cliutils.arg( + '--marker', + metavar='', + help='Service UUID (for example, of the last service in the list from ' + 'a previous request). Returns the list of services after this UUID.') +@cliutils.arg( + '--sort-key', + metavar='', + help='Service field that will be used for sorting.') +@cliutils.arg( + '--sort-dir', + metavar='', + choices=['asc', 'desc'], + help='Sort direction: "asc" (the default) or "desc".') +@cliutils.arg( + '--detail', + dest='detail', + action='store_true', + default=False, + help="Show detailed information about the services.") +@cliutils.arg( + '--fields', + nargs='+', + dest='fields', + metavar='', + action='append', + default=[], + help="One or more service fields. Only these fields will be fetched from " + "the server. Can not be used when '--detail' is specified.") +def do_enabled_webservice_list(cc, args): + """List the services which are registered with the Iotronic service.""" + params = {} + + if args.detail: + fields = res_fields.EXPWEBSERVICE_DETAILED_RESOURCE.fields + field_labels = res_fields.EXPWEBSERVICE_DETAILED_RESOURCE.labels + elif args.fields: + utils.check_for_invalid_fields( + args.fields[0], res_fields.EXPWEBSERVICE_DETAILED_RESOURCE.fields) + resource = res_fields.Resource(args.fields[0]) + fields = resource.fields + field_labels = resource.labels + else: + fields = res_fields.EXPWEBSERVICE_RESOURCE.fields + field_labels = res_fields.EXPWEBSERVICE_RESOURCE.labels + + sort_fields = res_fields.EXPWEBSERVICE_DETAILED_RESOURCE.sort_fields + sort_field_labels = res_fields.EXPWEBSERVICE_DETAILED_RESOURCE.sort_labels + + params.update(utils.common_params_for_list(args, + sort_fields, + sort_field_labels)) + + enabWebservices = cc.enabledwebservice.list(**params) + cliutils.print_list(enabWebservices, fields, + field_labels=field_labels, + sortby_index=None, + json_flag=args.json)