Skip to content

Commit 866acb6

Browse files
liuh-80yanjundeng
authored andcommitted
Change PTF docker image to use GNXI from google repo (sonic-net#22062)
Change PTF docker image to use GNXI from google repo #### Why I did it Currently PTF docker using GNXI from a private repo #### How I did it Change PTF docker image to use GNXI from google repo Generate patch file from private repo and apply to google repo. #### How to verify it Pass all test case. Download ptf docker image and verified the patched GNXI is same with private repo. #### Description for the changelog Change PTF docker image to use GNXI from google repo
1 parent 6a8a3ff commit 866acb6

7 files changed

+834
-3
lines changed

dockers/docker-ptf/Dockerfile.j2

+9-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ RUN apt-get update \
9292
automake \
9393
iproute2 \
9494
wireshark-common \
95-
freeradius
95+
freeradius \
96+
quilt
9697

9798
{% if PTF_ENV_PY_VER == "py3" %}
9899
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1 \
@@ -261,9 +262,14 @@ RUN ln -s /usr/bin/tcpdump /usr/sbin/tcpdump
261262
RUN mkdir -p /var/log/supervisor
262263

263264
# Install Python-based GNMI client
264-
RUN git clone https://github.com/lguohan/gnxi.git \
265+
RUN git clone https://github.com/google/gnxi.git \
265266
&& cd gnxi \
266-
&& git checkout 3adf8b9 \
267+
&& git checkout 208acfa85f5b5b8717e14896e9d6ee93cfda9d5f
268+
269+
COPY gnxi-patches/ gnxi/patches/
270+
271+
RUN cd gnxi \
272+
&& quilt push -a \
267273
&& cd gnmi_cli_py \
268274
{% if PTF_ENV_PY_VER == "mixed" %}
269275
&& pip install -r requirements.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
From d01b36e471f387007680e0f07d8bfe32db8e0269 Mon Sep 17 00:00:00 2001
2+
From: Guohan Lu <[email protected]>
3+
Date: Fri, 3 Jul 2020 09:17:32 +0000
4+
Subject: [PATCH 1/5] add xpath_target option
5+
6+
Signed-off-by: Guohan Lu <[email protected]>
7+
---
8+
gnmi_cli_py/py_gnmicli.py | 19 ++++++++++++-------
9+
1 file changed, 12 insertions(+), 7 deletions(-)
10+
11+
diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py
12+
index 7c9e92b..062dee7 100644
13+
--- a/gnmi_cli_py/py_gnmicli.py
14+
+++ b/gnmi_cli_py/py_gnmicli.py
15+
@@ -126,6 +126,9 @@ def _create_parser():
16+
required=False, action='store_true')
17+
parser.add_argument('-x', '--xpath', type=str, help='The gNMI path utilized'
18+
'in the GetRequest or Subscirbe', required=True)
19+
+ parser.add_argument('-xt', '--xpath_target', type=str, help='The gNMI prefix'
20+
+ 'target in the GetRequest or Subscirbe', default=None,
21+
+ required=False)
22+
parser.add_argument('-o', '--host_override', type=str, help='Use this as '
23+
'Targets hostname/peername when checking it\'s'
24+
'certificate CN. You can check the cert with:\nopenssl '
25+
@@ -258,7 +261,7 @@ def _get_val(json_value):
26+
return val
27+
28+
29+
-def _get(stub, paths, username, password):
30+
+def _get(stub, paths, username, password, prefix):
31+
"""Create a gNMI GetRequest.
32+
33+
Args:
34+
@@ -266,16 +269,17 @@ def _get(stub, paths, username, password):
35+
paths: gNMI Path
36+
username: (str) Username used when building the channel.
37+
password: (str) Password used when building the channel.
38+
+ prefix: gNMI Path
39+
40+
Returns:
41+
a gnmi_pb2.GetResponse object representing a gNMI GetResponse.
42+
"""
43+
+ kwargs = {}
44+
if username: # User/pass supplied for Authentication.
45+
- return stub.Get(
46+
- gnmi_pb2.GetRequest(path=[paths], encoding='JSON_IETF'),
47+
- metadata=[('username', username), ('password', password)])
48+
- return stub.Get(gnmi_pb2.GetRequest(path=[paths], encoding='JSON_IETF'))
49+
-
50+
+ kwargs = {'metadata': [('username', username), ('password', password)]}
51+
+ return stub.Get(
52+
+ gnmi_pb2.GetRequest(prefix=prefix, path=[paths], encoding='JSON_IETF'),
53+
+ **kwargs)
54+
55+
def _set(stub, paths, set_type, username, password, json_value):
56+
"""Create a gNMI SetRequest.
57+
@@ -368,6 +372,7 @@ def main():
58+
json_value = args['value']
59+
private_key = args['private_key']
60+
xpath = args['xpath']
61+
+ prefix = gnmi_pb2.Path(target=args['xpath_target'])
62+
host_override = args['host_override']
63+
user = args['username']
64+
password = args['password']
65+
@@ -381,7 +386,7 @@ def main():
66+
if mode == 'get':
67+
print('Performing GetRequest, encoding=JSON_IETF', 'to', target,
68+
' with the following gNMI Path\n', '-'*25, '\n', paths)
69+
- response = _get(stub, paths, user, password)
70+
+ response = _get(stub, paths, user, password, prefix)
71+
print('The GetResponse is below\n' + '-'*25 + '\n')
72+
if form == 'protobuff':
73+
print(response)
74+
--
75+
2.48.1.windows.1
76+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
From 53901aba9ead82be21f1408a601b6266dcf1e3e4 Mon Sep 17 00:00:00 2001
2+
From: macikgozwa <[email protected]>
3+
Date: Mon, 9 Nov 2020 16:19:24 -0800
4+
Subject: [PATCH 2/5] Adding support for subscribe mode (#1)
5+
6+
- Adding support for subscribe mode. The code is mostly based on this patch: https://github.com/google/gnxi/pull/65
7+
- Adding a new parameter to limit the number of updates, e.g. after a number of streaming updates the client would stop listening. It is convenient for testing purposes.
8+
- Changing the sample interval unit to millisecond. This is also required for testing cases.
9+
10+
Co-authored-by: Murat Acikgoz <[email protected]>
11+
---
12+
gnmi_cli_py/py_gnmicli.py | 102 +++++++++++++++++++++++++++++++++++---
13+
1 file changed, 95 insertions(+), 7 deletions(-)
14+
15+
diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py
16+
index 062dee7..7152f13 100644
17+
--- a/gnmi_cli_py/py_gnmicli.py
18+
+++ b/gnmi_cli_py/py_gnmicli.py
19+
@@ -24,9 +24,7 @@ Current supported gNMI features:
20+
- Auto-loads Target cert from Target if not specified
21+
- User/password based authentication
22+
- Certifificate based authentication
23+
-
24+
-Current unsupported gNMI features:
25+
-- Subscribe
26+
+- Subscribe request
27+
"""
28+
29+
from __future__ import absolute_import
30+
@@ -40,14 +38,16 @@ import re
31+
import ssl
32+
import sys
33+
import six
34+
+import datetime
35+
try:
36+
import gnmi_pb2
37+
except ImportError:
38+
print('ERROR: Ensure you\'ve installed dependencies from requirements.txt\n'
39+
'eg, pip install -r requirements.txt')
40+
import gnmi_pb2_grpc
41+
+import grpc
42+
43+
-__version__ = '0.4'
44+
+__version__ = '0.5'
45+
46+
_RE_PATH_COMPONENT = re.compile(r'''
47+
^
48+
@@ -143,6 +143,21 @@ def _create_parser():
49+
required=False, action='store_true')
50+
parser.add_argument('-n', '--notls', help='gRPC insecure mode',
51+
required=False, action='store_true')
52+
+ parser.add_argument('--interval', default=10000, type=int,
53+
+ help='sample interval in millisecond (default: 10000ms)')
54+
+ parser.add_argument('--timeout', type=int, help='subscription'
55+
+ 'duration in seconds (default: none)')
56+
+ parser.add_argument('--heartbeat', default=0, type=int, help='heartbeat interval (default: None)')
57+
+ parser.add_argument('--aggregate', action='store_true', help='allow aggregation')
58+
+ parser.add_argument('--suppress', action='store_true', help='suppress redundant')
59+
+ parser.add_argument('--submode', default=2, type=int,
60+
+ help='subscription mode [0=TARGET_DEFINED, 1=ON_CHANGE, 2=SAMPLE]')
61+
+ parser.add_argument('--update_count', default=0, type=int, help='Max number of streaming updates to receive. 0 means no limit.')
62+
+ parser.add_argument('--subscribe_mode', default=0, type=int, help='[0=STREAM, 1=ONCE, 2=POLL]')
63+
+ parser.add_argument('--encoding', default=0, type=int, help='[0=JSON, 1=BYTES, 2=PROTO, 3=ASCII, 4=JSON_IETF]')
64+
+ parser.add_argument('--qos', default=0, type=int, help='')
65+
+ parser.add_argument('--use_alias', action='store_true', help='use alias')
66+
+ parser.add_argument('--prefix', default='', help='gRPC path prefix (default: none)')
67+
return parser
68+
69+
70+
@@ -353,6 +368,79 @@ def _open_certs(**kwargs):
71+
return kwargs
72+
73+
74+
+def gen_request(paths, opt, prefix):
75+
+ """Create subscribe request for passed xpath.
76+
+ Args:
77+
+ paths: (str) gNMI path.
78+
+ opt: (dict) Command line argument passed for subscribe reqeust.
79+
+ Returns:
80+
+ gNMI SubscribeRequest object.
81+
+ """
82+
+ mysubs = []
83+
+ mysub = gnmi_pb2.Subscription(path=paths, mode=opt["submode"],
84+
+ sample_interval=opt["interval"]*1000000,
85+
+ heartbeat_interval=opt['heartbeat']*1000000,
86+
+ suppress_redundant=opt['suppress'])
87+
+ mysubs.append(mysub)
88+
+
89+
+ if prefix:
90+
+ myprefix = prefix
91+
+ elif opt["prefix"]:
92+
+ myprefix = _parse_path(_path_names(opt["prefix"]))
93+
+ else:
94+
+ myprefix = None
95+
+
96+
+ if opt["qos"]:
97+
+ myqos = gnmi_pb2.QOSMarking(marking=opt["qos"])
98+
+ else:
99+
+ myqos = None
100+
+ mysblist = gnmi_pb2.SubscriptionList(prefix=myprefix, mode=opt['subscribe_mode'],
101+
+ allow_aggregation=opt['aggregate'], encoding=opt['encoding'],
102+
+ subscription=mysubs, use_aliases=opt['use_alias'], qos=myqos)
103+
+ mysubreq = gnmi_pb2.SubscribeRequest(subscribe=mysblist)
104+
+
105+
+ print('Sending SubscribeRequest\n'+str(mysubreq))
106+
+ yield mysubreq
107+
+
108+
+
109+
+def subscribe_start(stub, options, req_iterator):
110+
+ """ RPC Start for Subscribe reqeust
111+
+ Args:
112+
+ stub: (class) gNMI Stub used to build the secure channel.
113+
+ options: (dict) Command line argument passed for subscribe reqeust.
114+
+ req_iterator: gNMI Subscribe Request from gen_request.
115+
+ Returns:
116+
+ Start Subscribe and printing response of gNMI Subscribe Response.
117+
+ """
118+
+ metadata = [('username', options['username']), ('password', options['password'])]
119+
+ max_update_count = options["update_count"]
120+
+ try:
121+
+ responses = stub.Subscribe(req_iterator, options['timeout'], metadata=metadata)
122+
+ update_count = 0
123+
+ for response in responses:
124+
+ print('{0} response received: '.format(datetime.datetime.now()))
125+
+ if response.HasField('sync_response'):
126+
+ print(str(response))
127+
+ elif response.HasField('error'):
128+
+ print('gNMI Error '+str(response.error.code)+\
129+
+ ' received\n'+str(response.error.message) + str(response.error))
130+
+ elif response.HasField('update'):
131+
+ print(response)
132+
+ update_count = update_count+1
133+
+ else:
134+
+ print('Unknown response received:\n'+str(response))
135+
+
136+
+ if max_update_count != 0 and update_count == max_update_count:
137+
+ print("Max update count reached {0}".format(update_count))
138+
+ break
139+
+ except KeyboardInterrupt:
140+
+ print("Subscribe Session stopped by user.")
141+
+ except grpc.RpcError as x:
142+
+ print("grpc.RpcError received:\n%s" %x)
143+
+ except Exception as err:
144+
+ print(err)
145+
+
146+
+
147+
def main():
148+
argparser = _create_parser()
149+
args = vars(argparser.parse_args())
150+
@@ -414,9 +502,9 @@ def main():
151+
response = _set(stub, paths, 'delete', user, password, json_value)
152+
print('The SetRequest response is below\n' + '-'*25 + '\n', response)
153+
elif mode == 'subscribe':
154+
- print('This mode not available in this version')
155+
- sys.exit()
156+
+ request_iterator = gen_request(paths, args, prefix)
157+
+ subscribe_start(stub, args, request_iterator)
158+
159+
160+
if __name__ == '__main__':
161+
- main()
162+
+ main()
163+
\ No newline at end of file
164+
--
165+
2.48.1.windows.1
166+

0 commit comments

Comments
 (0)