Skip to content

Commit

Permalink
Merge pull request #119 from akarneliuk/0.8.12
Browse files Browse the repository at this point in the history
0.8.12
  • Loading branch information
akarneliuk authored May 1, 2023
2 parents 196985f + 00bdcc7 commit 4ee6773
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 93 deletions.
5 changes: 4 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ Contributors
Dev Log
=======

Release **0.8.12**:
- Fixed operation of `no_qos_marking` flag for `pygnmicli`.

Release **0.8.11**:
- Previous release introduced break for telemetry in `Juniper` due to inconsistency of communicated encoudings in `Capabilities()` and what is really supported in `Subscribe()`.

Expand Down Expand Up @@ -424,7 +427,7 @@ Release **0.1.0**:

(c)2020-2022, karneliuk.com

.. |version| image:: https://img.shields.io/static/v1?label=latest&message=v0.8.10&color=success
.. |version| image:: https://img.shields.io/static/v1?label=latest&message=v0.8.12&color=success
.. _version: https://pypi.org/project/pygnmi/
.. |tag| image:: https://img.shields.io/static/v1?label=status&message=stable&color=success
.. _tag: https://pypi.org/project/pygnmi/
Expand Down
2 changes: 1 addition & 1 deletion pygnmi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
pyGNMI module to manage network devices with gNMI
(c)2020-2023, Karneliuk
"""
__version__ = "0.8.11"
__version__ = "0.8.12"
93 changes: 59 additions & 34 deletions pygnmi/arg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,27 @@ def parse_args(msg):
"""
parser = argparse.ArgumentParser()
parser.add_argument(
"-t", "--target",
"-t",
"--target",
type=str,
required=True,
help="Target device connection details in 'host:port' format",
)
parser.add_argument(
"-u", "--user",
"-u",
"--user",
type=str,
required=False,
help="Username to use when connecting",
dest="username"
dest="username",
)
parser.add_argument(
"-p", "--pass",
"-p",
"--pass",
type=str,
required=False,
help="Password to use when connecting",
dest="password"
dest="password",
)
parser.add_argument(
"--token",
Expand All @@ -42,31 +45,36 @@ def parse_args(msg):
help="Specify the token for token-based authentication",
)
parser.add_argument(
"-c", "--path-cert",
"-c",
"--path-cert",
type=str,
required=False,
help="Path to certificate chain file",
)
parser.add_argument(
"-k", "--path-key",
"-k",
"--path-key",
type=str,
required=False,
help="Path to private key file"
help="Path to private key file",
)
parser.add_argument(
"-r", "--path-root",
"-r",
"--path-root",
type=str,
required=False,
help="Path to root CA file"
help="Path to root CA file",
)
parser.add_argument(
"-O", "--override",
"-O",
"--override",
type=str,
required=False,
help="Override the expected server hostname to match certificate name",
)
parser.add_argument(
"-i", "--insecure",
"-i",
"--insecure",
action="store_true",
default=False,
help="Set to disable TLS encryption on the gRPC channel",
Expand All @@ -78,64 +86,79 @@ def parse_args(msg):
help="Set to disable SSL certificate valication on the encrypted gRPC channel",
)
parser.add_argument(
"-o", "--operation",
"-o",
"--operation",
type=str,
required=False,
choices=[
"capabilities", "get", "set-update", "set-replace", "set-delete",
"subscribe-stream", "subscribe-poll", "subscribe-once", "subscribe2"
"capabilities",
"get",
"set-update",
"set-replace",
"set-delete",
"subscribe-stream",
"subscribe-poll",
"subscribe-once",
"subscribe2",
],
default="capabilities",
help="gNMI Request type",
)
parser.add_argument(
"-e", "--encoding",
"-e",
"--encoding",
type=str,
required=False,
choices=["json", "bytes", "proto", "ascii", "json_ietf"],
default="json",
help="Specif the encoding in the gNMI RPC (subject to be supported by the network device",
)
parser.add_argument(
"-x", "--gnmi-path",
"-x",
"--gnmi-path",
type=str,
required=False,
default="", nargs="+",
help="gNMI paths of interest in XPath format, space separated"
default="",
nargs="+",
help="gNMI paths of interest in XPath format, space separated",
)
parser.add_argument(
"--gnmi-path-target",
type=str,
required=False,
help="Set target for GNMI path if it is different to the endpoint itself."
help="Set target for GNMI path if it is different to the endpoint itself.",
)
parser.add_argument(
"-d", "--datastore",
"-d",
"--datastore",
type=str,
required=False,
choices=["all", "config", "operational", "state"],
default="all", const="all", nargs="?",
default="all",
const="all",
nargs="?",
help="Which datastore to operate on",
)
parser.add_argument(
"-f", "--file",
"-f",
"--file",
type=str,
required=False,
help="Path to file containing JSON data to use in a set request",
)
parser.add_argument(
"-D", "--debug",
"-D",
"--debug",
action="store_true",
default=False,
help="Set to enable printing of Protobuf messages to STDOUT",
)
parser.add_argument(
"-C", "--compare",
"-C",
"--compare",
type=str,
required=False,
choices=[
"get", "print", ""
],
choices=["get", "print", ""],
default="",
help="Compare the states of the devices before and after change to show difference",
)
Expand Down Expand Up @@ -166,23 +189,25 @@ def parse_args(msg):
parser.add_argument(
"--no-qos-marking",
action="store_true",
required=False,
default=False,
help="Do not send qos marking with subscription request",
)

