Version control of roles in Ansible

Role reuse is an important part of building an efficient, standardized system of playbooks for administrators and engineers to apply. We have given many examples throughout this bookfor example, in Chapter 10, Managing Users on Linux—we proposed a simple role that would add users to a Linux system. To save you referring back, the code is as follows:

---
- name: Add required users to Linux servers
user:
name: "{{ item.name }}"
comment: "{{ item.comment }}"
shell: /bin/bash
groups: "{{ item.groups }}"
append: yes
state: present
loop:
- { name: 'johndoe', comment: 'John Doe', groups: 'sudo'}
- { name: 'janedoe', comment: 'Jane Doe', groups: 'docker'}

Given our discussion about role reuse, I'm sure that you can see that the design of this role could be improved. This role has hardcoded user accounts in it, which does not lend itself to reuse at all. However, if the user accounts were specified via an Ansible variable, then this role could be used in any playbook that needed to add a user account to a Linux system. This moves us one step closer to our goal of creating standardized, reusable code.

However, we need to ensure that the code appears in every playbook that requires it. Further, we must also ensure that the version is kept up to date—otherwise, if someone makes an improvement to the code (or fixes a bug or adapts the code for a newer version of Ansible because of some feature deprecation), this will only exist in the modified role—all of the copies will be out of date. If the role is copied to any playbooks, it will become difficult to ensure that they are kept up to date. To achieve this, we clearly need to start storing our roles in our source control system, and in this case, we must store one role per repository (the reasons for this will become apparent as we progress through the following examples).

Once your roles are in your source control system, there are two ways to address the problem of efficient and effective reuse. The first is to make use of Git submodules. This is a Git-specific technology so will not suit you if you are using Subversion or Mercurial, but if you are using Git it is one of two possible solutions.

A Git submodule is basically a reference to another Git repository from within another. Hence, it does not actually contain the code of the submoduleit simply contains a reference to it that can be cloned and updated as required. Suppose that you are writing a playbook to install Apache 2 on a server and you decide that, rather than write your own module, you are going to use Jeff Geerling's Apache 2 role from GitHub (https://github.com/geerlingguy/ansible-role-apache):

  1. Before you start, you will need to have your playbook directory structure created and checked into your version control system. Then, ensure you have the roles/ directory in your playbook structure as normal and change to this directory:
$ mkdir roles
$ cd roles
  1.  Now, check out the code you want as a submodule, providing the Git tool with a directory name to clone it to—in our case, we'll call it jeffgeerling.apache2:
$ git submodule add https://github.com/geerlingguy/ansible-role-apache.git jeffgeerling.apache2
  1. Once this is done, you will notice that you have a new file at the root of your working copy called .gitmodules. You will need to add this and the directory created by the submodule add command to your repository:
$ git add ../.gitmodules jeffgeerling.apache2
$ git commit -m "Added Apache2 submodule as role"
$ git push

That's all there is to it—you now have this role stored within your playbook directory structure, but as far as Git is concerned, it is stored elsewhere. The whole process should look something like what's shown in the following screenshot:

To update this submodule at any time, you must change into the directory you created for it earlier and then run a standard git pull command. The beauty of this is that, as far as Git is concerned, the submodule is just another repository and so you can run all of the usual subcommands you are used to such as push, pull, status, and so on.

The only thing to add is that, when you clone the playbook directory for the first time from your Git server, although it will be aware of the submodule, it doesn't actually check out the code. Hence, when you clone for the first time, you must run the following commands:

$ git clone <your repository URL>
$ cd <your repository name>
$ git submodule init
$ git submodule update

From here, you can use the working copy and submodule exactly as described previously.

The other way to solve the problem of role code reuse is to make use of the ansible-galaxy tool. We saw ansible-galaxy in action in Chapter 2, Automating Your IT Infrastructure with Ansible, where we demonstrated it as a way of cloning publicly available roles from the Ansible Galaxy web site (https://galaxy.ansible.com/). However, ansible-galaxy can also clone roles from a valid Git URL. 

Suppose we wanted to achieve exactly what we have just done with the Apache 2 role, but without using Git submodules. Instead, we create a file called requirements.yml in the base directory of the playbook structure.

To clone the role we just used, our requirements.yml file would need to look like this:

---
- src: https://github.com/geerlingguy/ansible-role-apache.git
scm: git

You can, of course, have more than one requirement in this filejust specify them as a standard YAML list. When you have completed this file, you can then download the roles to your working copy using this command:

$ ansible-galaxy install -r requirements.yml --roles-path roles

This clones the Git repository referenced by the src parameter in requirements.yml into the roles/ directory. Note that we do not customize the directory name, so the one from the Git repository is used for the role name (in this case, ansible-role-apache). The following screenshot shows an example of this being completed:

Unlike the submodules, ansible-galaxy does not actually clone the repository as a working copy; hence, you cannot simply change into its directory and run git pull command to update it to the latest version. Instead, requirements.yml should remain in your working copy, and in the future, to update, you would run the following command:

$ ansible-galaxy install -r requirements.yml --roles-path roles --force

The --force parameter instructs ansible-galaxy to download the role even if it is already downloaded, hence overwriting the version you have already installed.

We have only scratched the surface of what can be achieved with requirements.yml—you can download from private repositories, ensure you only ever download a specific Git version, and more—this is left as an exercise for you to investigate.

Hence, you have two completely different yet equally valid ways to efficiently reuse roles by storing them individually in a source control system. By considering everything in this section, including the decision to use AWX or Ansible Tower, you should have a robust and scalable automation architecture built around Ansible.

In the next section, we will address another facet of Ansible that has so far not received a great deal of attention by virtue of our simple example structure, and yet is vital to its operation—the inventory.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset