From d6ef7c8530ca1f45cc1a0b41a97919fa4d98e1f1 Mon Sep 17 00:00:00 2001 From: Xu Yuandong Date: Mon, 23 Sep 2019 21:13:42 +0800 Subject: [PATCH] =?UTF-8?q?module=5Futils-network-cloudengine=EF=BC=9A=20f?= =?UTF-8?q?ix=20get=5Fnc=5Fnext.=20(#62587)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix get_nc_next. * add a changelog fragment. * upadte for changelgo fragment. * merge two prs, one depens another. * merge two prs, one depens another. * update changelog. --- ...62587-module_utils-network-cloudengine.yml | 3 +++ .../module_utils/network/cloudengine/ce.py | 11 +++++----- lib/ansible/plugins/netconf/ce.py | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/62587-module_utils-network-cloudengine.yml diff --git a/changelogs/fragments/62587-module_utils-network-cloudengine.yml b/changelogs/fragments/62587-module_utils-network-cloudengine.yml new file mode 100644 index 0000000000..708128caf3 --- /dev/null +++ b/changelogs/fragments/62587-module_utils-network-cloudengine.yml @@ -0,0 +1,3 @@ +bugfixes: + - "Cloudengine module_utils - the ``set-id`` (RPC-REPLY XML attribute) may change over the time althougth ``set-id`` is the identity of the next RPC packet." + - "Cloudengine netconf plugin - add a dispatch RPC function,just return original RPC-REPLY, the function is used by ``Cloudengine module_utils``." diff --git a/lib/ansible/module_utils/network/cloudengine/ce.py b/lib/ansible/module_utils/network/cloudengine/ce.py index 43d689f0ed..01df0e795d 100644 --- a/lib/ansible/module_utils/network/cloudengine/ce.py +++ b/lib/ansible/module_utils/network/cloudengine/ce.py @@ -357,12 +357,13 @@ def get_nc_next(module, xml_str): response = conn.get(xml_str, if_rpc_reply=True) result = response.find('./*') set_id = response.get('set-id') - fetch_node = new_ele_ns('get-next', 'http://www.huawei.com/netconf/capability/base/1.0', {'set-id': set_id}) - while True: + while True and set_id is not None: try: - next = conn.dispatch(etree.tostring(fetch_node)) - if next is not None: - result.extend(next) + fetch_node = new_ele_ns('get-next', 'http://www.huawei.com/netconf/capability/base/1.0', {'set-id': set_id}) + next_xml = conn.dispatch_rpc(etree.tostring(fetch_node)) + if next_xml is not None: + result.extend(next_xml.find('./*')) + set_id = next_xml.get('set-id') except ConnectionError: break if result is not None: diff --git a/lib/ansible/plugins/netconf/ce.py b/lib/ansible/plugins/netconf/ce.py index ef436d5229..784e283d57 100644 --- a/lib/ansible/plugins/netconf/ce.py +++ b/lib/ansible/plugins/netconf/ce.py @@ -36,6 +36,11 @@ try: except (ImportError, AttributeError): # paramiko and gssapi are incompatible and raise AttributeError not ImportError HAS_NCCLIENT = False +try: + from lxml.etree import fromstring +except ImportError: + from xml.etree.ElementTree import fromstring + class Netconf(NetconfBase): @@ -213,3 +218,19 @@ class Netconf(NetconfBase): @ensure_connected def discard_changes(self, *args, **kwargs): return self.m.discard_changes(*args, **kwargs).data_xml + + @ensure_ncclient + @ensure_connected + def dispatch_rpc(self, rpc_command=None, source=None, filter=None): + """ + Execute rpc on the remote device eg. dispatch('get-next') + :param rpc_command: specifies rpc command to be dispatched either in plain text or in xml element format (depending on command) + :param source: name of the configuration datastore being queried + :param filter: specifies the portion of the configuration to retrieve (by default entire configuration is retrieved) + :return: Returns xml string containing the rpc-reply response received from remote host + """ + if rpc_command is None: + raise ValueError('rpc_command value must be provided') + resp = self.m.dispatch(fromstring(rpc_command), source=source, filter=filter) + # just return rpc-reply xml + return resp.xml