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

Type check fails when using in an ansible action plugin #210

Closed
jovial opened this issue Feb 19, 2024 · 6 comments · Fixed by #211
Closed

Type check fails when using in an ansible action plugin #210

jovial opened this issue Feb 19, 2024 · 6 comments · Fixed by #211
Labels
S: triage Issue needs triage.

Comments

@jovial
Copy link

jovial commented Feb 19, 2024

I'm hitting the following error when trying to use your library in ansible action plugin:

TASK [my_action] ************************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: Pattern and root_dir should be of the same type, not <class 'ansible.utils.unsafe_proxy.AnsibleUnsafeText'> and <class 'str'>
fatal: [localhost]: FAILED! => {"msg": "Unexpected failure during module execution: Pattern and root_dir should be of the same type, not <class 'ansible.utils.unsafe_proxy.AnsibleUnsafeText'> and <class 'str'>", "stdout": ""}

I've simplified this down to:

(kayobe-venv) [vagrant@controller1 vagrant]$ cat /tmp/test2.yml
---

- hosts: localhost
  vars:
    test: "{{ lookup('env', 'TEST_VAR') }}"
  tasks:
   - my_action:
        glob: "{{ test }}"

and

(venv-test) [vagrant@controller1 vagrant]$ cat /tmp/action_plugins/my_action.py
#!/usr/bin/python

from ansible.plugins.action import ActionBase
from wcmatch import glob

class ActionModule(ActionBase):
    def run(self, tmp=None, task_vars=None):
        super(ActionModule, self).run(tmp, task_vars)
        module_args = self._task.args.copy()
        result = glob.glob(module_args.get('glob'), flags=glob.GLOBSTAR)

and you run can run it with:

[vagrant@controller1 vagrant]$ python3 -m venv ~/venv-test
[vagrant@controller1 vagrant]$ source ~/venv-test/bin/activate
(venv-test) [vagrant@controller1 vagrant]$ pip install -U pip setuptools
(venv-test) [vagrant@controller1 vagrant]$ pip install 'ansible>=7,<9.0' wcmatch===8.5
(venv-test) [vagrant@controller1 vagrant]$ export TEST_VAR=myglob
(venv-test) [vagrant@controller1 vagrant]$ ansible-playbook /tmp/test2.yml

This used to work until ansible/ansible#82294 was merged. It looks like the behaviour to preserve AnsibleUnsafeText seems to be correct (as it was set from a user controllable environment variable), so I am just wondering if we make the check less restrictive. Both instances pass instanceof(instance, str), but only the glob passes instanceof(instance, 'ansible.utils.unsafe_proxy.AnsibleUnsafeText).AnsibleUnsafeText behaves exactly like a string but is used to mark it as unsafe to template.

@gir-bot gir-bot added the S: triage Issue needs triage. label Feb 19, 2024
@facelessuser
Copy link
Owner

facelessuser commented Feb 19, 2024

I think I know how to fix the issue. We should not be comparing their types, we should be checking if it is an instance of the base type. I'll get a PR ready, and if you can verify it fixes the issue, I think we'll be able to get a solution out.

@facelessuser
Copy link
Owner

@jovial can you verify that this PR fixes your issue?

@jovial
Copy link
Author

jovial commented Feb 20, 2024

@jovial can you verify that this PR fixes your issue?

Thanks for the quick patch. I'm hitting this strange error:

TASK [my_action] ************************************************************************************************************************************************************
task path: /tmp/test2.yml:7
The full traceback is:
Traceback (most recent call last):
  File "/home/vagrant/kayobe-venv/lib64/python3.9/site-packages/ansible/executor/task_executor.py", line 165, in run
    res = self._execute()
  File "/home/vagrant/kayobe-venv/lib64/python3.9/site-packages/ansible/executor/task_executor.py", line 676, in _execute
    result["_ansible_no_log"] = no_log
TypeError: 'NoneType' object does not support item assignment
fatal: [localhost]: FAILED! => {
    "msg": "Unexpected failure during module execution: 'NoneType' object does not support item assignment",
    "stdout": ""
}

I installed by doing:

git clone https://github.com/facelessuser/wcmatch/
cd wcmatch/
git checkout bugfix/typecheck
pip install .

Maybe I'm doing something stupid. Just looking into it.

EDIT: just to clarify if I then install the version from pypi, I can reproduce the error in this bug report again (i.e we get further)

@jovial
Copy link
Author

jovial commented Feb 20, 2024

My bad.. I wasn't returning anything from the action plugin. Modifying it to:

(kayobe-venv) [vagrant@controller0 wcmatch]$ cat /tmp/action_plugins/my_action.py 
#!/usr/bin/python

from ansible.plugins.action import ActionBase
from wcmatch import glob

class ActionModule(ActionBase):
    def run(self, tmp=None, task_vars=None):
        super(ActionModule, self).run(tmp, task_vars)
        module_args = self._task.args.copy()
        result = glob.glob(module_args.get('glob'), flags=glob.GLOBSTAR)
        return {"globs": result}

Appears to work:

(kayobe-venv) [vagrant@controller0 wcmatch]$ export TEST_VAR="*.py"
(kayobe-venv) [vagrant@controller0 wcmatch]$ ansible-playbook /tmp/test2.yml -vv
ansible-playbook [core 2.15.6]
  config file = None
  configured module search path = ['/home/vagrant/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/vagrant/kayobe-venv/lib64/python3.9/site-packages/ansible
  ansible collection location = /home/vagrant/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/vagrant/kayobe-venv/bin/ansible-playbook
  python version = 3.9.18 (main, Jan  4 2024, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] (/home/vagrant/kayobe-venv/bin/python3)
  jinja version = 3.1.3
  libyaml = True
No config file found; using defaults
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: test2.yml *********************************************************************************************************************************************************
1 plays in /tmp/test2.yml

PLAY [localhost] ************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************
task path: /tmp/test2.yml:3
ok: [localhost]

TASK [my_action] ************************************************************************************************************************************************************
task path: /tmp/test2.yml:7
ok: [localhost] => {"changed": false, "globs": ["hatch_build.py"]}

PLAY RECAP ******************************************************************************************************************************************************************
localhost 

Thanks very much :)

@facelessuser
Copy link
Owner

Great, I'll roll out the fix to PyPI sometime today.

@facelessuser
Copy link
Owner

Fix released

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S: triage Issue needs triage.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants