Installing Katello (the upstream project of Red Hat Network Satellite Server 6) and provisioning Foreman proxies (that are the upstream software of the Red Hat Network Satellite Server 6 Capsules), same way as installing software in general, is a typical time consuming and error prone task that is often convenient to automate in some way.
Ansible can be easily exploited to automate Katello installation having it to:
- ensure that the target system meets the minimal requirements
- automatically partition the system in the most convenient way
- install everything taking in account of using the right versions of the involved packages so as to avoid installation failure because of wrong dependencies
- set up all the configurations that are required to improve the usability of the installed environment
- take care of issuing all the necessary statements to configure a Foreman proxy (a Capsule) on Katello (the Satellite) and automatically provision it
This post, based on CentOS 7, shows how to structure an Ansible project developing playbooks that either install Katello or install and configure Foreman proxies (Capsules, in Red Hat Network Satellite Server 6 terms). In addition to that, the playbooks can also be used to reconfigure the provisioned Katello or Foreman proxies, for example to enable plugins. In this post we also see how to install the "theforeman.foreman" Ansible galaxy collection along with its dependencies, that enables the management of Katello using Ansible.
Prerequisites
Katello is a huge step onward from Spacewalk: everything has been completely redesigned to improve software lifecycle management. It is a massive suite that, as you can easily argue, demands a high amount of CPU and RAM.
The very minimum requirements are:
- 4 cores
- 20 GB of RAM
- enough disk space to store the packages that are provided by its repositories
As you can easily figure out, running Katello does require a lot of GB of disk space not because of the Katello software itself, but for the amount of data required by the packages and images it downloads when providing local software repositories. It is straightforward that the best approach is using LVM to manage the disk space, since this system will keep on demanding more and more disk space as time passes by.
In this Lab we use the "system" Volume Group, that is the one used by the base platform, but you may of course prefer using a dedicated Volume Group; about the sizing, in my opinion a LVM Volume Group with at least 100GiB is a good starting point.
If your Volume Group is not big enough, you can attach additional disks, mark them as Physical Volumes and extend the Volume Group over them. For example, to add the "/dev/sdb" disk to the "system" Volume Group issue:
sudo pvcreate /dev/sdb
sudo vgextend system /dev/sdb
Install And Configure Ansible On The Katello Host
The community version of Ansible is available in the EPEL repository, so we need to enable it:
sudo yum install -y epel-release
we are ready to install Ansible as follows:
sudo yum install -y ansible
it is better to have a dedicated operating system user to run the Ansible playbooks and commands. In this post this is the "ansible" user - create it as follows:
sudo useradd -r -m -c "Ansible Automation" ansible
most of the tasks performed by Ansible do require administrative rights: let's create the sudo rule that grants the "ansible" user the right to run any kind of command as any user without being asked for a password:
sudo bash -c "cat > /etc/sudoers.d/ansible" <<'EOF'
ansible ALL=(ALL) NOPASSWD: ALL
EOF
Setup The Katello Ansible Project
We are ready to implement the Ansible project that manages the automated installation of Katello.
Its directory layout, as by the Ansible best practices, is as follows:
a directory tree containing the list of available target hosts along with their properties: the hosts and host-groups are listed in the "hosts" file (in this post we are using the INI syntax), whereas their properties are declared into a dedicated file, with the host name itself as the filename, stored beneath the "host_vars" sub-directory
a directory where to store the task files that are imported by the main playbook - the rationale is grouping tasks so to keep the project tidy
a directory tree where to store the JINJA template files used by Ansible to generate configuration files from
a directory tree where resource files are stored. In this project we store settings files for the different versions of Katello beneath the "versions" directory, whereas we put the patches that apply to specific versions of Katello into the "patches" directory. The "sudo" and the "smartproxies" directories are instead needed when dealing with Foreman proxies (Capsules): "sudo" is used to store the file with the sudo settings for the "ansible" that must be granted on the Foreman proxies hosts so to be able to get administrative rights when installing and configuring them; "smartproxies" is used to store the file with the certificate bundle used when installing the Foreman proxy and a text file with the command that is used by the Ansible automation to perform the configuration.
a directory where to store the "requirements.yml" file with the list of the collections that are necessary to install since they are required to run the playbooks. Doing this way our project is compatible with Red Hat Ansible Tower, enabling you to configure the job to automatically download the collections listed in this file before running the playbooks.
just switch to the user "ansible":
sudo su - ansible
then create the whole directory tree of the project as follows:
mkdir -m 755 katello \
katello/inventory \
katello/inventory/host_vars \
katello/collections \
katello/files \
katello/files/smartproxies \
katello/files/sudo \
katello/files/versions \
katello/files/patches \
katello/files/patches/3.12 \
katello/templates \
katello/tasks
then change directory into it:
cd katello
Configuring The Inventory
Ansible fetches its target hosts from the so called "inventory": since we are going to configure our custom inventory into the "inventory" directory, we must configure Ansible to use the "inventory" directory as the default inventory lookup path.
Create the ansible.cfg file with the following contents:
[defaults]
inventory = inventory
Ansible target hosts and groups of hosts are listed in the "hosts" text file of the "inventory" directory. In this project we are using the INI syntax, so add the hostnames of the systems you want to install Katello and provision the Foreman proxies onto into the inventory/hosts file as follows:
sat-ci-up3a002 ansible_connection=local
since in this post the "sat-ci-up3a002" host is both the Ansible management station and the host we install Katello onto, we set the "ansible_connection" attribute to "local" to avoid the unnecessary use of SSH connections to the local system itself.
Create the inventory/host_vars/sat-ci-up3a002.yml file that contains the settings that are specific to the "sat-ci-up3a002" host:
katello_version: "3.12"
katello_scenario: "katello"
katello_admin_user: admin
katello_cli_admin_user: katello
server_domain: mgmt.carcano.local
provisioning_interface: eth0
provisining_network: "10.1.0"
katello_installer_extra_options:
- "--foreman-proxy-dns true"
- "--foreman-proxy-dhcp true"
- "--foreman-proxy-tftp true"
- "--foreman-proxy-dns-interface {{ provisioning_interface }}"
- "--foreman-proxy-dhcp-interface {{ provisioning_interface }}"
- "--foreman-proxy-dns-zone provision.{{ server_domain }}"
- "--foreman-proxy-dns-forwarders 10.0.2.3"
- "--foreman-proxy-dns-reverse {{ provisining_network.split('.')[2] }}.{{ provisining_network.split('.')[1] }}.{{ provisining_network.split('.')[0] }}.in-addr.arpa"
- "--foreman-proxy-dhcp-range '{{ provisining_network }}.10 {{ provisining_network }}.20'"
- "--foreman-proxy-dhcp-gateway {{ provisining_network }}.1"
- "--foreman-proxy-dhcp-nameservers {{ provisining_network }}.1"
katello_plugins:
- "--enable-foreman-plugin-remote-execution"
- "--enable-foreman-proxy-plugin-remote-execution-ssh"
- "--foreman-proxy-plugin-remote-execution-ssh-install-key=true"
katello_organizations:
- name: Carcano
description: Carcano SA
storage_pools:
- name: system
disks:
- sda2
- sdb
volumes:
- name: pulp_cache
size: 13G
fs_type: xfs
mount_point: /var/cache/pulp
- name: pulp_data
size: 50G
fs_type: xfs
mount_point: /var/lib/pulp
- name: mongodb
size: 20G
fs_type: xfs
mount_point: /var/lib/mongodb
- name: qpidd
size: 5G
fs_type: xfs
mount_point: /var/lib/qpidd
- name: pgsql_data
size: 5G
fs_type: xfs
mount_point: /var/lib/pgsql
- name: squid_data
size: 5G
fs_type: xfs
mount_point: /var/lib/squid
as you see the host specific settings in this file are:
- filesystem partitioning (lines 27-56)
- katello version to install (line 1)
- a configuration switch (katello_scenario) that tells Ansible that this host is a Katello server (line 2)
- katello administrator username (line 3)
- katello cli (hammer) administrator username (line 4)
- infrastructural information (lines 5-19)
- Katello plugins (lines 20-23)
- list of Katello organizations to create (lines 24-26)
You can of course extend it with attributes as by your needs.
Configuring The Encrypted Secrets File
As you probably already figured-out, sensitive attributes have not been put inside the previous files because they must be stored using an encrypted format: in this post we use Ansible Vault encrypted files, but Ansible lets you use several other kinds of vaults if necessary.
To generate the files/secrets.yml encrypted file, type the command:
ansible-vault create files/secrets.yml
fill-in it with the following contents:
katello_admin_password: grimoire
root_user_password: grimoire
doing this way we are keeping both the password of the Katello administrator and of the root user of the foreman proxies hosts safe from malicious eyes.
Configuring Resource Files
Resource files can have several purposes - in this project we have two kind of them:
- var files, used to provide variables used by the tasks
- patch files, that are simply copied to the filesystem of the target host and applied to fix problems that affect specific versions of Katello.
Common Software Repositories
There are settings that remains the same across the various versions of Katello - we store them into the files/repos.yml file:
apypie_url: https://yum.theforeman.org/client/2.0/el7/x86_64/python2-apypie-0.2.1-2.el7.noarch.rpm
it contains only the URL to download the apypie RPM package that is needed by the "theforeman.foreman" Ansible galaxy collection.
Katello Version Specific Software Repositories
Then let's create the files with the URLs from where to download the RPM packages that provides the repository configuration specific to install a specific Katello version:
the files/versions/katello_3_12.yml file is specific to version 3.12:
foreman_release: https://yum.theforeman.org/releases/1.22/el7/x86_64/foreman-release.rpm
katello_repos: https://fedorapeople.org/groups/katello/releases/yum/3.12/katello/el7/x86_64/katello-repos-latest.rpm
puppet_repos: https://yum.puppet.com/puppet5-release-el-7.noarch.rpm
the files/versions/katello_3_16.yml file is specific to version 3.16:
foreman_release: https://yum.theforeman.org/releases/2.1/el7/x86_64/foreman-release.rpm
katello_repos: https://fedorapeople.org/groups/katello/releases/yum/3.16/katello/el7/x86_64/katello-repos-latest.rpm
puppet_repos: https://yum.puppet.com/puppet6-release-el-7.noarch.rpm
Patches
It is known that Katello 3.12 has a problem with subscriptions ending beyond the 2049 year: to fix it, create the files/patches/3.12/rhsm-beyond-2049.patch patch file with the following contents:
Are you enjoying these high quality free contents on a blog without annoying banners? I like doing this for free, but I also have costs so, if you like these contents and you want to help keeping this website free as it is now, please put your tip in the cup below:
Even a small contribution is always welcome!
--- katello-3.12.3/app/lib/katello/resources/candlepin/product.rb 2022-03-12 16:45:49.423241421 +0100
+++ katello-3.12.3-patched/app/lib/katello/resources/candlepin/product.rb 2022-03-12 16:48:21.638478669 +0100
@@ -72,8 +72,10 @@
def create_unlimited_subscription(owner_key, product_id, start_date)
start_date ||= Time.now
- # End it 100 years from now
- end_date ||= start_date + 10_950.days
+ # python-rhsm - (subscription-manager) can't read certificates with an end date
+ # beyond 2049 year
+ end_date = Time.parse('2049-12-01 00:00:00 +0000')
+ end_date ||= start_date + 3_650.days
pool = {
'startDate' => start_date,
Configuration Files
In this post we create the "katello" user specifically to be able to issue hammer statements without having to type the user credentials each time: Hammer can use a credential file indeed - the playbook generates it from the templates/foreman.j2 file with the following contents:
:foreman:
:username: '{{ katello_admin_user }}'
:password: '{{ katello_admin_password }}'
Creating The Playbooks
We are finally ready to code the playbook: as we said, in order to keep it simple to maintain and understand, we split the tasks into several specialized tasks files.
Environment Validation Tasks File
The tasks that performs the validation to make sure that the installation requirements are met can be grouped within the same file: let's put them into the tasks/validate.yml file:
---
- name: add installed packages to the collected facts
package_facts:
manager: auto
tags:
- never
- install
- name: fail if katello is already installed
fail:
msg: Katello is already installed on this host
when: "'katello' in ansible_facts.packages"
tags:
- never
- install
- name: make sure the system has enough CPU cores to bare Katello
fail:
msg: "This system does not have the minimum required cores to run Katello.\nKatello needs at least 4 cores "
when: ansible_processor_cores < 4
tags:
- never
- install
- name: make sure the system has enough RAM to bare Katello
fail:
msg: "This system does not have the minimum required memory to run Katello.\nKatello needs at least 20GiB of RAM"
when: ansible_memory_mb.real.total < 19900
tags:
- never
- install
this task list makes sure that:
- Katello has not been installed yet
- the system does have at least 4 cores
- the system does have at least 20GB of RAM
If any of these requirements is not met the playbook fails with an error message specific that highlights which requirement is not met.
Filesystems Creation Tasks File
Before installing it is always wise to create dedicated partitions as suggested by the installation best practices of the product. We put these tasks in the tasks/filesystems.yml file:
---
- block:
- name: installing rhel-system-roles
yum:
name: rhel-system-roles
state: installed
delegate_to: localhost
- include_role:
name: rhel-system-roles.storage
- name: removing RPM packages conflicting with Katello
yum:
name:
- libmodulemd
- libblockdev*
state: absent
become: true
tags:
- never
- install
this task list:
- installs the "rhel-system-roles" RPM packages that provides the official Red Hat roles to manage the system
- includes and runs the "rhel-system-roles.storage" role that automatically setup partitions as specified by the "storage_pools" variable - this variable is set within the inventory for each specific target host
- removes some RPM packages that are installed when running the role but that seem to conflict during the installation of Katello
Packages Installation Tasks File
We have reached the core part of the installation: create the tasks/install.yml file with the following contents:
---
- name: updating the system
become: true
yum:
name: '*'
state: latest
register: system_output
tags:
- never
- install
- debug:
var: system_output
verbosity: 2
tags:
- never
- install
- name: disabling every repository
become: true
shell: yum-config-manager --disable "\*"
tags:
- never
- install
- name: installing the packages providing the configuration of the repositories
become: true
yum:
name: "{{ packages }}"
state: installed
vars:
packages:
- "{{ foreman_release }}"
- "{{ katello_repos }}"
- "{{ puppet_repos }}"
- "epel-release"
tags:
- never
- install
- name: installing the Foreman Release SCL package
become: true
yum:
name: foreman-release-scl
state: installed
tags:
- never
- install
- name: installing Katello package
become: true
yum:
name: katello
state: latest
tags:
- never
- install
- name: installing apypie
become: true
yum:
name: "{{ apypie_url }}"
state: installed
delegate_to: localhost
tags:
- never
- install
- name: reinstalling RPM packages conflicting with Katello during install
become: true
yum:
name:
- libmodulemd
- libblockdev*
state: latest
tags:
- never
- install
the task list performs a system update, then it installs the RPM packages that configure the repositories from where download Katello and Foreman packages of the selected version. It also takes care of install the "theforeman.foreman" Ansible galaxy collection, installing also its requisite "apypie". In addition to that, it re-installs the RPM packages needed by "rhel-system-roles.storage" that it uninstalled before to avoid conflicts during the installation of the Katello and Foreman RPM packages.
Since we also apply patches when necessary, we create the tasks file to apply them: these tasks are stored into the tasks/patches.yml file:
---
- name: copying patch rhsm-beyond-2049.patch to /tmp
become: true
copy:
src: files/patches/3.12/rhsm-beyond-2049.patch
dest: /tmp
when: 'katello_version == "3.12"'
tags:
- never
- install
- name: applying rhsm-beyond-2049.patch
become: true
shell: patch -p1 < /tmp/rhsm-beyond-2049.patch
args:
chdir: /opt/theforeman/tfm/root/usr/share/gems/gems/katello-3.12.3
when: katello_version == "3.12"
tags:
- never
- install
- name: removing rhsm-beyond-2049.patch from /tmp
become: true
file:
dest: /tmp/rhsm-beyond-2049.patch
state: absent
when: katello_version == "3.12"
tags:
- never
- install
in this post it applies only the "year 2049 bug" patch file to Katello 3.12, but you can extend it with other patches as necessary.
Foreman-Proxy Node Pre-Configuration Task File
This task file is the one that configures the foreman-proxy nodes to be managed using Ansible: create the tasks/prepare-smartproxy.yml with the following contents:
---
- block:
- name: create ansible user
user:
name: ansible
password: "!"
- name: create sudo rule
copy:
src: files/sudo/ansible
dest: /etc/sudoers.d
- name: create /home/ansible/.ssh directory
become_user: ansible
file:
path: /home/ansible/.ssh
state: directory
mode: "0700"
- name: authorize ansible SSH public key
become_user: ansible
copy:
src: /home/ansible/.ssh/id_rsa.pub
dest: "/home/ansible/.ssh/authorized_keys"
mode: "0640"
become: true
when: katello_scenario != "katello"
tags:
- never
- install
as you see this task file copies the files/sudo/ansible with the sudo rule for the Ansible user to the /etc/sudoers.d directory of the target system. Create the files/sudo/ansible file with the following contents_
ansible ALL=(ALL) NOPASSWD: ALL
Foreman-Proxy Configuration Task File
This task file is the one that creates the foreman-proxy (the Capsule, in Satellite terms) configuration file that is used by foreman-installer to configure the foreman-proxy: create the tasks/configure-smartproxy.yml with the following contents:
---
- block:
- name: generate smart-proxy certificates bundle
shell:
cmd: "foreman-proxy-certs-generate --no-colors --foreman-proxy-fqdn {{ ansible_fqdn }} --certs-tar /home/ansible/katello/files/smartproxies/{{ inventory_hostname }}.tar"
chdir: /root
register: foreman_proxy_certs_generate
delegate_to: localhost
- name: print the outcome of foreman-proxy-certs-generate
debug:
msg: "{{ foreman_proxy_certs_generate }}"
verbosity: 1
- set_fact:
foreman_proxy_install_command: "{{ foreman_proxy_install_command | default([]) + [ item | regex_replace ('\\\\','') | regex_replace(' +',' ') ] }}"
loop: "{{ foreman_proxy_certs_generate.stdout_lines[-10:] }}"
- set_fact:
foreman_proxy_install_command: "{{ foreman_proxy_install_command | join(' ') | replace(' ',' ') }}"
- debug:
msg: "{{ foreman_proxy_install_command }}"
- name: print the command to install foreman proxy
debug:
msg: "{{ foreman_proxy_install_command }}"
verbosity: 1
- name: create files/smartproxies/{{ inventory_hostname }}-capsule-install.txt
copy:
content: "{{ foreman_proxy_install_command }}"
dest: files/smartproxies/{{ inventory_hostname }}-capsule-install.txt
mode: "0644"
delegate_to: localhost
- name: create /root/files/smartproxies direcotry
file:
path: /root/files/smartproxies
state: directory
recurse: yes
mode: "0750"
- name: copy files/smartproxies/{{ inventory_hostname }}.tar to /root/files/smartproxies
copy:
src: files/smartproxies/{{ inventory_hostname }}.tar
dest: /root
become: true
when: katello_scenario != "katello"
tags:
- never
- install
Katello Configuration Tasks File
This last task file is the one that configures Katello: create the tasks/setup.yml with the following contents:
---
- name: configure firewalld services
become: true
ansible.posix.firewalld:
service: "{{ item }}"
permanent: true
immediate: true
state: enabled
loop:
- dns
- dhcp
- tftp
- http
- https
tags:
- never
- install
- name: configure firewalld services
become: true
ansible.posix.firewalld:
port: "{{ item }}"
permanent: true
immediate: true
state: enabled
loop:
- 5647/tcp
- 8000/tcp
- 8140/tcp
- 8443/tcp
- 9090/tcp
tags:
- never
- install
- name: adding katello user
become: true
user:
name: katello
comment: Katello
shell: /bin/bash
tags:
- never
- install
- name: creating hammer configuration directories for the katello user
become: true
become_user: katello
file:
dest: "/home/katello/{{ item }}"
state: directory
loop:
- .hammer
- .hammer/cli.modules.d
- .hammer/log
tags:
- never
- install
- name: generating hammer configuration file for the katello user
become: true
become_user: katello
template:
src: templates/foreman.j2
dest: /home/katello/.hammer/cli.modules.d/foreman.yml
tags:
- never
- install
- config
- debug:
msg: "installing katello with options {{ katello_installer_extra_options | join (' ') }}"
verbosity: 1
tags:
- never
- install
- name: setup Katello
become: true
shell: foreman-installer --scenario katello
--foreman-initial-admin-password {{ katello_admin_password }}
{{ katello_installer_extra_options | default() | join (' ') }}
register: katello_setup_output
when: katello_scenario == "katello"
tags:
- never
- install
- name: setup Foreman Smart-Proxy
become: true
command: "{{ foreman_proxy_install_command }} {{ katello_installer_extra_options | default() | join (' ') }}"
register: katello_setup_output
when: katello_scenario != "katello"
tags:
- never
- install
- debug:
var: katello_setup_output.stdout
tags:
- never
- install
- config
- debug:
msg: "configuring the plugins {{ katello_plugins | join (' ') }}"
verbosity: 1
tags:
- never
- config
- name: configure plugins
become: true
shell: foreman-installer {{ katello_plugins | join (' ') }}
register: katello_plugins_output
tags:
- never
- install
- config
- debug:
var: katello_plugins_output.stdout
tags:
- never
- install
- config
- name: configure the katello endpoint to connect to in /etc/hammer/cli.modules.d/foreman.yml file
become: true
lineinfile:
insertafter: ':foreman:'
path: /etc/hammer/cli.modules.d/foreman.yml
regexp: "^[ ]*:host:[ ]*.*"
line: " :host: 'https://{{ katello_hammer_api_host }}'"
when: katello_scenario != "katello"
tags:
- never
- install
- config
- name: add ssl section in /etc/hammer/cli.modules.d/foreman.yml file
become: true
lineinfile:
path: /etc/hammer/cli.modules.d/foreman.yml
regexp: ':ssl:'
insertbefore: 'EOF'
line: ':ssl:'
when: katello_scenario != "katello"
tags:
- never
- install
- config
- name: configure ssl_ca_file /etc/hammer/cli.modules.d/foreman.yml in file
become: true
lineinfile:
path: /etc/hammer/cli.modules.d/foreman.yml
regexp: "^[ ]*:ssl_ca_file:[ ]*'"
insertafter: ':ssl:'
line: " :ssl_ca_file: '/etc/pki/katello/certs/katello-server-ca.crt'"
when: katello_scenario != "katello"
tags:
- never
- install
- config
the above tasks:
- configure firewalld
- configure Katello
- configure Katello plugins
- create and configure the "katello" user as the user dedicated to run hammer commands without having to bother to specify credentials each time
Main Playbook
We are finally ready to create the site.yml file:
---
- name: prepare the Foreman Proxies to be managed by ansible
gather_facts: false
hosts: all
remote_user: root
vars:
- ansible_ssh_pass: "{{ root_user_password }}"
vars_files:
- files/secrets.yml
tasks:
- import_tasks: tasks/prepare-smartproxy.yml
- name: install and configure Katello and/or Foreman Proxies
gather_facts: true
hosts: all
remote_user: ansible
vars_files:
- files/repos.yml
- files/secrets.yml
tasks:
- include_vars:
file: files/versions/katello_{{ katello_version | replace('.','_') }}.yml
tags: always
- import_tasks: tasks/validate.yml
- import_tasks: tasks/filesystems.yml
- import_tasks: tasks/install.yml
- import_tasks: tasks/patches.yml
- import_tasks: tasks/configure-smartproxy.yml
- import_tasks: tasks/setup.yml
this is the main playbook of this Ansible project, that can be used to both install or re-configure Katello (for example enabling other plugins): as you see it does not contain any particular task: it just loads its settings from the var files and imports the actual tasks from the task files.
Other Playbooks
Besides installing Katello, we can exploit Ansible also to manage it. For example Katello relies on Organizations to segregate software life-cycles: organizations can be created using the Katello Web-UI or using the hammer command line utility, but we can of course use Ansible to manage them.
This can be accomplished by exploiting the "organizations" module of the "theforeman.foreman" Ansible galaxy collection.
Just to taste the gist of it, let's create the organization.yml playbook with the following contents:
---
- hosts: all
vars_files:
- files/secrets.yml
tasks:
- include_vars:
file: files/versions/katello_{{ katello_version | replace('.','_') }}.yml
tags: always
- name: create organizations
theforeman.foreman.organization:
server_url: "https://{{ inventory_hostname }}"
validate_certs: no
username: "{{ katello_admin_user }}"
password: "{{ katello_admin_password }}"
name: "{{ item.name }}"
description: "{{ item.description }}"
state: present
loop: "{{ katello_organizations }}"
delegate_to: localhost
this playbook creates the organizations listed in the "katello_organization" variable that is set in the settings file specific for the host (inventory/host_vars/sat-ci-up3a002.yml).
You can of course create other playbook to manage other stuff, for example Locations. You can get help on each module using the ansible-doc command line utility. For example, to get the documentation of the "theforeman.foreman.location" module type:
ansible-doc theforeman.foreman.location
Installing The Required Ansible Collections
The playbooks we wrote requires the following Ansible collections:
Ansible collections must be listed into the collections/requirements.yml file - create it with the following contents:
---
collections:
- ansible.posix
- theforeman.foreman
and then easily installed using the ansible-galaxy command line utility as follows:
sudo ansible-galaxy collection install -r collections/requirements.yml -p /usr/share/ansible/collections
note that if you are using Ansible Tower, you may skip to run the ansible-galaxy command, configuring the job to automatically download the required roles.
Running The Playbooks
We are finally ready to have a go trying everything.
Deploying The Katello Node
We can simply run ansible-playbook with the "install" tag (-t install), limiting the targets only to the "sat-ci-up3a002" host, so installing Katello version "1.12", but we can of course easily install the version "1.16" by setting the value of "katello_version" variable to "1.16" in the inventory/host_vars/sat-ci-up3a002.yml file. This file by the way contains several other settings, such as the partitioning scheme and sizing, that can be adjusted at wish.
When done with the settings, simply issue:
ansible-playbook -t install --ask-vault-pass --limit sat-ci-up3a002 site.yml
You can relax with a cup of tea if you fancy: installing and configuring everything takes quite a lot of time to complete.
Reconfiguring Katello
Besides installing Katello, the site.yml playbook can also be used to re-configure it, for example to enable other Foreman plugins such as the Ansible plugin (a very handy plugin that enables Katello to perform remote executions using Ansible).
This can be easily accomplished by adding the relevant foreman-installer options to the "katello_plugins" list in the inventory/host_vars/sat-ci-up3a002.yml file.
For example, modify the "katello_plugins" list as follows:
katello_plugins:
- "--enable-foreman-plugin-remote-execution"
- "--enable-foreman-proxy-plugin-remote-execution-ssh"
- "--foreman-proxy-plugin-remote-execution-ssh-install-key=true"
- "--enable-foreman-plugin-ansible"
- "--enable-foreman-proxy-plugin-ansible"
we just added:
- the "--enable-foreman-plugin-ansible" option to enable the Ansible feature on Katello itself
- the "--enable-foreman-proxy-plugin-ansible" option to enable the Ansible feature on the Foreman proxy installed on the same host where Kastello is running
now run the playbook, limiting it to the sat-ci-up3a002 target host:
ansible-playbook -t config --ask-vault-pass --limit sat-ci-up3a002 site.yml
Managing Katello Using Ansible
The organization.yml playbook has been specifically developed to show you how to use the "theforeman.foreman" Ansible galaxy role: this playbook exploits the "organization" module to add to Katello the organizations listed in the "katello_organizations" list contained in the inventory/host_vars/sat-ci-up3a002.yml file.
Let's run it to see it in action:
ansible-playbook --ask-vault-pass --limit sat-ci-up3a002 organization.yml
the output is as follows:
PLAY [all] **************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************
ok: [sat-ci-up3a002]
TASK [include_vars] *****************************************************************************************************************************
ok: [sat-ci-up3a002]
TASK [create organizations] *********************************************************************************************************************
changed: [sat-ci-up3a002 -> localhost] => (item={u'name': u'Carcano', u'description': u'Carcano SA'})
PLAY RECAP **************************************************************************************************************************************
sat-ci-up3a002 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
as you see by the above report, the "create organizations" task has been reported with state changed: this means that at least one Organization has been modified on Katello.
One of the most handy features of Ansible is that you do not have to bother about the outcome of re-running the same task multiple times: every run always produces the same outcome, since modules are idempotent.
Let's see this with our own eyes: run the playbook again - the output this time must be as follows:
PLAY [all] **************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************
ok: [sat-ci-up3a002]
TASK [include_vars] *****************************************************************************************************************************
ok: [sat-ci-up3a002]
TASK [create organizations] *********************************************************************************************************************
ok: [sat-ci-up3a002 -> localhost] => (item={u'name': u'Carcano', u'description': u'Carcano SA'})
PLAY RECAP **************************************************************************************************************************************
sat-ci-up3a002 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
as you see, this time the state of the "create organizations" task is ok, meaning that Ansible has not performed any changes because everything was already set.
Be wary however that Ansible is not "declarative": if you remove an organization from the "katello_organizations" list and run the playbook again, the organization does not get removed - since the state parameter of the module is set to "present", so it only takes care to create the organization that are listed in the variable but does not exist in Katello. If you want to remove an organization, you must create a task that explicitly specify its name and set the state to "absent".
Footnotes
Here it ends this tutorial on installing Katello using Ansible - we also saw how to instantiate modules from the "theforeman.foreman" Ansible galaxy collection. As you see it is very easy to create an Ansible project that installs Katello and reconfigure it if necessary: ... but what about Foreman proxies (Capsules, in Satellite terms)?
The site playbook has been designed so to let you easily provision capsules too, ... but this will be the topic of the next post. Stay tuned!
john says:
Well, thanks, it really helped. I love this kind of posts and probably there are a lot like me (not too many tho’) so please do not stop if you ever think that no one is using them. 🙂 Cheers from RO.
Marco Antonio Carcano says:
You are welcome Jon, I’m pleased to see that they are helping people. Thank you for the feedback
Tom McManus says:
Very thorough and helpful, thank you!
Marco Antonio Carcano says:
Thank you for your feedback, Tom.