Skip to content

Commit de478bf

Browse files
authored
Merge pull request #48 from cisco-ie/subscribe-xpaths-refactor
Refactor subscribe_xpaths into base Client
2 parents fb94dd2 + d824e7c commit de478bf

File tree

9 files changed

+384
-223
lines changed

9 files changed

+384
-223
lines changed

README.md

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,12 @@ cisco-gnmi capabilities 127.0.0.1:57500 -auto_ssl_target_override
257257
```
258258
cisco-gnmi capabilities --help
259259
usage: cisco-gnmi [-h] [-os {None,IOS XR,NX-OS,IOS XE}]
260-
[-root_certificates ROOT_CERTIFICATES]
261-
[-private_key PRIVATE_KEY]
262-
[-certificate_chain CERTIFICATE_CHAIN]
263-
[-ssl_target_override SSL_TARGET_OVERRIDE]
264-
[-auto_ssl_target_override] [-debug]
265-
netloc
260+
[-root_certificates ROOT_CERTIFICATES]
261+
[-private_key PRIVATE_KEY]
262+
[-certificate_chain CERTIFICATE_CHAIN]
263+
[-ssl_target_override SSL_TARGET_OVERRIDE]
264+
[-auto_ssl_target_override] [-debug]
265+
netloc
266266
267267
Performs Capabilities RPC against network element.
268268
@@ -309,16 +309,17 @@ cisco-gnmi get 127.0.0.1:57500 -os "IOS XR" -xpath /interfaces/interface/state/c
309309

310310
#### Usage
311311
```
312+
cisco-gnmi get --help
312313
usage: cisco-gnmi [-h] [-xpath XPATH]
313-
[-encoding [{JSON,BYTES,PROTO,ASCII,JSON_IETF}]]
314-
[-data_type [{ALL,CONFIG,STATE,OPERATIONAL}]] [-dump_json]
315-
[-os {None,IOS XR,NX-OS,IOS XE}]
316-
[-root_certificates ROOT_CERTIFICATES]
317-
[-private_key PRIVATE_KEY]
318-
[-certificate_chain CERTIFICATE_CHAIN]
319-
[-ssl_target_override SSL_TARGET_OVERRIDE]
320-
[-auto_ssl_target_override] [-debug]
321-
netloc
314+
[-encoding {JSON,BYTES,PROTO,ASCII,JSON_IETF}]
315+
[-data_type {ALL,CONFIG,STATE,OPERATIONAL}] [-dump_json]
316+
[-os {None,IOS XR,NX-OS,IOS XE}]
317+
[-root_certificates ROOT_CERTIFICATES]
318+
[-private_key PRIVATE_KEY]
319+
[-certificate_chain CERTIFICATE_CHAIN]
320+
[-ssl_target_override SSL_TARGET_OVERRIDE]
321+
[-auto_ssl_target_override] [-debug]
322+
netloc
322323
323324
Performs Get RPC against network element.
324325
@@ -328,9 +329,9 @@ positional arguments:
328329
optional arguments:
329330
-h, --help show this help message and exit
330331
-xpath XPATH XPaths to Get.
331-
-encoding [{JSON,BYTES,PROTO,ASCII,JSON_IETF}]
332+
-encoding {JSON,BYTES,PROTO,ASCII,JSON_IETF}
332333
gNMI Encoding.
333-
-data_type [{ALL,CONFIG,STATE,OPERATIONAL}]
334+
-data_type {ALL,CONFIG,STATE,OPERATIONAL}
334335
gNMI GetRequest DataType
335336
-dump_json Dump as JSON instead of textual protos.
336337
-os {None,IOS XR,NX-OS,IOS XE}
@@ -381,16 +382,17 @@ Please note that `Set` operations may be destructive to operations and should be
381382

382383
#### Usage
383384
```
385+
cisco-gnmi set --help
384386
usage: cisco-gnmi [-h] [-update_json_config UPDATE_JSON_CONFIG]
385-
[-replace_json_config REPLACE_JSON_CONFIG]
386-
[-delete_xpath DELETE_XPATH] [-no_ietf] [-dump_json]
387-
[-os {None,IOS XR,NX-OS,IOS XE}]
388-
[-root_certificates ROOT_CERTIFICATES]
389-
[-private_key PRIVATE_KEY]
390-
[-certificate_chain CERTIFICATE_CHAIN]
391-
[-ssl_target_override SSL_TARGET_OVERRIDE]
392-
[-auto_ssl_target_override] [-debug]
393-
netloc
387+
[-replace_json_config REPLACE_JSON_CONFIG]
388+
[-delete_xpath DELETE_XPATH] [-no_ietf] [-dump_json]
389+
[-os {None,IOS XR,NX-OS,IOS XE}]
390+
[-root_certificates ROOT_CERTIFICATES]
391+
[-private_key PRIVATE_KEY]
392+
[-certificate_chain CERTIFICATE_CHAIN]
393+
[-ssl_target_override SSL_TARGET_OVERRIDE]
394+
[-auto_ssl_target_override] [-debug]
395+
netloc
394396
395397
Performs Set RPC against network element.
396398
@@ -469,24 +471,28 @@ interface Loopback9339
469471
```
470472

