Courseiva

Red Hat Certified Engineer EX294 (EX294) — Questions 151–225

392 questions total · 6pages · All types, answers revealed

Page 2

Page 3 of 6

Page 4
151
MCQeasy

An automation engineer wants to run a playbook only on hosts that belong to both the 'webservers' group and the 'production' group. Which inventory grouping method achieves this?

A.webservers:&production
B.webservers:production
C.webservers:!production
D.webservers+,production
AnswerA

The :& intersection pattern targets hosts present in both groups simultaneously, matching the requirement to run only where webservers and production overlap. Other patterns like :! or union would include hosts outside the intended set.

Why this answer

In Ansible, the '&' operator is used to intersect groups. 'webservers:&production' targets hosts that are in both the 'webservers' and 'production' groups. Option B is wrong because 'webservers:production' uses ':' which is a union operator, meaning hosts in either group. Option C is wrong because 'webservers:!production' uses '!' to exclude hosts in production.

Option D is wrong because 'webservers+,production' is not a valid inventory pattern; Ansible does not support '+' for group intersection.

152
MCQeasy

A developer reports that a role's behavior is not as expected. They set a variable in the playbook's vars section, but the role still uses the value from its vars/main.yml. Which of the following explains this issue?

A.vars defined in the playbook have higher precedence than those in roles/vars/main.yml
B.vars defined in group_vars override both play and role vars
C.the playbook must use include_vars after the role to override
D.vars defined in roles/vars/main.yml have higher precedence than those in the playbook's vars section
AnswerD

Correct: role vars override play vars.

Why this answer

In Ansible, variable precedence is hierarchical, and role defaults (roles/role_name/defaults/main.yml) have the lowest precedence, while role vars (roles/role_name/vars/main.yml) have a higher precedence than playbook-level vars. Since the developer set the variable in the playbook's vars section, but the role still uses the value from its vars/main.yml, this indicates that vars defined in roles/vars/main.yml override those in the playbook's vars section, making option D correct.

Exam trap

The trap here is that candidates often confuse role defaults (defaults/main.yml) with role vars (vars/main.yml), assuming both are easily overridden by playbook vars. In Red Hat Ansible Automation Platform, role vars have higher precedence than playbook vars, making them effectively 'hardcoded' unless overridden by even higher precedence sources like extra vars or set_facts.

How to eliminate wrong answers

Option A is wrong because vars defined in the playbook have lower precedence than those in roles/vars/main.yml, not higher. Option B is wrong because group_vars have a lower precedence than both play vars and role vars, so they cannot override both; in fact, role vars override group_vars. Option C is wrong because include_vars is used to load variables from a file at runtime, but it does not change the inherent precedence; the role's vars/main.yml would still take precedence over playbook vars regardless of when include_vars is used.

153
Multi-Selecthard

An organization needs to implement security best practices for Ansible automation. Which three measures should be taken? (Choose three.)

Select 3 answers
A.Use ansible-vault to encrypt sensitive variables
B.Store all secrets in plain text in repository
C.Regularly rotate Ansible Vault passwords
D.Disable SSH host key checking globally
E.Limit access to automation controller using RBAC
AnswersA, C, E

Encrypting sensitive variables with ansible-vault protects credentials and secrets at rest, satisfying the requirement to secure automation data. Vault-encrypted files remain usable in playbooks via the vault password, so confidentiality is achieved without breaking execution. This directly addresses the security best-practise constraint in the stem.

Why this answer

Option A is correct because ansible-vault encrypts sensitive variables and files (e.g., via `ansible-vault encrypt` or `encrypt_string`) so secrets such as passwords and API keys are not exposed in plain text within playbooks or repositories. Option C is correct because regularly rotating Ansible Vault passwords limits the impact of a compromised vault password and should be paired with `ansible-vault rekey` to re-encrypt vaulted content under the new password. Option E is correct because limiting access to the automation controller with role-based access control (RBAC) enforces least privilege, ensuring only authorized users or teams can launch jobs, edit credentials, or manage inventories.

Option B is not acceptable since storing secrets in plain text in a repository exposes them to anyone with repo access and violates security best practices. Option D is wrong because disabling SSH host key checking globally removes protection against man-in-the-middle attacks and should not be done as a security measure.

Exam trap

The trap here is that candidates may think disabling SSH host key checking is acceptable for convenience in lab environments, but the exam expects you to recognize it as a security risk that should never be applied globally in production.

154
MCQhard

An administrator uses an inventory file with a group 'web' and a host 'web1' that also belongs to group 'db'. The group_vars/web.yml file sets 'http_port: 80', and group_vars/db.yml sets 'http_port: 3306'. The playbook uses 'http_port' to configure a service. What will be the value of http_port for web1 when the playbook runs?

A.3306, because the 'db' group is alphabetically before 'web'.
B.The playbook will fail with an error because http_port is defined in two groups.
C.80, because group_vars/web.yml takes precedence over group_vars/db.yml for hosts in both groups.
D.80, because the 'web' group appears first in the inventory file.
AnswerC

Ansible merges group variables for a host by processing groups in alphabetical order, with later groups overriding earlier ones. Since 'web' comes after 'db' alphabetically, variables from group_vars/web.yml override those from group_vars/db.yml. Therefore, http_port is 80 for web1. This is the correct precedence rule for group variables at the same level.

Why this answer

When a host belongs to multiple groups, Ansible merges group variables by processing groups in alphabetical order. Later groups override earlier ones. 'db' precedes 'web' alphabetically, so variables from group_vars/web.yml override those from group_vars/db.yml. Thus http_port becomes 80.

Inventory file order and duplicate definitions do not cause errors; precedence rules apply.

Exam trap

The trap here is thinking that inventory file order or a failure occurs when a variable is defined in multiple groups, when actually alphabetical group order determines the final value.

155
MCQhard

An organization uses Automation Controller with multiple teams. They want to ensure that team members can only launch job templates that are explicitly assigned to their team. Which configuration approach should be used?

A.Assign each team to an organization and set organization-level permissions
B.Set 'allow simultaneous' to false on job templates
C.Use an Identity Provider (IdP) to restrict access
D.Create roles and assign them at the job template level using team roles
AnswerD

Assigning team roles directly on each job template grants the team execute permission only for that template, satisfying the constraint that members launch solely explicitly assigned templates. Organisation-wide roles would over-grant access, so template-level role assignment is required.

Why this answer

Automation Controller (formerly Ansible Tower) uses Role-Based Access Control (RBAC) where roles (e.g., Execute, Admin) can be assigned to teams at the job template level. This ensures that only members of a specific team can launch the job templates explicitly assigned to that team, without affecting other teams or requiring organization-wide permissions.

Exam trap

The trap here is confusing authentication (IdP) with authorization (RBAC), leading candidates to choose Option C, even though IdPs like LDAP or SAML only verify who the user is, not what they can do within Automation Controller.

How to eliminate wrong answers

Option A is wrong because setting organization-level permissions grants access to all teams within the organization, not restricting job template access to a specific team. Option B is wrong because 'allow simultaneous' controls whether multiple concurrent runs of the same job template are permitted, not who can launch it. Option C is wrong because an Identity Provider (IdP) handles authentication (verifying user identity), not authorization (controlling access to specific resources like job templates); RBAC within Automation Controller is required for fine-grained access control.

156
MCQmedium

A sysadmin receives an error when running a job template: 'ERROR! the role 'common' was not found in the specified roles path'. The role exists in a source control repository referenced in the project. What is the most likely cause?

A.The inventory does not include the target hosts
B.The project's source control sync failed, so the roles directory is empty
C.The job template is configured with an incorrect schedule
D.The credential used does not have access to the source control repository
AnswerB

A failed project sync leaves the local checkout without the roles directory, so Ansible's configured roles path contains no `common` role and the lookup fails. The stem states the role exists only in source control, making a stale or empty working copy the direct cause of the not-found error.

Why this answer

The error indicates that Ansible cannot find the 'common' role in the specified roles path. Since the role exists in the source control repository referenced by the project, the most likely cause is that the project's source control sync failed, leaving the roles directory empty or incomplete. Without a successful sync, the role files are not present on the Ansible control node, causing the job template execution to fail.

Exam trap

The trap here is that candidates may confuse a credential failure (Option D) with a sync failure, but the error message specifically points to a missing role file, not an authentication issue, and the sync failure is the direct cause of the missing role.

How to eliminate wrong answers

Option A is wrong because the inventory not including target hosts would cause a different error, such as 'No hosts matched' or a failure to connect, not a missing role error. Option C is wrong because an incorrect schedule would prevent the job from running at the intended time but would not cause a missing role error during execution. Option D is wrong because if the credential lacked access to the source control repository, the project sync would fail with an authentication or authorization error, not a missing role error after a successful sync.

157
Multi-Selectmedium

Which TWO options are valid methods for including collections in an execution environment?

Select 2 answers
A.Use ansible-galaxy collection install command in a pre-build script.
B.List collections under 'collections' in execution-environment.yml.
C.Use a 'galaxy.yml' file in the build context.
D.Add a requirements.yml file with collections.
E.Include collections in the base image directly.
AnswersB, D

Listing collections under the collections key in execution-environment.yml lets ansible-builder resolve and install them directly from configured Galaxy or Automation Hub sources during the image build, satisfying the requirement to include collections in the execution environment.

Why this answer

Option B is correct because the execution-environment.yml definition file supports a 'collections' key where you list collection names (and optionally versions/sources) that ansible-builder will install into the resulting execution environment image. Option D is correct because ansible-builder recognizes a requirements.yml file (referenced via the 'dependencies' section, e.g. galaxy: requirements.yml) that specifies collections to install, using the standard Galaxy requirements format. Option A is not the intended answer because running ansible-galaxy collection install in a pre-build script is a manual workaround rather than a declared, supported method for including collections in the execution environment definition.

Option C is incorrect because galaxy.yml is a collection's own metadata/manifest file used when building or publishing a collection, not a mechanism for adding collections to an execution environment. Option E is incorrect because baking collections into the base image is not a valid ansible-builder method for including collections; collections should be declared in the execution environment definition so they are installed during the build.

Exam trap

