Skip to content

aci_rest module fails with an error when using certificate authentication and a xml fragment payload #339

@DanielMuller-TN

Description

@DanielMuller-TN

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

We have a reasonably simple Ansible playbook which creates a skeleton tenancy in ACI and sets some sane base policies for consistency in our environment. This was developed in approximately April 2021 using what would have been release 2.0.0 of the collection.

We haven't had reason to use it again until now and found that the playbook consistently failing on the task step which invoked the aci_rest module to push updated OSPF timer policies. The actual task step is (setting our reference bandwidth to 200G which is our default):

  cisco.aci.aci_rest:
    path: "/api/mo/uni/tn-{{ aci_tenant_name | upper }}/ospfCtxP-{{ aci_tenant_name | upper }}_{{ network.vrf | upper }}_OSPF.Timers.xml"
    method: post
    content:
      <ospfCtxPol bwRef="200000" />
  when: network.ospf is defined

When executed the playbook would fail with an error of:

TypeError: must be str, not bytes

We use certificate authentication on our production environment to avoid triggering the basic authentication rate limiting. In the course of troubleshooting against our lab ACI environment I switched back to basic authentication and the entire playbook executed without error.

I switched to basic authentication in our production environment and the playbook successfully executed the "Create OSPF timer policies" task steps (although it eventually failed when it triggered the DOS protection and basic auth was rate limited, but that was a known issue).

This indicated the error was only involved when certificate authentication was used. Diving back through the commit history I found that in August 2021 commit 6b69c246cc5b0e818a7f6d31bfc38b1e67c1317b was made that added validation of the XML content in the request payload where previously it has been passed through unchanged.

I suspect what is happening from my lmited understaning is that because the "content" value I'm passing to the aci_rest module isn't a full XML document containing an XML encoding header the lxml.etree.tostring() function call on line 393 of aci_rest.py is returning a byte array instead of a unencoded string.

You can also serialise to a Unicode string without declaration by passing the name 'unicode' as encoding (or the str function in Py3 or unicode in Py2). This changes the return value from a byte string to an unencoded unicode string.
source: https://lxml.de/api/[lxml.etree](https://lxml.de/api/lxml.etree-module.html#tostring)-module.html#tostring

Apologises, I haven't spent a huge amount of time trying to figure it out. I've brute force worked around it by testing whether the payload is an instance of "bytes" in the cert_auth() function in the module_utils/aci.py file and decoding it to utf-8 to get around my immediate issues.

Affected Module Name(s):

  • cisco.aci.aci_rest

APIC version and APIC Platform

ACI 4.2(6d)

Collection versions

  • cisco.aci 2.10
  • cisco.aci 2.11

Output/ Error message

An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: must be str, not bytes
fatal: [production]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/nfs/XXX/.ansible/tmp/ansible-tmp-1667368739.0076344-749867-157854826012646/AnsiballZ_aci_rest.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/nfs/XXX/.ansible/tmp/ansible-tmp-1667368739.0076344-749867-157854826012646/AnsiballZ_aci_rest.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/nfs/XXX/.ansible/tmp/ansible-tmp-1667368739.0076344-749867-157854826012646/AnsiballZ_aci_rest.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.cisco.aci.plugins.modules.aci_rest', init_globals=None, run_name='__main__', alter_sys=True)\n  File \"/usr/lib64/python3.6/runpy.py\", line 205, in run_module\n    return _run_module_code(code, init_globals, run_name, mod_spec)\n  File \"/usr/lib64/python3.6/runpy.py\", line 96, in _run_module_code\n    mod_name, mod_spec, pkg_name, script_name)\n  File \"/usr/lib64/python3.6/runpy.py\", line 85, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_cisco.aci.aci_rest_payload_onj9z7r4/ansible_cisco.aci.aci_rest_payload.zip/ansible_collections/cisco/aci/plugins/modules/aci_rest.py\", line 457, in <module>\n  File \"/tmp/ansible_cisco.aci.aci_rest_payload_onj9z7r4/ansible_cisco.aci.aci_rest_payload.zip/ansible_collections/cisco/aci/plugins/modules/aci_rest.py\", line 419, in main\n  File \"/tmp/ansible_cisco.aci.aci_rest_payload_onj9z7r4/ansible_cisco.aci.aci_rest_payload.zip/ansible_collections/cisco/aci/plugins/module_utils/aci.py\", line 336, in cert_auth\nTypeError: must be str, not bytes\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

Expected Behavior

  • Task to complete successfully updated the reference bandwidth of the target OSPF timer policy to 200G

Actual Behavior

  • Failed with a TypeError

Playbook tasks to Reproduce

  cisco.aci.aci_rest:
    path: "/api/mo/uni/tn-{{ aci_tenant_name | upper }}/ospfCtxP-{{ aci_tenant_name | upper }}_{{ network.vrf | upper }}_OSPF.Timers.xml"
    method: post
    content:
      <ospfCtxPol bwRef="200000" />

You need to be using certificate based authentication. I suspect any bare XML fragment will trigger the behaviour.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions