ansible.netcommon icon indicating copy to clipboard operation
ansible.netcommon copied to clipboard

ansible.netcommon.restconf_config: RPC POST fails (reboot)

Open netgab opened this issue 2 years ago • 2 comments

SUMMARY

When performing a POST RPC operation to reboot a devide, the task fails.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

ansible.netcommon.restconf_config

ANSIBLE VERSION
ansible [core 2.14.1]
  config file = /home/student01/module03-3/ansible/ansible.cfg
  configured module search path = ['/home/student01/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/student01/module03-3/venv/lib/python3.9/site-packages/ansible
  ansible collection location = /home/student01/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/student01/module03-3/venv/bin/ansible
  python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110] (/home/student01/module03-3/venv/bin/python3)
  jinja version = 3.1.2
  libyaml = True
COLLECTION VERSION
Collection        Version
----------------- -------
ansible.netcommon 4.1.0  
CONFIGURATION
CONFIG_FILE() = /home/student01/module03-3/ansible/ansible.cfg
HOST_KEY_CHECKING(/home/student01/module03-3/ansible/ansible.cfg) = False
OS / ENVIRONMENT
  • Ansible control node: Debian 11
  • Ansible host: Cisco Catalyst 8000V
STEPS TO REPRODUCE
---
- name: "RESTCONF test playbook"
  hosts: "ios_xe"
  gather_facts: false
  vars:
    ansible_connection: ansible.netcommon.httpapi
    ansible_network_os: ansible.netcommon.restconf
    ansible_httpapi_use_ssl: true
    ansible_httpapi_validate_certs: false
    ansible_httpapi_port: 443
    ansible_httpapi_restconf_root: /restconf/data/
    ansible_user: "{{ lookup('env', 'USER') }}"
      
  tasks:
    - name: "RESTCONF: Reboot"
      ansible.netcommon.restconf_config:
        method: "post"
        path: "/Cisco-IOS-XE-rpc:reload"
        content: |
          {
              "Cisco-IOS-XE-rpc:input": {
                  "force": true,
                  "reason": "Test"
              }
          }
EXPECTED RESULTS

The IOS-XE devices should reboot.

ACTUAL RESULTS

The IOS-XE devices do not reboot. Ansible shows an HTTP 405 error:

