Skip to content

Commit

Permalink
Merge pull request #51 from miott/dev
Browse files Browse the repository at this point in the history
Fix issue with check_config and set prefix.
  • Loading branch information
remingtonc authored May 1, 2020
2 parents bb9dc4b + 770d9e7 commit 9b09824
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/cisco_gnmi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
from .xe import XEClient
from .builder import ClientBuilder

__version__ = "1.0.7"
__version__ = "1.0.8"
16 changes: 10 additions & 6 deletions src/cisco_gnmi/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
from .util import gen_target_netloc, get_cert_from_target, get_cn_from_cert


LOGGER = logging.getLogger(__name__)
logger = LOGGER


class ClientBuilder(object):
"""Builder for the creation of a gNMI client.
Supports construction of base Client and XRClient.
Expand Down Expand Up @@ -134,8 +138,8 @@ def set_os(self, name=None):
if name not in self.os_class_map.keys():
raise Exception("OS not supported!")
else:
LOGGER.debug("Using %s wrapper.", name or "Client")
self.__client_class = self.os_class_map[name]
logging.debug("Using %s wrapper.", name or "Client")
return self

def set_secure(
Expand Down Expand Up @@ -257,7 +261,7 @@ def set_channel_option(self, name, value):
found_index = index
break
if found_index is not None:
logging.warning("Found existing channel option %s, overwriting!", name)
LOGGER.warning("Found existing channel option %s, overwriting!", name)
self.__channel_options[found_index] = new_option
else:
self.__channel_options.append(new_option)
Expand All @@ -279,26 +283,26 @@ def construct(self):
self.__root_certificates, self.__private_key, self.__certificate_chain
)
if self.__username and self.__password:
LOGGER.debug("Using username/password call authentication.")
channel_metadata_creds = grpc.metadata_call_credentials(
CiscoAuthPlugin(self.__username, self.__password)
)
logging.debug("Using username/password call authentication.")
if channel_ssl_creds and channel_metadata_creds:
LOGGER.debug("Using SSL/metadata authentication composite credentials.")
channel_creds = grpc.composite_channel_credentials(
channel_ssl_creds, channel_metadata_creds
)
logging.debug("Using SSL/metadata authentication composite credentials.")
else:
LOGGER.debug("Using SSL credentials, no metadata authentication.")
channel_creds = channel_ssl_creds
logging.debug("Using SSL credentials, no metadata authentication.")
if self.__ssl_target_name_override is not False:
if self.__ssl_target_name_override is None:
if not self.__root_certificates:
raise Exception("Deriving override requires root certificate!")
self.__ssl_target_name_override = get_cn_from_cert(
self.__root_certificates
)
logging.warning(
LOGGER.warning(
"Overriding SSL option from certificate could increase MITM susceptibility!"
)
self.set_channel_option(
Expand Down
16 changes: 15 additions & 1 deletion src/cisco_gnmi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
from . import util


LOGGER = logging.getLogger(__name__)
logger = LOGGER


class Client(object):
"""gNMI gRPC wrapper client to ease usage of gNMI.
Expand Down Expand Up @@ -109,6 +113,7 @@ def capabilities(self):
proto.gnmi_pb2.CapabilityResponse
"""
message = proto.gnmi_pb2.CapabilityRequest()
LOGGER.debug(str(message))
response = self.service.Capabilities(message)
return response

Expand Down Expand Up @@ -163,6 +168,9 @@ def get(
request.use_models = use_models
if extension:
request.extension = extension

LOGGER.debug(str(request))

get_response = self.service.Get(request)
return get_response

Expand Down Expand Up @@ -190,7 +198,7 @@ def set(
"""
request = proto.gnmi_pb2.SetRequest()
if prefix:
request.prefix = prefix
request.prefix.CopyFrom(prefix)
test_list = [updates, replaces, deletes]
if not any(test_list):
raise Exception("At least update, replace, or delete must be specified!")
Expand All @@ -207,6 +215,9 @@ def set(
request.delete.extend(deletes)
if extensions:
request.extension.extend(extensions)

LOGGER.debug(str(request))

response = self.service.Set(request)
return response

Expand Down Expand Up @@ -244,6 +255,9 @@ def validate_request(request):
)
if extensions:
subscribe_request.extensions.extend(extensions)

LOGGER.debug(str(subscribe_request))

return subscribe_request

