From e8d5d5fe1b28f11f9ca88080bec57adafca3e864 Mon Sep 17 00:00:00 2001 From: Fabio Verboso Date: Tue, 10 Jul 2018 10:57:16 +0200 Subject: [PATCH] Ports Change-Id: I15ff94437501318f148c62e39d64b43c951d46f6 --- iotronicclient/client.py | 4 +- iotronicclient/common/filecache.py | 6 +- iotronicclient/common/http.py | 4 +- iotronicclient/v1/client.py | 5 + iotronicclient/v1/port.py | 102 +++++++++++++++++++++ iotronicclient/v1/port_shell.py | 131 +++++++++++++++++++++++++++ iotronicclient/v1/resource_fields.py | 33 ++++++- iotronicclient/v1/shell.py | 3 +- 8 files changed, 278 insertions(+), 10 deletions(-) create mode 100644 iotronicclient/v1/port.py create mode 100644 iotronicclient/v1/port_shell.py diff --git a/iotronicclient/client.py b/iotronicclient/client.py index 086a46c..b4d4516 100644 --- a/iotronicclient/client.py +++ b/iotronicclient/client.py @@ -125,8 +125,8 @@ def get_client(api_version, os_auth_token=None, iotronic_url=None, if session: try: # Pass the endpoint, it will be used to get hostname - # and port that will be used for API version caching. It will - # be also set as endpoint_override. + # and port.py that will be used for API version caching. + # It will be also set as endpoint_override. endpoint = session.get_endpoint( service_type=os_service_type, interface=os_endpoint_type, diff --git a/iotronicclient/common/filecache.py b/iotronicclient/common/filecache.py index f2d01df..17f6947 100644 --- a/iotronicclient/common/filecache.py +++ b/iotronicclient/common/filecache.py @@ -75,7 +75,7 @@ def save_data(host, port, data): """Save 'data' for a particular 'host' in the appropriate cache dir. param host: The host that we need to save data for - param port: The port on the host that we need to save data for + param port.py: The port.py on the host that we need to save data for param data: The data we want saved """ key = _build_key(host, port) @@ -85,11 +85,11 @@ def save_data(host, port, data): def retrieve_data(host, port, expiry=None): """Retrieve the version stored for an iotronic 'host', if it's not stale. - Check to see if there is valid cached data for the host/port + Check to see if there is valid cached data for the host/port.py combination and return that if it isn't stale. param host: The host that we need to retrieve data for - param port: The port on the host that we need to retrieve data for + param port.py: The port.py on the host that we need to retrieve data for param expiry: The age in seconds before cached data is deemed invalid """ # Ensure that a cache file exists first diff --git a/iotronicclient/common/http.py b/iotronicclient/common/http.py index ad41d7a..aecd334 100644 --- a/iotronicclient/common/http.py +++ b/iotronicclient/common/http.py @@ -81,7 +81,7 @@ def _extract_error_json(body): def get_server(endpoint): - """Extract and return the server & port that we're connecting to.""" + """Extract and return the server & port.py that we're connecting to.""" if endpoint is None: return None, None parts = urlparse.urlparse(endpoint) @@ -440,7 +440,7 @@ class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection): self.insecure = insecure def connect(self): - """Connect to a host on a given (SSL) port. + """Connect to a host on a given (SSL) port.py. If ca_file is pointing somewhere, use it to check Server Certificate. diff --git a/iotronicclient/v1/client.py b/iotronicclient/v1/client.py index b5f7303..b420052 100644 --- a/iotronicclient/v1/client.py +++ b/iotronicclient/v1/client.py @@ -22,6 +22,7 @@ from iotronicclient.v1 import board from iotronicclient.v1 import exposed_service from iotronicclient.v1 import plugin from iotronicclient.v1 import plugin_injection +from iotronicclient.v1 import port from iotronicclient.v1 import service @@ -66,3 +67,7 @@ class Client(object): self.service = service.ServiceManager(self.http_client) self.exposed_service = exposed_service.ExposedServiceManager( self.http_client) + self.port = port.PortManager( + self.http_client) + self.portonboard = port.PortOnBoardManager( + self.http_client) diff --git a/iotronicclient/v1/port.py b/iotronicclient/v1/port.py new file mode 100644 index 0000000..cedd4e9 --- /dev/null +++ b/iotronicclient/v1/port.py @@ -0,0 +1,102 @@ +# 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 Port(base.Resource): + def __repr__(self): + return "" % self._info + + +class PortOnBoardManager(base.Manager): + resource_class = Port + _resource_name = 'boards' + + def attach_port(self, board_ident, network_ident, subnetwork_ident): + path = "%s/ports" % board_ident + body = {"network": network_ident, + "subnet": subnetwork_ident} + + return self._update(path, body, method='PUT') + + def detach_port(self, board_ident, port_ident): + path = "%s/ports/" % board_ident + path = path + port_ident + return self._delete(resource_id=path) + + +class PortManager(base.Manager): + resource_class = Port + _resource_name = 'ports' + + def list(self, marker=None, limit=None, + detail=False, sort_key=None, sort_dir=None, fields=None): + """Retrieve a list of ports. + + :param marker: Optional, the UUID of a port, eg the last + port 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 ports to return. + 2) limit == 0, return the entire list of ports. + 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 ports. + + :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 ports. + + """ + 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), "ports") + else: + return self._list_pagination(self._path(path), "ports", + limit=limit) diff --git a/iotronicclient/v1/port_shell.py b/iotronicclient/v1/port_shell.py new file mode 100644 index 0000000..cd91186 --- /dev/null +++ b/iotronicclient/v1/port_shell.py @@ -0,0 +1,131 @@ +# 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 import cliutils +from iotronicclient.common import utils +from iotronicclient.v1 import resource_fields as res_fields + + +def _print_port_show(port, fields=None, json=False): + if fields is None: + fields = res_fields.PORT_RESOURCE.fields + + data = dict( + [(f, getattr(port, f, '')) for f in fields]) + cliutils.print_dict(data, wrap=72, json_flag=json) + + +@cliutils.arg('board', + metavar='', + help="Name or UUID of the board.") +@cliutils.arg('port', + metavar='', + help="Name or UUID of the port.") +def do_port_detach(cc, args): + """Detach a port from a board.""" + + cc.portonboard.detach_port(args.board, args.port) + + ''' + try: + cc.port.attach_port(args.board, args.port) + print(_('Port %(port)s has been detached from board %(board)s') % { + 'board': args.board, 'port': args.port}) + except exceptions.ClientException as e: + exceptions.ClientException( + "Failed to detach port on board %(board)s: %(error)s" % { + 'board': args.board, 'error': e}) + ''' + + +@cliutils.arg('board', + metavar='', + help="Name or UUID of the board.") +@cliutils.arg('network', + metavar='', + help="Name or UUID of the network.") +@cliutils.arg('subnetwork', + metavar='', + help="Name or UUID of the subnetwork.") +def do_port_attach(cc, args): + """Attach a port to a board.""" + + port = cc.portonboard.attach_port(args.board, args.network, + args.subnetwork) + _print_port_show(port) + + +@cliutils.arg( + '--limit', + metavar='', + type=int, + help='Maximum number of ports 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 port in the list from ' + 'a previous request). Returns the list of ports 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 ports.") +@cliutils.arg( + '--fields', + nargs='+', + dest='fields', + metavar='', + action='append', + default=[], + help="One or more port fields. Only these fields will be fetched from " + "the server. Can not be used when '--detail' is specified.") +def do_port_list(cc, args): + """List the ports which are registered with the Iotronic port.""" + params = {} + + if args.detail: + fields = res_fields.PORT_DETAILED_RESOURCE.fields + field_labels = res_fields.PORT_DETAILED_RESOURCE.labels + elif args.fields: + utils.check_for_invalid_fields( + args.fields[0], res_fields.PORT_DETAILED_RESOURCE.fields) + resource = res_fields.Resource(args.fields[0]) + fields = resource.fields + field_labels = resource.labels + else: + fields = res_fields.PORT_RESOURCE.fields + field_labels = res_fields.PORT_RESOURCE.labels + + sort_fields = res_fields.PORT_DETAILED_RESOURCE.sort_fields + sort_field_labels = res_fields.PORT_DETAILED_RESOURCE.sort_labels + + params.update(utils.common_params_for_list(args, + sort_fields, + sort_field_labels)) + + ports = cc.port.list(**params) + cliutils.print_list(ports, fields, + field_labels=field_labels, + sortby_index=None, + json_flag=args.json) diff --git a/iotronicclient/v1/resource_fields.py b/iotronicclient/v1/resource_fields.py index 5c543ff..83182dc 100644 --- a/iotronicclient/v1/resource_fields.py +++ b/iotronicclient/v1/resource_fields.py @@ -58,6 +58,10 @@ class Resource(object): 'public_port': 'Public Port', 'pid': 'Pid', 'protocol': 'Protocol', + 'MAC_add': 'Mac Address', + 'VIF_name': 'VIF', + 'network': 'Network', + 'ip': 'ip' # # 'address': 'Address', @@ -159,7 +163,7 @@ BOARD_DETAILED_RESOURCE = Resource( 'updated_at', 'location', 'project', - 'owner', + 'owner' ], sort_excluded=[ @@ -230,7 +234,6 @@ SERVICE_DETAILED_RESOURCE = Resource( 'extra', ]) - SERVICE_RESOURCE = Resource( ['uuid', 'name', @@ -253,3 +256,29 @@ EXPOSED_SERVICE_RESOURCE = Resource( 'created_at', 'updated_at', ]) + +PORT_RESOURCE = Resource( + ['uuid', + 'MAC_add', + 'VIF_name', + 'network', + 'board_uuid', + 'ip' + ] +) +# Service + +PORT_DETAILED_RESOURCE = Resource( + ['uuid', + 'MAC_add', + 'VIF_name', + 'network', + 'ip', + 'board_uuid', + 'extra', + 'created_at', + 'updated_at', + ], + sort_excluded=[ + 'extra', + ]) diff --git a/iotronicclient/v1/shell.py b/iotronicclient/v1/shell.py index 446d804..58c3aa3 100644 --- a/iotronicclient/v1/shell.py +++ b/iotronicclient/v1/shell.py @@ -16,15 +16,16 @@ from iotronicclient.v1 import board_shell from iotronicclient.v1 import exposed_service_shell 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 - COMMAND_MODULES = [ board_shell, plugin_shell, plugin_injection_shell, service_shell, exposed_service_shell, + port_shell, ]