XML parse error when trying to connect to Juniper Junos device over Netconf

Hi all, hope I’m in the right place for this question.

I’m trying to use Ansible to update the config on Juniper devices on our network. I’m starting with a small script to fetch the current running config, just as a sanity check to make sure my Ansible install is working correctly.

I’m fairly sure my playbook and inventory are correct - the connection is succeeding, but then it’s breaking down from there. When I try to run the playbook, I get the following error from Ansible, and the playbook fails:

nick.lockhart@netops-01:/srv/ansible$ ansible-playbook -u lab -k -i inventory playbooks/junos-get-info.yaml
SSH password:

PLAY [Get interface info to file] *******************************************************************************************************************************************

TASK [get interface information] ********************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: b"name 'RPCError' is not defined"
[WARNING]: Platform linux on host lab-pe-02is using the discovered Python interpreter at /usr/bin/python3, but future installation of another Python interpreter could
change the meaning of that path. See https://docs.ansible.com/ansible/2.10/reference_appendices/interpreter_discovery.html for more information.
fatal: [lab-pe-02]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "module_stderr": "[attached below]", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

PLAY RECAP ******************************************************************************************************************************************************************
lab-pe-02                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

nick.lockhart@netops-01:/srv/ansible$

and I’ve printed the stderr to make it more readable:

Traceback (most recent call last):
  File "/tmp/ansible_junipernetworks.junos.junos_rpc_payload_sdq4f5bz/ansible_junipernetworks.junos.junos_rpc_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py", line 91, in parse_rpc_error
  File "/usr/lib/python3.10/xml/etree/ElementTree.py", line 1342, in XML
    parser.feed(text)
xml.etree.ElementTree.ParseError: syntax error: line 1, column 0

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/nick.lockhart/.ansible/tmp/ansible-local-21323x9h_bhk7/ansible-tmp-1718959778.907722-21326-77614718989736/AnsiballZ_junos_rpc.py", line 102, in <module>
    _ansiballz_main()
  File "/home/nick.lockhart/.ansible/tmp/ansible-local-21323x9h_bhk7/ansible-tmp-1718959778.907722-21326-77614718989736/AnsiballZ_junos_rpc.py", line 94, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/nick.lockhart/.ansible/tmp/ansible-local-21323x9h_bhk7/ansible-tmp-1718959778.907722-21326-77614718989736/AnsiballZ_junos_rpc.py", line 40, in invoke_module
    runpy.run_module(mod_name='ansible_collections.junipernetworks.junos.plugins.modules.junos_rpc', init_globals=None, run_name='__main__', alter_sys=True)
  File "/usr/lib/python3.10/runpy.py", line 224, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib/python3.10/runpy.py", line 96, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_junipernetworks.junos.junos_rpc_payload_sdq4f5bz/ansible_junipernetworks.junos.junos_rpc_payload.zip/ansible_collections/junipernetworks/junos/plugins/modules/junos_rpc.py", line 177, in <module>
  File "/tmp/ansible_junipernetworks.junos.junos_rpc_payload_sdq4f5bz/ansible_junipernetworks.junos.junos_rpc_payload.zip/ansible_collections/junipernetworks/junos/plugins/modules/junos_rpc.py", line 158, in main
  File "/tmp/ansible_junipernetworks.junos.junos_rpc_payload_sdq4f5bz/ansible_junipernetworks.junos.junos_rpc_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py", line 58, in exec_rpc
  File "/tmp/ansible_junipernetworks.junos.junos_rpc_payload_sdq4f5bz/ansible_junipernetworks.junos.junos_rpc_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py", line 80, in __rpc__
  File "/tmp/ansible_junipernetworks.junos.junos_rpc_payload_sdq4f5bz/ansible_junipernetworks.junos.junos_rpc_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py", line 126, in parse_rpc_error
ansible.module_utils.connection.ConnectionError: b"name 'RPCError' is not defined"

Getting an XML parse error is not what I’d expect - just to check, I manually SSH’d to the Netconf port, and as far as I can tell, it’s returning valid XML:

nick.lockhart@netops-01:/srv/ansible$ ssh -p 830 lab@[redacted]
(lab@[redacted]) Password:
<!-- No zombies were killed during the creation of this user interface -->
<!-- user lab, class super-user -->
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <capabilities>
<!-- ... -->

Have I missed something in my playbook or inventory?

I’ve attached my files below for reference.

Inventory:

lab:
  hosts:
    lab-pe-02:
      ansible_port: 830
      ansible_host: # redacted - hostname here is correct
      ansible_network_os: junipernetworks.junos.junos
      ansible_connection: ansible.netcommon.netconf

Playbook:

---
  - name: Get interface info to file
    hosts: all
#    roles:
#      - junipernetworks.junos.role
    gather_facts: no
    connection: local

    tasks:
    - name: get interface information
      junipernetworks.junos.junos_rpc:
        rpc: get-interface-information
        args:
          interface-name: ae1
        output:  xml
      register: config_output

    - name: Write output to file
      copy:
        content:  "{{ config_output | to_nice_json }}"
        dest: "{{ playbook_dir }}/output/test-1.json"

And the output of ansible --version:

ansible 2.10.8
  config file = None
  configured module search path = ['/home/nick.lockhart/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]

I think I’ve attached everything I need to here - if further details on my setup or environment are needed, please let me know and I’ll add it as soon as I can.

Any help would be greatly appreciated - I’ve not really used Ansible before… :sweat_smile:

Hi again, took a break over the weekend, came back this morning and did some poking at this issue.

Turns out this was my fault, not Ansible’s. The XML error was a red herring - the real issue was RPCError is not defined. I didn’t have ncclient installed, so an import statement in the netconf module was failing, which caused the entire task to fall over. :person_facepalming:

If you’re running into this issue, make sure you’ve got ncclient installed as a system module. On Ubuntu and Debian, this is python3-ncclient.

1 Like