lab04
inside ansible-labs
lab04
folderinventory
folder from lab03
to lab04
cp -r ../lab03/inventory ./inventory
Create a file named full_playbook.yml
inside lab04
folder.
Add the following content to the file:
---
- name: Install and configure Redis
hosts: all
become: true
tags:
- redis
tasks:
- name: Install Redis
ansible.builtin.yum:
name: redis
state: present
when: ansible_facts['os_family'] == "RedHat"
notify:
- Start Redis
- name: Install Redis
ansible.builtin.apt:
name: redis-server
state: present
when: ansible_facts['os_family'] == "Debian"
notify:
- Start Redis
- name: Test Redis
ansible.builtin.command: redis-cli ping
register: redis_ping
- name: Print Redis ping
ansible.builtin.debug:
msg: ""
handlers:
- name: Start Redis
service:
name: redis
state: started
enabled: true
On this playbook, we are:
yum
and apt
modulesnotify
option to trigger the Start Redis
handlerservice
module to start the Redis servicecommand
module to run the redis-cli ping
command and register the outputdebug
module to print the output of the redis-cli ping
commandOn play definition we’re including the tag redis
to the play. This will allow us to run only the tasks with this tag.
Now let’s run the playbook:
ansible-playbook -i inventory/inventory.yml full_playbook.yml
You should see an error on the output when trying to run Test Redis
task.
This is because even you installed Redis, you didn’t started the service.
You notified the Start Redis
handler, but it will only run when the all playbook tasks run.
Now let’s add a meta
task to force the handler to run. Edit the file full_playbook.yml
and add the following task before the Test Redis
task:
- name: Force handler execution
meta: flush_handlers
Pay attention to the indentation. This task should be at the same level as the other tasks.
Now let’s run the playbook again:
ansible-playbook -i inventory/inventory.yml full_playbook.yml
Even forcing the handler to run, you’ll get an error on the Test Redis
task.
This is because that the task Install Redis
returned an OK
result and Ansible only runs the handler notified by a task if the task returns a Changed
result.
To force the handler to run, you need to change the Install Redis
task to return a Changed
result. You will use the changed_when
option to do this.
Edit the file full_playbook.yml
and change the Install Redis
task to the following:
- name: Install Redis
ansible.builtin.yum:
name: redis
state: present
when: ansible_facts['os_family'] == "RedHat"
register: redis_installed
changed_when: redis_installed.rc == 0
notify:
- Start Redis
On this task, you are using the changed_when
option to change the result of the task to Changed
when the rc
attribute of the redis_installed
variable is 0
.
The rc
attribute is the return code of the task. When the task runs without any error, the return code is 0
.
Let’s run the playbook again:
ansible-playbook -i inventory/inventory.yml full_playbook.yml
Now everything should run fine and you get an output for the Test Redis
task similar to the following:
TASK [Print Redis ping] ***************************
ok: [servidor-0] => {
"msg": "PONG"
}
ok: [servidor-1] => {
"msg": "PONG"
}
On this step, we’ll configure Redis to add a password.
Edit the file full_playbook.yml
and add the following task after the Print Redis ping
task:
- name: Configure Redis
ansible.builtin.replace:
path: /etc/redis/redis.conf
regexp: '^# requirepass foobared'
replace: 'requirepass ansible'
backup: yes
notify:
- Restart Redis
On this task, we are using the replace
module to replace the line # requirepass foobared
with requirepass ansible
on the file /etc/redis.conf
.
Then we are using the notify
option to trigger the Restart Redis
handler.
So you need to create the handler. Edit the file full_playbook.yml
and add the following handler after the Start Redis
handler:
- name: Restart Redis
ansible.builtin.service:
name: redis
state: restarted
Now let’s run the playbook again:
ansible-playbook -i inventory/inventory.yml full_playbook.yml
Take a look to the output of this run and check how the task run and at the end you see the handler running.
Now let’s run the playbook again:
ansible-playbook -i inventory/inventory.yml full_playbook.yml
As expected, everything run fine since you’re using idempotent tasks. If not, you’ll get an error on the Configure Redis
task because the regular expression will not match.
But you may notice a difference on the output of the Print Redis ping
task:
TASK [Print Redis ping] **************************
ok: [servidor-0] => {
"msg": "NOAUTH Authentication required."
}
ok: [servidor-1] => {
"msg": "NOAUTH Authentication required."
}
This is because you change the configuration of Redis and now it requires authentication.
So let’s change the Print Redis ping
task to use the redis-cli
command with the password.
First, create a variable named redis_password
with the value ansible
on the vars
section of the playbook:
vars:
redis_password: ansible
This block should be added before the tasks
section. Pay attention to the indentation.
Then, edit the Test Redis
task and change the command
module to use the redis-cli
command with the password:
- name: Test Redis
ansible.builtin.command: redis-cli -a ping
register: redis_ping
Finally, to make use of the variable, edit the Configure Redis
task and change the replace
module to use the variable:
- name: Configure Redis
ansible.builtin.replace:
path: /etc/redis/redis.conf
regexp: '^# requirepass foobared'
replace: 'requirepass '
backup: yes
notify:
- Restart Redis
Let’s run the playbook again:
ansible-playbook -i inventory/inventory.yml full_playbook.yml
Now you should see the output of the Print Redis ping
task similar to the following:
TASK [Print Redis ping] ***************************
ok: [servidor-0] => {
"msg": "PONG"
}
ok: [servidor-1] => {
"msg": "PONG"
}
Having the password on the playbook is not a good practice. We’re doing this way just for learning purposes and to be changed in a later lab when we introduce Ansible Vault.
Now let’s install PostgreSQL.
Edit the file full_playbook.yml
and add a new play after the Install and configure Redis
play:
- name: Install and configure PostgreSQL
hosts: db
become: true
gather_facts: false
tags:
- postgresql
Let’s understand what we’re doing here:
Install and configure PostgreSQL
hosts
option to run this play only on the db
groupbecome
option to run the tasks with sudo
gather_facts
option to false
to avoid gathering facts on this playtags
option to add the postgresql
tag to this playNow let’s add the task to install PostgreSQL:
tasks:
- name: Install PostgreSQL
ansible.builtin.package:
name: postgresql-server
state: present
Check that we’re using the ansible.builtin.package
module to install the postgresql-server
package.
This module can be used on both RedHat and Debian based systems and uses the correct package manager for each system.
You can check more details about this module on the Ansible documentation.
Then, you need to add the task to initialize the database:
- name: "Find out if PostgreSQL is initialized"
ansible.builtin.stat:
path: "/var/lib/pgsql/data/pg_hba.conf"
register: postgres_data
- name: "Initialize PostgreSQL"
ansible.builtin.shell: "postgresql-setup --initdb"
when: not postgres_data.stat.exists
These tasks will check if the file /var/lib/pgsql/data/pg_hba.conf
exists and if not, will initialize the database.
Pay attention to the when
condition on the second task. This task will only run if the file doesn’t exist.
When adding this to the file pay attention to the indentation. These tasks should be at the same level as the Install PostgreSQL
task.
Then, you need to add the task to start the service:
- name: Start PostgreSQL
ansible.builtin.service:
name: postgresql
state: started
enabled: true
This task will use the service
module to start the PostgreSQL service.
Finally, you need to add the tasks to test if PostgreSQL is running:
- name: Test PostgreSQL
become: true
become_user: postgres
ansible.builtin.shell: |
psql -c "SELECT version();"
register: postgresql_version
- name: Print PostgreSQL version
ansible.builtin.debug:
msg: ""
On this task you are using the shell
module to run the psql -c "SELECT version();"
command as the postgres
user and register the output.
Check the line become_user: postgres
. This is needed because the postgres
user is the one that can run the psql
command.
Now let’s run the playbook:
ansible-playbook -i inventory/inventory.yml full_playbook.yml --tags postgresql
On the command above, you’re running the playbook and filtering the tasks by the postgresql
tag.
You should run everything without any error.
Now let’s run the playbook again:
ansible-playbook -i inventory/inventory.yml full_playbook.yml --tags postgresql
And confirm that only the testing tasks returns a Changed
result.
Now you need to add to this playbook the tasks to install and configure Apache.
Those tasks already exists on the webserver.yml
playbook from the previous lab.
So start to copy the file webserver.yml
from lab03
to lab04
:
cp ../lab03/webserver.yml .
You need to copy the file index.html
from lab03
to lab04
:
cp ../lab03/index.html .
Then, edit the file full_playbook.yml
and use the import_playbook
module to import the webserver.yml
playbook:
- name: Install and configure web server
tags:
- webserver
import_playbook: webserver.yml
This should be added after the last play.
Let’s run the playbook:
ansible-playbook -i inventory/inventory.yml full_playbook.yml --tags webserver
You should see the tasks from the webserver.yml
playbook running.
After you added all the tasks, your full_playbook.yml
should look like this:
---
- name: Install and configure Redis
hosts: all
become: true
tags:
- redis
vars:
redis_password: ansible
tasks:
- name: Install Redis
ansible.builtin.yum:
name: redis
state: present
when: ansible_facts['os_family'] == "RedHat"
register: redis_installed
changed_when: redis_installed.rc == 0
notify:
- Start Redis
- name: Print
ansible.builtin.debug:
msg: ""
- name: Install Redis
ansible.builtin.apt:
name: redis-server
state: present
when: ansible_facts['os_family'] == "Debian"
notify:
- Start Redis
- meta: flush_handlers
- name: Test Redis
ansible.builtin.command: redis-cli -a ping
register: redis_ping
- name: Print Redis ping
ansible.builtin.debug:
msg: ""
- name: Configure Redis
ansible.builtin.replace:
path: /etc/redis/redis.conf
regexp: '^# requirepass foobared'
replace: 'requirepass '
backup: yes
notify:
- Restart Redis
handlers:
- name: Start Redis
service:
name: redis
state: started
enabled: true
- name: Restart Redis
service:
name: redis
state: restarted
- name: Install and configure PostgreSQL
hosts: db
become: true
gather_facts: false
tags:
- postgresql
tasks:
- name: Install PostgreSQL
ansible.builtin.package:
name: postgresql-server
state: present
- name: "Find out if PostgreSQL is initialized"
ansible.builtin.stat:
path: "/var/lib/pgsql/data/pg_hba.conf"
register: postgres_data
- name: "Initialize PostgreSQL"
shell: "postgresql-setup --initdb"
when: not postgres_data.stat.exists
- name: Start PostgreSQL
service:
name: postgresql
state: started
enabled: true
- name: Test PostgreSQL
become: true
become_user: postgres
ansible.builtin.shell: |
psql -c "SELECT version();"
register: postgresql_version
- name: Print PostgreSQL version
ansible.builtin.debug:
msg: ""
- name: Install and configure web server
tags:
- webserver
import_playbook: webserver.yml
Now let’s run the full playbook without setting any tag.
ansible-playbook -i inventory/inventory.yml full_playbook.yml
You should see all the tasks running and not making any change on the server unless on testing tasks.
On this lab you learned how to create a playbook to install and configure multiple services on different servers.