args = parser.parse_args()

targets = args.target
try:
if re.match(r'\[.*\]', targets):
parsed_args = re.sub(r'^\[([0-9a-fA-F:]+?)\]:(\d+?)$', r'\g<1> \g<2>', targets)
args.target = parsed_args.split(' ')
if re.match(r"\[.*\]", targets):
parsed_args = re.sub(r"^\[([0-9a-fA-F:]+?)\]:(\d+?)$", r"\g<1> \g<2>", targets)
args.target = parsed_args.split(" ")
args.target = (str(args.target[0]), int(args.target[1]))
else:
args.target = (str(targets.split(':')[0]), int(targets.split(':')[1]))
args.target = (str(targets.split(":")[0]), int(targets.split(":")[1]))
except IndexError:
parser.error(msg['bad_host'])
parser.error(msg["bad_host"])
except ValueError:
parser.error(msg['wrong_data'])
parser.error(msg["wrong_data"])

if args.operation in ("set-update", "set-replace"):
if args.file is None:
Expand Down
90 changes: 35 additions & 55 deletions scripts/pygnmicli
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python
#(c)2019-2022, karneliuk.com
# (c)2019-2022, karneliuk.com


# Modules
Expand All @@ -14,54 +14,58 @@ from pygnmi.client import gNMIclient
from pygnmi.artefacts.messages import msg

# Variables
path_log = 'log/execution.log'
path_log = "log/execution.log"


# Body
def main():

# Setting logger
if not os.path.exists(path_log.split('/')[0]):
os.mkdir(path_log.split('/')[0])
if not os.path.exists(path_log.split("/")[0]):
os.mkdir(path_log.split("/")[0])

logging.basicConfig(
filename=path_log,
level=logging.INFO,
format='%(asctime)s.%(msecs)03d+01:00,%(levelname)s,%(message)s',
datefmt='%Y-%m-%dT%H:%M:%S'
format="%(asctime)s.%(msecs)03d+01:00,%(levelname)s,%(message)s",
datefmt="%Y-%m-%dT%H:%M:%S",
)
logging.info('Starting application...')
logging.info("Starting application...")

# Collecting inputs
args = parse_args(msg)

