Community Note
- Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
- Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
- If you are interested in working on this issue or have submitted a pull request, please leave a comment
Description
The HTTPAPI Connection plugin is not able to retrieve the token from the login method when using local login domain.
Affected Module Name(s):
ND version and ND Platform
APIC version and APIC Platform for Site related issues
Collection versions
- cisco.nd 0.1.2
- cisco.mso 2.1.0
- ansible.netcommon 4.1.0
Output/ Error message
fatal: [ndo-lab1]: FAILED! => {"changed": false, "current": {}, "msg": "ND HTTPAPI send_request() Exception: command timeout triggered, timeout value is 30 secs.
See the timeout setting options in the Network Debug and Troubleshooting Guide. - Traceback (most recent call last):
File "/root/.ansible/collections/ansible_collections/ansible/netcommon/plugins/connection/httpapi.py", line 286, in send
response = open_url(url, data=data, **url_kwargs)
File "/root/ansible_dev/.venv/lib/python3.10/site-packages/ansible/module_utils/urls.py", line 1665, in open_url
return Request().open(method, url, data=data, headers=headers, use_proxy=use_proxy,
File "/root/ansible_dev/.venv/lib/python3.10/site-packages/ansible/module_utils/urls.py", line 1557, in open
r = urllib_request.urlopen(request, None, timeout)
File "/usr/lib/python3.10/urllib/request.py", line 216, in urlopen
return opener.open(url, data, timeout)
File "/usr/lib/python3.10/urllib/request.py", line 525, in open
response = meth(req, response)
File "/usr/lib/python3.10/urllib/request.py", line 634, in http_response
response = self.parent.error(
File "/usr/lib/python3.10/urllib/request.py", line 563, in error
return self._call_chain(*args)
File "/usr/lib/python3.10/urllib/request.py", line 496, in _call_chain
result = func(*args)
File "/usr/lib/python3.10/urllib/request.py", line 643, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 401: Unauthorized
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
# repeat traceback, same as above
Expected Behavior
ok: [ndo-lab1]
Actual Behavior
Error as listed above
Playbook tasks to Reproduce
Inventory:
all:
hosts:
ndo-lab1:
ansible_host: "{{ lookup('env', 'NDO_HOSTNAME') }}"
ansible_user: "{{ lookup('env', 'NDO_USERNAME') }}"
ansible_ssh_pass: "{{ lookup('env', 'NDO_PASSWORD') }}"
ansible_httpapi_validate_certs: false
ansible_httpapi_use_ssl: true
ansible_connection: ansible.netcommon.httpapi
ansible_network_os: cisco.nd.nd
Playbook:
- name: "Test NDO Queries"
connection: local
hosts: ndo-lab1
gather_facts: false
tasks:
- cisco.nd.nd_version:
login_domain: Local
state: query
- cisco.mso.mso_schema:
login_domain: Local
state: query
Important Factoids
The first query for the nd_version
works, but it turns out this is a false positive because the /version.json
endpoint does not require any authentication (at least for my install). The second query fails with the error above.
I enabled persistent logging with the following environment variables:
export ANSIBLE_LOG_PATH='ansible.log'
export ANSIBLE_PERSISTENT_LOG_MESSAGES=True
With this enabled, I was able to see that the connection plugin is sending the username and password to the NDO /login
endpoint for both queries, but it is not receiving the token back in either case.
Relevant (redacted) logs for the nd_version
query:
2023-01-24 12:25:47,054 p=2116836 u=root n=ansible | send url 'https://<NDO_HOSTNAME>:443/login' with data '{"userName": "admin", "userPasswd": "<NDO_PASSWORD>", "domain": "Local"}' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/json'}, 'method': 'POST', 'force_basic_auth': True, 'url_username': 'admin', 'url_password': '<NDO_PASSWORD>'}'
2023-01-24 12:25:47,055 p=2116836 u=root n=ansible | received response: 'b'''
2023-01-24 12:25:47,055 p=2116836 u=root n=ansible | send url 'https://<NDO_HOSTNAME>:443/version.json' with data 'null' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/json', 'Authorization': 'Bearer None'}, 'method': 'GET'}'
2023-01-24 12:25:47,055 p=2116836 u=root n=ansible | received response: 'b'{\n "commit_id": "8ebcd0bdc",\n "build_time": "now",\n "build_host": "kube15",\n "user": "root",\n "product_id": "nd",\n "product_name": "Nexus Dashboard",\n "release": false,\n "major": 2,\n "minor": 1,\n "maintenance": 2,\n "patch": "d"\n}''
You can clearly see the received response: 'b'''
and in the header in the query call is 'Authorization': 'Bearer None'
. The same thing happens for the mso_schema
query, but since that endpoint requires authentication it loops back to login again and eventually fails due to timeout.
Relevant (redacted) logs for the mso_schema
query:
2023-01-24 12:26:18,646 p=2116903 u=root n=ansible | send_request method called
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | send_request reseting connection as host has changed from <NDO_HOSTNAME> to None
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | send_request() - connection.send(/mso/api/v1/schemas, null, GET, {'Content-Type': 'application/json'})
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | ESTABLISH HTTP(S) CONNECTFOR USER: admin TO https://<NDO_HOSTNAME>:443
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | Starting Login to <NDO_HOSTNAME>
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | login() - connection.send(/login, {"userName": "admin", "userPasswd": "<NDO_PASSWORD>", "domain": "Local"}, POST, {'Content-Type': 'application/json'})
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | send url 'https://<NDO_HOSTNAME>:443/login' with data '{"userName": "admin", "userPasswd": "<NDO_PASSWORD>", "domain": "Local"}' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/json', 'Authorization': 'Bearer None'}, 'method': 'POST'}'
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | received response: 'b'''
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | send url 'https://<NDO_HOSTNAME>:443/mso/api/v1/schemas' with data 'null' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/json', 'Authorization': 'Bearer None'}, 'method': 'GET'}'
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | Starting Login to <NDO_HOSTNAME>
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | login() - connection.send(/login, {"userName": "admin", "userPasswd": "<NDO_PASSWORD>", "domain": "Local"}, POST, {'Content-Type': 'application/json'})
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | send url 'https://<NDO_HOSTNAME>:443/login' with data '{"userName": "admin", "userPasswd": "<NDO_PASSWORD>", "domain": "Local"}' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/json'}, 'method': 'POST', 'force_basic_auth': True, 'url_username': 'admin', 'url_password': '<NDO_PASSWORD>'}'
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | received response: 'b'''
2023-01-24 12:26:18,647 p=2116903 u=root n=ansible | send url 'https://<NDO_HOSTNAME>:443/mso/api/v1/schemas' with data 'null' and kwargs '{'timeout': 30, 'validate_certs': False, 'use_proxy': True, 'headers': {'Content-Type': 'application/json', 'Authorization': 'Bearer None'}, 'method': 'GET'}'
# logs repeated until timeout
Once again you can see the same behavior of an empty response and Bearer None
for the header, which causes the urllib.error.HTTPError: HTTP Error 401: Unauthorized
in the error message.
Lastly, I reserved a NDO sandbox from Cisco and tried it there and got the same results.