Skip to content

Commit ce7c716

Browse files
authored
Add gnxi patch to fix poll mode in gnmi_cli (sonic-net#23123)
<!-- Please make sure you've read and understood our contributing guidelines: https://github.com/Azure/SONiC/blob/gh-pages/CONTRIBUTING.md failure_prs.log Make sure all your commits include a signature generated with `git commit -s` ** If this is a bug fix, make sure your description includes "fixes #xxxx", or "closes #xxxx" or "resolves #xxxx" Please provide the following information: --> #### Why I did it POLL mode fails with "invalid argument" when executing gnmi_cli_py --subscribe_mode 2. Fixes poll mode queries. Also adds escape '/' logic into py_gnmi_cli similiar to how its done in openconfig. openconfig/gnmi@c0a4ed7 ##### Work item tracking - Microsoft ADO **(number only)**: #### How I did it Check for subscribe mode POLL, send poll requests at interval. #### How to verify it Run gnmi_cli_py POLL mode <!-- If PR needs to be backported, then the PR must be tested against the base branch and the earliest backport release branch and provide tested image version on these two branches. For example, if the PR is requested for master, 202211 and 202012, then the requester needs to provide test results on master and 202012. --> #### Which release branch to backport (provide reason below if selected) <!-- - Note we only backport fixes to a release branch, *not* features! - Please also provide a reason for the backporting below. - e.g. - [x] 202006 --> - [ ] 201811 - [ ] 201911 - [ ] 202006 - [ ] 202012 - [ ] 202106 - [ ] 202111 - [ ] 202205 - [ ] 202211 - [ ] 202305 #### Tested branch (Please provide the tested image version) <!-- - Please provide tested image version - e.g. - [x] 20201231.100 --> - [ ] <!-- image version 1 --> - [ ] <!-- image version 2 --> #### Description for the changelog <!-- Write a short (one line) summary that describes the changes in this pull request for inclusion in the changelog: --> <!-- Ensure to add label/tag for the feature raised. example - PR#2174 under sonic-utilities repo. where, Generic Config and Update feature has been labelled as GCU. --> #### Link to config_db schema for YANG module changes <!-- Provide a link to config_db schema for the table for which YANG model is defined Link should point to correct section on https://github.com/Azure/sonic-buildimage/blob/master/src/sonic-yang-models/doc/Configuration.md --> #### A picture of a cute animal (not mandatory but encouraged)
1 parent 74680ea commit ce7c716

2 files changed

Lines changed: 113 additions & 1 deletion

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
From 8bda329bbcf455b7d403b1d1b06bb616578615c7 Mon Sep 17 00:00:00 2001
2+
From: Zain Budhwani <[email protected]>
3+
Date: Mon, 21 Apr 2025 20:55:38 +0000
4+
Subject: [PATCH] Fix py_gnmicli.py POLL mode
5+
6+
---
7+
gnmi_cli_py/py_gnmicli.py | 26 ++++++++++++++++++++++++--
8+
1 file changed, 24 insertions(+), 2 deletions(-)
9+
10+
diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py
11+
index 0ea6f3d..473d193 100644
12+
--- a/gnmi_cli_py/py_gnmicli.py
13+
+++ b/gnmi_cli_py/py_gnmicli.py
14+
@@ -39,6 +39,7 @@ import ssl
15+
import sys
16+
import string
17+
import six
18+
+import time
19+
import datetime
20+
try:
21+
import gnmi_pb2
22+
@@ -47,6 +48,7 @@ except ImportError:
23+
'eg, pip install -r requirements.txt')
24+
import gnmi_pb2_grpc
25+
import grpc
26+
+from gnmi_pb2 import Poll
27+
28+
__version__ = '0.5'
29+
30+
@@ -153,6 +155,8 @@ def _create_parser():
31+
required=False, action='store_true')
32+
parser.add_argument('--interval', default=10000, type=int,
33+
help='sample interval in millisecond (default: 10000ms)')
34+
+ parser.add_argument('--polling_interval', default=10, type=int,
35+
+ help='polling interval in second (default: 10)')
36+
parser.add_argument('--timeout', type=int, help='subscription'
37+
'duration in seconds (default: none)')
38+
parser.add_argument('--heartbeat', default=0, type=int, help='heartbeat interval (default: None)')
39+
@@ -161,6 +165,7 @@ def _create_parser():
40+
parser.add_argument('--submode', default=2, type=int,
41+
help='subscription mode [0=TARGET_DEFINED, 1=ON_CHANGE, 2=SAMPLE]')
42+
parser.add_argument('--update_count', default=0, type=int, help='Max number of streaming updates to receive. 0 means no limit.')
43+
+ parser.add_argument('--max_sync_count', default=-1, type=int, help='Max number of sync responses to receive. -1 means no limit.')
44+
parser.add_argument('--subscribe_mode', default=0, type=int, help='[0=STREAM, 1=ONCE, 2=POLL]')
45+
parser.add_argument('--encoding', default=0, type=int, help='[0=JSON, 1=BYTES, 2=PROTO, 3=ASCII, 4=JSON_IETF]')
46+
parser.add_argument('--qos', default=0, type=int, help='')
47+
@@ -203,11 +208,17 @@ def _path_names(xpath):
48+
# Split the given string using unescaped '/'.
49+
while end < len(xpath):
50+
if xpath[end] == '/':
51+
+ if end > 0:
52+
+ if xpath[end-1] == '\\':
53+
+ end += 1
54+
+ continue
55+
if not insideBrackets:
56+
# Current '/' is a valid path element
57+
# separator.
58+
if end > begin:
59+
- path.append(xpath[begin:end])
60+
+ element = xpath[begin:end]
61+
+ element = element.replace('\\', '')
62+
+ path.append(element)
63+
end += 1
64+
begin = end
65+
else:
66+
@@ -473,6 +484,11 @@ def gen_request(paths, opt, prefix):
67+
print('Sending SubscribeRequest\n'+str(mysubreq))
68+
yield mysubreq
69+
70+
+ if opt["subscribe_mode"] == gnmi_pb2.SubscriptionList.POLL:
71+
+ while True:
72+
+ poll_request = gnmi_pb2.SubscribeRequest(poll = Poll())
73+
+ yield poll_request
74+
+ time.sleep(opt["polling_interval"])
75+
76+
def check_event_response(response, filter_event_regex):
77+
resp = str(response)
78+
@@ -491,15 +507,21 @@ def subscribe_start(stub, options, req_iterator):
79+
"""
80+
metadata = [('username', options['username']), ('password', options['password'])]
81+
max_update_count = options["update_count"]
82+
+ max_sync_count = options["max_sync_count"]
83+
filter_event_regex = options["filter_event_regex"]
84+
85+
try:
86+
responses = stub.Subscribe(req_iterator, options['timeout'], metadata=metadata)
87+
update_count = 0
88+
+ sync_count = 0
89+
for response in responses:
90+
+ if sync_count != -1 and sync_count == max_sync_count:
91+
+ print("Max sync responses count reached {0}".format(sync_count))
92+
+ break
93+
print('{0} response received: '.format(datetime.datetime.now()))
94+
if response.HasField('sync_response'):
95+
print(str(response))
96+
+ sync_count = sync_count + 1
97+
elif response.HasField('error'):
98+
print('gNMI Error '+str(response.error.code)+\
99+
' received\n'+str(response.error.message) + str(response.error))
100+
@@ -517,7 +539,7 @@ def subscribe_start(stub, options, req_iterator):
101+
update_count = update_count+1
102+
else:
103+
print('Unknown response received:\n'+str(response))
104+
-
105+
+
106+
if max_update_count != 0 and update_count == max_update_count:
107+
print("Max update count reached {0}".format(update_count))
108+
break
109+
--
110+
2.25.1
111+

dockers/docker-ptf/gnxi-patches/series

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
0003-gNMI_client-Add-an-option-to-trigger-memory-spike-on.patch
44
0004-Add-support-for-streaming-structured-events-in-night.patch
55
0005-Enhance-gnmi_cli_py-4.patch
6-
0006-Add-support-for-extensive-configurations.patch
6+
0006-Add-support-for-extensive-configurations.patch
7+
0007-Fix-py_gnmicli.py-POLL-mode.patch

0 commit comments

Comments
 (0)