The RHCE 8 exam is totally based on Ansible. Generally, 15-17 questions are asked to solve in the exam. In this article, I will try to solve all questions that you might face in the exam. Please ensure that you have already completed the RHCSA exam and have basic knowledge of YAML.
Question 1: Install and configure Ansible
User ismat has been created on your control node with the appropriate permissions already, do not change or modify ssh keys. Install the necessary packages to run ansible on the control node. Configure ansible.cfg to be in folder /home/ismat/ansible/ansible.cfg and configure to access remote machines via the ismat user.
All roles should be in the path /home/ismat/ansible/roles.
The inventory path should be in /home/ismat/ansible/inventory.
You will have access to 5 nodes:
node1.example.com
node2.example.com
node3.example.com
node4.example.com
node5.example.com
Configure these nodes to be in an inventory file where node1 is a member of group dev, node2 is a member of group test, node3 is a member of group proxy, node4 and node5 are members of group prod, Also, prod is a member of group webservers.
Solution:
The environment will remain ready. You just need to install the ansible in the control node by the command. But at home for practice, you need to enable an ansible repository.
sudo yum install -y ansible
For writing code easily you can install vim package also. In a real exam, it helps you a lot as you have to write everything in a text file and vim editor will show you an error if you do a mistake in yml syntax.
sudo yum -y install vim
create a file /home/ismat/ansible/inventory and a directory
/home/ismat/ansible/roles. Navigate to /home/ismat/ansible directory.
$ mkdir /home/ismat/ansible
$ touch /home/ismat/ansible/inventory
$ mkdir /home/ismat/ansible/roles
$ touch /home/ismat/ansible.cfg
$ cd /home/ismat/ansible
Now edit the inventory file ( vim inventory)
[dev]
node1.example.com
[test]
node2.example.com
[proxy]
node3.example.com
[prod]
node4.example.com
node5.example.com
[webservers:children]
prod
Edit the ansible.cfg file with the following information
[defaults]
inventory=/home/ismat/ansible/inventory
roles_path= /etc/ansible/roles:/usr/share/ansible/roles:/home/ismat/ansible/roles
remote_user= ismat
host_key_checking=false
[privilege_escalation]
become=true
become_user=root
become_method=sudo
become_ask_pass=false
Verify your installation
ansible --version
The above command’s output will shows ansible version installed and also configuration file location : config file = /home/ismat/ansible/ansible.cfg . If it comes in this way then your installation is done perfectly. Please run a command always from /home/ismat/ansible directory.
Tips: You can copy the /etc/ansible.cfg file to /home/ismat/ansible/ansible.cfg and uncomment and edit the above configuration parameters .
For practice at home install Ansible on CentOS 8 which is very straightforward. Click Install Ansible on CentOS 8 to see details.
cp /etc/ansible.cfg /home/ismat/ansible/ansible.cfg
Question2: Repository setup
Create a file called adhoc.sh in /home/ismat/ansible which will use adhoc commands to set up a new repository. The name of the repo will be ‘EPEL’ the description ‘RHEL8’ the baseurl is ‘https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rmp’ , set gpgcheck and gpgkey is http://example.key and enable the repo
Solution:
vim adhoc.sh
#!/bin/bash
ansible all -m yum_repository -a 'name=EPEL description=RHEL8 baseurl=https://dl.fedoraproject.org/pub/epel/epelrelease-
latest-8.noarch.rmp gpgcheck=yes gpgkey=http://example.key enabled=yes'
$ chmod 777 adhoc.sh
$ ./adhoc.sh
Tips: In the real exam if you forget syntax run the following command and you will get all options and can make sure your syntax is correct.
$ ansible-doc yum_repository
Question 3: Install packages
Create a file called packages.yml in /home/ismat/ansible to install some packages for the following hosts. On dev, prod and webservers install packages httpd, mod_ssl, and mariadb. On dev only install the development tools package. Also, on dev host update all the packages to the latest.
Solution:
---
- name: Install Common Packages
hosts: dev,prod,webservers
tasks:
- name: Install httpd,mod_ssl,mariadb
yum:
name:
- httpd
- mod_ssl
- mariadb
state: present
- name: Install development tools package on dev host
yum:
name: '@Development tools'
state: latest
when: "'dev' in group_names"
- name: Update all the packages on dev hosts
yum:
name: '*'
state: latest
when: "'dev' in group_names"
...
Tips: To know how to write code for the yum module. Run command ansible-doc yum , scrolling to the bottom, and copy example code.
Question 4: Create Role including template
Create a role called sample-apache in /home/ismat/ansible/roles that enables and starts httpd, enables and starts the firewall; and allows the webserver service. Create a template called index.html.j2 which creates and serves a message from /var/www/html/index.html. Whenever the content of the file changes, restart the webserver service.
Welcome to [FQDN] on [IP]
Replace the FQDN with the fully qualified domain name and IP with the ip address of the node using ansible facts. Lastly, create a playbook in /home/ismat/ansible named apache.yml and use the role to serve the index file on webserver hosts.
Solution:
Navigate to /home/ismat/ansible/roles directory and run command
$ ansible-galaxy init sample-apache
vim sample-apache/tasks/main.yml
---
# tasks file for sample-apache
- name: Enable httpd
service:
name: httpd
state: started
enabled: yes
- name: Enable firewalld
service:
name: firewalld
state: started
enabled: yes
- name: Allow webserver service
firewalld:
service: http
state: enabled
permanent: yes
immediate: yes
- name: Create index file from index.html.j2
template:
src: index.html.j2
dest: /var/www/html/index.html
notify:
- restart_webservers
vim sample-apache/templates/index.html.j2
Welcome to {{ ansible_fqdn }} on {{ ansible_default_ipv4.address }}
Tips: There is a chance you can’t remember ansible_fqdn or ansible_default_ipv4.address these kinds of facts. You can run adhoc command of the setup module to get the whole remote machine facts and save them to a file. ansible node2.example.com -m setup > facts.json. Then vim facts.json file and find the facts variables. It is extremely helpful if you are afraid of a spelling mistake.
vim sample-apache/handlers/main.yml
---
# handlers file for sample-apache
- name: restart_webservers
service:
name: httpd
state: restarted
Navigate back to your ansible working directory /home/ismat/ansible and write in apache.yml ( vim apache.yml)
---
- name: Install apachec from apache-role
hosts: webservers
roles:
- name: sample-apache
...
Question 5: Install Role from ansible-galaxy repository
Create a file called requirements.yml in /home/ismat/ansible/roles to install two roles. The source for the first role is geerlingguy.haproxy and geerlingguy.php. Name the first haproxy-role and the second php-role. The roles should be installed in /home/ismat/ansible/roles.
Solution:
Create a file requirements.yml in /home/ismat/ansible/roles and write the following code
- name: haproxy-role
src: geerlingguy.haproxy
- name: php-role
src: geerlingguy.php
Navigate to the roles directory and run the following command
$ ansible-galaxy install -r requirements.yml -p /home/sandy/ansible/roles/
Check the roles were installed
$ ls *
haproxy-role php-role sample-apache
Question 6: Call Role from playbook
Use the roles from Task 5 in a file called role.yml in /home/ismat/ansible/. The haproxy-role should be used on the proxy host. And when you curl http://node3.example.com. it should display “Welcome to node4.example.com” and when you curl again “Welcome to node5.example.com” The php-role should be used on the prod host.
Solution:
vim /home/ismat/ansible/role.yml
---
- name: install haproxy and php roles
hosts: all
vars:
haproxy_backend_servers:
- name: web1
address: node4.example.com:80
- name: web2
address: node5.example.com:80
tasks:
- name: import hasproxy
include_role:
name: haproxy-role
when: "'proxy' in group_names"
- name: import php
include_role:
name: php-role
when: "'prod' in group_names"
...
Question 7: Create secret file
Create an ansible vault password file called lock.yml with the password reallysafepw in the /home/ismat/ansible directory. In the lock.yml file define two variables. One is pw_dev and the password is ‘dev’ and the other is pw_mgr and the password is ‘mgr’. Create a regular file called secret.txt which contains the password for lock.yml.
Solution:
Run the following command
$ ansible-vault create lock.yml
New Vault password:
Confirm New Vault password:
$ ansible-vault view lock.yml
Vault password:
pw_dev: dev
pw_mgr: mgr
Create a file /home/ismat/ansible/secret.txt and write reallysafepw
$ vim /home/ismat/ansible/secret.txt
$ cat /home/ismat/ansible/secret.txt
reallysafepw
Question 8: Read secret from vault
Create the users in the file users_list.yml file provided. Do this in a playbook called users.yml located at /home/ismat/ansible. The passwords for these users should be set using the lock.yml file from TASK7. When running the playbook, the lock.yml file should be unlocked with secret.txt file from Question 7.
All users with the job of ‘developer’ should be created on the dev hosts, add them to the group devops, their password should be set using the pw_dev variable. Likewise create users with the job of ‘manager’ on the proxy host and add the users to the group ‘managers’, their password should be set using the pw_mgr variable.
users_list.yml
users:
- username: bill
job: developer
- username: chris
job: manager
- username: dave
job: test
- username: ethan
job: developer
Solution:
Write your code in /home/ismat/ansible/users.yml file
---
- name: user create
hosts: dev,proxy
vars_files:
- lock.yml
- users_list.yml
tasks:
- name: developer user create
user:
name: "{{ item.username }}"
group: devops
state: present
password: "{{ pw_dev | password_hash('sha512') }}"
when: item.job=="developer" and "dev" in group_names
loop: "{{ users }}"
- name: manager user create
user:
name: "{{ item.username }}"
group: managers
state: present
password: "{{ pw_mgr | password_hash('sha512') }}"
when: item.job=="manager" and "proxy" in group_names
loop: "{{ users }}"
...
Run the playbook as follows
$ ansible-playbook users.yml --vault-password-file secret.txt
Question 9: Download and modify file
Create a file in /home/ismat/ansible/ called report.yml. Using this playbook, get a file called report.txt. Download the file from http://classroom.example.com to all remote hosts at /root/report.txt. Then edit the lines in the file to provide the real information of the hosts. If a disk does not exist then write NONE. The file content of report.txt is
HOST= inventory hostname
MEMORY=total memory in mb
BIOS=bios version
VDA_DISK_SIZE=disk size
VDB_DISK_SIZE=disk size
Solution:
---
- name: copy file with custom information
hosts: all
tasks:
- name: get file
get_url:
url: https://classroom.example.com/report.txt
dest: /root/report.txt
- name: chahge hostname
lineinfile:
path: /root/report.txt
line: HOST={{ ansible_hostname }}
regex: ^HOST
state: present
- name: chahge memory
lineinfile:
path: /root/report.txt
line: MEMORY={{ ansible_memtotal_mb }}
regex: ^MEMORY
state: present
- name: chahge bios version
lineinfile:
path: /root/report.txt
line: BIOS={{ ansible_bios_version }}
regex: ^BIOS
state: present
- name: chahge vda
lineinfile:
path: /root/report.txt
line: VDA_DISK_SIZE={% if ansible_devices.vda is defined %}{{ ansible_devices.vda.size }} {% else %} NONE {% endif %}
regex: ^VDA_DISK_SIZE
state: present
- name: chahge vdb
lineinfile:
path: /root/report.txt
line: VDB_DISK_SIZE={% if ansible_devices.sda is defined %}{{ ansible_devices.sda.size }} {% else %} NONE {% endif %}
regex: ^VDB_DISK_SIZE
state: present
...
Tips: At real exam you will not see the content of report.txt file. So first download it to your working directory by the command curl
http://dl.example.com/report.txt –output report.txt . After the task is completed you can delete the file from your working directory
Question 10: Create file using jinja2 template
Download the jinja template from http://dl.example.com/hosts.j2 in /home/ismat/ansible/ and Edit this file so it looks like the one below. The order of the nodes doesn’t matter. Then create a playbook in /home/ismat/ansible called hosts.yml and install the template on dev node at /root/myhosts
Download the jinja template from http://dl.example.com/hosts.j2 in /home/ismat/ansible/ and edit it. Then create a playbook in /home/ismat/ansible called hosts.yml and install the template on dev node at /root/myhosts so that /root/myhosts content will be like below. The order of the nodes doesn’t matter.
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.2.1 node1.example.com node1
10.0.2.2 node2.example.com node2
10.0.2.3 node3.example.com node3
10.0.2.4 node4.example.com node4
10.0.2.5 node5.example.com node5
Solution:
Download the template
$ curl http://dl.example.com/hosts.j2 --output hosts.j2
Edit the hosts.j2 file as follows
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{% for host in groups.all %}
{{ hostvars[host].ansible_default_ipv4.address }} {{ hostvars[host].ansible_fqdn }} {{ hostvars[host].ansible_hostname }}
{% endfor %}
Write a playbook named hosts.yml
---
- name: use hosts.j2 template
hosts: all
tasks:
- name: template a file to dev hosts
template:
src: /home/ismat/ansible/hosts.j2
dest: /root/myhosts
when: "'dev' in group_names"
...
Question 11: Create LVM
In /home/ismat/ansible/ create a playbook called logvol.yml. In the play create a logical volume called lv0 and make it of size 12GiB on volume group vg0 If there is not enough space in the volume group print a message “Not enough space for logical volume” and then make a 6GiB Iv0 instead. If the volume group still doesn’t exist, create a message “Volume group doesn’t exist” Create an xfs filesystem on all lv0 logical volumes. Don’t mount the logical volume.
Write logvol.yml playbook
---
- name: create volume
hosts: all
tasks:
- name: create partition
parted:
device: /dev/sdb
number: 1
flags: [lvm]
state: present
- name: create vg
lvg:
vg: vg0
pvs: /dev/sdb1
when: ansible_devices.sdb.partitions.sdb1 is defined
- name: create lv
lvol:
vg: vg0
lv: lv0
size: 12000m
when: ansible_lvm.vgs.vg0 is defined and ((ansible_lvm.vgs.vg0.size_g | float) > 12)
- name: send message if volume group is not large enough
debug:
msg: Not enough space for logical volume
when: ansible_lvm.vgs.vg0 is defined and ((ansible_lvm.vgs.vg0.size_g | float) < 12)
- name: create similiar volume
lvol:
vg: vg0
lv: lv0
size: 6000m
when: ansible_lvm.vgs.vg0 is defined and ((ansible_lvm.vgs.vg0.size_g | float) < 12)
- name: create fs
filesystem:
dev: /dev/vg0/lv0
fstype: xfs
when: ansible_lvm.vgs.vg0 is defined
...
Question 12: Read content from custom web directory
Create a playbook called webdev.yml in /home/ismat/ansible. The playbook will create a directory /webdev on dev host. The permission of the directory is u=rwx,g=rw, other has no permission. Set group id for the folder and owner is webdev. Create a symbolic link from /webdev to /var/www/html/webdev. Serve a file from /webdev/index.html which displays the text “Development”. Curl http://node1.example.com/webdev/index.html to test
Write the playbook webdev.yml
---
- name: web development
hosts: dev
tasks:
- name: create webdev user
user:
name: webdev
state: present
- name: create directory
file:
path: /webdev
state: directory
owner: webdev
mode: u=rwx,g=rw,0=---,g+s
- name: create symbolic link
file:
src: /webdev
path: /var/www/html/webdev
state: link
- name: create index.html
copy:
content: Development
dest: /var/www/html/webdev/index.html
- name: install selinux policy
yum:
name: python3-policycoreutils
state: present
- name: allow httpd from custom directory
sefcontext:
target: '/webdev(/.*)?'
setype: httpd_sys_content_t
state: present
- name: restore the context
shell: restorecon -vR /webdev
...
Question 13: Set up NTP using Red Hat system roles
Create a playbook called timesync.yml in /home/ismat/ansible using rhel system role timesync. Set the time to use currently configured ntp with the server 0.uk.pool.ntp.org. Enable burst. Do this on all hosts.
Solution:
Install Redhat System Roles
$ sudo yum install rhel-system-roles
Check timesync role is installed properly
$ ls -d /usr/share/ansible/roles/*.timesync
/usr/share/ansible/roles/rhel-system-roles.timesync
Write a playbook /home/ismat/ansible/timesync.yml
---
- name: use rhel system role to timesync
hosts: all
roles:
- rhel-system-roles.timesync
vars:
timesync_ntp_servers:
- hostname: 0.uk.pool.ntp.org
iburst: yes
...
Question 14: Write content filtered by host
Create a playbook called issue.yml in /home/ismat/ansible which changes the file /etc/issue on all managed nodes: If the host is a member of dev then write “Development” If the host is a member of test then write “Test” If the host is a member of prod then write “Production”
Solution:
Write a playbook /home/ismat/ansible/issue.yml
---
- name: change issue file
hosts: all
tasks:
- name: change dev hosts issue file
copy:
content: "Development"
dest: /etc/issue
when: '"dev" in group_names'
- name: change test hosts issue file
copy:
content: "Test"
dest: /etc/issue
when: '"test" in group_names'
- name: change prod hosts issue file
copy:
content: "Producation"
dest: /etc/issue
when: '"prod" in group_names'
...
Question 15: Schedule cron job
Create a playbook called regulartasks.yml which has the system that appends the date to /root/datefile every day at noon. Name is job ‘datejob’
Solution:
Write a playbook /home/sandy/ismat/regulartasks.yml
---
- name: cron
hosts: all
tasks:
- name: ensure a job that runs at noon
cron:
name: "datejob"
minute: "0"
hour: "12"
job: "date >> /root/datefile"
...
Question 16: Create and change password of vault file
Create an empty encrypted file called myvault.yml in /home/ismat/ansible and set the password to notsafepw. Rekey the password to iaiai202112.
Solution:
$ ansible-vault create myvault.yml
New Vault password:
Confirm New Vault password:
Check you set up the right password
$ ansible-vault view myvault.yml
Vault password:
Rekey the password
$ ansible-vault rekey myvault.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
Check rekey is successful
$ ansible-vault view myvault.yml
Vault password:
You can download all the playbooks from https://github.com/zillur00/ansible-exam