The trap here is that candidates confuse the `galaxy.yml` file (used for defining a collection's metadata) with the `execution-environment.yml` file (used for specifying collections to include in an execution environment), or they mistakenly think runtime commands like `ansible-galaxy collection install` are valid build-time methods.

158
MCQhard

An Ansible automation is used to manage firewall rules on a set of Linux servers. The playbook defines a variable "allow_rules" as: allow_rules: - proto: tcp dport: 80 comment: HTTP - proto: tcp dport: 443 comment: HTTPS The engineer needs to use the "iptables" module to create rules. The module expects "chain" to be specified, and the engineer wants to dynamically set the chain based on the port: ports 80 and 443 go to "INPUT" chain, while others go to "FORWARD". The engineer writes a loop: - name: Add iptables rules iptables: chain: "{{ item.dport | map('some_filter') }}" protocol: "{{ item.proto }}" destination_port: "{{ item.dport }}" comment: "{{ item.comment }}" loop: "{{ allow_rules }}" But this fails because the chain field expects a string, not a list. The engineer realizes the map filter returns a list. Which of the following modifications correctly sets the chain based on port number?

A.chain: "{{ item.dport | regex_replace('^(80|443)$', 'INPUT') | default('FORWARD', true) }}"
B.chain: "{{ (item.dport in [80,443]) | ternary('INPUT', 'FORWARD') }}"
C.chain: "{{ item.dport | select('in', [80,443]) | list | first | default('FORWARD') }}"
D.chain: "{{ item.dport | replace('80','INPUT') | replace('443','INPUT') | default('FORWARD') }}"
AnswerB

The ternary filter tests whether item.dport is 80 or 443 and returns the matching string, so chain receives 'INPUT' or 'FORWARD'. This satisfies the module's string requirement, unlike the map filter which returned a list.

Why this answer

It uses the `ternary` filter to evaluate a condition (`item.dport in [80,443]`) and return 'INPUT' if true, or 'FORWARD' if false. This produces a single string, which is exactly what the `chain` parameter expects, avoiding the list output from `map`.

Exam trap

The trap here is that candidates often reach for `map` or `select` filters without realizing they produce lists, and then try to coerce them into strings with `first` or `join`, which can fail or produce unexpected results when the list is empty or contains non-string values.

How to eliminate wrong answers

Option A is wrong because `regex_replace` only replaces matched patterns within the string; it does not change the string to 'INPUT' for ports 80 or 443, and the `default` filter would only apply if the result is an undefined value, not a string that wasn't replaced. Option C is wrong because `select('in', [80,443])` returns a list of items that match the condition; even after `list | first`, if the list is empty (e.g., port 8080), `first` returns `None`, and `default('FORWARD')` would then apply, but for ports 80 or 443 it returns the port number itself (an integer), not 'INPUT'. Option D is wrong because `replace` performs simple substring replacement; it would change '80' to 'INPUT' even if the port is 8080 (e.g., '8080' becomes 'INPUT80'), and it does not handle the case where the port is not 80 or 443, leaving the original port number as the chain value.

159
MCQmedium

A playbook reads a JSON file on the control node with the `file` lookup and registers the content as a string named `raw_config`. A task must convert that string into a native Python dictionary so later tasks can reference keys such as `raw_config.database.port`. Which filter should be applied to the registered content?

A.from_json
B.combine
C.from_yaml
D.to_json
AnswerA

The `from_json` filter deserializes a JSON-formatted string into the native data structure Ansible uses, so a string containing an object becomes a dictionary whose keys can be addressed with dotted notation. Because the lookup returned text rather than structured data, this conversion is exactly what allows `raw_config.database.port` to resolve in later tasks.

Why this answer

The registered content is a string because the lookup returns file contents verbatim. To use nested keys, that string must be parsed into Ansible's native data structures. The `from_json` filter performs exactly this deserialization, turning a JSON object string into a dictionary that supports dotted access.

The reverse filter or YAML-specific parsers would not produce the required dictionary from a JSON string.

Exam trap

The trap here is assuming a lookup returns structured data rather than a string, so candidates reach for serialization filters instead of a parser.

160
MCQhard

You are writing an Ansible playbook to perform a rolling update of a 20-node RHEL application cluster. The application requires that no more than 20 percent of the fleet be offline at any time. You want the playbook to update hosts in batches that respect this constraint and to abort the entire rollout if the failure rate within any batch exceeds 10 percent. Which combination of play keywords should you use?

A.`serial: 4` and `max_fail_percentage: 25`
B.`serial: 4` and `max_fail_percentage: 10`
C.`serial: 20%` and `max_fail_percentage: 10`
D.`serial: 20` and `max_fail_percentage: 10`
AnswerC

Using `serial: 20%` sizes each batch to 20 percent of the 20-node fleet, which is exactly 4 hosts, satisfying the requirement that no more than 20 percent be offline. `max_fail_percentage: 10` then aborts the rollout if more than 10 percent of the hosts in the current batch fail. This directly encodes both constraints in the play.

Why this answer

The requirement is to cap concurrent offline hosts at 20 percent of the fleet while aborting when batch failures exceed 10 percent. With 20 nodes, 20 percent equals 4 hosts, so `serial: 20%` expresses the constraint as a percentage that scales with inventory size. `max_fail_percentage: 10` then aborts the play when more than 10 percent of the hosts in the current batch fail. Together they encode both the availability and failure-tolerance policies directly in the play.

Exam trap

The trap here is confusing percentage-based serial values with absolute host counts, or assuming max_fail_percentage applies to the whole inventory rather than only to the hosts in the current serial batch.

161
Multi-Selecthard

Which TWO statements about Ansible content collections are correct?

Select 2 answers
A.Collections can be installed only from Galaxy.
B.The collection name must be a single word without namespace.
C.Collections can be distributed via Automation Hub or Galaxy.
D.A collection can contain only roles and playbooks.
E.A collection must have a galaxy.yml file in its root directory.
AnswersC, E

Collections are distributed as tarballs through Galaxy, Automation Hub, or private Galaxy servers, which is the standard distribution mechanism. This satisfies the statement's requirement, distinguishing collections from standalone roles shared via Git or Galaxy alone.

Why this answer

Option C is correct because Ansible content collections can be obtained from both public Ansible Galaxy and Red Hat Automation Hub (as well as private Automation Hub instances), which are the standard distribution sources configured via ansible.cfg or the ansible-galaxy CLI. Option E is correct because a collection's source tree requires a galaxy.yml metadata file at its root, which defines the namespace, name, version, authors, and dependencies used when building and publishing the collection artifact. Option A is wrong because collections can also be installed from Automation Hub, private automation hubs, Git repositories, tarballs, or local paths, not only Galaxy.

Option B is wrong because a collection name uses the format namespace.collection (for example, ansible.builtin), so it must include a namespace rather than being a single word. Option D is wrong because collections can contain many content types beyond roles and playbooks, including modules, plugins, filters, tests, and documentation.

Exam trap

Red Hat often tests the requirement for a `galaxy.yml` file in the collection root, as candidates may mistakenly think it is optional or confuse it with other configuration files like `meta/main.yml`.

162
MCQhard

An administrator is building a role whose task list must run a platform-specific set of tasks: one file for Red Hat Enterprise Linux hosts and another for Debian hosts, with the choice made at runtime based on gathered facts. The role must remain readable and avoid loading the wrong file even partially. Which approach should the administrator use?

A.Place both platform task files in the role and rely on the role's meta/main.yml dependencies to select one.
B.Put the platform-specific tasks directly in tasks/main.yml and use tags to select which ones run.
C.Use ansible.builtin.include_tasks with a filename built from ansible_facts, so only the matching file is loaded at runtime.
D.Use ansible.builtin.import_tasks for both platform files and wrap each in a when condition.
AnswerC

include_tasks is processed dynamically during execution, so a filename assembled from a fact such as ansible_facts['os_family'] is evaluated when the task is reached and only the selected file is read. This keeps platform logic readable and avoids parsing the non-matching file entirely.

Why this answer

Dynamic inclusion through include_tasks evaluates the filename expression when the task executes, after facts are available, so exactly one platform file is loaded. Static import_tasks resolves at parse time and cannot branch on facts, and tags or meta dependencies are selected by the operator or parse order rather than by host platform.

Exam trap

The trap here is assuming that a when condition on an imported task file prevents that file from being parsed, when imports are resolved before facts exist.

163
MCQeasy

You are performing a rolling update of a 6-node RHEL web server fleet using an Ansible playbook. The playbook currently uses `serial: 1` and takes a long time because each host is updated sequentially. You want to update two hosts at a time to reduce the total rollout duration while still keeping at least four hosts serving traffic. Which change should you make?

A.Change `serial: 1` to `serial: 2`.
B.Add `forks: 2` to the play.
C.Change `serial: 1` to `serial: 4`.
D.Add `throttle: 2` to the play.
AnswerA

Changing serial from 1 to 2 updates two hosts per batch, leaving four hosts online at all times, which satisfies the requirement to keep at least four hosts serving traffic. It halves the number of batches compared to serial of 1, reducing the total rollout time while respecting the availability constraint.

Why this answer

To update two hosts at a time in a six-node fleet while keeping four hosts online, the serial batch size must be two. Changing serial from 1 to 2 directly controls how many hosts Ansible targets per play iteration, halving the number of batches and shortening the rollout. Other keywords such as throttle and forks affect concurrency of task execution but do not define rolling update batch boundaries.

Exam trap

The trap here is confusing concurrency controls like forks or throttle with the serial keyword, which is the actual mechanism that defines rolling update batch size.

164
MCQmedium

An automation team uses Ansible Automation Platform to manage secrets. They have a requirement that certain tasks must not log sensitive output to the Ansible logs. Which Ansible task keyword should be used to prevent a task from logging its output?

A.`no_log: true`
B.`ignore_errors: true`
C.`check_mode: true`
D.`become: true`
AnswerA

The `no_log` keyword, when set to `true` on a task, prevents Ansible from logging the task's output, including any sensitive data. This is the correct way to ensure that secrets are not exposed in logs. It can be applied at the task level or globally in `ansible.cfg` with `no_log = True`. This directly addresses the requirement to avoid logging sensitive output.

Why this answer

The `no_log` keyword is specifically designed to prevent Ansible from logging a task's output. When set to `true`, it suppresses the output that would normally appear in logs, including any sensitive data. This is the recommended approach for tasks that handle passwords, API keys, or other secrets.

The other keywords control privilege escalation, error handling, or dry-run mode, none of which address logging of sensitive information.

Exam trap

The trap here is confusing `no_log` with other task keywords that control behavior but do not affect logging, such as `become` or `ignore_errors`.

165
MCQhard

A collection version is already published on Automation Hub. The developer needs to update the collection with a new feature. What must be done to the version number before publishing again?

A.No change needed; Automation Hub overwrites.
B.Increment the patch or minor version number.
C.Increment the major version number.
D.Change the version to a pre-release identifier.
AnswerB

Automation Hub rejects republishing an existing version, so the version field in galaxy.yml must be incremented before rebuilding and publishing. A patch bump suits a feature addition only if the project's convention allows it; otherwise a minor increment is used to signal new functionality.

Why this answer

Automation Hub enforces immutable collection versions; once a version is published, it cannot be overwritten or deleted. To publish a new feature, you must increment the patch (e.g., 1.0.0 → 1.0.1) or minor (e.g., 1.0.0 → 1.1.0) version number in the galaxy.yml file, following semantic versioning (semver) as required by Ansible collections.

Exam trap

The trap here is that candidates assume Automation Hub behaves like a mutable artifact repository (e.g., overwriting on re-upload), but Red Hat enforces immutability to ensure version integrity and reproducibility across environments.

How to eliminate wrong answers

Option A is wrong because Automation Hub does not allow overwriting an existing version; collections are immutable once published, and attempting to publish the same version will result in an error. Option C is wrong because incrementing the major version (e.g., 1.0.0 → 2.0.0) is only required when introducing breaking changes, not for a new feature that is backward-compatible. Option D is wrong because pre-release identifiers (e.g., 1.0.0-alpha.1) are used for testing or development versions and are not intended for publishing a stable new feature to Automation Hub.

166
MCQmedium

An inventory is sourced from an external dynamic inventory plugin. The plugin returns hosts with groups including 'webservers' and 'dbservers'. An administrator wants to add a custom variable to all hosts in the 'webservers' group without modifying the plugin script. How can this be achieved?

A.Modify the dynamic inventory plugin script to add the variable
B.Add the variable to the host_vars file for each host
C.Create a group_vars file named 'webservers' in the project directory and define the variable
D.Use the 'add_host' module in a playbook to set the variable
AnswerC

Group_vars files are loaded automatically by Ansible from the project directory and override or supplement plugin-supplied group data, so defining 'webservers' there injects the custom variable into every host in that group without touching the dynamic inventory script.

Why this answer

Ansible's group_vars mechanism allows you to define variables for all hosts in a group by creating a YAML file named after the group (e.g., 'webservers') in the group_vars directory. This approach does not require modifying the dynamic inventory plugin script, which is external and should remain untouched. The variable will be automatically applied to all hosts in the 'webservers' group during playbook execution.

Exam trap

The trap here is that candidates may think modifying the plugin script (Option A) is acceptable, but the EX294 exam emphasizes immutability of external sources and using Ansible's built-in variable precedence and group_vars instead.

How to eliminate wrong answers

Option A is wrong because modifying the dynamic inventory plugin script violates the requirement to not modify the plugin, and it is not a best practice—external plugins should be treated as immutable. Option B is wrong because adding the variable to host_vars files for each host would be repetitive and inefficient, and it does not leverage group-level inheritance; it also requires knowing all hostnames in advance. Option D is wrong because the 'add_host' module is used to dynamically add hosts to the in-memory inventory during playbook runtime, not to set persistent variables for existing group members; it would not apply the variable to all hosts in the 'webservers' group automatically.

167
MCQhard

A platform team uses an Ansible playbook with 'serial: "20%"' to roll out a new configuration to 50 hosts. During the third batch, a task fails on several hosts, and the play aborts with a message about max_fail_percentage. Which statement correctly describes how Ansible determined the batch size and the failure threshold in this run?

A.The batch size was 5 hosts, and the failure threshold was evaluated against the 5 hosts in the current batch.
B.The batch size was 20 hosts, and the failure threshold was evaluated against 50 hosts.
C.The batch size was 10 hosts, and the failure threshold was evaluated against the 10 hosts in the current batch.
D.The batch size was 10 hosts, and the failure threshold was evaluated against all 50 hosts regardless of batch.
AnswerC

serial: "20%" on 50 hosts produces batches of 10. max_fail_percentage is then calculated against the size of the current serial batch, so failures are compared to those 10 hosts. This is exactly how Ansible determines both values during a rolling update.

Why this answer

When serial is a percentage, Ansible multiplies that percentage by the total number of hosts in the play to determine each batch size. For 50 hosts at 20%, each batch contains 10 hosts. max_fail_percentage is then evaluated against the current batch, so the abort decision is based on failures among those 10 hosts, not the full inventory.

Exam trap

The trap here is assuming max_fail_percentage is measured against the full inventory when serial is expressed as a percentage.

168
MCQmedium

An organization uses separate network hops that require different SSH usernames for different inventory groups. Which Ansible configuration approach ensures each group uses the correct SSH user without duplicating playbooks?

A.Create a group_vars directory with a file named after the group containing ansible_user.
B.Specify the SSH user in the inventory file for each host.
C.Set the ansible_user variable in ansible.cfg.
D.Define ansible_user in the playbook using vars.
AnswerA

Group variables are loaded automatically for hosts in the matching group, so placing ansible_user in group_vars/<group>.yml supplies the correct SSH username per inventory group. One playbook then runs against all groups without hard-coded credentials or duplication.

Why this answer

Group variables in Ansible are defined in group_vars/<group_name>.yml, and variables set there apply to all hosts in that group. Placing ansible_user in a group-specific file ensures each inventory group uses its correct SSH username without duplicating playbook logic. This is the idiomatic Ansible way to scope connection variables per group.

Exam trap

The trap is thinking ansible.cfg or playbook vars can scope connection settings per group; the exam tests whether you know that group_vars is the correct precedence layer for group-specific SSH users.

How to eliminate wrong answers

Option B is wrong because setting ansible_user per host in the inventory works but duplicates configuration and does not scale when groups share a user. Option C is wrong because ansible.cfg sets global defaults and cannot vary ansible_user per inventory group. Option D is wrong because defining ansible_user in playbook vars applies to the play, not per group, and would require conditional logic or multiple plays.

169
Drag & Dropmedium

Drag and drop the steps to configure a basic NFS server to export a directory in the correct order.

Drag or tap steps into the slots.

Steps
Order
1Step 1
2Step 2
3Step 3
4Step 4

Why this order

To configure a basic NFS server to export a directory, the correct sequence is: install the NFS packages (e.g., nfs-utils), create the directory to be shared, edit /etc/exports to define the export, start and enable the NFS server service, and finally verify the export using 'showmount -e localhost'. This workflow ensures that all prerequisites are met before each step, avoiding errors such as missing directories or unapplied configuration.

170
MCQhard

An administrator is deploying a containerized Ansible Automation Platform 2.4 on a RHEL 9 host using the `ansible-container-installer`. After running the installation, the automation controller web UI is unreachable, and `podman ps` shows that the `automation-controller` container is in a restart loop. The administrator checks the container logs and sees repeated messages about failing to connect to the PostgreSQL database. The database container is running. Which action should the administrator take next?

A.Increase the memory limit for the automation controller container by editing the `container.yml` file and re-running the installer.
B.Restart the PostgreSQL container with `podman restart postgresql` and then restart the automation controller container.
C.Verify that the `postgresql` container's data directory has the correct SELinux context and that the `container_manage_cgroup` boolean is enabled.
D.Inspect the `automation-controller` container's environment variables to ensure the database hostname, port, username, and password match those configured for the PostgreSQL container.
AnswerD

In a containerized AAP deployment, the controller connects to the database using environment variables such as `CONTROLLER_PG_HOST`, `CONTROLLER_PG_PORT`, `CONTROLLER_PG_USER`, and `CONTROLLER_PG_PASSWORD`. If these do not match the actual database container's configuration, the controller will fail to connect and restart. Verifying and correcting these variables resolves the issue.

Why this answer

In a containerized AAP deployment, the automation controller and PostgreSQL run as separate containers. The controller uses environment variables to locate and authenticate to the database. When the controller container enters a restart loop with database connection errors, the most likely cause is a mismatch in these environment variables.

Verifying and aligning them with the database container's configuration restores connectivity and allows the controller to start successfully.

Exam trap

The trap here is focusing on container runtime or resource issues when the error message explicitly points to a database connection failure, which is typically a configuration mismatch.

171
MCQmedium

An Ansible playbook uses async and poll to run a long-running task. The task reports 'async task did not complete within the requested time'. Which of the following is the most likely cause?

A.the poll interval is set too long
B.the async timeout value is set too short for the task duration
C.the async task requires become: yes
D.the host is unreachable
AnswerB

With async, the controller waits up to the poll interval for completion; if the task exceeds the configured async timeout, Ansible reports that it did not complete in time. Extending the timeout or increasing poll resolves this.

Why this answer

The error 'async task did not complete within the requested time' indicates that the async timeout value (set via the async parameter) is too short for the actual task duration. The poll interval does not affect the timeout; it only controls how often Ansible checks the task status. Option B is correct because increasing the async value allows the task more time to complete.

172
MCQmedium

A team develops a custom Ansible role 'webserver' that depends on another role 'common'. They want to ensure that when 'webserver' is used, 'common' is automatically installed from the same Galaxy server. Which approach should they use?

A.Add a requirements.yml file in the role's root directory specifying common.
B.Add a dependencies: ['common'] to the role's meta/main.yml file.
C.Use ansible-galaxy install webserver --with-dependencies to install common separately.
D.Include the 'common' role in the playbook before 'webserver'.
AnswerB

Correct: Role dependencies in meta/main.yml are automatically installed.

Why this answer

Ansible roles can declare dependencies in the `meta/main.yml` file using the `dependencies` key. When the 'webserver' role is installed via `ansible-galaxy install`, Ansible automatically resolves and installs all listed dependencies from the same Galaxy server, ensuring 'common' is present without manual intervention.

Exam trap

The trap here is that candidates confuse role dependencies (declared in `meta/main.yml`) with playbook-level role ordering or external requirements files, leading them to choose options that manage execution order or manual installation instead of automatic dependency resolution.

How to eliminate wrong answers

Option A is wrong because a `requirements.yml` file in the role's root directory is not automatically processed by Ansible when installing a role; it is used at the project or playbook level to define external role collections for `ansible-galaxy install -r`. Option C is wrong because `--with-dependencies` is not a valid flag for `ansible-galaxy install`; dependencies are resolved automatically from `meta/main.yml` without requiring a separate flag. Option D is wrong because including 'common' in the playbook before 'webserver' only controls execution order at runtime, not installation; it does not ensure 'common' is installed from Galaxy automatically.

173
MCQhard

Refer to the exhibit. The playbook copies all .conf files from the control node to host1. If the playbook runs again on the same host without any changes, which task status is expected?

A.The task will fail because the destination directory already contains files.
B.All items will show 'ok' because files are identical.
C.The task will be skipped because the files already exist.
D.All items will show 'changed'.
AnswerB

The copy module compares checksums, so identical .conf files on host1 produce no transfer and report 'ok'. This satisfies the stem's constraint of a second run with no changes, where idempotence means unchanged state yields 'ok' rather than 'changed'.

Why this answer

Ansible's `copy` module is idempotent: when the source and destination files are identical (same content and checksum), the module reports `ok` rather than `changed`. On a second run with no source changes, all items in the loop will show `ok` because Ansible compares checksums and determines no copy is needed. This is the core idempotency guarantee of Ansible modules.

Exam trap

The trap is assuming that re-running a copy task always reports `changed` or `skipped` — candidates forget that Ansible's checksum-based idempotency produces `ok` for identical files.

How to eliminate wrong answers

Option A is wrong because the `copy` module overwrites destination files by default and does not fail when files already exist — it simply compares and skips if identical. Option C is wrong because the task is not skipped; `skipped` status only occurs when a `when` condition evaluates to false or the module explicitly skips, not when files are unchanged. Option D is wrong because `changed` would only appear if the file content differed from the source; identical files produce `ok`, not `changed`.

174
MCQhard

An administrator is using a role named 'app' that contains a task file 'install.yml' and a handler 'restart app'. The role is included in a playbook with 'include_role' and a variable 'app_version' set to '2.0'. The task file 'install.yml' includes a task that notifies the handler. During execution, the handler runs immediately after the task, before other tasks in the play. Which action should the administrator take to ensure the handler runs only at the end of the play?

A.Add 'meta: flush_handlers' after the role inclusion.
B.Set 'force_handlers: false' in the play to prevent handlers from running until the end.
C.Check the role for a 'meta: flush_handlers' task and remove it, because it forces handlers to run prematurely.
D.Ensure that the handler is not notified until the end of the play by moving the notification to a task that runs last.
AnswerC

Handlers normally run at the end of a play. If a handler runs immediately after the notifying task, the most likely cause is a 'meta: flush_handlers' task within the role or play that forces handlers to run at that point. Removing that task will restore the default behavior, where handlers run at the end of the play. This is the correct action to ensure the handler runs only at the end.

Why this answer

Handlers are designed to run at the end of a play. If a handler runs immediately after being notified, it is typically because a 'meta: flush_handlers' task is present, which explicitly forces handlers to run at that point. Removing that task restores the default behavior.

The other options either do not address the cause or would force handlers to run even earlier.

Exam trap

The trap here is confusing 'force_handlers' with handler timing; 'force_handlers' controls running handlers after failures, not when they run during a successful play.

175
MCQeasy

An administrator needs to create a new Ansible content collection named `myorg.automation` that will contain roles and modules. Which command initializes the collection directory structure with the required skeleton files?

A.ansible-galaxy collection init myorg.automation
B.ansible-playbook --init-collection myorg.automation
C.ansible-galaxy init myorg.automation
D.ansible-builder init myorg.automation
AnswerA

The `ansible-galaxy collection init` command creates a new collection directory structure with the specified namespace and name. It generates skeleton files including `galaxy.yml`, `README.md`, `docs/`, `plugins/`, `roles/`, and `playbooks/`. This command is the standard way to start a new collection, ensuring all necessary files are present for development and packaging.

Why this answer

The `ansible-galaxy collection init` command is the correct way to create a new collection skeleton. It sets up the directory structure with the namespace and collection name, and generates essential files like `galaxy.yml` and `README.md`. Other commands either initialize roles (`ansible-galaxy init`) or serve entirely different purposes.

Exam trap

The trap here is confusing `ansible-galaxy init` for roles with `ansible-galaxy collection init` for collections, as both use the `ansible-galaxy` command but target different content types.

176
MCQeasy

Refer to the exhibit. What is the output of the debug task?

A.10.0.0.5
B.[ '192.168.1.10' ]
C.eth0
D.192.168.1.10
AnswerD

The debug task prints the value held in the variable, which resolves to 192.168.1.10 as shown in the exhibit's host facts. Other addresses appearing in the inventory belong to different hosts or interfaces, so they are not the registered output.

Why this answer

The `debug` task in Ansible uses the `msg` parameter to display the value of a variable. In the exhibit, the variable `ansible_default_ipv4.address` is referenced, which returns the IPv4 address of the default network interface. Since the host's default interface is eth0 with IP 192.168.1.10, the debug output is that IP address.

Option D correctly shows the output as '192.168.1.10'.

Exam trap

The trap here is that candidates often confuse `ansible_default_ipv4` with `ansible_all_ipv4_addresses` or think the output includes the interface name, leading them to select the interface name (eth0) or a list of all IPs instead of the single default IP.

How to eliminate wrong answers

Option A is wrong because '10.0.0.5' is not the IP address of the default interface (eth0) in this scenario; it might be a secondary IP or unrelated. Option B is wrong because it wraps the IP in a list format with brackets and quotes, but the `msg` parameter outputs a plain string, not a list. Option C is wrong because 'eth0' is the interface name, not the IP address; the `ansible_default_ipv4.address` fact specifically returns the IP address, not the interface name.

177
MCQmedium

A playbook uses a loop over a list of packages to ensure they are installed. However, the playbook runs slowly because each package is processed individually. Which optimization technique should be used to improve performance?

A.Pass the entire list to the package module's 'name' parameter instead of looping.
B.Use with_items instead of loop; with_items is faster.
C.Set the async parameter on the looped task to run packages in parallel.
D.Use the serial keyword at the play level to increase parallelism.
AnswerA

Passing the whole list to the package module's name parameter lets Ansible invoke the underlying package manager once for all packages, rather than spawning a separate module execution per item. This removes per-iteration overhead, directly addressing the slow loop described in the stem.

Why this answer

Ansible's package modules (such as yum, apt, or dnf) accept a list of packages in the 'name' parameter. Passing the entire list in a single task eliminates the overhead of multiple task executions, SSH connection reuse, and module setup/teardown that occur with each iteration in a loop. This reduces the number of Ansible task runs from N to 1, significantly improving performance.

Exam trap

The trap here is that candidates often confuse task-level parallelism (which Ansible does not natively support for loops) with host-level parallelism (controlled by 'serial' or 'strategy'), leading them to select options that seem to increase parallelism but do not apply to a single-host loop.

How to eliminate wrong answers

Option B is wrong because 'with_items' is a legacy loop syntax that is functionally equivalent to 'loop' and does not provide any performance advantage; both still execute the task once per item. Option C is wrong because setting 'async' on a looped task does not run packages in parallel; it only allows the task to run in the background with polling, but each iteration still runs sequentially. Option D is wrong because the 'serial' keyword controls the number of hosts processed at a time in a play, not the parallelism of tasks within a single host; it does not affect how a loop over packages is executed on a given host.

178
Multi-Selectmedium

Which TWO of the following statements about Ansible roles are correct?

Select 2 answers
A.Role names must be prefixed with 'ansible-role-' when published to Ansible Galaxy.
B.Variables in 'defaults/main.yml' have the lowest precedence and can be overridden by inventory variables.
C.Role dependencies are defined in the 'meta/main.yml' file.
D.The 'include_role' module can only be used for static imports.
E.A role's tasks are executed before any 'pre_tasks' defined in the playbook.
AnswersB, C

Variables in `defaults/main.yml` sit at the bottom of Ansible's precedence order, below inventory group_vars, host_vars and play vars. This satisfies the stem's requirement that role defaults remain overridable, letting consumers customise a role without editing its files.

Why this answer

Option B is correct because variables defined in a role's defaults/main.yml have the lowest precedence in Ansible's variable hierarchy, meaning they can be overridden by inventory variables (host_vars, group_vars), play vars, and virtually any other variable source. Option C is correct because role dependencies are declared in the meta/main.yml file under the 'dependencies' key, which Ansible reads to automatically pull in and execute dependent roles before the current role. Option A is incorrect because the 'ansible-role-' prefix is only a naming convention recommended for Galaxy, not a mandatory requirement.

Option D is incorrect because include_role performs dynamic inclusion at runtime, whereas import_role is used for static imports. Option E is incorrect because pre_tasks in a playbook always run before the roles section, not after.

Exam trap

The trap is mixing up defaults vs vars precedence and static vs dynamic role inclusion; candidates often assume defaults override inventory variables or that include_role is static, both of which are backwards.

179
MCQhard

An administrator is writing a playbook that must execute a task only when a file exists on the remote host. They use the `stat` module to check the file and register the result. Which conditional expression should be used to run a subsequent task based on the file's existence?

A.`when: stat_result.exists`
B.`when: stat_result.stat.is_exists`
C.`when: stat_result.is_exists`
D.`when: stat_result.stat.exists`
AnswerD

The `stat` module registers a variable that contains a `stat` key, which is a dictionary with keys such as `exists`, `isreg`, etc. Therefore, the correct conditional to check if the file exists is `stat_result.stat.exists`. This is the standard way to use the result of the `stat` module.

Why this answer

The `stat` module returns a dictionary where the `stat` key contains the file status information. The correct way to check if the file exists is to reference `stat_result.stat.exists`. This ensures the conditional evaluates correctly based on the module's output.

Exam trap

The trap here is forgetting that the `stat` module nests its results under a `stat` key; many mistakenly use `stat_result.exists` directly.

180
MCQmedium

A playbook uses a variable named `db_port` that must be defined by the user at runtime, but should fall back to 5432 if the user does not provide it. Which approach ensures this behavior without failing the play when the variable is undefined?

A.Use the `default` filter: `{{ db_port | default(5432) }}`.
B.Define `db_port` in `group_vars/all.yml` with a value of 5432.
C.Reference `db_port` directly and set `ignore_errors: true` on the task.
D.Use `vars_prompt` to ask for `db_port` with a `default` keyword set to 5432.
AnswerA

The `default` filter returns the specified fallback value when the variable is undefined, which directly satisfies the requirement. It does not error on undefined variables, so the play continues. Using it in a template or module argument such as `port: "{{ db_port | default(5432) }}"` provides a safe default. This is the idiomatic Ansible way to handle optional variables with fallback values.

Why this answer

The `default` filter is the correct mechanism because it supplies a fallback only when the variable is undefined, allowing user-provided values to take precedence. It avoids interactive prompts and precedence conflicts, and it works in any templated context. The other options either force a value, require interaction, or fail to provide a value at all.

Exam trap

The trap here is assuming that defining a variable in group_vars or using vars_prompt with a default is equivalent to a runtime fallback filter.

181
MCQmedium

An administrator is deploying a containerized Ansible Automation Platform 2.4 on RHEL 9. After running the installer, the `automation-controller` containers fail to start, and the installer log reports that the `podman` service is not running. The administrator confirms that `podman` is installed. Which action should the administrator take to resolve the failure?

A.Enable and start the `podman.socket` service, then rerun the installer
B.Add the `awx` user to the `docker` group and restart the `automation-controller` service
C.Set `container_runtime=podman` in the inventory and rerun `setup.sh`
D.Install the `docker-ce` package and configure the installer to use Docker instead of Podman
AnswerA

Containerized AAP uses Podman to run its services, and the installer expects the Podman API socket to be available. Enabling and starting `podman.socket` provides that API endpoint. Rerunning the installer after the socket is active allows the container services to start, resolving the reported failure.

Why this answer

The containerized AAP installer relies on the Podman API, which is exposed by `podman.socket`. When that socket is inactive, container operations fail even though the Podman binary is present. Enabling and starting `podman.socket`, then rerunning the installer, restores the API endpoint and allows the AAP container services to start successfully.

Exam trap

The trap here is assuming that an installed Podman binary is sufficient, when the installer actually requires the Podman API socket service to be running.

182
MCQeasy

You provision a new RHEL 9 control node and create a project directory at /home/devops/ansible. While testing connectivity with `ansible all -m ping`, every host returns UNREACHABLE, yet `ssh` from the shell to those same hosts works without a password. The inventory file at /home/devops/ansible/inventory defines the group `web` with `web1 ansible_host=10.20.30.41`. Which action most directly resolves the failure?

A.Add `ansible_connection=local` to the inventory host entry.
B.Add `ansible_python_interpreter=/usr/bin/python3` to the inventory host entry.
C.Install the `sshpass` package on the control node.
D.Add `ansible_user=devops` to the inventory host entry or run the ad-hoc command with `-u devops`.
AnswerD

Ansible defaults to the local username for the remote SSH user unless told otherwise. If the local account differs from the remote account that owns the authorized key, the ping module cannot authenticate and the host is reported UNREACHABLE. Supplying the correct remote user through a host variable or the -u flag restores connectivity, and the inventory already resolves the address correctly.

Why this answer

Because manual SSH succeeds but Ansible cannot connect, the difference lies in the identity Ansible uses. Ansible defaults to the local account name for remote logins, so when that name differs from the account holding the authorized key, the connection is refused and hosts are marked UNREACHABLE. Defining the correct remote user in inventory or on the command line restores key-based access without altering the transport.

Exam trap

The trap here is assuming that working manual SSH guarantees Ansible uses the same username, when Ansible actually defaults to the local account name.

183
Multi-Selecteasy

Which TWO filters are commonly used for list manipulation in Ansible? (Select exactly two.)

Select 2 answers
A.`default`
B.`map`
C.`ternary`
D.`select`
E.`regex_replace`
AnswersB, D

The map filter applies a function to every element of a list, returning a transformed list of equal length. It is a core Jinja2 list-manipulation filter in Ansible, satisfying the stem by enabling element-wise transformation within playbooks and templates.

Why this answer

The `map` filter is specifically designed for list manipulation in Ansible, allowing you to apply a transformation (such as extracting a specific attribute) to every element in a list. Option D is correct because the `select` filter is used to filter list items based on a condition, returning only those elements that match. Both are core Jinja2 filters commonly used in Ansible playbooks for processing lists.

Exam trap

The trap here is that candidates often confuse filters that operate on strings (like `regex_replace`) or single values (like `default` and `ternary`) with those designed for list iteration, leading them to select incorrect options that are not list-specific.

184
Multi-Selectmedium

An organization uses automation controller and must ensure that sensitive data such as passwords and API keys are not exposed in job output. Which TWO actions should the administrator take? (Choose two.)

Select 2 answers
A.Use automation controller credentials to store secrets instead of plaintext variables.
B.Disable job output entirely for all job templates that use secrets.
C.Mark sensitive variables as no_log: true in tasks that might display them.
D.Enable verbose logging on the job template to audit variable usage.
E.Store all secrets in an unencrypted file on the automation controller and rely on file permissions.
AnswersA, C

Automation controller credentials securely store secrets and inject them at runtime without writing them to job output. Using credentials instead of plaintext variables in playbooks prevents accidental exposure in logs and job details, aligning with the requirement to keep sensitive data out of output.

Why this answer

Using no_log: true on tasks that handle secrets prevents their output from being logged or displayed. Storing secrets in automation controller credentials keeps them out of playbooks and job output. Together, these actions ensure sensitive data is not exposed while maintaining operational visibility.

Exam trap

The trap here is believing that increasing logging or relying on file permissions alone will protect secrets, when in fact those approaches can increase exposure or fail to secure the data.

185
MCQmedium

A playbook includes a role that has a task notifying a handler defined within the role. Another task in the play, outside the role, also notifies the same handler by name. After running the playbook, the administrator notices that the handler runs only once. What is the reason for this behavior?

A.Handlers are executed immediately when notified, so the first notification triggers it and the second is ignored.
B.Handlers are executed only once per play, even if notified multiple times.
C.The handler runs only if the notifying task reports a changed status, and both tasks reported 'ok'.
D.The handler is scoped to the role and cannot be notified from outside the role.
AnswerB

Ansible handlers are designed to run only once at the end of a play, regardless of how many times they are notified. This prevents redundant service restarts. Even if multiple tasks notify the same handler, it will execute a single time after all tasks complete, unless explicitly flushed.

Why this answer

Handlers in Ansible are run once per play at the end, even if notified multiple times. This is by design to avoid multiple restarts of a service. The handler's scope is not limited to the role; it can be notified from anywhere in the play.

The correct explanation is that handlers are deduplicated and executed once.

Exam trap

The trap here is thinking that handlers run immediately upon notification or that they are scoped to roles. In fact, they are queued and run once at the end of the play.

186
MCQeasy

An administrator wants to apply a role to a subset of hosts based on a condition. The condition should be evaluated for each host individually. Which approach is correct?

A.Use the 'tags' directive on the role and run the playbook with '--tags'.
B.Use the 'become' directive on the role to control privilege escalation.
C.Use the 'delegate_to' directive on the role to target specific hosts.
D.Use the 'when' directive on the role inclusion in the play.
AnswerD

Applying 'when' to a role inclusion (e.g., 'roles: - role: myrole when: condition') evaluates the condition per host. If true, the role is applied to that host. This is the standard way to conditionally apply roles on a per-host basis, ensuring the role's tasks run only where the condition is met.

Why this answer

The 'when' directive on a role inclusion evaluates the condition for each host, applying the role only where the condition is true. This is the correct method for per-host conditional role application. Tags, become, and delegate_to serve different purposes and do not provide conditional execution based on host-specific variables.

Exam trap

The trap here is thinking that tags or other directives can conditionally apply roles per host, when 'when' is the correct mechanism.

187
MCQhard

What is the most likely cause of the failure?

A.The --check flag prevents role variable resolution.
B.The nginx role's defaults or vars do not define 'nginx_version'.
C.The host web1 is not configured to use the nginx role.
D.The nginx role was not included in the playbook correctly.
AnswerB

The role references nginx_version, but neither defaults nor vars supply it. Ansible resolves variables from role defaults, vars, inventory, or playbook; with none defining nginx_version, the variable is undefined and templating fails during the play.

Why this answer

The error indicates that Ansible cannot resolve the variable 'nginx_version' during the playbook run. Since the `--check` flag only simulates changes and does not affect variable resolution, the most likely cause is that the nginx role's `defaults/main.yml` or `vars/main.yml` does not define this variable, leaving it undefined and causing the failure.

Exam trap

The trap here is that candidates often assume the `--check` flag is the culprit for any failure during a dry run, but Ansible's check mode still resolves all variables and validates templates, so a missing variable error is not caused by the check flag itself.

How to eliminate wrong answers

Option A is wrong because the `--check` flag does not prevent role variable resolution; it only skips the execution of modules that would make changes, while variable resolution still occurs normally. Option C is wrong because the host web1 does not need to be 'configured to use the nginx role' in a separate step; roles are applied via the playbook's `roles:` directive or `include_role`, and the error is about a missing variable, not role assignment. Option D is wrong because the error message does not indicate a syntax or inclusion issue with the role; it specifically points to an undefined variable, meaning the role was included but its variable definitions are incomplete.

188
MCQeasy

A playbook must execute a task on a host that is not part of the inventory, such as a temporary cloud instance. The task should run on that host without modifying the inventory file. Which directive should be used?

A.add_host
B.local_action
C.delegate_to
D.include_vars
AnswerA

The add_host module dynamically adds a host to the in-memory inventory during playbook execution. It allows you to target a host that is not in the static inventory, and subsequent plays can use it. This meets the requirement without editing the inventory file.

Why this answer

The add_host module is designed to add hosts to the in-memory inventory at runtime, enabling tasks to run on hosts not present in the static inventory. Other directives like delegate_to, local_action, and include_vars serve different purposes and do not add hosts.

Exam trap

The trap here is confusing delegate_to with add_host. delegate_to requires the host to already exist in the inventory, while add_host creates the host entry dynamically.

189
MCQmedium

Refer to the exhibit. The playbook fails with an error. What is the most likely cause?

A.import_tasks cannot be used with a loop.
B.import_tasks must be placed in a role.
C.The loop variable should be referenced as '{{ item }}' without quotes.
D.The file names must be literal without templates.
AnswerA

The failure stems from `import_tasks` being static: it is parsed at playbook load time, so it cannot accept a `loop`, which is evaluated at runtime. The stem's error arises because the task file is imported before loop items exist. Switching to `include_tasks`, which is dynamic, resolves this constraint.

Why this answer

`import_tasks` is a static import that is processed at playbook parse time, before any variables or loops are evaluated. Ansible does not support using `import_tasks` inside a loop (`loop:` or `with_items:`) because the import occurs once during parsing, not dynamically per iteration. To run tasks repeatedly, you must use `include_tasks`, which is processed dynamically at runtime and supports loops.

Exam trap

Red Hat often tests the distinction between static (`import_tasks`) and dynamic (`include_tasks`) includes, and the trap here is that candidates confuse the two, thinking any include can be used with a loop, when only dynamic includes support iteration.

How to eliminate wrong answers

Option B is wrong because `import_tasks` does not need to be placed in a role; it can be used in any playbook or task file to import a list of tasks from another file. Option C is wrong because referencing the loop variable as `'{{ item }}'` with quotes is valid in Ansible; the error is not caused by quoting but by the static import limitation. Option D is wrong because file names in `import_tasks` can be templates (e.g., `{{ var }}.yml`) as long as they resolve to a valid file at parse time; the issue is not with templating but with the loop construct.

190
MCQhard

An Ansible rolling update playbook has 'serial: 1' and 'max_fail_percentage: 0'. During the update of a 5-host group, the first host fails. What is the outcome?

A.The play pauses for manual intervention
B.The play retries the failed host
C.The play aborts immediately
D.The play continues with the remaining 4 hosts
E.The play marks the host as unreachable and continues
AnswerC

With `serial: 1`, each host forms its own batch, so the first host's failure leaves a 100% batch failure rate. Since `max_fail_percentage: 0` permits no failures, Ansible aborts the play immediately, preventing any remaining hosts from being updated.

Why this answer

With 'serial: 1', Ansible updates one host at a time. 'max_fail_percentage: 0' means that if any host fails (0% failure tolerance), the entire playbook run is aborted immediately. When the first host fails, Ansible stops further execution because the failure percentage exceeds the threshold, and no retries or continuation occur.

Exam trap

The trap here is that candidates often assume 'serial: 1' means the play will skip the failed host and continue with the next, but 'max_fail_percentage: 0' overrides that by aborting on any failure.

How to eliminate wrong answers

Option A is wrong because Ansible does not pause for manual intervention by default; it aborts based on max_fail_percentage. Option B is wrong because Ansible does not automatically retry failed hosts unless a retry mechanism (like 'until' or 'retries') is explicitly configured, which is not the case here. Option D is wrong because 'max_fail_percentage: 0' prevents continuation after any failure; the play does not proceed to remaining hosts.

Option E is wrong because marking a host as unreachable is a separate behavior (e.g., when connection fails), but here the host fails during the update, and the failure percentage triggers an abort, not an unreachable status.

191
Multi-Selecthard

An automation engineer is using Ansible to manage a fleet of servers. They need to ensure that certain tasks run only on hosts that match specific criteria. Which two of the following are valid ways to limit task execution based on host facts? (Choose two.)

Select 2 answers
A.Use the 'group_by' module to create dynamic groups based on facts, then target those groups in subsequent plays.
B.Use the 'tags' keyword to tag tasks with fact values, then run the playbook with --tags to filter.
C.Use the 'delegate_to' directive with a fact-based expression to delegate tasks to matching hosts.
D.Use the 'when' conditional with a fact variable, such as when: ansible_facts['os_family'] == 'RedHat'.
E.Use the 'run_once' keyword with a fact-based condition to run the task only on the first matching host.
AnswersA, D

The group_by module creates new inventory groups based on facts, such as os_family. You can then write plays that target these dynamic groups. This is a valid approach to limit task execution to hosts matching specific fact criteria, though it requires a separate play or playbook run.

Why this answer

The 'when' conditional and the 'group_by' module are both valid methods to limit task execution based on host facts. The 'when' clause evaluates facts per host, while 'group_by' dynamically creates groups that can be targeted in subsequent plays. Tags, delegate_to, and run_once do not provide fact-based filtering of hosts.

Exam trap

The trap here is assuming that tags or run_once can be used for fact-based filtering. Tags are static, and run_once ignores facts, so they cannot select hosts based on facts.

192
Multi-Selecthard

Which TWO of the following are best practices when coordinating rolling updates with Ansible?

Select 2 answers
A.Define a 'max_fail_percentage' to abort the update if too many hosts fail.
B.Use the 'serial' keyword to update a subset of hosts at a time.
C.Use 'strategy: free' to allow hosts to run tasks independently.
D.Use 'gather_facts: no' to speed up the playbook.
E.Set 'any_errors_fatal: true' to stop the update on the first failure.
AnswersA, B

Setting `max_fail_percentage` halts the play once failed hosts exceed the threshold, preventing a faulty update from cascading across the remaining batch. This directly satisfies the stem's coordination requirement by bounding blast radius during rolling updates, rather than letting Ansible continue through every host regardless of accumulating failures.

Why this answer

Option B is correct because the 'serial' keyword controls how many hosts are targeted per play iteration, which is the fundamental mechanism for performing a rolling update in Ansible—updating a small batch at a time rather than all hosts at once. Option A is correct because 'max_fail_percentage' works together with 'serial' to abort the entire play if the number of failed hosts in a batch exceeds the defined threshold, preventing a bad rollout from cascading across the fleet. Option C is not a best practice for rolling updates because 'strategy: free' lets each host proceed through tasks independently without waiting for others, which breaks the controlled batch-by-batch ordering that rolling updates require.

Option D is not inherently a rolling-update best practice; disabling fact gathering may speed execution but does not coordinate or sequence updates and can break plays that depend on facts. Option E is not appropriate here because 'any_errors_fatal: true' aborts the whole play on the very first host failure, which is more aggressive than the graduated tolerance provided by 'max_fail_percentage' and is not the recommended pairing for controlled rolling updates.

Exam trap

The trap here is that candidates often confuse 'any_errors_fatal' (which stops on the first failure globally) with 'max_fail_percentage' (which aborts only after a threshold of failures in a batch), leading them to select option E instead of A.

193
MCQeasy

A playbook includes multiple roles. The administrator wants to skip a specific role during execution. Which technique should they use?

A.Add a condition to each task in the role
B.Use the '--limit' option to exclude hosts
C.Use tags on the role and run with --tags
D.Use tags on the role and run with --skip-tags
AnswerD

Tags applied to a role let you selectively control execution; running ansible-playbook with --skip-tags excludes any role carrying that tag. This satisfies the requirement to skip one specific role while the remaining roles in the playbook still run.

Why this answer

Ansible roles support tagging, and the `--skip-tags` option allows you to exclude all tasks within a role that share a specific tag. By assigning a unique tag to the role (e.g., `tags: skip_me`) and running the playbook with `--skip-tags skip_me`, the entire role is skipped without modifying individual tasks or hosts.

Exam trap

Candidates often confuse --tags and --skip-tags, mistakenly choosing --tags when the goal is to skip a role.

How to eliminate wrong answers

Option A is wrong because adding a condition to each task in the role is inefficient, error-prone, and violates DRY principles; it requires modifying every task and does not leverage Ansible's built-in role-skipping mechanisms. Option B is wrong because `--limit` filters hosts, not roles or tasks; it cannot skip a specific role within a playbook that targets multiple hosts. Option C is wrong because using `--tags` includes only tagged items, but the question asks to skip a specific role, not to include only certain roles; `--tags` would require tagging all other roles and tasks, which is impractical and opposite to the goal.

194
MCQeasy

A company uses Ansible Automation Platform and wants to ensure that all playbook runs are logged for audit purposes. What is the simplest way to achieve centralized logging of job runs?

A.Use the logging module in each playbook to write to a central syslog.
B.Configure the syslog server in the automation controller settings.
C.Add a playbook callback that sends output to a file on each node.
D.Enable verbose logging in the inventory file.
AnswerB

Configuring the syslog server in automation controller settings forwards job-run audit records directly to a central collector, satisfying the requirement for centralised logging without extra tooling. Automation controller emits job events, activity stream entries and login attempts over syslog, so a single setting delivers the audit trail the stem demands.

Why this answer

Automation Controller (formerly Ansible Tower) has a built-in setting under 'System → Logging' where you can configure a syslog server (e.g., using RFC 5424). Once configured, all job runs, playbook output, and audit events are automatically forwarded to that central syslog server without modifying any playbooks or adding custom callbacks. This is the simplest, most centralized, and most maintainable approach for audit logging.

Exam trap

The trap here is that candidates often think they need to modify playbooks (Option A) or write custom callback plugins (Option C) to achieve logging, when the platform already provides a simple, built-in configuration option for centralized syslog forwarding.

How to eliminate wrong answers

Option A is wrong because adding a 'logging' module call to every playbook is not centralized; it requires manual insertion into each playbook, violates the principle of separation of concerns, and does not capture system-level events like job launches or failures. Option C is wrong because a callback plugin that writes to a file on each node creates distributed logs, not centralized logging, and requires custom development and deployment to all nodes. Option D is wrong because enabling verbose logging in the inventory file is not a valid Ansible concept; inventory files do not have a 'verbose' setting, and even if you meant verbosity at the ansible-playbook command level, that only increases output detail locally and does not send logs to a central server.

195
MCQeasy

An Ansible playbook needs to ensure a service is enabled and running on boot. Which combination of parameters should be used with the 'systemd' module?

A.enabled: yes, state: reloaded
B.enabled: yes, state: started
C.enabled: yes, daemon_reload: yes
D.enabled: yes, state: restarted
AnswerB

Setting enabled: yes registers the unit for start on boot, while state: started ensures it is running now. Together they satisfy both halves of the stem's requirement, unlike state alone or enabled alone, which leave one condition unmet.

Why this answer

The 'systemd' module in Ansible requires both 'enabled: yes' to set the service to start on boot and 'state: started' to ensure the service is currently running. This combination directly fulfills the requirement of ensuring a service is enabled and running on boot.

Exam trap

The trap here is that candidates often confuse 'enabled' with 'state' or assume 'daemon_reload' or 'reloaded' can substitute for starting the service, but only the combination of 'enabled: yes' and 'state: started' fully satisfies the requirement for both boot persistence and current running state.

How to eliminate wrong answers

Option A is wrong because 'state: reloaded' only reloads the service's configuration without starting it if it is not running, and it does not guarantee the service is enabled on boot. Option C is wrong because 'daemon_reload: yes' only reloads the systemd manager configuration (e.g., after adding new unit files) but does not start the service or enable it on boot. Option D is wrong because 'state: restarted' restarts the service if it is running but does not ensure it is enabled to start on boot, and it will fail if the service is not already running.

196
Matchingmedium

Match each firewall zone to its default behavior.

Drag a concept onto its matching description — or click a concept then click the description.

Concepts
Matches

Default zone, untrusted network

Private network, slightly trusted

Demilitarized zone, limited access

All traffic accepted

All incoming packets dropped

Why these pairings

Common firewalld zones include public (default deny), trusted (allow all), external (NAT with limited inbound), dmz (limited inbound for public servers), internal (trusted but filtered), and drop (silent discard). Common confusions involve swapping the behaviors of public and trusted, or misunderstanding dmz as fully blocking instead of selectively allowing.

197
MCQhard

An automation team is designing a content collection to distribute internal Ansible modules across the organization. The collection should be installed from a private Galaxy server. To minimize namespace conflicts and ensure discoverability, which naming convention should be used for the collection?

A.collection_name.namespace
B.namespace_collection_name
C.namespace-collection_name
D.namespace.collection_name
AnswerD

The namespace.collection_name format is mandatory for Galaxy-hosted collections, where the namespace scopes ownership and prevents conflicts between organisations. This satisfies the stem's requirement to minimise namespace conflicts and ensure discoverability on a private Galaxy server.

Why this answer

In Ansible, collections are distributed using a fully qualified collection name (FQCN) in the format `namespace.collection_name`. This naming convention is required by the Ansible Galaxy server and the `ansible-galaxy collection install` command to uniquely identify and install collections, minimizing namespace conflicts and ensuring discoverability across the organization.

Exam trap

The trap here is that candidates may confuse the dot separator with other common naming conventions (like underscores or hyphens used in Python packages or Ansible roles), but Ansible collections strictly require the `namespace.collection_name` format with a dot.

How to eliminate wrong answers

Option A is wrong because `collection_name.namespace` reverses the required order; the namespace must come first, followed by a dot and then the collection name. Option B is wrong because `namespace_collection_name` uses an underscore separator, but Ansible collections require a dot (`.`) as the delimiter between namespace and collection name. Option C is wrong because `namespace-collection_name` uses a hyphen, which is not the correct separator; the dot is the only valid separator in Ansible's FQCN for collections.

198
Multi-Selecthard

Which TWO of the following are correct about Ansible Vault?

Select 2 answers
A.vault encryption is irreversible
B.vault encrypted files cannot be edited in place
C.the vault password can be provided via the '--vault-password-file' option
D.vault can encrypt only specific variable values within a file
E.the vault id can be specified to use multiple vault passwords
AnswersC, E

Correct: this is a common way to automate vault decryption.

Why this answer

The `--vault-password-file` option allows Ansible to read the vault password from a file, which is a standard method for providing the password non-interactively, especially in automation scripts or CI/CD pipelines. This avoids the need for manual password entry and supports secure password management.

Exam trap

In the RHCE exam, candidates often assume vault encryption is irreversible or that it can encrypt only specific values within a file, confusing it with `ansible-vault encrypt_string` which encrypts a single string, not partial file encryption.

199
MCQeasy

An administrator is rolling out a configuration change to a fleet of 12 application servers. The change must be applied to one server at a time so that the load balancer always has 11 healthy backends. Which playbook directive guarantees this behavior?

A.throttle: 1
B.serial: 1
C.order: sequential
D.forks: 1
AnswerB

serial: 1 instructs Ansible to process exactly one host per batch, so the play runs completely on one server before moving to the next. On a 12-node fleet, that leaves 11 servers untouched and available to the load balancer at all times. This directly satisfies the requirement of updating one server at a time without taking down capacity.

Why this answer

serial defines how many hosts Ansible includes in each rolling batch. Setting serial: 1 ensures the entire play finishes on one host before the next host begins, which keeps 11 of 12 servers available to the load balancer. Other keywords such as throttle and forks affect parallelism or task concurrency, but they do not create per-host rolling batches.

Exam trap

The trap here is confusing task-level concurrency controls like throttle or forks with the play-level batch size set by serial.

200
Drag & Dropmedium

Drag and drop the steps to configure a logical volume (LV) using LVM on a new disk in the correct order.

Drag or tap steps into the slots.

Steps
Order
1Step 1
2Step 2
3Step 3
4Step 4

Why this order

The correct sequence for configuring a logical volume using LVM on a new disk is: first create a physical volume from the disk, then create a volume group from that physical volume, then create a logical volume from the volume group, then format the logical volume with a filesystem, and finally mount the filesystem to make it accessible. This order ensures that each step builds upon the previous one, following the LVM hierarchy of PV -> VG -> LV -> filesystem -> mount.

201
Drag & Dropmedium

Drag and drop the steps to configure a systemd service to start automatically at boot in the correct order.

Drag or tap steps into the slots.

Steps
Order
1Step 1
2Step 2
3Step 3
4Step 4

Why this order

The correct sequence for configuring a systemd service to start at boot is: first create the unit file, then reload systemd to load the new unit, next enable the service to create the necessary symlinks for automatic start, then start the service immediately, and finally verify its status. Common mistakes include omitting the reload step, enabling after starting, or performing the reload too late.

202
MCQmedium

A playbook uses the 'block' and 'rescue' keywords to handle errors. The block contains three tasks. The first task fails. What happens next?

A.The rescue section runs and retries the failed task.
B.The rescue section runs immediately after the failure.
C.The playbook fails with an error message.
D.The remaining tasks in the block run, then the rescue section runs.
AnswerB

Ansible aborts the remaining tasks inside the block as soon as one fails, then transfers execution to the rescue section, which runs immediately. The rescue handles the error, allowing the playbook to continue rather than halting.

Why this answer

In Ansible, when a task inside a `block` fails, the `rescue` section is executed immediately after the failure, without running any remaining tasks in the block. This is analogous to a try-catch mechanism in programming: the block is the 'try', and the rescue is the 'catch'. Option B correctly describes this behavior.

Exam trap

The trap here is that candidates often confuse `block`/`rescue` with a simple retry mechanism or assume that all tasks in the block must complete before error handling, but Ansible's behavior is to immediately jump to rescue on the first failure.

How to eliminate wrong answers

Option A is wrong because the rescue section does not retry the failed task; it runs a separate set of tasks to handle the error, and retry logic would require a `until` loop or `retries` parameter on the task itself. Option C is wrong because the playbook does not fail immediately; the rescue section is designed to catch the error and continue execution, preventing a playbook failure unless the rescue itself fails. Option D is wrong because the remaining tasks in the block are skipped once a task fails; the rescue runs immediately, not after the block completes.

203
MCQeasy

An administrator is installing Ansible Automation Platform 2.4 on a RHEL 9 server. They have extracted the installer tarball and are ready to run the setup script. Which command should they use to perform a standard installation using the default inventory?

A.`./setup.sh`
B.`./install.sh`
C.`ansible-playbook -i inventory install.yml`
D.`ansible-playbook setup.yml`
AnswerA

The `setup.sh` script is the documented entry point for installing Ansible Automation Platform. It reads the `inventory` file in the same directory and executes the installer playbooks with the appropriate environment. Running this script performs the standard installation using the default inventory file, which the administrator can edit beforehand.

Why this answer

The AAP installer is executed by running the `setup.sh` script from the extracted directory. This script reads the `inventory` file and runs the necessary playbooks. Using any other command, such as `ansible-playbook` with a guessed playbook name or a nonexistent `install.sh`, will not perform the installation correctly.

Exam trap

The trap here is assuming that because AAP is Ansible-based, you must run a playbook directly, when the supported method is the wrapper script `setup.sh`.

204
MCQmedium

An administrator wants to create a custom credential type to store a third-party API key. The API key must be passed to the playbook as an environment variable `MY_API_KEY`. What is the correct Injector configuration in the custom credential type definition?

A.file: {MY_API_KEY: "{{ api_key }}"}
B.env: {"MY_API_KEY": api_key}
C.extra_vars: {MY_API_KEY: "{{ api_key }}"}
D.env: {MY_API_KEY: "{{ api_key }}"}
AnswerD

The env dictionary maps credential inputs to environment variables.

Why this answer

The Injector configuration for a custom credential type in Ansible Automation Platform uses the `env` key to map credential inputs to environment variables. The syntax `env: {"MY_API_KEY": "{{ api_key }}"}` correctly references the input field `api_key` using Jinja2 templating and assigns it to the environment variable `MY_API_KEY`, which the playbook can then access via `ansible_env.MY_API_KEY`.

Exam trap

The trap here is that candidates often confuse `env` with `extra_vars` or forget the Jinja2 templating syntax, leading them to pick Option B (missing braces) or Option C (incorrect injector type).

How to eliminate wrong answers

Option A is wrong because `file` is not a valid Injector key; it is used for file-based credential types (e.g., SSH keys) but not for environment variables. Option B is wrong because it omits the required Jinja2 braces around the variable reference (`api_key` instead of `{{ api_key }}`), which would cause the literal string 'api_key' to be passed rather than the credential input value. Option C is wrong because `extra_vars` is used to inject variables into the playbook's variable space, not as environment variables; it would set `MY_API_KEY` as an Ansible variable, not an environment variable.

205
Multi-Selectmedium

Which THREE of the following are valid attributes of the ansible.builtin.service module?

Select 3 answers
A.state
B.enabled
C.pattern
D.name
E.runlevel
AnswersA, B, D

Correct: state controls whether the service is started/stopped.

Why this answer

The `state` attribute is a core parameter of the `ansible.builtin.service` module, used to define the desired service status (e.g., `started`, `stopped`, `restarted`, `reloaded`). This directly controls the service's runtime state on the target system.

Exam trap

The trap here is that candidates confuse module-specific parameters (like `pattern` for `systemd` or `runlevel` for legacy init scripts) with the generic `service` module, which only supports `state`, `enabled`, `name`, and a few others like `arguments` and `use`.

206
MCQeasy

An administrator notices that during a rolling update, the playbook seems to hang after updating the first host. The playbook uses serial: 5. What is the most likely cause?

A.The playbook has an infinite loop.
B.One of the hosts in the batch is taking too long to complete its tasks.
C.The SSH control path is exhausted.
D.The max_fail_percentage is set too high.
AnswerB

With `serial: 5`, Ansible waits for every host in the current batch to finish all tasks before starting the next batch. A single slow host therefore blocks the remaining four, making the playbook appear to hang after the first host completes. The constraint is batch-wide synchronisation, not task failure.

Why this answer

When `serial: 5` is set, Ansible processes hosts in batches of five. If one host in the batch takes an unusually long time to complete its tasks (e.g., due to a slow network, a hanging service restart, or a long-running command), the entire batch will appear to hang because Ansible waits for all hosts in the current batch to finish before proceeding to the next batch. This is the most likely cause of the observed behavior during a rolling update.

Exam trap

Red Hat often tests the misconception that `serial` controls parallelism across all hosts (like `forks`), but the trap here is that `serial` batches hosts sequentially, so a single slow host in a batch blocks the entire batch from completing, causing the playbook to appear to hang.

How to eliminate wrong answers

Option A is wrong because an infinite loop would cause the playbook to run indefinitely on a single host, not hang after updating the first host in a batch; the playbook would continue looping on that host without progressing. Option C is wrong because SSH control path exhaustion would typically manifest as SSH connection failures or errors, not a hang after the first host completes; it is a connection pooling issue, not a batch processing delay. Option D is wrong because `max_fail_percentage` controls how many hosts can fail before Ansible aborts the playbook; a high value would allow more failures, not cause a hang, and it does not affect the timing of task completion within a batch.

207
MCQeasy

A junior admin is troubleshooting why a job template fails with 'Permission denied' when connecting to a target host. The job template uses a machine credential that appears correct. What is the first thing to check?

A.Verify the inventory contains the correct host IP
B.Check the credential's username and private key / password
C.Check the vault credential used in the job template
D.Check the project sync status
AnswerB

A 'Permission denied' error during connection typically stems from an invalid credential, so verifying the username and private key or password is the first check. The credential may appear correct while containing a mismatched key or wrong user.

Why this answer

The error 'Permission denied' during SSH connection to a target host indicates an authentication failure. Since the machine credential appears correct, the most immediate cause is that the username or private key/password stored in the credential is incorrect or mismatched. This is the first thing to check because the credential directly controls authentication to the target host.

Exam trap

The trap here is that candidates often confuse 'Permission denied' with a network or inventory issue, leading them to check the inventory or project sync instead of the credential's authentication details.

How to eliminate wrong answers

Option A is wrong because verifying the inventory host IP addresses connectivity issues (e.g., wrong host or unreachable), not authentication failures; 'Permission denied' is an SSH-level error, not a network reachability error. Option C is wrong because vault credentials are used to decrypt sensitive data within Ansible, not for SSH authentication to target hosts; they do not affect the 'Permission denied' error. Option D is wrong because project sync status relates to retrieving playbook content from a source control repository, not to SSH authentication; a failed sync would cause a different error (e.g., 'project not found'), not 'Permission denied'.

208
MCQhard

A company uses Ansible Tower and has defined a custom inventory script. The inventory returns JSON with nested groups. The playbook needs to list all hosts from a specific group 'webservers' that are not in the 'drain' subgroup. Which combination of filters correctly extracts these hosts?

A.{{ groups['webservers'] | symmetric_difference(groups['drain']) }}
B.{{ groups['webservers'] | intersect(groups['drain']) }}
C.{{ groups['webservers'] | union(groups['drain']) }}
D.{{ groups['webservers'] | difference(groups['drain']) }}
AnswerD

The difference filter returns elements in the first list absent from the second, so hosts in webservers but not drain are extracted. Both groups resolve via the groups magic variable, giving the exact set difference the playbook requires.

Why this answer

The `difference` filter in Ansible returns the elements of the first list that are not present in the second list. This directly matches the requirement: all hosts in the 'webservers' group that are not in the 'drain' subgroup.

Exam trap

The trap here is that candidates confuse `difference` with `symmetric_difference` (option A) or `intersect` (option B), often misreading the requirement as 'hosts not in drain' versus 'hosts in both groups'.

How to eliminate wrong answers

Option A is wrong because `symmetric_difference` returns elements that are in either list but not in both, which would include hosts in 'drain' but not in 'webservers' — not the required set. Option B is wrong because `intersect` returns only hosts that are in both groups, which is the exact opposite of what is needed. Option C is wrong because `union` combines all unique elements from both groups, giving all hosts from 'webservers' and 'drain' without exclusion.

209
MCQhard

Refer to the exhibit. An administrator runs a playbook in check mode and receives the shown output. What should be done to fix the failure while maintaining idempotency?

A.Modify the deploy role to use the force parameter when copying files.
B.Add a task in the apache role to create the /var/www/html directory using the file module.
C.Run the playbook without check mode to force the deployment.
D.Add a pre_task in the playbook to create /var/www/html before roles execute.
AnswerB

Creating the directory with the file module declares the desired state, so repeated runs report no change and idempotency holds. The failure stems from httpd's document root being absent before the copy task runs; the file module with state: directory satisfies that prerequisite declaratively rather than through an imperative shell command.

Why this answer

The failure in check mode indicates that the /var/www/html directory does not exist, and the apache role's copy task cannot write to it. The correct fix is to add a task in the apache role that uses the file module to create the directory with the desired state (e.g., state: directory), ensuring idempotency because the task will only create it if absent. This keeps the role self-contained and maintains idempotent behavior.

Exam trap

EX294 often tests the misconception that running without check mode or using force parameters resolves missing directory issues, but the real fix is to ensure the role itself creates required directories idempotently.

How to eliminate wrong answers

Option A is wrong because using the force parameter on the copy module only overwrites existing files; it does not create missing parent directories and would still fail. Option C is wrong because running without check mode does not fix the underlying missing directory; it would still fail unless the directory is created, and it breaks idempotency by potentially making changes without proper state management. Option D is wrong because adding a pre_task in the playbook creates the directory outside the role, which reduces role reusability and may not be idempotent if the pre_task is not properly written; it also violates the principle of keeping role dependencies within the role.

210
MCQmedium

An administrator is writing a playbook that must execute a task only when a specific variable is defined. The variable may be set in the inventory, group_vars, or host_vars. Which conditional ensures the task runs only if the variable 'app_port' is defined?

A.when: app_port is exists
B.when: app_port is not undefined
C.when: app_port
D.when: app_port is defined
AnswerD

The 'is defined' test is the correct Ansible conditional to check if a variable exists in the current host's context. It evaluates to true if 'app_port' is set from any source, including inventory, group_vars, or host_vars. This directly satisfies the requirement without erroring if the variable is missing, unlike a direct truthiness check.

Why this answer

The 'is defined' test is the standard way to check if a variable exists in Ansible. It correctly handles variables set from any source and avoids errors when the variable is missing. The other options either test truthiness, use invalid syntax, or confuse file existence with variable definition.

Only the correct option reliably ensures the task runs when 'app_port' is defined.

Exam trap

The trap here is confusing variable existence with truthiness or using an invalid test like 'is not undefined' or 'is exists'.

211
MCQhard

Refer to the exhibit. An administrator runs an Ansible playbook and receives the error shown. The playbook uses a variable 'vault_httpd_port' that should be stored in an encrypted vault file. Which step should the administrator take first to resolve the issue?

A.Re-encrypt the vault file with a different password.
B.Add 'vault_httpd_port' to the group_vars/all.yml file without encryption.
C.Use the --ask-vault-pass option again with a different password.
D.Ensure the vault file is referenced in the playbook using include_vars or vars_files, and that the vault password is correct.
AnswerD

Referencing the vault file via `vars_files` or `include_vars` is what actually loads `vault_httpd_port` into the play's variable scope; without that, Ansible cannot decrypt or resolve it, producing the undefined-variable error. Supplying the correct vault password then allows decryption to succeed, satisfying the stem's encrypted-vault constraint.

Why this answer

The error indicates Ansible cannot find the variable 'vault_httpd_port' because the encrypted vault file containing it is not being loaded into the playbook's variable scope. The administrator must first verify that the vault file is properly referenced via include_vars or vars_files in the playbook, and that the correct vault password is supplied (e.g., via --ask-vault-pass or a vault password file). Without loading the vault file, the variable remains undefined regardless of encryption password changes.

Exam trap

EX294 often tests the misconception that simply re-encrypting or changing the vault password resolves variable loading issues, when the real problem is that the vault file is not referenced in the playbook.

How to eliminate wrong answers

Option A is wrong because re-encrypting the vault file with a different password does not address the missing variable reference or loading mechanism. Option B is wrong because storing the variable unencrypted in group_vars/all.yml defeats the purpose of vault encryption and does not resolve the underlying issue of the vault file not being loaded. Option C is wrong because using --ask-vault-pass with a different password is only relevant if the vault file is already referenced; the primary issue is that the vault file is not being included or referenced in the playbook.

212
Multi-Selecteasy

Which TWO filters can be used to conditionally select elements from a list based on a test? (Select exactly two.)

Select 2 answers
A.map
B.combine
C.reject
D.select
E.flatten
AnswersC, D

The reject filter removes list elements matching the supplied test, returning the remaining items. It performs conditional exclusion rather than selection, which is why it pairs with select as one of the two test-based list filters in Ansible.

Why this answer

In Ansible, the `reject` filter removes elements from a list that match a given condition, effectively selecting only those that do not match. The `select` filter does the opposite: it keeps elements that match the condition. Both are used for conditional selection from a list based on a test, making C and D correct.

Exam trap

The trap here is that candidates may confuse `map` with `select` because both iterate over lists, but `map` transforms elements while `select`/`reject` filter them based on a test.

213
Multi-Selecteasy

Which two statements about Ansible roles are correct? (Select exactly 2.)

Select 2 answers
A.Roles must have a meta/main.yml file.
B.Roles are a type of playbook.
C.Roles can include tasks, handlers, variables, and defaults.
D.Roles cannot be used with include_role.
E.Roles can be installed from Galaxy.
AnswersC, E

A role's directory structure defines separate subdirectories for tasks, handlers, variables and defaults, each loaded automatically during role execution. This satisfies the stem's requirement for a correct structural statement, distinguishing roles from loose playbooks that must declare such content inline.

Why this answer

Option C is correct because an Ansible role is a structured directory layout that can bundle tasks (tasks/main.yml), handlers (handlers/main.yml), variables (vars/main.yml), and defaults (defaults/main.yml) along with files, templates, and meta, allowing reusable automation content. Option E is correct because roles can be installed from Ansible Galaxy using the ansible-galaxy role install command (e.g., ansible-galaxy install geerlingguy.nginx), which fetches roles from Galaxy or a configured requirements file. Option A is not required: meta/main.yml is optional and only needed when declaring role dependencies or Galaxy metadata.

Option B is inaccurate because a role is a reusable content structure invoked by a playbook via roles or include_role/import_role, not itself a playbook. Option D is false because include_role is specifically used to dynamically include roles at runtime.

Exam trap

EX294 often tests the misconception that roles require a meta/main.yml file or that they are a type of playbook, when in fact meta is optional and roles are separate reusable components invoked by playbooks.

214
MCQeasy

In an Ansible playbook, the 'strategy' parameter is set to 'free'. What behavior does this strategy produce?

A.Playbook runs tasks on hosts in batches of 1.
B.Strategy is deprecated and replaced by 'linear'.
C.All hosts run the same task at the same time, then move to the next task.
D.Each host runs through the playbook independently of other hosts.
AnswerD

The free strategy lets each host proceed through the play at its own pace without waiting at task barriers for other hosts, so hosts complete independently. This differs from linear, which synchronises hosts at each task.

Why this answer

The 'free' strategy in Ansible allows each host to run through the playbook independently, without waiting for other hosts to finish the current task. This means a faster host can proceed to subsequent tasks while slower hosts are still working on earlier tasks, maximizing parallelism and reducing overall execution time.

Exam trap

The trap here is confusing the 'free' strategy with the 'serial' parameter or the default 'linear' strategy, leading candidates to incorrectly associate batching or synchronized task execution with 'free'.

How to eliminate wrong answers

Option A is wrong because the 'free' strategy does not run tasks in batches of 1; that behavior is achieved by setting the 'serial' parameter to 1, which controls batch size, not the strategy. Option B is wrong because the 'free' strategy is not deprecated and is still fully supported; the 'linear' strategy is the default, not a replacement for 'free'. Option C is wrong because it describes the 'linear' strategy, where all hosts execute the same task simultaneously before moving to the next task; the 'free' strategy allows hosts to proceed independently.

215
MCQmedium

A playbook registers the output of the `package_facts` module and must build a list containing only the version strings of installed packages whose name begins with 'httpd'. Which filter pipeline extracts those versions?

A.ansible_facts.packages | dict2items | selectattr('key', 'match', '^httpd') | map(attribute='value') | flatten | map(attribute='version') | list
B.ansible_facts.packages | dict2items | selectattr('key', 'match', '^httpd') | map(attribute='value.version') | list
C.ansible_facts.packages | selectattr('name', 'match', '^httpd') | map(attribute='version') | list
D.ansible_facts.packages | dict2items | selectattr('key', 'match', '^httpd') | map(attribute='value') | list
AnswerA

This pipeline converts the package mapping to key/value pairs, keeps only keys matching the 'httpd' prefix with a regular expression, extracts each matching value (a list of records), flattens the nested lists, then maps to the `version` attribute of each record. The final list contains only version strings for the matching packages, which is precisely what the scenario demands.

Why this answer

Package facts are stored as a dictionary keyed by package name, with each value being a list of records. Extracting versions therefore requires converting the mapping to items, filtering keys, unwrapping the value lists with flatten, and then mapping the version attribute. Pipelines that skip the flatten step or that treat the dictionary as a list of objects cannot reach the nested version field.

Exam trap

The trap here is forgetting that each package entry is a list of records, so mapping directly to a version attribute fails without flattening first.

216
MCQmedium

An Ansible automation team is designing a playbook to manage network devices. They need to ensure that the playbook can handle transient network failures by retrying failed tasks a specific number of times with a delay between retries. Which approach should they use?

A.Set `max_fail_percentage` in the play to 0 and use `ignore_errors: yes` with a rescue block.
B.Use the `throttle` keyword to limit concurrent tasks and rely on idempotency.
C.Set `serial: 1` on the play to ensure only one host is processed at a time and rely on idempotency.
D.Use the `until` loop with `retries` and `delay` parameters on the task.
AnswerD

The until loop repeats a task until its condition succeeds, with retries setting the maximum attempts and delay setting the pause between them. This directly handles transient network failures by retrying failed tasks as specified.

Why this answer

The `until` loop with `retries` and `delay` parameters is the correct approach because it allows a task to be retried a specified number of times with a configurable pause between attempts, directly addressing transient network failures. This is a built-in Ansible feature for handling intermittent issues without additional error-handling constructs.

Exam trap

The trap here is that candidates confuse concurrency controls (`serial`, `throttle`) or error-handling directives (`ignore_errors`, `max_fail_percentage`) with the retry mechanism, which is specifically implemented via the `until` loop with `retries` and `delay` parameters.

How to eliminate wrong answers

Option A is wrong because `max_fail_percentage` controls the percentage of hosts that can fail before the play aborts, not task retries; combining `ignore_errors: yes` with a rescue block would suppress errors but not implement retry logic. Option B is wrong because the `throttle` keyword limits the number of concurrent task executions, which is unrelated to retrying failed tasks. Option C is wrong because `serial: 1` processes hosts one at a time to control rolling updates or concurrency, not to retry tasks on failure.

217
MCQhard

A task registers the output of a command that returns a string containing a JSON document in `result.stdout`. You must extract the numeric value at `metrics.cpu.load` and use it as an integer in a subsequent comparison. Which expression correctly parses the string and retrieves the integer value?

A.{{ result.stdout | from_json | json_query('metrics.cpu.load') | int }}
B.{{ result.stdout | json_query('metrics.cpu.load') | from_json | int }}
C.{{ result.stdout | to_json | json_query('metrics.cpu.load') | int }}
D.{{ result.stdout | from_json | map(attribute='metrics.cpu.load') | int }}
AnswerA

`from_json` parses the JSON string into a Python dictionary, `json_query` traverses the nested path `metrics.cpu.load`, and `int` coerces the resulting value to an integer for comparison. This chain matches the scenario where stdout is a JSON string and the target is a nested numeric field.

Why this answer

The correct order is to parse the raw JSON string first with `from_json`, then traverse the nested structure with `json_query`, and finally cast the extracted value with `int`. Reversing or substituting `to_json` breaks the pipeline because it serializes rather than parses. Using `map` is inappropriate for a single dictionary input, and querying before parsing cannot succeed on a raw string.

Exam trap

The trap here is assuming `to_json` and `from_json` are interchangeable, when only `from_json` parses a string into structured data.

218
MCQmedium

An administrator is using ansible-playbook with an inventory file that defines a group 'webservers' and a group 'dbservers'. The administrator wants to run a playbook only against hosts in 'webservers' but exclude any host that is also in 'dbservers'. Which inventory pattern should be used with the --limit option?

A.webservers:&dbservers
B.webservers:dbservers
C.webservers:!dbservers
D.webservers,!dbservers
AnswerC

The pattern 'webservers:!dbservers' selects all hosts in webservers and then excludes any host that is in dbservers. This is the correct syntax for set operations in Ansible inventory patterns. The colon separates the intersection and exclusion, and the exclamation mark denotes exclusion. This pattern will limit execution to the desired hosts.

Why this answer

Ansible inventory patterns support set operations using colons and special characters. To select hosts in one group and exclude those in another, the pattern 'group1:!group2' is used. The exclamation mark indicates exclusion, and the colon separates the two patterns.

This allows precise targeting of hosts for playbook execution.

Exam trap

The trap here is using a comma instead of a colon to separate the group and the exclusion pattern, which is invalid syntax and will not work as intended.

219
MCQeasy

A user wants to use a collection from Automation Hub. Which command downloads and installs the collection to the default collections path?

A.ansible-pull collection install
B.ansible-playbook collection install
C.ansible-collection install
D.ansible-galaxy collection install
AnswerD

ansible-galaxy collection install resolves and downloads the named collection from the configured Automation Hub server, placing it under the default collections path (~/.ansible/collections). It performs both retrieval and installation in one command, satisfying the requirement.

Why this answer

The correct command to download and install a collection from Automation Hub to the default collections path is `ansible-galaxy collection install`. This command uses the `ansible-galaxy` utility, which is the standard tool for managing Ansible roles and collections, and the `collection install` subcommand specifically handles collection installation from configured sources like Automation Hub or Ansible Galaxy.

Exam trap

The trap here is that candidates confuse the `ansible-galaxy` command with other Ansible executables like `ansible-playbook` or `ansible-pull`, or assume a non-existent command like `ansible-collection` exists, because the exam tests precise knowledge of which tool handles collection management.

How to eliminate wrong answers

Option A is wrong because `ansible-pull` is used for pulling and applying playbooks from a repository in a reverse mode, not for installing collections; it does not have a `collection install` subcommand. Option B is wrong because `ansible-playbook` is used to execute playbooks, not to manage collections; it has no `collection install` subcommand. Option C is wrong because `ansible-collection` is not a valid Ansible command; the correct utility is `ansible-galaxy`.

220
Matchingmedium

Match each Ansible module to its primary function.

Drag a concept onto its matching description — or click a concept then click the description.

Concepts
Matches

Manage packages via YUM

Copy files to remote hosts

Manage system services

Deploy Jinja2 templates

Manage user accounts

Why these pairings

The yum module manages packages, service manages system services, and copy transfers files from local to remote. Common confusions include swapping definitions or using the wrong direction for file transfers.

221
MCQhard

A playbook uses an Ansible collection that includes a custom module. The module's documentation is missing. What is the best way to locate the module's source code?

A.Run ansible-doc <module name>.
B.Search the Ansible Galaxy website.
C.Navigate to the collection's plugin directory on the control node.
D.Look in the roles directory.
AnswerC

Ansible installs collections under the control node's collection path, with each module stored as a Python file inside the collection's plugins/modules directory. Reading that file reveals the actual implementation, which is the only reliable source when the module's generated documentation is absent.

Why this answer

Ansible collections store custom modules in the 'plugins/modules' directory within the collection's installation path on the control node. Navigating to that directory allows you to view the module's source code directly, which is the most reliable way to locate it when documentation is missing.

Exam trap

EX294 often tests the assumption that ansible-doc always works, even when documentation is missing, leading candidates to choose that option instead of locating the source file.

How to eliminate wrong answers

Option A is wrong because ansible-doc relies on documentation strings within the module; if documentation is missing, ansible-doc may not display useful information or may fail. Option B is wrong because searching Ansible Galaxy might find the collection, but it does not guarantee access to the specific module's source code, especially if the collection is private or not published. Option D is wrong because the roles directory contains roles, not collection modules; custom modules from collections are not stored there.

222
MCQeasy

An administrator wants to reuse a set of tasks across multiple playbooks. Which Ansible approach is most appropriate?

A.Encrypting the tasks with Ansible Vault.
B.Creating a role with tasks in tasks/main.yml.
C.Using ansible-doc to document the tasks.
D.Writing a custom module in Python.
AnswerB

A role packages tasks in tasks/main.yml so any playbook can invoke the same reusable unit through the roles keyword, avoiding duplicated task definitions. This satisfies the requirement to reuse one task set across multiple playbooks without copying content.

Why this answer

Roles are the standard Ansible mechanism for packaging and reusing tasks, variables, handlers, and other automation content across multiple playbooks. By placing tasks in a role's `tasks/main.yml`, the administrator can reference that role in any playbook using the `roles:` directive, enabling clean, modular reuse without duplication.

Exam trap

The trap here is that candidates may confuse Ansible Vault's encryption capability with code reuse, or think that writing a custom module is a simpler way to bundle tasks, when in fact roles are the explicit, built-in solution for task reuse in Ansible.

How to eliminate wrong answers

Option A is wrong because Ansible Vault encrypts sensitive data (e.g., passwords, keys) but does not provide a mechanism to reuse tasks across playbooks; it is a security feature, not a code reuse feature. Option C is wrong because `ansible-doc` is a command-line tool that displays documentation for installed modules and plugins; it does not enable task reuse or packaging. Option D is wrong because writing a custom Python module extends Ansible's capabilities with new, atomic actions, but it is not the intended or most appropriate way to reuse a set of tasks; roles are designed specifically for that purpose.

223
MCQeasy

An automation team wants to securely store SSH private keys for use in playbooks. Which Ansible feature should they use?

A.Ansible Collections
B.Ansible Vault
C.Ansible Fact Cache
D.Ansible Galaxy
AnswerB

Ansible Vault encrypts sensitive files and variables at rest using AES-256, so SSH private keys can be stored in encrypted form and decrypted at runtime with the vault password. This satisfies the requirement for secure storage rather than plaintext in the repository.

Why this answer

Ansible Vault is the correct feature for securely storing SSH private keys because it encrypts sensitive data at rest using AES-256, allowing keys to be decrypted at runtime when a vault password or key is provided. This enables playbooks to reference encrypted SSH key files without exposing plaintext credentials in version control or on disk.

Exam trap

The trap here is that candidates might confuse Ansible Vault with Ansible Galaxy, assuming Galaxy provides security features because it is a central repository, but Galaxy only distributes content and has no encryption or secure storage capabilities.

How to eliminate wrong answers

Option A is wrong because Ansible Collections are a distribution format for packaging and sharing automation content (roles, modules, plugins), not a mechanism for encrypting or securing sensitive data like SSH keys. Option C is wrong because Ansible Fact Cache stores gathered system facts (e.g., IP addresses, OS version) in a backend like Redis or Memcached to improve performance, and it does not provide encryption or secure storage for secrets. Option D is wrong because Ansible Galaxy is a public hub for sharing Ansible content (roles, collections) and a command-line tool for downloading them, with no built-in encryption or secure storage capability for SSH private keys.

224
MCQhard

An automation controller administrator needs to ensure that a vault password used by multiple job templates is rotated periodically without editing each job template. Which approach is most efficient and secure?

A.Store the vault password in a file on the automation controller and reference it from each job template's extra variables.
B.Use a separate vault credential for each job template so that rotation can be done independently.
C.Create a single vault credential, attach it to all relevant job templates, and update the credential when rotating the password.
D.Embed the vault password in the playbook repository and use a source control webhook to trigger updates.
AnswerC

A single vault credential can be shared across multiple job templates. When the password is rotated, updating the credential automatically propagates the new password to all attached job templates, avoiding individual edits. This centralizes management and reduces the risk of missing a template.

Why this answer

A shared vault credential in automation controller allows multiple job templates to use the same secret. Rotating the password only requires updating the credential, which automatically applies to all attached job templates. This is both efficient and secure, as the credential is encrypted and access-controlled.

Exam trap

The trap here is thinking that separate credentials per job template or storing the password in the repository is necessary, when a shared credential provides centralized rotation.

225
Multi-Selecteasy

Which TWO elements can be used to include external task files in a playbook?

Select 2 answers
A.import_tasks
B.include_tasks
C.include_vars
D.add_host
E.include_role
AnswersA, B

import_tasks is processed statically at playbook parse time, splicing the external task file into the play before execution. This makes it one of the two valid elements for including external task files in a playbook.

Why this answer

Both A. import_tasks and B. include_tasks are the two Ansible directives designed to bring external task files into a playbook, which is exactly what the scenario asks for. import_tasks is processed statically at playbook parse time, so the referenced YAML file's tasks are inserted before execution begins, making it suitable for fixed, always-included task lists. include_tasks is processed dynamically at runtime, allowing the included file to be chosen conditionally or looped over, which is useful when the task file depends on variables or facts. The other options do not belong: include_vars loads variables from an external file rather than tasks, add_host dynamically adds a host to the in-memory inventory, and include_role imports a role (which may contain tasks) but is not the directive for including a standalone external task file.

Exam trap

The trap here is that candidates often confuse `include_tasks` and `import_tasks` with variable-loading or inventory-modifying modules, or they mistakenly think `include_role` can be used to include arbitrary task files instead of entire roles.

Page 2

Page 3 of 6

Page 4

All pages