-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from cisco-ie/actual-doc-examples
Add several examples
- Loading branch information
Showing
10 changed files
with
495 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
gnmi_sub.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
#!/usr/bin/env python | ||
"""Copyright 2020 Cisco Systems | ||
All rights reserved. | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
The contents of this file are licensed under the Apache License, Version 2.0 | ||
(the "License"); you may not use this file except in compliance with the | ||
License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
License for the specific language governing permissions and limitations under | ||
the License. | ||
""" | ||
|
||
"""Custom usage, no wrapper. | ||
Because we're not using a wrapper, we are going to need to build our own protos. | ||
""" | ||
|
||
import json | ||
from getpass import getpass | ||
from cisco_gnmi import ClientBuilder, proto | ||
|
||
"""First let's build a Client. We are not going to specify an OS | ||
name here resulting in just the base Client returned without any OS | ||
convenience methods. Client does have some level of "convenience" built-in | ||
insofar as it doesn't take direct <RPC>Requests (SubscribeRequest) etc. | ||
To directly use the gNMI RPCs access via client.service.<RPC>(). | ||
So - either: | ||
* Pass args to the client.<RPC>() methods. | ||
* Pass full <RPC>Request protos to client.service.<RPC>() | ||
This code passes args to the client.<RPC>() methods. | ||
""" | ||
target = input("Host/Port: ") | ||
username = input("Username: ") | ||
password = getpass() | ||
client = ( | ||
ClientBuilder(target) | ||
.set_secure_from_target() | ||
.set_ssl_target_override() | ||
.set_call_authentication(username, password) | ||
.construct() | ||
) | ||
"""Capabilities is an easy RPC to test.""" | ||
input("Press Enter for Capabilities...") | ||
capabilities = client.capabilities() | ||
print(capabilities) | ||
"""Let's build a Get! | ||
client.get() expects a list of Paths as the primary method of interaction. | ||
client.parse_xpath_to_gnmi_path is a convenience method to..parse an XPath to a Path. | ||
Generally OS wrappers will override this function to specialize on origins, etc. | ||
But we are not using a wrapper, and if using OpenConfig pathing we don't need an origin. | ||
""" | ||
input("Press Enter for Get...") | ||
get_path = client.parse_xpath_to_gnmi_path("/interfaces/interface/state/counters") | ||
get_response = client.get([get_path], data_type="STATE", encoding="JSON_IETF") | ||
print(get_response) | ||
"""Let's build a sampled Subscribe! | ||
client.subscribe() accepts an iterable of SubscriptionLists | ||
""" | ||
input("Press Enter for Subscribe SAMPLE...") | ||
subscription_list = proto.gnmi_pb2.SubscriptionList() | ||
subscription_list.mode = proto.gnmi_pb2.SubscriptionList.Mode.Value("STREAM") | ||
subscription_list.encoding = proto.gnmi_pb2.Encoding.Value("PROTO") | ||
sampled_subscription = proto.gnmi_pb2.Subscription() | ||
sampled_subscription.path.CopyFrom( | ||
client.parse_xpath_to_gnmi_path("/interfaces/interface/state/counters") | ||
) | ||
sampled_subscription.mode = proto.gnmi_pb2.SubscriptionMode.Value("SAMPLE") | ||
sampled_subscription.sample_interval = 10 * int(1e9) | ||
subscription_list.subscription.extend([sampled_subscription]) | ||
for subscribe_response in client.subscribe([subscription_list]): | ||
print(subscribe_response) | ||
break | ||
"""Now let's do ON_CHANGE. Just have to put SubscriptionMode to ON_CHANGE.""" | ||
input("Press Enter for Subscribe ON_CHANGE...") | ||
subscription_list = proto.gnmi_pb2.SubscriptionList() | ||
subscription_list.mode = proto.gnmi_pb2.SubscriptionList.Mode.Value("STREAM") | ||
subscription_list.encoding = proto.gnmi_pb2.Encoding.Value("PROTO") | ||
onchange_subscription = proto.gnmi_pb2.Subscription() | ||
onchange_subscription.path.CopyFrom( | ||
client.parse_xpath_to_gnmi_path( | ||
"/syslog/messages/message", origin="Cisco-IOS-XR-infra-syslog-oper" | ||
) | ||
) | ||
onchange_subscription.mode = proto.gnmi_pb2.SubscriptionMode.Value("ON_CHANGE") | ||
subscription_list.subscription.extend([onchange_subscription]) | ||
synced = False | ||
for subscribe_response in client.subscribe([subscription_list]): | ||
if subscribe_response.sync_response: | ||
synced = True | ||
print("Synced. Now perform action that will create a changed value.") | ||
print("If using XR syslog as written, just try SSH'ing to device.") | ||
continue | ||
if not synced: | ||
continue | ||
print(subscribe_response) | ||
break | ||
"""Let's build a Set! | ||
client.set() expects updates, replaces, and/or deletes to be provided. | ||
updates is a list of Updates | ||
replaces is a list of Updates | ||
deletes is a list of Paths | ||
Let's do an update. | ||
""" | ||
input("Press Enter for Set update...") | ||
set_update = proto.gnmi_pb2.Update() | ||
# This is the fully modeled JSON we want to update with | ||
update_json = json.loads( | ||
""" | ||
{ | ||
"openconfig-interfaces:interfaces": { | ||
"interface": [ | ||
{ | ||
"name": "Loopback9339" | ||
} | ||
] | ||
} | ||
} | ||
""" | ||
) | ||
# Let's just do an update from the very top element | ||
top_element = next(iter(update_json.keys())) | ||
set_update.path.CopyFrom(client.parse_xpath_to_gnmi_path(top_element)) | ||
# Remove the top element from the config since it's now in Path | ||
update_json = update_json.pop(top_element) | ||
# Set our update payload | ||
set_update.val.json_ietf_val = json.dumps(update_json).encode("utf-8") | ||
set_result = client.set(updates=[set_update]) | ||
print(set_result) | ||
# This may all seem somewhat obtuse, and that's what the client wrappers are for. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#!/usr/bin/env python | ||
"""Copyright 2020 Cisco Systems | ||
All rights reserved. | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
The contents of this file are licensed under the Apache License, Version 2.0 | ||
(the "License"); you may not use this file except in compliance with the | ||
License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
License for the specific language governing permissions and limitations under | ||
the License. | ||
""" | ||
|
||
"""This is effectively just demo code to load the output of subscribe_dump.py | ||
""" | ||
import argparse | ||
import os | ||
import logging | ||
import json | ||
import cisco_gnmi | ||
from google.protobuf import json_format, text_format | ||
|
||
|
||
def main(): | ||
logging.basicConfig(level=logging.INFO) | ||
logging.info("Demo of loading protobufs from files.") | ||
args = setup_args() | ||
src_proto_array = load_proto_file(args.protos_file) | ||
parsed_proto_array = [] | ||
for proto_msg in src_proto_array: | ||
parsed_proto = None | ||
if args.text_format is True: | ||
parsed_proto = text_format.Parse( | ||
proto_msg, cisco_gnmi.proto.gnmi_pb2.SubscribeResponse() | ||
) | ||
else: | ||
if args.raw_json: | ||
parsed_proto = json_format.Parse( | ||
proto_msg, cisco_gnmi.proto.gnmi_pb2.SubscribeResponse() | ||
) | ||
else: | ||
parsed_proto = json_format.ParseDict( | ||
proto_msg, cisco_gnmi.proto.gnmi_pb2.SubscribeResponse() | ||
) | ||
parsed_proto_array.append(parsed_proto) | ||
logging.info("Parsed %i formatted messages into objects!", len(parsed_proto_array)) | ||
|
||
|
||
def load_proto_file(filename): | ||
if not filename.endswith(".json"): | ||
raise Exception("Expected JSON file (array of messages) from proto_dump.py") | ||
proto_array = None | ||
with open(filename, "r") as protos_fd: | ||
proto_array = json.load(protos_fd) | ||
if not isinstance(proto_array, (list)): | ||
raise Exception("Expected array of messages from file!") | ||
return proto_array | ||
|
||
|
||
def setup_args(): | ||
parser = argparse.ArgumentParser(description="Proto Load Example") | ||
parser.add_argument("protos_file", help="File containing protos.", type=str) | ||
parser.add_argument( | ||
"-text_format", | ||
help="Protos are in text format instead of JSON.", | ||
action="store_true", | ||
) | ||
parser.add_argument( | ||
"-raw_json", | ||
help="Do not serialize to dict, but directly to JSON.", | ||
action="store_true", | ||
) | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
cisco_gnmi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#!/usr/bin/env python | ||
"""Copyright 2020 Cisco Systems | ||
All rights reserved. | ||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
The contents of this file are licensed under the Apache License, Version 2.0 | ||
(the "License"); you may not use this file except in compliance with the | ||
License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
License for the specific language governing permissions and limitations under | ||
the License. | ||
""" | ||
|
||
"""This demoes a gNMI subscription and dumping messages to a file.""" | ||
import json | ||
import logging | ||
import argparse | ||
from getpass import getpass | ||
from google.protobuf import json_format, text_format | ||
from cisco_gnmi import ClientBuilder | ||
|
||
|
||
def main(): | ||
logging.basicConfig(level=logging.INFO) | ||
args = setup_args() | ||
username = input("Username: ") | ||
password = getpass() | ||
logging.info("Connecting to %s as %s ...", args.netloc, args.os) | ||
client = ( | ||
ClientBuilder(args.netloc) | ||
.set_os(args.os) | ||
.set_secure_from_target() | ||
.set_ssl_target_override() | ||
.set_call_authentication(username, password) | ||
.construct() | ||
) | ||
formatted_messages = [] | ||
try: | ||
logging.info("Subscribing to %s ...", args.xpath) | ||
sub_args = {"xpath_subscriptions": args.xpath} | ||
if args.encoding: | ||
sub_args["encoding"] = args.encoding | ||
for message in client.subscribe_xpaths(**sub_args): | ||
if message.sync_response and not args.no_stop: | ||
logging.warning("Stopping on sync_response.") | ||
break | ||
formatted_message = None | ||
if args.text_format is True: | ||
formatted_message = text_format.MessageToString(message) | ||
else: | ||
if args.raw_json: | ||
formatted_message = json_format.MessageToJson(message) | ||
else: | ||
formatted_message = json_format.MessageToDict(message) | ||
logging.info(formatted_message) | ||
formatted_messages.append(formatted_message) | ||
except KeyboardInterrupt: | ||
logging.warning("Stopping on interrupt.") | ||
except Exception: | ||
logging.exception("Stopping due to exception!") | ||
finally: | ||
logging.info("Writing to %s ...", args.protos_file) | ||
with open(args.protos_file, "w") as protos_fd: | ||
json.dump( | ||
formatted_messages, | ||
protos_fd, | ||
sort_keys=True, | ||
indent=4, | ||
separators=(",", ": "), | ||
) | ||
|
||
|
||
def setup_args(): | ||
parser = argparse.ArgumentParser(description="gNMI Proto Dump Example") | ||
parser.add_argument("netloc", help="<host>:<port>", type=str) | ||
parser.add_argument( | ||
"-os", | ||
help="OS to use.", | ||
type=str, | ||
default="IOS XR", | ||
choices=list(ClientBuilder.os_class_map.keys()), | ||
) | ||
parser.add_argument( | ||
"-xpath", | ||
help="XPath to subscribe to.", | ||
type=str, | ||
default="/interfaces/interface/state/counters", | ||
) | ||
parser.add_argument( | ||
"-protos_file", help="File to write protos.", type=str, default="gnmi_sub.json" | ||
) | ||
parser.add_argument( | ||
"-no_stop", help="Do not stop on sync_response.", action="store_true" | ||
) | ||
parser.add_argument( | ||
"-encoding", help="gNMI subscription encoding.", type=str, nargs="?" | ||
) | ||
parser.add_argument( | ||
"-text_format", | ||
help="Protos are in text format instead of JSON.", | ||
action="store_true", | ||
) | ||
parser.add_argument( | ||
"-raw_json", | ||
help="Do not serialize to dict, but directly to JSON.", | ||
action="store_true", | ||
) | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.