Using Ansible 2.x To Support Multiple Package Managers (Unix Distributions)
1 January 2016
Ansible version 2 adds a range of new features including
better support for multiple package managers with a new
package
module.
During a recent upgrade of servers - which used various different
package management systems
(yum
and dnf
) - we decided to upgrade our
Anisble scripts to version 2 (currently in rc3) to
simplify support for these different package management
systems that we use.
This blog post provides details how this was done including code samples.
Historically Handling Multiple Package Managers with Ansible 1.x
Traditionally, with Ansible 1.x the packages were handled
via specific modules to support each of the major package
managers. For example, yum
for CentOS/Fedora and
apt-get
for Debian distributions.
For example, the installation a package ntpd
can
have been written as,
- name: install ntpd
yum: name=ntpd state=latest
when: ansible_distribution == "Fedora"
- name: install ntpd
apt-get: name=ntpd state=latest
when: ansible_distribution == 'Ubuntu'
The issue with this code is that it repeat itself
with the only difference being the distribution.
This repetition
breaks the DRY principle
(https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
and leads to a lot of boiler plate
repetition.
Anisble 2.x Package Module
Ansible 2.x introduces a new package
module
which attempts to eliminate this issue
(see docs.ansible.com/package_module.htm). Using the
module the code can now be written without repetition as
the package manager will be selected at run-time by ansible.
For example the above code now becomes,
- name: install ntpd
package: name=ntpd state=latest
This is easier to read and makes it more robust by removig the references to the specific distribution's package manager.
For example, this
will now work on any distribution that has a
ntpd
package such
as BSD distribution which had not been considered before.
Anisble 2.x Package Module Limitation
Whilst the package
module is a significant improvement
there is a limitation to its use as the name of the software
package being installed needs to have the same on each distributions.
For example, the Apache web server's package is named
httpd
on CentOS/Fedora and apache2
on Debian distributions.
The recommended way that we resolved this issue is use variable which can be changed depending up this distribution.
- name: install apache
package : name={{apachepkg}} state=present
This approach has now created a different issue in that a list of package names needs to be maintained for each distribution that is used.
In practice we have not found this to be a significant issue as many of the package names are the same across the distributions that we use. So this is now a much smaller task than before (as this can be included in a single place in the source) and the DRY principle has been upheld.
Final Code
In the vast majority of our Ansible scripts we successfully did a
global search for our existing package managers
references (such as yum
, apt-get
) and
replaced them with package
references.
There were only a few cases were the package name was different.
In the cases where the package names did not match we created a simple variable at the start of the Ansible code to handle the difference.
For example,
- name: defined var apachepkg (Fedora)
apachepkg=httpd
when: ansible_distribution == "Fedora"
- name: defined var apachepkg (Ubuntu)
apachepkg=apache2
when: ansible_distribution == 'Ubuntu'
- name: install apache
package : name={{apachepkg}} state=latest
If there had been many references that we had to handle an alternative approach we could have used would have been to create distribution specific variable files and to load these.
For example,
# files to provide distribution specific package names
- include_vars: "{{item}}"
with_first_found:
- "package-names-{{ansible_distribution}}.yml"
- "package-names-{{ansible_os_family}}.yml"
- "package-names.yml"
- name: install apache
package : name={{apachepkg}} state=latest
Conclusion
The upgrade to the Ansible 2.x package
was very effective and solved our issue of maintaining
duplicate code for different package managers (on
different Unix platforms).
However, in the future there is the possibility for the
package
module to have its own built-in
look-up feature to automatically hand the
differences in packages names
between the various Unix distributions.
Also see more postings in my Blog.