diff --git a/lib/ansible/module_utils/network/common/netconf.py b/lib/ansible/module_utils/network/common/netconf.py index 234d125830e..2cec50a8da2 100644 --- a/lib/ansible/module_utils/network/common/netconf.py +++ b/lib/ansible/module_utils/network/common/netconf.py @@ -25,13 +25,19 @@ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # +import sys + from ansible.module_utils._text import to_text, to_native from ansible.module_utils.connection import Connection, ConnectionError try: - from lxml.etree import Element, fromstring + from lxml.etree import Element, fromstring, XMLSyntaxError except ImportError: from xml.etree.ElementTree import Element, fromstring + if sys.version_info < (2, 7): + from xml.parsers.expat import ExpatError as XMLSyntaxError + else: + from xml.etree.ElementTree import ParseError as XMLSyntaxError NS_MAP = {'nc': "urn:ietf:params:xml:ns:netconf:base:1.0"} @@ -67,25 +73,28 @@ class NetconfConnection(Connection): def parse_rpc_error(self, rpc_error): if self.check_rc: - error_root = fromstring(rpc_error) - root = Element('root') - root.append(error_root) + try: + error_root = fromstring(rpc_error) + root = Element('root') + root.append(error_root) - error_list = root.findall('.//nc:rpc-error', NS_MAP) - if not error_list: - raise ConnectionError(to_text(rpc_error, errors='surrogate_then_replace')) - - warnings = [] - for error in error_list: - try: - message = error.find('./nc:error-message', NS_MAP).text - except Exception: - message = error.find('./nc:error-info', NS_MAP).text - - severity = error.find('./nc:error-severity', NS_MAP).text - - if severity == 'warning' and self.ignore_warning: - warnings.append(message) - else: + error_list = root.findall('.//nc:rpc-error', NS_MAP) + if not error_list: raise ConnectionError(to_text(rpc_error, errors='surrogate_then_replace')) - return warnings + + warnings = [] + for error in error_list: + try: + message = error.find('./nc:error-message', NS_MAP).text + except Exception: + message = error.find('./nc:error-info', NS_MAP).text + + severity = error.find('./nc:error-severity', NS_MAP).text + + if severity == 'warning' and self.ignore_warning: + warnings.append(message) + else: + raise ConnectionError(to_text(rpc_error, errors='surrogate_then_replace')) + return warnings + except XMLSyntaxError: + raise ConnectionError(rpc_error) diff --git a/lib/ansible/plugins/action/iosxr.py b/lib/ansible/plugins/action/iosxr.py index 5f2b2ba3cdf..89f4e085d97 100644 --- a/lib/ansible/plugins/action/iosxr.py +++ b/lib/ansible/plugins/action/iosxr.py @@ -41,11 +41,7 @@ class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): socket_path = None - if self._play_context.connection == 'network_cli': - provider = self._task.args.get('provider', {}) - if any(provider.values()): - display.warning('provider is unnecessary when using network_cli and will be ignored') - elif self._play_context.connection == 'local': + if self._play_context.connection == 'local': provider = load_provider(iosxr_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) if self._task.action in ['iosxr_netconf', 'iosxr_config', 'iosxr_command'] or \ @@ -77,6 +73,10 @@ class ActionModule(_ActionModule): 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path + else: + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using {0} and will be ignored'.format(self._play_context.connection)) # make sure we are in the right cli context which should be # enable mode and not config module diff --git a/test/integration/targets/iosxr_banner/tasks/netconf.yaml b/test/integration/targets/iosxr_banner/tasks/netconf.yaml index 1286b354228..0e92b1c60fb 100644 --- a/test/integration/targets/iosxr_banner/tasks/netconf.yaml +++ b/test/integration/targets/iosxr_banner/tasks/netconf.yaml @@ -9,8 +9,14 @@ - name: set test_items set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" -- name: run test case - include: "{{ test_case_to_run }}" +- name: run test cases (connection=netconf) + include: "{{ test_case_to_run }} ansible_connection=netconf" with_items: "{{ test_items }}" loop_control: loop_var: test_case_to_run + +- name: run test case (connection=local) + include: "{{ test_case_to_run }} ansible_connection=local" + with_first_found: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/iosxr_banner/tests/netconf/basic-login.yaml b/test/integration/targets/iosxr_banner/tests/netconf/basic-login.yaml index 3c0518ee388..4335d598270 100644 --- a/test/integration/targets/iosxr_banner/tests/netconf/basic-login.yaml +++ b/test/integration/targets/iosxr_banner/tests/netconf/basic-login.yaml @@ -1,11 +1,4 @@ --- -- name: Enable Netconf service - iosxr_netconf: - netconf_port: 830 - netconf_vrf: 'default' - state: present - register: result - - name: setup - remove login iosxr_banner: banner: login diff --git a/test/integration/targets/iosxr_banner/tests/netconf/basic-motd.yaml b/test/integration/targets/iosxr_banner/tests/netconf/basic-motd.yaml index 241910ad6bc..49969dd6162 100644 --- a/test/integration/targets/iosxr_banner/tests/netconf/basic-motd.yaml +++ b/test/integration/targets/iosxr_banner/tests/netconf/basic-motd.yaml @@ -1,11 +1,4 @@ --- -- name: Enable Netconf service - iosxr_netconf: - netconf_port: 830 - netconf_vrf: 'default' - state: present - register: result - - name: setup - remove motd iosxr_banner: banner: motd diff --git a/test/integration/targets/iosxr_banner/tests/netconf/basic-no-login.yaml b/test/integration/targets/iosxr_banner/tests/netconf/basic-no-login.yaml index 2601bf1f445..c8bb8f16166 100644 --- a/test/integration/targets/iosxr_banner/tests/netconf/basic-no-login.yaml +++ b/test/integration/targets/iosxr_banner/tests/netconf/basic-no-login.yaml @@ -1,11 +1,4 @@ --- -- name: Enable Netconf service - iosxr_netconf: - netconf_port: 830 - netconf_vrf: 'default' - state: present - register: result - - name: Setup iosxr_banner: banner: login diff --git a/test/integration/targets/iosxr_interface/tasks/netconf.yaml b/test/integration/targets/iosxr_interface/tasks/netconf.yaml index 1286b354228..0e92b1c60fb 100644 --- a/test/integration/targets/iosxr_interface/tasks/netconf.yaml +++ b/test/integration/targets/iosxr_interface/tasks/netconf.yaml @@ -9,8 +9,14 @@ - name: set test_items set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" -- name: run test case - include: "{{ test_case_to_run }}" +- name: run test cases (connection=netconf) + include: "{{ test_case_to_run }} ansible_connection=netconf" with_items: "{{ test_items }}" loop_control: loop_var: test_case_to_run + +- name: run test case (connection=local) + include: "{{ test_case_to_run }} ansible_connection=local" + with_first_found: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/iosxr_interface/tests/netconf/basic.yaml b/test/integration/targets/iosxr_interface/tests/netconf/basic.yaml index cbda5e16162..515f1db39b0 100644 --- a/test/integration/targets/iosxr_interface/tests/netconf/basic.yaml +++ b/test/integration/targets/iosxr_interface/tests/netconf/basic.yaml @@ -1,13 +1,6 @@ --- - debug: msg="START iosxr_interface netconf/basic.yaml" -- name: Enable Netconf service - iosxr_netconf: - netconf_port: 830 - netconf_vrf: 'default' - state: present - register: result - - name: Setup interface iosxr_interface: name: GigabitEthernet0/0/0/1 diff --git a/test/integration/targets/prepare_iosxr_tests/tasks/main.yml b/test/integration/targets/prepare_iosxr_tests/tasks/main.yml index 4a57bfe3927..251506c71c2 100644 --- a/test/integration/targets/prepare_iosxr_tests/tasks/main.yml +++ b/test/integration/targets/prepare_iosxr_tests/tasks/main.yml @@ -1,10 +1,17 @@ --- - - name: Ensure we have loopback 888 for testing iosxr_config: src: config.j2 connection: network_cli +- name: Enable Netconf service + iosxr_netconf: + netconf_port: 830 + netconf_vrf: 'default' + state: present + connection: network_cli + tags: netconf + # Some AWS hostnames can be longer than those allowed by the system we are testing # Truncate the hostname # http://jinja.pocoo.org/docs/2.9/templates/#truncate