Skip to content

Change PTF docker image to use GNXI from google repo #22062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions dockers/docker-ptf/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ RUN apt-get update \
automake \
iproute2 \
wireshark-common \
freeradius
freeradius \
quilt

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

# Install Python-based GNMI client
RUN git clone https://github.com/lguohan/gnxi.git \
RUN git clone https://github.com/google/gnxi.git \
&& cd gnxi \
&& git checkout 3adf8b9 \
&& git checkout 208acfa85f5b5b8717e14896e9d6ee93cfda9d5f

COPY gnxi-patches/ gnxi/patches/

RUN cd gnxi \
&& quilt push -a \
&& cd gnmi_cli_py \
{% if PTF_ENV_PY_VER == "mixed" %}
&& pip install -r requirements.txt
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
From d01b36e471f387007680e0f07d8bfe32db8e0269 Mon Sep 17 00:00:00 2001
From: Guohan Lu <[email protected]>
Date: Fri, 3 Jul 2020 09:17:32 +0000
Subject: [PATCH 1/5] add xpath_target option

Signed-off-by: Guohan Lu <[email protected]>
---
gnmi_cli_py/py_gnmicli.py | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py
index 7c9e92b..062dee7 100644
--- a/gnmi_cli_py/py_gnmicli.py
+++ b/gnmi_cli_py/py_gnmicli.py
@@ -126,6 +126,9 @@ def _create_parser():
required=False, action='store_true')
parser.add_argument('-x', '--xpath', type=str, help='The gNMI path utilized'
'in the GetRequest or Subscirbe', required=True)
+ parser.add_argument('-xt', '--xpath_target', type=str, help='The gNMI prefix'
+ 'target in the GetRequest or Subscirbe', default=None,
+ required=False)
parser.add_argument('-o', '--host_override', type=str, help='Use this as '
'Targets hostname/peername when checking it\'s'
'certificate CN. You can check the cert with:\nopenssl '
@@ -258,7 +261,7 @@ def _get_val(json_value):
return val


-def _get(stub, paths, username, password):
+def _get(stub, paths, username, password, prefix):
"""Create a gNMI GetRequest.

Args:
@@ -266,16 +269,17 @@ def _get(stub, paths, username, password):
paths: gNMI Path
username: (str) Username used when building the channel.
password: (str) Password used when building the channel.
+ prefix: gNMI Path

Returns:
a gnmi_pb2.GetResponse object representing a gNMI GetResponse.
"""
+ kwargs = {}
if username: # User/pass supplied for Authentication.
- return stub.Get(
- gnmi_pb2.GetRequest(path=[paths], encoding='JSON_IETF'),
- metadata=[('username', username), ('password', password)])
- return stub.Get(gnmi_pb2.GetRequest(path=[paths], encoding='JSON_IETF'))
-
+ kwargs = {'metadata': [('username', username), ('password', password)]}
+ return stub.Get(
+ gnmi_pb2.GetRequest(prefix=prefix, path=[paths], encoding='JSON_IETF'),
+ **kwargs)

def _set(stub, paths, set_type, username, password, json_value):
"""Create a gNMI SetRequest.
@@ -368,6 +372,7 @@ def main():
json_value = args['value']
private_key = args['private_key']
xpath = args['xpath']
+ prefix = gnmi_pb2.Path(target=args['xpath_target'])
host_override = args['host_override']
user = args['username']
password = args['password']
@@ -381,7 +386,7 @@ def main():
if mode == 'get':
print('Performing GetRequest, encoding=JSON_IETF', 'to', target,
' with the following gNMI Path\n', '-'*25, '\n', paths)
- response = _get(stub, paths, user, password)
+ response = _get(stub, paths, user, password, prefix)
print('The GetResponse is below\n' + '-'*25 + '\n')
if form == 'protobuff':
print(response)
--
2.48.1.windows.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
From 53901aba9ead82be21f1408a601b6266dcf1e3e4 Mon Sep 17 00:00:00 2001
From: macikgozwa <[email protected]>
Date: Mon, 9 Nov 2020 16:19:24 -0800
Subject: [PATCH 2/5] Adding support for subscribe mode (#1)

- Adding support for subscribe mode. The code is mostly based on this patch: https://github.com/google/gnxi/pull/65
- 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.
- Changing the sample interval unit to millisecond. This is also required for testing cases.

Co-authored-by: Murat Acikgoz <[email protected]>
---
gnmi_cli_py/py_gnmicli.py | 102 +++++++++++++++++++++++++++++++++++---
1 file changed, 95 insertions(+), 7 deletions(-)

diff --git a/gnmi_cli_py/py_gnmicli.py b/gnmi_cli_py/py_gnmicli.py
index 062dee7..7152f13 100644
--- a/gnmi_cli_py/py_gnmicli.py
+++ b/gnmi_cli_py/py_gnmicli.py
@@ -24,9 +24,7 @@ Current supported gNMI features:
- Auto-loads Target cert from Target if not specified
- User/password based authentication
- Certifificate based authentication
-
-Current unsupported gNMI features:
-- Subscribe
+- Subscribe request
"""

from __future__ import absolute_import
@@ -40,14 +38,16 @@ import re
import ssl
import sys
import six
+import datetime
try:
import gnmi_pb2
except ImportError:
print('ERROR: Ensure you\'ve installed dependencies from requirements.txt\n'
'eg, pip install -r requirements.txt')
import gnmi_pb2_grpc
+import grpc

-__version__ = '0.4'
+__version__ = '0.5'

_RE_PATH_COMPONENT = re.compile(r'''
^
@@ -143,6 +143,21 @@ def _create_parser():
required=False, action='store_true')
parser.add_argument('-n', '--notls', help='gRPC insecure mode',
required=False, action='store_true')
+ parser.add_argument('--interval', default=10000, type=int,
+ help='sample interval in millisecond (default: 10000ms)')
+ parser.add_argument('--timeout', type=int, help='subscription'
+ 'duration in seconds (default: none)')
+ parser.add_argument('--heartbeat', default=0, type=int, help='heartbeat interval (default: None)')
+ parser.add_argument('--aggregate', action='store_true', help='allow aggregation')
+ parser.add_argument('--suppress', action='store_true', help='suppress redundant')
+ parser.add_argument('--submode', default=2, type=int,
+ help='subscription mode [0=TARGET_DEFINED, 1=ON_CHANGE, 2=SAMPLE]')
+ parser.add_argument('--update_count', default=0, type=int, help='Max number of streaming updates to receive. 0 means no limit.')
+ parser.add_argument('--subscribe_mode', default=0, type=int, help='[0=STREAM, 1=ONCE, 2=POLL]')
+ parser.add_argument('--encoding', default=0, type=int, help='[0=JSON, 1=BYTES, 2=PROTO, 3=ASCII, 4=JSON_IETF]')
+ parser.add_argument('--qos', default=0, type=int, help='')
+ parser.add_argument('--use_alias', action='store_true', help='use alias')
+ parser.add_argument('--prefix', default='', help='gRPC path prefix (default: none)')
return parser


@@ -353,6 +368,79 @@ def _open_certs(**kwargs):
return kwargs


+def gen_request(paths, opt, prefix):
+ """Create subscribe request for passed xpath.
+ Args:
+ paths: (str) gNMI path.
+ opt: (dict) Command line argument passed for subscribe reqeust.
+ Returns:
+ gNMI SubscribeRequest object.
+ """
+ mysubs = []
+ mysub = gnmi_pb2.Subscription(path=paths, mode=opt["submode"],
+ sample_interval=opt["interval"]*1000000,
+ heartbeat_interval=opt['heartbeat']*1000000,
+ suppress_redundant=opt['suppress'])
+ mysubs.append(mysub)
+
+ if prefix:
+ myprefix = prefix
+ elif opt["prefix"]:
+ myprefix = _parse_path(_path_names(opt["prefix"]))
+ else:
+ myprefix = None
+
+ if opt["qos"]:
+ myqos = gnmi_pb2.QOSMarking(marking=opt["qos"])
+ else:
+ myqos = None
+ mysblist = gnmi_pb2.SubscriptionList(prefix=myprefix, mode=opt['subscribe_mode'],
+ allow_aggregation=opt['aggregate'], encoding=opt['encoding'],
+ subscription=mysubs, use_aliases=opt['use_alias'], qos=myqos)
+ mysubreq = gnmi_pb2.SubscribeRequest(subscribe=mysblist)
+
+ print('Sending SubscribeRequest\n'+str(mysubreq))
+ yield mysubreq
+
+
+def subscribe_start(stub, options, req_iterator):
+ """ RPC Start for Subscribe reqeust
+ Args:
+ stub: (class) gNMI Stub used to build the secure channel.
+ options: (dict) Command line argument passed for subscribe reqeust.
+ req_iterator: gNMI Subscribe Request from gen_request.
+ Returns:
+ Start Subscribe and printing response of gNMI Subscribe Response.
+ """
+ metadata = [('username', options['username']), ('password', options['password'])]
+ max_update_count = options["update_count"]
+ try:
+ responses = stub.Subscribe(req_iterator, options['timeout'], metadata=metadata)
+ update_count = 0
+ for response in responses:
+ print('{0} response received: '.format(datetime.datetime.now()))
+ if response.HasField('sync_response'):
+ print(str(response))
+ elif response.HasField('error'):
+ print('gNMI Error '+str(response.error.code)+\
+ ' received\n'+str(response.error.message) + str(response.error))
+ elif response.HasField('update'):
+ print(response)
+ update_count = update_count+1
+ else:
+ print('Unknown response received:\n'+str(response))
+
+ if max_update_count != 0 and update_count == max_update_count:
+ print("Max update count reached {0}".format(update_count))
+ break
+ except KeyboardInterrupt:
+ print("Subscribe Session stopped by user.")
+ except grpc.RpcError as x:
+ print("grpc.RpcError received:\n%s" %x)
+ except Exception as err:
+ print(err)
+
+
def main():
argparser = _create_parser()
args = vars(argparser.parse_args())
@@ -414,9 +502,9 @@ def main():
response = _set(stub, paths, 'delete', user, password, json_value)
print('The SetRequest response is below\n' + '-'*25 + '\n', response)
elif mode == 'subscribe':
- print('This mode not available in this version')
- sys.exit()
+ request_iterator = gen_request(paths, args, prefix)
+ subscribe_start(stub, args, request_iterator)


if __name__ == '__main__':
- main()
+ main()
\ No newline at end of file
--
2.48.1.windows.1

Loading
Loading