response_stream = self.service.Subscribe(
Expand Down
4 changes: 4 additions & 0 deletions src/cisco_gnmi/nx.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
from .client import Client, proto, util


LOGGER = logging.getLogger(__name__)
logger = LOGGER


class NXClient(Client):
"""NX-OS-specific wrapper for gNMI functionality.
Expand Down
14 changes: 9 additions & 5 deletions src/cisco_gnmi/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
from urlparse import urlparse


LOGGER = logging.getLogger(__name__)
logger = LOGGER


def gen_target_netloc(target, netloc_prefix="//", default_port=9339):
"""Parses and validates a supplied target URL for gRPC calls.
Uses urllib to parse the netloc property from the URL.
Expand All @@ -51,11 +55,11 @@ def gen_target_netloc(target, netloc_prefix="//", default_port=9339):
if not parsed_target.netloc:
raise ValueError("Unable to parse netloc from target URL %s!" % target)
if parsed_target.scheme:
logging.debug("Scheme identified in target, ignoring and using netloc.")
LOGGER.debug("Scheme identified in target, ignoring and using netloc.")
target_netloc = parsed_target
if parsed_target.port is None:
ported_target = "%s:%i" % (parsed_target.hostname, default_port)
logging.debug("No target port detected, reassembled to %s.", ported_target)
LOGGER.debug("No target port detected, reassembled to %s.", ported_target)
target_netloc = gen_target_netloc(ported_target)
return target_netloc

Expand Down Expand Up @@ -120,11 +124,11 @@ def get_cn_from_cert(cert_pem):
cert_cns = cert_parsed.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)
if len(cert_cns) > 0:
if len(cert_cns) > 1:
logging.warning(
LOGGER.warning(
"Multiple CNs found for certificate, defaulting to the first one."
)
cert_cn = cert_cns[0].value
logging.debug("Using %s as certificate CN.", cert_cn)
LOGGER.debug("Using %s as certificate CN.", cert_cn)
else:
logging.warning("No CN found for certificate.")
LOGGER.warning("No CN found for certificate.")
return cert_cn
22 changes: 16 additions & 6 deletions src/cisco_gnmi/xe.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
from .client import Client, proto, util


LOGGER = logging.getLogger(__name__)
logger = LOGGER


class XEClient(Client):
"""IOS XE-specific wrapper for gNMI functionality.
Assumes IOS XE 16.12+
Expand Down Expand Up @@ -108,7 +112,13 @@ def delete_xpaths(self, xpaths, prefix=None):
paths.append(self.parse_xpath_to_gnmi_path(xpath))
return self.set(deletes=paths)

def set_json(self, update_json_configs=None, replace_json_configs=None, ietf=True):
def set_json(
self,
update_json_configs=None,
replace_json_configs=None,
ietf=True,
prefix=None,
):
"""A convenience wrapper for set() which assumes JSON payloads and constructs desired messages.
All parameters are optional, but at least one must be present.
Expand All @@ -132,15 +142,15 @@ def set_json(self, update_json_configs=None, replace_json_configs=None, ietf=Tru
raise Exception("Must supply at least one set of configurations to method!")

def check_configs(name, configs):
if isinstance(name, string_types):
logging.debug("Handling %s as JSON string.", name)
if isinstance(configs, string_types):
LOGGER.debug("Handling %s as JSON string.", name)
try:
configs = json.loads(configs)
except:
raise Exception("{name} is invalid JSON!".format(name=name))
configs = [configs]
elif isinstance(name, dict):
logging.debug("Handling %s as already serialized JSON object.", name)
elif isinstance(configs, dict):
LOGGER.debug("Handling %s as already serialized JSON object.", name)
configs = [configs]
elif not isinstance(configs, (list, set)):
raise Exception(
Expand Down Expand Up @@ -171,7 +181,7 @@ def create_updates(name, configs):

updates = create_updates("update_json_configs", update_json_configs)
replaces = create_updates("replace_json_configs", replace_json_configs)
return self.set(updates=updates, replaces=replaces)
return self.set(prefix=prefix, updates=updates, replaces=replaces)

def get_xpaths(self, xpaths, data_type="ALL", encoding="JSON_IETF"):
"""A convenience wrapper for get() which forms proto.gnmi_pb2.Path from supplied xpaths.
Expand Down
8 changes: 6 additions & 2 deletions src/cisco_gnmi/xr.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
from .client import Client, proto, util


LOGGER = logging.getLogger(__name__)
logger = LOGGER


class XRClient(Client):
"""IOS XR-specific wrapper for gNMI functionality.
Expand Down Expand Up @@ -130,14 +134,14 @@ def set_json(self, update_json_configs=None, replace_json_configs=None, ietf=Tru

def check_configs(name, configs):
if isinstance(name, string_types):
logging.debug("Handling %s as JSON string.", name)
LOGGER.debug("Handling %s as JSON string.", name)
try:
configs = json.loads(configs)
except:
raise Exception("{name} is invalid JSON!".format(name=name))
configs = [configs]
elif isinstance(name, dict):
logging.debug("Handling %s as already serialized JSON object.", name)
LOGGER.debug("Handling %s as already serialized JSON object.", name)
configs = [configs]
elif not isinstance(configs, (list, set)):
raise Exception(
Expand Down

0 comments on commit 9b09824

Please sign in to comment.