Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically install Ansible Galaxy roles, using Vagrant?

Using one playbook only, then it's not possible to have Ansible automagically install the dependent roles. At least according to this SO thread.

But, I have the added "advantage" of using Vagrant and Vagrant's Ansible local provisioner. Any tricks I may apply?

like image 294
Martin Andersson Avatar asked Sep 04 '17 23:09

Martin Andersson


1 Answers

Update 2018-11-22!

Given the evolution of software, I can not guarantee that all of the "old stuff/answer" below is still legit and won't set your machine on fire lol. I do, however, maintain a Vagrantfile on GitHub that does install Ansible Galaxy roles automatically and this guy should essentially be regarded as the only one and holy truth (scroll down a bit in the file). If the GitHub-guy-file doesn't work for ya, toss in an issue on the GitHub tracker and I'll see to it.

Old stuff/answer..

Something like this (Vagrantfile):

config.vm.provision 'ansible', run: 'always', type: :ansible_local do |ansible|
  ansible.galaxy_role_file = 'requirements.yml'
  ansible.playbook = 'playbook.yml'
end

Contents of requirements.yml:

---
- src: mongrelion.docker

Please note how my 1 role is specified in a separate file, which is totally overkill. I would like to specify the role in the Vagrantfile, without adding yet another shell script that install Ansible before Vagrant has had a chance and then run the galaxy install command. I find it convenient to let Vagrant install Ansible and it just feels bad for every extra "script" I throw in when Ansible is supposed to be the provisioner lol.

For the records, ansible-galaxy install does not require a role file to be specified; a role name as an argument to the command would suffice in which case the role would be downloaded (docs).

I tried about half a day to hack and slash various Vagrant options one may set, such as the galaxy_command but each new trickery caused a new problem which was a hard stop for Vagrant (sounds familiar?? hahaha).

If you find a way to set the role inline without depending on yet another file or a nitehacked shell script in the Vagrantfile, please holla at me =)

How do I change where the Ansible role files get stored?

By default, Ansible Galaxy downloads the role files to a subdirectory in the project: ./roles/. Ansible automagically looks for roles in this subdirectory when parsing the playbook file.

I find this location to not be convenient, given my personal goal to keep project folders clean and commit as little junk as possible to my repository. Thankfully, it is possible to change Galaxy's download path by setting galaxy_roles_path to another location that Ansible also uses to look for roles in: /etc/ansible/roles/.

If only it was that easy.

[At least on my machine:] When Vagrant installs Ansible, the folder is created with write-permissions only for the root user. I.e., when ansible-galaxy install run 1 minute later and downloads the role, everything crash because of insufficient permissions. Or to put it differently, Ansible can't put shit in his own "home folder". That's kind of funny actually.

The fix is to inject some chmod magic to the folder before Ansible manages to screw up for himself:

config.vm.provision 'preemptively give others write access to /etc/ansible/roles', type: :shell, inline: <<~'EOM'
  mkdir /etc/ansible/roles -p
  chmod o+w /etc/ansible/roles
EOM

config.vm.provision 'ansible', run: 'always', type: :ansible_local do |ansible|
  ansible.galaxy_role_file = 'requirements.yml'
  ansible.galaxy_roles_path = '/etc/ansible/roles'
  ansible.playbook = 'playbook.yml'
end

How do I stop the role from constantly being reinstalled?

I find it to be a good practice to let the Ansible provisioner always run. So that he can do his thing, so to speak. The terminal output reveals that vagrant up downloads and install the role on each run. This annoys the shit out of me.

The galaxy_command uses by default the --force flag - why? Have no idea. But removing it solves the problem. Now we get a warning instead:

[WARNING]: - mongrelion.docker (master) is already installed - use --force to change version to unspecified

Tiresome. I should be flattered, not warned ;) Vagrant prolly added the --force flag to suppress this warning? By random accident, I found another solution. Add an explicit version tag (docs) to the role definition and voila, warning is replaced with something cute instead:

- mongrelion.docker (6a4fe8fc18550bfff8eeecd89888cf817cdf4bfc) is already installed, skipping.

If you still get the warning message, then that's cuz you had another version installed already before adding the version tag explicitly. So, now you must use --force at least once to force the update or manually remove the old (ansible-galaxy remove stupid.role).

Having said all of the above, this is the final contents I ended up with..

Vagrantfile:
config.vm.provision 'preemptively give others write access to /etc/ansible/roles', type: :shell, inline: <<~'EOM'
  sudo mkdir /etc/ansible/roles -p
  sudo chmod o+w /etc/ansible/roles
EOM

config.vm.provision 'ansible', run: 'always', type: :ansible_local do |ansible|
  ansible.galaxy_role_file = 'requirements.yml'
  ansible.galaxy_roles_path = '/etc/ansible/roles'
  ansible.galaxy_command = 'ansible-galaxy install --role-file=%{role_file} --roles-path=%{roles_path}'
  ansible.playbook = 'playbook.yml'
end
requirements.yml:

---
- src: mongrelion.docker
  version: 6a4fe8fc18550bfff8eeecd89888cf817cdf4bfc

like image 83
Martin Andersson Avatar answered Sep 20 '22 02:09

Martin Andersson