Installing Ansible role dependencies

I have a monolithic Ansible playbook that contains dozens of different roles, all bundled into the same Git repository. Some of the roles are more generically useful than others, so I thought I would do some refactoring.

I decided to move the role that installs and configures fail2ban to its own repository, and then call that new/refactored role as a dependency in my now-slightly-less-monolithic role.

Of course, I had no idea what I was doing.

The first thing I tried was creating a simple ansible-test playbook with a single test role. Just to make sure it did something, I had it copy a file to the /tmp directory on the target host. In roles/test/meta/main.yml I added a dependency:

---  
dependencies:
  - { role: "git+https://git.osric.net/chris/ansible-fail2ban.git" }
...

Then I tried running the playbook:

$ ansible-playbook -i hosts site.yml

Which produced the following error:

ERROR! the role 'git+https://git.osric.net/chris/ansible-fail2ban.git' was not found in /home/chris/ansible-test/roles:/usr/local/etc/ansible/roles:/home/chris/ansible-test/roles:/home/chris/ansible-test

The error appears to have been in '/home/chris/ansible-test/roles/test/meta/main.yml': line 4, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

dependencies:
- { role: "git+https://git.osric.net/chris/ansible-fail2ban.git" }
  ^ here
This one looks easy to fix.  It seems that there is a value started
with a quote, and the YAML parser is expecting to see the line ended
with the same kind of quote.  For instance:

    when: "ok" in result.stdout

Could be written as:

   when: '"ok" in result.stdout'

Or equivalently:

   when: "'ok' in result.stdout"

That’s a long and, as it turns out, misleading error. There is no issue with unbalanced quotes. The real error is on the first line:

ERROR! the role 'git+https://git.osric.net/chris/ansible-fail2ban.git' was not found

Isn’t is supposed to automatically install? Isn’t that the magic of dependencies?

Apparently not. The convention, as far as I can tell, is to use a requirements.yml file that describes where to find the dependencies, e.g.:

---
src: git+https://git.osric.net/chris/ansible-fail2ban.git
...

Then you use ansible-galaxy to install the dependencies:

$ ansible-galaxy install -r requirements.yml -p roles/

It worked! I now had a new role in roles/ansible-fail2ban with the expected content.

It turned out that I had left out an important piece of the ansible-fail2ban role (I forgot to add, commit, and push the defaults/main.yml into the remote origin).

I tried re-installing the repository using the --force option:

$ ansible-galaxy install --force -r requirements.yml -p roles/
- ansible-fail2ban is already installed, skipping.

Wait, what? What is --force actually supposed to do? It turned out, this was a bug in my version of ansible (and ansible-galaxy), as described in this bug: https://github.com/ansible/galaxy-issues/issues/249

Before:

$ ansible-galaxy --version
ansible-galaxy 2.3.1.0

After:

$ ansible-galaxy --version
ansible-galaxy 2.4.3.0

I ran the install again:

$ ansible-galaxy install --force -r requirements.yml -p roles/
- changing role ansible-fail2ban from  to unspecified
- extracting ansible-fail2ban to /home/chris/ansible-test/roles/ansible-fail2ban
- ansible-fail2ban was installed successfully

It worked! But the first output line about that bit “changing role ansible-fail2ban from to unspecified” led me to believe that I could change the role destination. I’d rather have roles/fail2ban than roles/ansible-fail2ban.

We can specify additional attributes, including name. See Ansible Galaxy – Installing Multiple Roles from a File for details.

[Pet peeve: documentation that does not include the most verbose & complete example possible. Every single option should be demonstrated. Why not include both? Here is the simplest possible example that works, here is the most complete example possible. This is open source, so I could fix it I suppose….]

I updated my requirements.yml file:

---
- name: fail2ban
  scm: git
  src: git+https://git.osric.net/chris/ansible-fail2ban.git
  version: master  
...

I installed the requirements again:

$ ansible-galaxy install --force -r requirements.yml -p roles/

Which successfully created an additional copy of the role in the specified directory:

$ ls roles | cat
fail2ban
ansible-fail2ban
test

That meant I also needed to update the dependency in roles/test/meta/mail.yml:

---
dependencies: 
  - { role: fail2ban }
...

I ran the test playbook again. It worked! Now I just have a couple dozen more roles to refactor.

Leave a Reply

Your email address will not be published. Required fields are marked *