ONLY FOR SELF STUDY, NO COMMERCIAL USAGE!!!
Contents
- ***ONLY FOR SELF STUDY, NO COMMERCIAL USAGE!!!***
- Chapter 7. Simplifying Playbooks with Roles and Ansible Content Collections
- Describing Role Structure
- Creating Roles
- Deploying Roles from External Content Sources
- Getting Roles and Modules from Content Collections
- Ansible Content Collections
- Namespaces for Ansible Content Collections
- Selecting Sources of Ansible Content Collections
- Installing Ansible Content Collections
- Installing Ansible Content Collections with a Requirements File
- Configuring Ansible Content Collection Sources
- Using Resources from Ansible Content Collections
- References
- Example
- Reusing Content with System Roles
- Chapter 7 Example
Chapter 7. Simplifying Playbooks with Roles and Ansible Content Collections
Describing Role Structure
Ansible roles make it easier to reuse Ansible code generically. You can package all the tasks, variables, files, templates, and other resources needed to provision infrastructure or deploy applications in a standardized directory structure. Copy a role from project to project by copying the directory, then call the role within a play.
Ansible roles have the following benefits:
- Roles group content together, enabling easy sharing of code with others.
- Roles can define the essential elements of a system type, such as a web server, database server, or Git repository.
- Roles make larger projects more manageable.
- Roles can be developed in parallel by different users.
In addition to writing, using, reusing, and sharing your own roles, you can obtain roles from other sources. You can find roles by using distribution packages, such as Ansible Content Collections. Or, you can download roles from the Red Hat automation hub, a private automation hub, and from the community’s Ansible Galaxy website.
Red Hat Enterprise Linux includes some roles in the rhel-system-roles
package. You learn more about rhel-system-roles
later in this chapter.
Examining the Ansible Role Structure
An Ansible role is defined by a standardized structure of subdirectories and files.
The top-level directory defines the name of the role itself. Files are organized into subdirectories that are named according to each file’s purpose in the role, such as tasks
and handlers
.
The files
and templates
subdirectories contain files referenced by tasks in other playbooks and task files.
The following tree
command displays the directory structure of the user.example
role.
[user@host roles]$ tree user.example
user.example/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
Table 7.1. Ansible Role Subdirectories
Subdirectory | Function |
---|---|
defaults | The main.yml file in this directory contains the default values of role variables that can be overwritten when the role is used. These variables have low precedence and are intended to be changed and customized in plays. |
files | This directory contains static files that are referenced by role tasks. |
handlers | The main.yml file in this directory contains the role’s handler definitions. |
meta | The main.yml file in this directory contains information about the role, including author, license, platforms, and optional role dependencies. |
tasks | The main.yml file in this directory contains the role’s task definitions. |
templates | This directory contains Jinja2 templates that are referenced by role tasks. |
tests | This directory can contain an inventory and test.yml playbook that can be used to test the role. |
vars | The main.yml file in this directory defines the role’s variable values. Often these variables are used for internal purposes within the role. These variables have high precedence and are not intended to be changed when used in a playbook. |
Not every role has all of these directories.
Defining Variables and Defaults
Role variables are defined by creating a vars/main.yml
file with key-value pairs in the role directory hierarchy. These variables are referenced in role task files like any other variable: {{
VAR_NAME }}
. These variables have a high precedence and can not be overridden by inventory variables. These variables are used by the internal functioning of the role.
Default variables enable you to set default values for variables that can be used in a play to configure the role or customize its behavior. These variables are defined by creating a defaults/main.yml
file with key-value pairs in the role directory hierarchy. Default variables have the lowest precedence of any available variables.
Default variable values can be overridden by any other variable, including inventory variables. These variables are intended to provide the person writing a play that uses the role with a way to customize or control exactly what it is going to do. You can use default variables to provide information to the role that it needs to configure or deploy something properly.
Define a specific variable in either vars/main.yml
or defaults/main.yml
, but not in both places. Use default variables when you intend that the variable values might be overridden.
Using Ansible Roles in a Play
There are several ways to call roles in a play. The two primary methods are:
- You can include or import them like a task in your
tasks
list. - You can create a
roles
list that runs specific roles before your play’s tasks.
The first method is the most flexible, but the second method is also commonly used and was invented before the first method.
Including and Importing Roles as Tasks
Import Roles
Roles can be added to a play by using an ordinary task. Use the ansible.builtin.import_role
module to statically import a role, and the ansible.builtin.include_role
module to dynamically include a role.
The following play demonstrates how you can import a role by using a task with the ansible.builtin.import_role
module. The example play runs the task A normal task
first, then imports the role2
role.
- name: Run a role as a task
hosts: remote.example.com
tasks:
- name: A normal task
ansible.builtin.debug:
msg: 'first task'
- name: A task to import role2 here
ansible.builtin.import_role:
name: role2
With the ansible.builtin.import_role
module, Ansible treats the role as a static import and parses it during initial playbook processing.
In the preceding example, when the playbook is parsed:
- If
roles/role2/tasks/main.yml
exists, Ansible adds the tasks in that file to the play. - If
roles/role2/handlers/main.yml
exists, Ansible adds the handlers in that file to the play. - If
roles/role2/defaults/main.yml
exists, Ansible adds the default variables in that file to the play. - If
roles/role2/vars/main.yml
exists, Ansible adds the variables in that file to the play (possibly overriding values from role default variables due to precedence).
Important
Because ansible.builtin.import_role
is processed when the playbook is parsed, the role’s handlers, default variables, and role variables are all exposed to all the tasks and roles in the play, and can be accessed by tasks and roles that precede it in the play (even though the role has not run yet).
You can also set variables for the role when you call the task, in the same way that you can set task variables:
- name: Run a role as a task
hosts: remote.example.com
tasks:
- name: A task to include role2 here
ansible.builtin.import_role:
name: role2
vars:
var1: val1
var2: val2
Include Roles
Including roles: dynamic reuse
The ansible.builtin.include_role
module works in a similar way, but it dynamically includes the role when the playbook is running instead of statically importing it when the playbook is initially parsed.
---
- hosts: webservers
tasks:
- name: Print a message
ansible.builtin.debug:
msg: "this task runs before the example role"
- name: Include the example role
include_role:
name: example
- name: Print a message
ansible.builtin.debug:
msg: "this task runs after the example role"
One key difference between the two modules is how they handle task-level keywords, conditionals, and loops:
ansible.builtin.import_role
applies the task’s conditionals and loops to each of the tasks being imported.ansible.builtin.include_role
applies the task’s conditionals and loops to the statement that determines whether the role is included or not.
In addition, when you include a role, its role variables and default variables are not exposed to the rest of the play, unlike ansible.builtin.import_role
.
---
- hosts: webservers
tasks:
- name: Include the some_role role
include_role:
name: some_role
when: "ansible_facts['os_family'] == 'RedHat'"
Using a Roles Section in a Play
Another way you can call roles in a play is to list them in a roles
section. The roles
section is very similar to the tasks
section, except instead of consisting of a list of tasks, it consists of a list of roles.
In the following example play, the role1
role runs, then the role2
role runs.
---
- name: A play that only has roles
hosts: remote.example.com
roles:
- role: role1
- role: role2
For each role specified, the role’s tasks, handlers, variables, and dependencies are imported into the play in the order in which they are listed.
When you use a roles
section to import roles into a play, the roles run first, before any tasks that you define for that play. Whether the roles
section is listed before or after the tasks
section in the play does not matter.
---
- name: Roles run before tasks
hosts: remote.example.com
tasks:
- name: A task
ansible.builtin.debug:
msg: "This task runs after the role."
roles:
- role: role1
Because roles run first, it generally makes sense to list the roles
section before the tasks
section, if you must have both. The preceding play can be rewritten as follows without changing how it runs:
---
- name: Roles run before tasks
hosts: remote.example.com
roles:
- role: role1
tasks:
- name: A task.
ansible.builtin.debug:
msg: "This task runs after the role."
Important
A tasks
section in a play is not required. In fact, it is generally a good practice to avoid both roles
and tasks
sections in a play to avoid confusion about the order in which roles and tasks run.
If you must have a tasks
section and roles, it is better to create tasks that use ansible.builtin.import_role
and ansible.builtin.include_role
to run at the correct points in the play’s execution.
The following example sets values for two role variables of role2
, var1
and var2
. Any defaults
and vars
variables are overridden when role2
is used.
---
- name: A play that runs the second role with variables
hosts: remote.example.com
roles:
- role: role1
- role: role2
var1: val1
var2: val2
Another equivalent playbook syntax that you might see in this case is:
---
- name: A play that runs the second role with variables
hosts: remote.example.com
roles:
- role: role1
- { role: role2, var1: val1, var2: val2 }
There are situations in which this can be harder to read, even though it is more compact.
Important
Ansible looks for duplicate role lines in the roles
section. If two roles are listed with exactly the same parameters, the role only runs once.
For example, the following roles
section only runs role1
one time:
roles:
- { role: role1, service: "httpd" }
- { role: role2, var1: true }
- { role: role1, service: "httpd" }
To run the same role a second time, it must have different parameters defined:
roles:
- { role: role1, service: "httpd" }
- { role: role2, var1: true }
- { role: role1, service: "postfix" }
Special Tasks Sections
There are two special task sections, pre_tasks
and post_tasks
, that are occasionally used with roles
sections. The pre_tasks
section is a list of tasks, similar to tasks
, but these tasks run before any of the roles in the roles
section. If any task in the pre-tasks
section notify a handler, then those handler tasks run before the roles or normal tasks.
Plays also support a post_tasks
keyword. These tasks run after the play’s tasks
and any handlers notified by the play’s tasks
.
The following play shows an example with pre_tasks
, roles
, tasks
, post_tasks
and handlers
. It is unusual that a play would contain all of these sections.
- name: Play to illustrate order of execution
hosts: remote.example.com
pre_tasks:
- name: This task runs first
ansible.builtin.debug:
msg: This task is in pre_tasks
notify: my handler
changed_when: true
roles:
- role: role1
tasks:
- name: This task runs after the roles
ansible.builtin.debug:
msg: This task is in tasks
notify: my handler
changed_when: true
post_tasks:
- name: This task runs last
ansible.builtin.debug:
msg: This task is in post_tasks
notify: my handler
changed_when: true
handlers:
- name: my handler
ansible.builtin.debug:
msg: Running my handler
In the preceding example, an ansible.builtin.debug
task runs in each tasks
section and in the role in the roles
section. Each of those tasks notifies the my handler
handler, which means the my handler
task runs three times:
- After all the
pre_tasks
tasks run - After all the
roles
tasks andtasks
tasks run - After all the
post_tasks
run
Note
In general, if you think you need pre_tasks
and post_tasks
sections in your play because you are using roles
, consider importing the roles as tasks and including only a tasks
section. Alternatively, it might be simpler to have multiple plays in your playbook.
References
Creating Roles
The Role Creation Process
Creating roles in Ansible does not require any special development tools.
Creating and using a role is a three-step process:
- Create the role directory structure.
- Define the role content.
- Use the role in a playbook.
Creating the Role Directory Structure
Ansible looks for roles in a subdirectory called roles
in the directory containing your Ansible Playbook. Each role has its own directory with a standardized directory structure. This structure allows you to store roles with the playbook and other supporting files.
For example, the following directory structure contains the files that define the motd
role.
[user@host ~]$ tree roles/
roles/
└── motd
├── defaults
│ └── main.yml
├── files
├── handlers
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
└── templates
└── motd.j2
The README.md
provides a basic human-readable description of the role, documentation, examples of how to use it, and any non-Ansible role requirements. The meta
subdirectory contains a main.yml
file that specifies information about the author, license, compatibility, and dependencies for the module.
The files
subdirectory contains fixed content files and the templates
subdirectory contains templates that the role can deploy.
The other subdirectories can contain main.yml
files that define default variable values, handlers, tasks, role metadata, or variables, depending on their subdirectory.
If a subdirectory exists but is empty, such as handlers
in this example, it is ignored. You can omit the subdirectory altogether if the role does not use a feature. This example omits the vars
subdirectory.
Run ansible-galaxy role init
to create the directory structure for a new role.
Specify the role’s name as an argument to the command, which creates a subdirectory for the new role in the current working directory.
[user@host playbook-project]$ cd roles
[user@host roles]$ ansible-galaxy role init my_new_role
- Role my_new_role was created successfully
[user@host roles]$ ls my_new_role/
defaults files handlers meta README.md tasks templates tests vars
Defining the Role Content
After creating the directory structure, you must write the content of the role. A good place to start is the *
ROLENAME*/tasks/main.yml
task file, the main list of tasks that the role runs.
The following tasks/main.yml
file manages the /etc/motd
file on managed hosts. It uses the template
module to deploy the template named motd.j2
to the managed host. Because the template
module is configured within a role task, instead of a playbook task, the motd.j2
template is retrieved from the role’s templates
subdirectory.
[user@host ~]$ cat roles/motd/tasks/main.yml
---
# tasks file for motd
- name: deliver motd file
ansible.builtin.template:
src: motd.j2
dest: /etc/motd
owner: root
group: root
mode: 0444
The following command displays the contents of the motd.j2
template of the motd
role. It references Ansible facts and a system_owner
variable.
[user@host ~]$ cat roles/motd/templates/motd.j2
This is the system {{ ansible_facts['hostname'] }}.
Today's date is: {{ ansible_facts['date_time']['date'] }}.
Only use this system with permission.
You can ask {{ system_owner }} for access.
The role defines a default value for the system_owner
variable. The defaults/main.yml
file in the role’s directory structure is where this value is set.
The following defaults/main.yml
file sets the system_owner
variable to [email protected]
. This email address is written in the /etc/motd
file of managed hosts when this role is applied.
[user@host ~]$ cat roles/motd/defaults/main.yml
---
system_owner: [email protected]
Recommended Practices for Role Content Development
Roles allow you to break down playbooks into multiple files, resulting in reusable code. To maximize the effectiveness of newly developed roles, consider implementing the following recommended practices into your role development:
- Maintain each role in its own version control repository. Ansible works well with Git-based repositories.
- Use variables to configure roles so that you can reuse the role to perform similar tasks in similar circumstances.
- Avoid storing sensitive information in a role, such as passwords or SSH keys. Configure role variables that are used to contain sensitive values when called in a play with default values that are not sensitive. Playbooks that use the role are responsible for defining sensitive variables through Ansible Vault variable files or other methods.
- Use the
ansible-galaxy role init
command to start your role, and then remove any unnecessary files and directories. - Create and maintain
README.md
andmeta/main.yml
files to document the role’s purpose, author, and usage. - Keep your role focused on a specific purpose or function. Instead of making one role do many things, write more than one role.
- Reuse roles often.
Resist creating new roles for edge configurations. If an existing role accomplishes most of the required configuration, refactor the existing role to integrate the new configuration scenario.
Use integration and regression testing techniques to ensure that the role provides the required new functionality and does not cause problems for existing playbooks.
A longer unofficial list of good practices to follow when you write a role is available from https://redhat-cop.github.io/automation-good-practices/#_roles_good_practices_for_ansible
.
Changing a Role’s Behavior with Variables
A well-written role uses default variables to alter the role’s behavior to match a related configuration scenario. Roles that use variables are more generic and reusable in a variety of contexts.
The value of any variable defined in a role’s defaults
directory is overwritten if that same variable is defined:
- In an inventory file, either as a host variable or a group variable.
- In a YAML file under the
group_vars
orhost_vars
directories of a playbook project. - As a variable nested in the
vars
keyword of a play. - As a variable when including the role in
roles
keyword of a play.
The following example shows how to use the motd
role with a different value for the system_owner
role variable. The value specified, [email protected]
, replaces the variable reference when the role is applied to a managed host.
[user@host ~]$ cat use-motd-role.yml
---
- name: use motd role playbook
hosts: remote.example.com
remote_user: devops
become: true
vars:
system_owner: [email protected]
roles:
- role: motd
When defined in this way, the system_owner
variable replaces the value of the default variable of the same name. Any variable definitions nested within the vars
keyword do NOT replace the value of the same variable if defined in a role’s vars
directory.
The following example also shows how to use the motd
role with a different value for the system_owner
role variable. The value specified, [email protected]
, replaces the variable reference regardless of being defined in the role’s vars
or defaults
directory.
[user@host ~]$ cat use-motd-role.yml
---
- name: use motd role playbook
hosts: remote.example.com
remote_user: devops
become: true
roles:
- role: motd
system_owner: [email protected]
Important NOTE
Variable precedence can be confusing when working with role variables in a play.
- Most other variables override a role’s default variables: inventory variables, play
vars
, inline role parameters, and so on. - Fewer variables can override variables defined in a role’s
vars
directory. Facts, variables loaded withinclude_vars
, registered variables, and role parameters can override these variables. Inventory variables and playvars
cannot. This behavior is important because it helps keep your play from accidentally changing the internal functioning of the role. - Variables declared inline as role parameters have very high precedence; they can also override variables defined in a role’s
vars
directory.
If a role parameter has the same name as a variable set in play vars
, a role’s vars
, or an inventory or playbook variable, the role parameter overrides the other variable.
Defining Role Dependencies
Role dependencies allow a role to include other roles as dependencies.
For example, a role that defines a documentation server might depend upon another role that installs and configures a web server.
Dependencies are defined in the meta/main.yml
file in the role directory hierarchy.
The following is a sample meta/main.yml
file.
---
dependencies:
- role: apache
port: 8080
- role: postgres
dbname: serverlist
admin_user: felix
A meta/main.yml
file might also have a top-level galaxy_info
key that has a dictionary of other attributes that specify the author, purpose, license, and the versions of Ansible Core and operating systems that the role supports.
By default, if multiple roles have a dependency on a role, and that role is called by different roles in the play multiple times with the same attributes, then the role only runs the first time it appears. This behavior can be overridden by setting the allow_duplicates
variable to yes
in your role’s meta/main.yml
file.
Important:
Limit your role’s dependencies on other roles. Dependencies make it harder to maintain your role, especially if it has many complex dependencies.
References
Using Roles — Ansible Documentation
Using Variables — Ansible Documentation
Roles Good Practices for Ansible
Example
[student@workstation role-create]$ mkdir -v roles; cd roles
mkdir: created directory 'roles'
# create role 'myvhost'
[student@workstation roles]$ ansible-galaxy role init myvhost
- Role myvhost was created successfully
# delete unused 3 folders
[student@workstation roles]$ rm -rvf myvhost/{defaults,vars,tests}
[student@workstation role-create]$ tree
.
├── ansible.cfg
├── inventory
├── roles
│ └── myvhost
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── README.md
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── verify-config.yml
├── verify-content.yml
├── verify-httpd.yml
└── vhost.conf.j2
# file contents
[student@workstation role-create]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops
#Try me...
#callback_whitelist=timer
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[student@workstation role-create]$ cat inventory
workstation
[webservers]
servera.lab.example.com
[student@workstation role-create]$ cat verify-config.yml
---
- name: Verify the httpd config
hosts: servera.lab.example.com
tasks:
- name: Verify the httpd config file is in place
ansible.builtin.command: cat /etc/httpd/conf.d/vhost.conf
register: config
- name: What does the httpd config file contain
ansible.builtin.debug:
msg: '{{ config }}.stdout_lines'
[student@workstation role-create]$ cat verify-content.yml
---
- name: Verify the index.html file
hosts: servera.lab.example.com
tasks:
- name: Verify the index.html file is in place
ansible.builtin.command: cat /var/www/vhosts/servera/index.html
register: content
- name: What does the index.html config file contain
ansible.builtin.debug:
msg: '{{ content }}.stdout_lines'
[student@workstation role-create]$ cat verify-httpd.yml
---
- name: Verify the httpd service
hosts: servera.lab.example.com
tasks:
- name: Verify the httpd service is installed
ansible.builtin.command: rpm -q httpd
register: installed
- name: Is the httpd service installed
ansible.builtin.debug:
msg: '{{ installed }}.stdout'
- name: Verify the httpd service is started
ansible.builtin.command: systemctl is-active httpd
register: started
- name: Is the httpd service started
ansible.builtin.debug:
msg: '{{ started }}.stdout'
- name: Verify the httpd service is enabled
ansible.builtin.command: systemctl is-enabled httpd
register: enabled
- name: Is the httpd service enabled
ansible.builtin.debug:
msg: '{{ enabled }}.stdout'
[student@workstation role-create]$ cat vhost.conf.j2
# {{ ansible_managed }}
<VirtualHost *:80>
ServerAdmin webmaster@{{ ansible_fqdn }}
ServerName {{ ansible_fqdn }}
ErrorLog logs/{{ ansible_hostname }}-error.log
CustomLog logs/{{ ansible_hostname }}-common.log common
DocumentRoot /var/www/vhosts/{{ ansible_hostname }}/
<Directory /var/www/vhosts/{{ ansible_hostname }}/>
Options +Indexes +FollowSymlinks +Includes
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Edit the main.yml
file in the tasks
subdirectory of the role. The role should perform the following tasks:
- Install the
httpd
package. - Enable and start the
httpd
service. - Install the web server configuration file using a template provided by the role.
[student@workstation role-create]$ cat roles/myvhost/tasks/main.yml
---
# tasks file for myvhost
- name: installing httpd
ansible.builtin.dnf:
name: httpd
state: present
- name: Starting httpd svc
ansible.builtin.service:
name: httpd
state: started
enabled: true
- name: Installing web server config file
ansible.builtin.template:
src: vhost.conf.j2
dest: /etc/httpd/conf.d/vhost.conf
owner: root
group: root
mode: 0644
notify:
- restart httpd
[student@workstation role-create]$ cat roles/myvhost/handlers/main.yml
---
# handlers file for myvhost
- name: restart httpd
ansible.builtin.service:
name: httpd
state: restarted
# copying vhost template
[student@workstation role-create]$ mv -v vhost.conf.j2 roles/myvhost/templates/
renamed 'vhost.conf.j2' -> 'roles/myvhost/templates/vhost.conf.j2'
# Creating html content
[student@workstation role-create]$ mkdir -pv files/html
mkdir: created directory 'files'
mkdir: created directory 'files/html'
[student@workstation role-create]$ echo 'simple index' > files/html/index.html
Creating the use-vhost-role.yml
which we are using the role myvhost
created before:
---
- name: Use myvhost role playbook
hosts: webservers
pre_tasks:
- name: pre_tasks message
ansible.builtin.debug:
msg: 'Ensure web server configuration.'
roles:
- myvhost
post_tasks:
- name: HTML content is installed
ansible.builtin.copy:
src: files/html/
dest: "/var/www/vhosts/{{ ansible_hostname }}"
- name: post_tasks message
ansible.builtin.debug:
msg: 'Web server is configured.'
check the result with:
student@workstation role-create]$ ansible-navigator run -m stdout use-vhost-role.yml --syntax-check
playbook: /home/student/role-create/use-vhost-role.yml
[student@workstation role-create]$ ansible-navigator run -m stdout use-vhost-role.yml
[student@workstation role-create]$ ansible-navigator run -m stdout verify-config.yml
[student@workstation role-create]$ ansible-navigator run -m stdout verify-content.yml
[student@workstation role-create]$ ansible-navigator run -m stdout verify-httpd.yml
[student@workstation role-create]$ curl http://servera.lab.example.com
simple index
Deploying Roles from External Content Sources
External Content Sources
If you are using roles in your Ansible Playbooks, then you should get those roles from some centrally managed source. This practice ensures that all your projects have the current version of the role and that each project can benefit from bug fixes discovered by other projects with which they share the role.
- role that stored in a Git repository managed by your organization.
- a distributed as a
tar
archive file from a website or through other means. - the open source community maintains some roles through the Ansible Galaxy website. Note: These roles are not reviewed or supported officially by Red Hat, but might contain code that your organization finds useful.
It is increasingly common for roles to be packaged as Ansible Content Collections and offered by their authors through various methods:
- In Red Hat Certified Ansible Content Collections from the Red Hat hosted automation hub at
https://console.redhat.com
, or through a private automation hub - As private content packaged from a private automation hub
- By the community from Ansible Galaxy at
https://galaxy.ansible.com
This section only covers how to get roles that are not packaged into an Ansible Content Collections.
Introducing Ansible Galaxy
A public library of Ansible content written by a variety of Ansible administrators and users is available at Ansible Galaxy. This library contains thousands of Ansible roles, and it has a searchable database that helps you identify roles that might help you accomplish an administrative task.
The ansible-galaxy
command that you use to download and manage roles from Ansible Galaxy can also be used to download and manage roles from your own Git repositories.
The Ansible Galaxy Command Line Tool
You can use the ansible-galaxy
command-line tool with the role
argument to search for, display information about, install, list, remove, or initialize roles.
[user@host project]$ ansible-galaxy role -h
usage: ansible-galaxy role [-h] ROLE_ACTION ...
positional arguments:
ROLE_ACTION
init Initialize new role with the base structure of a role.
remove Delete roles from roles_path.
delete Removes the role from Galaxy. It does not remove or alter the actual GitHub repository.
list Show the name and version of each role installed in the roles_path.
search Search the Galaxy database by tags, platforms, author and multiple keywords.
import Import a role into a galaxy server
setup Manage the integration between Galaxy and the given source.
info View more details about a specific role.
install Install role(s) from file(s), URL(s) or Ansible Galaxy
optional arguments:
-h, --help show this help message and exit
Installing Roles Using a Requirements File
If you have a playbook that must have specific roles installed, then you can create a roles/requirements.yml
file in the project directory that specifies which roles are needed. This file acts as a dependency manifest for the playbook project that enables playbooks to be developed and tested separately from any supporting roles.
Then, before you run ansible-navigator run
, you can use the ansible-galaxy role
command to install those roles in your project’s roles
directory.
Note:
If you use automation controller, it automatically downloads roles specified in your roles/requirements.yml
file when it runs your playbook.
For example, you could have a role in a public repository on a Git server at https://git.example.com/someuser/someuser.myrole
. A simple requirements.yml
to install someuser.myrole
might contain the following content:
- src: https://git.example.com/someuser/someuser.myrole
scm: git
version: "1.5.0"
The src
attribute specifies the source of the role, in this case the URL for the repository of the role on your Git server. You can also use SSH key-based authentication by specifying something like [email protected]:someuser/someuser.myrole
as provided by your Git repository.
The scm
attribute indicates that this role is from a Git repository.
The version
attribute is optional, and specifies the version of the role to install, in this case 1.5.0
. In the case of a role stored in Git, the version can be the name of a branch, a tag, or a Git commit hash. If you do not specify a version, the command uses the latest commit on the default branch.
Important:
Specify the version of the role in your requirements.yml
file, especially for playbooks in production.
If you do not specify a version, you get the latest version of the role.
If the upstream author makes changes to the role that are incompatible with your playbook, it might cause an automation failure or other problems.
To install roles using a role requirements file, run the ansible-galaxy role install
command from within your project directory. Include the following options:
-r roles/requirements.yml
to specify the location of your requirements file-p roles
to install the role into a subdirectory of theroles
directory
[user@host project]$ ansible-galaxy role install -r roles/requirements.yml \
> -p roles
Starting galaxy role install process
- downloading role from https://git.example.com/someuser/someuser.myrole
- extracting myrole to /home/user/project/roles/someuser.myrole
- someuser.myrole (1.5.0) was installed successfully
Important:
If you do not specify the -p roles
option, then ansible-galaxy role install
uses the first directory in the default roles_path
setting to determine where to install the role. This defaults to the user’s ~/.ansible/roles
directory, which is outside the project directory and unavailable to the execution environment if you use ansible-navigator
to run your playbooks.
One way to avoid the need to specify -p roles
is to apply the following setting in the defaults
section of your project’s ansible.cfg
file:
roles_path = roles
If you have a tar
archive file that contains a role, you can use roles/requirements.yml
to install that file from a URL:
# from a role tar ball, given a URL;
# supports 'http', 'https', or 'file' protocols
- src: file:///opt/local/roles/tarrole.tar
name: tarrole
- src: https://www.example.com/role-archive/someuser.otherrole.tar
name: someuser.otherrole
Note:
Red Hat recommends that you use version control with roles, storing them in a version control system such as Git. If a recent change to a role causes problems, using version control allows you to roll back to a previous, stable version of the role.
Finding Community-managed Roles in Ansible Galaxy
The open source Ansible community operates a public server, https://galaxy.ansible.com
, that contains roles and Ansible Content Collections shared by other Ansible users.
Browsing Ansible Galaxy for Roles
The Search tab on the left side of the Ansible Galaxy website home page gives you access to information about the roles published on Ansible Galaxy. You can search for an Ansible role by name or by using tags or other role attributes.
Results are presented in descending order of the Best Match
score, which is a computed score based on role quality, role popularity, and search criteria. (Content Scoring in the Ansible Galaxy documentation has more information on how roles are scored by Ansible Galaxy.)
Figure 7.1: Ansible Galaxy search screen
Ansible Galaxy reports the number of times each role has been downloaded from Ansible Galaxy. In addition, Ansible Galaxy also reports the number of watchers, forks, and stars the role’s GitHub repository has. You can use this information to help determine how active development is for a role and how popular it is in the community.
The following figure shows the search results that Ansible Galaxy displayed after a keyword search for redis
was performed.
Figure 7.2: Ansible Galaxy search results example
The Filters menu to the right of the search box allows searches by type, contributor type, contributor, cloud platform, deprecated, platform, and tags.
Possible platform values include EL
for Red Hat Enterprise Linux (and closely related distributions such as CentOS) and Fedora
, among others.
Tags are arbitrary single-word strings set by the role author that describe and categorize the role. You can use tags to find relevant roles. Possible tag values include system
, development
, web
, monitoring
, and others. In Ansible Galaxy, a role can have up to 20 tags.
Important:
In the Ansible Galaxy search interface, keyword searches match words or phrases in the README
file, content name, or content description. Tag searches, by contrast, specifically match tag values that the author set for the role.
Searching for Roles from the Command Line
The ansible-galaxy role search
command searches Ansible Galaxy for roles.
If you specify a string as an argument, it is used to search Ansible Galaxy for roles by keyword. You can use the --author
, --platforms
, and --galaxy-tags
options to narrow the search results. You can also use those options as the main search key.
For example, the command ansible-galaxy role search --author geerlingguy
displays all roles submitted by the user geerlingguy
. Results are displayed in alphabetical order, not by descending Best Match
score.
The following example displays the names of roles that include redis
, and are available for the Enterprise Linux (EL
) platform.
[user@host ~]$ ansible-galaxy role search 'redis' --platforms EL
Found 232 roles matching your search:
Name Description
---- -----------
...output omitted...
aboveops.ct_redis Ansible role for creating Redis container
adfinis-sygroup.redis Ansible role for Redis
adriano-di-giovanni.redis Ansible role for Redis
AerisCloud.redis Installs redis on a server
alainvanhoof.alpine_redis Redis for Alpine Linux
...output omitted...
The ansible-galaxy role info
command displays more detailed information about a role. Ansible Galaxy gets this information from a number of places, including the role’s meta/main.yml
file and its GitHub repository.
The following command displays information about the geerlingguy.redis
role, available from Ansible Galaxy.
[user@host ~]$ ansible-galaxy role info geerlingguy.redis
Role: geerlingguy.redis
description: Redis for Linux
...output omitted...
created: 2023-05-08T20:50:00.204075Z
download_count: 1306420
github_branch: master
github_repo: ansible-role-redis
github_user: geerlingguy
id: 10990
imported: 2022-09-26T12:10:34.707632-04:00
modified: 2023-10-29T18:44:43.771821Z
path: ('/home/student/.ansible/roles', '/usr/share/ansible/roles', '/etc/ansible/roles')
upstream_id: 468
username: geerlingguy
Downloading Roles from Ansible Galaxy
The following example shows how to configure a requirements file that uses a variety of remote sources.
[user@host project]$ cat roles/requirements.yml
# from Ansible Galaxy, using the latest version
- src: geerlingguy.redis
# from Ansible Galaxy, overriding the name and using a specific version
- src: geerlingguy.redis
version: "1.5.0"
name: redis_prod
# from any Git based repository, using HTTPS
- src: https://github.com/geerlingguy/ansible-role-nginx.git
scm: git
version: master
name: nginx
# from a role tar ball, given a URL;
# supports 'http', 'https', or 'file' protocols
- src: file:///opt/local/roles/myrole.tar
name: myrole
Explanation:
# The `version` keyword is used to specify a role's version. The `version` keyword can be any value that corresponds to a branch, tag, or commit hash from the role's software repository.
# If the role is hosted in a source control repository, the `scm` attribute is required.
# If the role is hosted on Ansible Galaxy or as a tar archive, the `scm` keyword is omitted.
# The `name` keyword is used to override the local name of the role.
Managing Downloaded Roles
The ansible-galaxy role
command can also manage local roles, such as those roles found in the roles
directory of a playbook project. The ansible-galaxy role list
command lists the local roles.
[user@host project]$ ansible-galaxy role list
# /home/user/project/roles
- geerlingguy.redis, 1.7.0
- redis_prod, 1.5.0
- nginx, master
- myrole, (unknown version)
...output omitted...
You can remove a role with the ansible-galaxy role remove
command.
[user@host ~]$ ansible-galaxy role remove nginx
- successfully removed nginx
References
ansible-galaxy — Ansible Documentation
Red Hat Hybrid Cloud Console | Ansible Automation Platform Dashboard
Example
Create a role requirements file in your project directory that downloads the student.bash_env
role. This role configures the default initialization files for the Bash shell used for newly created users, the default prompt for the accounts of these users, and the prompt color to use.
[student@workstation ~]$ cd role-galaxy/
[student@workstation role-galaxy]$ ll
total 68
-rw-r--r--. 1 student student 144 Sep 6 10:14 ansible.cfg
-rw-r--r--. 1 student student 61440 Sep 6 10:14 bash_env.tar
-rw-r--r--. 1 student student 67 Sep 6 10:14 inventory
drwxr-xr-x. 2 student student 6 Sep 6 10:15 roles
[student@workstation role-galaxy]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops
[privilege_escalation]
become=true
become_method=sudo
become_user=root
become_ask_pass=false
[student@workstation role-galaxy]$ cat inventory
workstation.lab.example.com
[devservers]
servera.lab.example.com
[student@workstation role-galaxy]$ ll roles/
total 0
[student@workstation role-galaxy]$ cd roles/
[student@workstation roles]$ ll
total 0
Create a file called requirements.yml
in the roles
subdirectory. The URL of the role’s Git repository is: [email protected]:student/bash_env
.
To see how the role affects the behavior of production hosts, use the main
branch of the repository. Set the local name of the role to student.bash_env
.
the roles/requirements.yml
file contains the following content:
---
# requirements.yml
- src: [email protected]:student/bash_env
scm: git
version: main
name: student.bash_env
[student@workstation role-galaxy]$ tree
.
├── ansible.cfg
├── bash_env.tar
├── inventory
└── roles
└── requirements.yml
1 directory, 4 files
installing the role
[student@workstation role-galaxy]$ ansible-galaxy role install -r roles/requirements.yml -p roles/
Starting galaxy role install process
- extracting student.bash_env to /home/student/role-galaxy/roles/student.bash_env
- student.bash_env (main) was installed successfully
[student@workstation role-galaxy]$ tree
.
├── ansible.cfg
├── bash_env.tar
├── inventory
└── roles
├── requirements.yml
└── student.bash_env
├── defaults
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
│ ├── _bash_profile.j2
│ ├── _bashrc.j2
│ └── _vimrc.j2
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 14 files
# look the roles folder
[student@workstation role-galaxy]$ ansible-galaxy role list
# /usr/share/ansible/roles
- linux-system-roles.certificate, (unknown version)
- linux-system-roles.cockpit, (unknown version)
- linux-system-roles.crypto_policies, (unknown version)
- linux-system-roles.firewall, (unknown version)
- linux-system-roles.ha_cluster, (unknown version)
...omited...
# /etc/ansible/roles
[WARNING]: - the configured path /home/student/.ansible/roles does not exist.
# use -p specific the roles folder, here we see the roles we created
[student@workstation role-galaxy]$ ansible-galaxy role list -p roles/
# /home/student/role-galaxy/roles
- student.bash_env, main
# /usr/share/ansible/roles
- linux-system-roles.certificate, (unknown version)
- linux-system-roles.cockpit, (unknown version)
Test1:
Create a playbook named use-bash_env-role.yml
that uses the student.bash_env
role. The playbook must have the following contents:
---
- name: Use student.bash_env role playbook
hosts: devservers
vars:
default_prompt: '[\u on \h in \W dir]\$ '
pre_tasks:
- name: Ensure test user does not exist
ansible.builtin.user:
name: student2
state: absent
force: true
remove: true
roles:
- student.bash_env
post_tasks:
- name: Create the test user
ansible.builtin.user:
name: student2
state: present
password: "{{ 'redhat' | password_hash }}"
You must create a user account to see the effects of the configuration change. The pre_tasks
and post_tasks
section of the playbook ensure that the student2
user account is deleted and created each time the playbook is run.
When you run the use-bash_env-role.yml
playbook, the student2
account is created with a password of redhat
.
Note:
The student2
password is generated using a filter. Filters take data and modify it; here, the redhat
string is modified by passing it to the password_hash
filter to convert the value into a protected password hash. By defaul, the hashing algorithm used is sha512
.
Run the use-bash_env-role.yml
playbook.
[student@workstation role-galaxy]$ ansible-navigator run -m stdout use-bash_env-role.yml
PLAY [use student.bash_env role in this playbook] ******************************
TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]
TASK [Ensure test user does not exist] *****************************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .bashrc] *************************************
changed: [servera.lab.example.com]
TASK [student.bash_env : put away .bash_profile] *******************************
ok: [servera.lab.example.com]
TASK [student.bash_env : put away .vimrc] **************************************
ok: [servera.lab.example.com]
TASK [create the test user] ****************************************************
[WARNING]: The input password appears not to have been hashed. The 'password'
argument must be encrypted for this module to work properly.
changed: [servera.lab.example.com]
PLAY RECAP *********************************************************************
servera.lab.example.com : ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[student@workstation role-galaxy]$ ssh student2@servera
Register this system with Red Hat Insights: insights-client --register
Create an account or view all your systems at https://red.ht/insights-dashboard
Test2:
Run the playbook using the development version of the student.bash_env
role.
The development version of the role is located in the dev
branch of the Git repository. The development version of the role uses a new variable, prompt_color
.
Before running the playbook, add the prompt_color
variable to the vars
section of the playbook and set its value to blue
.
-
Update the
roles/requirements.yml
file, and set theversion
value todev
. Ensure that theroles/requirements.yml
file contains the following content:--- # requirements.yml - src: [email protected]:student/bash_env scm: git version: dev name: student.bash_env
-
Modify the
~/role-galaxy/ansible.cfg
and add theroles_path
setting to the[defaults]
section of the file. This sets the default roles path and enable you to omit the-p roles
option when typingansible-galaxy
commands.When completed, the file contains then following content:
[defaults] inventory=inventory remote_user=devops roles_path=roles [privilege_escalation] become=true become_method=sudo become_user=root become_ask_pass=false
-
Remove the existing version of the
student.bash_env
role from theroles
subdirectory.[student@workstation role-galaxy]$ ansible-galaxy role remove student.bash_env - successfully removed student.bash_env
-
Use the
ansible-galaxy role install
command to install the role by using the updated requirements file.[student@workstation role-galaxy]$ ansible-galaxy role install \ > -r roles/requirements.yml Starting galaxy role install process - extracting student.bash_env to /home/student/role-galaxy/roles/student.bash_env - student.bash_env (dev) was installed successfully
-
Modify the
use-bash_env-role.yml
file. Add theprompt_color
variable with a value ofblue
to thevars
section of the playbook. Ensure that the file contains the following content:--- - name: Use student.bash_env role playbook hosts: devservers vars: prompt_color: blue default_prompt: '[\u on \h in \W dir]\$ ' pre_tasks: ...output omitted...
-
Run the
use-bash_env-role.yml
playbook again and see students2 became blue prompt.
Getting Roles and Modules from Content Collections
Ansible Content Collections
With Ansible Content Collections, Ansible code updates are separated from updates to modules and plug-ins. An Ansible Content Collection provides a set of related modules, roles, and other plug-ins that you can use in your playbooks. This approach enables vendors and developers to maintain and distribute their collections at their own pace, independently of Ansible releases.
For example:
- The
redhat.insights
content collection provides modules and roles that you can use to register a system with Red Hat Insights for Red Hat Enterprise Linux. - The
cisco.ios
content collection, supported and maintained by Cisco, provides modules and plug-ins that manage Cisco IOS network appliances.
You can also select a specific version of a collection (possibly an earlier or later one) or choose between a version of a collection supported by Red Hat or vendors, or one provided by the community.
Ansible 2.9 and later support Ansible Content Collections. Upstream Ansible unbundled most modules from the core Ansible code in Ansible Base 2.10 and Ansible Core 2.11 and placed them in collections. Red Hat Ansible Automation Platform 2.2 provides automation execution environments based on Ansible Core 2.13 that inherit this feature.
You can develop your own collections to provide custom roles and modules to your teams. course: Developing Advanced Automation with Red Hat Ansible Automation Platform (DO374).
Namespaces for Ansible Content Collections
The namespace is the first part of a collection name. For example, all the collections that the Ansible community maintains are in the community
namespace, and have names like community.crypto
, community.postgresql
, and community.rabbitmq
.
Selecting Sources of Ansible Content Collections
Regardless of whether you are using ansible-navigator
with the minimal automation execution environment or ansible-playbook
on bare metal Ansible Core, you always have at least one Ansible Content Collection available to you: ansible.builtin
.
In addition, your automation execution environment might have additional automation execution environments built into it, for example, the default execution environment used by Red Hat Ansible Automation Platform 2.2, ee-supported-rhel8
.
If you need to have additional Ansible Content Collections, you can add them to the collections
subdirectory of your Ansible project. You might obtain Ansible Content Collections from several sources:
-
Automation Hub
Automation hub is a service provided by Red Hat to distribute Red Hat Certified Ansible Content Collections that are supported by Red Hat and ecosystem partners. You need a valid Red Hat Ansible Automation Platform subscription to access automation hub. Use the automation hub web UI at https://console.redhat.com/ansible/automation-hub/ to browse these collections.
-
Private Automation Hub
Your organization might have its own on-site private automation hub, and might also use that hub to distribute its own Ansible Content Collections. Private automation hub is included with Red Hat Ansible Automation Platform.
-
Ansible Galaxy
Ansible Galaxy is a community-supported website that hosts Ansible Content Collections that have been submitted by a variety of Ansible developers and users. Ansible Galaxy is a public library that provides no formal support guarantees and that is not curated by Red Hat. For example, the
community.crypto
,community.postgresql
, andcommunity.rabbitmq
collections are all available from that platform.Use the Ansible Galaxy web UI at https://galaxy.ansible.com/ to search it for collections. -
Third-Party Git Repository or Archive File
You can also download Ansible Content Collections from a Git repository or a local or remote
tar
archive file, much like you can download roles.
Installing Ansible Content Collections
The Ansible configuration collections_paths
setting specifies a colon separated list of paths on the system where Ansible looks for installed collections.
You can set this directive in the ansible.cfg
configuration file.
The following default value references the collections_paths
directive.
~/.ansible/collections:/usr/share/ansible/collections
The following example uses the ansible-galaxy collection install
command to download and install the community.crypto
Ansible Content Collection. The -p collections
option installs the collection in the local collections
subdirectory.
[user@controlnode ~]$ ansible-galaxy collection install community.crypto -p collections
Important:
You must specify the -p collections
option or ansible-galaxy
installs the collection based on your current collections_paths
setting, or into your ~/.ansible/collections/
directory on the control node by default. The ansible-navigator
command does not load this directory into the automation execution environment, although this directory is available to Ansible commands that use the control node as the execution environment, such as ansible-playbook
.
When you install the community.crypto
collection, you could see a warning that your Ansible project’s playbooks might not find the collection because the specified path is not part of the configured Ansible collections path.
You can safely ingore this warning because your Ansible project checks the local collections
subdirectory before checking directories specified by the collections_paths
setting and can use the collections stored there.
The command can also install a collection from a local or a remote tar
archive, or a Git repository. A Git repository must have a valid galaxy.yml
or MANIFEST.json
file that provides metadata about the collection, such as its namespace and version number.
For example, see the community.general
collection at https://github.com/ansible-collections/community.general
.
[user@controlnode ~]$ ansible-galaxy collection install \
> /tmp/community-dns-1.2.0.tar.gz -p collections
...output omitted...
[user@controlnode ~]$ ansible-galaxy collection install \
> http://www.example.com/redhat-insights-1.0.5.tar.gz -p collections
...output omitted...
[user@controlnode ~]$ ansible-galaxy collection install \
> [email protected]:organization/repo_name.git -p collections
Installing Ansible Content Collections with a Requirements File
If your Ansible project needs additional Ansible Content Collections, you can create a collections/requirements.yml
file in the project directory that lists all the collections that the project requires. Automation controller detects this file and automatically installs the specified collections before running your playbooks.
A requirements file for Ansible Content Collections is a YAML file that consists of a collections
dictionary key that has the list of collections to install as its value. Each list item can also specify the particular version of the collection to install, as shown in the following example:
---
collections:
- name: community.crypto
- name: ansible.posix
version: 1.2.0
- name: /tmp/community-dns-1.2.0.tar.gz
- name: http://www.example.com/redhat-insights-1.0.5.tar.gz
- name: git+https://github.com/ansible-collections/community.general.git
version: main
The ansible-galaxy
command can then use the collections/requirements.yml
file to install all those collections. Specify the requirements file with the --requirements-file
(or -r
) option, and use the -p collections
option to install the Ansible Content Collection into the collections
subdirectory.
[root@controlnode ~]# ansible-galaxy collection install \
> -r collections/requirements.yml -p collections
Configuring Ansible Content Collection Sources
By default, the ansible-galaxy
command uses Ansible Galaxy at https://galaxy.ansible.com/ to download Ansible Content Collections. You might not want to use this command, preferring automation hub or your own private automation hub. Alternatively, you might want to try automation hub first, and then try Ansible Galaxy.
You can configure the sources that ansible-galaxy
uses to get Ansible Content Collections in your Ansible project’s ansible.cfg
file. The relevant parts of that file might look like the following example:
...output omitted...
[galaxy]
server_list = automation_hub, galaxy
[galaxy_server.automation_hub]
url=https://console.redhat.com/api/automation-hub/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
token=eyJh...Jf0o
[galaxy_server.galaxy]
url=https://galaxy.ansible.com/
Instead of a token, you can use the username
and password
parameters to provide your customer portal username and password.
...output omitted...
[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/
username=operator1
password=Sup3r53cR3t
...output omitted...
However, you might not want to expose your credentials in the ansible.cfg
file because the file could potentially get committed when using version control.
It is preferable to remove the authentication parameters from the ansible.cfg
file and define them in environment variables, as shown in the following example:
export ANSIBLE_GALAXY_SERVER_<server_id>_<key>=value
-
server_id
Server identifier in uppercase. The server identifier is the name you used in the
server_list
parameter and in the name of the[galaxy_server.*
server_id*]
section. -
key
Name of the parameter in uppercase.
The following example provides the token
parameter as an environment variable:
[user@controlnode ~]$ cat ansible.cfg
...output omitted...
[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
[user@controlnode ~]$ export \
> ANSIBLE_GALAXY_SERVER_AUTOMATION_HUB_TOKEN='eyJh...Jf0o'
[user@controlnode ~]$ ansible-galaxy collection install ansible.posix \
> -p collections
Using Resources from Ansible Content Collections
You can use the ansible-navigator collections
command in your Ansible project directory to list all the collections that are installed in your automation execution environment. This includes the Ansible Content Collections in your project’s collections
subdirectory.
You can select the line number of the collection in the interactive mode of ansible-navigator
to view its contents. Then, you can select the line number of a module, role, or other plug-in to see its documentation. You can also use other tools, such as ansible-navigator doc
, with the FQCN of a module to view that module’s documentation.
The following playbook invokes the mysql_user
module from the community.mysql
collection for a task.
---
- name: Create the operator1 user in the test database
hosts: db.example.com
tasks:
- name: Ensure the operator1 database user is defined
community.mysql.mysql_user:
name: operator1
password: Secret0451
priv: '.:ALL'
state: present
The following playbook uses the organizations
role from the redhat.satellite
collection.
---
- name: Add the test organizations to Red Hat Satellite
hosts: localhost
tasks:
- name: Ensure the organizations exist
include_role:
name: redhat.satellite.organizations
vars:
satellite_server_url: https://sat.example.com
satellite_username: admin
satellite_password: Sup3r53cr3t
satellite_organizations:
- name: test1
label: tst1
state: present
description: Test organization 1
- name: test2
label: tst2
state: present
description: Test organization 2
References
Ansible Automation Platform Certified Content
Using collections — Ansible Documentation
Galaxy User Guide — Ansible Documentation
Example
Install the collection from tar or requirement.yml
[student@workstation role-collections]$ ll
total 3040
-rw-r--r--. 1 student student 146 Sep 9 03:05 ansible.cfg
-rw-r--r--. 1 student student 419 Sep 9 03:05 bck.yml
-rw-r--r--. 1 student student 2235450 Sep 9 03:05 community-general-5.5.0.tar.gz
-rw-r--r--. 1 student student 6234 Sep 9 03:05 gls-utils-0.0.1.tar.gz
-rw-r--r--. 1 student student 199 Sep 9 03:05 inventory
-rw-r--r--. 1 student student 519 Sep 9 03:05 new_system.yml
-rw-r--r--. 1 student student 34218 Sep 9 03:05 redhat-insights-1.0.7.tar.gz
-rw-r--r--. 1 student student 808333 Sep 9 03:05 redhat-rhel_system_roles-1.19.3.tar.gz
-rw-r--r--. 1 student student 239 Sep 9 03:05 requirements.yml
[student@workstation role-collections]$ cat ansible.cfg
[defaults]
inventory=./inventory
remote_user=devops
[privilege_escalation]
become=true
become_method=sudo
become_user=root
become_ask_pass=false
[student@workstation role-collections]$ cat bck.yml
---
- name: Backup the system configuration
hosts: servera.lab.example.com
become: true
gather_facts: false
tasks:
- name: Ensure the machine is up
gls.utils.newping:
data: pong
- name: Ensure configuration files are saved
ansible.builtin.include_role:
name: gls.utils.backup
vars:
backup_id: backup_etc
backup_files:
- /etc/sysconfig
- /etc/yum.repos.d
[student@workstation role-collections]$ cat inventory
[controlnode]
workstation.lab.example.com
[na_datacenter]
servera.lab.example.com
[europe_datacenter]
serverb.lab.example.com
[database_servers]
servera.lab.example.com
serverb.lab.example.com
[student@workstation role-collections]$ cat new_system.yml
---
- name: Configure the system
hosts: servera.lab.example.com
become: true
gather_facts: true
tasks:
- name: Ensure the system is registered with Insights
ansible.builtin.include_role:
name: redhat.insights.insights_client
vars:
auto_config: false
insights_proxy: http://proxy.example.com:8080
- name: Ensure SELinux mode is Enforcing
ansible.builtin.include_role:
name: redhat.rhel_system_roles.selinux
vars:
selinux_state: enforcing
[student@workstation role-collections]$ cat requirements.yml
---
collections:
- name: /home/student/role-collections/redhat-insights-1.0.7.tar.gz
- name: /home/student/role-collections/redhat-rhel_system_roles-1.19.3.tar.gz
- name: /home/student/role-collections/community-general-5.5.0.tar.gz
[student@workstation role-collections]$ ansible-galaxy collection install gls-utils-0.0.1.tar.gz -p collections
# entering TUI to check collections
[student@workstation role-collections]$ ansible-navigator collections
[student@workstation role-collections]$ ansible-navigator run -m stdout bck.yml
[student@workstation role-collections]$ ansible-galaxy collection install -r requirements.yml -p collections
[student@workstation role-collections]$ ansible-galaxy collection list -p collections
# /usr/share/ansible/collections/ansible_collections
Collection Version
------------------------ -------
redhat.rhel_system_roles 1.16.2
# /home/student/role-collections/collections/ansible_collections
Collection Version
------------------------ -------
community.general 5.5.0
gls.utils 0.0.1
redhat.insights 1.0.7
redhat.rhel_system_roles 1.19.3
[student@workstation role-collections]$ ansible-navigator run -m stdout new_system.yml --check
Reusing Content with System Roles
System Roles
System roles are a set of Ansible roles that you can use to configure and manage various components, subsystems, and software packages included with Red Hat Enterprise Linux. System roles provide automation for many common system configuration tasks, including time synchronization, networking, firewall, tuning, and logging.
These roles are intended to provide an automation API that is consistent across multiple major and minor releases of Red Hat Enterprise Linux. The Knowledgebase article at https://access.redhat.com/articles/3050101
documents the versions of Red Hat Enterprise Linux on your managed hosts that specific roles support.
Simplified Configuration Management
System roles can help you simplify automation across multiple versions of Red Hat Enterprise Linux. For example, the recommended time synchronization service is different in different versions of Red Hat Enterprise Linux.
- The
chronyd
service is preferred in RHEL 9. - The
ntpd
service is preferred in RHEL 6.
You can use an Ansible Playbook that runs the redhat.rhel_system_roles.timesync
role to configure time synchronization for managed hosts running either version of Red Hat Enterprise Linux.
Support for System Roles
System roles are provided as the Red Hat Certified Ansible Content Collection redhat.rhel_system_roles
through automation hub for Red Hat Ansible Automation Platform customers, as part of their subscription.
In addition, the roles are provided as an RPM package (rhel-system-roles
) with Red Hat Enterprise Linux 9 for use with the version of Ansible Core provided by that operating system.
Some system roles are in “Technology Preview”. These are tested and are stable, but might be subject to future changes that are incompatible with the current state of the role. Integration testing is recommended for playbooks that incorporate any “Technology Preview” role. Playbooks might require refactoring if role variables change in a future version of the role.
You can access documentation for the system roles in ansible-navigator
, or by reviewing the documentation on the Red Hat Customer Portal at Administration and configuration tasks using System Roles in RHEL .
Installing the System Roles Ansible Content Collection
You can install the redhat.rhel_system_roles
Ansible Content Collection with the ansible-galaxy collection install
command. An Ansible project can specify this dependency by creating a collections/requirements.yml
file. The following example assumes that your project is set up to pull Ansible Content Collections from automation hub.
---
collections:
- name: redhat.rhel_system_roles
The following command installs any required collections for a given project into the project’s collections/
directory.
[user@demo demo-project]$ ansible-galaxy collection \
> install -p collections/ -r collections/requirements.yml
...output omitted...
Upstream development is done through the Linux System Roles project; their development versions of the system roles are provided through Ansible Galaxy as the fedora.linux_system_roles
Ansible Content Collection. These roles are not supported by Red Hat.
Example: Time Synchronization Role
Suppose you need to configure NTP time synchronization on your web servers. You could write automation yourself to perform each of the necessary tasks. But the system roles collection includes a role that can perform the configuration, redhat.rhel_system_roles.timesync
.
The documentation for this role describes all the variables that affect the role’s behavior and provides three playbook snippets that illustrate different time synchronization configurations.
To manually configure NTP servers, the role has a variable named timesync_ntp_servers
. This variable defines a list of NTP servers to use. Each item in the list is made up of one or more attributes. The two key attributes are hostname
and iburst
.
Attribute | Purpose |
---|---|
hostname | The hostname of an NTP server with which to synchronize. |
iburst | A Boolean that enables or disables fast initial synchronization. Defaults to no in the role, but you should normally set this to yes . |
Given this information, the following example is a play that uses the redhat.rhel_system_roles.timesync
role to configure managed hosts to get time from three NTP servers by using fast initial synchronization.
- name: Time Synchronization Play
hosts: webservers
vars:
timesync_ntp_servers:
- hostname: 0.rhel.pool.ntp.org
iburst: yes
- hostname: 1.rhel.pool.ntp.org
iburst: yes
- hostname: 2.rhel.pool.ntp.org
iburst: yes
roles:
- redhat.rhel_system_roles.timesync
This example sets the role variables in a vars
section of the play, but a better practice might be to configure them as inventory variables for hosts or host groups.
Consider an example project with the following structure:
[user@demo demo-project]$ tree
.
├── ansible.cfg
├── group_vars
│ └── webservers
│ └── timesync.yml
├── inventory
└── timesync_playbook.yml
(1) | Defines the time synchronization variables overriding the role defaults for hosts in group webservers in the inventory. This file would look something like:timesync_ntp_servers: - hostname: 0.rhel.pool.ntp.org iburst: yes - hostname: 1.rhel.pool.ntp.org iburst: yes - hostname: 2.rhel.pool.ntp.org iburst: yes |
---|---|
(2) | The content of the playbook simplifies to: |
- name: Time Synchronization Play
hosts: webservers
roles:
- redhat.rhel_system_roles.timesync
This structure cleanly separates the role, the playbook code, and configuration settings. The playbook code is simple, easy to read, and should not require complex refactoring.
This structure also supports a dynamic, heterogeneous environment. Hosts with new time synchronization requirements might be placed in a new host group. Appropriate variables are defined in a YAML file and placed in the appropriate group_vars
(or host_vars
) subdirectory.
Example: SELinux Role
As another example, the redhat.rhel_system_roles.selinux
role simplifies management of SELinux configuration settings. This role is implemented using the SELinux-related Ansible modules. The advantage of using this role instead of writing your own tasks is that it relieves you from the responsibility of writing those tasks. Instead, you provide variables to the role to configure it, and the maintained code in the role ensures your desired SELinux configuration is applied.
This role can perform the following tasks:
- Set enforcing or permissive mode
- Run
restorecon
on parts of the file system hierarchy - Set SELinux Boolean values
- Set SELinux file contexts persistently
- Set SELinux user mappings
Calling the SELinux Role
Sometimes, the SELinux role must ensure that the managed hosts are rebooted in order to completely apply its changes. However, the role does not ever reboot hosts itself, enabling you to control how the reboot is handled. Therefore, it is a little more complicated than usual to properly use this role in a play.
The role sets a Boolean variable, selinux_reboot_required
, to true
and fails if a reboot is needed. You can use a block
/rescue
structure to recover from the failure by failing the play if that variable is not set to true
, or rebooting the managed host and rerunning the role if it is true
. The block in your play should look something like this:
- name: Apply SELinux role
block:
- include_role:
name: redhat.rhel_system_roles.selinux
rescue:
- name: Check for failure for other reasons than required reboot
ansible.builtin.fail:
when: not selinux_reboot_required
- name: Restart managed host
ansible.builtin.reboot:
- name: Reapply SELinux role to complete changes
include_role:
name: redhat.rhel_system_roles.selinux
Configuring the SELinux Role
The variables used to configure the redhat.rhel_system_roles.selinux
role are described in the role’s documentation. The following examples show some ways to use this role.
The selinux_state
variable sets the mode that SELinux runs in. It can be set to enforcing
, permissive
, or disabled
. If it is not set, the mode is not changed.
selinux_state: enforcing
The selinux_booleans
variable takes a list of SELinux Boolean values to adjust. Each item in the list is a dictionary of variables: the name
of the Boolean, the state
(whether it should be on
or off
), and whether the setting should be persistent
across reboots.
This example sets httpd_enable_homedirs
to on
persistently:
selinux_booleans:
- name: 'httpd_enable_homedirs'
state: 'on'
persistent: 'yes'
The selinux_fcontexts
variable takes a list of file contexts to persistently set (or remove), and works much like the selinux fcontext
command.
The following example ensures the policy has a rule to set the default SELinux type for all files under /srv/www
to httpd_sys_content_t
.
selinux_fcontexts:
- target: '/srv/www(/.*)?'
setype: 'httpd_sys_content_t'
state: 'present'
The selinux_restore_dirs
variable specifies a list of directories on which to run the restorecon
command:
selinux_restore_dirs:
- /srv/www
The selinux_ports
variable takes a list of ports that should have a specific SELinux type.
selinux_ports:
- ports: '82'
setype: 'http_port_t'
proto: 'tcp'
state: 'present'
There are other variables and options for this role. See the role documentation for more information.
Using System Roles with Ansible Core Only
This section is relevant if you plan to use system roles without a Red Hat Ansible Automation Platform subscription, by using the version of Ansible Core that is provided with Red Hat Enterprise Linux 9.
That version of Ansible Core is only supported for use with system roles and other automation code provided by Red Hat. In addition, it does not include ansible-navigator
, so you have to use tools like ansible-playbook
that treat your control node as the execution environment to run your automation.
Because ansible-playbook
does not use execution environments, the only Ansible Content Collection that you have available by default is ansible.builtin
collection. Other packages included with Red Hat Enterprise Linux might add additional Ansible Content Collections to the control node.
Installing the System Roles RPM Package
Make sure that your control node is registered with Red Hat Subscription Manager and has a Red Hat Enterprise Linux subscription. You should also install the ansible-core
RPM package.
To install the rhel-system-roles
RPM package, make sure that the AppStream package repository is enabled. For Red Hat Enterprise Linux 9 on the x86_64 processor architecture, this is the rhel-9-for-x86_64-appstream-rpms
repository. Then, you can install the package.
[user@controlnode ~]$ sudo dnf install rhel-system-roles
If you use Ansible Core from a basic Red Hat Enterprise Linux installation for your control node, and do not have a Red Hat Ansible Automation Platform subscription on that node, then your control node should be a fully updated installation of the most recent version of Red Hat Enterprise Linux. You should also use the most recent version of the ansible-core
and rhel-system-roles
packages.
After installation, the collection is installed in the /usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles
directory on your control node. The individual roles are also installed in the /usr/share/ansible/roles
directory for backward compatibility:
[user@controlnode ~]$ ls -1F /usr/share/ansible/roles/
linux-system-roles.certificate@
linux-system-roles.cockpit@
linux-system-roles.crypto_policies@
linux-system-roles.firewall@
linux-system-roles.ha_cluster@
linux-system-roles.kdump@
linux-system-roles.kernel_settings@
linux-system-roles.logging@
linux-system-roles.metrics@
linux-system-roles.nbde_client@
linux-system-roles.nbde_server@
linux-system-roles.network@
linux-system-roles.postfix@
linux-system-roles.selinux@
linux-system-roles.ssh@
linux-system-roles.sshd@
linux-system-roles.storage@
linux-system-roles.timesync@
linux-system-roles.tlog@
linux-system-roles.vpn@
rhel-system-roles.certificate/
rhel-system-roles.cockpit/
rhel-system-roles.crypto_policies/
rhel-system-roles.firewall/
rhel-system-roles.ha_cluster/
rhel-system-roles.kdump/
rhel-system-roles.kernel_settings/
rhel-system-roles.logging/
rhel-system-roles.metrics/
rhel-system-roles.nbde_client/
rhel-system-roles.nbde_server/
rhel-system-roles.network/
rhel-system-roles.postfix/
rhel-system-roles.selinux/
rhel-system-roles.ssh/
rhel-system-roles.sshd/
rhel-system-roles.storage/
rhel-system-roles.timesync/
rhel-system-roles.tlog/
rhel-system-roles.vpn/
The corresponding upstream name of each role is linked to the system role. This enables individual roles to be referenced in a playbook by either name.
If you are using ansible-playbook
to run your playbook, and your playbook refers to a system role that was installed using the RPM package’s FQCN, you must use the redhat.rhel_system_roles
version of its name. For example, you could refer to the firewall
role as:
redhat.rhel_system_roles.firewall
(its FQCN in the collection)rhel-system-roles.firewall
(its name as an independent role)linux-system-roles.firewall
(its name as the upstream independent role)
You cannot use fedora.linux_system_roles.firewall
because the fedora.linux_system_roles
collection is not installed on the system.
In addition, the independent role names only work if /usr/share/ansible/roles
is in your roles_path
setting.
Accessing Documentation for System Roles
If you are working with system roles in Red Hat Enterprise Linux and do not have ansible-navigator
available to you, there are other ways to get documentation about system roles.
The official documentation for system roles is located at Administration and configuration tasks using System Roles in RHEL .
However, if you installed the system roles from the RPM package, documentation is also available under the /usr/share/doc/rhel-system-roles/
directory.
[user@controlnode ~]$ ls -1 /usr/share/doc/rhel-system-roles/
certificate
cockpit
collection
crypto_policies
firewall
ha_cluster
kdump
kernel_settings
logging
metrics
nbde_client
nbde_server
network
postfix
selinux
ssh
sshd
storage
timesync
tlog
vpn
Each role’s documentation directory contains a README.md
file. The README.md
file contains a description of the role, along with information on how to use it.
The README.md
file also describes role variables that affect the behavior of the role. Often the README.md
file contains a playbook snippet that demonstrates variable settings for a common configuration scenario.
Running Playbooks Without Automation Content Navigator
You can use the ansible-playbook
command to run a playbook that uses system roles in Red Hat Enterprise Linux when you do not have Red Hat Ansible Automation Platform or `ansible-navigator``.
The syntax of ansible-playbook
is very similar to ansible-navigator run -m stdout
, and takes many of the same options.
[user@controlnode ~]$ ansible-playbook playbook.yml
References
Red Hat Enterprise Linux (RHEL) System Roles
Red Hat Enterprise Linux System Roles Ansible Collection
Linux System Roles Ansible Collection
Example
Add the collections_paths
key to the ansible.cfg
file, so that the ./collections
directory is searched.
[defaults]
inventory=./inventory
remote_user=devops
collections_paths=./collections:~/.ansible/collections:/usr/share/ansible/collections
install the redhat.rhel_system_roles
collection from the tar
[student@workstation role-system]$ ansible-galaxy collection \
> install -p collections/ redhat-rhel_system_roles-1.19.3.tar.gz
[student@workstation role-system]$ ansible-galaxy collection list
# /home/student/role-system/collections/ansible_collections
Collection Version
------------------------ -------
redhat.rhel_system_roles 1.19.3
Create the configure_time.yml
playbook with one play that targets the database_servers
host group and runs the redhat.rhel_system_roles.timesync
role in its roles
section.
Create the group_vars/all
subdirectory.
[student@workstation role-system]$ mkdir -pv group_vars/all
mkdir: created directory 'group_vars'
mkdir: created directory 'group_vars/all'
Create a group_vars/all/timesync.yml
file, adding variable definitions to satisfy the time synchronization requirements. The file now contains:
---
#redhat.rhel_system_roles.timesync variables for all hosts
timesync_ntp_provider: chrony
timesync_ntp_servers:
- hostname: classroom.example.com
iburst: yes
Add two tasks to the configure_time.yml
file to get and conditionally set the time zone for each host. Ensure that both tasks run after the redhat.rhel_system_roles.timesync
role.
configure_time.yml
file is like:
---
- name: Time Synchronization
hosts: database_servers
roles:
- redhat.rhel_system_roles.timesync
post_tasks:
- name: Get time zone
ansible.builtin.command: timedatectl show
register: current_timezone
changed_when: false
- name: Set time zone
ansible.builtin.command: "timedatectl set-timezone {{ host_timezone }}"
when: host_timezone not in current_timezone.stdout
notify: reboot host
handlers:
- name: reboot host
ansible.builtin.reboot:
For each data center, create a file named timezone.yml
that contains an appropriate value for the host_timezone
variable. Use the timedatectl list-timezones
command to find the valid time zone string for each data center.
[student@workstation role-system]$ mkdir -pv \
> group_vars/{na_datacenter,europe_datacenter}
[student@workstation role-system]$ timedatectl list-timezones | grep Chicago
America/Chicago
[student@workstation role-system]$ timedatectl list-timezones | grep Helsinki
Europe/Helsinki
[student@workstation role-system]$ echo "host_timezone: America/Chicago" > \
> group_vars/na_datacenter/timezone.yml
[student@workstation role-system]$ echo "host_timezone: Europe/Helsinki" > \
> group_vars/europe_datacenter/timezone.yml
run the playbook
[student@workstation role-system]$ ansible-navigator run \
> -m stdout configure_time.yml
examine the result:
[student@workstation role-system]$ ssh servera date
Tue Sep 10 07:43:33 PM CDT 2024
[student@workstation role-system]$ ssh serverb date
Wed Sep 10 03:43:41 AM EEST 2024
Chapter 7 Example
[student@workstation role-review]$ ll
total 1540
-rw-r--r--. 1 student student 232 Sep 11 10:35 ansible.cfg
drwxr-xr-x. 10 student student 154 Sep 11 21:46 apache.developer_configs
-rw-r--r--. 1 student student 143360 Sep 11 10:35 apache.tar
drwxr-xr-x. 3 student student 33 Sep 11 10:42 collections
-rw-r--r--. 1 student student 595 Sep 11 10:35 developer.conf.j2
-rw-r--r--. 1 student student 1566 Sep 11 10:35 developer_tasks.yml
-rw-r--r--. 1 student student 83 Sep 11 10:35 inventory
-rw-r--r--. 1 student student 396 Sep 11 10:35 jdoe2.key.pub
-rw-r--r--. 1 student student 396 Sep 11 10:35 jdoe.key.pub
-rw-r--r--. 1 student student 808333 Sep 11 10:35 redhat-rhel_system_roles-1.19.3.tar.gz
-rw-r--r--. 1 student student 231 Sep 11 10:35 selinux.yml
-rw-r--r--. 1 student student 138 Sep 11 10:35 web_developers.yml
-rw-r--r--. 1 student student 715 Sep 11 22:49 web_dev_server.yml
[student@workstation role-review]$ cat ansible.cfg
[defaults]
inventory=./inventory
remote_user=devops
collections_paths=./collections:~/.ansible/collections:/usr/share/ansible/collections
[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False
[student@workstation role-review]$
[student@workstation role-review]$
[student@workstation role-review]$ cat inventory
[controlnode]
workstation.lab.example.com
[dev_webserver]
servera.lab.example.com
[student@workstation role-review]$
[student@workstation role-review]$
[student@workstation role-review]$ cat developer.conf.j2
#This is an Ansible Template
# 'item' is a user from the web_developers user list,
# and defines:
# - user_port
# - username
# - name
Listen {{ item['user_port'] }}
<VirtualHost *:{{ item['user_port'] }}>
ServerName {{ inventory_hostname }}
ErrorLog "logs/{{ item['username'] }}_error_log"
CustomLog "logs/{{ item['username'] }}_access_log" common
DocumentRoot /srv/{{ item['username'] }}/www
<Directory /srv/{{ item['username'] }}/www >
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
[student@workstation role-review]$
[student@workstation role-review]$
[student@workstation role-review]$ cat developer_tasks.yml
---
# tasks file for apache.developer_configs
- name: Create user accounts
ansible.builtin.user:
name: "{{ item['username'] }}"
state: present
loop: "{{ web_developers }}"
#Allows 'student' user to login to
# any of the user accounts - for the lab only.
# Jinja syntax for 'key' keyword available from the documentation.
- name: Give student access to all accounts
ansible.posix.authorized_key:
user: "{{ item['username'] }}"
state: present
key: "{{ lookup('file', '/home/student/role-review/'+ item['username'] + '.key.pub') }}"
loop: "{{ web_developers }}"
- name: Create content directory
ansible.builtin.file:
path: /srv/{{ item['username'] }}/www
state: directory
owner: "{{ item['username'] }}"
loop: "{{ web_developers }}"
- name: Create skeleton index.html if needed
ansible.builtin.copy:
content: "This is index.html for user: {{ item['name'] }} ({{ item['username'] }})\n"
dest: /srv/{{ item['username'] }}/www/index.html
force: false
owner: "{{ item['username'] }}"
group: root
mode: 0664
loop: "{{ web_developers }}"
- name: Set firewall port
ansible.posix.firewalld:
port: "{{ item['user_port'] }}/tcp"
permanent: true
state: enabled
loop: "{{ web_developers }}"
notify: restart firewalld
- name: Copy Per-Developer Config files
ansible.builtin.template:
src: developer.conf.j2
dest: "/etc/httpd/conf.d/developer_{{ item['username'] }}.conf"
owner: root
group: root
mode: 0644
loop: "{{ web_developers }}"
notify: restart apache
[student@workstation role-review]$
# install rhel roles
[student@workstation role-review]$ ansible-galaxy collection \
> install -p collections/ redhat-rhel_system_roles-1.19.3.tar.gz
[student@workstation role-review]$ ansible-galaxy collection list
#Make sure to install any roles that are dependencies of roles in your playbook.
the apache.developer_configs role that you write later in this lab depends on the infra.apache role.
Create a roles/requirements.yml file. This file installs the role from the Git repository at [email protected]:infra/apache, use version v1.4, and name it infra.apache locally.
# create roles dir
[student@workstation role-review]$ mkdir -v roles
roles/requirements.yml
file contains the following content:
- name: infra.apache
src: [email protected]:infra/apache
scm: git
version: v1.4
[student@workstation role-review]$ ansible-galaxy role install \
> -r roles/requirements.yml -p roles
Initialize a new role named apache.developer_configs
in the roles
subdirectory.
[student@workstation roles]$ ansible-galaxy role init apache.developer_configs
Add the infra.apache
role as a dependency for the new role, using the same information for name, source, version, and version control system as the roles/requirements.yml
file.
Modify the roles/apache.developer_configs/meta/main.yml
file of the apache.developer_configs
role to reflect a dependency on the infra.apache
role.
dependencies:
- name: infra.apache
src: [email protected]:infra/apache
scm: git
version: v1.4
The developer_tasks.yml
file in the project directory contains tasks for the role. Move this file to the correct location in the role directory hierarchy for a tasks file that is used by this role, replacing the existing file in that location.
The developer.conf.j2
file in the project directory is a Jinja2 template that is used by the tasks file. Move this file to the correct location for template files that are used by this role.
[student@workstation role-review]$ mv -v developer_tasks.yml \
> roles/apache.developer_configs/tasks/main.yml
[student@workstation role-review]$ mv -v developer.conf.j2 \
> roles/apache.developer_configs/templates/
renamed 'developer.conf.j2' -> 'roles/apache.developer_configs/templates/developer.conf.j2'
Review the web_developers.yml
file.
---
web_developers:
- username: jdoe
name: John Doe
user_port: 9081
- username: jdoe2
name: Jane Doe
user_port: 9082
Place the web_developers.yml
file in the group_vars/dev_webserver
subdirectory.
[student@workstation role-review]$ mkdir -pv group_vars/dev_webserver
[student@workstation role-review]$ mv -v web_developers.yml \
> group_vars/dev_webserver/
/home/student/role-review/web_dev_server.yml
playbook contains the following content:
---
- name: Configure Dev Web Server
hosts: dev_webserver
force_handlers: true
roles:
- apache.developer_configs
run the playbook
[student@workstation role-review]$ ansible-navigator run \
> -m stdout web_dev_server.yml
...
RUNNING HANDLER [infra.apache : restart apache] ********************************
fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "msg": "Unable to restart service httpd: Job for httpd.service failed because the control process exited with error code.\nSee \"systemctl status httpd.service\" and \"journalctl -xeu httpd.service\" for details.\n"}
...
An error occurs when the httpd service is restarted. The httpd service daemon cannot bind to the non-standard HTTP ports, due to the SELinux context on those ports.
Apache HTTPD failed to restart in the preceding step because the network ports it uses for your developers are labeled with the wrong SELinux contexts.
You can use the provided variable file, selinux.yml
, with the redhat.rhel_system_roles.selinux
role to fix the issue.
Create a pre_tasks
section for your play in the web_dev_server.yml
playbook. In that section, use a task to include the redhat.rhel_system_roles.selinux
role in a block
/rescue
structure, so that it is properly applied.
Move the selinux.yml
file to the correct location so that its variables are set for the dev_webserver
host group.
[student@workstation role-review]$ cat selinux.yml
---
# variables used by redhat.rhel_system_roles.selinux
selinux_policy: targeted
selinux_state: enforcing
selinux_ports:
- ports:
- "9081"
- "9082"
proto: 'tcp'
setype: 'http_port_t'
state: 'present'
[student@workstation role-review]$ mv -v selinux.yml \
> group_vars/dev_webserver/
renamed 'selinux.yml' -> 'group_vars/dev_webserver/selinux.yml'
---
- name: Configure Dev Web Server
hosts: dev_webserver
force_handlers: true
roles:
- apache.developer_configs
pre_tasks:
- name: Verify SELinux configuration
block:
- name: Apply SELinux role
ansible.builtin.include_role:
name: redhat.rhel_system_roles.selinux
rescue:
# Fail if failed for a different reason than selinux_reboot_required.
- name: Handle general failure
ansible.builtin.fail:
msg: "SELinux role failed."
when: not selinux_reboot_required
- name: Restart managed host
ansible.builtin.reboot:
msg: "Ansible rebooting system for updates."
- name: Reapply SELinux role to complete changes
ansible.builtin.include_role:
name: redhat.rhel_system_roles.selinux
run again
[student@workstation role-review]$ ansible-navigator run \
> -m stdout web_dev_server.yml
...
PLAY RECAP *********************************************************************
servera.lab.example.com : ok=21 changed=2 unreachable=0 failed=0 skipped=16 rescued=0 ignored=0
Test the configuration of the development web server. Verify that all endpoints are accessible and serving each developer’s content.
[student@workstation role-review]$ curl servera
This is the production server on servera.lab.example.com
[student@workstation role-review]$ curl servera:9081
This is index.html for user: John Doe (jdoe)
[student@workstation role-review]$ curl servera:9082
This is index.html for user: Jane Doe (jdoe2)
TO BE CONTINUED…