cloud-init
cloud-init copied to clipboard
Ansible module doesn't find collections installed by the playbook
Bug report
We have a playbook that looks something like this:
- name: Example customization playbook
hosts: 127.0.0.1
connection: local
gather_facts: true
tasks:
- name: Install roles and collections
community.general.ansible_galaxy_install:
type: both
requirements_file: ./requirements.yml
- name: Execute a role from collection installed from requirements.yml
ansible.builtin.include_role:
name: my_namespace.my_collection.role1
And we invoke that like this:
ansible:
install_method: pip
package_name: ansible
run_user: my_user
pull:
url: "<url>"
playbook_name: "custom.yml"
Debug logs show that the collection is installed in the first task. However, it appears that ansible-pull
can't find the role:
TASK [Execute a role] **********************************************************
ERROR! the role 'my_namespace.my_collection.role1' was not found in /home/my_user/.ansible/pull/test/roles:/home/my_user/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/my_user/.ansible/pull/test
Indeed, ansible-pull
doesn't seem to be looking in the collection install path (although it is clearly able to use the Community collection?). Executing ansible --version
as a task in the playbook shows:
"stdout_lines": [
"ansible [core 2.17.0]",
" config file = None",
" configured module search path = ['/home/imy_user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']",
" ansible python module location = /home/my_user/.local/lib/python3.10/site-packages/ansible",
" ansible collection location = /home/my_user/.ansible/collections:/usr/share/ansible/collections",
" executable location = /home/my_user/.local/bin/ansible",
" python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)",
" jinja version = 3.0.3",
" libyaml = True"
]
And the collection is indeed installed to the first location in the "ansible collection location" path.
Things we've tried to solve the problem, but haven't:
- Using an
ansible.cfg
file in the repository cloned to force the collection installation location, but it has made no difference. - Splitting the playbook into two plays, one to install the collection, the second to execute the role, but this hasn't helped
- Both import_role vs include_role
- Executing the role from "roles:" rather than as part of a task
Manually logging into the instance and running the custom.yml
playbook completes as expected - showing both that the collection is installed and that the "system" Ansible can find it.
We don't know a priori if a requirements.yml
file exists, which makes using the "galaxy/actions" more problematic, and it isn't clear from the documentation if installing from a requirements.yml file works:
galaxy:
actions:
- ["ansible-galaxy", "install", "-r", "./requirements.yml"]
TL;DR It doesn't seem possible to use roles from within a collection installed as part of the playbook executed by the Ansible module.
Steps to reproduce the problem
See sample playbook and cloud-init config above
Environment details
-
Operating System Distribution: Ubuntu 20.04 and 22.04
-
Cloud-init version:
Ubuntu 20.04 - /usr/bin/cloud-init 24.1.3-0ubuntu1~20.04.1
Ubuntu 22.04 - /usr/bin/cloud-init 24.1.3-0ubuntu1~22.04.1
- Cloud provider, platform or installer type: Openstack with Terraform launching Ubuntu cloud images
cloud-init logs
The relevant section appears to be:
2024-06-18 07:51:22,085 - util.py[WARNING]: Running module ansible (<module 'cloudinit.config.cc_ansible' from '/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py'>) failed
2024-06-18 07:51:22,085 - util.py[DEBUG]: Running module ansible (<module 'cloudinit.config.cc_ansible' from '/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py'>) failed
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/cloudinit/config/modules.py", line 286, in _run_modules
ran, _r = cc.run(
File "/usr/lib/python3/dist-packages/cloudinit/cloud.py", line 60, in run
return self._runners.run(name, functor, args, freq, clear_on_fail)
File "/usr/lib/python3/dist-packages/cloudinit/helpers.py", line 156, in run
results = functor(**args)
File "/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py", line 202, in handle
run_ansible_pull(ansible, deepcopy(pull_cfg))
File "/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py", line 258, in run_ansible_pull
stdout = pull.pull(
File "/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py", line 90, in pull
stdout, _ = self.do_as([*self.cmd_pull, *args])
File "/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py", line 100, in do_as
return self.distro.do_as(command, self.run_user, **kwargs)
File "/usr/lib/python3/dist-packages/cloudinit/distros/__init__.py", line 1225, in do_as
return subp.subp(
File "/usr/lib/python3/dist-packages/cloudinit/subp.py", line 298, in subp
raise ProcessExecutionError(
cloudinit.subp.ProcessExecutionError: Unexpected error while running command.
Command: ['su', '-', 'my_user', '-c', 'env PATH=$PATH ansible-pull --url=https://<url> custom.yml']
Exit code: 1
Reason: -
Stdout: Starting Ansible Pull at 2024-06-18 07:51:15
/home/ipuuser/.local/bin/ansible-pull --url=<url> custom.yml
[WARNING]: Could not match supplied host pattern, ignoring: test
localhost | CHANGED => {
"after": "bd5cab726a44c0640f65b6607770bd29ffae3bb8",
"before": null,
"changed": true
}
[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'
[WARNING]: Could not match supplied host pattern, ignoring: test1
ERROR! the role 'my_namespace.my_collection.role1' was not found in /home/my_user/.ansible/pull/test1/roles:/home/my_user/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/my_user/.ansible/pull/test1
The error appears to be in '/home/my_user/.ansible/pull/test/custom.yml': line 54, column 15, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
ansible.builtin.include_role:
name: my_namespace.my_collection.role1
^ here
Stderr: