Skip to content

Commit

Permalink
add netconf base namespace to edit-config config element if it is mis…
Browse files Browse the repository at this point in the history
…sing (#528)

* add netconf base namespace to edit-config config element if it is missing
  • Loading branch information
einarnn committed Apr 10, 2022
1 parent 872b1dc commit e4dad6e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 2 deletions.
9 changes: 9 additions & 0 deletions ncclient/devices/csr.py
Expand Up @@ -14,6 +14,7 @@


from .default import DefaultDeviceHandler
from warnings import warn

def csr_unknown_host_cb(host, fingerprint):
#This will ignore the unknown host check when connecting to CSR devices
Expand All @@ -25,7 +26,15 @@ class CsrDeviceHandler(DefaultDeviceHandler):
"""
def __init__(self, device_params):
warn(
'CsrDeviceHandler is deprecated, please use IosxeDeviceHandler',
DeprecationWarning,
stacklevel=2)
super(CsrDeviceHandler, self).__init__(device_params)

def add_additional_ssh_connect_params(self, kwargs):
warn(
'CsrDeviceHandler is deprecated, please use IosxeDeviceHandler',
DeprecationWarning,
stacklevel=2)
kwargs['unknown_host_cb'] = csr_unknown_host_cb
13 changes: 13 additions & 0 deletions ncclient/devices/default.py
Expand Up @@ -255,6 +255,19 @@ def reply_parsing_error_transform(self, reply_cls):
def transform_reply(self):
return False

def transform_edit_config(self, node):
"""
Hook for working around bugs in devices that cannot deal with
standard config payloads for edits. This will be called
in EditConfig.request just before the request is submitted,
meaning it will get an XML tree rooted at edit-config.
:param node: the XML tree for edit-config
:return: either the original XML tree if no changes made or a modified XML tree
"""
return node

def get_xml_parser(self, session):
"""
vendor can chose which parser to use for RPC reply response.
Expand Down
16 changes: 14 additions & 2 deletions ncclient/devices/iosxe.py
Expand Up @@ -12,13 +12,17 @@
"""


from .default import DefaultDeviceHandler

from ncclient.operations.third_party.iosxe.rpc import SaveConfig
from ncclient.xml_ import BASE_NS_1_0

import logging
logger = logging.getLogger("ncclient.devices.iosxe")


def iosxe_unknown_host_cb(host, fingerprint):
#This will ignore the unknown host check when connecting to CSR devices
# This will ignore the unknown host check when connecting to CSR devices
return True

class IosxeDeviceHandler(DefaultDeviceHandler):
Expand All @@ -36,3 +40,11 @@ def add_additional_operations(self):

def add_additional_ssh_connect_params(self, kwargs):
kwargs['unknown_host_cb'] = iosxe_unknown_host_cb

def transform_edit_config(self, node):
# find the first node that has the tag "config" with no namespace
nodes = node.findall("./config")
if len(nodes) == 1:
logger.debug('IOS XE handler: patching namespace of config element')
nodes[0].tag = '{%s}%s' % (BASE_NS_1_0, 'config')
return node
1 change: 1 addition & 0 deletions ncclient/operations/edit.py
Expand Up @@ -72,6 +72,7 @@ def request(self, config, format='xml', target='candidate', default_operation=No
sub_ele(node, "url").text = config
else:
raise OperationError("Invalid URL.")
node = self._device_handler.transform_edit_config(node)
return self._request(node)


Expand Down
19 changes: 19 additions & 0 deletions test/unit/devices/test_iosxe.py
@@ -1,5 +1,17 @@
import unittest
from ncclient.devices.iosxe import *
from ncclient.xml_ import new_ele
from ncclient.xml_ import qualify
from ncclient.xml_ import validated_element


CFG_BROKEN = """
<config>
<native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
<hostname>tl-einarnn-c8kv</hostname>
</native>
</config>
"""


class TestIosxeDevice(unittest.TestCase):
Expand All @@ -20,3 +32,10 @@ def test_add_additional_ssh_connect_params(self):

def test_csr_unknown_host_cb(self):
self.assertTrue(iosxe_unknown_host_cb('host', 'fingerprint'))

def test_iosxe_transform_edit_config(self):
node = new_ele("edit-config")
node.append(validated_element(CFG_BROKEN, ("config", qualify("config"))))
node = self.obj.transform_edit_config(node)
config_nodes = node.findall('./config')
self.assertTrue(len(config_nodes) == 0)

0 comments on commit e4dad6e

Please sign in to comment.