lab04 inside ansible-labslab04 folderinventory folder from lab03 to lab04
cp -r ../lab03/inventory ./inventoryCreate 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 PostgreSQLhosts option to run this play only on the db groupbecome option to run the tasks with sudogather_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.