Ansible Sample Exam for EX407

This is a sample Ansible exam that I’ve created to prepare for EX407. I have not taken the EX407 exam yet.

No answers to the sample exam questions will be provided.

Requirements

There are 18 questions in total.

You will need five RHEL 7 (or CentOS 7) 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. The following FQDNs will be used throughout the sample exam.

  1. ansible-control.hl.local – Ansible control node
  2. ansible2.hl.local – managed host
  3. ansible3.hl.local – managed host
  4. ansible4.hl.local – managed host
  5. ansible5.hl.local – managed host

There are a couple of requiremens that should be met before proceeding further:

  1. ansible-control.hl.local server has passwordless SSH access to all managed servers (using the root user).
  2. ansible5.hl.local server has a 1GB secondary /dev/sdb disk attached.
  3. There are no regular users created on any of the servers.

Tips and Suggestions

I tried to cover as many exam objectives as possible, however, note that there will be no questions related to dynamic inventory.

Some questions may depend on the outcome of others. Please read all questions before proceeding.

Note that the purpose of the sample exam is to test your skills. Please don’t post your playbooks in the comments section.

Sample Exam Questions

Note: you have root access to all five servers.

Task 1: Ansible Installation and Configuration

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.

Create a configuration file /home/automation/plays/ansible.cfg to meet the following requirements:

  1. 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.
  2. The inventory file path is /home/automation/plays/inventory.
  3. Privilege escallation is disabled by default.
  4. Ansible should be able to manage 10 hosts at a single time.
  5. Ansible should connect to all managed nodes using the automation user.

Create an inventory file /home/automation/plays/inventory with the following:

  1. ansible2.hl.local is a member of the proxy host group.
  2. ansible3.hl.local is a member of the webservers host group.
  3. ansible4.hl.local is a member of the webservers host group.
  4. ansible5.hl.local is a member of the database host group.

Task 2: Ad-Hoc Commands

Generate an SSH keypair on the control node. You can perform this step manually.

Write a script /home/automation/plays/adhoc that uses Ansible ad-hoc commands to achieve the following:

  1. User automation is created on all inventory hosts.
  2. SSH key (that you generated) is copied to all inventory hosts for the automation user and stored in /home/automation/.ssh/authorized_keys.
  3. The automation user is allowed to elevate privileges on all inventory hosts without having to provide a password.

After running the adhoc script, you should be able to SSH into all inventory hosts using the automation user without password, as well as a run all privileged commands.

Task 3: File Content

Create a playbook /home/automation/plays/motd.yml that runs on all inventory hosts and does the following:

  1. The playbook should replace any existing content of /etc/motd with text. Text depends on the host group.
  2. On hosts in the proxy host group the line should be “Welcome to HAProxy server”.
  3. On hosts in the webserver host group the line should be “Welcome to Apache server”.
  4. On hosts in the database host group the line should be “Welcome to MySQL server”.

Task 4: Configure SSH Server

Create a playbook /home/automation/plays/sshd.yml that runs on all inventory hosts and configures SSHD daemon as follows:

  1. banner is set to /etc/motd
  2. X11Forwarding is disabled
  3. MaxAuthTries is set to 3

Task 5: Ansible Vault

Create Ansible vault file /home/automation/plays/secret.yml. Encryption/decryption password is devops.

Add the following variables to the vault:

  1. user_password with value of devops
  2. database_password with value of devops

Store Ansible vault password in the file /home/automation/plays/vault_key.

Task 6: Users and Groups

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: alice
    uid: 1201
  - username: vincent
    uid: 1202
  - username: sandy
    uid: 2201
  - username: patrick
    uid: 2202

