Hi,
I´m just starting with ansible and finishing my first playbook. It´s about downloading released packages from private Github Repositories. They can be either whl packages or packed tar.gz. Therefore I implemented different tasks for each case. The results seem to be ok, the file is downloaded and extracted properly. But there is a very confusing error message appearing when downloading a .whl file, if downloading a tar.gz file, there is no error message.
Whats confusing is: the Task “Copy whl file” does not have any endswith functionality used from my point of view.
Can someone explain what is going on there? Even if it´s working out, I don´t like to have this error there and want to fix it.
First things first, please mention the ansible-core version you’re using. I think there have been quite some changes to 2.19, so it might be worth knowing what exact version you’re running.
That said, you’re using file_to_copy both as a host fact (in Set file_to_copy if whl package) and as a variable within the play (register: file_to_copy). I’m not sure if they are really the same, so maybe Ansible gets confused by this. Just an idea.
The problem is that file_to_copy is a dictionary here (thanks to the “Extract tar.gz file” task) and not a string, and the exact error in the “Copy whl file” task is only visible when enabling tracebacks (for example by setting the environment variable ANSIBLE_DISPLAY_TRACEBACK=error):
TASK [Copy whl file] *******************************************************************************************************************************************************
[ERROR]: Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'
Origin: /path/to/test-error.yml:24:7
22 msg: "After unpacking: {{ file_to_copy }}"
23
24 - name: Copy whl file
^ column 7
Traceback (most recent call last):
File "/path/to/ansible/executor/task_executor.py", line 423, in _execute
result = self._execute_internal(templar, variables)
File "/path/to/ansible/executor/task_executor.py", line 636, in _execute_internal
result = self._handler.run(task_vars=vars_copy)
File "/path/to/ansible/plugins/action/copy.py", line 469, in run
trailing_slash = source.endswith(os.path.sep)
^^^^^^^^^^^^^^^
AttributeError: '_AnsibleTaggedDict' object has no attribute 'endswith'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/path/to/ansible/executor/task_executor.py", line 428, in _execute
raise AnsibleTaskError(obj=self._task.get_ds()) from ex
ansible.errors.AnsibleTaskError: Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'"}
The error happens in the copy task, but it’s a crash in the action plugin. It’s basically a bug in the parameter validation of the copy action. (Actually it’s the missing error validation of the copy action.)
(This bug is triggered by a bug in the playbook, see what @mariolenz wrote.)
Version is
ansible [core 2.20.3]
installed with pip and running on Ubuntu WSL2 distribution.
I understood your second point. I assumed here that the same variable will be set with this approach, no matter which task is executed. Would something like pulling file_to_copy to the beginning of the play be more ansible-compliant?