F5Networks / f5-ansible

Imperative Ansible modules for F5 BIG-IP products
GNU General Public License v3.0
375 stars 231 forks source link

{BUG} bigip_appsvcs_extension - Throws error when state set to 'absent' #1565

Closed cdd2 closed 4 years ago

cdd2 commented 4 years ago
ISSUE TYPE
COMPONENT NAME

bigip_appsvcs_extension

ANSIBLE VERSION
2.9.0
  config file = None
  configured module search path = ['/Users/s006000/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/s006000/repos/ansible-role-f5/venv/lib/python3.7/site-packages/ansible
  executable location = /Users/s006000/repos/ansible-role-f5/venv/bin/ansible
  python version = 3.7.4 (default, Jul  9 2019, 18:13:23) [Clang 10.0.1 (clang-1001.0.46.4)]
PYTHON VERSION
Python 3.7.4
BIGIP VERSION
Sys::Version
Main Package
  Product     BIG-IP
  Version     12.1.2
  Build       2.0.276
  Edition     Hotfix HF2
  Date        Sat Nov 11 04:32:09 PST 2017
CONFIGURATION
OS / ENVIRONMENT

macOS Mojave - 10.14.4

SUMMARY

When setting the state of the bigip_appsvcs_extension to 'absent,' the module will successfully remove the tenants specified, but the task always fails and throws a Python 'TypeError: argument of type 'NoneType' is not iterable.' This error occurs even if there are no tenants to remove.

STEPS TO REPRODUCE
---
- hosts: localhost
  vars:
    bigip_provider:
      server: '{{ lookup("env", "BIGIP_SERVER") }}'
      user: '{{ lookup("env", "BIGIP_USER") }}'
      password: '{{ lookup("env", "BIGIP_PASSWORD") }}'
      validate_certs: no
  tasks:
    - name: Remove AS3 objects
      bigip_appsvcs_extension:
        tenants: all
        state: absent
        provider: "{{ bigip_provider }}"
      delegate_to: localhost
EXPECTED RESULTS

This should remove all tenants (if present) without error. In the event there are no tenants to remove, this should exit gracefully and indicate that no change has been made.

ADDITIONAL INFORMATION ON ERROR

I believe the problem is linked to the 'tenant_exists' function. The code flow when state is 'absent' is as follows:

The 'tenant_exists' function does a GET request to check for the tenant's existence, but if the tenant doesn't exist then (at least for the BIG IP version I'm using) it returns an empty string for the content (Postman screenshot below).

When this occurs, the 'resp.content' is the empty string, and when "_json.loads(self._content or 'null')" is called it returns None. The GET request was successful (returns a 204 response code), so the check "'statusCode' in response" is made, and here the error occurs because 'response' is 'None.'

Adding a null check at line 481 in the bigip_appsvcs_extension.py would probably solve this issue, but I don't know what side effects that would have.

def tenant_exists(self):
    uri = "https://{0}:{1}/mgmt/shared/appsvcs/declare/{2}".format(
        self.client.provider['server'],
        self.client.provider['server_port'],
        self.want.tenants
    )
    resp = self.client.api.get(uri)
    try:
        response = resp.json()
    except ValueError:
        return False
    if resp.status == 404 or 'statusCode' in response and response['statusCode'] == 404:
        return False
    return True

(https://github.com/f5devcentral/ansible-role-f5ansible/blob/67e2dc74cf68ca9d5fb7744db37b9494b70f79ce/library/bigip_appsvcs_extension.py#L470-L483)

def json(self):
    return _json.loads(self._content or 'null')

https://github.com/f5devcentral/ansible-role-f5ansible/blob/67e2dc74cf68ca9d5fb7744db37b9494b70f79ce/module_utils/network/f5/icontrol.py#L113-L114

Response of GET Request on a nonexistant tenant image

ACTUAL RESULTS

This will remove tenants (if they exist) but because it runs the 'tenant_exists' function before and after removal, this always throws an error currently (if removal is successful). So, while this test does not explicitly delete any tenants (as I did not create any in the playbook), the same error occurs when it does delete a tenant.

TASK [Remove AS3 objects] *********************************************************************************************************************************************************************
task path: /Users/s006000/repos/ansible-role-f5/ex-playbook.yml:10
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: s006000
<localhost> EXEC /bin/sh -c 'echo ~s006000 && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784 `" && echo ansible-tmp-1573845661.663744-47363881108784="` echo /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784 `" ) && sleep 0'
Using module file /Users/s006000/repos/ansible-role-f5/venv/lib/python3.7/site-packages/ansible/modules/network/f5/bigip_appsvcs_extension.py
<localhost> PUT /Users/s006000/.ansible/tmp/ansible-local-16862n4ku4u_m/tmp0ecw7n_r TO /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py
<localhost> EXEC /bin/sh -c 'chmod u+x /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/ /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py && sleep 0'
<localhost> EXEC /bin/sh -c '/Users/s006000/repos/ansible-role-f5/venv/bin/python3 /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py", line 102, in <module>
    _ansiballz_main()
  File "/Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py", line 94, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py", line 40, in invoke_module
    runpy.run_module(mod_name='ansible.modules.network.f5.bigip_appsvcs_extension', init_globals=None, run_name='__main__', alter_sys=False)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 208, in run_module
    return _run_code(code, {}, init_globals, run_name, mod_spec)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py", line 549, in <module>
  File "/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py", line 542, in main
  File "/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py", line 353, in exec_module
  File "/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py", line 488, in absent
  File "/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py", line 483, in tenant_exists
TypeError: argument of type 'NoneType' is not iterable

fatal: [localhost -> localhost]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/Users/s006000/.ansible/tmp/ansible-tmp-1573845661.663744-47363881108784/AnsiballZ_bigip_appsvcs_extension.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible.modules.network.f5.bigip_appsvcs_extension', init_globals=None, run_name='__main__', alter_sys=False)\n  File \"/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py\", line 208, in run_module\n    return _run_code(code, {}, init_globals, run_name, mod_spec)\n  File \"/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py\", line 85, in _run_code\n    exec(code, run_globals)\n  File \"/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py\", line 549, in <module>\n  File \"/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py\", line 542, in main\n  File \"/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py\", line 353, in exec_module\n  File \"/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py\", line 488, in absent\n  File \"/var/folders/zv/c_n06p517fd005qhv8clwq1xzdj_m0/T/ansible_bigip_appsvcs_extension_payload_li5siaj9/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py\", line 483, in tenant_exists\nTypeError: argument of type 'NoneType' is not iterable\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
    "rc": 1
}

PLAY RECAP ************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
erjac77 commented 4 years ago

I also have this problem.

The tenant is successfully removed, but the task failed with this error:

  File "/tmp/ansible_bigip_appsvcs_extension_payload__umrhl9c/ansible_bigip_appsvcs_extension_payload.zip/ansible/modules/network/f5/bigip_appsvcs_extension.py", line 483, in tenant_exists
TypeError: argument of type 'NoneType' is not iterable
focrensh commented 4 years ago

Please try the Role that we have on galaxy. This is where we focus new features for Automation Toolchain from ansible.

https://galaxy.ansible.com/f5devcentral/atc_deploy