diff --git a/changelogs/fragments/iosxr_netconf_plugin_fix.yaml b/changelogs/fragments/iosxr_netconf_plugin_fix.yaml new file mode 100644 index 00000000000..309e05cfecb --- /dev/null +++ b/changelogs/fragments/iosxr_netconf_plugin_fix.yaml @@ -0,0 +1,2 @@ +bugfixes: +- Fix iosxr netconf plugin response namespace (https://github.com/ansible/ansible/pull/49300) diff --git a/lib/ansible/module_utils/network/iosxr/iosxr.py b/lib/ansible/module_utils/network/iosxr/iosxr.py index 23575ce79d6..b49c72875af 100644 --- a/lib/ansible/module_utils/network/iosxr/iosxr.py +++ b/lib/ansible/module_utils/network/iosxr/iosxr.py @@ -358,7 +358,10 @@ def get_config_diff(module, running=None, candidate=None): def discard_config(module): conn = get_connection(module) try: - conn.discard_changes() + if is_netconf(module): + conn.discard_changes(remove_ns=True) + else: + conn.discard_changes() except ConnectionError as exc: module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) @@ -370,9 +373,9 @@ def commit_config(module, comment=None, confirmed=False, confirm_timeout=None, try: if is_netconf(module): if check: - reply = conn.validate() + reply = conn.validate(remove_ns=True) else: - reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist) + reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist, remove_ns=True) elif is_cliconf(module): if check: module.fail_json(msg="Validate configuration is not supported with network_cli connection type") @@ -389,7 +392,10 @@ def get_oper(module, filter=None): if filter is not None: try: - response = conn.get(filter) + if is_netconf(module): + response = conn.get(filter=filter, remove_ns=True) + else: + response = conn.get(filter) except ConnectionError as exc: module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) else: @@ -404,7 +410,7 @@ def get_config(module, config_filter=None, source='running'): # Note: Does not cache config in favour of latest config on every get operation. try: if is_netconf(module): - out = to_xml(conn.get_config(source=source, filter=config_filter)) + out = to_xml(conn.get_config(source=source, filter=config_filter, remove_ns=True)) elif is_cliconf(module): out = conn.get_config(source=source, flags=config_filter) cfg = out.strip() @@ -436,7 +442,7 @@ def load_config(module, command_filter, commit=False, replace=False, try: for filter in to_list(command_filter): - conn.edit_config(filter) + conn.edit_config(config=filter, remove_ns=True) candidate = get_config(module, source='candidate', config_filter=nc_get_filter) diff = get_config_diff(module, running, candidate) diff --git a/lib/ansible/plugins/netconf/iosxr.py b/lib/ansible/plugins/netconf/iosxr.py index a8a0e1b76c7..c64a61071b5 100644 --- a/lib/ansible/plugins/netconf/iosxr.py +++ b/lib/ansible/plugins/netconf/iosxr.py @@ -124,56 +124,80 @@ class Netconf(NetconfBase): # TODO: change .xml to .data_xml, when ncclient supports data_xml on all platforms @ensure_connected - def get(self, filter=None): + def get(self, filter=None, remove_ns=False): if isinstance(filter, list): filter = tuple(filter) try: - response = self.m.get(filter=filter) - return remove_namespaces(response) + resp = self.m.get(filter=filter) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml + return response except RPCError as exc: raise Exception(to_xml(exc.xml)) @ensure_connected - def get_config(self, source=None, filter=None): + def get_config(self, source=None, filter=None, remove_ns=False): if isinstance(filter, list): filter = tuple(filter) try: - response = self.m.get_config(source=source, filter=filter) - return remove_namespaces(response) + resp = self.m.get_config(source=source, filter=filter) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml + return response except RPCError as exc: raise Exception(to_xml(exc.xml)) @ensure_connected - def edit_config(self, config=None, format='xml', target='candidate', default_operation=None, test_option=None, error_option=None): + def edit_config(self, config=None, format='xml', target='candidate', default_operation=None, test_option=None, error_option=None, remove_ns=False): if config is None: raise ValueError('config value must be provided') try: - response = self.m.edit_config(config, format=format, target=target, default_operation=default_operation, test_option=test_option, - error_option=error_option) - return remove_namespaces(response) + resp = self.m.edit_config(config, format=format, target=target, default_operation=default_operation, test_option=test_option, + error_option=error_option) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml + return response except RPCError as exc: raise Exception(to_xml(exc.xml)) @ensure_connected - def commit(self, confirmed=False, timeout=None, persist=None): + def commit(self, confirmed=False, timeout=None, persist=None, remove_ns=False): try: - response = self.m.commit(confirmed=confirmed, timeout=timeout, persist=persist) - return remove_namespaces(response) + resp = self.m.commit(confirmed=confirmed, timeout=timeout, persist=persist) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml + return response except RPCError as exc: raise Exception(to_xml(exc.xml)) @ensure_connected - def validate(self, source="candidate"): + def validate(self, source="candidate", remove_ns=False): try: - response = self.m.validate(source=source) - return remove_namespaces(response) + resp = self.m.validate(source=source) + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml + return response except RPCError as exc: raise Exception(to_xml(exc.xml)) @ensure_connected - def discard_changes(self): + def discard_changes(self, remove_ns=False): try: - response = self.m.discard_changes() - return remove_namespaces(response) + resp = self.m.discard_changes() + if remove_ns: + response = remove_namespaces(resp) + else: + response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml + return response except RPCError as exc: raise Exception(to_xml(exc.xml))