471473
### Subscribe
472-
This command will output the `SubscribeResponse` to `stdout` or `-dump_file`. `-xpath` may be specified multiple times to specify multiple `Path`s for the `GetRequest`. Subscribe currently only supports a sampled stream. `ON_CHANGE` is possible but not implemented in the CLI, yet. :)
474+
This command will output the `SubscribeResponse` to `stdout` or `-dump_file`. `-xpath` may be specified multiple times to specify multiple `Path`s for the `GetRequest`.
475+
473476
```
474477
cisco-gnmi subscribe 127.0.0.1:57500 -os "IOS XR" -xpath /interfaces/interface/state/counters -auto_ssl_target_override
475478
```
476479

477480
#### Usage
478481
```
479482
cisco-gnmi subscribe --help
480-
usage: cisco-gnmi [-h] [-xpath XPATH] [-interval INTERVAL] [-dump_file DUMP_FILE]
481-
[-dump_json] [-sync_stop]
482-
[-encoding [{JSON,BYTES,PROTO,ASCII,JSON_IETF}]]
483-
[-os {None,IOS XR,NX-OS,IOS XE}]
484-
[-root_certificates ROOT_CERTIFICATES]
485-
[-private_key PRIVATE_KEY]
486-
[-certificate_chain CERTIFICATE_CHAIN]
487-
[-ssl_target_override SSL_TARGET_OVERRIDE]
488-
[-auto_ssl_target_override] [-debug]
489-
netloc
483+
usage: cisco-gnmi [-h] [-xpath XPATH] [-interval INTERVAL]
484+
[-mode {TARGET_DEFINED,ON_CHANGE,SAMPLE}]
485+
[-suppress_redundant]
486+
[-heartbeat_interval HEARTBEAT_INTERVAL]
487+
[-dump_file DUMP_FILE] [-dump_json] [-sync_stop]
488+
[-sync_start] [-encoding {JSON,BYTES,PROTO,ASCII,JSON_IETF}]
489+
[-os {None,IOS XR,NX-OS,IOS XE}]
490+
[-root_certificates ROOT_CERTIFICATES]
491+
[-private_key PRIVATE_KEY]
492+
[-certificate_chain CERTIFICATE_CHAIN]
493+
[-ssl_target_override SSL_TARGET_OVERRIDE]
494+
[-auto_ssl_target_override] [-debug]
495+
netloc
490496
491497
Performs Subscribe RPC against network element.
492498
@@ -498,11 +504,18 @@ optional arguments:
498504
-xpath XPATH XPath to subscribe to.
499505
-interval INTERVAL Sample interval in seconds for Subscription. Defaults
500506
to 10.
507+
-mode {TARGET_DEFINED,ON_CHANGE,SAMPLE}
508+
SubscriptionMode for Subscription. Defaults to SAMPLE.
509+
-suppress_redundant Suppress redundant information in Subscription.
510+
-heartbeat_interval HEARTBEAT_INTERVAL
511+
Heartbeat interval in seconds.
501512
-dump_file DUMP_FILE Filename to dump to. Defaults to stdout.
502513
-dump_json Dump as JSON instead of textual protos.
503514
-sync_stop Stop on sync_response.
504-
-encoding [{JSON,BYTES,PROTO,ASCII,JSON_IETF}]
505-
gNMI Encoding.
515+
-sync_start Start processing messages after sync_response.
516+
-encoding {JSON,BYTES,PROTO,ASCII,JSON_IETF}
517+
gNMI Encoding. Defaults to whatever Client wrapper
518+
prefers.
506519
-os {None,IOS XR,NX-OS,IOS XE}
507520
OS wrapper to utilize. Defaults to IOS XR.
508521
-root_certificates ROOT_CERTIFICATES

scripts/gen_certs.sh

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,55 @@
33

44
CERT_BASE="certs"
55

6-
if [ -z $1 ]; then
7-
echo "Usage: gen_certs.sh <hostname> [<password>]"
6+
if [ -z $1 ] || [ -z $2 ]; then
7+
echo "Usage: gen_certs.sh <server_hostname> <ip> [<password>]"
88
exit 1
99
fi
1010

11+
server_hostname=$1
12+
ip=$2
13+
password=$3
14+
1115
mkdir -p $CERT_BASE
1216

17+
function print_red () {
18+
printf "\033[0;31m$1 ...\033[0m\n"
19+
}
20+
1321
# Setting up a CA
14-
openssl genrsa -out $CERT_BASE/rootCA.key 2048
15-
openssl req -subj /C=/ST=/L=/O=/CN=rootCA -x509 -new -nodes -key $CERT_BASE/rootCA.key -sha256 -out $CERT_BASE/rootCA.pem
22+
if [ -f "$CERT_BASE/rootCA.key" ] && [ -f "$CERT_BASE/rootCA.pem" ]; then
23+
print_red "SKIPPING rootCA generation, already exist"
24+
else
25+
print_red "GENERATING rootCA"
26+
openssl genrsa -out $CERT_BASE/rootCA.key 2048
27+
openssl req -subj /C=/ST=/L=/O=/CN=rootCA -x509 -new -nodes -key $CERT_BASE/rootCA.key -sha256 -days 1095 -out $CERT_BASE/rootCA.pem
28+
fi
1629

1730
# Setting up device cert and key
31+
print_red "GENERATING device certificates with CN $server_hostname and IP $ip"
1832
openssl genrsa -out $CERT_BASE/device.key 2048
19-
openssl req -subj /C=/ST=/L=/O=/CN=$1 -new -key $CERT_BASE/device.key -out $CERT_BASE/device.csr
20-
openssl x509 -req -in $CERT_BASE/device.csr -CA $CERT_BASE/rootCA.pem -CAkey $CERT_BASE/rootCA.key -CAcreateserial -out $CERT_BASE/device.crt -sha256
33+
openssl req -subj /C=/ST=/L=/O=/CN=$server_hostname -new -key $CERT_BASE/device.key -out $CERT_BASE/device.csr
34+
openssl x509 -req -in $CERT_BASE/device.csr -CA $CERT_BASE/rootCA.pem -CAkey $CERT_BASE/rootCA.key -CAcreateserial -out $CERT_BASE/device.crt -days 1095 -sha256 -extfile <(printf "%s" "subjectAltName=DNS:$server_hostname,IP:$ip")
2135

22-
# Encrypt device key - needed for input to IOS
23-
if [ ! -z $2 ]; then
24-
openssl rsa -des3 -in $CERT_BASE/device.key -out $CERT_BASE/device.des3.key -passout pass:$2
36+
# Encrypt device key
37+
if [ ! -z $password ]; then
38+
print_red "ENCRYPTING device certificates and bundling with password"
39+
# DES 3 for device, needed for input to IOS XE
40+
openssl rsa -des3 -in $CERT_BASE/device.key -out $CERT_BASE/device.des3.key -passout pass:$password
41+
# PKCS #12 for device, needed for NX-OS
42+
# Uncertain if this is correct
43+
openssl pkcs12 -export -out $CERT_BASE/device.pfx -inkey $CERT_BASE/device.key -in $CERT_BASE/device.crt -certfile $CERT_BASE/rootCA.pem -password pass:$password
2544
else
26-
echo "Skipping device key encryption."
45+
print_red "SKIPPING device key encryption"
2746
fi
2847

2948
# Setting up client cert and key
30-
openssl genrsa -out $CERT_BASE/client.key 2048
31-
openssl req -subj /C=/ST=/L=/O=/CN=gnmi_client -new -key $CERT_BASE/client.key -out $CERT_BASE/client.csr
32-
openssl x509 -req -in $CERT_BASE/client.csr -CA $CERT_BASE/rootCA.pem -CAkey $CERT_BASE/rootCA.key -CAcreateserial -out $CERT_BASE/client.crt -sha256
49+
if [ -f "$CERT_BASE/client.key" ] && [ -f "$CERT_BASE/client.crt" ]; then
50+
print_red "SKIPPING client certificates generation, already exist"
51+
else
52+
hostname=$(hostname)
53+
print_red "GENERATING client certificates with CN $hostname"
54+
openssl genrsa -out $CERT_BASE/client.key 2048
55+
openssl req -subj /C=/ST=/L=/O=/CN=$hostname -new -key $CERT_BASE/client.key -out $CERT_BASE/client.csr
56+
openssl x509 -req -in $CERT_BASE/client.csr -CA $CERT_BASE/rootCA.pem -CAkey $CERT_BASE/rootCA.key -CAcreateserial -out $CERT_BASE/client.crt -days 1095 -sha256
57+
fi

src/cisco_gnmi/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@
3030
from .xe import XEClient
3131
from .builder import ClientBuilder
3232

33-
__version__ = "1.0.5"
33+
__version__ = "1.0.6"

src/cisco_gnmi/cli.py

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import argparse
3535
from getpass import getpass
3636
from google.protobuf import json_format, text_format
37-
from . import ClientBuilder, proto
37+
from . import ClientBuilder, proto, __version__
3838
from google.protobuf.internal import enum_type_wrapper
3939
import sys
4040

@@ -52,6 +52,8 @@ def main():
5252
usage="""
5353
cisco-gnmi <rpc> [<args>]
5454
55+
Version {version}
56+
5557
Supported RPCs:
5658
{supported_rpcs}
5759
@@ -62,7 +64,8 @@ def main():
6264
6365
See <rpc> --help for RPC options.
6466
""".format(
65-
supported_rpcs="\n".join(list(rpc_map.keys()))
67+
version=__version__,
68+
supported_rpcs="\n".join(sorted(list(rpc_map.keys())))
6669
),
6770
)
6871
parser.add_argument("rpc", help="gNMI RPC to perform against network element.")
@@ -91,8 +94,7 @@ def gnmi_capabilities():
9194

9295

9396
def gnmi_subscribe():
94-
"""Performs a sampled Subscribe against network element.
95-
TODO: ON_CHANGE
97+
"""Performs a streaming Subscribe against network element.
9698
"""
9799
parser = argparse.ArgumentParser(
98100
description="Performs Subscribe RPC against network element."
@@ -106,6 +108,20 @@ def gnmi_subscribe():
106108
type=int,
107109
default=10,
108110
)
111+
parser.add_argument(
112+
"-mode",
113+
help="SubscriptionMode for Subscription. Defaults to SAMPLE.",
114+
default="SAMPLE",
115+
choices=proto.gnmi_pb2.SubscriptionMode.keys(),
116+
)
117+
parser.add_argument(
118+
"-suppress_redundant",
119+
help="Suppress redundant information in Subscription.",
120+
action="store_true",
121+
)
122+
parser.add_argument(
123+
"-heartbeat_interval", help="Heartbeat interval in seconds.", type=int
124+
)
109125
parser.add_argument(
110126
"-dump_file",
111127
help="Filename to dump to. Defaults to stdout.",
@@ -120,11 +136,15 @@ def gnmi_subscribe():
120136
parser.add_argument(
121137
"-sync_stop", help="Stop on sync_response.", action="store_true"
122138
)
139+
parser.add_argument(
140+
"-sync_start",
141+
help="Start processing messages after sync_response.",
142+
action="store_true",
143+
)
123144
parser.add_argument(
124145
"-encoding",
125-
help="gNMI Encoding.",
146+
help="gNMI Encoding. Defaults to whatever Client wrapper prefers.",
126147
type=str,
127-
nargs="?",
128148
choices=proto.gnmi_pb2.Encoding.keys(),
129149
)
130150
args = __common_args_handler(parser)
@@ -138,20 +158,30 @@ def gnmi_subscribe():
138158
kwargs["encoding"] = args.encoding
139159
if args.interval:
140160
kwargs["sample_interval"] = args.interval * int(1e9)
161+
if args.mode:
162+
kwargs["sub_mode"] = args.mode
163+
if args.suppress_redundant:
164+
kwargs["suppress_redundant"] = args.suppress_redundant
165+
if args.heartbeat_interval:
166+
kwargs["heartbeat_interval"] = args.heartbeat_interval * int(1e9)
141167
try:
142-
logging.info(
168+
logging.debug(
143169
"Dumping responses to %s as %s ...",
144170
args.dump_file,
145171
"JSON" if args.dump_json else "textual proto",
146172
)
147-
logging.info("Subscribing to:\n%s", "\n".join(args.xpath))
173+
logging.debug("Subscribing to:\n%s", "\n".join(args.xpath))
174+
synced = False
148175
for subscribe_response in client.subscribe_xpaths(args.xpath, **kwargs):
149176
logging.debug("SubscribeResponse received.")
150177
if subscribe_response.sync_response:
151178
logging.debug("sync_response received.")
152179
if args.sync_stop:
153180
logging.warning("Stopping on sync_response.")
154181
break
182+
synced = True
183+
if not synced and args.sync_start:
184+
continue
155185
formatted_message = __format_message(subscribe_response)
156186
if args.dump_file == "stdout":
157187
logging.info(formatted_message)
@@ -175,14 +205,12 @@ def gnmi_get():
175205
"-encoding",
176206
help="gNMI Encoding.",
177207
type=str,
178-
nargs="?",
179208
choices=proto.gnmi_pb2.Encoding.keys(),
180209
)
181210
parser.add_argument(
182211
"-data_type",
183212
help="gNMI GetRequest DataType",
184213
type=str,
185-
nargs="?",
186214
choices=enum_type_wrapper.EnumTypeWrapper(
187215
proto.gnmi_pb2._GETREQUEST_DATATYPE
188216
).keys(),

0 commit comments

Comments
 (0)