# gNMI operation
with gNMIclient(
target=args.target, username=args.username, password=args.password, token=args.token,
path_cert=args.path_cert, path_key=args.path_key, path_root=args.path_root,
override=args.override, insecure=args.insecure, debug=args.debug,
show_diff=args.compare, skip_verify=args.skip_verify, gnmi_timeout=args.gnmi_timeout,
no_qos_marking=args.no-qos-marking
target=args.target,
username=args.username,
password=args.password,
token=args.token,
path_cert=args.path_cert,
path_key=args.path_key,
path_root=args.path_root,
override=args.override,
insecure=args.insecure,
debug=args.debug,
show_diff=args.compare,
skip_verify=args.skip_verify,
gnmi_timeout=args.gnmi_timeout,
no_qos_marking=args.no_qos_marking,
) as GC:

result = None

# Collecting supported capabilities (needed to figure out encoding for telemetry)
GC.capabilities()

if args.operation == 'capabilities':
print(f'Doing {args.operation} request to {args.target}...')
if args.operation == "capabilities":
print(f"Doing {args.operation} request to {args.target}...")
result = GC.capabilities()

elif args.operation == 'get':
print(f'Doing {args.operation} request to {args.target}...')
result = GC.get(path=args.gnmi_path,
datatype=args.datastore,
encoding=args.encoding,
target=args.gnmi_path_target)
elif args.operation == "get":
print(f"Doing {args.operation} request to {args.target}...")
result = GC.get(path=args.gnmi_path, datatype=args.datastore, encoding=args.encoding, target=args.gnmi_path_target)

elif args.operation.startswith('set'):
print(f'Doing {args.operation} request to {args.target}...')
elif args.operation.startswith("set"):
print(f"Doing {args.operation} request to {args.target}...")
mode = args.operation.split("-")[1]
kwargs = {}
if mode == "delete":
Expand All @@ -75,21 +79,10 @@ def main():
kwargs[mode] = [(args.gnmi_path[0], jdata)]
result = GC.set(encoding=args.encoding, target=args.gnmi_path_target, **kwargs)

elif args.operation.startswith('subscribe'):
elif args.operation.startswith("subscribe"):
mode = args.operation.split("-")[1]
subscription_list = [
{
'path': xpath,
'mode': 'target_defined'
}
for xpath in args.gnmi_path
]
subscribe = {
'subscription': subscription_list,
'use_aliases': False,
'mode': mode,
'encoding': args.encoding
}
subscription_list = [{"path": xpath, "mode": "target_defined"} for xpath in args.gnmi_path]
subscribe = {"subscription": subscription_list, "use_aliases": False, "mode": mode, "encoding": args.encoding}

# Set up extensions
if args.ext_history_snapshot_time:
Expand All @@ -99,11 +92,7 @@ def main():
except:
time_to_int = args.ext_history_snapshot_time

EXT = {
"history": {
"snapshot_time": time_to_int
}
}
EXT = {"history": {"snapshot_time": time_to_int}}

elif args.ext_history_range_start and args.ext_history_range_end:
try:
Expand All @@ -114,22 +103,13 @@ def main():
time_to_int_1 = args.ext_history_range_start
time_to_int_2 = args.ext_history_range_start

EXT = {
"history": {
"range": {
"start": time_to_int_1,
"end": time_to_int_2
}
}
}
EXT = {"history": {"range": {"start": time_to_int_1, "end": time_to_int_2}}}

else:
EXT = None

# Telemetry
result = GC.subscribe2(subscribe=subscribe,
target=args.gnmi_path_target,
extension=EXT)
result = GC.subscribe2(subscribe=subscribe, target=args.gnmi_path_target, extension=EXT)

if mode == "stream":
try:
Expand All @@ -153,7 +133,7 @@ def main():
except KeyboardInterrupt:
sys.exit("Telemtry collection is temrinated.")

if result and not args.debug and not args.operation.startswith('subscribe'):
if result and not args.debug and not args.operation.startswith("subscribe"):
_print_result(result)


Expand Down
Loading

0 comments on commit 4ee6773

Please sign in to comment.