Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bigip_command: doesnt fail on invalid command or when command returns non-zero exit code #2449

Open
megamattzilla opened this issue Jan 6, 2025 · 6 comments
Labels
awaiting-user-action issue awaiting user's response and/or requested action

Comments

@megamattzilla
Copy link

COMPONENT NAME

bigip_command:

Environment

ANSIBLE VERSION
ansible [core 2.15.9]
  config file = /Users/userDocuments/GitHub/local-ansible/ansible.cfg
  configured module search path = ['/Users/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/user/python3.9.6-ansible/lib/python3.9/site-packages/ansible
  ansible collection location = /Users/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /Users/user/python3.9.6-ansible/bin/ansible
  python version = 3.9.6 (default, Oct  4 2024, 08:01:31) [Clang 16.0.0 (clang-1600.0.26.4)] (/Users/user/python3.9.6-ansible/bin/python)
  jinja version = 3.1.3
  libyaml = True
BIGIP VERSION
Sys::Version
Main Package
  Product     BIG-IP
  Version     17.1.1.3
  Build       0.0.5
  Edition     Point Release 3
  Date        Thu Mar 21 04:23:27 PDT 2024
CONFIGURATION

defaults

OS / ENVIRONMENT

MacOS

SUMMARY

bigip_command: doesnt fail on invalid command or when command returns non zero exit code. It always shows as ok even if it runs an invalid command.

STEPS TO REPRODUCE

Run playbook with invalid command:

  tasks:
    - name: Run invalid command
      bigip_command:
        commands: show ltm virtual doesntexist
        provider: "{{ provider }}"
      register: command
      delegate_to: localhost
      
    - debug:
        msg: "{{ command }}"
EXPECTED RESULTS

Ansible task exits with failure.

ACTUAL RESULTS

Ansible task with invalid command or one that returns non-zero exit code as successful ok.

PLAY [Run invalid command] ****************************************************************************************************************************************************

TASK [Run invalid command] ****************************************************************************************************************************************************
ok: [192.168.1.103 -> localhost]

TASK [debug] ******************************************************************************************************************************************************************
ok: [192.168.1.103] => {
    "msg": {
        "changed": false,
        "executed_commands": [
            "tmsh -c \\\"show ltm virtual doesntexist\\\""
        ],
        "failed": false,
        "stdout": [
            "01020036:3: The requested Virtual Server (/Common/doesntexist) was not found."
        ],
        "stdout_lines": [
            [
                "01020036:3: The requested Virtual Server (/Common/doesntexist) was not found."
            ]
        ]
    }
}

PLAY RECAP ********************************************************************************************************************************************************************
192.168.1.103              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
@megamattzilla megamattzilla added bug Issues that are related to bugs in the Ansible modules untriaged issue that needs an initial response from the developers labels Jan 6, 2025
@JonahBraun
Copy link

JonahBraun commented Jan 7, 2025

Mitigation action plugin that wraps bigip_command and adds error checking:

#!/usr/bin/python
#
# A wrapper around bigip_command that checks for errors and fails if so.
# Mitigation for https://github.com/F5Networks/f5-ansible/issues/2449

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.plugins.action import ActionBase

class ActionModule(ActionBase):
    def run(self, tmp=None, task_vars=None):
        result = self._execute_module(
            module_name='bigip_command',
            module_args=self._task.args,
            task_vars=task_vars or {},
            tmp=tmp
        )

        if result.get('stdout') and 'error' in result['stdout'][0].lower():
            result['failed'] = True
            result['msg'] = f"bigip_command failed: {result['stdout'][0]}"

        return result

@pgouband
Copy link
Contributor

pgouband commented Jan 7, 2025

Hi @megamattzilla,

Module is working as designed and provides the output of tmsh command so the result is the same as CLI.

@pgouband pgouband added awaiting-user-action issue awaiting user's response and/or requested action and removed bug Issues that are related to bugs in the Ansible modules untriaged issue that needs an initial response from the developers labels Jan 7, 2025
@megamattzilla
Copy link
Author

The modules runs the TMSH commands, but it should check that the command was successful before it reports the ansible task as status ok. Running an invalid command via TMSH does not report ok.

I think this module always showing as ok (or changed when running invalid modify command) gives ansible F5 customers a bad user experience.

Running the same invalid command via TMSH shows an error message:

root@(17-1-demo)(cfg-sync Standalone)(Active)(/Common)(tmos)# doesntexist
Syntax Error: unexpected argument "doesntexist"

root@(17-1-demo)(cfg-sync Standalone)(Active)(/Common)(tmos)# show ltm virtual doesnt exist
01020036:3: The requested Virtual Server (/Common/doesnt) was not found.

TMSH shell shows the error when invalid commands are made- this module does not, so in that regard I think the module can be misleading.

@pgouband
Copy link
Contributor

pgouband commented Jan 7, 2025

Hi @megamattzilla,

The current output provided by the module is the same as the CLI as you can see below.
The behavior is the same using CLI and API.

PLAY [all] *****************************************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************************
ok: [10.1.1.9]

TASK [Run invalid command] *************************************************************************************************************************
ok: [10.1.1.9 -> localhost]

TASK [debug] ***************************************************************************************************************************************
ok: [10.1.1.9] => {
    "msg": {
        "changed": false,
        "executed_commands": [
            "tmsh -c \\\"show ltm virtual doesntexist\\\""
        ],
        "failed": false,
        "stdout": [
            "01020036:3: The requested Virtual Server (/Common/doesntexist) was not found."
        ],
        "stdout_lines": [
            [
                "01020036:3: The requested Virtual Server (/Common/doesntexist) was not found."
            ]
        ]
    }
}

PLAY RECAP *****************************************************************************************************************************************
10.1.1.9                   : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
$ ansible-playbook -i hosts cmd2449-error.yml 

PLAY [all] *****************************************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************************
ok: [10.1.1.9]

TASK [Run invalid command] *************************************************************************************************************************
[WARNING]: Using "write" commands is not idempotent. You should use a module that is specifically made for that. If such a module does not exist,
then please file a bug. The command in question is "doesnotexist..."
ok: [10.1.1.9 -> localhost]

TASK [debug] ***************************************************************************************************************************************
ok: [10.1.1.9] => {
    "msg": {
        "changed": false,
        "executed_commands": [
            "tmsh -c \\\"doesnotexist\\\""
        ],
        "failed": false,
        "stdout": [
            "Syntax Error: unexpected argument \"doesnotexist\""
        ],
        "stdout_lines": [
            [
                "Syntax Error: unexpected argument \"doesnotexist\""
            ]
        ],
        "warnings": [
            "Using \"write\" commands is not idempotent. You should use a module that is specifically made for that. If such a module does not exist, then please file a bug. The command in question is \"doesnotexist...\""
        ]
    }
}

PLAY RECAP *****************************************************************************************************************************************
10.1.1.9                   : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

@JonahBraun
Copy link

@pgouband so are you saying that this is a bug with the cli tool and that the bug report should be opened there?

I think you would agree from an automation perspective (which Ansible is for), having a module that silently claims success when it fails is an issue!

@pgouband
Copy link
Contributor

pgouband commented Jan 7, 2025

Hi @JonahBraun,

That's not a bug.
API and CLI are providing the same output.
From Ansible point of view the call to the API was made and the response was provided so the API call is a success.
The command inside the API call is failing.
Do you agree?

I understand your point of view about managing the error message provided by the command in different ways but when do we should provide only the output of call or modify the message to provide an error?
The request is more complex and different customers could have different points of view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting-user-action issue awaiting user's response and/or requested action
Projects
None yet
Development

No branches or pull requests

3 participants