Foreman is a great tool to automate all the things around your infrastructure, but how can you automate Foreman itself?
Using Ansible and the Foreman Ansible Modules of course!
As a reader of this blog you probably don’t need convincing that automation is great, enables easier collaboration, better accountability and easier reproducibility.
This post will show you how you can use Foreman Ansible Modules to manage your Foreman and Katello installations via Ansible.
What are Foreman Ansible Modules?
Foreman Ansible Modules (FAM) are a set of Ansible modules to manage Foreman ;-)
These modules are an evolution from the foreman
and katello
modules currently present in Ansible itself, as those are deprecated since Ansible 2.8 and are scheduled for removal in 2.12.
Due to the use of a Katello (or rather Satellite) specific library, the old modules would not work properly in plain Foreman setups and often lacked features that were not yet present in Red Hat Satellite 6.
Over the course of the past year, the community sat together, cleaned the modules up, created tests and documentation and finally also ported the modules to a Satellite independent library.
Today we cover most Foreman and Katello workflows (see below for examples) and would like to extend to other plugins soon.
How can the modules be used?
The foreman-ansible-modules git repository contains instructions how the modules can be installed in your environment and module documentation is available from theforeman.org.
Usually you’ll find one module per Foreman entity (Organization, Location, Host Group etc.) or action (Katello Repository Sync, Katello Content Upload, etc).
Each module takes a set of common parameters:
server_url
: the URL of your Foreman instance (e.g.https://foreman.example.com
)username
: the login of the user that will be used for API authentication (e.g.admin
)password
: the password of said user (e.g.changeme
)validate_certs
: whether or not to validate the TLS certificates the server presents
So if you’re about to create a new domain
, the task in your Ansible playbook will look like this:
- name: create example.org domain
foreman_domain:
name: example.org
state: present
server_url: https://foreman.example.com
username: admin
password: changeme
That’s it, now you just have to write playbooks for every part of your Foreman environment and done ;-)
How do the modules work?
MAGIC! Well, actually, no, not magic, DOCUMENTATION!
Foreman has a powerful API with rich API documentation.
This documentation is generated by the apipie-rails
gem, which also provides a machine readable version of said documentation.
You’ve probably seen long-ish rake apipie:cache
processes when installing Foreman and plugins – that’s the gem re-generating the documentation to match the set of plugins available in your environment.
The modules use a library (apypie
) that can parse the machine readable documentation of your instance and generate correct API requests based on that documentantion.
Given almost all modules share a lot of common code, there is an abstraction class ForemanAnsibleModule
which takes care of the common tasks like establishing an API connection, executing searches and creating/updating/deleting entities. This allows the modules be clean and only contain data/code relevant for their specific task – have a look at the foreman_organization
module for a very simple example.
Examples
The previous example was quite short. Here are a few real world examples how we use the modules today. For the sake of readability, the server_url
, username
and password
parameters were omitted.
Enable and sync a Katello repository and add it to a Content View
- hosts: localhost
vars:
content_view: RHEL
product: "Red Hat Enterprise Linux Server"
repo: "Red Hat Enterprise Linux 7 Server (RPMs)"
repo_variants:
- releasever: "7Server"
basearch: "x86_64"
organization: ACME
tasks:
- name: "Enable {{ repo }} repository"
katello_repository_set:
name: "{{ repo }}"
product: "{{ product }}"
repositories: "{{ repo_variants }}"
organization: "{{ org }}"
state: enabled
- name: "Sync {{ repo }} repository"
katello_sync:
repository: "{{ repo }}"
product: "{{ product }}"
organization: "{{ org }}"
- name: "Create RHEL ContentView"
katello_content_view:
name: "{{ content_view }}"
repositories:
- name: "{{ repo }}"
product: "{{ product }}"
organization: "{{ org }}"
state: present
- name: "Publish RHEL content view"
katello_content_view_version:
content_view: "{{ content_view }}"
organization: "{{ org }}"
Create Katello Lifecycle Environment and Activation Key
- hosts: localhost
vars:
activation_key: rhel
lifecycle_env: Test
content_view: RHEL
subscriptions:
- name: "Red Hat Enterprise Linux"
organization: ACME
tasks:
- name: "Create {{ lifecycle_env }} LCE"
katello_lifecycle_environment:
name: "{{ lifecycle_env }}"
prior: "Library"
organization: "{{ org }}"
state: present
- name: "Create {{ activation_key }}-{{ lifecycle_env }} Activation Key"
katello_activation_key:
name: "{{ activation_key }}-{{ lifecycle_env }}"
lifecycle_environment: "{{ lifecycle_env }}"
content_view: "{{ content_view }}"
subscriptions: "{{ subscriptions }}"
organization: "{{ org }}"
state: present