TASK [RESTCONF: Reboot] ***********************************************************************************************************************************************************************************************************************************
task path: /home/student01/module03-3/ansible/play_restconf_post_rpc.yml:15
<10.21.128.202> attempting to start connection
<10.21.128.202> using connection plugin ansible.netcommon.httpapi
Found ansible-connection at path /home/student01/module03-3/venv/bin/ansible-connection
<10.21.128.202> local domain socket does not exist, starting it
<10.21.128.202> control socket path is /home/student01/.ansible/pc/cbffa12376
<10.21.128.202> Loading collection ansible.netcommon from /home/student01/module03-3/venv/lib/python3.9/site-packages/ansible_collections/ansible/netcommon
<10.21.128.202> local domain socket listeners started successfully
<10.21.128.202> loaded API plugin ansible_collections.ansible.netcommon.plugins.httpapi.restconf from path /home/student01/module03-3/venv/lib/python3.9/site-packages/ansible_collections/ansible/netcommon/plugins/httpapi/restconf.py for platform type ansible.netcommon.restconf
<10.21.128.202> 
<10.21.128.202> local domain socket path is /home/student01/.ansible/pc/cbffa12376
<10.21.128.202> ESTABLISH LOCAL CONNECTION FOR USER: student01
<10.21.128.202> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/student01/.ansible/tmp/ansible-local-335749i68q0if8 `"&& mkdir "` echo /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365 `" && echo ansible-tmp-1673590236.583306-335768-184237654076365="` echo /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365 `" ) && sleep 0'
Using module file /home/student01/module03-3/venv/lib/python3.9/site-packages/ansible_collections/ansible/netcommon/plugins/modules/restconf_config.py
<10.21.128.202> PUT /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/tmpjntyh1we TO /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365/AnsiballZ_restconf_config.py
<10.21.128.202> EXEC /bin/sh -c 'chmod u+x /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365/ /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365/AnsiballZ_restconf_config.py && sleep 0'
<10.21.128.202> EXEC /bin/sh -c '/home/student01/module03-3/venv/bin/python3 /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365/AnsiballZ_restconf_config.py && sleep 0'
<10.21.128.202> EXEC /bin/sh -c 'rm -f -r /home/student01/.ansible/tmp/ansible-local-335749i68q0if8/ansible-tmp-1673590236.583306-335768-184237654076365/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
  File "/tmp/ansible_ansible.netcommon.restconf_config_payload_1e0lfg7y/ansible_ansible.netcommon.restconf_config_payload.zip/ansible_collections/ansible/netcommon/plugins/modules/restconf_config.py", line 172, in main
  File "/tmp/ansible_ansible.netcommon.restconf_config_payload_1e0lfg7y/ansible_ansible.netcommon.restconf_config_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/restconf/restconf.py", line 32, in get
    return connection.send_request(
  File "/tmp/ansible_ansible.netcommon.restconf_config_payload_1e0lfg7y/ansible_ansible.netcommon.restconf_config_payload.zip/ansible/module_utils/connection.py", line 200, in __rpc__
    raise ConnectionError(to_text(msg, errors='surrogate_then_replace'), code=code)
fatal: [c8k_student01-1]: FAILED! => {
    "changed": false,
    "code": 405,
    "invocation": {
        "module_args": {
            "content": "{\n    \"Cisco-IOS-XE-rpc:input\": {\n        \"force\": true,\n        \"reason\": \"Test\"\n    }\n}\n",
            "format": "json",
            "method": "post",
            "path": "/Cisco-IOS-XE-rpc:reload"
        }
    },
    "msg": "HTTP Error 405: Method Not Allowed"
}

PLAY RECAP ************************************************************************************************************************************************************************************************************************************************
c8k_student01-1            : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

When using curl everything works like expected. Input file: rpc-reboot.json

{
    "Cisco-IOS-XE-rpc:input": {
        "force": true,
        "reason": "Test"
    }
}

curl operation:

$ curl -k -X POST -u student01 -H "Accept:application/yang-data+json" -H "Content-Type:application/yang-data+json" https://10.21.128.203/restconf/data/Cisco-IOS-XE-rpc:reload -d @rpc-reboot.json -v
Enter host password for user 'student01':
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.21.128.203:443...
* Connected to 10.21.128.203 (10.21.128.203) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=IOS-Self-Signed-Certificate-4022925155
*  start date: Jan 11 05:51:50 2023 GMT
*  expire date: Jan 10 05:51:50 2033 GMT
*  issuer: CN=IOS-Self-Signed-Certificate-4022925155
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* Server auth using Basic with user 'student01'
> POST /restconf/data/Cisco-IOS-XE-rpc:reload HTTP/1.1
> Host: 10.21.128.203
> Authorization: Basic c3R1ZGVudDAxOjEyMzRRd2Vy
> User-Agent: curl/7.74.0
> Accept:application/yang-data+json
> Content-Type:application/yang-data+json
> Content-Length: 84
> 
* upload completely sent off: 84 out of 84 bytes
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: openresty
< Date: Fri, 13 Jan 2023 05:28:05 GMT
< Content-Type: application/yang-data+json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
< Pragma: no-cache
< Content-Security-Policy: default-src 'self'; block-all-mixed-content; base-uri 'self'; frame-ancestors 'none';
< Strict-Transport-Security: max-age=15552000; includeSubDomains
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< 
{
  "Cisco-IOS-XE-rpc:output": {
    "result": "RPC request successful"
  }
}
* Connection #0 to host 10.21.128.203 left intact

netgab avatar Jan 13 '23 06:01 netgab

Can you rerun this with device interaction logging turned on and share the relevant section? The error is just what we get back from the remote server, but there's probably something strange happening such that the request is not what we expect it to be.

Qalthos avatar Jan 30 '23 20:01 Qalthos

Hey @Qalthos , thank you for the reply. So I did that:

2023-01-31 07:09:05,905 p=26128 u=student01 n=ansible | PLAY [RESTCONF test playbook] ************************************************************************************************************************************************************
2023-01-31 07:09:06,048 p=26128 u=student01 n=ansible | TASK [RESTCONF: Reboot] ******************************************************************************************************************************************************************
2023-01-31 07:09:07,312 p=26169 u=student01 n=ansible | jsonrpc request: b'{"jsonrpc": "2.0", "method": "pop_messages", "id": "b8b20e23-d92d-43ff-8b1f-d0b71bb06a3b", "params": [[], {}]}'
2023-01-31 07:09:07,313 p=26169 u=student01 n=ansible | jsonrpc response: {"jsonrpc": "2.0", "id": "b8b20e23-d92d-43ff-8b1f-d0b71bb06a3b", "result_type": "pickle", "result": "(lp0\n(Vvvvv\np1\nVloaded API plugin ansible_collections.ansible.netcommon.plugins.httpapi.restconf from path /home/student01/module03-3/venv/lib/python3.9/site-packages/ansible_collections/ansible/netcommon/plugins/httpapi/restconf.py for platform type ansible.netcommon.restconf\np2\ntp3\na(Vlog\np4\nVplatform_type is set to ansible.netcommon.restconf\np5\ntp6\na(Vwarning\np7\nVPersistent connection logging is enabled for 10.21.128.202. This will log ALL interactions to /home/student01/module03-3/ansible/ansible.log and WILL NOT redact sensitive configuration like passwords. USE WITH CAUTION!\np8\ntp9\na."}
2023-01-31 07:09:07,329 p=26172 u=student01 n=ansible | jsonrpc request: b'{"jsonrpc": "2.0", "method": "pop_messages", "id": "8a83e873-1f78-42aa-a490-1d1267117d8d", "params": [[], {}]}'
2023-01-31 07:09:07,330 p=26172 u=student01 n=ansible | jsonrpc response: {"jsonrpc": "2.0", "id": "8a83e873-1f78-42aa-a490-1d1267117d8d", "result_type": "pickle", "result": "(lp0\n(Vvvvv\np1\nVloaded API plugin ansible_collections.ansible.netcommon.plugins.httpapi.restconf from path /home/student01/module03-3/venv/lib/python3.9/site-packages/ansible_collections/ansible/netcommon/plugins/httpapi/restconf.py for platform type ansible.netcommon.restconf\np2\ntp3\na(Vlog\np4\nVplatform_type is set to ansible.netcommon.restconf\np5\ntp6\na(Vwarning\np7\nVPersistent connection logging is enabled for 10.21.128.203. This will log ALL interactions to /home/student01/module03-3/ansible/ansible.log and WILL NOT redact sensitive configuration like passwords. USE WITH CAUTION!\np8\ntp9\na."}
2023-01-31 07:09:07,398 p=26128 u=student01 n=ansible | platform_type is set to ansible.netcommon.restconf
2023-01-31 07:09:07,400 p=26128 u=student01 n=ansible | [WARNING]: Persistent connection logging is enabled for 10.21.128.202. This will log ALL interactions to /home/student01/module03-3/ansible/ansible.log and WILL NOT redact sensitive
configuration like passwords. USE WITH CAUTION!

2023-01-31 07:09:07,423 p=26128 u=student01 n=ansible | platform_type is set to ansible.netcommon.restconf
2023-01-31 07:09:07,424 p=26128 u=student01 n=ansible | [WARNING]: Persistent connection logging is enabled for 10.21.128.203. This will log ALL interactions to /home/student01/module03-3/ansible/ansible.log and WILL NOT redact sensitive
configuration like passwords. USE WITH CAUTION!

2023-01-31 07:09:08,137 p=26169 u=student01 n=ansible | jsonrpc request: b'{"jsonrpc": "2.0", "method": "send_request", "id": "d04475c8-dbc2-4883-ac86-d9bd62fb6eb5", "params": [[null], {"path": "/Cisco-IOS-XE-rpc:reload", "method": "GET", "accept": null}]}'
2023-01-31 07:09:08,158 p=26172 u=student01 n=ansible | jsonrpc request: b'{"jsonrpc": "2.0", "method": "send_request", "id": "0458c432-99a9-4763-bcec-90d86d5b0198", "params": [[null], {"path": "/Cisco-IOS-XE-rpc:reload", "method": "GET", "accept": null}]}'
2023-01-31 07:09:08,463 p=26172 u=student01 n=ansible | jsonrpc response: {"jsonrpc": "2.0", "id": "0458c432-99a9-4763-bcec-90d86d5b0198", "error": {"code": 405, "message": "HTTP Error 405: Method Not Allowed"}}
2023-01-31 07:09:08,537 p=26128 u=student01 n=ansible | fatal: [c8k_student01-2]: FAILED! => {"changed": false, "code": 405, "msg": "HTTP Error 405: Method Not Allowed"}
2023-01-31 07:09:08,816 p=26169 u=student01 n=ansible | jsonrpc response: {"jsonrpc": "2.0", "id": "d04475c8-dbc2-4883-ac86-d9bd62fb6eb5", "error": {"code": 405, "message": "HTTP Error 405: Method Not Allowed"}}
2023-01-31 07:09:08,889 p=26128 u=student01 n=ansible | fatal: [c8k_student01-1]: FAILED! => {"changed": false, "code": 405, "msg": "HTTP Error 405: Method Not Allowed"}
2023-01-31 07:09:08,891 p=26172 u=student01 n=ansible | jsonrpc request: b'{"jsonrpc": "2.0", "method": "reset", "id": "e41c5a30-fc27-4b71-94af-a88f669feb1d", "params": [[], {}]}'
2023-01-31 07:09:08,892 p=26172 u=student01 n=ansible | jsonrpc response: {"jsonrpc": "2.0", "id": "e41c5a30-fc27-4b71-94af-a88f669feb1d", "result_type": "pickle", "result": "N."}
2023-01-31 07:09:08,893 p=26169 u=student01 n=ansible | jsonrpc request: b'{"jsonrpc": "2.0", "method": "reset", "id": "ca671859-0a49-4468-882c-cf06b8187ede", "params": [[], {}]}'
2023-01-31 07:09:08,894 p=26169 u=student01 n=ansible | jsonrpc response: {"jsonrpc": "2.0", "id": "ca671859-0a49-4468-882c-cf06b8187ede", "result_type": "pickle", "result": "N."}
2023-01-31 07:09:08,897 p=26128 u=student01 n=ansible | PLAY RECAP *******************************************************************************************************************************************************************************
2023-01-31 07:09:08,897 p=26128 u=student01 n=ansible | c8k_student01-1            : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
2023-01-31 07:09:08,898 p=26128 u=student01 n=ansible | c8k_student01-2            : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
2023-01-31 07:09:08,994 p=26172 u=student01 n=ansible | ESTABLISH HTTP(S) CONNECTFOR USER: student01 TO https://10.21.128.203:443
2023-01-31 07:09:08,994 p=26172 u=student01 n=ansible | send url 'https://10.21.128.203:443/restconf/data/Cisco-IOS-XE-rpc:reload' with data 'None' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/yang-data+json', 'Accept': 'application/yang-data+json'}, 'method': 'GET', 'force_basic_auth': True, 'url_username': 'student01', 'url_password': 'automate2023'}'
2023-01-31 07:09:08,994 p=26172 u=student01 n=ansible | received response: 'b'''
2023-01-31 07:09:08,995 p=26172 u=student01 n=ansible | resetting persistent connection for socket_path /home/student01/.ansible/pc/f2d2969f3a
2023-01-31 07:09:08,995 p=26172 u=student01 n=ansible | closing http(s) connection to device
2023-01-31 07:09:08,995 p=26169 u=student01 n=ansible | ESTABLISH HTTP(S) CONNECTFOR USER: student01 TO https://10.21.128.202:443
2023-01-31 07:09:08,995 p=26169 u=student01 n=ansible | send url 'https://10.21.128.202:443/restconf/data/Cisco-IOS-XE-rpc:reload' with data 'None' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/yang-data+json', 'Accept': 'application/yang-data+json'}, 'method': 'GET', 'force_basic_auth': True, 'url_username': 'student01', 'url_password': 'automate2023'}'
2023-01-31 07:09:08,995 p=26172 u=student01 n=ansible | reset call on connection instance
2023-01-31 07:09:08,996 p=26169 u=student01 n=ansible | received response: 'b'''
2023-01-31 07:09:08,996 p=26169 u=student01 n=ansible | resetting persistent connection for socket_path /home/student01/.ansible/pc/96e0c36405
2023-01-31 07:09:08,996 p=26169 u=student01 n=ansible | closing http(s) connection to device
2023-01-31 07:09:08,996 p=26169 u=student01 n=ansible | reset call on connection instance
2023-01-31 07:09:08,996 p=26172 u=student01 n=ansible | shutdown complete
2023-01-31 07:09:08,997 p=26169 u=student01 n=ansible | shutdown complete

So it seems like, that the module is trying to do a GET instead of the desired POST

netgab avatar Jan 31 '23 06:01 netgab