def subscribe(self, subscribe: dict = None, poll: bool = False, aliases: list = None, timeout: float = 0.0): """ Implementation of the subscribe gNMI RPC to pool """ logger.info(f'Collecting Telemetry...') if (subscribe and poll) or (subscribe and aliases) or (poll and aliases): raise Exception( 'Subscribe request supports only one request at a time.') if poll: if isinstance(poll, bool): if poll: request = Poll() gnmi_message_request = SubscribeRequest(poll=request) else: logger.error( 'Subscribe pool request is specificed, but the value is not boolean.' ) if aliases: if isinstance(aliases, list): request = AliasList() for ae in aliases: if isinstance(ae, tuple): if re.match('^#.*', ae[1]): request.alias.add(path=gnmi_path_generator(ae[0]), alias=ae[1]) else: raise ValueError( 'The alias is malformed. It should start with #...' ) gnmi_message_request = SubscribeRequest(aliases=request) else: logger.error( 'Subscribe aliases request is specified, but the value is not list.' ) if subscribe: gnmi_message_request = self._build_subscriptionrequest(subscribe) if self.__debug: print( "gNMI request:\n------------------------------------------------" ) print(gnmi_message_request) print("------------------------------------------------") return self.__stub.Subscribe(self.__generator(gnmi_message_request), metadata=self.__metadata)
def set(self, delete: list = None, replace: list = None, update: list = None, encoding: str = 'json'): """ Changing the configuration on the destination network elements. Could provide a single attribute or multiple attributes. delete: - list of paths with the resources to delete. The format is the same as for get() request replace: - list of tuples where the first entry path provided as a string, and the second entry is a dictionary with the configuration to be configured replace: - list of tuples where the first entry path provided as a string, and the second entry is a dictionary with the configuration to be configured The encoding argument may have the following values per gNMI specification: - json - bytes - proto - ascii - json_ietf """ del_protobuf_paths = [] replace_msg = [] update_msg = [] encoding_set = {'json', 'bytes', 'proto', 'ascii', 'json_ietf'} if encoding not in encoding_set: logger.error( f'The encoding {encoding} is not supported. The allowed are: {", ".join(encoding_set)}.' ) raise Exception( f'The encoding {encoding} is not supported. The allowed are: {", ".join(encoding_set)}.' ) if delete: if isinstance(delete, list): try: del_protobuf_paths = [ gnmi_path_generator(pe) for pe in delete ] except: logger.error( f'Conversion of gNMI paths to the Protobuf format failed' ) raise Exception( f'Conversion of gNMI paths to the Protobuf format failed' ) else: logger.error( f'The provided input for Set message (delete operation) is not list.' ) raise Exception( f'The provided input for Set message (delete operation) is not list.' ) if replace: if isinstance(replace, list): for ue in replace: if isinstance(ue, tuple): u_path = gnmi_path_generator(ue[0]) u_val = json.dumps(ue[1]).encode('utf-8') if encoding == 'json': replace_msg.append( Update(path=u_path, val=TypedValue(json_val=u_val))) elif encoding == 'bytes': replace_msg.append( Update(path=u_path, val=TypedValue(bytes_val=u_val))) elif encoding == 'proto': replace_msg.append( Update(path=u_path, val=TypedValue(proto_bytes=u_val))) elif encoding == 'ascii': replace_msg.append( Update(path=u_path, val=TypedValue(ascii_val=u_val))) elif encoding == 'json_ietf': replace_msg.append( Update(path=u_path, val=TypedValue(json_ietf_val=u_val))) else: logger.error( f'The input element for Update message must be tuple, got {ue}.' ) raise Exception( f'The input element for Update message must be tuple, got {ue}.' ) else: logger.error( f'The provided input for Set message (replace operation) is not list.' ) raise Exception( 'The provided input for Set message (replace operation) is not list.' ) if update: if isinstance(update, list): for ue in update: if isinstance(ue, tuple): u_path = gnmi_path_generator(ue[0]) u_val = json.dumps(ue[1]).encode('utf-8') if encoding == 'json': update_msg.append( Update(path=u_path, val=TypedValue(json_val=u_val))) elif encoding == 'bytes': update_msg.append( Update(path=u_path, val=TypedValue(bytes_val=u_val))) elif encoding == 'proto': update_msg.append( Update(path=u_path, val=TypedValue(proto_bytes=u_val))) elif encoding == 'ascii': update_msg.append( Update(path=u_path, val=TypedValue(ascii_val=u_val))) elif encoding == 'json_ietf': update_msg.append( Update(path=u_path, val=TypedValue(json_ietf_val=u_val))) else: logger.error( f'The input element for Update message must be tuple, got {ue}.' ) raise Exception( f'The input element for Update message must be tuple, got {ue}.' ) else: logger.error( f'The provided input for Set message (update operation) is not list.' ) raise Exception( 'The provided input for Set message (replace operation) is not list.' ) try: gnmi_message_request = SetRequest(delete=del_protobuf_paths, update=update_msg, replace=replace_msg) if self.__debug: print( "gNMI request:\n------------------------------------------------" ) print(gnmi_message_request) print("------------------------------------------------") gnmi_message_response = self.__stub.Set(gnmi_message_request, metadata=self.__metadata) if self.__debug: print( "\n\n\ngNMI response:\n------------------------------------------------" ) print(gnmi_message_response) print("------------------------------------------------") if gnmi_message_response: response = {} if gnmi_message_response.response: response.update({'response': []}) for response_entry in gnmi_message_response.response: response_container = {} if response_entry.path and response_entry.path.elem: resource_path = [] for path_elem in response_entry.path.elem: tp = '' if path_elem.name: tp += path_elem.name if path_elem.key: for pk_name, pk_value in sorted( path_elem.key.items()): tp += f'[{pk_name}={pk_value}]' resource_path.append(tp) response_container.update( {'path': '/'.join(resource_path)}) else: response_container.update({'path': None}) if response_entry.op: if response_entry.op == 1: res_op = 'DELETE' elif response_entry.op == 2: res_op = 'REPLACE' elif response_entry.op == 3: res_op = 'UPDATE' else: res_op = 'UNDEFINED' response_container.update({'op': res_op}) response['response'].append(response_container) return response else: logger.error('Failed parsing the SetResponse.') return None except grpc._channel._InactiveRpcError as err: print(f"Host: {self.__target_path}\nError: {err.details()}") logger.critical( f"GRPC ERROR Host: {self.__target_path}, Error: {err.details()}" ) raise Exception(err) except: logger.error(f'Collection of Set information failed is failed.') return None
def _build_subscriptionrequest(self, subscribe: dict): if not isinstance(subscribe, dict): raise ValueError( 'Subscribe subscribe request is specified, but the value is not dict.' ) request = SubscriptionList() # use_alias if 'use_aliases' not in subscribe: subscribe.update({'use_aliases': False}) if isinstance(subscribe['use_aliases'], bool): request.use_aliases = subscribe['use_aliases'] else: raise ValueError('Subsricbe use_aliases should have boolean type.') # mode if 'mode' not in subscribe: subscribe.update({'mode': 'stream'}) if subscribe['mode'].lower() in {'stream', 'once', 'poll'}: if subscribe['mode'].lower() == 'stream': request.mode = 0 elif subscribe['mode'].lower() == 'once': request.mode = 1 elif subscribe['mode'].lower() == 'poll': request.mode = 2 else: raise ValueError('Subscribe mode is out of allowed ranges.') # allow_aggregation if 'allow_aggregation' not in subscribe: subscribe.update({'allow_aggregation': False}) if isinstance(subscribe['allow_aggregation'], bool): request.allow_aggregation = subscribe['allow_aggregation'] else: raise ValueError( 'Subsricbe allow_aggregation should have boolean type.') # updates_only if 'updates_only' not in subscribe: subscribe.update({'updates_only': False}) if isinstance(subscribe['updates_only'], bool): request.updates_only = subscribe['updates_only'] else: raise ValueError( 'Subsricbe updates_only should have boolean type.') # encoding if 'encoding' not in subscribe: subscribe.update({'encoding': 'proto'}) if subscribe['encoding'].upper() in Encoding.keys(): request.encoding = Encoding.Value(subscribe['encoding'].upper()) else: raise ValueError( f'Subscribe encoding {subscribe["encoding"]} is out of allowed ranges.' ) # qos if 'qos' not in subscribe: subscribe.update({'qos': 0}) # if subscribe['qos'] >= 0 and subscribe['qos'] <= 64: # request.qos = QOSMarking(marking=subscribe['qos']) # use_models if 'use_models' not in subscribe: subscribe.update({'use_models': []}) if isinstance(subscribe['use_models'], list) and subscribe['use_models']: raise NotImplementedError( 'This will be done later at some point, if there is a need.') # prefix if 'prefix' not in subscribe: subscribe.update({'prefix': None}) if subscribe['prefix']: request.prefix = gnmi_path_generator(subscribe['prefix']) # subscription if 'subscription' not in subscribe or not subscribe['subscription']: raise ValueError('Subscribe:subscription value is missing.') for se in subscribe['subscription']: # path for that subscription if 'path' not in se: raise ValueError('Subscribe:subscription:path is missing') se_path = gnmi_path_generator(se['path']) # subscription entry mode; only relevent when the subscription request is stream if subscribe['mode'].lower() == 'stream': if 'mode' not in se: raise ValueError('Subscribe:subscription:mode is missing') se_mode = SubscriptionMode.Value(se['mode'].upper()) else: se_mode = 0 if 'sample_interval' in se and isinstance(se['sample_interval'], int): se_sample_interval = se['sample_interval'] else: se_sample_interval = 0 if 'suppress_redundant' in se and isinstance( se['suppress_redundant'], bool): se_suppress_redundant = se['suppress_redundant'] else: se_suppress_redundant = False if 'heartbeat_interval' in se and isinstance( se['heartbeat_interval'], int): se_heartbeat_interval = se['heartbeat_interval'] else: se_heartbeat_interval = 0 request.subscription.add(path=se_path, mode=se_mode, sample_interval=se_sample_interval, suppress_redundant=se_suppress_redundant, heartbeat_interval=se_heartbeat_interval) return SubscribeRequest(subscribe=request)
def get(self, path: list, datatype: str = 'all', encoding: str = 'json'): """ Collecting the information about the resources from defined paths. Path is provided as a list in the following format: path = ['yang-module:container/container[key=value]', 'yang-module:container/container[key=value]', ..] Available path formats: - yang-module:container/container[key=value] - /yang-module:container/container[key=value] - /yang-module:/container/container[key=value] - /container/container[key=value] - / The datatype argument may have the following values per gNMI specification: - all - config - state - operational The encoding argument may have the following values per gNMI specification: - json - bytes - proto - ascii - json_ietf """ logger.info(f'Collecting info from requested paths (Get operation)...') datatype = datatype.lower() type_dict = {'all', 'config', 'state', 'operational'} encoding_set = {'json', 'bytes', 'proto', 'ascii', 'json_ietf'} if datatype in type_dict: if datatype == 'all': pb_datatype = 0 elif datatype == 'config': pb_datatype = 1 elif datatype == 'state': pb_datatype = 2 elif datatype == 'operational': pb_datatype = 3 else: logger.error( 'The GetRequst data type is not within the dfined range') if encoding in encoding_set: if encoding.lower() == 'json': pb_encoding = 0 elif encoding.lower() == 'bytes': pb_encoding = 1 elif encoding.lower() == 'proto': pb_encoding = 2 elif encoding.lower() == 'ascii': pb_encoding = 3 else: pb_encoding = 4 try: if not path: protobuf_paths = [] protobuf_paths.append(gnmi_path_generator(path)) else: protobuf_paths = [gnmi_path_generator(pe) for pe in path] except: logger.error( f'Conversion of gNMI paths to the Protobuf format failed') raise Exception( 'Conversion of gNMI paths to the Protobuf format failed') if self.__capabilities and 'supported_encodings' in self.__capabilities: if 'json' in self.__capabilities['supported_encodings']: pb_encoding = 0 elif 'json_ietf' in self.__capabilities['supported_encodings']: pb_encoding = 4 try: gnmi_message_request = GetRequest(path=protobuf_paths, type=pb_datatype, encoding=pb_encoding) if self.__debug: print( "gNMI request:\n------------------------------------------------" ) print(gnmi_message_request) print("------------------------------------------------") gnmi_message_response = self.__stub.Get(gnmi_message_request, metadata=self.__metadata) if self.__debug: print( "\n\n\ngNMI response:\n------------------------------------------------" ) print(gnmi_message_response) print("------------------------------------------------") if gnmi_message_response: response = {} if gnmi_message_response.notification: response.update({'notification': []}) for notification in gnmi_message_response.notification: notification_container = {} notification_container.update( {'timestamp': notification.timestamp} ) if notification.timestamp else notification_container.update( {'timestamp': 0}) if notification.update: notification_container.update({'update': []}) for update_msg in notification.update: update_container = {} if update_msg.path and update_msg.path.elem: resource_path = [] for path_elem in update_msg.path.elem: tp = '' if path_elem.name: tp += path_elem.name if path_elem.key: for pk_name, pk_value in sorted( path_elem.key.items()): tp += f'[{pk_name}={pk_value}]' resource_path.append(tp) update_container.update( {'path': '/'.join(resource_path)}) else: update_container.update({'path': None}) if update_msg.HasField('val'): if update_msg.val.HasField( 'json_ietf_val'): update_container.update({ 'val': json.loads( update_msg.val.json_ietf_val) }) elif update_msg.val.HasField('json_val'): update_container.update({ 'val': json.loads(update_msg.val.json_val) }) elif update_msg.val.HasField('string_val'): update_container.update( {'val': update_msg.val.string_val}) elif update_msg.val.HasField('int_val'): update_container.update( {'val': update_msg.val.int_val}) elif update_msg.val.HasField('uint_val'): update_container.update( {'val': update_msg.val.uint_val}) elif update_msg.val.HasField('bool_val'): update_container.update( {'val': update_msg.val.bool_val}) elif update_msg.val.HasField('float_val'): update_container.update( {'val': update_msg.val.float_val}) elif update_msg.val.HasField( 'decimal_val'): update_container.update({ 'val': update_msg.val.decimal_val }) elif update_msg.val.HasField('any_val'): update_container.update( {'val': update_msg.val.any_val}) elif update_msg.val.HasField('ascii_val'): update_container.update( {'val': update_msg.val.ascii_val}) elif update_msg.val.HasField( 'proto_bytes'): update_container.update({ 'val': update_msg.val.proto_bytes }) notification_container['update'].append( update_container) response['notification'].append(notification_container) return response except grpc._channel._InactiveRpcError as err: print(f"Host: {self.__target_path}\nError: {err.details()}") logger.critical( f"GRPC ERROR Host: {self.__target_path}, Error: {err.details()}" ) raise Exception(err) except: logger.error(f'Collection of Get information failed is failed.') return None
def subscribe(self, subscribe: dict = None, poll: bool = False, aliases: list = None): """ Implentation of the subsrcibe gNMI RPC to pool """ logging.info(f'Collecting Telemetry...') if (subscribe and poll) or (subscribe and aliases) or (poll and aliases): raise Exception( 'Subscribe request supports only one request at a time.') if poll: if isinstance(poll, bool): if poll: request = Poll() gnmi_message_request = SubscribeRequest(poll=request) else: logging.error( 'Subscribe pool request is specificed, but the value is not boolean.' ) if aliases: if isinstance(aliases, list): request = AliasList() for ae in aliases: if isinstance(ae, tuple): if re.match('^#.*', ae[1]): request.alias.add(path=gnmi_path_generator(ae[0]), alias=ae[1]) else: raise ValueError( 'The alias is malformed. It should start with #...' ) gnmi_message_request = SubscribeRequest(aliases=request) else: logging.error( 'Subscribe aliases request is specified, but the value is not list.' ) if subscribe: if isinstance(subscribe, dict): request = SubscriptionList() # use_alias if 'use_aliases' not in subscribe: subscribe.update({'use_aliases': False}) if isinstance(subscribe['use_aliases'], bool): request.use_aliases = subscribe['use_aliases'] else: raise ValueError( 'Subsricbe use_aliases should have boolean type.') # mode if 'mode' not in subscribe: subscribe.update({'mode': 'stream'}) if subscribe['mode'].lower() in {'stream', 'once', 'poll'}: if subscribe['mode'].lower() == 'stream': request.mode = 0 elif subscribe['mode'].lower() == 'once': request.mode = 1 elif subscribe['mode'].lower() == 'poll': request.mode = 2 else: raise ValueError( 'Subscribe mode is out of allowed ranges.') # allow_aggregation if 'allow_aggregation' not in subscribe: subscribe.update({'allow_aggregation': False}) if isinstance(subscribe['allow_aggregation'], bool): request.allow_aggregation = subscribe['allow_aggregation'] else: raise ValueError( 'Subsricbe allow_aggregation should have boolean type.' ) # updates_only if 'updates_only' not in subscribe: subscribe.update({'updates_only': False}) if isinstance(subscribe['updates_only'], bool): request.updates_only = subscribe['updates_only'] else: raise ValueError( 'Subsricbe updates_only should have boolean type.') # encoding if 'encoding' not in subscribe: subscribe.update({'encoding': 'proto'}) if subscribe['encoding'].lower() in { 'json', 'bytes', 'proto', 'ascii', 'json_ietf' }: if subscribe['encoding'].lower() == 'json': request.encoding = 0 elif subscribe['encoding'].lower() == 'bytes': request.encoding = 1 elif subscribe['encoding'].lower() == 'proto': request.encoding = 2 elif subscribe['encoding'].lower() == 'ascii': request.encoding = 3 elif subscribe['encoding'].lower() == 'json_ietf': request.encoding = 4 else: raise ValueError( 'Subscribe encoding is out of allowed ranges.') # qos if 'qos' not in subscribe: subscribe.update({'qos': 0}) # if subscribe['qos'] >= 0 and subscribe['qos'] <= 64: # request.qos = QOSMarking(marking=subscribe['qos']) # use_models if 'use_models' not in subscribe: subscribe.update({'use_models': []}) if isinstance(subscribe['use_models'], list) and subscribe['use_models']: raise NotImplementedError( 'This will be done later at some point, if there is a need.' ) # prefix if 'prefix' not in subscribe: subscribe.update({'prefix': None}) if subscribe['prefix']: request.prefix = gnmi_path_generator(subscribe['prefix']) # subscription if 'subscription' not in subscribe: subscribe.update({'subscription': []}) if subscribe['subscription']: for se in subscribe['subscription']: if 'path' in se: v1 = gnmi_path_generator(se['path']) else: raise ValueError( 'Subscribe:subscription:path is missing') if 'mode' in se: if se['mode'].lower() in { 'target_defined', 'on_change', 'sample' }: if se['mode'].lower() == 'target_defined': v2 = 0 elif se['mode'].lower() == 'on_change': v2 = 1 elif se['mode'].lower() == 'sample': v2 = 2 else: raise ValueError( 'Subscribe:subscription:mode is not inside allowed range' ) else: raise ValueError( 'Subscribe:subscription:mode is missing') if 'sample_interval' in se and isinstance( se['sample_interval'], int): v3 = se['sample_interval'] else: v3 = 0 if 'suppress_redundant' in se and isinstance( se['suppress_redundant'], bool): v4 = se['suppress_redundant'] else: v4 = False if 'heartbeat_interval' in se and isinstance( se['heartbeat_interval'], int): v5 = se['heartbeat_interval'] else: v5 = 0 request.subscription.add(path=v1, mode=v2, sample_interval=v3, suppress_redundant=v4, heartbeat_interval=v5) else: raise ValueError( 'Subscribe:subscription value is missing.') gnmi_message_request = SubscribeRequest(subscribe=request) else: logging.error( 'Subscribe subscribe requst is specified, but the value is not list.' ) return self.__stub.Subscribe(self.__generator(gnmi_message_request), metadata=self.__metadata)
def set(self, delete: list = None, replace: list = None, update: list = None): """ Changing the configuration on the destination network elements. Could provide a single attribute or multiple attributes. delete: - list of paths with the resources to delete. The format is the same as for get() request replace: - list of tuples where the first entry path provided as a string, and the second entry is a dictionary with the configuration to be configured replace: - list of tuples where the first entry path provided as a string, and the second entry is a dictionary with the configuration to be configured """ del_protobuf_paths = [] replace_msg = [] update_msg = [] if delete: if isinstance(delete, list): try: del_protobuf_paths = [ gnmi_path_generator(pe) for pe in delete ] except: logging.error( f'Conversion of gNMI paths to the Protobuf format failed' ) sys.exit(10) else: logging.error( f'The provided input for Set message (delete operation) is not list.' ) sys.exit(10) if replace: if isinstance(replace, list): for ue in replace: if isinstance(ue, tuple): u_path = gnmi_path_generator(ue[0]) u_val = json.dumps(ue[1]).encode('utf-8') replace_msg.append( Update(path=u_path, val=TypedValue(json_val=u_val))) else: logging.error( f'The input element for Update message must be tuple, got {ue}.' ) sys.exit(10) else: logging.error( f'The provided input for Set message (replace operation) is not list.' ) sys.exit(10) if update: if isinstance(update, list): for ue in update: if isinstance(ue, tuple): u_path = gnmi_path_generator(ue[0]) u_val = json.dumps(ue[1]).encode('utf-8') update_msg.append( Update(path=u_path, val=TypedValue(json_val=u_val))) else: logging.error( f'The input element for Update message must be tuple, got {ue}.' ) sys.exit(10) else: logging.error( f'The provided input for Set message (update operation) is not list.' ) sys.exit(10) try: if self.__to_print: print( SetRequest(delete=del_protobuf_paths, update=update_msg, replace=replace_msg)) gnmi_message_request = SetRequest(delete=del_protobuf_paths, update=update_msg, replace=replace_msg) gnmi_message_response = self.__stub.Set(gnmi_message_request, metadata=self.__metadata) if self.__to_print: print(gnmi_message_response) if gnmi_message_response: response = {} if gnmi_message_response.response: response.update({'response': []}) for response_entry in gnmi_message_response.response: response_container = {} if response_entry.path and response_entry.path.elem: resource_path = [] for path_elem in response_entry.path.elem: tp = '' if path_elem.name: tp += path_elem.name if path_elem.key: for pk_name, pk_value in path_elem.key.items( ): tp += f'[{pk_name}={pk_value}]' resource_path.append(tp) response_container.update( {'path': '/'.join(resource_path)}) else: response_container.update({'path': None}) if response_entry.op: if response_entry.op == 1: res_op = 'DELETE' elif response_entry.op == 2: res_op = 'REPLACE' elif response_entry.op == 3: res_op = 'UPDATE' else: res_op = 'UNDEFINED' response_container.update({'op': res_op}) response['response'].append(response_container) return response else: logging.error('Failed parsing the SetResponse.') return None except grpc._channel._InactiveRpcError as err: print( f"Host: {self.__target[0]}:{self.__target[1]}\nError: {err.details()}" ) logging.critical( f"Host: {self.__target[0]}:{self.__target[1]}, Error: {err.details()}" ) sys.exit(10) except: logging.error(f'Collection of Set information failed is failed.') return None
def get(self, path: list, datatype: str = 'all'): """ Collecting the information about the resources from defined paths. Path is provided as a list in the following format: path = ['yang-module:container/container[key=value]', 'yang-module:container/container[key=value]', ..] The datatype argument may have the following value per gNMI specification: - all - config - state - operational """ logging.info( f'Collecting info from requested paths (Get opertaion)...') datatype = datatype.lower() type_dict = {'all', 'config', 'state', 'operational'} if datatype in type_dict: if datatype == 'all': pb_datatype = 0 elif datatype == 'config': pb_datatype = 1 elif datatype == 'state': pb_datatype = 2 elif datatype == 'operational': pb_datatype = 3 else: logging.error( 'The GetRequst data type is not within the dfined range') try: protobuf_paths = [gnmi_path_generator(pe) for pe in path] except: logging.error( f'Conversion of gNMI paths to the Protobuf format failed') sys.exit(10) if self.__capabilities and 'supported_encodings' in self.__capabilities: if 0 in self.__capabilities['supported_encodings']: enc = 0 elif 4 in self.__capabilities['supported_encodings']: enc = 4 else: enc = 0 try: gnmi_message_request = GetRequest(path=protobuf_paths, type=pb_datatype, encoding=enc) gnmi_message_response = self.__stub.Get(gnmi_message_request, metadata=self.__metadata) if self.__to_print: print(gnmi_message_response) if gnmi_message_response: response = {} if gnmi_message_response.notification: response.update({'notification': []}) for notification in gnmi_message_response.notification: notification_container = {} notification_container.update( {'timestamp': notification.timestamp} ) if notification.timestamp else notification_container.update( {'timestamp': 0}) if notification.update: notification_container.update({'update': []}) for update_msg in notification.update: update_container = {} if update_msg.path and update_msg.path.elem: resource_path = [] for path_elem in update_msg.path.elem: tp = '' if path_elem.name: tp += path_elem.name if path_elem.key: for pk_name, pk_value in path_elem.key.items( ): tp += f'[{pk_name}={pk_value}]' resource_path.append(tp) update_container.update( {'path': '/'.join(resource_path)}) else: update_container.update({'path': None}) if update_msg.HasField('val'): if update_msg.val.HasField( 'json_ietf_val'): update_container.update({ 'val': json.loads( update_msg.val.json_ietf_val) }) elif update_msg.val.HasField('json_val'): update_container.update({ 'val': json.loads(update_msg.val.json_val) }) notification_container['update'].append( update_container) response['notification'].append(notification_container) return response except grpc._channel._InactiveRpcError as err: print( f"Host: {self.__target[0]}:{self.__target[1]}\nError: {err.details()}" ) logging.critical( f"Host: {self.__target[0]}:{self.__target[1]}, Error: {err.details()}" ) sys.exit(10) except: logging.error(f'Collection of Get information failed is failed.') return None
def test_xpath(xpath, yangpath): compare_paths(gnmi_path_generator(xpath), yangpath)