Ansible Sample Exam for RHCE EX294 and EX407

This is a sample Ansible exam that I’ve created to prepare for the new RHCE exam EX294.

As with the real exam, no answers to the sample exam questions will be provided.

Requirements

There are 18 questions in total.

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. 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 and playbooks, unless you are working on the task #2 that requires creating the automation user on inventory hosts. You have root access to all five servers.
  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 (not the control node).
  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 on the control node as the automation user, 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 webservers 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 mysql80-community.
  3. The description of the repository is “MySQL 8.0 YUM Repo”.
  4. Repository baseurl is http://repo.mysql.com/yum/mysql-8.0-community/el/8/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 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 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 webservers 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.

Disclaimer

If you have taken the RHCE exam, please honour the NDA that you had signed before sitting the exam, and DO NOT POST comments discussing exam tasks and questions. Comments discussing exam content will be removed.

723 thoughts on “Ansible Sample Exam for RHCE EX294 and 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! :)

    • I adhere to Jhonatan comments, i used your guide on RHCE, and got my certification. So now onto Ansible with this guide. if it helps on something i did the prep-course on Linux Academy, and this guide is way harder and has more content.
      i just wanted to put my comment to thank you for your amazing work with this site which became my default “go to” when i’m studying any new subject.
      My most sincere thanks to you Tomas.

  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 }}”

    • Tomas
      Solved it with creating role, delegate_to and post_tasks :-)
      I hope that this is one of the proper solutions.

    • Hello Adam,
      Create role is not necessar for the Task18, just create template with magic variables.
      Thanks

    • For task 18, do we use vim editor and manually create the template file (server_list.j2) beforehand and then create the playbook (server_list.yml) to call the template file (server_list.j2) to create the /etc/server_list.txt on the managed nodes ? or do we create a playbook (server_list.yml) to dynamically create the the template file (server_list.j2) and then call the template file (server_list.j2) to create the /etc/server_list.txt on the managed nodes?

      Thanks.

  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" ))

    • This is wrong. When the UID is 20000 it will not work. You can do (item.uid | string) is regex(‘^1’)

  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.

    • Use this to gather facts all servers

      tasks:
      – name: Gather the fact from all servers
      setup:
      delegate_to: “{{ item }}”
      delegate_facts: true
      with_items: “{{ groups[‘all’] }}”

  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 :-)

  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 ?

    • Can someone had a response of this ?
      I tried multiple solution but won’t be able to construct this variable with this structure
      haproxy_backend_servers:
      – name: foo-app
      address: foo-address
      – name: bar-app
      address: bar-address

    • You can do something like this:

          haproxy_backend_servers:
            - name: web1
              address: ansible3.hl.local:80
            - name: web2
              address: ansible4.hl.local:80
    • haproxy_backend_server can be dynamically created. But I would say that is a more advanced practice, should not be part of a basic exam like this.


      – name: Collect webservers
      hosts: all
      tasks:
      – name: Register webservers
      set_fact:
      webservers: “{{ webservers|default([]) + [ {‘name’: item.ansible_hostname, ‘address’: item.ansible_default_ipv4.address+’:80′} ] }}”
      delegate_to: localhost
      with_items: “{{ groups.webservers | map(‘extract’, hostvars) | list }}”

      – name: Task 11 – HAproxy
      hosts: proxy
      become: True

      pre_tasks:
      – name: Debug
      debug:
      msg: “{{ webservers }}”

      tasks:
      – name: Open port on FW
      firewalld:
      service: http
      permanent: yes
      state: enabled
      immediate: True

      roles:
      – name: geerlingguy.haproxy
      vars:
      haproxy_frontend_name: ‘hafrontend’
      haproxy_frontend_port: 80
      haproxy_frontend_mode: ‘http’

      haproxy_backend_name: ‘habackend’
      haproxy_backend_mode: ‘http’
      haproxy_backend_balance_method: ’roundrobin’

      haproxy_backend_servers: “{{ webservers }}”

  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!

    • you can simplify your playbook by using one task

      – name: ansible playbook task 06
      hosts: all
      vars_files:
      – user_list.yml
      – secret.yml
      become: yes
      tasks:
      – user:
      name: “{{item.username}}”
      uid: “{{item.uid}}”
      password: “{{user_password|password_hash(‘sha512’)}}”
      groups: wheel
      shell: /bin/bash
      loop: “{{users}}”
      when: (ansible_fqdn in groups[‘webservers’] and item.uid|string|first == “1”) or (ansible_fqdn in groups[‘database’] and item.uid|string|first == “2”)

  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.

  44. Thank you

    I am preparing for EX294 towards RHCE, anyone know if there are more sample exams and any other practice, preparation for EX294?

    thanks for help

  45. Hi Tom,

    Task 6: Instruction is not clear to me how the users would be able to ssh to inventory hosts without passwd using the key already created for automation user from (task 2)?

    How would the key from one user allow another user to ssh to a remote server ?

    Thank you

  46. For the sample exam if that’s what needed ….. great. But for my own understanding I still don’t get it.

    Thank you

    • When you use ssh-keygen to generate a public/private RSA key pair it does just that – creates a key pair. The key pair can be used with any user on any system. You would normally have a key pair per user account, however, this is not set in stone.

      You can use the same key pair for multiple users if you want to. It’s the same thing as if you were to use identical passwords for different user accounts. I hope this clarifies things for you.

  47. Hello Guys,

    While working on my lab, I’m not getting correct idea.

    1. While Creating a logical volume (“mylv1”) of size 1200M on volume group (“myvg1”)

    2. If volume group doesn’t exist with enough space then it should display message “Volume Group does not have enough space” should be displayed.

    3. If there is not enough free space in volume group (“myvg1”), message “Not enough Free Space” should be displayed. And logical volume (“mylv1”) should be created with 600M size instead of 1200M.

    I’m unable to write logic

    Thanks in advance.

    • The logic could be something like this:

      1. Check if the volume group exists.
      2. If it does not exist, print an error message.
      3. If it does exist, check the size of the volume group.
      4. If the size is sufficient, proceed with volume creation.
      5. If the size is insufficient, display an error message.

  48. Task 8: In the thread above I see rpm_key being suggested. If the read task 8 instructions it does not ask to install the gpg key. My understanding the key will be applied automatically for any package installs from the repo.

    Is it really required to install the key?

    Thanks

  49. Doubt on Task1 and Task2
    Task1 – says that the user that the adhoc scripts and playbooks should run as automation user
    Task2 – says to create the user automation on all the managed nodes using adhoc script.

    Doesn’t it contradict or am I missing something.
    First task says to run ansible as automation user and second says to make users on managed nodes.

    • Task 1 says that you need to configure ansible.cfg to use the automation user. It says nothing about ad-hoc commands. Note that you have root access to all five servers.

      Task 2 asks you to use Ansible ad-hoc commands to create the automation user. Ansible will default to running from your user account. Note that you can use the -u switch to connect as a different user.

    • So Tomas, as I understood TASK2 has to be run as root user and then the subsequent tasks with automation user?

  50. Hi Tomas, you help me with my RHCE, now I think you can help me with EX407.
    My question to you, is this sample 100%? Whats the reason why you did not cover Tower and Galaxy?
    Thank you

    • Ansible Tower is not part of the exam objectives (at least not for Ansible 2.7 which I took). Galaxy is included in the sample exam.

  51. Hi Tomas,
    Task two, when I tried to use when condition against uid it won’t recognise it.
    I tired to do it like this when: “{{ users[‘uid’] > 1200 }}”
    i can get the user name using item.username along with with_items
    any clue or advice

    • Your goal is to get two users created in the webservers group, and two users in the database group according to the requirements. If you can solve it by using item.username, then it’s totally fine.

  52. HI everyone! Happy new year! for task 4 would you use a template with a configured sshd_config file per requirements or would you use lineinfile and execute the playbook in 3 tasks for the sshd_config file modification following with a handler to restart sshd service?

  53. Hello everyone, I have a couple of questions regarding the EX294 exam – are all the machines ( the “master” node and all its hosts ) already configured ( I mean IP-s are set, there’s a root user already created ), or we need as in the RHCSA exam, configure the network, default gateway etc? And regarding the scripting task – are we allowed to install “sshpass” in order to facilitate the script execution, or it’s forbidden ( if so, could you guys share a bit of your knowledge, how exactly could we skip the initial “ask password” moment )? Because, I’m struggling to find the way how to fulfill the criteria “use Ansible ad hoc commands to first create the user, then copy the ssh-key and finally put a specific content into the sudoers file / or we can just append the newly created “automation” user to the “wheel” group —> the way that I see the things is : run the script as a root ( hence one have ssh key pair to send to the managed hosts ), then using the -u switch to the Ansible ad hoc commands execute them as the “automation” user / obviously his own ssh-key needs to be created separately before sending it to the hosts).

    Thank you in advance

    • I can’t tell you what’s on the exam, but all the info that you’ve been given is sufficient to solve the questions.

  54. Hello Tomas,
    First thing,your test questions are challenging and great for studying and practicing!

    For Task 3: Can I use 3 different copy modules and change the content: using variables and use different when: inventory_hostname in groups[‘proxy’], groups[‘webserver’], groups[‘database’] to do this task or am I supposed to use loop to do this?

    • Thanks! You can do it either way. There is no one right solution, you can solve the question however you see fit.

  55. For Task 18: Is the assumption that the Jinga2 template (server_list.j2) is created ahead of time for the playbook use?

    • Please disregard this question. The template file needs to be created on the control node ahead of time and gets pushed out to the managed node when the playbook is run.

  56. Hi Tomas,
    For Task 2, any clue what is wrong with this?
    ansible all -m user -a ‘name=automation password={{ ‘devops’ | password_hash(‘sha512’, ‘mysecretsalt’) }}’ -b -u root

    I get error saying:
    “msg”: “The tasks includes an option with an undefined variable. The error was ‘sha512’ is undefined”

    I tried to used the FAQ encrypted password for the user module and it is not working. :(

    Thanks.

  57. Hi Tomas,

    I have given EX294 exam thrice but got failed all the times. I have got all the outputs in exam but I got 177 in first and 2nd attempt and 145 in 3rd attempt. Whereas I have verified output for all the questions and got the correct output. I am going to write exam on 23rd Feb,2020 again. Can you please suggest me tips to clear this exam, it’s very important for me to clear the exam. Hope I will get response from you ASAP. Thank you!!

    • Tomas – when you say “don’t run your playbooks with root privileges” does that mean don’t become root in the playbook? Seems like just about every task requires the remote_user to become root.

      Thanks for any insight!

    • Just to clarity – If user provided to execute the playbooks does not have password-less elevated privilege’s then is it good practice to enable that in the sudoers before running playbooks or use the provided user as is (assuming that they don’t have pwless elev) and enter their pw using the -K and -b option every time a playbook is executed? Or maybe this is nuisance is a non-issue.

    • Hi Tomas, Mike Myers,

      Could you please advise bit more on the privilege issue, since it seems to be a hindrance. So if the non-sudoer, regular user is the owner & executor of all playbooks, as per exam rule, then without adding him to sudoers on managed nodes, nothing will work. But for evaluation, the managed nodes are completely reset to their initial states and then control node’s playbooks are triggered. So the sudoer setting will naturally be lost. So how come will anything work? During evaluation won’t all tasks fail? ( just adding become=true or -b won’t suffice, right)

    • Hi Mike, you can run ansible as a regular user but log into remote hosts as root by passing the remote user parameter.

  58. Hi Tomas!
    Yesterday I have failed my ex407 v2.7 with 96 scores:( I have an official learning subscription and complete do407 course, but the practical part is very poor and not enough. I have seen at one of your posts where you are advised to practice such a lot as you can. Can you please advise what practical lab/materials/tasks do you use to prepare your practical part for this exam?
    Also, I am interested in what differences between v2.3 and 2.7 because both exams are available.
    Thanks for your posts.

    • I spent a lot of time writing playbooks for various services (Apache, MySQL, Postfix, HAproxy, FTP, SSH etc) using my homelab. I also converted my Puppet manifests to Ansible playbooks, that helped a lot. Try automating services that you use at work.

      I am aware of the two exam versions, but I don’t really know the differences between v2.3 and v2.7. I took the latter one.

  59. Hi Tomas,

    First of all thanks for the effort you made.

    I planning for Ansible exam, next week and I have one question regarding the Task2(creation of “automation” user)
    I am fine with creation of user and pushing the ssh_keys (both with adhoc and playbook).

    My question is does this user by default has privilege to do sudo without password. Or we need to configure them on the managed nodes in the exam.

    I know it is not advisable to edit the visudo file… I am aware alternatively to edit the /etc/sudoers.d and make entry for that user accordingly.

    Just I want to how to tackle this situation . Any idea will be really helpful for the exam.

    Thanks,

    • In the sample exam case the automation user does not exist by default. It is therefore up to you how you want to handle it. You can create a user and then configure the system to allow sudo access.

  60. Hi, Tomas. Thank you for sharing this sample exam.
    I have a question about it. Is necessary to complete this sample exam in how long to be prepared for the ex407?

    • The Ansible exam is 4 hours, therefore you probably want to spend less than that solving the sample exam. I’d aim for 3 hours.

  61. Hi Tomas,

    I can’t find the ansible ad-hoc command to copy the key to the servers
    On examination is it possible to use this directly ” ssh-copy-id @” ?

  62. Hi Tomas. Congratulations on passing ex407. Can you tell me which exam you think is harder, your exam example or the ex407?

  63. Hi Tomas, I have failed 3 times. I am planning to give exam again on Feb 25. Though I got all the output still did not through the exam. In configuration file I gave become_method=su under privilege escalation. Please share some tips to pass the exam.

    • I’m sorry to hear that, from my experience, the key to success is practice. Can you solve all sample exam questions in 3 hours?

    • Yes, I am have completed the paper within 3 hrs. Also verified all the Output. I see repos were installed on all the nodes but but got result in that objective as 0. For each and every question I got exact output.

  64. Hi Tomas,
    Please any updates on EX294? I am planning to sit the exams but have no sample exams or real materials for preparation apart from Sander Van Vugt classes on oreilly.

    Thank you

    • What update are you talking about exactly? The sample example for EX294 is the same as for EX407. They share almost identical exam objectives.

  65. Hi Tomas,

    I have just finished TASH 2 (Ad-Hoc Commands). I wanted to send it to you for your feedback. Where can I send it to you?

    • Well done. The goal of the sample exam is to allow you to test your skills, since there are many different ways you can solve Ansible tasks, providing feedback on an individual basis isn’t something that I offer I’m afraid.

  66. Hi Tomas,

    First of all thanks for your effort with sample exam preparation. Good job !

    I have a question regarding Task 2 (ad hoc ). Please correct me if I’m wrong.

    You mentioned that all tasks should be executed with “automation” user. But executing ad hoc command “ansible all -m user -a ‘name=automation state=present’ -u root” under automation user always failed because the user has no access to root ssh keys !

    To workaround this we can add to the addhoc command –ask-pass and provide root password but I suspect that root password is not known in real exam.

    Thanks for explanation

    • Task 2 asks you to use Ansible ad-hoc commands to create the automation user (this user does not exist at this point). Ansible will default to running from your user account. Note that you can use the -u switch to connect as a different user, e.g. root. You know the root password in the sample exam scenario (because it’s your VMs), this is sufficient to solve the task.

    • This bothered me a lot. But indeed, we have to assume we know the root password of the managed nodes. Otherwise no solution is possible.

      In the end I made a seperate inventory “myadhocinventory”with ansible_user=root ansible_ssh_pass=mymanagednoderootpw.

      And then I call the script like this:
      ansible -i /home/myuser/myadhocinventory all -m shell -a “useradd bob” -b
      ..
      ..

  67. Hello, Can anyone help me with a playbook to check if the managed servers are in timesync with the control node, I have used the timesync role to achieve the sync, however I want to write a task that checks the same conditionally.

  68. Thank you so much Tomas,

    I have passed the ansible exam and i was practicing your sample paper. It was really helpful.

  69. Wanna ask about #task 2. So I should create script named adhoc and inside this script I write ad-hoc command. Then I just run something like ‘./adhoc’ ??

  70. Hi Tomas,

    For # task 9, how do I check the Volume group exists using stat (what should be provided in path).

  71. Hello Tomas ,
    I can’t perform this task 6: “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.”
    For example, do I have to copy alice’s public key to the vincent and vincent user to Alice?
    Is there a specific form to do this?
    Or is it simpler than expected?
    I’m wasting a lot of time figuring this out. Could you help me?

  72. Hi, Tomas. I would like to say thank you for the ansible sample exam that you have created. It really helps me to pass on the exam.
    Now, I will take the OpenShift Administrator EX280 :)
    Thank you again, man.

  73. Hi Tomas,
    Could you please clarify something for me?
    The control-node has passwordless access to the inventory hosts(using root). Ansible will run on “automation” user on the control-node. So in order to run adhoc commands with “-u root” ( to create the ‘automation’ user on the inv hosts) , user “automation” needs to connect on inventory hosts on user root. What is the proper way to achieve this?
    1.I reset the root passwords on all inv hosts and use ‘–ask-pass’ on the adhoc command
    2. Or I MANUALLY copy the public key of ‘automation’ user from control-node to the ‘root’ user of each inv hosts? This way the control-node will be able to connect in the end to both users root and automation on every inv host with the same key.

    I am interested in the right way that RedHat would point for this.

    Thanks!

    • Yes, the control node has passwordless access to the inventory hosts using the root account. You need to configure that part manually when you set your homelab environment up.

    • Well, both solutions work. Is there a prefered way considering the way RedHat validates this step?
      Thanks for this site and for replying.

    • I’m still a bit confused on how I should aproach this, if I use – u root -k it requires input and I don’t know if that’s ok.
      I have the option to manually copy the ssh key or share the root password in the script but if I’m not breaking the NDA is there a right way to do it?

  74. Hi Thomas,

    The last part of task 6 (After running the playbook, users should be able to SSH into their respective servers without passwords.”) , I can be done by logging into the machines and running the “ssh-copy-id” command from one user to another or I have to do it in the users.yml playbook ?

    Thanks

  75. Hi,

    First off, thanks for this practice exam! Second, i’m doing task 6, i have it working in regards to creating the users on the servers, what i’m struggling to understand is the SSH key, should it be another play using authorized key module to put the key from /home/automation/.ssh/id_rsa.pub on each server in the users home directory? Or am i looking to much into it?

    • I guess everyone is struggling with this.

      can do this part with fetch and authorized_keys to append user’s indiividual key but the question lies in dynamic host lookup

      Simple example , for webservers there are node2 and node3, but alice’s public key in these separate nodes are different how do dynamically get those pub keys and append into the respective server.

      Can someone help?

    • The public key is the same regardless of the node. As per instructions, use the SSH key that you created previously (you were asked to create one key). The task requires you to use that key. Since you only have one key, it is going to be the same for all nodes.

    • Hi Pmtaa,
      In order to achieve Task 2 requirements you need to connect on the “root” user on each inventory host. So you need to use the “-u root” option. Option “-b” is used when you need to elevate privileges – and it is not the case here.

    • Hi, you will want to use the -u option with root as the user as this will run the ansible command as the root user. If you have set your environment up correctly you shouldn’t need the -ask-pass flag, don’t forget these commands are going to be run by a script. The -b flag option will elevate the user that is executing the ansible command to root but the automation user doesn’t have root permissions at this stage.

    • How to setup the environment correctly and not have to use the –ask-pass for root?

      Thanks.

    • Hello,
      How to setup the environment to correctly so the –ask-pass flag is not needed?

      Is this the correct way to setup the environement and not be prompted for the root password when running the adhoc command?
      ansible all -e “ansible_user=root ansible_password=rootpassword” -u root -m user -a “name=ansible password={{ ‘ansible’ | password_hash(‘sha512’, ‘mysecretsalt’) }}”

      Thanks in advance for your help.

  76. Hi Tomas,

    For Task 3, I have the below playbook that works fine.

    – name: Replace the existing content of /etc/motd
    hosts: all
    become: true
    become_user: root
    tasks:
    – name: Replace /etc/motd on PROXY host group
    content: ‘Welcome to PROXY’
    dest: /etc/motd
    when: inventory_hostname in groups[‘proxy’]

    – name: Replace /etc/motd on webservers host group
    content: ‘Welcome to webservers’
    dest: /etc/motd
    when: inventory_hostname in groups[‘webservers’]

    – name: Replace /etc/motd on database host group
    content: ‘Welcome to MYSQL server’
    dest: /etc/motd
    when: inventory_hostname in groups[‘database’]

    In the above playbook if I use “when: inventory_hostname = ‘ansible2’ ” instead of “when: inventory_hostname in groups[‘proxy’] it is not working. What is wrong with that?

  77. Hi Pmtaa,
    In order to achieve Task 2 requirements you need to connect on the “root” user on each inventory host. So you need to use the “-u root” option. Option “-b” is used when you need to elevate privileges – and it is not the case here.

  78. Hi Tomas,

    For Task 9, I am getting the below error message.

    TASK [sample-mysql : Change mysql root password] *******************************************************************************************************************************************************************************************
    fatal: [serverc]: FAILED! => {“changed”: false, “msg”: “The PyMySQL (Python 2.7 and Python 3.X) or MySQL-python (Python 2.X) module is required.”}

    I have both python 2.7 and 3.6 installed.
    [root@serverc ~]# yum module list|grep python
    libselinux-python 2.8 common Python 2 bindings for libselinux
    python27 2.7 [d] common [d] Python programming language, version 2.7
    python36 3.6 [d][e] common [d], build Python programming language, version 3.6
    [root@serverc ~]#

    My tasks/main.yml:

    # tasks file for sample-mysql
    – name: Create primary partition
    parted:
    device: /dev/sdb
    number: 1
    label: gpt
    flags: lvm
    part_start: 1MB
    part_end: 800MB
    name: primary
    state: present

    – name: Create volume group
    lvg:
    vg: vg_database
    pvs: /dev/sdb1

    – name: Create logical volume
    lvol:
    vg: vg_database
    lv: lv_mysql
    size: 512m
    state: present

    – name: Create file system
    filesystem:
    fstype: xfs
    dev: /dev/vg_database/lv_mysql

    – name: Mount the file system
    mount:
    path: /mnt/mysql_backups
    src: /dev/vg_database/lv_mysql
    fstype: xfs
    state: present

    – name: Install mysql package
    yum:
    name: mysql-community-server
    state: present

    – name: Configure Firewall
    firewalld:
    port: 3306/tcp
    permanent: yes
    immediate: yes
    state: enabled

    – name: Change mysql root password
    mysql_user:
    name: root
    check_implicit_admin: yes
    login_user: root
    login_password: “{{ database_password }}”
    priv: ‘*.*:ALL’
    state: present

    – name: Start mysql
    service:
    name: mysql
    enabled: yes
    state: started

    – name: Copy my.cnf.j2 template
    template:
    src: my.cnf.j2
    dest: /etc/.my.cnf
    notify:
    – restart mysql

    • Thanks a lot that fixed the issue. How do I know if mysql is working fine? Below is the output I get when I run the playbook.

      [automation@workstation plays]$ ansible-playbook mysql.yml –vault-password-file=vault_key

      PLAY [Main playbook for mysql] *************************************************************************************************************************************************************************************************************

      TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [command] *****************************************************************************************************************************************************************************************************************************
      [WARNING]: Consider using the yum module rather than running ‘yum’. If you need to use command because yum is insufficient you can add ‘warn: false’ to this command task or set ‘command_warnings=False’ in ansible.cfg to get rid of
      this message.

      changed: [serverc]

      TASK [sample-mysql : Create primary partition] *********************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Create volume group] **************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Create logical volume] ************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Create file system] ***************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Mount the file system] ************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Install python3-PyMySQL] **********************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Install mysql package] ************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Configure Firewall] ***************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Start mysql] **********************************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Change mysql root password] *******************************************************************************************************************************************************************************************
      ok: [serverc]

      TASK [sample-mysql : Copy my.cnf.j2 template] **********************************************************************************************************************************************************************************************
      changed: [serverc]

      RUNNING HANDLER [sample-mysql : restart mysql] *********************************************************************************************************************************************************************************************
      changed: [serverc]

      PLAY RECAP *********************************************************************************************************************************************************************************************************************************
      serverc : ok=14 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

      [automation@workstation plays]$

    • systemctl status confirms mysql is running. Anything else I can check if mysql is OK?

      root@serverc ~]# systemctl status mysql
      ● mysqld.service – MySQL Community Server
      Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
      Active: active (running) since Tue 2020-03-10 07:53:55 EDT; 9min ago
      Process: 12589 ExecStartPost=/usr/bin/mysql-systemd-start post (code=exited, status=0/SUCCESS)
      Process: 12573 ExecStartPre=/usr/bin/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
      Main PID: 12588 (mysqld_safe)
      Tasks: 23 (limit: 17484)
      Memory: 136.8M
      CGroup: /system.slice/mysqld.service
      ├─12588 /bin/sh /usr/bin/mysqld_safe –basedir=/usr
      └─12763 /usr/sbin/mysqld –basedir=/usr –datadir=/var/lib/mysql –plugin-dir=/usr/lib64/mysql/plugin –log-error=/var/log/mysqld.log –pid-file=/var/run/mysqld/mysqld.pid –socket=/var/lib/mysql/mysql.sock

      Mar 10 07:53:52 serverc systemd[1]: Stopped MySQL Community Server.
      Mar 10 07:53:52 serverc systemd[1]: Starting MySQL Community Server…
      Mar 10 07:53:54 serverc mysqld_safe[12588]: 200310 07:53:54 mysqld_safe Logging to ‘/var/log/mysqld.log’.
      Mar 10 07:53:54 serverc mysqld_safe[12588]: 200310 07:53:54 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
      Mar 10 07:53:55 serverc systemd[1]: Started MySQL Community Server.
      [root@serverc ~]#

  79. Hi,

    For TASK 11, my playbook worked fine. HAPROXY is running on both the servers. But I am getting the below error when I run “curl” command. Has anyone experienced this issue?

    [automation@workstation plays]$ curl http:// serverb/
    503 Service Unavailable
    No server is available to handle this request.

    [automation@workstation plays]$ curl http:// serverd/
    503 Service Unavailable
    No server is available to handle this request.

    [automation@workstation plays]$

    [root@serverb ~]# systemctl status haproxy.service
    ● haproxy.service – HAProxy Load Balancer
    Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; vendor preset: disabled)
    Active: active (running) since Sun 2020-03-08 22:06:03 AEDT; 11h ago
    Process: 6019 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q (code=exited, status=0/SUCCESS)
    Main PID: 6020 (haproxy)
    Tasks: 2 (limit: 11491)
    Memory: 2.8M
    CGroup: /system.slice/haproxy.service
    ├─6020 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
    └─6022 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid

    Mar 08 22:06:03 serverb systemd[1]: Stopped HAProxy Load Balancer.
    Mar 08 22:06:03 serverb systemd[1]: Starting HAProxy Load Balancer…
    Mar 08 22:06:03 serverb haproxy[6020]: Proxy hafrontend started.
    Mar 08 22:06:03 serverb haproxy[6020]: [WARNING] 067/220603 (6020) : parsing [/etc/haproxy/haproxy.cfg:15] : the ‘contimeout’ directive is now deprecated in favor of ‘timeout connect’, and will not be supported in future versions.
    Mar 08 22:06:03 serverb haproxy[6020]: [WARNING] 067/220603 (6020) : parsing [/etc/haproxy/haproxy.cfg:16] : the ‘clitimeout’ directive is now deprecated in favor of ‘timeout client’, and will not be supported in future versions.
    Mar 08 22:06:03 serverb haproxy[6020]: [WARNING] 067/220603 (6020) : parsing [/etc/haproxy/haproxy.cfg:17] : the ‘srvtimeout’ directive is now deprecated in favor of ‘timeout server’, and will not be supported in future versions.
    Mar 08 22:06:03 serverb haproxy[6020]: Proxy hafrontend started.
    Mar 08 22:06:03 serverb haproxy[6020]: Proxy habackend started.
    Mar 08 22:06:03 serverb haproxy[6020]: Proxy habackend started.
    Mar 08 22:06:03 serverb systemd[1]: Started HAProxy Load Balancer.

    [root@serverd ~]# systemctl status haproxy.service
    ● haproxy.service – HAProxy Load Balancer
    Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; vendor preset: disabled)
    Active: active (running) since Tue 2020-03-10 05:47:51 EDT; 12h ago
    Process: 7339 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q (code=exited, status=0/SUCCESS)
    Main PID: 7341 (haproxy)
    Tasks: 2 (limit: 5040)
    Memory: 4.5M
    CGroup: /system.slice/haproxy.service
    ├─7341 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid
    └─7343 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid

    Mar 10 05:47:51 serverd systemd[1]: Stopped HAProxy Load Balancer.
    Mar 10 05:47:51 serverd systemd[1]: Starting HAProxy Load Balancer…
    Mar 10 05:47:51 serverd haproxy[7341]: [WARNING] 069/054751 (7341) : parsing [/etc/haproxy/haproxy.cfg:15] : the ‘contimeout’ directive is now deprecated in favor of ‘timeout connect’, and will not be supported in future versions.
    Mar 10 05:47:51 serverd haproxy[7341]: [WARNING] 069/054751 (7341) : parsing [/etc/haproxy/haproxy.cfg:16] : the ‘clitimeout’ directive is now deprecated in favor of ‘timeout client’, and will not be supported in future versions.
    Mar 10 05:47:51 serverd haproxy[7341]: [WARNING] 069/054751 (7341) : parsing [/etc/haproxy/haproxy.cfg:17] : the ‘srvtimeout’ directive is now deprecated in favor of ‘timeout server’, and will not be supported in future versions.
    Mar 10 05:47:51 serverd haproxy[7341]: Proxy hafrontend started.
    Mar 10 05:47:51 serverd haproxy[7341]: Proxy hafrontend started.
    Mar 10 05:47:51 serverd haproxy[7341]: Proxy habackend started.
    Mar 10 05:47:51 serverd haproxy[7341]: Proxy habackend started.
    Mar 10 05:47:51 serverd systemd[1]: Started HAProxy Load Balancer.

    • Just had a similar problem. Getting HTTP 503 on the proxy but curling the backend servers worked just fine from the proxy.

      I simply added an additional task to restart haproxy after enabling firewall port 80. Fixed it for me.

  80. Hei Tomas , everybody,

    Thanks Tomas for this sample exam. You have no idea how much it helped …or..you do have :).
    I have just passed EX294 today with 240/300.

    As an advice for those who will take this exam in the future: you really need to solve the exercicess fast. you need to have very very very good practice in order to touch all tasks. I didn t have time to touch two exercices and a third one I didn t finish.
    Also I didn t like that I couldn’t configure my .vimrc (or idk it didn t work) and I lost precious minutes with indentation – thing that does not happen when I work or practice with ansible.

    Goodluck 2 all!

  81. Hi Everyone!
    Hope you are keeping safe! qq: Any idea if there is access to Ansible Galaxy roles on EX294?

    Thanks,
    jn

  82. Hi! Thank you for your shared experience! Could you tell, did you have questions on exam about vagrant and dynamic inventory?
    Thank you a lot!

  83. Hi Tomas,

    Thanks for the sample exam, it is a great exercise. I am having trouble understanding Task 15. Setting the fact is easy, but I cannot understand how it can be retrieved from ansible_local.custom.sample_exam. Can you please give me hint?

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

  84. Hi Tomas,
    I cannot understand what the role in exercise 12 (Security) is for ?
    Can it work this way?

    – name: Secuity
    hosts: webserver
    become: true
    tashs:
    – name: “Set httpd_can_network_connect flag on and keep it persistent across reboots”
    seboolean:
    name: httpd_can_network_connect
    state: yes
    persistent: yes

  85. Hi,
    Did anyone here take the EX447 exam and could offer me some tips on what to study, especially for git and Tower (API)?
    Thanks!

  86. I don’t see how I can use the templates module to complete task 18. I did it this way however:


    – hosts: all
    become: yes
    tasks:
    – name: create server list
    lineinfile:
    path: /home/automation/plays/server_list
    line: ‘{{ ansible_fqdn }}’
    create: yes
    delegate_to: 127.0.0.1
    – name: copy server list
    copy:
    src: /home/automation/plays/server_list
    dest: /etc/server_list.txt
    owner: automation
    mode: 0600
    setype: net_conf_t
    – name: delete server list
    file:
    path: /home/automation/plays/server_list
    state: absent
    delegate_to: 127.0.0.1

    The result is not a ordered list, but gets the job done:
    [automation@ansible2 ~]$ cat /etc/server_list.txt
    ansible2.hl.local
    ansible5.hl.local
    ansible3.hl.local
    ansible4.hl.local

    Any hints on a better way of doing this?

    • As per requirements – the file server_list.txt should update in case the inventory changes/updates – so the best way would be to use ‘template’ module. This particular task is very easy to achieve using the “template”.
      Hint – look at the “magic variables” ->
      To get a list of what they contain, run:
      ansible localhost -m debug -a “var=hostvars”

      Hope this helps. Good luck.

    • i still do not get how to make loop …
      i got this so far:


      – name: task_18_custom_template
      hosts: database
      become: true
      vars:
      zdroj: /home/automation/plays/server_list.j2
      ciel: /etc/server_list.txt
      tasks:
      – name:
      template:
      src: “{{ zdroj }}”
      dest: “{{ ciel }}”
      owner: automation
      mode: ‘0600’
      setype: net_conf_t

      [automation@control plays]$ cat server_list.j2
      {% for inventory_hostname in groups[‘servers’] %}
      {{ ansible_facts.fqdn }}
      {% endfor %}

      i dont know how to force template to make correct loop ..aaaa
      can you direct me a bit pls ..

      thanks

  87. Hi Tomas, thanks you for sharing this.
    I have a question when i run the authorized_key in the adhoc command for task number2 ansible all –ask-pass -m authorized_key -a ‘user=automation state=present key=”{{lookup(‘file’, ‘/home/automation/.ssh/id_rsa.pub}}”‘
    I always get this error:
    template error : unexpected ‘/’.string: key=”{{lookup(‘file’, ‘/home/automation/.ssh/id_rsa.pub}}”
    Why am i getting this error ?
    Thank you.

  88. Hey Tomas, i have a “general” question (not necessarily about this test, but i couldn’t find any example on the internet)
    when working with ansible-vault is it possible to use the protected data, but withouth the need of using the “–ask-vault-pass”, “–vault-id” or any of the call methods from the CLI.
    to put it simple, is there any way to ONLY run “ansible-playbook playbook.yml” when the playbook uses protected data?

    (ps: i believe the only way is to set the vault_key file location in ansible.cfg?)

    • Hi Nick, if you don’t provide the vault password on the CLI, then you have to store it somewhere in a file.

      You can do something like this:

      ansible-playbook --vault-password-file=vault_secret.txt playbook.yml
    • Hey Nick,
      The answer to Your question is Yes – You can run a playbook containing Vault encrypted data without providing the command line arguments for vault pass or id-> look in the /etc/ansible/ansible.cfg and You will figure out the way.
      Good luck.

  89. Hello Thomas,
    Would you please advise with task 11 “Use geerlingguy.haproxy

    The proxy server installed and haproxy service active, and firewall port 80 added however when am curl://proxy_server
    i have error
    503 Service Unavailable
    No server is available to handle this request.

    also via web: 503 Service Unavailable
    Please see output from files below:

    # vim haproxy.yml

    – name: task_11
    hosts: proxy
    become: yes
    roles:
    – geerlingguy.haproxy
    vars:
    haproxy_frontend_mode: ‘http’
    haproxy_backend_port: 80
    haproxy_backend_balance_method: ’roundrobin’
    haproxy_backend_servers:
    – name: node1
    address: 192.168.1.80:80
    – name: node2
    address: 192.168.55.63:80

    tasks:
    – name: install firewalld
    yum:
    name: firewalld
    state: present
    – name: satrt service
    service:
    name: firewalld
    state: started
    enabled: yes
    – name: configure firewall 80
    firewalld:
    port: 80/tcp
    state: enabled
    permanent: yes
    immediate: yes
    and
    # vim/etc/haproxy/haproxy.cfg
    global
    log /dev/log local0
    log /dev/log local1 notice
    stats socket /var/lib/haproxy/stats level admin
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon

    defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5000
    timeout client 50000
    timeout server 50000

    frontend hafrontend
    bind *:80
    mode http
    default_backend habackend

    backend habackend
    mode http
    balance roundrobin
    option forwardfor
    option httpchk HEAD / HTTP/1.1\r\nHost:localhost
    cookie SERVERID insert indirect
    server node1 192.168.1.80:80 cookie node1 check
    server node2 192.168.55.63:80 cookie node2 check

    Please advice

    Many thanks,
    Przemo

  90. Hi Tomas,

    Task 2 questions were sounding bit confusing, it did not clearly mention if the ssh keys to be generated on root or automation user on controller, since it was mentioned that we need to use automation user for all plays/tasks I believe keys to be generated will be for automation user – just wondering if the questions will be similarly phrased in exam as well?

    • It doesn’t matter, you can use any user to generate a keypair. The outcome of the task is clearly stated: as long as the SSH key that you generated gets copied to all inventory hosts for the automation user and you can SSH into all inventory hosts using the automation user without a password, you have completed the task.

  91. Hi, Tomas,

    I have two questions for you:
    1. Is the resolution of machine hostnames resolved by a DNS or do I need to add entries in the /etc/hosts file?

    2 . In Task 2: Ad-Hoc Commands, the command to create the automation user and deploy the public key, must be done so that the root password is given in input (stdin) or just run the script and each time type the root password for each machine?

    • Hi Riccardo, you can use the hosts file if you don’t have a working DNS server, either way is fine.

      With regards to the second question, again, either way is fine, as long as the ad-hoc command creates the user.

  92. Hello,

    The sixth task is giving me headache since yesterday, and I feel lost:
    “Each user should have an SSH key uploaded (use the SSH key that you created previously, see task #2).”

    And in an anwser you said:
    You can reuse the same SSH keys as many times and on as many users as you want.

    and when someone asks this:
    How would the key from one user allow another user to ssh to a remote server ?

    You said: It’s the same key. It’s like using the same password on multiple accounts.

    Can you please give an example (outside of the exam question), where you have two users a and b on two servers server1 and server2, let’s say you logged as user a and created private/public ssh keys for this user, did ssh-copy-id and now this user can ssh to server 2 without password.
    Now how I can reuse the same public key of user a for user b and then ssh to server2 as user b without password ?

    From what I see we can’t reuse the same public key.

    • Generate an SSH keypair using ssh-keygen. If you don’t change the filename, you’ll normally get two files created, id_rsa and id_rsa.pub. The first one is your private key, and the second one is your public key. If you have two (or more) users on different servers, you can use those keys for both/all of them. What that means is that the users will use the same key. Simply copy the private key and save it as ${HOME}/.ssh/id_rsa, then copy the public key and save it as ${HOME}/.ssh/authorized_keys. Regardless of the actual username, you can repeat this process for as many Linux accounts as you need.

    • Thank for the details !
      After testing this yesterday, I have to say that you were right, I want just to add in case we didn’t copy the private key of user.a to the home directory of user.b ,we need to login as user.a and then do ssh user.b@server2 or do this:
      sudo -u user.a ssh user.b@server2

  93. Hi Tomas.
    Thank you for this, it is very helpful.
    when I arrived to task 6 … the ssh part it worked if i used that one key that I generated in the earlier however for outside of this sample exam i tried to generate a different ssh for every user and after i ran the playbook the files are copied correctly to every host but every time I try to connect it asks me for a password !?
    I’ve had a really hard time figuring it out ? is it because of the private key ? and if so how can I overcome this problem?
    Thank you very much.

    • When you try to connect, what private key do you use? Your private key has to match the user it has been deployed to.

  94. Hi Tomas ,
    for the conduct of exercise n° 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.

    I tried to solve it this way in the playbook:
    – name: “Private Key for alice”
    copy:
    src: /home/automation/.ssh/id_rsa
    dest: /home/{{ item.username }}/.ssh/id_rsa
    owner: “{{ item.username }}”
    group: “{{ item.username }}”
    mode: ‘0600’
    with_items: “{{ users }}”
    when:
    – item.username == ‘alice’
    – “‘webservers’ in group_names”

    – name: Remove public key
    file:
    path: /home/{{ item.username }}/.ssh/id_rsa.pub
    state: absent
    with_items: “{{ users }}”
    when:
    – item.username == ‘alice’
    – “‘webservers’ in group_names”

    – name: “Authorized key for alice”
    copy:
    src: /home/automation/.ssh/id_rsa.pub
    dest: /home/{{ item.username }}/.ssh/authorized_keys
    owner: “{{ item.username }}”
    group: “{{ item.username }}”
    mode: ‘0600’
    with_items: “{{ users }}”
    when:
    – item.uid|string|first == ‘1’
    – “‘webservers’ in group_names”

    Can it be a good solution?
    Thanks

    • Hi Patrick, I didn’t use any to be honest with you, therefore can’t recommend much, sorry.

      Ansible documentation website was one of my main study resources if that helps.

  95. Hi Tomas,
    I saw a files directory in your homelab3, with each of the users unique SSH public key file.
    Please if could explain how to create such a files directory.

    Thanks Jules!

    • Hi Jules, it’s actually the opposite, if you open the files, you will notice that all users share the same SSH key. These files are stored on the control node, you can create them manually.

  96. Hi. Tomas, thank you for cool sample of EX-294. I’m preparing for this exam and your sample is very useful.
    I want to ask about Mysql task (Task 9). As I know in CentOS we should use mariaDB. I installed mariaDB instead mysql-community-server and mysql_user module don’t work well. What is preferred way to manage user passwords on mysql?

  97. Hi Tomas,

    When I create a repo as per Task 8, mysql-community-server installation on Centos 8 is not working. Have you tried on Centos 8?

    Thanks,
    Rajesh

  98. Dear Tomas,

    An excellent sample exam!!
    Going to take the EX407 tomorrow, wish me luck.

    1 thing threw me off, and looking at the comments i’m not the only one.
    Task 6 last question: is this the SSH key of the automation user, that you are revering to?(not the SSH public key of the automation user)
    Because the last line says:
    After running the playbook, users should be able to SSH into their respective servers without passwords.
    Means that i distribute the SSH key and SSH public key?

    Regards, Dennis

    • I hope that your exam went well!

      To answer your question, yes, there is a single SSH key that you have to generate and use for this sample exam.

  99. Hi Tomas,

    Should I create the user “automate” anyway even if I was not asked for ?

    Thanks,
    Ikram

  100. Hey Tomas,

    Any advice on how to learn Ansible as a first time beginner? so many resources but get put off as Ansible does look a bit challenging. How did you go about gaining Ansible knowledge? :)

    • Hi Niraj,

      My advise would be to start with simple things that you use daily, and gradually progress to more complicated services. I started with writing playbooks that install packages and configure firewall rules. My goal was to have a basic Apache webserver running that displayed a static page.

      Then I started using Ansible variables, vault and templates. After that I moved on to using Ansible roles and even writing my own ones. It will require a lot of practice, but that’s the way forward if you want to learn it.

  101. Hi Tomas,
    how would you go about “zeroing” a file with Ansible aka removing it’s contents completely and replacing it with just a single line?

    • Also, let’s take into account the following scenario:
      – multiple LVM actions are required on all of the inventory, such as creating the partition, the VG, LV and finally the filesystem
      – let’s say that nodes setup is inconsistent, that is some nodes don’t have the extra disk, while others have it, but it’s too small for the required LV size, for example
      Now, I would use ignore_errors and use the fail module, together with registering the command results to display certain messages where they apply, such as “no sdb here” or “not enough space for the LV, thus we are creating a smaller one”.
      Is such a solution acceptable in your opinion? Would there be a more “professional” approach?

      Thanks.

  102. thx sir for sharing this to us….is there any place where i can get the playbooks answering the questions??? just for estudy purposes…any git hub repo or so???

    thx in advance!!!!

  103. I’m preparing to take the exam next month, I’m confused with TASK #2.

    I’m assuming scripts need to be run as the original user with root access. I KNOW we can’t run as automation user on managed nodes, as they are not created. And if that’s the case, why are the stored with the automation user as script “adhoc”. Why would we create a script that can’t be run as the user.

    Can someone explain how this is suppose to work?

    • Hi Darryl, first of all, good luck with your studies!

      This is just a sample exam, therefore the questions may not necessarily reflect real life use cases.

      The scenario of the sample exam is that you have no regular users on your managed hosts, but you do have root access. In theory you can create the ad-hoc script anywhere you like on the OS. In this particular case the script is /home/automation/plays/adhoc, but feel free to create it elsewhere if that helps you. I believe that the confusion is the username that needs creating – automation. If I asked you to create a user called alice on all managed host, would that clarify the confusion for you?

  104. Tomas

    Thank man for time you have place into this. I’m serious, i do really appreciated it.

    I’m getting literally paid to get my ansible certification, so its my job. I already went through linux academy’s training, which was great. I need more practice before taking the exam. I have been using ansible for years but haven’t used many of the features.

    My confusion is that configured the ansible.cfg to use automation user in TASK #1, I always set my environment variable ANSIBLE_CONFIG in .bash_profile to the ansible.cfg that I want to use. I created the ad hoc script in location as you specified. If I use my original user (my username points to root) to run it fails as it tries to use automation user from ansible.cfg AND if I switch to the automation user to run, it fails because automation user isn’t created on the system. Does this script need to be run and successful in current configuration?

    • Thanks for your kind words Darryl. As always, I’m glad to know that you find the material useful.

      Task #1 says that you have to use the automation user for all sample exam tasks and playbooks, unless you are working on task #2 that requires creating the automation user on inventory hosts. Note how the username is the same, but in reality it does not have to be. It can be anything. I could’ve asked you to create a user called alice, but I didn’t. Why? Because this throws a curveball. Something that you should be prepared for when you take the real exam (again, this is just a sample exam that I had created before I took EX407).

      For task #2, Ansible will default to running from your user account. However, you can use the -u root switch to connect as a different user, e.g. root. You already know the root password in this sample exam scenario because these are your servers, therefore it is sufficient to solve the question. I hope this clarifies things.

    • Just adding to this my own 2 cents on the same task (which is not really as straight-forward to complete as it may sound) – as I was also trying to resolve it in different ways:
      1. “use the “automation” user for all sample exam tasks” -> Well that is not a big deal, if You read /etc/ansible/ansible.cfg “default” configuration, BUT the question is:
      1.1 in Ansible – You can specify the “become” user in two ways (as far as I am aware):
      a -> using “-b” flag -> and that means that on local machine(ansible control node in this case) it runs task as whatever current user is, then connect as the user-name specified in Your ansible.cfg file – and as that user will “sudo” on the remote host. What that means for this particular task – is that this is not the correct way to accomplish this – as user does not yet exist on the remote host and keys are also not yet setup (that is the actual task)
      b -> as Tomas mentioned – using “-u root” flag, which effectively means: on the localhost (same, ansible control machine) “become” root – and then, being root – connect to ansible managed nodes as root (so key-less authentication root->root must already be in place between the control and managed nodes) and then, as root, perform that tasks on the managed nodes. All good with that, BUT that means that on local host (control node) current user (automation in this case) must be allowed/privileged to do “sudo su -” -> so to do that – You need to tweek it’s permissions not only on the managed nodes, but also on the control node.

      All above may sound a bit “messy” – but that was the only way I managed to acomplish the task (using method “b”)
      Would love to hear other views on this.
      BTW, Tomas – Thx for putting together this exercises set.
      Rgds, kalihawk

    • Just to clarify, the flag -b invokes privilege escalation on the remote node for whatever remote user you are using.

      The flag -u specifies the remote username to use to login to the remote node instead of the current user.

    • Tomas, Thx for Your update’ response
      I worked on this task again today and that is, in fact, correct as You formulated:
      “Just to clarify, the flag -b invokes privilege escalation on the remote node for whatever remote user you are using.
      The flag -u specifies the remote username to use to login to the remote node instead of the current user.”

      So my previous solution was not entirely correct, and You do not need privileged permissions for the current user(i.e “automation”) to use “-u root” but, instead the solution is to have the correct remote authentication method (hint: There is already access to root account on all servers – so that should be sufficient to set-up the correct cross-servers authentication for any user-account).

      Hope this helps
      Good luck’ with the Prep’ for this exam.

  105. Ha ha, sorry man I missed that completely. Thanks again. Yeah, that makes perfect sense, thank. This is a real good test. I do have another question and you might not have the answer, this isn’t on the practice exam. I need to hash password with sha-512. I can download many programs to do it, but are there any base Redhat programs to hash passwords. I thought openssl would have the proper hash but it doesn’t.

  106. Thanks a million again, that’s perfect. I never had to deal with passwords or vault even though been using ansible for many years.

    I finished entire practice exam, I’m actually going to start over and do it again.

    I did have two issues that I didn’t really resolve, failed to set the root password on mysql using the mysql_user module and custom fact. My fact.yml create /etc/ansible/fact.d/custom in ini format on target host. I can retrieve all my facts on command line using filter “*ansible_local*” but empty on filter “*ansible_local.custom.sample_exam*”. Even though my results on “*ansible_local*” filter look like this:

    ansible5 | SUCCESS => {
    “ansible_facts”: {
    “ansible_local”: {
    “custom”: {
    “sample_exam”: {
    “datacenter”: “alexandria”,
    “server_role”: “mysql”,
    “type”: “physical”
    }
    }
    },
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }

    Do you have any ideas why filter isn’t working?

    • Hey, Darryl
      I would like to update my previous answer. While working on the same task today – I happened to observe the same behavior (can see the local_facts but not particular value of a “target” fact):
      ———————————————————————————————————————
      [automation@ansible]$ ansible node1 -m setup -a “filter=ansible_local”
      node1 | SUCCESS => {
      “ansible_facts”: {
      “ansible_local”: {
      “custom”: {
      “sample_exam”: {
      “server_role”: “mysql”
      }
      }
      },
      “discovered_interpreter_python”: “/usr/bin/python”
      },
      “changed”: false
      }

      [automation@ansible]$ ansible node1 -m setup -a “filter=ansible_local.custom.sample_exam”
      node1 | SUCCESS => {
      “ansible_facts”: {
      “discovered_interpreter_python”: “/usr/bin/python”
      },
      “changed”: false
      }
      [automation@ansible]$
      ———————————————————————
      However, that does not mean that is wrong – as same behavior happens when working with ansible_facts:

      [automation@ansible]$ ansible node1 -m setup -a “filter=ansible_default_ipv4”
      node1 | SUCCESS => {
      “ansible_facts”: {
      “ansible_default_ipv4”: {
      “address”: “172.xxxxxxx”,
      “alias”: “ens5”,
      “broadcast”: “172.xxxxxxx”,
      “gateway”: “172.xxxxxx”,
      “interface”: “ens5”,
      “macaddress”: “xxxxxxxx”,
      “mtu”: 9001,
      “netmask”: “255.xxxxxxxxx”,
      “network”: “172.xxxxxxxx”,
      “type”: “ether”
      },
      “discovered_interpreter_python”: “/usr/bin/python”
      },
      “changed”: false
      }
      [automation@ansible]$ ansible node1 -m setup -a “filter=ansible_default_ipv4.address”
      node1 | SUCCESS => {
      “ansible_facts”: {
      “discovered_interpreter_python”: “/usr/bin/python”
      },
      “changed”: false
      }
      [automation@ansible]$

      ————————————————————————————————————————–
      But then, to confirm it has been set-up correctly, I used “debug” module to retrieve the local_fact value – and that worked correctly, so I am still reading on this – why can not retrieve using the “setup” module, but works using the “debug” module:
      ——————————————-
      In the playbook:
      – name: print local fact
      debug:
      msg: “{{ ansible_local.custom.sample_exam.server_role }}”
      ——————————————–
      TASK [print local fact] **********************************************************************************************
      ok: [node1] => {
      “msg”: “mysql”

      ——————————————–
      Would be interesting to hear other opinions on this – but that seem the “correct” behavior, as far as I can say from my limited knowledge.
      Good luck

  107. Hi Tomas, excellent sample exam, thank you so much. It helped me a lot. I found the 2.7 exam quite tricky to be honest, there were a couple of things that threw me off, but your exam was a huge assistance, thank you again!

  108. Hi Tomas,

    Thanks for your sample exam. I have passed the exam. Your sample exam helped me a lot. Much appreciated.

  109. These examples are awesome. I have worked through all of them but I am stuck on task 11 with the haproxy role. Is the intent to dynamically build the backend server list from the webservers group? If so, here are my struggles and was wondering if I could get just the slightest hint?
    – The instructions say that the playbook should only run against the proxy group. In this case, how do you collect the appropriate info from the webservers group?
    – Given that the proper data can be collected, is there a way to construct the backend server list dynamically? I envision looping over the weservers group and adding a row to the list each time but I cans seem to locate the proper way to do the actual add.

    • Hi Troy, you know the servers in the webservers group already, therefore collecting such info dynamically isn’t necessary in this case.

    • Yeah, maybe dynamic wasn’t the best choice of words. My struggle is that I figure we don’t want to hard code the back end server list but rather it should query the webserver group each time it is run. I know to loop on groups[‘webservers’] to do that but I can’t seem to get how to then properly format the backend_servers var from within that loop. In addition the instructions state that the playbook should be run against the proxy group. If webservers is not included in the hosts definition of the playbook, I do not seem to get ansible_facts which I believe are needed for the backend list.

    • You can if you would like. The approach i took is running the playbook against proxy and webservers group. I then used a block so i can only run the tasks on the proxy group. I will leave it at that and if you need more help, feel free to ask.

    • WOO HOO RHCE Test Passed. Your sample test questions were a tremendous help. Thank you!!!!

  110. Hi Tomas

    Thanks for posting sample exam questions it will be very helpful for me but can you give me tips how to memorize YAML playbook syntax for RHCE EX294 Exam. Is there any sample playbook in server which I can refer during exam or any man page?

    Thanks & Regards
    Charanjit Singh

    • What I did is I wrote playbooks over and over in my homelab until I was able do that from memory. Also, it helped to configure vim for space indentation.

    • For specific modules you can use ansible-doc in combination with the “-s” flag which prints out the usage of the module with all parameters.

      For a complete playbook you probably can check the example playbooks which come with the rhel-system-roles package. (search for the files with “rpm -ql rhel-system-roles” after installation…

      Regards
      Markus

  111. Thank you, Tomas. I passed EX294(RHCE V8) today. Your sample exam helps me a lot.
    Have a nice day sir.

  112. Hey Tomas,
    I have been using Ansible with AWS and GCP for sometime now and have gone through linux academy course for the same. Is is necessary for me if I take EX407, to be RCHE or any other certified linux expert as my linux knowledge is basic but I am comfortable with Ansible. What do you think?

    • RHCE 8 is all about Ansible, therefore if you’re comfortable with it, you can take the exam. Note that you have to have an active RHCSA certification to receive RHCE.

  113. After 100+ hours of study, I don’t want to get this wrong if this is specified on the exam and get a zero over something trivial.

    What do you mean by privilege escalation disabled? Does that mean in config we set ‘become’ to false and then for each and every play we must use -b? The documentation says use -b to run operations with become, so wondering if we need to deliberately set become to false in .cfg? Sanders van Vugt suggests to set become to true in .cfg. Would that violate the specification for Task1 here?

    • I should say thanks in advance, since often people tell me I come off as too serious when writing ha. I just mean, don’t want to fail over a small misstep. I am assuming if become is set to false, then we must use the option -b with all playbooks that require sudo privileges. Can you tell me if this is correct way of interpreting the instructions. My biggest fear is doing something like this and then having the autograder not use the -b switch and getting a 0 for everything.

    • The sample exam tasks asks you to disable privilege escallation, you can do so by setting become=False in the .cfg file. I hope this clarifies things for you.

  114. Hi Tomas,

    i’m not sure about Task 13. In this subtask: “If a server has less than 2048MB of RAM, then the following error message is displayed”, should be done with debug: msg or with fail module and custom msg?

  115. Hi Tomas,
    Today I took the RHCE and it went great, just wanted to thank you this really helped.

    • Hi Aditya, thanks for reaching out. What have you tried so far, and what is not working in particular? Can you also post error messages that you get?

    • Hello Tomas,

      Thank you for your reply. I managed to figure out the issue. Thank you once again.

  116. Hello Tomas,

    During exam, one should execute the playbook with –

    1. become: yes OR
    2. become_method: sudo

    Please advise..because this simple mistake can lead to failure in exam.

    • My advice is to follow exam instructions and use whatever is required. If this isn’t explicitly set then use your best judgement. Example: if a task does not require elevated privileges then don’t use become/sudo. If a task does require elevated privileges, say package installation, then use become/sudo.

  117. Hello Tomas;
    Thank you so much for this sample exam.
    I have some worries about the firt question. After creating my script, when I run it against target hosts, I have to manualy accept the SSH key from each target (x 4) :-(
    It’s annoyant for me; and I wonder if Examinator could smash me because of this issue.
    Thanks in advance for your answer

    • Hi Judi, no worries, you are welcome!

      With regards to your question, you will always have to trust a connection to an SSH server when connecting for the first time. There is no other way around it. An SSH client receives a public key from the server and has no way of knowing whether it should trust it.

    • Hi Judi,
      You can always add ignore host key check to inventory file

      [all:vars]
      ansible_ssh_common_args=’-o StrictHostKeyChecking=no -o userknownhostsfile=/dev/null’

      it’s a work around for known ansible bug that you can’t disable strict host key checking

  118. Task 18:
    When RH asks for persistent changes – what’s about the setype?
    If I just use the setype-parameter it is changed, but won’t survive a full relable or restorecon run, but a normal reboot. Is this enough or should I use sefcontext before creation of the file?

    Any experiences with this?
    Regards
    markus

  119. Hi Tomas
    Thanks for the above Questions, i have been going through them they quite helpful, do you perhaps have the updated ones with solutions?

    Thanks

  120. Hello, Tomas. Sorry to hijack the comments but I am in dire need of your expertise. A monumental task for me (of paramount importance) would likely be greatly simplified with a snippet of your advice. Are you able to email me at the address I provide to post here? TIA if you can do so.

  121. Hi Guys,
    Task 9,
    Configure MySQL root user password.
    I encountered the error,
    fatal: [node4.ansi.example.com]: FAILED! => {“changed”: false, “msg”: “unable to connect to database, check login_user and login_password are correct or /root/.my.cnf has the credentials. Exception message: (2003, \”Can’t connect to MySQL server on ‘localhost’ ([Errno 111] Connection refused)\”)”}

    Any idea how to handle this? Try so many matter also failed.
    I’m using mysql_user module to change the root db password.

    • Hi, i think you’ve to specify the `login_unix_socket` parameter:

      – name: Ensure mysql root password is updated for all root accounts
      mysql_user:
      name: root
      host: localhost
      login_unix_socket: /var/lib/mysql/mysql.sock
      password: “{{ database_password }}”

    • Hi, full answer:
      as reported in the doc https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_user_module.html#notes, you’ve to create 2 tasks:

      “`
      – name: Ensure mysql root password is updated for all root accounts
      mysql_user:
      name: root
      host: localhost
      login_unix_socket: /var/lib/mysql/mysql.sock
      password: “{{ database_password }}”
      notify: restart_mysql

      – name: Create `/root/.my.cnf` with root password credentials
      template:
      src: creds.j2
      dest: /root/.my.cnf
      owner: root
      mode: 0600
      notify: restart_mysql
      “`

      The templates looks like this:
      “`
      [automation@ansible-control plays]$ cat roles/sample-mysql/templates/creds.j2
      [client]
      user=root
      password={{ database_password }}
      “`

    • Ive tried this 100 times and 100 different ways, it still doesn’t work, no idea whats wrong. I even follow the Ansible docs guidance and still not working at all.

  122. Hi Tomas
    In the examination objectives, there are the following requirements:
    – Use both static and dynamic inventories to define groups of hosts
    – Utilize an existing dynamic inventory script

    that however I have not seen used in the exercises proposed by you.
    Do you think they may be there during the exam?
    Thank you again for your valuable work

    Best Regards
    Riccardo

    • Hi Riccardo, I’m aware. There are no questions related to dynamic inventory in my sample exam because it would make the set up too complicated. Any exam objective is a fair game, my advice is to be familiar with all of them.

      You can use KVM, Proxmox or AWS to practise dynamic inventory.

  123. Quite useful. 70% question models covered from here. Thanks to Tomas.
    If anyone need exam discount code(15% OFF) send me mail to [email protected] with subject line “Red Hat Ansible Exam Discount code” I will share to the first two people.( If i did not replied you means nothing left :) )
    Exam takers please note the below as well apart from the model questions provided here.:
    1. Familiarize with requirements.yml(ansible-galaxy)
    2. Practice rhel-system-roles.timesync/selinux
    3. Practice ansible-vault rekey
    4. How to check a specific vg exists in a system (when: ansible_lvm.vgs.vg_name is defined)
    5. During this pandemic time, only remote exams are available in most of the countries. Make sure to connect to the control node using ssh from terminal to copy paste the URLs from questions , instaed of vm console.
    6. Add — to each yaml files even though without — it works.
    7. Run ansible ping for all hosts before starting on questions.
    # ansible all -m ping
    8. Make sure the facts are gathering.
    If not, do ‘gather_facts: yes’
    If gathering = explicit in config, then we have to indicate ‘gather_facts: yes’ for facts gathering.
    9. Understand suid,sgid and sticky bit stuffs
    setuid bit
    $ chmod 4775 test
    setgid bit
    $ chmod 2775 test
    sticky bit
    $ chmod 1775 test
    10. Make sure you thoroughly know the below modules without needing to check ansible-doc
    parted:
    lvg:
    lvol:
    filesystem:
    mount:
    firewalld:
    copy:
    include_role:
    archive:
    blockinfile:
    debug:
    yum:
    cron:
    yum_repository:
    template:
    sefcontext:
    lineinfile:
    sysctl:
    file:
    user:
    group:
    authorized_key:
    stat:
    debug:
    11. Name the tasks and playbook

  124. Hello Tomas,

    Thank you very much for preparing a sample exam. If one is able to solve this sample exam, will he/she be able to pass the actual redhat ex407 exam?

  125. I ssh onto the servers in the inventory as automation user but can’t go to root as it says incorrect password. I have edited the /etc/sudoers file but can’t get it to work. can I see the answer for questions 1 and 2 ?

  126. Hi Tomas,
    first of all, I want to thank you for this big effort.
    I am a newbie in ansible, and I am planning to take the exam.
    can you guide me to accomplish my goal?
    from zero to pass the exam.
    thank you so much.
    cordialy

    • Hi Rachid, thanks. To prepare for the exam, I would suggest you to start with creating a homelab. I’d say get a couple of RHEL/CentOS VMs deployed and start writing playbooks to cover all exam objectives. Use Ansible documentation as much as you can.

  127. Hi Tomas,
    First of all congrats on achieving your goals.
    This site is top notch on how to prepare to RH certificate exams.
    Right now i’m preparing for ex407 exam and this example exam really sharpened my ansible skills.
    Just one question regarding your remark “don’t run your playbooks with root privileges”
    In general not related to exam do you mean to use “become” in playbook where privilege escalation needed?

    Thank for this great practice exam

    • Hi Yuri, thanks very much.

      That’s right, I’d suggest to use “become” where privilege escalation is required.

  128. Hello Tomas,

    does ansible connect to galaxy.ansible.com for installing selinux RHEL system roles or is it an inbuilt role? please advise

    • Thank you for the reply, Tomas. So does it mean that we have to install rhel system roles using yum instead of ansible-galaxy if any questions come in regards to rhel system roles in ex407? please suggest.

    • Does that mean we need to install rhel system role using yum instead of ansible-galaxy? pls suggest.

    • Hi Antony, sorry about that, I appreciate your intent to share the discount code. To be honest with you, I felt that some of your tips and suggestions while extremelly useful, were perhaps too specific and related directly to certains tasks that appeared on the exam.

  129. Hello Tomas

    First of all, excellent entry, I’ve failed my first examen attempt but I’m studying to pass it!
    In the task 9, I’ve some doubts, since I’m facing the bellow issue.
    1st Task – Create the partition – Success
    2nd Task – Creat the VG – Fails, device not found

    However, when I re-run the playbook, the tasks are completed without errors… I’ve already tried to add a setup task to gather facts after the partition is created and before the VG is attempted to be create, but this still fails and I have no idea what else to do. Hope you may help to clear this doubt.

    PLAY [Task 9 Create and Work with Roles] *******************************************

    TASK [Gathering Facts] ***************************************************************
    ok: [node4.ansi.example.com]

    TASK [sample-mysql : Create a primary partition] ****************************************************************
    changed: [node4.ansi.example.com]

    TASK [sample-mysql : Update facts from server] ***************************************************************
    ok: [node4.ansi.example.com]

    TASK [sample-mysql : Create a VG] ***********************************************************************************
    fatal: [node4.ansi.example.com]: FAILED! => {“changed”: false, “msg”: “Device /dev/sdb1 not found.”}

    When I re-run, there’s no error
    TASK [sample-mysql : Create a primary partition] ************************************************
    changed: [node4.ansi.example.com]

    TASK [sample-mysql : Update facts from server] ************************************************
    ok: [node4.ansi.example.com]

    TASK [sample-mysql : Create a VG] ***************************************************************
    changed: [node4.ansi.example.com]

    • Hi Hugo, thanks. I’d suggest to enable verbose logging and check the output to see if the partition exists during the first run.

    • Thanks for the tip Tomas, however still can’t figure out why this is not working the first time.

      This is the output when running first time

      TASK [sample-mysql : Create a primary partition] *********************************************************************************************************************************************************************************************
      task path: /home/automation/plays/roles/sample-mysql/tasks/main.yml:5
      changed: [node4.ansi.example.com] => {“changed”: true, “disk”: {“dev”: “/dev/sdb”, “logical_block”: 512, “model”: “ATA VBOX HARDDISK”, “physical_block”: 512, “size”: 2097152.0, “table”: “gpt”, “unit”: “kib”}, “partitions”: [], “script”: “unit KiB mklabel gpt”}

      TASK [sample-mysql : Create a VG] ************************************************************************************************************************************************************************************************************
      task path: /home/automation/plays/roles/sample-mysql/tasks/main.yml:16
      fatal: [node4.ansi.example.com]: FAILED! => {“changed”: false, “msg”: “Device /dev/sdb1 not found.”}

      It seems isn’t creating the partition 1!!

      But when I run again the playbook, it creates it.

      TASK [sample-mysql : Create a primary partition] *********************************************************************************************************************************************************************************************
      task path: /home/automation/plays/roles/sample-mysql/tasks/main.yml:5
      changed: [node4.ansi.example.com] => {“changed”: true, “disk”: {“dev”: “/dev/sdb”, “logical_block”: 512, “model”: “ATA VBOX HARDDISK”, “physical_block”: 512, “size”: 2097152.0, “table”: “gpt”, “unit”: “kib”}, “partitions”: [{“begin”: 1024.0, “end”: 819200.0, “flags”: [“lvm”], “fstype”: “”, “name”: “primary”, “num”: 1, “size”: 818176.0, “unit”: “kib”}], “script”: “unit KiB mkpart primary 1MiB 800MiB unit KiB set 1 lvm on”}

      TASK [sample-mysql : Create a VG] ************************************************************************************************************************************************************************************************************
      task path: /home/automation/plays/roles/sample-mysql/tasks/main.yml:16
      changed: [node4.ansi.example.com] => {“changed”: true}

      So, still have no idea why is not working… this is the only task of your post that I’m not able to complete with success.

      These are the tasks

      – name: Create a primary partition
      parted:
      device: /dev/sdb
      flags: [ lvm ]
      number: 1
      state: present
      label: gpt
      part_start: 1MiB
      part_end: 800MiB
      part_type: primary

      – name: Create a VG
      lvg:
      vg: vg_database
      pvs: /dev/sdb1

      I’ll really appreciate any hint to solve this.

  130. Hi Tomas

    The partition array is empty since isn’t creating any partition, but if I add 2 times the same task, the first fails and the second is a success.

    I’ve seen the output of the fdisk command over the disk with the issue and I got this

    [automation@node3 ~]$ sudo fdisk /dev/sdb
    Welcome to fdisk (util-linux 2.32.1).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    The old ext4 signature will be removed by a write command.
    Device does not contain a recognized partition table.
    Created a new DOS disklabel with disk identifier 0x419057c0.

    “The old ext4 signature will be removed by a write command.” <—– I guess this is not normal. But I've seen this in the machines from the Lab I used for this testing, RHCE8Env.
    Once I save the changes of the new DOS disklabel created, I can run the parted task without issues.

  131. Hi Tomas,

    Want to know, during the exam, if we will be provided access refer to the Ansible documentation like: https://docs.ansible.com/ansible/2.8/modules/yum_module.html#examples

    Otherwise, how are they expecting us to remember all the parameters to all the hundreds of different modules used in Ansible.

    Would like to know your thoughts on this topic.

    Thank you!

    The above comment is with respect to “referring the Ansible documentation during the exam”

    • Hi, as you probably already know, Ansible documentation will be provided. I’m sure you’ll understand that I can’t go into any more detail than that.

      You should also be familiar with ansible-doc. Last but not least, I believe that there is a certain level of expectation for a candidate to know, and have experience with, most commonly used Ansible modules for system administration tasks which are listed under the exam objectives.

      The best part about Ansible is that you can pick the module you want as long as you solve the problem. It’s the outcome that matters really. For example, there are half a dozen of ways to partition a disk. You only need to know one to be able to do that. I hope this helps.

  132. Hey there I’ve notice that after you’ve taken your 407 you’ve said that you don’t need any Linux knowledge only Ansible. So does that mean that you will be provided with the information that you need to put inside your Jinja2 tamplates? Is it going to be something like you’ve done in your sample exam. Also is the galaxy website also available, or do we have to use the cli to search for galaxy roles? I hope this is not too much revealing of an information.

    • Hi, I said that there is no advanced Linux knowledge required. You should be familiar with Red Hat Enterprise Linux if you take the exam. Also Ansible facts. Know what information they provide.

      There is no Internet access provided during the exam therefore the Galaxy website won’t be available, however, if required, local resources will be provided. I hope this helps.

  133. Thank you Tomas for providing this helpful tutorial.
    my question is do you know if there is a specific editor we can use to write the playbooks during the exam(EX407) ? or it is just enough to use vim ?

    • Hi, I think that you can install and use whatever text editor you feel comfortable with as long as it’s available from a base repository, or RHEL DVD (if you use a locally mounted ISO file as a repo).

  134. Wow! Finish the sample exam like for about 4 hours. Great questions provided! Much better than the book exams I read before.

    Tomas, I would like to ask you some questions about the real ex294. Can I run the playbooks in the exam that may not finished and have some mistakes thus cause the managed hosts no needed change. For example, If I write the condition wrong and create a no needed user on a host. Do I need to remove the user. Or as long as I have the correct playbooks/scripts they just run on clean hosts against?

    Thank you!

  135. Hi, Reg Task2 :
    “SSH key (that you generated) is copied to all inventory hosts for the automation user and stored in /home/automation/.ssh/authorized_keys.”

    Do we copy the actual key to the remote hosts via ad-hoc command in script or do we copy the file itself from ansible node to remote hosts ?

  136. I think on task 16 there is a missing package for the database host group. Or there is a typo with the second and?

  137. Hi Tomas,

    I have a question regarding the vault questions. It is possible in 2 ways to make the reference to the key file (command or via ansible.cfg)

    Do you have any idea how this is judged on the exam? Should it be via command file or ansible.cfg? or is it up to me to make the choise?

    • Hi, yes, you can either specify the vault key on the CLI, or you can specify it in the ansible configuration file.

      All changes that you make during the exam must be persistent. Therefore using ansible configuration file would be my preference.

  138. Hi Tomas! I’ve went trough all the tasks but i’m a little confused if I’ve approached the first task right, are those requirements from task 1 ment to be done also in a script?
    Thank you for the sample exam!

  139. Hi,

    Will be the ‘https://docs.ansible.com/’ available? Or a local copy of it as internet access won’t be provided?
    Or the only option is the ansible-doc cli?

    Thanks,

  140. Just a minor remark about task 13: What if the server has exactly 2048MB of RAM?

    Now the real question: I solved it by using two tasks: The first task with
    – sysctl …
    when: ansible_facts.memtotal_mb>2048

    and the second task with
    – fail:
    msg: Server memory less than 2048MB, Memory {{ ansible_facts.memtotal_mb }}
    when: ansible_facts.memtotal_mb<2048

    Now I wonder could it have been solved with only 1 task?

    • If the server has exactly 2048MB of RAM, then neither condition is met and the playbook does nothing.

      The question does not specify the number of tasks, therefore if it works, then it’s an accepted solution.

  141. Hello people,
    In first let me thank you for your help here creating exercises to prepare us for the exam.
    I’m here to share some complement to your help.

    Based on the requirements I’ve created an infrastructure to use has lab. This infrastructure is for VirtualBox and it’s created with vagrant.

    Here goes the project link:
    https://github.com/JoaoMJoia/vagrant-vb-rhce

    Any doubt contact me.

    Thanks again for the help here.

  142. Hi Tomas,
    thank you for this valuable resource, I’m another one that will afford the EX294 exam and your simulation is what I was searching for.

    I have a couple of questions regarding the real exam, since you already did it.
    1 – Does Red Hat allows you to use the GUI “Text Editor” or you are forced to use “vim”?
    2- Can you switch between users login and work on the account that will effectively manage the control node?
    Thank you a lot for your time and generosity.
    GP

    • Hi! Yes, a graphical user interface is usually available during Red Hat exams, therefore you do not have to use vim if you don’t want to.

      I’m not sure what you mean by your second question, sorry. You will be given accounts to work with. I hope this helps!

    • Hi Tomas,
      thank for your fast reply, and sorry for not being clear.

      For the last question, I meant this:
      since the exam very likely will require to have to create another user on the control machine, that will execute ansible playbooks, I was wondering if I can switch to the new created account for creating and running the playbooks.

      The exam will be a remote exam, like a kiosk but from home, and I’m trying to optimize my habits to cope with work to do in a strict time.

      Thank you for you kindness.
      GP

  143. Thank you very much.

    One last question, since reading other posts seems that you had kiosk/remote exams.
    Your device (latpop or workstation) is the control node and you work on that? Or you work directly on remote virtual machines?

    Thank you
    GP

    • No worries! Yes, I took individual exams (KIOSK) because it was easy to schedule them. You basically work with a remote system using a web browser. I can’t tell you any more than that without breaking NDA.

  144. Heyy Tomas!
    I wanted to know that “can we access the manged nodes and see things have worked or not for conformation”?
    or we just have to use ansible-adhoc command every time.
    and also make minor changes direct to the managed node? or is there any problem with that?

  145. Just wanna say thanks.
    I passed the EX294 today with 300 point/100% on every objective. Your guide was a HUGE help.
    I am preparing for EX447 now.
    Thanks again!

    • Hi, I get this asked every once in a while. I’m not sure how this would work to be honest with you because I already know what’s on the real Ansible exam.

      I would need to make sure that no real exam questions appear in my sample exam due to NDA. It gets a bit tricky here. You’d know for a fact that my sample exam questions will not be on the exam. Would you still solve them? I doubt it. Most people won’t I reckon.

      When I created this sample exam for EX407 I was using RHLS and its study material. It was relatively easy to match the exam objectives with Red Hat’s study guide. Even more, there were sample questions provided by Red Hat that in some form ended up in my sample exam. I think this is one of the reasons why this sample exam is so successful.

  146. Hi,
    i m so thankful for the help, i would really know if we still work with the same session as root user or we must switch to automation user, and perform task of creating ssh-keygen

    • after finishing task 1, we must switch to automation user and perform all required tasks using that automation.

    • Yes, that is correct. Use should use the automation user for all sample exam tasks and playbooks unless you are working on the task #2 that requires creating the user.

  147. in task 6, should we add another plays to copy ssh-key in authorized_keys for each user to allow thein connect to that server without using pasword ????????

    • so we need to involve another play in the same playbook with a blockinfile module to copy the ssh-key in home dir (authorized_keys) for each user. won’t that large playbook take a lot of time. Thanks for your cooperation

    • That is correct, you have to have a play within the playbook that copies the SSH key for each user. In terms of time, you have 4 hours to solve all tasks.

  148. in this part of exam task 5: Store Ansible vault password in the file /home/automation/plays/vault_key.
    must we encrypt that file ? or store the pass in plein text form ???? thanks in advance.

  149. Hello Tomas,

    I would like to create a playbook that executes the command ‘df’ and after a while, if the command does not respond and remains in the app, it must proceed with the other hosts. I can’t find any solution to this problem.
    I have tried everything about command timeout but nothing.
    Could you help me find a solution?
    Thanks

    • You could simply add the Linux “timeout” command before “df”. That way “df” will be killed after a specific timeout :)

      ansible all -i inventory.yml -m command -a “timeout 10 df”

  150. Hi Tomas,

    Are there any solutions to the sample questions you posted somewhere? If yes then would be able to share them.
    Thanks in advance

    • Hi Vikas, not that I’m aware off. I encourage people not to post answers because there are different ways to solve questions, and more importantly, doing so defeats the purpose of the sample exam.

  151. Hi Tomas, this question is not about the question of the exam but has a working purpose.
    If you have any suggestions to give me, I would be very grateful.

  152. Hi Tomas,

    Just took my EX294 yesterday and passed. I prepared by using Sander’s cert guide and used your practice exam as a benchmark. Thanks so much for creating this! This practice exam was considerably more difficult than the actual exam itself, which I really like. I work on a team of engineers and am sharing this exam with others preparing for the EX294.

    • Hi Cory, thanks for letting me know, that is amazing, congratulations.

      It’s much better to be overprepared than underprepared!

    • Hi Cory
      I have a question to You. Do I have to write playbooks during the exam and then run them or just write. Are the materials in the Sander’s book and sample exam on this website sufficient for pass EX294?

    • Hi Radek,

      Sorry just saw your questions. You do have to write playbooks and run them, yes. Also, Sander’s materials are more than enough prep for the exam. I studied using only his materials and finished in just over 3 hours w/ an 88% pass.

  153. Hey Tomas,

    Thank you so much for compiling and sharing this practice exam! It makes for a good exercise, moving towards EX407 in its final days. A few of the tasks made me investigate things I’d never done or seen before! Task 18 for example was a nice eye opener.

    • They had the nerve to copy somebody’s content that’s available on a public domain free of charge, and present it as their own work without giving any credit? That’s unheard-of. How dare they? What a shame.

    • Hi, thanks for bringing this to our attention.

      The article was promptly removed without incident despite being heavily modified. About the only connection to the original source would be the task names. It was a mistake here not to credit the original author but as you know public domain doesn’t require that. The article was removed now but you can check the git log if you want to see what the original looked like. Please don’t make this a bigger incident than it has to be. Thanks!

    • I think there is some misunderstanding here.

      My previous comment was pure sarcasm, nothing more, nothing less. A poor attempt to highlight the fact that the content that I produce is on a public domain, and people copy it without giving credit all the time. I can only apologise if this was not clear.

      I did not contact you because your copied something. I contacted you because you claimed the work to be your own, and I quote:

      “The materials and examples used are our own […]”

      I would like to make it clear that the decision to remove the article was yours. I made no such request. I said that giving credit to my website would have been nice, and also wished you to keep up the good work, because your website does have good study material and a lot of useful information overall.

      You said that about the only connection to the original source would be the task names, and that it was heavily modified. I respectfully disagree.

      Take the task about security for example, this is your version:

      Create a playbook at `~/automation/plays/selinux.yml` and does the following:

      * Uses the selinux RHEL system role
      * Enables httpd_can_network_connect boolean on the web group
      * All changes must survive a reboot

      This is mine:

      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.

      Or a task about managing services, this is your version:

      Create a playbook at ~/automation/plays/target.yml that runs on the web group:

      * Set default boot target to multi-user

      This is mine:

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

      * Sets the default boot target to multi-user.

      Or a task about custom facts, this is your version:

      Create a playbook at ~/automation/plays/facts.yml that runs on hosts in the db group:

      * A custom Ansible fact server_role=mysql is created and can be retrieved from ansible_local.custom.sample_exam using the setup module.

      This is mine:

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

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

      There are many more, you can check that on GitHub, but I think that I have made my point.

      On a totally different topic, I’d like to thank you for your work on Rocky Linux so far. I’ve been following Slack messages and the project is really moving forward nicely.

    • Thanks for working these things out so quickly Tomas and Remyabel.

      I wasn’t aware Tomas, that your works are public domain. There is no notification thereof and at the bottom it says “copyright etc.”. Hence why I assumed that, in the least, it’d be a good idea to inform you.

      I’m glad you got things sorted!

    • I sense some confusion here. When I say that my content is available on a public domain, I mean that it is available on the Internet, for everyone, and without any form of subscription etc. There is no limit on who can access it, and it is free of charge for non-commercial use.

      I do not mean “public domain” as in Creative Commons lincence or any legal terms, there is no logo nor statement to suggest that. My content is indeed under copyright by default, as the footer of the website says, because I created it. I hope this clarifies things, and thanks very much for your comments!

  154. Thanks for the response.

    Admittedly I did not look too closely because I had no involvement in writing the article (my colleague did) so I’ll pass the information on to them. Not that it excuses anything, but that disclaimer looks more of a general “please do not associate this with redhat” and we’ll try to avoid making this mistake in the future.

    • No worries, that’s for letting me know, appreciated. All the best to you, and I hope we’ll get to talk on the Rocky Linux channel at some point in the future.

    • Hi, Red Hat announced that they will retire EX407 several months ago. You can still purchase the exam by the end of the year. You will not be able to purchase it in 2021.

  155. thank you for the response,

    if i buy it before the end of this year, will i be able to take the exam in the next year,i mean 2021 ?

    • Don’t quote me on this, but I think that you have 12 months after purchasing the exam to take it. Please check with Red Hat just to be on a safe side. Good luck with your exam!

  156. Passed the Ex294 a few days ago, and this sample exam really helped, without it, I think I maybe fail my exam. Thanks again, Thomas!
    For me, I don’t think this sample exam is more difficult than the real exam, I think it’s the same, the real exam is as difficult as this one.
    I got pretty low score on ansible vault though, don’t know why, I thought I’ve done it pretty well.

  157. Just wanted to say “thank you” once more. I passed the EX407 exam, on the cusp of it going EOL. Now that the adrenaline rush has ebbed away I almost feel like it was too easy, or that RH made a mistake in scoring my test. Out of 16 tasks I know I did not complete 3, but I passed in the end with 239 point (where 210 were needed).

    Still. Your sample exam is worth its weight in gold and I wanted to say I really appreciate the work you put into it!

  158. Hi,

    I’m here just to thank Tomas for this! I just passed EX294 with score 284/300! I studied with RHLS and executed this sample test until i was capable of resolve everything in less than 4 hours.

    Again thank you a lot for this and I will for sure recommend this with my coworkers and friends!

    • Nicely done, 284/300 is a very high score! You practised a lot and it was the key to success!

      As always, thanks for your feedback, it’s good to know it helped.

    • hi im planning to take the exam , but i don’t have the study materials , would you please guide me where to find it as im a self learner

  159. for task number 6 :

    this is my playbook :


    – hosts: all
    vars_files:
    – ./user_list.yml
    – ./secret.yml
    tasks:
    – name: create users in web servers
    user:
    name: “{{item.username}}”
    passwprd: “{{ user_password | password_hash(‘sha256’) }}”
    groups: wheel
    append: true
    when: ‘”webservers” in group_names and “12” in item.uid|string’
    with_items:
    – “{{users}}”
    – name: create users in database servers
    user:
    name: “{{item.username}}”
    passwprd: “{{ user_password | password_hash(‘sha256’) }}”
    groups: wheel
    append: true
    when: ‘”database” in group_names and “12” in item.uid|string’
    with_items:
    – “{{users}}”

    – name: Deploy Local User SSH Key
    authorized_key:
    user: “{{item.username}}”
    state: present
    manage_dir: true
    key: “{{ lookup(‘file’, ‘/root/.ssh/id_rsa.pub’) }}”

    – name: Setup Sudo Access for “{{item.username}}” User
    copy:
    dest: /etc/sudoers.d/”{{item.username}}”
    content: ‘”{{item.username}}” ALL=(ALL) NOPASSWD: ALL’
    validate: /usr/sbin/visudo -cf %s


    – hosts: all
    vars_files:
    – ./user_list.yml
    – ./secret.yml
    tasks:
    – name: create users in web servers
    user:
    name: “{{item.username}}”
    password: “{{ user_password | password_hash(‘sha256’) }}”
    groups: wheel
    append: true
    when: ‘”webservers” in group_names and “12” in item.uid|string ‘
    with_items:
    – “{{users}}”
    – name: create users in database servers
    user:
    name: “{{item.username}}”
    password: “{{ user_password | password_hash(‘sha256’) }}”
    groups: wheel
    append: true
    when: ‘”database” in group_names and “12” in item.uid|string ‘
    with_items:
    – “{{users}}”

    – name: Deploy Local User SSH Key
    authorized_key:
    user: “{{item.username}}”
    state: present
    manage_dir: true
    key: “{{ lookup(‘file’, ‘/root/.ssh/id_rsa.pub’) }}”
    with_items:
    – “{{users}}”
    when:
    – ‘”webservers” in group_names and “12” in item.uid|string ‘
    – ‘”database” in group_names and “12” in item.uid|string ‘

    – name: Setup Sudo Access for “{{item.username}}” User
    copy:
    dest: /etc/sudoers.d/”{{item.username}}”
    content: ‘”{{item.username}}” ALL=(ALL) NOPASSWD: ALL’
    validate: /usr/sbin/visudo -cf %s
    with_items:
    – “{{users}}”
    when:
    – ‘”webservers” in group_names and “12” in item.uid|string ‘
    – ‘”database” in group_names and “12” in item.uid|string ‘
    ~

  160. HI,
    I don’t know why i got an error msg in the exam environment about haproxy task, “Unable to access hostvars ..haproxy has no attribute ansible_eth0”
    i was trying so many solutions such as define mannually ansible_eth0, define the vars iface on the playbook itself but without any hope the haproxy always stopped while searching the right varaible.

    • Hey, mate!

      I hope I’m not too late. Ansible error messages can be cryptic and not helpful. It seems that your issue is that you’re trying to access a variable from a host that’s not part of the playbook. It could happen, for example, if you’re trying to grab the IP addresses of the backend web servers, but you’re running your playbook against the proxy server.

      For instance, say that you have 2 hosts in your inventory, ansible-1 and ansible-2, and the following playbook:

      – hosts: ansible-1
      tasks:
      – debug: var=hostvars[‘ansible-2’].ansible_eth0

      This task will fail because Ansible didn’t gather facts about host ansible-2. Ansible gather facts about the hosts included in the ‘hosts’ section, and it can take a LOT OF TIME in troubleshooting until you figure that out.

      Hope it helps. Peace.

  161. Hello, I have an issue:
    I have installed rhel-system-roles using yum and I can see them using “ansible-galaxy list” and default ansible.cfg, but when I change “roles_path” like “roles_path = /home/automation/plays/roles” ansible-galaxy list won’t show them anymore.
    Can someone please advice?

    • Hi, have you also copied your system roles in to the folder /home/automation/plays/roles? Ansible is looking for roles inside that folder as per your configuration, if the roles are not there, then nothing will be listed.

      If you don’t want to copy the roles, you can specify multiple colon-separated paths in your ansible.cfg, e.g.:

      roles_path = /home/automation/plays/roles:/usr/share/ansible/roles
  162. to save time i do this which i may think it will help someone :
    – start with short playbooks and then the roles ” please consider the order as there some tasks related to others”
    – in your playbook start by listing the tasks names then filling the modules you need for them , for examples like in task 9 i just copy the questions and paste it in my playbook file then edit it as name descriptions for my plays :
    ————————————
    – name: A primary partition number 1 of size 800MB on device /dev/sdb is created.
    parted:
    – name: An LVM volume group called vg_database is created that uses the primary partition created above.
    lvg:
    – name: An LVM logical volume called lv_mysql is created of size 512MB in the volume group vg_database.
    lvol:
    – name: An XFS filesystem on the logical volume lv_mysql is created.
    filesystem:
    – name: Logical volume lv_mysql is permanently mounted on /mnt/mysql_backups.
    mount:
    – name: mysql-community-server package is installed.
    yum:
    – name: Firewall is configured to allow all incoming traffic on MySQL port TCP 3306.
    firewalld:
    – name: MySQL root user password should be set from the variable database_password (see task #5).
    mysql_user:
    – name: MySQL server should be started and enabled on boot.
    service:
    – name: MySQL server configuration file is generated from the my.cnf.j2 Jinja2 template with the following content
    template
    ——————
    that will give you space to see the ansible-doc moduleName if you forgot something and will speed time for you

    hope this helps ^_^ and please if you have any advice to hep share it

  163. on task 2 the adhoc script
    i cant think of not using the -u root -k to prompt for the password
    is this acceptable or i need to provide the password in the script in some how ?
    and in the same task i will need to disable the “StrictHostKeyChecking” on the global ssh config and the “host_key_checking ” on the ansible.cfg file so no prompts will interrupt the script

    please help :(

  164. task 2 ” my solution ”
    #!/bin/bash
    sshpass -p toortoor ansible all -m user -a ‘name=mero password=”devops | password_hash(‘sha512′)” state=present’ -u root -k
    sshpass -p toortoor ansible all -m authorized_key -a “user=mero key='{{ lookup(‘file’, ‘/home/mero/.ssh/id_rsa.pub’) }}’ state=present” -u root -k
    sshpass -p toortoor ansible all -m shell -a ‘echo “automation ALL=(ALL) NOPASSWD:ALL” > /etc/sudoers.d/mero’ -u root -k

  165. Hello,
    Just wanted to say my thanks. Passed RHCE on 01JAN2020. I ran through this practice test multiple times. Breaking and fixing, trying different ways to complete the tasks. Thank you for the great content.

  166. Hi,
    i wanna know if i can take the EX294 exam without passing through RHCSA v8, i have already EX407 and RHCSA v7, i will be grateful if you can guide me

  167. Hi Lisenet. Please answer me here. Task number 2. If the automation user will create a user to all nodes (how can he do it, when it doesnt have access yet, or ssh-key define)

    question is. Does it mean. it is the root account that will create a script and run a ansible-adhoc command to all the nodes?
    Thanks

    • Hi, yes, since the automation user does not exist on the remote systems (the task is to create said user), you can use the remote root account to execute adhoc commands.

  168. Hello all
    Practicing for my test I found something that I think is a bug.

    If I set a non hashed password in a variable on a vault, and then try to use this line in the user module

    password: “{{ user_password | password_hash(‘sha512’) }}”

    the user account will be created but the password will not work.. If I add the debug module to the play to call the variable and hash it on the msg output I can see that the variable in the vault is called and then hashed.


    – name: debug password on vault
    hosts: all
    become: true
    vars_files:
    – secret.yml
    tasks:
    – name: Debug password from vault
    debug:
    msg: “{{ ‘user_pass’ | password_hash(‘sha512’)}}”

    – name: create user using var from vault and hashed pass
    user:
    name: user1
    password: “{{ ‘user_pass’ | password_hash(‘sha512’) }}”
    state: present

    Could anyone confirm if this is normal.?

  169. If EX407 is retired. Then the EX294 is the new ansible exam. What does it call you after you pass? RHCE?
    Or Linux Automation Engineer?

    Why did they retired the ex407? WHy not stick to the old exam for RHCE and Ansible.

    • If you wanted to become an RHCE on RHEL7, you had to pass the EX300 exam.

      With the release of RHEL8, Red Hat updated the RHCE exam objectives and re-named it to EX294. They did it in order “to reflect the need for the automation knowledge required to deploy, manage, and support a container-based architecture – making RHCE credential even more valuable and relevant”. I copied this from Red Hat’s website.

      If you passed EX300, you become RHCE on RHEL7. If you passed EX294, you become RHCE on RHEL8. Either way you still get the Red Hat Certified Engineer credential but for a different version of RHEL.

      I don’t know the official reason behind the retirement of the EX407 exam, but I suspect it’s because of EX294 – it is unreasonable to offer two pretty much identical exams in terms of objectives. One of them had to go.

  170. Hi Thomas,

    I could see that passing the EX407 was counting toward becoming a Red Hat Certified Architect, but EX294 can only serve as a foundational step on the path toward highest level of certification, this can cause a problem for me because if I take EX294 instead of retired EX407 which is the ansible exam that I deeply prepared for, It will not be a step forward toward RHCA, because EX294 is not one of the base certificates exam, add to that that I have passed RHCE based on rhel7 in the past.

    Let me know your input please, I was about to book EX407 until I found that it is marked as retired today

    • Hi, you are right, EX407 used to count towards RHCA, because it was an RHCA-level exam. Unfortunately the EX407 exam is no longer available.

      EX294 is the RHCE exam for RHEL8. If you are a Red Hat Certified Engineer already and want to progress towards Red Hat Certified Architect, then you don’t need to take EX294 (you are already an RHCE).

    • Hello nicortoso,

      I am facing the same problem as you …

      I spent 3 months preparing the EX407, I failed the exam in mid December, I wanted to re-register to take it again at the beginning of the year and it is no longer possible. I also have RHCE certification on RHEL 7 valid for a while. So I discovered the following exam which is eligible for RHCA: EX358. The subjects are those of the RHCE (RHEL 7) that you passed (Network, Bind, Apache, Nfs, Samba …), and using “Ansible”. I intend to personally orient myself towards this exam.

  171. Just wanted to say thank you for taking the time to post these sample exams, I passed EX407 today.. it was NOT easy but I did it! Cheers

  172. Hi Tomas,
    DO we have a link for ansible that will explain or educate us regarding (.split) (hostvars[groups]first]? Anything that will explain them. WHen and how to sue them? And explain what is hostvars

    {{ hostvars[groups[‘master’]|first][‘kubeadm_hash’].stdout }} -> this is first of the host
    – name: Uptime
    debug:
    #msg: “{{ users.results[0] }}”
    msg: “{{ users.stdout.split(‘\n’) }}” -> this will split the line

  173. question-related to task2..
    On the controller node we have an automation user.. do that user has sudo power?
    if not, we need to copy ssh public key to root@hostname first then use -u to adhoc commands.
    but to ssh-copy-id we also don’t have password for managed node?
    can anyone give me any better approch to solve this?

    • I’m not sure I follow, sorry. You said “we need to copy ssh public key to root@hostname first”. What is the reason behind this?

      On the control node, you have generated an SSH key using the automation user. The automation user has access to the key. It can therefore copy it to all managed nodes using a remote root account for login.

  174. When asked to “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.” how do we approach this one? because if I specify ‘roles_path = ‘ in ansible.cfg – then rolls work in there, but other playbooks say using reel system roles do not work after that modification. Is there any way to avoid this?

  175. I learned this in a hard way and painful way. Tomas, why below is no longer working in Ansible 2.9? gather_facts=yes

    {code}
    {% for host in groups.all %}
    {{ hostvars[host][‘ansible_all_ipv4_addresses’][0] }} {{ hostvars[host][‘ansible_fqdn’] }} {{ hostvars[host][‘inventory_hostname_short’] }}
    {% endfor %}

    {code}
    FAILED! => {“changed”: false, “msg”: “AnsibleUndefinedVariable: ‘ansible.vars.hostvars.HostVarsVars object’ has no attribute ‘ansible_all_ipv4_addresses'”}

    • Hi, I’ve just tested this on Ansible 2.9, and it works fine. Make sure that you gather facts for all hosts, and not just the ones you run your playbook against. You can try your playbook with hosts: all to see if that works.

  176. Tomas,
    wow this is just wow. It works if i will use hosts: all but not hosts: test or hosts: db.
    Why? this cause me confusion during one of the important things i need to do that. doesnt make sense to me.

    • You are using a Jinja template that requires access to a specific fact ansible_all_ipv4_addresses from all groups. This is due to for host in groups.all. For this to work, you must gather facts from all groups.

      You cannot gather facts for a specific group, e.g. db, and expect Ansible to know the value of ansible_all_ipv4_addresses for a host that is in a different group, e.g. test. I hope this clarifies things for you.

  177. System Role Network is not working? I have a machine in a private network, trying to use linux-system-roles.network, i tried –offline as flag is not working.

    [WARNING]: – linux-system-roles.network was NOT installed successfully: Unknown error when attempting to call
    Galaxy at ‘https://galaxy.ansible.com/api/’:

  178. Thats one my problem too, If my machine is doesnt have access to internet, How am i able to use the ansible-galaxy?
    How can I use the role?

    • Hi Tomas,, You mention that we need to access internet to perform sample exam. But in exam there will be no internet right? there will be no connection. So how will we deal witht this? Do you have the steps or the idea?

    • If you don’t have access to the Internet, then you cannot download roles from Galaxy.

      Out of curiousity, I can see that you have posted over 60 comments. Why use a different username every time? It’s a bit confusing, that’s all.

  179. Download and use roles with Ansible Galaxy – is one of the exam objectives, then how can you use an ansible galaxy?

  180. I passed my exam. Thank you for this sample..

    The results of your recent EX294 Red Hat Certified Engineer Exam are reported below.

    Exam domain number: 4
    Passing score: 210
    Your score: 225

    Result: PASS

    Congratulations — you have earned the Red Hat Certified Engineer certification.

    Performance on exam objectives:

    OBJECTIVE: SCORE
    Understand core components of Ansible: 70%
    Install and configure Ansible: 100%
    Run ad-hoc Ansible commands: 100%
    Use Ansible modules for system administration tasks: 71%
    Create Ansible plays and playbooks: 70%
    Create and use templates to create customized configuration files: 100%
    Work with Ansible variables and facts: 62%
    Create and work with roles: 93%
    Download and use roles with Ansible Galaxy: 0%
    Use Ansible Vault in playbooks to protect sensitive data: 43%

    • Hi,

      I need help to pass the exam, I did it 15 days ago and I failed, before trying again I would like to be able to specify some doubts that I have, especially with the adhoc question, since I do not know exactly the failure and in some forums I read that it goes With another module, could you help me to pass the exam on the second try? I’m a bit lost and can’t find much help, thankful in advance

    • Hi Aris,

      You can give me an email so I can talk to you about the exam topics, I showed up 15 days ago and did not pass the exam and I have some doubts that I cannot solve, for example ad-hoc run which was 0% in my score, please Could you help me to pass the exam on the second try? thanks in advance.

      All the best.

    • This is the domain number assigned to your workstation during the exam. When you sit a classroom exam, each workstation has a number allocated to it. It is the same for individual exams as well, you just don’t see other exam takers and their workstations.

    • in the exam environment – what would be the best way to copy paste between windows and for opening new terminals… Ctrl + Shift + T …

  181. Great work Tom. I passed EX294 exam this weekend with perfect 100% score in first attempt for exam domain number 20. I used RH course, labs and ansible docs for my learning / practice, and used this sample exam to test my knowledge. It has been very helpful to explore ansible from different perspectives. Thanks for the good work.

  182. Im trying to do TASK2 within a playbook :


    – name: tasks
    hosts: prod
    remote_user: automation
    become: yes
    vars_files: myvault1.yml

    tasks:
    – name: create the user
    user:
    name: automation
    shell: /bin/bash
    password: “{{ my_password | password_hash(‘sha512’) }}”
    ssh_key_file: .ssh/id_rsa
    generate_ssh_key: yes
    ssh_key_bits: 2048

    – name: Configure sudo perms
    copy:
    content: “automation ALL=(ALL) NOPASSWD: ALL”
    dest: /etc/sudoers.d/automation

    – name: Copy SSH keys
    authorized_key:
    user: automation
    key: “{{ lookup(‘file’, ‘/home/automation/.ssh/id_rsa.pub’) }}”
    path: /home/automation/.ssh/authorized_keys
    state: present

    Im getting tje following which is logical :

    fatal: [node3]: UNREACHABLE! => {“changed”: false, “msg”: “Failed to connect to the host via ssh: ansibleuser@node3: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).”, “unreachable”: true}

    But Im confused , how we’re gonna create the automation user on the managed nodes , do we have to make it manually ? But that it’s contradicting with what TASK 2 requires.

    • Hi, please read the requirements section carefully. The contol node has passwordless SSH access to all managed servers (using the root user). Also, task 1 has the following reminder: you have root access to all five servers.

      You can’t use remote_user: automation because that user does not exist on managed nodes. The task is to create the user using ad-hoc commands.

  183. Ho Tomas,
    If you can explain for morons :)

    now, IF I understand well:
    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:
    User automation is created on all inventory hosts (not the control node).
    SSH key (that you generated) is copied to all inventory hosts for the automation user and stored in /home/automation/.ssh/authorized_keys.
    The automation user is allowed to elevate privileges on all inventory hosts without having to provide a password.

    A. control node has passwordless access to all managed node or should I deploy sshkey of root to all managed nodes ?
    B. automation user already exists on managed node (should only generate sshkey) ?
    B.1 SSH key (that you generated) => I supposed is generated on controlnode for user automation ?

    C. in order de deploy user automation on all managed nodes: as root : ansible all -m command -a “useradd automation”

    I know some of RH exams are bit confusing but…..

    • Hi Florin, thanks for your message. See answers to your questions below.

      A. Yes. This is mentioned in the requirements section: ansible-control.hl.local server has passwordless SSH access to all managed servers (using the root user).

      B. No. This is mentioned in the requirements section: there are no regular users created on any of the servers. Therefore the automation user does not exist on managed nodes. The task 2 requires you to create the automation user on all inventory hosts (managed nodes).

      B1. Yes. This is mentioned in task 2: generate an SSH keypair on the control node.

      C. In order to create a user on managed nodes, you can use the remote root account for SSH.

      I hope this clarifies things for you.

  184. First of all thanks for this great sample exam! It’s awesome!
    I have a question about Ansible Installation in the exam.
    Can Installing Ansible itself be one of the tasks in the exam? I cannot see that in the exam objectives, but since I want to be ready for the worst-case scenario this is my biggest concern at the moment (my exam is in 2 days).
    The reason it’s a concern is that since in the exam the nodes don’t have internet access, I am not sure how I can install Ansible. Can’t use subscription-manager since there is no subscription. PIP will also fail as there is no internet.
    Appreciate your help.

    • Thank you for your feedback, appreciated.

      Installing Ansible can be one of the tasks. If you look at the official EX294 exam objectives published on the Red Hat’s website, you will find this:

      * Install and configure an Ansible control node
      * Install required packages

      There can therefore be a task to install and configure Ansible packages on the control node.

      You don’t need Internet access to install packages if you have a locally available repository to download files from. Or your systems could be subscribed to a local Satellite server, making subscription-manager a valid option. If you use Pip, you can instruct it to search for packages in a given local folder instead using the Internet. I hope this answers your question.

    • I had seen those two exam objectives but thought it might be extra packages, not Ansible itself. Ok, now I know it can be :)
      I know about local repositories using FTP, HTTP, etc, and how to configure them, but didn’t know about the possibility of subscribing to a local Sattelite server or PIP using the local folder. I think I should read about them before the exam.
      Thank you again!

    • No worries, you’re welcome. In restricted environments where no Internet access is allowed, you will normally find a Satellite server that provides packages and security updates to your private network. I’ve also seen Pulp being used instead of Satellite where configuration management functionality of Satellite was not required.

      For homelab deployments a local repo with FTP/HTTP would be sufficient.

  185. Hello,

    Can we use group_vars folder during the exam ? Because I can see only playbook in comments.

    thx.

    • Hi, the sample exam is based on EX294 exam objectives. You can still use it to test your EX447 skills, but there will be topics that are not covered, e.g. Ansible Tower.

  186. Thank you for sharing this lab with us Lisenet!
    Having fun trying to crack down all the exercises in less than 3 hours…
    Can I ask you a question? Is the scenario “ansible-control.hl.local server has passwordless SSH access to all managed servers (using the root user)” accurate for the real exam? I’m studying on other example samples, like the one from Sander Van Vugt OReilly course, and part of the job is to create a script to deploy users and sudoers settings on all managed hosts (similarly to adhoc script in Task 2 of your lab sample)… but without the ssh-keys exchange!

    • Hi Marco, no worries, thanks for your feedback, and good luck with your studies.

      The task that you’ve mentioned is specific to the sample exam environment. In order to make my local deployment easier, I figured I would configure passwordless SSH access to all managed servers before starting to write ansible tasks. You can skip it if you have your VMs configured in a different way.

  187. Hello,

    For anyone that passed the exam: I DO have few things that I’m a bit worried:

    1. dynamic inventories
    2. looping facts => for instance: getting all interfaces that have IP defined, getting ALL disks and size of each one of them ?
    3. Using those advanced looping either inside playbook or jira2 template…

    • If you are worried about these areas, then I’d recommend practising the things that you’ve mentioned before taking the exam, and then you should be ready.

    • …still this doesn’t answer the main questions:

      are those advanced topics related to jira templates part of the exam as they aren’t covered by RH294 official docs/labs…

    • That’s something that you should check with the Red Hat’s certification team. They should be able to clarify this for you.

  188. Today I cleared my EX294 .. this sample test helped me a lot to do a better practice and prepare for exam !!

  189. I cannot accomplish the task 8 and task 9 on Rhel8.
    And I cannot install mysql-community-server on my server, is there a step that I missed?

    Can anyone help-me?

  190. Hello lisenet,

    First of all congratulations for the blog, know that it has helped a lot.

    in the third question, it doesn’t matter how I’m going to write my playbook, the important thing is to reach the goal, correct? on this issue I created an action for each group and it worked. But would you advise me to use another way?

    • Hi Gustavo, thanks. You are right, the important thing is to reach the goal, solve the problem. As far as I am aware, there is no one “correct” way to write Ansible playbooks, therefore I don’t have an advice in this case, I’m sorry.

      What I would suggest though is to check Ansible’s best practices, if you follow them, you should be good to go.

  191. First, thank you for your work. Highly appreciated.
    Just one question: Can I make the ansible user on control node sudo no password and run the adhocs commands as sudo to setup users on the managed nodes? That way I can access the root user keys on control to login on managed nodes and run the ad hoc commands. Is that the expected approach? There are many ways to do this, not sure best/acceptable approach.
    Is the approach above acceptable? Again, much thanks.

    • Hi, thanks for your feedback.

      I see what you mean. You can certainly configure sudo rules on the control node to allow the ansible user to execute commands using sudo without having to authenticate, and this approach would work. However, I’d say that such configuration is frowned upon in Linux land as it goes against best practices.

      If you look at the OpenSCAP guide that presents a catalog of security-relevant configuration settings for RHEL 8, you will find that there is a rule to ensure that users re-authenticate for privilege escalation. As a rule of thumb, you should only use sudo if you must execute commands on the control node that require elevated privileges, e.g. to install packages or to access LVM. In this particular case, you can SSH into managed nodes as the (remote) root user, therefore I would not use sudo to run ad-hoc commands.

    • Thank you for taking the time to answer. Really appreciate your contributions.

      Last question:
      Can I run the setup user ad hoc script as root user from control? Should I expect clear instructions from the exam?

      My apologies for all these questions, it is just the prep towards the exam. The sample exam I’ve done few times now no problem. Thank you very much.

    • No worries, the pleasure is all mine.

      You could run the ad-hoc script as the root user, and it would work, but the sample exam requirement is to use the automation user on the control node for all sample exam tasks and playbooks. The ad-hoc script should be created as /home/automation/plays/adhoc, which is in the home directory of the automation user.

      I appreciate that the wording of the sample exam might be a bit confusing in this case, but that’s what happens when you get too familiar with something – it just makes sense. For that I can only apologise.

      In terms of the real exam, I don’t remember exactly, I know that I had issues understanding some questions, and even left feedback using the form provided, but I’m not sure whether it was Ansible related on not – I’ve taken a few. I think that common sense should prevail. If you are given a regular user to work with, then you should assume that all tasks must be completed using that user, unless stated otherwise.

  192. Note: your answers are amazingly well developed and complete. I will certainly read the security guide best practices posted. Impressive. Sincerely, all the best.

  193. Task 18 — found en error in Ansible 2.10.7 on Ubuntu. I don’t understand the reason, but ansible get wrong ansible_fqdn, and only ansible_nodename shown fqdn (i use kvm). Tested CentOS 2.9.x without bug.
    2 question: is it important to sort fqdn names in file by name?

    $ ansible all -a “hostname -f”
    ansible3.hl.local | CHANGED | rc=0 >>
    ansible3.hl.local
    ansible2.hl.local | CHANGED | rc=0 >>
    ansible2.hl.local
    ansible5.hl.local | CHANGED | rc=0 >>
    ansible5.hl.local
    ansible4.hl.local | CHANGED | rc=0 >>
    ansible4.hl.local

    $ ansible all -m setup -a filter=*fqdn
    ansible3.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_fqdn”: “ansible3.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }
    ansible5.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_fqdn”: “ansible5”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }
    ansible4.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_fqdn”: “ansible4.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }
    ansible2.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_fqdn”: “ansible2.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }

    $ ansible all -m setup -a filter=*nodename
    ansible5.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_nodename”: “ansible5.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }
    ansible4.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_nodename”: “ansible4.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }
    ansible2.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_nodename”: “ansible2.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }
    ansible3.hl.local | SUCCESS => {
    “ansible_facts”: {
    “ansible_nodename”: “ansible3.hl.local”,
    “discovered_interpreter_python”: “/usr/bin/python”
    },
    “changed”: false
    }

  194. Hello
    Kind of nervous about the exam and probably starting to have really made up questions but here they are:
    1. Will I be provided with IP addresses of managed nodes to configure them? Or simply this work would be already done for me? Just starting with installing ansible on the control node?
    2. Would there be no repo configured on the control node for installing ansible and etc?
    3. Are there any other methods of installing ansible (not yum, pip3)?
    Sorry if you have already answered these questions, guess I didn’t find answers

    • Hi, thanks for your message. Please see the answers below.

      1. You will be provided with everything that is required to configure the system, including IP addresses.
      2. You may be required to configure a repository, or a repository may already be preconfigured for you, either way. Be prepared for both scenarios.
      3. I think these are the ones, yum and pip.

  195. Hello all,
    for Task 6, here is my solution. It works:

    – hosts: all
    become: yes
    vars_files:
    – /home/automation/plays/secret.yml
    – /home/automation/plays/vars/user_list.yml
    tasks:
    – name: Users whose user ID starts with 1 should be created on servers in the webservers host group
    user:
    name: “{{ item.username }}”
    uid: “{{ item.uid }}”
    state: present
    groups: wheel
    shell: /bin/bash
    password: “{{ user_password | password_hash(‘sha512’) }}”
    when: “‘webservers’ in group_names and {{ item.uid | string | first }} == 1”
    with_items: “{{ users }}”

    – name: Set authorized key taken from file for webservers users
    authorized_key:
    user: “{{ item.username }}”
    state: present
    key: “{{ lookup(‘file’, ‘/home/automation/plays/automation.pub’) }}”
    when: “‘webservers’ in group_names and {{ item.uid | string | first }} == 1”
    with_items: “{{ users }}”

    – name: Users whose user ID starts with 2 should be created on servers in the database host group
    user:
    name: “{{ item.username }}”
    uid: “{{ item.uid }}”
    state: present
    groups: wheel
    shell: /bin/bash
    password: “{{ user_password | password_hash(‘sha512’) }}”
    when: “‘database’ in group_names and {{ item.uid | string | first }} == 2”
    with_items: “{{ users }}”

    – name: Set authorized key taken from file
    authorized_key:
    user: “{{ item.username }}”
    state: present
    key: “{{ lookup(‘file’, ‘/home/automation/plays/automation.pub’) }}”
    when: “‘database’ in group_names and {{ item.uid | string | first }} == 2”
    with_items: “{{ users }}”

  196. My utmost respect to Starfighter Lisenet dedication, passion and commitment to our community.
    Also to all Linux warriors that have contributed to our community, in the comments, you are also an essential part of our community.
    I am now Red Hat Certified Engineer, and recently passed the exam.
    My sincerest thank you to all of you.

  197. Thanks for this. It’s a nice lab.
    Network engineer here, trying to learn more about Ansible.
    Spent the entire day working on task 9 and I’ve got to say that it’s a little too tough or I’m missing something. A few too many gotchas in there, I believe, and not really tied to Ansible, but just MySQL stuff.
    It’s been a long day and I haven’t been taking notes, but off the top of my head:

    1. Needed to disable the appstream repo to install the community server. Otherwise it just said there was no such package.

    2. Couldn’t connect to mysql on root because the server generated a pw on installation. Most info online says it doesn’t happen, but was able to confirm it through logs after a hint from a page I ran into. Log line in question below:

    “2021-05-04T20:01:54.520237Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: OhgFfq)fa2XJ”

    Looks to be a quirk specific to this community server package, but strangely enough, it didn’t happen when I reinstalled the package way later, but I had done a heap of changes by that time so it’s possible that some custom config somewhere remained after I uninstalled the package.

    3. The mysql_user module seemed to refuse to use the login_password setting so Ansible kept throwing an error saying root login without a password was being refused.

    4. Had to remove the mysql root password manually on the server itself in order to push through the playbook.

    5. This removal failed until I found out I had to uninstall the password validation component to make it work.

    6. Once everything actually went through, there was still an issue with the mysql root account as I was now able to log in both without a password and specifically with the desired password (random ones didn’t work).

    I just gave up at that point.

    For reference and if it helps anyone in the future, I worked on RHEL 8 machines from the CloudGuru Playground.

    • Thank you very much for your feedback! The goal of this sample lab is to give you an opportunity to test your skills deploying various services that you’d use in real life situations. If you go through the fire and flames during the preparation stage (which, by the looks of it, you have), then you will find it easier during the real exam! You’ve learnt a lot. Never give up.

    • Hey Moca, i also been dealling with this a lot… and lucky me… my playground box kinda hung…
      but while checking hte ansible-doc mysql_user. i noticed this *NOTE*

      NOTES:
      * MySQL server installs with default login_user of ‘root’ and no password. To secure this user as part of an idempotent playbook, you must create at
      least two tasks: the first must change the root user’s password, without providing any login_user/login_password details. The second must drop a
      ~/.my.cnf file containing the new root credentials. Subsequent runs of the playbook will then succeed by reading the new credentials from the file.
      * Currently, there is only support for the `mysql_native_password` encrypted password hash module.
      * Requires the PyMySQL (Python 2.7 and Python 3.X) or MySQL-python (Python 2.X) package on the remote host. The Python package may be installed with
      apt-get install python-pymysql (Ubuntu; see [apt]) or yum install python2-PyMySQL (RHEL/CentOS/Fedora; see [yum]). You can also use dnf install
      python2-PyMySQL for newer versions of Fedora; see [dnf].
      * Both `login_password’ and `login_user’ are required when you are passing credentials. If none are present, the module will attempt to read the
      credentials from `~/.my.cnf’, and finally fall back to using the MySQL default login of ‘root’ with no password.

  198. Hello again,
    thank you very much for your sample, this helped me a lot! Btw, I’ve passed the exam, yay!

  199. Dear,
    Many thanks in advance for all you’ve done here.
    I’ve passed a lot of time to perform this sample exam several times.
    Exam is scheduled tomorrow. Hope I’ll pass it – If I do, I’ll come back to you with a million Thanks.

    Regards
    M

  200. I like to give a thanks to Lisenet for this practice exam. I passed RHCE 294 exam, yesterday, and believe this practice exam is a great reason why. In my opinion, much of this exam is harder than actual exam. This exam is excellent study material, while not perfect BUT very effective preparation.

    While I can’t say what is on exam, I would tell everyone to understand all basic modules, basic conditional on those modules, variables, facts and other standard Ansible usage.

    Also, Ansible is a tool, remember this is a Linux exam, and troubleshooting problems are Linux problems not just Ansible.

  201. Task 9 is broken!

    1. mysql generates a root password -> /var/log/mysqld.log
    2. Got error with Ansible Plugin “mysq_user” when try changing the password:
    Authentication plugin ‘caching_sha2_password’ cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so
    Looks Mysql 8.0 changed auth module to “caching_sha2_password” and ansible doesn’t support it.
    3. Also tryed alter Password with shell command:
    mysql –connect-expired-password -e “ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘{{ database_password }}’;”
    But mysql does not accept it because of password policy:
    ERROR 1819 (HY000) at line 1: Your password does not satisfy the current policy requirements”

    • Hi Ives, thanks very much for your feedback! The task was originally written with MySQL 5.7 in mind, therefore I would not be surprised if things have changed with MySQL 8.0.

  202. Hi Tomas,

    First and foremost, thanks for this awesome lab!

    I’ll sit the EX294 in 2 days, I’ve done your lab several times with variations (e.g., by using non-standard ports for MySQL, configuring web severs to use non-standard ports and directories, and adequating these configurations with selinux system role etc.).

    What is actually making me nervous is the “state” of offline documentation. I’ve read that ansible documentation should be available offline for consultation? When I took my RHCSA, offline documentation was so slow, I couldn’t rely on it for very much.

    • Hi, you are right, Ansible documentation is available offline. I don’t remember having any issues with it being slow, but that’s just my experience. I also didn’t use it much.

  203. Hi Lisenet,

    I took the exam today and didn’t pass. I feel very frustrated. The questions were doable but the time was not enough and out of 4 exercises the playbooks failed me. I am also trying to understand how I could get the following percentage:
    Install and configure Ansible: 0%

    If that was the case, I couldn’t even run the playbooks. Could you give me an explanation? I would appreciate it

    • Hi Riccardo, I’m sorry to hear that you didn’t pass the exam. I don’t have an explanation I’m afraid as I don’t know what the grading script does exactly. I understand this is frustrating, and I wish you luck the next time.

    • Hi Riccardo,
      I got the exact same mark, 0%. I don’t understand how that could be. I used sudo yum install ansible command and see the output shows ansible is installed.

  204. Hi again Tomas,

    I passed my RHCE yesterday – I can safely say your sample exam has greatly helped me and even though there were gotcha moments, I was able to clear the exam with a comfortable margin.

    Thanks again! Your work is inspiring!

    I’m thinking of clearing Openshift next.

  205. 284, my fault, I gave them too much credit and tried to fix a fake problem… oh well. great test, thanks :)

  206. Hi Lisenet,

    to your knowledge is it sufficient to run “yum install ansible” to be able to install Ansible on the node control?
    And on the manage servers no installation is required. Right?

    • Hi, it is one of the ways to install ansible, and it should be sufficient. Managed servers don’t need to have ansible installed.

    • Hi Andrew, you can create a symlink as per stackoverflow suggestion, it works and it would therefore solve the task.

  207. In Task 11, I succesfully downloaded geerlingguy.haproxy and installed role for haproxy. Playbook looks ok but the haproxy is not able to start on the managed nodes. Even when manually started the haproxy on the managed node (systemctl start haproxy), it failed to start. But when I rebooted the managed nodes, the haproxy starts properly. Even the playbook does not give an error anymore.

    Is there a way to make the haproxy starts via the control node without rebooting the manage node?

  208. Thanks. Today cleared exam EX294 with good margin. I have referred sandra’s cert guide and your question for preparation.

  209. I just took exam last end of Oct. I answered all tasks 17 confidently, all my playbook are working with complied to the given tasks. however when the result came out I was unbelievably shocked my score is 208. it was below passing score. The part that I cannot accept is that on the installations and configuration of ansible i got 0%. how is that happened?! i did: dnf update, dnf install ansible, and when i su to require user i did pip3 install ansible –user, i even did ansible –version to ensure that i correctly i stallee it.

    now i’m raising this concern to redhat i hope the favor turns on me.

  210. I feel very frustrated, I answered all Tasks in exam then the result reveals i got 0% in installation and configuration of ansible. how could that happened? all my playbooks are working and complied all tasks.

    • this worked for me
      root@controlserver]# ssh-copy-id [email protected] ;ssh-copy-id [email protected] ……..
      adhoc.sh
      #!/bin/bash
      export ANSIBLE_LOG_PATH=$(mktemp –suffix=_ansible.log)
      echo “Create automation user …”
      ansible all -m user -a “name=automation” –become -u root -i /home/automation/plays/inventory
      echo “copy sshkey …”
      ansible all -m authorized_key -a “user=automation state=present key='{{ lookup(‘file’, ‘/home/automation/.ssh/id_rsa.pub’)}}'” –become -u root -i /home/automation/plays/inventory
      echo “copy sudoers file …”
      ansible all -m copy -a “src=/etc/sudoers.d/automation dest=/etc/sudoers.d/” –become -u root -i /home/automation/plays/inventory
      ansible_exit=$?
      if [ $ansible_exit -eq 0 ]
      then
      echo “NO ERROR IN EXECUTION”
      else
      echo “Something is wrong”
      fi
      echo Logfile available at $ANSIBLE_LOG_PATH
      exit $ansible_exit

  211. Thanks, Lisenet for this wonderful post. I have finished all these questions today.

    Just wanted to clarify is it expected to install Ansible using yum or pip3 or dnf.? Kindly suggest.

  212. Yes, I can install ansible using dnf, yum, and PIP3. I am concerned with the previous comments in the post about installing ansible in the exam.

    Also wanted to confirm , shall we use root to install ansible or user-provided in the question to connect to managed nodes.

    Need your expert advice.

    Thanks in advance.

    • If you use a package manager to install ansible, then you need elevate privileges, therefore use sudo or the root user. If you use pip to install ansible, then installing with --user is recommended, therefore use the user provided in the question.

  213. for home test environments what is the best way to open new (multiple) windows or terminals for writing scripts, testing, and for viewing ansible-doc. ?

  214. two general requests – in exam environment (i) copy paste command ? (ii) command or ways to open additional terminals or screen on the same control server…
    Thanks much in advance.

  215. Hello lisenet, great exam sample! Thanks for it!

    When testing task 15, if i do ansible database -m setup -a “filter=ansible_local.custom.sample_exam” it doesn’t show the value of “ansible_local.custom.sample_exam”, but if i use it on a playbook with debug, it shows “server_role”: “mysql”.

    I’m puzzled… Any ideas?

  216. Hi,

    I have recently passed the Ansible Exam. I am pretty sure if you solve these problems, you will clear Ansible exam easily.

    • Hi Zillur, well done, and congratulations! Your comment has been edited to remove Red Hat exam content material as it violates NDA.

  217. Hello everyone
    I have given my rhce 294 yesterday
    Questions were mix of some easy straight forward questions and some mixture of multiple chapters total 15 questions were asked 4 hrs time and time goes really fast.

    make sure to practise so you can complete 18 questions in 3.5 hrs that is speed required and I could not do every question fastly hence had to drop 10 question which showed I have to pratice regularly for some months before I can actually perform like redhat expected me to

    Hence I failed yesterday exam

    I wish everyone giving ex294 best of luck and make sure you can complete task without having to look in ansible doc all the time because that is where I lost all of my time and copy and paste is not a good idea controller in exam env are laggy make sure you can type fast

    Thank You Lisenet for your sample excercise it really help me to get better understanding of rhce pattern but I guess I need to pratice a lot

    • Hi, I’m sorry to hear you did no pass the exam. Your comment has been edited to remove Red Hat exam content material as it violates NDA. It’s a hands-on exam and you need to know Ansible well. The purpose of this sample exam is to give you an understanding on where you stand in terms of preparation, if you can solve all 18 questions in under 4 hours then you’re more or less ready. Better luck next time!

  218. I would like to give a big thank you to Lisenet for creating the questions in this exam. It along with the Sanders Van Vogt book/practice exams helped me achieve a perfect 300/300 score last night for EX294, renewing my RHCE for another 3 years. I was surprised about the results as I wasn’t sure about the behavior for several playbooks, but I did finish the exam with 45 minutes left in the 4 hour exam which I used to double and triple check my playbooks.

    Just as a reference, I completed this exam from Lisenet about 4-5x and finished it within 2 hours and 10 minutes on my last two tries. I started studying for the EX294 at the beginning of this year. I have limited experience with Ansible, though I am an experienced UNIX Administrator with several years of solid RHEL and scripting experience under my belt. Good luck on your exam, all!

    P.S. I would love it if you ended up creating a EX280 Openshift sample exam too since that’ll be next on my list ;)

  219. Hi Thomas,
    Thank you very much for your efforts and labor. Last week I passed the EX294 and your sample exam was way harder than actual exam. I have tried twice and never managed to finish your exam in 4 hours. But in the actual exam, when I was working on the last question, there was one hour left :).
    Thanks again/

  220. cleared! Thank you for creating a community and keeping folks like me inspired. :-) Also the practice questions were of great help. Cheers.

  221. Hi Lisenet, great practice stuff so far!

    However, I’m stuck on Task 9, as “mysql-community-server” is not coming up as an available package to install.

    I logged into ansible5, elevated to root, and this is what I see about the repo (as set up in prior task in this practice):

    # yum repoinfo mysql80-community
    Updating Subscription Management repositories.
    Last metadata expiration check: 0:07:19 ago on Fri 29 Apr 2022 04:52:11 PM EDT.
    Repo-id : mysql80-community
    Repo-name : “MySQL 8.0 YUM Repo”
    Repo-status : enabled
    Repo-revision : 1651100734
    Repo-updated : Wed 27 Apr 2022 07:05:34 PM EDT
    Repo-pkgs : 142
    Repo-available-pkgs: 64
    Repo-size : 4.7 G
    Repo-baseurl : http://repo.mysql.com/yum/mysql-8.0-community/el/8/x86_64/
    Repo-expire : 172,800 second(s) (last: Fri 29 Apr 2022 03:52:20 PM EDT)
    Repo-filename : /etc/yum.repos.d/mysql80-community.repo

    # yum repository-packages mysql80-community list –all
    Updating Subscription Management repositories.
    Last metadata expiration check: 0:05:20 ago on Fri 29 Apr 2022 04:52:11 PM EDT.
    Available Packages
    mysql-community-client-plugins.x86_64 8.0.29-1.el8 mysql80-community
    mysql-community-debugsource.x86_64 8.0.29-1.el8 mysql80-community
    mysql-community-icu-data-files.x86_64 8.0.29-1.el8 mysql80-community
    mysql-community-server-debug.x86_64 8.0.29-1.el8 mysql80-community
    mysql-ref-manual-8.0-en-html-chapter.noarch 1-20220324 mysql80-community
    mysql-ref-manual-8.0-en-pdf.noarch 1-20220324 mysql80-community
    mysql80-community-release.noarch el8-4 mysql80-community

    The image I used to create all the VMs I’m running this on is “Red Hat Enterprise Linux release 8.5”, would that be the problem?

    • This task was originally written for RHEL 7 I think and may not reflect the package name that’s available on RHEL 8.

    • So to proceed with the task and what is coming next, would you recommend using mysql-server from the standard RHEL8 repo & adjusting further work as needed?

  222. I think there is something wrong with the mysql80-community repos, which obviously isn’t your issue.

    I did eventually get it to work, but I had to disable the RHEL8 baseos and appstream repos before Ansible yum module would install the mysql80 package. Plus I had to specifically state to install both mysql-community-common and mysql-community-server in the task for it to work

  223. This was an EXCELLENT pre-test and helped me get my RHCE. I think the hardest/trickiest part of this was using the root user with key to create the automation user on the other VM’s. Thanks for keeping this online!

  224. I am confused about one of the objectives. If I disable privilege escalation in the ansible.cfg and run all the tasks as the automation user that won’t work because some tasks require root privileges. The only way around this I can see is to include the become/become_method/become_user options in the playbooks themselves. Would that satisfy the practice exam requirements?

    I could also run the plays at “ansible-playbook -b –become-method=sudo –become-user=root play.yml”. But the exam objective is slightly vague on this.

  225. This is a really awesome study tool. Passed my RHCE EX294 and i think if you can get through all the questions here then you should be ready to go. Thanks Lisenet !

  226. Passed my RHCE EX294 last Friday. Due to the NDA I can neither confirm or deny anything. But this is a very good practice exam :).

  227. I recently passed the Ansible exam and wrote a full solution that users may expect in real exams.

    • Hi, thanks for your comment. I’m afraid we are unable to link to solutions that have been produced after passing the exam.

  228. Here is my solution for task 18 if anyone is interested:


    – name: create list of servers from template
    hosts: all
    become: true
    tasks:
    – name: use template to populate list of hosts and configure SElinux
    block:
    – template:
    src: server_list.j2
    dest: /etc/server_list.txt
    owner: automation
    group: automation
    mode: ‘0600’
    – name: set selinux fcontext
    include_role:
    name: rhel-system-roles.selinux
    vars:
    selinux_fcontexts:
    – { target: ‘/etc/server_list.txt’, setype: ‘net_conf_t’, ftype: ‘f’ }
    selinux_restore_dirs:
    – /etc/server_list.txt
    when: inventory_hostname in groups[‘database’]

  229. Hello!

    I am doing my exam soon, I could do all tasks (with some minor mistakes) focused in 2:30hs, and I think that is a good indicator

    I do have one question that maybe you could help me with, if you could.

    – On the requirements it says that the controller has SSH access to all servers with the root user.
    – Later on Task 2, using the user “automation” i need to create an ad-hoc script. However, I’m getting stuck on how I would the user root ssh key on an ad-hoc script

    Here are the things i’ve tried

    – Using “-u root” does not help, since it changes the SSH username to root, and we are the user automation. We still need the key.
    – Using “sudo ansible all -m ping -u root” actually works, since in sudo we use the root environment (and the ssh key), and the SSH username is “root”. I dont know however if it is in the best practices to use a sudo ad-hoc command.
    – I’ve tried adding an extra variable “ansible_ssh_private_key_file=/root/.ssh/id_rsa” to the ad-hoc command, but of course I got a permission denied error.

    In the end, to continue with my exam, I added as an extra variable “ansible_password=password” to the ad-hoc script, which made the user “automation” on all machines and I could continue. Again however, I dont know if this is an accepted solution, and root password might not be setup, since we have passwordless login between root users

    Could you point me in the right direction? I just need a small tip, maybe I am overthinking the solution

    • Hi! You’re right, you do have SSH access to all servers with the root user, but it does not say that you must use the root user ssh key on an ad-hoc script. You can use a password if you want. Remember, this is not a real exam.

      The ad-hoc script must be run as the automation user on the control node, but it does not specify the user that you need to use to connect to managed nodes via SSH. Since you don’t have any users created on the managed nodes, you need to use the root user to connect to them.

    • Thanks for your guidance, I think I might have a solution then.

      It involves using the root user in the controller server and the automation user key that is created in the Task 2. Since we do have root access in the controller, and in all the servers, with one simple action the adhoc script works without sudo, and the Task 2 requirements are fulfilled.

      I think I might have been over-thinking it way too much. Thanks again, this sample exam is a really good practice environment!

  230. Lisenet, thanks for responding, I am currently running Ansible version 2.13 and I have mastered the questions on this exam, but I am concerned that this version may not be simulated to ansible 2.9 that the exam runs in.

    • No worries. I would suggest you to reach out to Red Hat training and ask them to clarify the Ansible version used on the exam. This way you will know the one to practise on.

  231. In my test environment, i install ansible by the following steps:
    yum install epel-release -y
    yum install ansible -y

    • Hi Tara, congrats!

      can I ask you about the exam..

      did you use ansible-navigator on exam v8?

  232. If I add custom variables to the inventory file or use group_vars, and host_vars instead of adding variables to the playbook or writing things out statically in tasks, would you say that is an acceptable way to solve the question?

  233. Task 6.
    Each user should have an SSH key uploaded (use the SSH key that you created previously, see task #2).
    I didn’t understand what need to do. need generate ssh key for users or use authorized_key from control and send my pub key to users? After running the playbook, users should be able to SSH into their respective servers without passwords.
    If I use generate_ssh_key: yes ssh_key_bits: 2048 ssh_key_file: .ssh/id_rsa , users will not connect without a password. if i use authorized_key, only “automation” can connect without password to users.

    • The task #6 asks you to use the existing SSH key that you had created previously in task #2. You do not need to generate any new SSH keys. Use the key that you have already when you are creating new users on the managed nodes. All users share the same SSH key.

  234. Hello Sir,

    First thank you for this amazing content.
    I have one question regarding Task 2 because i’m overthinking it too much despite the fact that i figured out, but something is bothering me.

    We are executing the script as automation user, and since it will be the first time that we ssh into the remote nodes, We will obtain this message :

    The authenticity of host ‘node1 (192.168.1.57)’ can’t be established.
    ECDSA key fingerprint is SHA256:uPrs3Ok+HtRE1f6o5hJqEDgFa3KzzL3i2nTAG01Wx9w.
    Are you sure you want to continue connecting (yes/no/[fingerprint])?

    So the script will be paused until we provide a “yes” for each node.
    Can you give me some suggestions to prevent that please?

    • Hi, thank you for your feedback. In order to disable host key checking and in turn the prompt that you are referring to, you can set the following in your ansible.cfg:

      host_key_checking = False
  235. Hello again!

    For task 6 i understand that we should use the same ssh key we created in task 2 for for all the users.*
    What is confusing for me is this :
    After running the playbook, users should be able to SSH into their respective servers without passwords.

    Like there is only one node in database group, so my question is :
    How will Patrick and Sandy be able to SSH into their respective servers without passwords if they are created on ONE NODE only, which is ansible5.hl.local ?

    Is there something i’m not getting? thanks :)

    • Hi, users patrick and sandy should be able to SSH into those servers where their accounts exist. In this case, their accounts would be created on the servers in the database host group, which is ansible5.hl.local. So both patrick and sandy should be able to SSH into one server, ansible5.hl.local. I hope this clarifies things.

  236. TASK 6:
    loop: “{{ users }}”
    when: >
    (inventory_hostname in groups[‘webservers’] and item.uid >= 1000 and item.uid = 1999)

  237. Hi, thanks for this amazing post, it was really helpfull to me 3 years ago when I first had to practice for my EX294.

    It’s time for my renewal, and I wondered if anyone has taken the new EX294 over RHEL9 to confirm that, appart form the changes in Ansible Automation Platform (use of ansible-navigator vs ansible-playbook), the objectives are still the same covered in this post.

    • There’s a greater focus on collections now, but ansible-navigator isn’t needed so long as you know what modules you need and what collection they belong to. I’m sure you’ve cleared the exam by now, but just adding for anyone else preparing.

  238. I have passed my RedHat EX294 exam with the help of the EX294 practice test designed by professionals. It was really a great exam preparation resource. I would like to recommend it to those who want to pass the test on the first try.

  239. Hello!

    I know this post is from 2019 but I wonder whether you know the full use of FQCNs in playbooks are required in the RHCEv9/ex294 nowadays? And whether you lose points if you lose the old style short names? Thanks!

    • I don’t know if you lose points by not using FQCN during the exam, but your playbooks should still work even if you didn’t. My suggestion would be to use FQCN as that’s what Ansible lint recommends for best practice.

  240. Hi Tomas!
    Thank you for all your work on this site.
    I used it about 3 years ago when my RHCSA was about to expire and I wanted to take ex300 to stay current. Unfortunately i failed by 6%.
    Failing by such small margin it got personal xD and I decided to take ex200 again and then ex300. I passed ex200 100% but failed ex300 at about 50%, as one if the servers didn’t boot up.
    Time has passed, my RHCSA was again about to expire and I wanted to give RHCE a try one last time. This time with ex294.
    Well, today I’m RHCE certified, and your sample exam was a great study help :)
    P. S. For anyone interested, the Ex294v84 version of the exam (rhel 8 and no ansible navigator) is available till the end of 2024

Leave a Reply to Adam Cancel reply

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