Create a playbook /home/automation/plays/users.yml that uses the vault file /home/automation/plays/secret.yml to achieve the following:

  1. Users whose user ID starts with 1 should be created on servers in the webservers host group. User password should be used from the user_password variable.
  2. Users whose user ID starts with 2 should be created on servers in the database host group. User password should be used from the user_password variable.
  3. All users should be members of a supplementary group wheel.
  4. Shell should be set to /bin/bash for all users.
  5. Account passwords should use the SHA512 hash format.
  6. Each user should have an SSH key uploaded (use the SSH key that you created previously, see task #2).

After running the playbook, users should be able to SSH into their respective servers without passwords.

Task 7: Scheduled Tasks

Create a playbook /home/automation/plays/regular_tasks.yml that runs on servers in the proxy host group and does the following:

  1. A root crontab record is created that runs every hour.
  2. The cron job appends the file /var/log/time.log with the output from the date command.

Task 8: Software Repositories

Create a playbook /home/automation/plays/repository.yml that runs on servers in the database host group and does the following:

  1. A YUM repository file is created.
  2. The name of the repository is mysql56-community.
  3. The description of the repository is “MySQL 5.6 YUM Repo”.
  4. Repository baseurl is http://repo.mysql.com/yum/mysql-5.6-community/el/7/x86_64/.
  5. Repository GPG key is at http://repo.mysql.com/RPM-GPG-KEY-mysql.
  6. Repository GPG check is enabled.
  7. Repository is enabled.

Task 9: Create and Work with Roles

Create a role called sample-mysql and store it in /home/automation/plays/roles. The role should satisfy the following requirements:

  1. A primary partition number 1 of size 800MB on device /dev/sdb is created.
  2. An LVM volume group called vg_database is created that uses the primary partition created above.
  3. An LVM logical volume called lv_mysql is created of size 512MB in the volume group vg_database.
  4. An XFS filesystem on the logical volume lv_mysql is created.
  5. Logical volume lv_mysql is permanently mounted on /mnt/mysql_backups.
  6. mysql-community-server package is installed.
  7. Firewall is configured to allow all incoming traffic on MySQL port TCP 3306.
  8. MySQL root user password should be set from the variable database_password (see task #5).
  9. 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.pid

Create a playbook /home/automation/plays/mysql.yml that uses the role and runs on hosts in the database host group.

Task 10: Create and Work with Roles (Some More)

Create a role called sample-apache and store it in /home/automation/plays/roles. The role should satisfy the following requirements:

  1. The httpd, mod_ssl and php packages are installed. Apache service is running and enabled on boot.
  2. Firewall is configured to allow all incoming traffic on HTTP port TCP 80 and HTTPS port TCP 443.
  3. Apache service should be restarted every time the file /var/www/html/index.html is modified.
  4. A Jinja2 template file index.html.j2 is used to create the file /var/www/html/index.html with the following content:
The address of the server is: IPV4ADDRESS

IPV4ADDRESS is the IP address of the managed node.

Create a playbook /home/automation/plays/apache.yml that uses the role and runs on hosts in the webservers host group.

Task 11: Download Roles From an Ansible Galaxy and Use Them

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:

  1. Use geerlingguy.haproxy role to load balance request between hosts in the webservers host group.
  2. Use roundrobin load balancing method.
  3. HAProxy backend servers should be configured for HTTP only (port 80).
  4. 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 #10). Running the command again should return output from the other web server.

Task 12: Security

Create a playbook /home/automation/plays/selinux.yml that runs on hosts in the webservers host group and does the following:

  1. Uses the selinux RHEL system role.
  2. Enables httpd_can_network_connect SELinux boolean.
  3. The change must survive system reboot.

Task 13: Use Conditionals to Control Play Execution

Create a playbook /home/automation/plays/sysctl.yml that runs on all inventory hosts and does the following:

  1. If a server has more than 2048MB of RAM, then parameter vm.swappiness is set to 10.
  2. If a server has less than 2048MB of RAM, then the following error message is displayed:

Server memory less than 2048MB

Task 14: Use Archiving

Create a playbook /home/automation/plays/archive.yml that runs on hosts in the database host group and does the following:

  1. A file /mnt/mysql_backups/database_list.txt is created that contains the following line: dev,test,qa,prod.
  2. A gzip archive of the file /mnt/mysql_backups/database_list.txt is created and stored in /mnt/mysql_backups/archive.gz.

Task 15: Work with Ansible Facts

Create a playbook /home/automation/plays/facts.yml that runs on hosts in the database host group and does the following:

  1. A custom Ansible fact server_role=mysql is created that can be retrieved from ansible_local.custom.sample_exam when using Ansible setup module.

Task 16: Software Packages

Create a playbook /home/automation/plays/packages.yml that runs on all inventory hosts and does the following:

  1. Installs tcpdump and mailx packages on hosts in the proxy host groups.
  2. Installs lsof and mailx and packages on hosts in the database host groups.

Task 17: Services

Create a playbook /home/automation/plays/target.yml that runs on hosts in the webserver host group and does the following:

  1. Sets the default boot target to multi-user.

Task 18. Create and Use Templates to Create Customised Configuration Files

Create a playbook /home/automation/plays/server_list.yml that does the following:

  1. Playbook uses a Jinja2 template server_list.j2 to create a file /etc/server_list.txt on hosts in the database host group.
  2. The file /etc/server_list.txt is owned by the automation user.
  3. File permissions are set to 0600.
  4. SELinux file label should be set to net_conf_t.
  5. 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.

148 thoughts on “Ansible Sample Exam for EX407

  1. Hi @lisenet,

    Thanks for sharing this lab. I’ve used your RHCE lab for my studies and to be honest, in my humble option, your lab was harder than the proper exam itself. So I will use your lab again but this time for my EX407 studies and hopefully when I take the exam I will feel the same, and with a new cert on my belt.

    Thanks once again! :)

  2. Hello, Congratulations and thanks for this lab.
    First, I have a question about Task 5.
    How I can use condition with first caracter of userid?
    Thanks very much

    Fred

    • Hi, thanks very much! The goal of the sample exam is to test your Ansible skills. If you don’t know how to solve a task, then you need to work with Ansible documentation to find a solution. Good luck!

    • I had a hard time with this one but here is what I used.

      – name: create user for uid for webservers
      user:
      name: “{{item.username}}”
      password: “{{pass_works | password_hash(‘sha512’)}}”
      groups: wheel
      shell: /bin/bash
      ssh_key_file: .ssh/id_rsa
      generate_ssh_key: yes
      ssh_key_bits: 2048
      uid: “{{item.uid}}”
      when: ‘”webservers” in group_names and “12” in item.uid|string’
      loop: “{{users}}”
      – name: create user for uid for database
      user:
      name: “{{item.username}}”
      password: “{{pass_works | password_hash(‘sha512’)}}”
      groups: wheel
      shell: /bin/bash
      ssh_key_file: .ssh/id_rsa
      generate_ssh_key: yes
      ssh_key_bits: 2048
      uid: “{{item.uid}}”
      when: ‘”database” in group_names and “22” in item.uid|string’
      loop: “{{users}}”

    • Without posting a solution, I believe a helpful hint to solve this problem is regex.

    • you can also solve this by using multiple tasks using different hostgroup. so no conditions is needed and no regex is needed.

    • – name: create users WEBSERVERS
      user:
      name: “{{ item.username }}”
      uid: “{{ item.uid }}”
      groups: wheel
      shell: /bin/bash
      password: “{{ user_password|password_hash(‘sha512’, (256*256)|random(seed=inventory_hostname)|string) }}”
      when: “‘webservers’ in group_names and (item.uid|string)[0] == ‘1’”
      with_items:
      – “{{ users }}”

    • Nice Sample Exam Tomas well done!
      Solved all.

      If someone need a tip for solve some question I can give a hand too! :)

  3. Hello Tomas,
    I have a question ?

    What are differences between two conditions:

    when: “‘proxy’ in group_names”
    and
    when: ” {{ inventory_hostname in groups[‘proxy’] }}

    thanks you very much

    • The first one looks for a group membership in the array of all the groups the host is in.

      The second one checks if the hostname as configured in Ansible’s inventory host file belongs to a specific group in the inventory.

  4. Hello Tomas,

    How much focus I need to give for HA Load Balancing configurations for ansible exam.. i.e. Can I expect the configuration of HA using ansible or NOT ??

    • It’s usefull to know, so I’d suggest you to learn how to do it. Anything that falls under the exam objectives can be expected during the exam.

    • Hey,

      Just to clarify, task 12 that utilises RHEL System Roles would be only on the newer v2.7 exam.
      RHEL System Roles was available from RHEL 7.4 only and the Ansible v2.3 (407k exam) was based on RHEL 7.3 afaik

      Also, in the official RH learning guide for this course in Ansible v2.3 2017, System Roles are not covered at all but they are covered in the latest v2.7 2019 learning guide.

      In other words, if you are doing the 407kv27 exam, definitely learn it, if you are doing the older exam, I guess you are OK to skim it, BUT learn it anyway as it seems Red Hat is going to be pushing more and more official system roles to be released so you will encounter them in the real world.

      PS. Instead of using system roles, for v2.3 play around with modules like wait_for and async/polling as there is an overlap there in terms of end results.

      Love your work by the way Tomas.

    • Yea, you’re right. Ansible v2.3 exam was based on RHEL 7.3, therefore you can skip the system roles question if you want to.

    • for “Enables httpd_can_network_connect SELinux boolean”, we must use variables or use module?


    • – name: First Plays
      hosts: webservers
      tasks:
      – name: block
      block:
      – include_role:
      name: rhel-system-roles.selinux

      rescue:
      – name: debug
      fail:
      when: not selinux_reboot_required

      – name: reboot
      reboot:

      – include_role:
      name: rhel-system-roles.selinux

      AND

      group_vars/webservers.yml:

      selinux_booleans:
      – name: httpd_can_network_connect
      sate: on
      persistent: ‘yes’

    • Sorry,

      AND

      group_vars/webservers/webservers.yml:

      selinux_booleans:
      – name: httpd_can_network_connect
      sate: on
      persistent: ‘yes’

    • “Sometimes, the SELinux role must ensure managed hosts are rebooted in order to completely apply its changes. However, it does not ever reboot hosts itselfs. This is so that you can control how the reboot is handled. But it means that it is a little more complicated than usual to properly use this role in a play.
      The way this works is that the role will set a Boolean variable, selinux_reboot_required to true and fail if a reboot is needed’ RedHat

  5. Hi, Tomas

    great work, for question 17, I can only think of running the command modile with systemctl set-default multi-user

    but that’s not what you intended to test right? service module seem unable to set the target right?

    • Try to avoid the command module in playbooks, because it’s easy to write non-idempotent playbooks this way.

      What happens when you set the default target with a systemctl command? Have a think about it.

    • Hi, Tomas

      Many thanks for the prompt replies, really appreciate it.

      I am aware that the command modules should be avoided. I tried to use the systemd module, surprisingly it didn’t throw any error, but also it didn’t change the default target, have you verify that your target has changed?

      “`
      tasks:
      – name: change target with systemd
      systemd:
      name: multi-user.target
      state: started
      enabled: True
      “`

    • Hi, Tomas,

      Managed to think about a more idempotent solution, but still wouldn’t be super excited about it, as this is not really a solution for service.

      “`
      file:
      path: /etc/systemd/system/default.target
      src: /lib/systemd/system/multi-user.target
      state: link
      “`

    • Hi Tomas,
      “What happens when you set the default target with a systemctl command? Have a think about it”:

      systemctl create a symlink?
      maybe it’s preferable to use file module
      Thanks you very much

  6. Hi Tomas,
    I have question for Task 10:
    “Apache service should be restarted every time the file /var/www/html/index.html is modified.”
    We must use “handlers” after template module?
    Thanks you very much

  7. thanks you

    I have other question:
    My service will restart only when my template is copied.
    But if my file index.html is modify by others, my handler don’t works.

    • That’s expected, because the handler only runs when it’s triggered. If you have a process that modifies the file but does not trigger the handler, then the handler will not run.

  8. Curious about questions to relate to updating config files.

    Not about the answer, more about best practices. The simplest solution for updating configs seems to be using replace with regex and lineinfile modules. Is the best practice to use such modules against config files or to use templates that get copied over?

    • If you want to update a single line, then using a regex with lineinfile makes sense. If you have multiple lines that need changing, then using a template might be a better option.

  9. Hi Tomas,

    For “Task 2: Ad-Hoc Commands”, with whitch user we must run script?
    root ?
    Thanks you

  10. Thanks Tomas for the sample test. I have a question regarding the exam if you can help me out here.

    Will we get access to docs.ansible.com or some form of it during the RedHat exam or only ansible-doc is available?

  11. Hello Tomas,

    In task 6 , “Each user should have an SSH key uploaded (use the SSH key that you create previously)”,
    I don’t understant; we must use key file of automation user?
    Thanks a lot

    • good, i understood, when you say “previously”, we must use ssh keys that we have created during creation of users ( alice…etc)
      thanks

  12. Task 2 , is achieved using adhoc command or playbook or running a script on the destination server ?
    This statement is confusing ”
    Create an SSH keypair. Write a script /home/automation/plays/adhoc that uses Ansible ad-hoc commands to achieve the following:”

    If we have to use adhoc commands then we dont need to create a file.
    I know during the exam we will not be getting any explanation to the question.. it up to the students to analyze and sort out the problem. ( KIOSK Exams )

    • You have to write a script that uses ad-hoc commands. I’m sorry, but I don’t see anything confusing about this question.

  13. Task 6. Are we supposed to be parsing the first character of uid ? For the life of me I can’t parse it unless I force uid to be a string in the user_list.yml by surrounding the uid’s with double quotes. I could use , etc on the number but that is not what we are looking for either I suppose. Maybe i’m reading into your question too much ?

    Thank you for putting this together it is really making be dig into it and prep for the exam.

    Thanks,
    Phil

  14. Thank you for this post again, Tomas. I got my certification yesterday on ver. 2.7 and this exercise was extremely helpful. I am glad I found your site :)

  15. 2. SSH key (that you generated) is copied to all inventory hosts for the automation user and stored in /home/automation/.ssh/authorized_keys.

    Hi Tomas.
    in this question I must create ssh-key with script adhoc or I can create ssh-keygen before this script?
    Can you show ad-hoc comand for this question please.

  16. I tried for few hours, i could not find the substring or taking out first charecter from a string in the documentation, either i am dumb or its too much for a non genius to get certified. Giving up :(

  17. For task 6, I do that:


    – hosts: all
    become: yes

    vars_files:
    – secret.yml
    – user_list.yml

    tasks:
    – name: Creating users
    user:
    name: “{{ item.username }}”
    uid: “{{ item.uid }}”
    password: “{{ user_password | password_hash(‘sha512’) }}”
    shell: /bin/bash
    groups: wheel
    with_items: “{{ users }}”
    when: (( inventory_hostname in groups[‘webservers’] ) and ( “{{ item.uid }}” >= “1000” and “{{ item.uid }}” = “2000” and “{{ item.uid }}” = “1000” and “{{ item.uid }}” = “2000” and “{{ item.uid }}” < "3000" ))

  18. For task 6, I do that:

    – hosts: all
    become: yes

    vars_files:
    – secret.yml
    – user_list.yml

    tasks:
    – name: Creating users
    user:
    name: “{{ item.username }}”
    uid: “{{ item.uid }}”
    password: “{{ user_password | password_hash(‘sha512’) }}”
    shell: /bin/bash
    groups: wheel
    with_items: “{{ users }}”
    when: (( inventory_hostname in groups[‘webservers’] ) and ( “{{ item.uid }}” >= “1000” and “{{ item.uid }}” = “2000” and “{{ item.uid }}” < "3000" ))

    • this when statement also works for me:

      when: inventory_hostname in groups[‘webservers’] and item.uid|string|first == “1”

  19. @lisenet for question 18 . I Got some solution but I’m unable o get the full inventory, I’m able to take the inventory of webserver group only if I mention ‘all’, it throws an error.

    this is my templates– and can you tell me how to achieve all server inventory details.

    127.0.0.1 localhost
    ::1 locahost

    {% for host in groups[‘webserver’] %}
    {{ hostvars[host].ansible_default_ipv4.address }} {{ hostvars[host].ansible_facts.hostname }} {{ hostvars[host].ansible_facts.fqdn }}
    {% endfor %}

    • $ cat server_list.j2
      {% for host in groups[‘all’] %}
      {{hostvars[host][‘ansible_facts’][‘fqdn’]}}
      {% endfor %}

      $ cat server_list.yml

      – hosts: all
      become: yes
      tasks:
      – name: copy template
      template:
      src: server_list.j2
      dest: /etc/server_list.txt
      mode: ‘0600’
      setype: net_conf_t
      when: inventory_hostname in groups[‘database’]

    • the question says only apply to the database group not all. That’s what i am thinking too. If i set to all, i can easily get the results. Scratching my head for a solution.

  20. Thank you for those awesome questions! lisenet.

    for task 6. I am confused with the following two statements because my understanding is they are not same.

    *Each user should have an SSH key uploaded (use the SSH key that you create previously –if the ssh key is the same one specified in the Task 2, then the user, automation, can ssh into users’s respective servers as their account without passwords.)

    *After running the playbook, users should be able to SSH into their respective servers without passwords. — does it means users can ssh into their respective servers from the control node? then it needs these users exist and have their ssh key generated on the control node.

    • Thanks for your reply. Tomas :-)
      In task 2, it only asks to generate the ssh key for the user, automation. It does not mention to generate the ssh keys for other users on the control node.

      for the task 6, I use two plays in the playbook. the first play to create users and their ssh public key on control node, update known_hosts key for them. the second play to upload their ssh public key to their respective server. so the users can ssh their servers without password from the control node.

    • It does not have to. You can reuse the same SSH keys as many times and on as many users as you want.

      The goal of this sample example is to allow people to test theirs Ansible skills. Whether you write one play or two plays is irrelevant, as long as you solve the task. How you solve it is really up to you, because there is no one right answer.

  21. Thank you for the nice information, Tomas
    It is good to know. I never thought different accounts can use the same SSH keys(paired private/public SSH keys) for the SSH passwordless login before. it makes sense. I did a quick test and it works. Thanks again :-)

    • You’re welcome! It’s just a keypair, similar to TLS certificates, you can deploy them on multiple servers.

  22. First of all, i wanted to thank you for doing an awesome job, i’m planning to take the ansible exam in 5 weeks, i have noticed on the second task, when i try to modify the /usr/sbin/visudo file, it looks like its taking the changes but when you look inside the file, there’s nothing in there. So i ended up creating a file in the file in the /etc/sudoers.d

    Thank!

    • Thanks Tomas, awesome job.

      I use to change escalation privileges using /sbin/visudo (CentOS7). Can I keep using it or is there any module to change the escalation privileges?

  23. Thanks for the work you do for linux,
    Please point me to a reliable study guide for ex407 exam.
    I also have a situation where our remote servers do not permit remote root login via ssh, we use su to elevate from a normal user. My question is how do I su to root when deploying playbook as the ssh key if the support user not root without compromising security.
    thanks

    • I used DO407, if you have RHLS, that’s all you need.

      If you want to use su, then take a look at become_method: su.

  24. I’ve been using DO407 to study, that also includes a bit of Tower and Vagrant, however, I don’t see these mentioned as an objective on the EX407 exam. Would it be safe to assume they are not covered on the day?

  25. Hi, thank you for the tips, i have some questions:
    1- will this questions help me to pass EX294(RHEL8) exam. cause i heard both exams are basically the same.
    2- in Task10, you said “Apache service should be restarted every time the file /var/www/html/index.html is modified.”
    does this mean whenever i change index.html via the palybook or any change will trigger httpd to be restarted.
    3- how to note this questions to be near the actual exam questions.
    4- The services that appears in the tasks, are limited (for example only httpd and mysql), or we can face other complicated services such as (iscsi…ldap….)

    Thank you in advance.

    • The sample questions should help you to get an idea of what the exam might look like. If you can solve them all in less than 3 hours, then you are in a position to book the exam.

      With regards to the #10, the service should be restarted every time the playbook modifies the index file.

      In theory you can expect any service that is covered by official Red Hat training to appear on the exam.

  26. I don’t see how it’ meant to create ad-hoc script for generating SSH-KEYS on the nodes when you haven’t provisioned the controller’s key?

    • As the tasks says, you need to generate an SSH keypair on the control node and then copy the files to all inventory hosts for the automation user.

  27. Hi,
    Just wanted to say thank you for putting together this excellent practice exam. Unfortunately for me I discovered it too late (literally a day before my EX294 exam). I did not make it but plan a retake after practicing with this exam and being able to complete it within 3 hours. I literally ran out of time…

  28. Hi Everyone,

    In my practice lab I am working on below mention scenario,

    1. Create a logical volume (“mylvol1”) of size 1024M on volume group (“myvg1”)
    With Given conditions:
    a. If volume group doesn’t exist, message “Volume Group does not exist” should be displayed.
    b. If there is not enough free space in volume group (“myvg1”), message “Not enough Free Space” should be displayed. And logical volume (“mylvol1”) should be created with 700M size instead of 1024M.

    I am unable to create logic for condition “b”, please guide me.

    Thanks.

    • The logic for part b should be something like this:

      Check the disk space of the volume group, if it’s less that the required volume size, then display the message, if it’s greater that the required volume size, then create the volume.

  29. Tomas, I am not exaggerating or making up stories here. but the grading in RHCE is really weird. The script that they are running to check your config and output is unimaginable. :) But I am an RHCE now.
    My serious question to you.

    What do you think Ansible exam? you got 300/300. Are they just focus on the result? they dont care about your playbook etc?

    Is this just a result based?

    • I think that it’s an interesting yet challenging exam that requires you to know Ansible really well. As with all Red Hat exams, you need to solve problems, and the outcome is what matters the most from my experience.

      There are different ways you can write a playbook that achieves a specific goal (e.g. creates a new partition). The content of such playbook will depend on your experience and familiarity with the tool. As long as your playbook creates a partition, you should receive points for the task.

      It helps if you approach Red Hat exams from a customer’s point of view (pretty much what happens in reality). If a customer asks you to deploy a new website, they expect the end result to be a running website, they don’t care that much whether you use Apache, Nginx or Lighttpd to deliver the solution.

  30. Hi Tomas

    I wrote my ex294 and passed thanks to you. Honestly when I first found this page , I found many of the questions challenging, but after some practice it was a breeze . Thanks again

  31. Hi Tomas,

    For task 5, does it matter if we modify the user_list.yml file? Like so:


    users:
    – username: alice
    uid: 1201
    – username: vincent
    uid: 1202
    – username: sandy
    uid: 2201
    – username: patrick
    uid: 2202

  32. question no.2 “/home/automation/plays/adhoc” a directory?
    do files containing ad hoc commands need to be in a directory?

  33. Hi,

    For task 11 “Use geerlingguy.haproxy role to load balance request between hosts in the webservers host group”, the value of backend should be set automatically based on the inventory ?

    The var haproxy_backend_servers can be dynamically created ?

  34. I would to share my solution for task 6 , thats so hard but I do it :D ! I hope to schedule the exam in january in 2020.

    – hosts: all
    become: true
    vars_files:
    – user_list.yml
    – secret.yml
    tasks:
    – user:
    name: “{{ item.username }}”
    uid: “{{ item.uid }}”
    password: “{{ user_password | password_hash(‘sha512’) }}”
    shell: /bin/bash
    groups: wheel
    with_items: “{{ users }}”
    when:
    – “‘webservers’ in group_names and item.uid|string|first == ‘1’ ”
    – user:
    name: “{{ item.username }}”
    uid: “{{ item.uid }}”
    password: “{{ user_password | password_hash(‘sha512’) }}”
    shell: /bin/bash
    groups: wheel
    with_items: “{{ users }}”
    when:
    – “‘database’ in group_names and item.uid|string|first == ‘2’ “

    • Hi,
      Nice one on the item.uid|string|first == ‘1’ !
      I see you’re using ‘with_items: “{{ users }}”’. I’ve seen this in a lot of other playbooks as well and I was wondering what the preferred way is?
      The official RedHat course materials for EX294-8.0 state that since Ansible 2.5, the recommended way to write loops is to use the loop keyword. However, you do need to know the with_items keyword because you can encounter it in older playbooks…
      I’m guessing you should still get a pass if you use the older style, seeing as that it still works.

    • Hi Serge thanks for your tip!

      I’ve revisited the ansible documentation for loop scenarions and yes they recommend use loop than with_items.

      I will force me to write with loop .

      Thanks!

  35. So for task 6 is there any reason why my playbook would not be idempotent? Not sure how to ask this without giving the answer away. I’m simply user the user module to loop through the users list provided with appropriate conditionals targeting the UID and the server’s group membership. It works as expected but I always get a changed result when I run it.

  36. Hi,

    I passed the ex407 and now i want to take the EX294. Is there a difference? Do I need to study extra for the EX294? or can I directly book my exam?

    • I didn’t take EX294 so don’t take my word for it, but looking at the exam objectives as well as Red Hat training material they are almost identical. If you studied and passed EX407, you should be able to pass EX294 because the objectives are 95% the same.

  37. Task 16 asks us to run the playbook against all hosts but then says to only define a variable for groups proxy and database. This means the playbook would fail against the webservers group as the variable wouldn’t be defined. I’m assuming that the solution here is to implement a conditional on the task to only run when the packages variable is defined? Seems like the obvious fix but wanted to confirm that there’s nothing else I’m missing.

    Thanks!

    • Task 16 asks you to run the playbook against all hosts and install packages based on host groups. Whether you decide to use variables or not is completelly up to you.

    • Makes sense. Thanks

      BTW I just passed the ex294 with a 276 in large part due to this site. So thanks for the quality material as usual!

  38. Hi Tomas,
    Just did my EX294 re-take and passed it with a 279 score. So just wanted to say a big THANK YOU for putting this sample exam together, it has been a great help! In fact more so, in my opinion, than the lab materials offered with the official RH294 course on RHLS….

    If anyone is interested, I will post a terraform plan, an ansible playbook and a few ancillary scripts to easily build, configure and start, stop a lab, on github that you could use to practice this sample exam.

    Requirements are:
    – KVM installed (works on CentOS 8 and Fedora 30)
    – RHEL8 qcow2 image (you can download this if you have a free Red Hat developer account, it’s only 713MB).
    – about 6GB of memory available on your system (I’ve given all VMs 1024MB of memory but you can easily change this)
    – Approx 14GB of free space on root

  39. Fabiano, first of all congratulations for the fact, that you’ve managed to pass the EX407 exam. I would like to ask you, if the questions given by Tomas ( Tomas, your sample exam, appears to cover almost 100% of the topics, great job!!! ) were more difficult than the “real” ones and if there was a mandatory bash script creation on the exam?
    Thank you in advance

  40. Hi
    I prepare for EX294 and i have following question:
    I configure partition on disk with condition, when size is too big for disk, fail, display message.
    I do something like that:
    tasks:
    – name: block for disk
    block:
    – name: check size
    parted:
    device: /dev/vdb
    number: 1
    state: present
    part_end: 1GiB
    register: disk_data
    ignore_errors: yes
    – name: fail size
    fail:
    msg: “{{ disk_data.failed }} ERROR”
    when: disk_rozmiar.failed == 1

    It’s work, but I wonder about when condition.
    In my registered variable key failed it’s only I think for check that size is ok or not.
    This is output from registered variable:
    “msg”: {
    “changed”: true,
    “disk”: {
    “dev”: “/dev/vdb”,
    “logical_block”: 512,
    “model”: “Virtio Block Device”,
    “physical_block”: 512,
    “size”: 2097152.0,
    “table”: “msdos”,
    “unit”: “kib”
    },
    “failed”: false,
    “partitions”: [],
    “script”: “rm 1”
    }

    It’s this condition is properly set, or maybe i’m doing something wrong.
    Regards

    • Hi
      i want achieve, that when a partition size is a bigger than free disk space, then I have error msg in play, and from rescue block tasks are run
      Regards
      Tom

    • OK, what you want to do is to gather disk size info and register it so that you can use it later. Then implement a logical operation where an error message is displayed if the partition size is bigger that the disk size.

      There are several ways you can get disk size info, you can use stat, you can use parted, or you can use Ansible facts.

      Take a look at one of my Ansible playbooks on GitHub.

  41. Hello Tomas,

    Quick Question. For the task 12.
    “Uses the selinux RHEL system role”

    Should I install system role using galaxy and use them?

  42. Hi Tom,

    Task 2: Can you please clarify how can automation user on control node use ansible adhoc commands to setup itself (automation) on managed hosts when the user itself doesn’t exist there?

    Thank you

  43. Thank you Tom!

    Task 1: requires privilege escalation disabled by default. With this in place, is the expectation for automation user to be able to run privileged commands on managed hosts without manually using -b | –become ? If this is true then I don’t understand how could that be, please help me understand.

    • It means that you need to disable by default. It doesn’t say that you can’t use privilege escallation.

Leave a Reply to Tim Cancel reply

Your email address will not be published. Required fields are marked *