akarneliuk / pygnmi

The pure Python implementation of the gNMI client.
https://training.karneliuk.com
BSD 3-Clause "New" or "Revised" License
129 stars 44 forks source link

sub `once` doesnt close the session #72

Closed ksator closed 2 years ago

ksator commented 2 years ago

Hello

arista@devbox:~$ pip freeze | grep pyg
pygnmi==0.7.4
arista@devbox:~$ 

would like to use pygnmi with the sub rpc with once.

arista@devbox:~$ cat test7.py 
"""
pygnmi script
"""
from pygnmi.client import gNMIclient

TELEMETRY_REQUEST = {
                         'subscription': [
                             {
                                 'path': '/inventory/state/device/device-id'
                             }
                         ],
                         'mode': 'once',
                         'encoding': 'json'
                     }

with open("token.tok") as f:
    TOKEN = f.read().strip('\n')

if __name__ == "__main__":
     with gNMIclient(target=('192.168.0.5', '443'), token=TOKEN, skip_verify=True) as gconn:
         inventory = gconn.subscribe2(subscribe=TELEMETRY_REQUEST)
         for device in inventory:
                print(device)

It works
but it doesnt close the session as you can see below ... (so I did CNTL + C to stop it)

rista@devbox:~$ python test7.py 
ssl_target_name_override is applied, should be used for testing only!
{'update': {'update': [{'path': 'inventory/state/device[device-id=cvx01]/device-id', 'val': 'cvx01'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf3]/device-id', 'val': 'leaf3'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf4]/device-id', 'val': 'leaf4'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=host1]/device-id', 'val': 'host1'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=spine1]/device-id', 'val': 'spine1'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=spine2]/device-id', 'val': 'spine2'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf1]/device-id', 'val': 'leaf1'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf2]/device-id', 'val': 'leaf2'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=host2]/device-id', 'val': 'host2'}], 'timestamp': 1657867500000000000, 'prefix': ''}}
{'sync_response': True}

^CTraceback (most recent call last):
  File "/home/arista/test7.py", line 22, in <module>
    for device in inventory:
  File "/home/arista/.local/lib/python3.9/site-packages/pygnmi/client.py", line 990, in __next__
    return self.next()
  File "/home/arista/.local/lib/python3.9/site-packages/pygnmi/client.py", line 996, in next
    return self._next_update(timeout=None)
  File "/home/arista/.local/lib/python3.9/site-packages/pygnmi/client.py", line 1066, in _next_update
    return self._get_one_update(timeout=timeout)
  File "/home/arista/.local/lib/python3.9/site-packages/pygnmi/client.py", line 959, in _get_one_update
    return telemetryParser(self._updates.get(block=True, timeout=timeout))
  File "/usr/local/lib/python3.9/queue.py", line 171, in get
    self.not_empty.wait()
  File "/usr/local/lib/python3.9/threading.py", line 312, in wait
    waiter.acquire()
KeyboardInterrupt

arista@devbox:~$ 

gnmic equivalent command (it is OK i.e it stops by itself i.e no need to CNTL + C)

arista@devbox:~$ gnmic -a 192.168.0.5:443 --mode=once subscribe --path /inventory/state/device/device-id --token=`cat token.tok` --skip-verify

fyi pygnmi using sub and stream instead of once is OK

"""
pygnmi script
"""

from pygnmi.client import gNMIclient

TELEMETRY_REQUEST = {
                         'subscription': [
                             {
                                 'path': '/inventory/state/device/device-id',
                                 'mode': 'target_defined'
                             }
                         ],
                         'mode': 'stream',
                         'encoding': 'json'
                     }

with open("token.tok") as f:
    TOKEN = f.read().strip('\n')

if __name__ == "__main__":
    with gNMIclient(target=('192.168.0.5', '443'), token=TOKEN, skip_verify=True) as gconn:
        inventory = gconn.subscribe2(subscribe=TELEMETRY_REQUEST)
        for device in inventory:
            print(device)
akarneliuk commented 2 years ago

Hello @ksator ,

as usual, thanks a lot for raising requests. We've amended the logic for the iterator class in case the telemetry mode is once. Now it will automatically terminate once it receives {"sync_response": True} message, whilst the message itself also pass to the results. This functionality is available in the latest 0.7.5 release.

Best, Anton

ksator commented 2 years ago

Hello @akarneliuk Thank you so much. It works using 0.7.5.

arista@devbox:~$ pip freeze | grep pyg
pygnmi==0.7.5
arista@devbox:~$ 
arista@devbox:~$ cat test.py 
"""
pygnmi script
"""
from pygnmi.client import gNMIclient

TELEMETRY_REQUEST = {
                         'subscription': [
                             {
                                 'path': '/inventory/state/device/device-id'
                             }
                         ],
                         'mode': 'once',
                         'encoding': 'json'
                     }

with open("token.tok") as f:
    TOKEN = f.read().strip('\n')

if __name__ == "__main__":
     with gNMIclient(target=('192.168.0.5', '443'), token=TOKEN, skip_verify=True) as gconn:
         inventory = gconn.subscribe2(subscribe=TELEMETRY_REQUEST)
         for device in inventory:
                print(device)

arista@devbox:~$ 
arista@devbox:~$ python test.py 
ssl_target_name_override is applied, should be used for testing only!
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf3]/device-id', 'val': 'leaf3'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=spine2]/device-id', 'val': 'spine2'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=cvx01]/device-id', 'val': 'cvx01'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf2]/device-id', 'val': 'leaf2'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=spine1]/device-id', 'val': 'spine1'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=host2]/device-id', 'val': 'host2'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf1]/device-id', 'val': 'leaf1'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=leaf4]/device-id', 'val': 'leaf4'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'update': {'update': [{'path': 'inventory/state/device[device-id=host1]/device-id', 'val': 'host1'}], 'timestamp': 1658062800000000000, 'prefix': ''}}
{'sync_response': True}
arista@devbox:~$ 

so I am closing this issue.

Thanks!