Skip to content

Commit

Permalink
0.8.14
Browse files Browse the repository at this point in the history
  • Loading branch information
akarneliuk committed Mar 9, 2024
1 parent 038564f commit 21ba8ae
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 102 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.14**:
- Number of minor bug fixes and improvements.

Release **0.8.13**:
- Number of minor bug fixes and improvements.

Expand Down Expand Up @@ -430,7 +433,7 @@ Release **0.1.0**:

(c)2020-2022, karneliuk.com

.. |version| image:: https://img.shields.io/static/v1?label=latest&message=v0.8.13&color=success
.. |version| image:: https://img.shields.io/static/v1?label=latest&message=v0.8.14&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
3 changes: 2 additions & 1 deletion pygnmi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
pyGNMI module to manage network devices with gNMI
(c)2020-2023, Karneliuk
"""
__version__ = "0.8.12"

__version__ = "0.8.14"
8 changes: 7 additions & 1 deletion pygnmi/arg_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Module to process arguments used in pygnmi cli
"""


# Modules
import argparse
import re
Expand Down Expand Up @@ -122,6 +121,13 @@ def parse_args(msg):
nargs="+",
help="gNMI paths of interest in XPath format, space separated",
)
parser.add_argument(
"--gnmi-prefix",
type=str,
required=False,
default="",
help="gNMI prefix, which is shared across multiple paths of interest in XPath forma.",
)
parser.add_argument(
"--gnmi-path-target",
type=str,
Expand Down
126 changes: 79 additions & 47 deletions pygnmi/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
pyGNMI module to manage network devices with gNMI
(c)2020-2023, Karneliuk
(c)2020-2024, Karneliuk
"""

# Modules
Expand Down Expand Up @@ -108,7 +108,7 @@ def __init__(
if "keepalive_time_ms" in kwargs:
self.configureKeepalive(**kwargs)

self.__grpc_proxy = os.getenv('grpc_proxy')
self.__grpc_proxy = os.getenv("grpc_proxy")

def configureKeepalive(
self,
Expand Down Expand Up @@ -186,14 +186,14 @@ def connect(self, timeout: int = None):
# create tunnel to target
s.send(f"CONNECT {self.__target[0]}:{self.__target[1]} HTTP/1.0\r\n\r\n".encode())
buf = s.recv(8192)
if buf[9:12] != b'200':
if buf[9:12] != b"200":
raise gNMIException(f"Didn't get a 200 from the proxy, instead: {buf})")
# upgrade socket to ssl - ignore certifcate errors since we only want
# to get the certificate and don't transfer sensitive data
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
cert = ctx.wrap_socket(s, server_hostname = self.__target[0]).getpeercert(True)
cert = ctx.wrap_socket(s, server_hostname=self.__target[0]).getpeercert(True)
ssl_cert = ssl.DER_cert_to_PEM_cert(cert).encode("utf-8")
else:
ssl_cert = ssl.get_server_certificate((self.__target[0], self.__target[1])).encode("utf-8")
Expand All @@ -209,9 +209,9 @@ def connect(self, timeout: int = None):
# Collect Certificate's Comman Name
ssl_cert_common_name = None
try:
ssl_cert_common_name = ssl_cert_deserialized.subject.get_attributes_for_oid((x509.oid.NameOID.COMMON_NAME))[
0
].value
ssl_cert_common_name = ssl_cert_deserialized.subject.get_attributes_for_oid(
(x509.oid.NameOID.COMMON_NAME)
)[0].value

except BaseException as err:
logger.warning(f"Cannot get Common Name: {err}")
Expand Down Expand Up @@ -256,7 +256,9 @@ def connect(self, timeout: int = None):

# Set up SSL channel credentials
if self.__path_key and self.__path_root:
cert = grpc.ssl_channel_credentials(root_certificates=root_cert, private_key=key, certificate_chain=ssl_cert)
cert = grpc.ssl_channel_credentials(
root_certificates=root_cert, private_key=key, certificate_chain=ssl_cert
)

else:
cert = grpc.ssl_channel_credentials(ssl_cert)
Expand Down Expand Up @@ -421,7 +423,9 @@ def get(self, prefix: str = "", path: list = None, target: str = None, datatype:
try:
pb_datatype = GetRequest.DataType.Value(datatype.upper())
except ValueError:
logger.error(f"The GetRequest data type \"{datatype}\" is not within the defined range. Using default type 'all'.")
logger.error(
f"The GetRequest data type \"{datatype}\" is not within the defined range. Using default type 'all'."
)
pb_datatype = 0

# Set Protobuf value for encoding
Expand All @@ -448,7 +452,9 @@ def get(self, prefix: str = "", path: list = None, target: str = None, datatype:
raise gNMIException("Conversion of gNMI paths to the Protobuf format failed", e)

try:
gnmi_message_request = GetRequest(prefix=protobuf_prefix, path=protobuf_paths, type=pb_datatype, encoding=pb_encoding)
gnmi_message_request = GetRequest(
prefix=protobuf_prefix, path=protobuf_paths, type=pb_datatype, encoding=pb_encoding
)
debug_gnmi_msg(self.__debug, gnmi_message_request, "gNMI request")

gnmi_message_response = self.__stub.Get(gnmi_message_request, metadata=self.__metadata)
Expand All @@ -465,19 +471,25 @@ def get(self, prefix: str = "", path: list = None, target: str = None, datatype:
notification_container = {}

# Message Notification, Key timestamp
notification_container.update(
{"timestamp": notification.timestamp}
) if notification.timestamp else notification_container.update({"timestamp": 0})
(
notification_container.update({"timestamp": notification.timestamp})
if notification.timestamp
else notification_container.update({"timestamp": 0})
)

# Message Notification, Key prefix
notification_container.update(
{"prefix": gnmi_path_degenerator(notification.prefix)}
) if notification.prefix else notification_container.update({"prefix": None})
(
notification_container.update({"prefix": gnmi_path_degenerator(notification.prefix)})
if notification.prefix
else notification_container.update({"prefix": None})
)

# Message Notification, Key alias
notification_container.update(
{"alias": notification.alias}
) if notification.alias else notification_container.update({"alias": None})
(
notification_container.update({"alias": notification.alias})
if notification.alias
else notification_container.update({"alias": None})
)

# Message Notification, Key atomic
notification_container.update({"atomic": notification.atomic})
Expand All @@ -490,9 +502,11 @@ def get(self, prefix: str = "", path: list = None, target: str = None, datatype:
update_container = {}

# Message Update, Key path
update_container.update(
{"path": gnmi_path_degenerator(update_msg.path)}
) if update_msg.path else update_container.update({"path": None})
(
update_container.update({"path": gnmi_path_degenerator(update_msg.path)})
if update_msg.path
else update_container.update({"path": None})
)

# Message Update, Key val
if update_msg.HasField("val"):
Expand All @@ -502,7 +516,9 @@ def get(self, prefix: str = "", path: list = None, target: str = None, datatype:
)

elif update_msg.val.HasField("json_val"):
update_container.update({"val": process_potentially_json_value(update_msg.val.json_val)})
update_container.update(
{"val": process_potentially_json_value(update_msg.val.json_val)}
)

elif update_msg.val.HasField("string_val"):
update_container.update({"val": update_msg.val.string_val})
Expand Down Expand Up @@ -627,13 +643,18 @@ def set(
if replace:
paths_to_collect_list.extend([path_tuple[0] for path_tuple in replace])

pre_change_dict = self.get(prefix=prefix,
path=paths_to_collect_list,
encoding=encoding,
datatype='config')
pre_change_dict = self.get(
prefix=prefix, path=paths_to_collect_list, encoding=encoding, datatype="config"
)

if gnmi_extension:
gnmi_message_request = SetRequest(prefix=protobuf_prefix, delete=del_protobuf_paths, update=update_msg, replace=replace_msg, extension=[gnmi_extension])
gnmi_message_request = SetRequest(
prefix=protobuf_prefix,
delete=del_protobuf_paths,
update=update_msg,
replace=replace_msg,
extension=[gnmi_extension],
)
else:
gnmi_message_request = SetRequest(
prefix=protobuf_prefix, delete=del_protobuf_paths, update=update_msg, replace=replace_msg
Expand All @@ -647,14 +668,18 @@ def set(
response = {}

# Message SetResponse, Key timestamp
response.update(
{"timestamp": gnmi_message_response.timestamp}
) if gnmi_message_response.timestamp else response.update({"timestamp": 0})
(
response.update({"timestamp": gnmi_message_response.timestamp})
if gnmi_message_response.timestamp
else response.update({"timestamp": 0})
)

# Message SetResponse, Key prefix
response.update(
{"prefix": gnmi_path_degenerator(gnmi_message_response.prefix)}
) if gnmi_message_response.prefix else response.update({"prefix": None})
(
response.update({"prefix": gnmi_path_degenerator(gnmi_message_response.prefix)})
if gnmi_message_response.prefix
else response.update({"prefix": None})
)

if gnmi_message_response.response:
response.update({"response": []})
Expand All @@ -663,9 +688,11 @@ def set(
response_container = {}

# Message UpdateResult, Key path
response_container.update(
{"path": gnmi_path_degenerator(response_entry.path)}
) if response_entry.path else response_container.update({"path": None})
(
response_container.update({"path": gnmi_path_degenerator(response_entry.path)})
if response_entry.path
else response_container.update({"path": None})
)

## Message UpdateResult, Key op
if response_entry.op:
Expand All @@ -684,11 +711,13 @@ def set(

## Adding collection of data for diff before the change
if self.__show_diff:
post_change_dict = self.get(path=paths_to_collect_list, encoding=encoding, datatype='config')
post_change_dict = self.get(path=paths_to_collect_list, encoding=encoding, datatype="config")

is_printable = True if self.__show_diff == "print" else False

diff_list = diff_openconfig(pre_dict=pre_change_dict, post_dict=post_change_dict, is_printable=is_printable)
diff_list = diff_openconfig(
pre_dict=pre_change_dict, post_dict=post_change_dict, is_printable=is_printable
)

if diff_list and self.__show_diff == "get":
return response, diff_list
Expand Down Expand Up @@ -1084,8 +1113,7 @@ def next(self):
Blocks until one is available."""
return self._next_update(timeout=None)

def _next_update(self, timeout=None):
...
def _next_update(self, timeout=None): ...

# Overridden by each concrete class, as they each have slightly different
# behaviour around waiting (or not) for a sync_response flag
Expand Down Expand Up @@ -1203,9 +1231,11 @@ def telemetryParser(in_message=None, debug: bool = False):
if in_message.HasField("update"):
response.update({"update": {"update": []}})

response["update"].update(
{"timestamp": in_message.update.timestamp}
) if in_message.update.timestamp else in_message.update({"timestamp": 0})
(
response["update"].update({"timestamp": in_message.update.timestamp})
if in_message.update.timestamp
else in_message.update({"timestamp": 0})
)

if in_message.update.HasField("prefix"):
resource_prefix = []
Expand All @@ -1227,9 +1257,11 @@ def telemetryParser(in_message=None, debug: bool = False):
update_container = {}

# Message Update, Key path
update_container.update(
{"path": gnmi_path_degenerator(update_msg.path)}
) if update_msg.path else update_container.update({"path": None})
(
update_container.update({"path": gnmi_path_degenerator(update_msg.path)})
if update_msg.path
else update_container.update({"path": None})
)

if update_msg.val:
if update_msg.val.HasField("json_ietf_val"):
Expand Down
5 changes: 3 additions & 2 deletions pygnmi/create_gnmi_extension.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""This module contains the converter of dict() to Extension() GRPC class
(c)2019-2022, karneliuk.com"""
(c)2019-2024, karneliuk.com"""

# Modules
import datetime
from pygnmi.spec.v080.gnmi_ext_pb2 import Extension
Expand Down Expand Up @@ -59,7 +60,7 @@ def _get_time_ns_epoch(time_in_question) -> int:
result = int(time_stamp.timestamp() * pow(10, 9))

except Exception as err:
err.args += (f"Time conversion error: cannot convert {time_in_question}, use 'yyyy-mm-ddTHH:MM:SSZ' format. Details: {err}")
err.args += f"Time conversion error: cannot convert {time_in_question}, use 'yyyy-mm-ddTHH:MM:SSZ' format. Details: {err}"
raise

return result
Loading

0 comments on commit 21ba8ae

Please sign in to comment.