These are a few practice exams to get ready for the Red Hat Certified Engineer exam
The first practice exam was created by Lisenet . The practice exams cover as many of the exam objectives as possible
- You will need five RHEL 8 virtual machines to be able to successfully complete all questions.
- One VM will be configured as an Ansible control node.
- Other four VMs will be used to apply playbooks to solve the sample exam questions.
- Task 1 :
Install ansible package on the control node (including any dependencies) and configure the following:- 1 - Create a regular user automation with the password of devops. Use this user for all sample exam tasks.
- 2 - All playbooks and other Ansible configuration that you create for this sample exam should
be stored in /home/automation/plays.
- 3 - Create a configuration file /home/automation/plays/ansible.cfg to meet the following requirements:
- The roles path should include /home/automation/plays/roles, as well as any other path that may be required for the course of the sample exam.
- The inventory file path is /home/automation/plays/inventory.
- Privilege escallation is disabled by default.
- Ansible should be able to manage 10 hosts at a single time.
- Ansible should connect to all managed nodes using the automation user.
- Create an inventory file /home/automation/plays/inventory with the following:
- ansible2.hl.local is a member of the proxy host group.
- ansible3.hl.local is a member of the webservers host group.
- ansible4.hl.local is a member of the webservers host group.
- ansible5.hl.local is a member of the database host group
Task 2 :
- Generate an SSH key pair on the control node for the automation user. You can perform this step manually.
- Write a script /home/automation/plays/adhoc.sh that uses Ansible ad-hoc commands to achieve the following:
- User automation is created on all inventory hosts.
- The SSH public key that you just generated is copied to all managed hosts for the automation user.
- The automation user has full sudo access on all managed nodes without having to provide a password.
After running the adhoc.sh bash script, you should be able to SSH into all managed hosts using the automation user without a password, as well as a run all privileged commands.
Task 3 :
Create a playbook /home/automation/plays/motd.yml that runs on all inventory hosts and does the following:
The playbook should replace any existing content of /etc/motd with text. Text depends on the host group.- On hosts in the proxy host group the line should be “Welcome to HAProxy server”.
- On hosts in the webserver host group the line should be “Welcome to Apache server”.
- On hosts in the database host group the line should be “Welcome to MySQL server”
Task 4 :
Create a playbook /home/automation/plays/sshd.yml that runs on all inventory hosts and configures SSHD daemon as follows:
- banner is set to /etc/motd
- X11Forwarding is disabled
- MaxAuthTries is set to 3
- Task 5 :
Create Ansible vault file /home/automation/plays/secret.yml. Encryption/decryption password is devops.
Add the following variables to the vault:- user_password with value of devops
- database_password with value of devops
- Task 6 :
You have been provided with the list of users below. Use /home/automation/plays/vars/user_list.yml file to save this content.
---
users:
- username: aliceuid: 1201
- username: vincentuid: 1202
- username: sandyuid: 2201
- username: patrickuid: 2202- Create a playbook /home/automation/plays/users.yml that uses the vault file /home/automation/plays/secret.yml to achieve the following:
- Users whose user ID starts with 1 should be created on servers in the webservers host group.
- Users whose user ID starts with 2 should be created on servers in the database host group.
- All users should be members of a supplementary group wheel. All users password should be used from the user_password variable
- Shell should be set to /bin/bash for all users.
- Account passwords should use the SHA512 hash format.
After running the playbook, users should be able to SSH into their respective servers without passwords.
- Task 7 :
- Create a playbook /home/automation/plays/regular_tasks.yml that runs on servers in the proxy host group and does the following:
- A root crontab record is created that runs every hour.
- The cron job appends the file /var/log/time.log with the output from the date command.
Task 8 :
Create a playbook /home/automation/plays/repository.yml that runs on servers in the database host group and does the following:- A YUM repository file is created.
- The name of the repository is mysql56-community.
- The description of the repository is “MySQL 5.6 YUM Repo”.
- Repository baseurl is http://repo.mysql.com/yum/mysql-5.6-community/el/7/x86_64/.
- Repository GPG key is at http://repo.mysql.com/RPM-GPG-KEY-mysql.
- Repository GPG check is enabled.
- Repository is enabled.
Task 9 :
Create a role called sample-mysql and store it in /home/automation/plays/roles. The role should satisfy the following requirements:
- A primary partition number 1 of size 800MB on device /dev/sdb is created.
- An LVM volume group called vg_database is created that uses the primary partition created above.
- An LVM logical volume called lv_mysql is created of size 512MB in the volume group vg_database.
- An XFS filesystem on the logical volume lv_mysql is created.
- Logical volume lv_mysql is permanently mounted on /mnt/mysql_backups.
- mysql-community-server package is installed.
- Firewall is configured to allow all incoming traffic on MySQL port TCP 3306.
- MySQL root user password should be set from the variable database_password (see task #5).
- MySQL server should be started and enabled on boot. 10.MySQL server configuration file is generated from the my.cnf.j2 Jinja2 template with the following content:
[mysqld]
bind_address = {{ ansible_default_ipv4.address }}
skip_name_resolve
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pidCreate a playbook /home/automation/plays/mysql.yml that uses the role and runs on hosts in the database host group. Solution of Task9
- Task 10 :
Use Ansible Galaxy to download and install geerlingguy.haproxy role in /home/automation/plays/roles. Create a playbook /home/automation/plays/haproxy.yml that runs on servers in the proxy host group and does the following:- Use geerlingguy.haproxy role to load balance request between hosts in the webservers host group.
- Use roundrobin load balancing method.
- HAProxy backend servers should be configured for HTTP only (port 80).
- Firewall is configured to allow all incoming traffic on port TCP 80. If your playbook works, then doing “curl http://ansible2.hl.local/” should return output from the web server (see task #9 ). Running the command again should return output from the other web server.
- Task 11 :
Create a playbook /home/automation/plays/selinux.yml that runs on hosts in the webservers host group and does the following:- Uses the selinux RHEL system role.
- Enables httpd_can_network_connect SELinux boolean.
- The change must survive system reboot
- Task 12 :
Create a playbook /home/automation/plays/sysctl.yml that runs on all inventory hosts and does the following:- If a server has more than 2048MB of RAM, then parameter vm.swappiness is set to 10.
- If a server has less than 2048MB of RAM, then the following error message is displayed: Server memory less than 2048MB
- Task 13 :
Create a playbook /home/automation/plays/archive.yml that runs on hosts in the database host group and does the following:- A file /mnt/mysql_backups/database_list.txt is created that contains the following line: dev,test,qa,prod.
- A gzip archive of the file /mnt/mysql_backups/database_list.txt is created and stored in /mnt/mysql_backups/archive.gz
Task 14 :
Create a playbook /home/automation/plays/packages.yml that runs on all inventory hosts and does the following:
- Installs tcpdump and mailx packages on hosts in the proxy host groups.
- Installs lsof and mailx and packages on hosts in the database host groups.
- Task 15 :
Create a playbook /home/automation/plays/target.yml that runs on hosts in the webserver host group and does the following:- Sets the default boot target to multi-user.
- Task 16 :
Create a playbook /home/automation/plays/server_list.yml that does the following:- Playbook uses a Jinja2 template server_list.j2 to create a file /etc/server_list.txt on hosts in the database host group.
- The file /etc/server_list.txt is owned by the automation user.
- File permissions are set to 0600.
- SELinux file label should be set to net_conf_t.
- The content of the file is a list of FQDNs of all inventory hosts. After running the playbook, the content of the file /etc/server_list.txt should be the following: ansible2.hl.local ansible3.hl.local ansible4.hl.local ansible5.hl.local Note: if the FQDN of any inventory host changes, re-running the playbook should update the file with the new values.
Ansible-installation : # yum list installed platform-python # yum install ansible # ansible --version 1- # useradd automation # echo "devops" | passwd --stdin automation 2- # su - automation # mkdir plays ; cd plays 3- # vim ansible.cfg ## Ansible.config file [defaults]role_path = ./rolesinventory = ./inventoryforks = 10remote_user = automation [privilege_escalation]become = False# vim inventory [proxy]ansible2.hl.local [webservers]ansible3.hl.local ansible4.hl.local [database]ansible5.hl.local # ansible all --list-hosts# echo "automation ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/automation# ssh-keygen # vim adhoc.sh #!/bin/bash# you can specify the inventory file with -i option
ansible all -m user -a "user='automation'\ comment='User Create by Ansible'" -u root --ask-pass ansible all -m authorized_key -a "user=automation state=present \ key={{ lookup('file', '/home/automation/.ssh/id_rsa.pub') }}" -u root --ask-pass
ansible all -m copy -a "src='/etc/sudoers.d/automation' dest='/etc/sudoers.d/'" -u root --ask-pass
# chmod 755 adhoc.sh # ./adhoc.sh# mkdir group_vars ; cd group_vars# echo "message: Welcome to HAProxy server" >> proxy# echo "message: Welcome to Apache server" >> webserver# echo "message: Welcome to MySQLserver" >> database--- - name: Customize the message of the dayhosts: alltasks:
- name: Create the message of the day according to the managed hostcopy:
content: "{{ message }}"dest: /etc/motd owner: rootgroup: root mode: '0644'
...# vim defaults/main.yml # sshd config variables
ssh_config: - start_line: "^banner"
line: "banner /etc/motd"
- start_line: "X11Forwarding"
line: "X11Forwarding no"
- start_line: "^#MaxAuthTries"
line: "MaxAuthTries yes"--- - name: Configure the sshd service hosts: all vars_files:
- defaults/main.ymltasks: - name: Adding sshd config lineinfile:
path: /etc/ssh/sshd_config regexp: "{{ item.start_line }}"line: "{{ item.line }}"loop: "{{ ssh_config }}"notify: restart sshd # don't forget to restart the servicehandler:
- name: restart sshd service: name: sshd state: restarted
...
# ansible all -m command -a 'grep "MaxAuthTries" /etc/ssh/sshd_config' # ansible-vault create secret.yml
New Vault password: devops
Confirm New Vault password: devops
---
user_password: devops
database_password: devops
using the decr with vault-file :# vim vault-key
devops
# chmod 400 vault-key # ansible-vault view secret.yml --vault-password-file vault-key
---
user_password: devops
database_password: devops---
- name: Create usershosts: allbecome: yesvars_files:
- ./users_list.yml
- ./secret.ymltasks:
- name: Ensure group is existgroup:
name: wheelstate: present
- name: Create users that starts with 1 in their uiduser:
name: "{{ item.username }}"group: wheelpassword: "{{ user_password | password_hash('sha512') }}"shell: /bin/bashupdate_password: on_createwith_items: "{{ users }}"when:
- ansible_fqdn in groups['webservers']
- "item.uid|string|first == '1'"
- name: Create users that starts with 2 in their uiduser:
name: "{{ item.username }}"group: wheelpassword: "{{ user_password | password_hash('sha512') }}"shell: /bin/bashupdate_password: on_createwith_items: "{{ users }}"when:
- ansible_fqdn in groups['database']
- "item.uid|string|first == '2'"---
- name: Scheduled taskshosts: proxybecome: yestasks:
- name: Ensure file existsfile:
path: /var/log/time.logstate: touchmode: 0644
- name: Create cronjob for root usercron:
name: "check time"hour: "*/1"user: rootjob: "date >> /var/log/time.log"---
- name: Software repositorieshosts: databasebecome: yestasks:
- name: Create msyql repositoryyum_repository:
name: mysql56-communitydescription: "MySQL 5.6 YUM Repo"baseurl: "http://repo.mysql.com/yum/mysql-5.6-community/el/7/x86_64/"enabled: yesgpgcheck: yesgpgkey: "http://repo.mysql.com/RPM-GPG-KEY-mysql"# ansible database -m command -a 'cat /etc/yum.repos.d/MariaDB-10.5.repo' -b# cd roles # ansible-galaxy init sample-mysql# cd sample-mysql# vim vars/main.yml
---
partitions: - number: 1start: 1MiBend: 800MiBdevice: /dev/sdbvolume_groups: - name: vg_databasedevice: /dev/sdb1 logical_volumes: - name: lv_mysql size: 512MiBvgroup: vg_databasemount_path: /mnt/mysql_backups mysql_service: mariadbmysql_packages:
- mariadb
- mariadb-server
- python3-PyMySQL
...
# vim tasks/main.yml
---
- name: Create a primary partition on /dev/sdb parted: device: "{{ item.device }}"number: "{{ item.number }}"part_start: "{{ item.start }}"part_end: "{{ item.end }}"part_type: primarystate: presentunit: MiBloop: "{{ partitions }}"
- name: Ensure Volume group exist lvg: vg: "{{ item.name }}"pvs: "{{ item.device }}"loop: "{{ volume_groups }}" - name: Ensure Logical Volume exist lvol: lv: "{{ item.name }}"vg: "{{ item.vgroup }}"size: "{{ item.size }}"state: presentloop: "{{ logical_volumes }}"when: item.name not in ansible_lvm["lvs"]
- name: Create XFS filesystem filesystem: dev: "/dev/{{ item.vgroup }}/{{ item.name }}"type: xfsloop: "{{ logical_volumes }}" - name: Ensure Correct Capacity for {{ lv_name }}lvol:
vg: "{{ item.vgroup }}"lv: "{{ item.name }}"size: "{{ item.size }}"resizefs: trueforce: yesloop: "{{ logical_volumes }}"## remembre that the fs XFS does not support shrinking capacity
- name: Ensure the FS is mounted mount: src: /dev/{{ item.vgroup }}/{{ item.name }}"path: "{{ item.mount_path }}"fstype: xfs state: mountedloop: "{{ logical_volumes }}" - name: Ensure mysql is installedyum:
name: "{{ packages }}"state: present
- name: Ensure MySQL is enabled and startedservice: name: "{{ mysql_service }}"state: startedenabled: true
- name: Enable MySQL in firewalld firewalld: service: "{{ mysql_service }}"state: enabled permanent: trueimmediate: true
- name: Change MySQL root user passwordmysql_user: name: root password: "{{ database_password }}"state: present
- name: Copy my.cnf.j2 to /etc/my.cnftemplate:
src: my.cnf.j2dest: /etc/my.cnfnotify: restart mysql # vim handlers/main.yml
---
- name: restart mysql service: name: "{{ mysql_srv }}"state: restarted# vim templates/my.cfg.j2{{ ansible_managed }}[mysqld]bind_address = {{ ansible_facts['default_ipv4']['address'] }}skip_name_resolvedatadir = /var/lib/mysqlsocket = /var/lib/mysql/mysql.socksymbolic-links = 0sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES[mysqld_safe]log-error = /var/log/mysqld.logpid-file = /var/run/mysqld/mysqld.pid# vim mysql.yml
--- - name: Install mysql role hosts: databsevars_files:
- secret.ymlroles: sample-mysql# ansible-galaxy install geerlingguy.haproxy -p roles/---
- name: Configure HAPROXYhosts: proxybecome: yesroles:
- geerlingguy.haproxyvars:
haproxy_frontend_port: 80haproxy_frontend_mode: 'http'haproxy_backend_balance_method: 'roundrobin'haproxy_backend_servers:
- name: app1address: 10.0.0.23 # The @ ip of the webservers
- name: app2address: 10.0.0.25tasks:
- name: Ensure firewalld and its dependencies are installedyum:
name: firewalldstate: latest
- name: Ensure firewalld is runningservice:
name: firewalldstate: startedenabled: yes
- name: Ensure firewalld is allowing to the trafficfirewalld:
port: 80/tcppermanent: yesimmediate: yesstate: enabled# ansible proxy -m command -a 'systemctl is-enabled haproxy' -b# curl http://ansible2.hl.local/If you get stuck and forget the syntax, try this command :
# find /usr/share/ -iname example-selinux* ---
- name: Configure SELinuxhosts: webserversbecome: truetasks:
- name: Configure SELinuxblock:
- include_role:
name: rhel-system-roles.selinuxrescue:
# Fail if failed for a different reason than selinux_reboot_required.
- name: handle errorsfail:
msg: "role failed"when: not selinux_reboot_required
- name: restart managed hostreboot:
msg: "Ansible updates triggered"ignore_errors: true
- name: wait for managed host to come back wait_for_connections: delay: 10timeout: 300
- name: reapply the roleinclude_role:
name: rhel-system-roles.selinux---
- name: Set sysctl Parametershosts: allbecome: truevars: min_ram_mb: 2048tasks:
- name: Print error messagedebug:
msg: "Server memory less than 2048MB"when: ansible_memtotal_mb < min_ram_mb
- name: set vm.swappiness to 10sysctl:
name: vm.swappinessvalue: '10'state: presentwhen: ansible_memtotal_mb > min_ram_mb--
- name: Use Archivinghosts: databasebecome: yestasks:
- name: Create a directory if it does not exist file:
path: /mnt/mysql_backups/state: directorymode: 0775owner: rootgroup: root
- name: Copy the contentcopy:
content: "dev,test,qa,prod"dest: /mnt/mysql_backups/database_list.txt
- name: Create archivearchive:
path: /mnt/mysql_backups/database_list.txtdest: /mnt/mysql_backups/archive.gzformat: gz--### Solution of Task14
---
- name: Install packageshosts: allbecome: yestasks:
- name: Installs tcpdump and mailx packages on hosts in the proxy host groupsyum:
name:
- tcpdump
- mailxstate: latestwhen: inventory_hostname in groups['proxy']
- name: Installs lsof and mailx and packages on hosts in the database host groupsyum:
name:
- lsof
- mailxstate: latestwhen: inventory_hostname in groups['database']---
- name: default boot targethosts: webserversbecome: yestasks:
- name: Set default boot target to multi-userfile:
src: /usr/lib/systemd/system/multi-user.targetdest: /etc/systemd/system/default.targetstate: link# vim server_list.j2{% for host in groups['all'] %}{{ hostvars[host].inventory_hostname }}{% endfor %}# vim server_list.yml
---
- name: Create and Use Templates to Create Customised Configuration Fileshosts: databasebecome: yestasks:
- name: Create server listtemplate:
src: ./server_list.j2dest: /etc/server_list.txtowner: cloud_usermode: '0600'setype: net_conf_t- Will be updated soon
