From 00bdcc741596a8ec3e31ca40633cddf88ed3959a Mon Sep 17 00:00:00 2001 From: akarneliuk Date: Mon, 1 May 2023 12:21:21 +0100 Subject: [PATCH] 0.8.12 --- README.rst | 5 ++- pygnmi/__init__.py | 2 +- pygnmi/arg_parser.py | 93 ++++++++++++++++++++++++++++---------------- scripts/pygnmicli | 90 +++++++++++++++++------------------------- setup.py | 4 +- 5 files changed, 101 insertions(+), 93 deletions(-) diff --git a/README.rst b/README.rst index 9ff6d9e..9f06dfb 100644 --- a/README.rst +++ b/README.rst @@ -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()`. @@ -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/ diff --git a/pygnmi/__init__.py b/pygnmi/__init__.py index 40d1e18..fb7a267 100644 --- a/pygnmi/__init__.py +++ b/pygnmi/__init__.py @@ -2,4 +2,4 @@ pyGNMI module to manage network devices with gNMI (c)2020-2023, Karneliuk """ -__version__ = "0.8.11" +__version__ = "0.8.12" diff --git a/pygnmi/arg_parser.py b/pygnmi/arg_parser.py index 3869230..e9dba5f 100644 --- a/pygnmi/arg_parser.py +++ b/pygnmi/arg_parser.py @@ -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", @@ -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", @@ -78,18 +86,27 @@ 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"], @@ -97,45 +114,51 @@ def parse_args(msg): 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", ) @@ -166,6 +189,8 @@ 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", ) @@ -173,16 +198,16 @@ def parse_args(msg): 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: diff --git a/scripts/pygnmicli b/scripts/pygnmicli index 52a39b4..30ef40c 100644 --- a/scripts/pygnmicli +++ b/scripts/pygnmicli @@ -1,5 +1,5 @@ #!/usr/bin/env python -#(c)2019-2022, karneliuk.com +# (c)2019-2022, karneliuk.com # Modules @@ -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": @@ -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: @@ -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: @@ -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: @@ -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) diff --git a/setup.py b/setup.py index 611e508..f25a332 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="pygnmi", packages=["pygnmi", "pygnmi.spec.v080", "pygnmi.artefacts"], - version="0.8.11", + version="0.8.12", license="bsd-3-clause", description="Pure Python gNMI client to manage network functions and collect telemetry.", long_description=long_description, @@ -14,7 +14,7 @@ author="Anton Karneliuk", author_email="anton@karneliuk.com", url="https://github.com/akarneliuk/pygnmi", - download_url="https://github.com/akarneliuk/pygnmi/archive/v0.8.11.tar.gz", + download_url="https://github.com/akarneliuk/pygnmi/archive/v0.8.12.tar.gz", keywords=["gnmi", "automation", "grpc", "network"], install_requires=["grpcio", "protobuf", "cryptography", "dictdiffer"], classifiers=[