Best practice for Ansible play and role handling

When you start using ansible you write a play to (for example) configure a server for use in the profuction environment for the enterprise. You could so this as a
single play. This playbook can grow to be enormous in functionality and subsequently in number of lines. To prevent this, roles are created, this breaks up the the main play into manageble chunks of code, each with a dedicated function for the main play.

You could also use different files in the play for this, but this has the disadvantage that code is not reusable and might get copied into other playbooks, needing maintenance when the code changes (believe me, it will!).

Example 1

As an example, we have this playbook in a repository that will configure the server for production use. The play is not in one file, but broken into separate files, to deliver the functionality as a whole. We will not show you the contents of the whole play, that is not the target of this
document.

configure_server  (repository)
  audit.yml
  cups.yml
  firewall.yml
  grub.yml
  ldap.yml
  main.yml
  packages.yml
  satellite.yml
  selinux.yaml 
  sudoers.yml
  time_sync.yml
  sshd.yml
  users.yml
  templates (directory)
    sudo.j2
    sshd.j2
    grub.j2
    audit.j2
  README.md
  SVD.md

AS you see in the above example, the play consists of many files, a change to one file, is a change to the complete play and with many people working on th same play, this can become cumbersome.
As this is just a small example, you can imagine that changing and testing this becomes more problematic as the code grows. Reuse of code is not possible, without copying the file to a new repository and with every copy the locations to maintain a piece of code is added, and thus a risk for runnning old code that is not changed when the original code was changed.
Documenting this play is also a problem, the documentation is huge, if done in depth, and maintaining that will be error prone or things will get left out, making the documentation unuseable.

SO how do we solve this and still keep the overview over all code repositories?

Breaking code up in roles

Now we will breakup the code into roles, this enables us to manage the individual parts seperately.
But here it comes....
If you just give the roles the name of the file in the original playbook, you will eventually get namespace issues and you can't distingish by name, what repository holds a role and what repository holds a playbook.

Definition

A play is a complete set of tasks that will do all configuration for an item (eg. a server in an environment) A role is a set of tasks that will do the complete configuration for a subitem of a play.

Using this best practice will help you to keep track of all code..

Best practice

We start with the playbook repositories, we will describe this here:
A playbook has a specific function (eg. configure_rhel_server or something like that)
So we start with this convention fo example:
pl_rhel_configure_server

The this is based on the following:
* pl: This is a play (obviously)
* rhel: The os/middleware name this play installs/configures
* last part: is a descriptive shortname for the functionality

The roles will then be named as followes:
rl_rhel_role_name

This is the based on the following: * rl: This is a role (and cannot be run as play, but as part of one or more) * rhel: The os / middleware in which this role has a role to play * last part: The descriptive name for the part this role is implementing

Important
When you have a play that incorporates a lot of roles, the play book itself should
have no functionality in it, other than directing the roles, so the determins if a
role is being run or not. It does no changes on the systems it runs against.
This keeps the household clean...

Why this naming convention

Then naming convention help to keep thing organized in larger environments and over
time. When you haven't worked on your code for a long time, you probably won't remember
all relations between plays and roles.
Lets take a closer look at the git repositories when the naming convention is applied.

Example 2 (git project overview)

pl_rhel_config_server
pl_apache_web_server
rl_apache_certificate
rl_apache_content
rl_apache_packages
rl_rhel_audit_config
rl_rhel_cups_config
rl_rhel_firewall
rl_rhel_grub
rl_rhel_ldap
rl_rhel_packages
rl_rhel_satellite_registration
rl_rhel_selinux
rl_rhel_sudoers
rl_rhel_time_sync
rl_rhel_sshd_config
rl_rhel_local_users

In this example, there are only 2 play with a lot of roles, but because of the naming convention, you instantly know which roles belong to which plays.
You can see, when the number of plays increases, that this becomes important.
Maintenance with a larger team is also easier, you can work independently on multiple parts of the code (roles), without merge conflicts.
Documentation is also easier, as each role is documented in its own repository, making it easier to read and maintain. As a result, documentation is more acurate.

Git

As you will be storing these versioned plays and roles into git, create groups in git in which teams with the same responsibilities work together, this will help you to organiza the work even better.

file naming

Back

Backto Site