From 6ccc6e91648312cc210e9b6a18e469e64f4a523f Mon Sep 17 00:00:00 2001 From: Paul Vinciguerra Date: Tue, 27 Nov 2018 08:15:22 -0800 Subject: vpp_papi: Add custom exceptions. This patchset adds and raises the following custom exception classes: * class VPPApiError(Exception): * class VPPNotImplementedError(NotImplementedError): * class VPPIOError(IOError): * class VPPRuntimeError(RuntimeError): * class VPPValueError(ValueError): * class VPPSerializerValueError(ValueError): * class VPPStatsIOError(IOError): * class VPPStatsClientLoadError(RuntimeError): * class VppTransportShmemIOError(IOError): * class VppTransportSocketIOError(IOError) Change-Id: Ia40900fd2dcef148d01125d6c691329fc666901e Signed-off-by: Paul Vinciguerra --- src/vpp-api/python/vpp_papi/vpp_format.py | 15 ++++-- src/vpp-api/python/vpp_papi/vpp_papi.py | 49 +++++++++++++++----- src/vpp-api/python/vpp_papi/vpp_serializer.py | 54 +++++++++++++--------- src/vpp-api/python/vpp_papi/vpp_stats.py | 28 ++++++++--- src/vpp-api/python/vpp_papi/vpp_transport_shmem.py | 14 ++++-- .../python/vpp_papi/vpp_transport_socket.py | 15 ++++-- 6 files changed, 121 insertions(+), 54 deletions(-) (limited to 'src/vpp-api') diff --git a/src/vpp-api/python/vpp_papi/vpp_format.py b/src/vpp-api/python/vpp_papi/vpp_format.py index d020df96188..c6f9477e03f 100644 --- a/src/vpp-api/python/vpp_papi/vpp_format.py +++ b/src/vpp-api/python/vpp_papi/vpp_format.py @@ -14,9 +14,16 @@ # from socket import inet_pton, inet_ntop, AF_INET6, AF_INET +import socket + + +class VPPFormatError(Exception): + pass class VPPFormat(object): + VPPFormatError = VPPFormatError + @staticmethod def format_vl_api_ip6_prefix_t(args): prefix, len = args.split('/') @@ -52,7 +59,7 @@ class VPPFormat(object): try: return {'un': {'ip6': {'address': inet_pton(AF_INET6, args)}}, 'af': int(1)} - except Exception as e: + except socket.error as e: return {'un': {'ip4': {'address': inet_pton(AF_INET, args)}}, 'af': int(0)} @@ -62,7 +69,7 @@ class VPPFormat(object): return inet_ntop(AF_INET6, arg.un.ip6.address) if arg.af == 0: return inet_ntop(AF_INET, arg.un.ip4.address) - raise + raise VPPFormatError @staticmethod def format_vl_api_prefix_t(args): @@ -80,7 +87,7 @@ class VPPFormat(object): return "{}/{}".format(inet_ntop(AF_INET, arg.address.un.ip4.address), arg.address_length) - raise + raise VPPFormatError @staticmethod def format_u8(args): @@ -101,7 +108,7 @@ class VPPFormat(object): def unformat_bytes(args): try: return args.decode('utf-8') - except Exception as e: + except ValueError as e: return args @staticmethod diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py index bd2682f5b8f..3c3eb706bf9 100644 --- a/src/vpp-api/python/vpp_papi/vpp_papi.py +++ b/src/vpp-api/python/vpp_papi/vpp_papi.py @@ -77,6 +77,26 @@ class FuncWrapper(object): return self._func(**kwargs) +class VPPApiError(Exception): + pass + + +class VPPNotImplementedError(NotImplementedError): + pass + + +class VPPIOError(IOError): + pass + + +class VPPRuntimeError(RuntimeError): + pass + + +class VPPValueError(ValueError): + pass + + class VPP(object): """VPP interface. @@ -89,6 +109,11 @@ class VPP(object): provides a means to register a callback function to receive these messages in a background thread. """ + VPPApiError = VPPApiError + VPPRuntimeError = VPPRuntimeError + VPPValueError = VPPValueError + VPPNotImplementedError = VPPNotImplementedError + VPPIOError = VPPIOError def process_json_file(self, apidef_file): api = json.load(apidef_file) @@ -134,15 +159,15 @@ class VPP(object): if len(unresolved) == 0: break if i > 3: - raise ValueError('Unresolved type definitions {}' - .format(unresolved)) + raise VPPValueError('Unresolved type definitions {}' + .format(unresolved)) types = unresolved i += 1 for m in api['messages']: try: self.messages[m[0]] = VPPMessage(m[0], m[1:]) - except NotImplementedError: + except VPPNotImplementedError: self.logger.error('Not implemented error for {}'.format(m[0])) def __init__(self, apifiles=None, testmode=False, async_thread=True, @@ -192,7 +217,7 @@ class VPP(object): if testmode: apifiles = [] else: - raise + raise VPPRuntimeError for file in apifiles: with open(file) as apidef_file: @@ -202,7 +227,7 @@ class VPP(object): # Basic sanity check if len(self.messages) == 0 and not testmode: - raise ValueError(1, 'Missing JSON message definitions') + raise VPPValueError(1, 'Missing JSON message definitions') self.transport = VppTransport(self, read_timeout=read_timeout, server_address=server_address) @@ -333,7 +358,7 @@ class VPP(object): if api_dir is None: api_dir = cls.find_api_dir() if api_dir is None: - raise RuntimeError("api_dir cannot be located") + raise VPPApiError("api_dir cannot be located") if isinstance(patterns, list) or isinstance(patterns, tuple): patterns = [p.strip() + '.api.json' for p in patterns] @@ -352,7 +377,7 @@ class VPP(object): @property def api(self): if not hasattr(self, "_api"): - raise Exception("Not connected, api definitions not available") + raise VPPApiError("Not connected, api definitions not available") return self._api def make_function(self, msg, i, multipart, do_async): @@ -393,7 +418,7 @@ class VPP(object): rv = self.transport.connect(name.encode(), pfx, msg_handler, rx_qlen) if rv != 0: - raise IOError(2, 'Connect failed') + raise VPPIOError(2, 'Connect failed') self.vpp_dictionary_maxid = self.transport.msg_table_max_index() self._register_functions(do_async=do_async) @@ -459,7 +484,7 @@ class VPP(object): # No context -> async notification that we feed to the callback self.message_queue.put_nowait(r) else: - raise IOError(2, 'RPC reply message received in event handler') + raise VPPIOError(2, 'RPC reply message received in event handler') def decode_incoming_msg(self, msg): if not msg: @@ -474,7 +499,7 @@ class VPP(object): # msgobj = self.id_msgdef[i] if not msgobj: - raise IOError(2, 'Reply message undefined') + raise VPPIOError(2, 'Reply message undefined') r, size = msgobj.unpack(msg) return r @@ -502,7 +527,7 @@ class VPP(object): def validate_args(self, msg, kwargs): d = set(kwargs.keys()) - set(msg.field_by_name.keys()) if d: - raise ValueError('Invalid argument {} to {}' + raise VPPValueError('Invalid argument {} to {}' .format(list(d), msg.name)) def _call_vpp(self, i, msg, multipart, **kwargs): @@ -549,7 +574,7 @@ class VPP(object): while (True): msg = self.transport.read() if not msg: - raise IOError(2, 'VPP API client: read failed') + raise VPPIOError(2, 'VPP API client: read failed') r = self.decode_incoming_msg(msg) msgname = type(r).__name__ if context not in r or r.context == 0 or context != r.context: diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py index a001cca565a..f78972979cd 100644 --- a/src/vpp-api/python/vpp_papi/vpp_serializer.py +++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py @@ -55,14 +55,10 @@ class BaseTypes(object): return self.packer.unpack_from(data, offset)[0], self.packer.size -types = {} -types['u8'] = BaseTypes('u8') -types['u16'] = BaseTypes('u16') -types['u32'] = BaseTypes('u32') -types['i32'] = BaseTypes('i32') -types['u64'] = BaseTypes('u64') -types['f64'] = BaseTypes('f64') -types['bool'] = BaseTypes('bool') +types = {'u8': BaseTypes('u8'), 'u16': BaseTypes('u16'), + 'u32': BaseTypes('u32'), 'i32': BaseTypes('i32'), + 'u64': BaseTypes('u64'), 'f64': BaseTypes('f64'), + 'bool': BaseTypes('bool')} def vpp_get_type(name): @@ -72,6 +68,10 @@ def vpp_get_type(name): return None +class VPPSerializerValueError(ValueError): + pass + + class FixedList_u8(object): def __init__(self, name, field_type, num): self.name = name @@ -85,16 +85,18 @@ class FixedList_u8(object): if not list: return b'\x00' * self.size if len(list) > self.num: - raise ValueError('Fixed list length error for "{}", got: {}' - ' expected: {}' - .format(self.name, len(list), self.num)) + raise VPPSerializerValueError( + 'Fixed list length error for "{}", got: {}' + ' expected: {}' + .format(self.name, len(list), self.num)) return self.packer.pack(list) def unpack(self, data, offset=0, result=None): if len(data[offset:]) < self.num: - raise ValueError('Invalid array length for "{}" got {}' - ' expected {}' - .format(self.name, len(data[offset:]), self.num)) + raise VPPSerializerValueError( + 'Invalid array length for "{}" got {}' + ' expected {}' + .format(self.name, len(data[offset:]), self.num)) return self.packer.unpack(data, offset) @@ -106,8 +108,9 @@ class FixedList(object): def pack(self, list, kwargs): if len(list) != self.num: - raise ValueError('Fixed list length error, got: {} expected: {}' - .format(len(list), self.num)) + raise VPPSerializerValueError( + 'Fixed list length error, got: {} expected: {}' + .format(len(list), self.num)) b = bytes() for e in list: b += self.packer.pack(e) @@ -137,8 +140,9 @@ class VLAList(object): if not list: return b"" if len(list) != kwargs[self.length_field]: - raise ValueError('Variable length error, got: {} expected: {}' - .format(len(list), kwargs[self.length_field])) + raise VPPSerializerValueError( + 'Variable length error, got: {} expected: {}' + .format(len(list), kwargs[self.length_field])) b = bytes() # u8 array @@ -187,7 +191,8 @@ class VLAList_legacy(): total = 0 # Return a list of arguments if (len(data) - offset) % self.packer.size: - raise ValueError('Legacy Variable Length Array length mismatch.') + raise VPPSerializerValueError( + 'Legacy Variable Length Array length mismatch.') elements = int((len(data) - offset) / self.packer.size) r = [] for e in range(elements): @@ -241,7 +246,8 @@ class VPPUnionType(object): f_type, f_name = f if f_type not in types: logger.debug('Unknown union type {}'.format(f_type)) - raise ValueError('Unknown message type {}'.format(f_type)) + raise VPPSerializerValueError( + 'Unknown message type {}'.format(f_type)) fields.append(f_name) size = types[f_type].size self.packers[f_name] = types[f_type] @@ -309,7 +315,8 @@ class VPPType(object): self.fieldtypes.append(f_type) if f_type not in types: logger.debug('Unknown type {}'.format(f_type)) - raise ValueError('Unknown message type {}'.format(f_type)) + raise VPPSerializerValueError( + 'Unknown message type {}'.format(f_type)) if len(f) == 3: # list list_elements = f[2] if list_elements == 0: @@ -345,8 +352,9 @@ class VPPType(object): # Try one of the format functions if data and type(data) is not dict and a not in data: - raise ValueError("Invalid argument: {} expected {}.{}". - format(data, self.name, a)) + raise VPPSerializerValueError( + "Invalid argument: {} expected {}.{}". + format(data, self.name, a)) # Defaulting to zero. if not data or a not in data: # Default to 0 diff --git a/src/vpp-api/python/vpp_papi/vpp_stats.py b/src/vpp-api/python/vpp_papi/vpp_stats.py index 8344de0c55b..bb6cdf5ffdc 100644 --- a/src/vpp-api/python/vpp_papi/vpp_stats.py +++ b/src/vpp-api/python/vpp_papi/vpp_stats.py @@ -138,12 +138,26 @@ def stat_entry_to_python(api, e): return None +class VPPStatsIOError(IOError): + pass + + +class VPPStatsClientLoadError(RuntimeError): + pass + + class VPPStats(object): - def __init__(self, socketname='/var/run/stats.sock', timeout=10): + VPPStatsIOError = VPPStatsIOError + + default_socketname = '/var/run/stats.sock' + sharedlib_name = 'libvppapiclient.so' + + def __init__(self, socketname=default_socketname, timeout=10): try: - self.api = ffi.dlopen('libvppapiclient.so') + self.api = ffi.dlopen(VPPStats.sharedlib_name) except Exception: - raise RuntimeError("Could not open: libvppapiclient.so") + raise VPPStatsClientLoadError("Could not open: %s" % + VPPStats.sharedlib_name) self.client = self.api.stat_client_get() poll_end_time = time.time() + timeout @@ -154,7 +168,7 @@ class VPPStats(object): break if rv != 0: - raise IOError() + raise VPPStatsIOError() def heartbeat(self): return self.api.stat_segment_heartbeat_r(self.client) @@ -169,7 +183,7 @@ class VPPStats(object): rv = self.api.stat_segment_dump_r(counters, self.client) # Raise exception and retry if rv == ffi.NULL: - raise IOError() + raise VPPStatsIOError() rv_len = self.api.stat_segment_vec_len(rv) for i in range(rv_len): n = ffi.string(rv[i].name).decode() @@ -184,7 +198,7 @@ class VPPStats(object): try: dir = self.ls(name) return self.dump(dir).values()[0] - except Exception as e: + except VPPStatsIOError as e: if retries > 10: return None retries += 1 @@ -201,7 +215,7 @@ class VPPStats(object): error_names = self.ls(['/err/']) error_counters = self.dump(error_names) break - except Exception as e: + except VPPStatsIOError as e: if retries > 10: return None retries += 1 diff --git a/src/vpp-api/python/vpp_papi/vpp_transport_shmem.py b/src/vpp-api/python/vpp_papi/vpp_transport_shmem.py index 5920cd16dcb..53ae775069f 100644 --- a/src/vpp-api/python/vpp_papi/vpp_transport_shmem.py +++ b/src/vpp-api/python/vpp_papi/vpp_transport_shmem.py @@ -47,7 +47,13 @@ def vac_error_handler(arg, msg, msg_len): vpp_object.logger.warning("VPP API client:: %s", ffi.string(msg, msg_len)) +class VppTransportShmemIOError(IOError): + pass + + class VppTransport(object): + VppTransportShmemIOError = VppTransportShmemIOError + def __init__(self, parent, read_timeout, server_address): self.connected = False self.read_timeout = read_timeout @@ -95,23 +101,23 @@ class VppTransport(object): def _write_new_cffi(self, buf): """Send a binary-packed message to VPP.""" if not self.connected: - raise IOError(1, 'Not connected') + raise VppTransportShmemIOError(1, 'Not connected') return vpp_api.vac_write(ffi.from_buffer(buf), len(buf)) def _write_legacy_cffi(self, buf): """Send a binary-packed message to VPP.""" if not self.connected: - raise IOError(1, 'Not connected') + raise VppTransportShmemIOError(1, 'Not connected') return vpp_api.vac_write(bytes(buf), len(buf)) def read(self): if not self.connected: - raise IOError(1, 'Not connected') + raise VppTransportShmemIOError(1, 'Not connected') mem = ffi.new("char **") size = ffi.new("int *") rv = vpp_api.vac_read(mem, size, self.read_timeout) if rv: - raise IOError(rv, 'vac_read failed') + raise VppTransportShmemIOError(rv, 'vac_read failed') msg = bytes(ffi.buffer(mem[0], size[0])) vpp_api.vac_free(mem[0]) return msg diff --git a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py index 49e565980f2..393e2e9c9c1 100644 --- a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py +++ b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py @@ -13,7 +13,13 @@ except ImportError: import logging +class VppTransportSocketIOError(IOError): + pass + + class VppTransport(object): + VppTransportSocketIOError = VppTransportSocketIOError + def __init__(self, parent, read_timeout, server_address): self.connected = False self.read_timeout = read_timeout if read_timeout > 0 else 1 @@ -59,7 +65,8 @@ class VppTransport(object): else: self.parent.msg_handler_async(msg) else: - raise IOError(2, 'Unknown response from select') + raise VppTransportSocketIOError( + 2, 'Unknown response from select') def connect(self, name, pfx, msg_handler, rx_qlen): @@ -87,7 +94,7 @@ class VppTransport(object): msg = self._read() hdr, length = self.parent.header.unpack(msg, 0) if hdr.msgid != 16: - raise IOError('Invalid reply message') + raise VppTransportSocketIOError('Invalid reply message') r, length = sockclnt_create_reply.unpack(msg) self.socket_index = r.index @@ -136,7 +143,7 @@ class VppTransport(object): def write(self, buf): """Send a binary-packed message to VPP.""" if not self.connected: - raise IOError(1, 'Not connected') + raise VppTransportSocketIOError(1, 'Not connected') # Send header header = self.header.pack(0, len(buf), 0) @@ -177,7 +184,7 @@ class VppTransport(object): def read(self): if not self.connected: - raise IOError(1, 'Not connected') + raise VppTransportSocketIOError(1, 'Not connected') try: return self.q.get(True, self.read_timeout) except queue.Empty: -- cgit 1.2.3-korg