pygnmi icon indicating copy to clipboard operation
pygnmi copied to clipboard

_merge_updates() does not handle case where new_resp is None

Open ipmonk opened this issue 2 years ago • 4 comments

Crash seen when connecting to a Juniper box running Junos: 21.4R2-S1.12-EVO

# Modules
from pygnmi.client import gNMIclient, telemetryParser

# Variables
host = ('1.1.1.1', '50051')

# Body
subscribe = {
    'subscription': [
        {
            'path': '/components/component',
            'mode': 'sample',
            'sample_interval': 10000000000
        },
    ],
    'use_aliases': False,
    'mode': 'stream',
    'encoding': 'json'
}

if __name__ == '__main__':
    with gNMIclient(target=host, username='foo', password='lab123', insecure=True) as gc:
        telemetry_stream = gc.subscribe_stream(subscribe=subscribe)
        for telemetry_entry in telemetry_stream:
            print(telemetry_entry)

resulted in an unhandled exception:

Parsing of telemetry information is failed.
Traceback (most recent call last):
  File "/Users/foo/scripts/foo/gnmi-scripts/subscribe.py", line 25, in <module>
Exception in thread Thread-5:
Traceback (most recent call last):
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/threading.py", line 973, in _bootstrap_inner
    for telemetry_entry in telemetry_stream:
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/pygnmi/client.py", line 973, in __next__
    self.run()
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/threading.py", line 910, in run
    result = self.next()
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/pygnmi/client.py", line 985, in next
    self._target(*self._args, **self._kwargs)
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/pygnmi/client.py", line 908, in enqueue_updates
    return self._next_update(timeout=None)
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/pygnmi/client.py", line 1036, in _next_update
    for update in subscription:
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/grpc/_channel.py", line 426, in __next__
    return self._get_updates_till_sync(timeout=timeout)
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/pygnmi/client.py", line 949, in _get_updates_till_sync
    return self._next()
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/grpc/_channel.py", line 809, in _next
    self._merge_updates(resp, new_resp)
  File "/Users/foo/scripts/foo/gnmi-scripts/venv/lib/python3.9/site-packages/pygnmi/client.py", line 954, in _merge_updates
    if 'update' in new_resp:
TypeError: argument of type 'NoneType' is not iterable
    raise self
grpc._channel._MultiThreadedRendezvous: <_MultiThreadedRendezvous of RPC that terminated with:
	status = StatusCode.CANCELLED
	details = "Channel closed!"
	debug_error_string = "UNKNOWN:Error received from peer 1.1.1.1:50051 {grpc_message:"Channel closed!", grpc_status:1, created_time:"2022-10-25T18:22:42.347026+11:00"}"

workaround was to add a line to client.py in _merge_updates()

    def _merge_updates(self, resp, new_resp):
        if new_resp is not None:         ### adding this line
            if 'update' in new_resp:
                for key in new_resp['update']:
                    if key.upper() in UpdateResult.Operation.keys():
                        if key not in resp['update']:
                            resp['update'][key] = []
                        resp['update'][key] += new_resp['update'][key]
                    else:
                        resp['update'][key] = new_resp['update'][key]
            if 'sync_response' in new_resp:
                resp['sync_response'] = new_resp['sync_response']

ipmonk avatar Oct 25 '22 07:10 ipmonk