Courseiva

Red Hat Certified Engineer EX294 (EX294) — Questions 1–75

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

Page 1 of 6

Page 2
1
MCQmedium

Consider the task: `- debug: msg={{ item | upper }}` with `loop: "{{ ['a','b'] }}"`. What will be the output?

A.An error because upper expects a string, not a loop variable.
B.Two debug messages: 'a' and 'b'
C.Two debug messages: 'A' and 'B'
D.One debug message with the list ['A','B']
AnswerC

The `upper` filter transforms each string to uppercase, and `loop` iterates the list, producing one debug message per item. This satisfies the stem's requirement that both list elements be processed individually, yielding 'A' then 'B' as separate task iterations rather than a single combined output.

Why this answer

The `upper` filter in Ansible converts each string item in the loop to uppercase. The `loop` directive iterates over the list `['a','b']`, and for each iteration, the `{{ item | upper }}` expression applies the `upper` filter to the current item, resulting in `'A'` and `'B'`. The `debug` module then prints each transformed value as a separate message.

Exam trap

The trap here is that candidates may overlook the fact that the `upper` filter is applied to each item individually within the loop, leading them to think the output remains lowercase (Option B) or that the filter fails on a loop variable (Option A).

How to eliminate wrong answers

Option A is wrong because the `upper` filter in Ansible is designed to work with strings, and `item` in a loop is a scalar value (a string in this case), not a list; the filter correctly converts each string to uppercase. Option B is wrong because it ignores the effect of the `upper` filter, which transforms the items to uppercase before output. Option D is wrong because the `loop` directive causes the `debug` module to execute once per item, producing two separate messages, not a single message containing a list.

2
MCQmedium

An administrator is running `ansible-playbook -i inventories/prod site.yml` against the `prod` inventory, which contains a group `web` and a group `db`. The play is defined with `hosts: web:&db`. Which hosts will the play target?

A.All hosts that are in both the `web` group and the `db` group
B.All hosts in the inventory except those in the `web` and `db` groups
C.Only the first host listed in the `web` group that also appears in `db`
D.All hosts that are in the `web` group or in the `db` group
AnswerA

In an Ansible host pattern, the `&` separator means intersection (logical AND). Writing `web:&db` selects only hosts that appear in the `web` group and also in the `db` group. This is the correct behavior: the pattern applies both group filters and targets the overlap, which is exactly what the play declares.

Why this answer

The `:&` syntax in a host pattern performs set intersection, so the play runs only against hosts that are members of both the `web` and `db` groups. The `:` alone would create a union, and a leading `!` would exclude. Because the play uses `web:&db`, the correct target set is the overlap of the two groups.

Exam trap

The trap here is confusing the colon union operator with the ampersand intersection operator, which leads to selecting every host in either group instead of the shared members.

3
MCQmedium

An administrator runs a playbook with the serial keyword set to 2. The playbook targets 6 hosts and contains a task that runs a rolling update. During execution, the administrator notices that the task is executed on only 2 hosts at a time, but the playbook waits for all tasks to complete on those 2 hosts before moving to the next 2. What is the primary effect of the serial keyword in this scenario?

A.It limits the number of hosts that execute each task concurrently, processing hosts in batches.
B.It ensures that only 2 tasks are executed at a time on each host.
C.It sets the maximum number of forks used for parallel task execution across all hosts.
D.It restricts the play to run on only 2 hosts total, ignoring the rest.
AnswerA

The serial keyword defines the number of hosts to manage in each batch. With serial: 2, Ansible runs the entire play on 2 hosts, then the next 2, and so on, ensuring tasks complete on one batch before proceeding to the next. This is correct because it controls batch size and provides rolling updates.

Why this answer

The serial keyword controls how many hosts are included in each batch of a play. When set to 2, Ansible completes the entire play on the first 2 hosts before moving to the next 2. This provides rolling updates and limits the impact of failures.

It does not affect parallelism within a batch or limit the total number of hosts.

Exam trap

The trap here is confusing serial with forks or throttle, which control parallelism and task concurrency rather than host batching.

4
MCQhard

You are designing a rolling update playbook for a 20-node application cluster. The application requires that no more than 25% of the nodes be unavailable at any time. You want Ansible to automatically pause the play if the failure rate within a batch exceeds a threshold, so that you can investigate before continuing. Which play-level keyword should you use?

A.`serial`
B.`any_errors_fatal`
C.`ignore_errors`
D.`max_fail_percentage`
AnswerD

`max_fail_percentage` is a play-level keyword that aborts the play if the percentage of hosts that fail in a batch exceeds the specified value. In this scenario, setting it to a value that corresponds to the allowed unavailability (e.g., 25) will cause Ansible to stop the rolling update when too many hosts fail, allowing you to investigate before more batches are affected.

Why this answer

The `max_fail_percentage` keyword is designed to abort a play when the failure rate within a batch exceeds a given percentage. By setting it to 25, Ansible will stop the rolling update if more than 25% of the hosts in a batch fail, matching the application's availability requirement. This provides an automatic safety check during the update.

Exam trap

The trap here is confusing `max_fail_percentage` with `any_errors_fatal` or `serial`. `max_fail_percentage` is the only keyword that lets you define a percentage-based failure threshold per batch, while `serial` only controls batch size and `any_errors_fatal` aborts on any single error.

5
Multi-Selectmedium

You must store a database password that a playbook will use on managed nodes. Your security policy forbids clear-text secrets in the repository and requires that the secret remain usable with `ansible-playbook --vault-password-file /home/devops/.vault_pass`. Which two actions satisfy the policy? (Choose two.)

Select 2 answers
A.Reference the password with `lookup('env', 'DB_PASSWORD')` so it is read from the environment at run time.
B.Create the secret with `ansible-vault encrypt_string --vault-password-file /home/devops/.vault_pass --name db_password` and paste the resulting block into the vars file.
C.Commit the password in a vars file and add the file path to a .gitignore entry in the repository root.
D.Store the password in a YAML file, run `ansible-vault encrypt db_vars.yml`, and reference it from the playbook with `vars_files`.
E.Define the password as an extra variable with `-e db_password=...` in the playbook invocation.
AnswersB, D

encrypt_string produces an inline encrypted variable that can be embedded directly in a YAML vars file while leaving the rest of the file readable in version control. Because it is encrypted with the same vault password, the playbook decrypts it transparently when run with the matching --vault-password-file, satisfying both the no-clear-text rule and the operational requirement.

Why this answer

Both accepted approaches produce artifacts encrypted with the same vault password that the required --vault-password-file supplies. Inline encryption with encrypt_string hides a single value inside an otherwise readable vars file, while encrypting an entire vars file protects a group of secrets referenced through vars_files. Each keeps clear-text secrets out of the repository while remaining fully usable at run time.

Exam trap

The trap here is treating .gitignore or environment-variable lookups as secret protection, when both leave the value readable in clear text.

6
MCQeasy

An administrator creates a group named `webservers` in an INI-style inventory and a group named `webservers` in a YAML inventory under the same inventory directory. Both groups define different hosts. What is the result when Ansible loads the inventory?

A.Ansible raises a duplicate group error and refuses to load either inventory
B.Only the YAML definition is used because YAML takes precedence over INI
C.The two group definitions are merged, and the group contains the union of hosts from both files
D.The group from the first parsed file wins and the second group definition is ignored
AnswerC

When multiple inventory sources define the same group name, Ansible merges them and the group contains all hosts from every definition. Group membership is additive across sources, so the `webservers` group ends up with the combined host list. This is the expected behavior when an inventory directory contains both INI and YAML files.

Why this answer

Ansible merges group membership across all loaded inventory sources. When the same group name appears in an INI file and a YAML file, the group ends up containing the union of hosts from both definitions. There is no duplicate error and no format-based precedence for group membership.

Exam trap

The trap here is assuming that duplicate group names across inventory files cause an error or that one file format overrides another, when membership is actually merged.

7
MCQeasy

An administrator is preparing to install Red Hat Ansible Automation Platform 2.5 using the containerized installer on a RHEL 9 host. The installer bundle has been extracted, and the administrator must provide the subscription manifest and other settings before running the setup playbook. Which file should the administrator edit to supply these installation parameters?

A.The group_vars/all.yml file created automatically in /etc/awx after the bundle is extracted.
B.The inventory file in the installer's setup directory, which holds host and platform configuration variables.
C.The ansible-navigator.yml file in the user's home directory, specifying execution environment options.
D.The /etc/ansible/ansible.cfg file on the target host, adding an [aap] section with the install variables.
AnswerB

The containerized installer uses an INI-style inventory file in the setup directory to define the target hosts and platform variables such as admin password, registry credentials, and the path to the Red Hat subscription manifest. Editing this file supplies the parameters the setup playbook consumes during installation.

Why this answer

The containerized installer is driven by an inventory file in its setup directory that holds both the target host definitions and the platform variables, including the subscription manifest location. Editing this file is the supported way to supply installation parameters before running the setup playbook.

Exam trap

The trap here is confusing the installer's inventory file with general Ansible configuration files such as ansible.cfg or ansible-navigator.yml, which do not carry platform install variables.

8
MCQeasy

Based on the exhibit, which file is generated by `ansible-builder` to support the build?

A.requirements.yml
B.execution-environment.yml
C.Containerfile
D.ansible.cfg
AnswerC

`ansible-builder` generates a Containerfile (the Podman/Buildah equivalent of a Dockerfile) that defines the execution environment image build. It satisfies the stem's requirement by producing this build recipe from `execution-environment.yml`, which `ansible-builder build` then passes to Podman or Buildah to assemble the image.

Why this answer

The `ansible-builder` tool uses a definition file (typically `execution-environment.yml`) to construct a container image. During the build process, it generates a `Containerfile` (or `Dockerfile`) that contains the exact instructions for building the container image, such as base image selection, package installation, and collection inclusion. This generated file is the actual artifact that the container runtime (e.g., Podman or Docker) uses to create the execution environment image.

Exam trap

Red Hat often tests the distinction between the input definition file (`execution-environment.yml`) and the output build artifact (`Containerfile`), causing candidates to mistakenly select the input file as the generated output.

How to eliminate wrong answers

Option A is wrong because `requirements.yml` is an input file used to specify Ansible collections or Python dependencies for an execution environment, not a file generated by `ansible-builder` during the build process. Option B is wrong because `execution-environment.yml` is the definition file that you provide to `ansible-builder` as input, describing the base image, dependencies, and other settings; it is not generated by the tool. Option D is wrong because `ansible.cfg` is a configuration file for Ansible itself, controlling settings like inventory, roles path, and connection parameters, and it has no direct role in the `ansible-builder` build process.

9
MCQmedium

A role contains a handler. The playbook includes the role and also defines a task that notifies the same handler. When the playbook runs, the handler executes only once. Which of the following best explains this behavior?

A.the handler was already triggered by the role and is skipped for the play task
B.handlers are deduplicated by name; multiple notifications trigger the handler only once per play
C.the role's handler uses 'listen' which overrides notifications
D.the playbook's task notifies a different handler with the same name
AnswerB

Handlers are deduplicated by name, so notifications from both the role and the playbook task resolve to the same handler. It runs once per play after all notifying tasks complete, regardless of how many tasks notified it.

Why this answer

Ansible handlers are deduplicated by name within a play. When a handler is notified multiple times—whether from a role or a playbook task—it runs only once at the end of the play, after all tasks have completed. This prevents redundant executions and is a core design feature of Ansible's handler system.

Exam trap

The trap here is that candidates may think handlers are executed immediately upon notification or that multiple notifications cause multiple executions, but Ansible deduplicates by handler name and runs them only once per play, regardless of the number of notifications.

How to eliminate wrong answers

Option A is wrong because handlers are not 'skipped' after being triggered; they are simply queued and executed once regardless of how many times they are notified. Option C is wrong because the 'listen' directive allows multiple handlers to be triggered by a single notification, but it does not override or deduplicate notifications; deduplication is inherent to handler names. Option D is wrong because if the playbook's task notifies a different handler with the same name, it would be the same handler object (since names are unique within a play), and the behavior would still be deduplication, not a separate handler.

10
MCQhard

An administrator is designing a role that needs to execute a set of tasks conditionally based on whether a package is installed. Which approach is best practice?

A.Use the stat module to check package file existence
B.Use the command module to check package status
C.Use ansible_facts.packages
D.Use the package_facts module
AnswerD

package_facts gathers installed package information into the package_facts variable, letting subsequent tasks evaluate conditions against actual system state. This avoids shelling out to rpm or dpkg and keeps the check idempotent and portable across distributions.

Why this answer

The `package_facts` module is the best practice for gathering package installation status in Ansible. It populates the `ansible_facts.packages` variable with structured data about installed packages, allowing you to conditionally execute tasks using `when` statements without relying on external commands or file checks. This approach is idempotent, efficient, and aligns with Ansible's declarative philosophy.

Exam trap

The trap here is that candidates confuse `ansible_facts.packages` (which is a variable that must be populated by `package_facts`) with a pre-existing fact, leading them to choose option C without realizing the module is required first.

How to eliminate wrong answers

Option A is wrong because the `stat` module checks file existence, not package installation status; a package may be installed without its files in a predictable location, or files may exist from a different source. Option B is wrong because the `command` module is not idempotent and requires parsing command output (e.g., `rpm -q`), which is fragile, platform-specific, and violates Ansible's best practices of using dedicated modules. Option C is wrong because `ansible_facts.packages` is not automatically populated; it is only available after running the `package_facts` module or if the `gather_subset` includes `packages`, which is not the default and not a direct method to check package status.

11
MCQhard

A company manages its infrastructure using Ansible Tower. There are two teams: Team Alpha manages web servers in the 'webservers' group, and Team Beta manages database servers in the 'dbservers' group. Both teams need to use the same SSH credential to connect to their respective servers. The credential is stored in Tower as 'shared_ssh_key'. Team Alpha reports that they can launch jobs against the 'webservers' group, but Team Beta gets an error when trying to launch jobs against the 'dbservers' group: 'You do not have permission to use this credential.' Both teams are members of the same organization. The inventory is a single inventory source with separate groups. The credential has been assigned to the organization. What is the most likely cause of Team Beta's issue, and what is the correct solution?

A.Grant Team Beta the 'Use' role on the credential 'shared_ssh_key'.
B.Create a new credential with the same SSH key and assign it to Team Beta.
C.Assign the credential to the dbservers group in the inventory.
D.Move the credential from the organization to the project level.
AnswerA

Tower roles are scoped per object, not inherited from organisation membership. Team Alpha holds a Use role on the credential; Team Beta does not, so job launch is refused. Granting Team Beta the Use role on 'shared_ssh_key' satisfies the credential-permission constraint.

Why this answer

In Ansible Tower, credentials are assigned to an organization, but users or teams must be explicitly granted the 'Use' role on a credential to be able to use it in a job template. Team Alpha can use the credential because they likely have the 'Use' role, while Team Beta does not. Granting Team Beta the 'Use' role on 'shared_ssh_key' resolves the permission error.

Exam trap

The trap here is that candidates assume assigning a credential to an organization automatically grants all members the right to use it, but Tower requires explicit 'Use' role assignment for each team or user.

How to eliminate wrong answers

Option B is wrong because creating a duplicate credential violates the principle of least privilege and adds unnecessary management overhead; the existing credential can be shared by granting the 'Use' role. Option C is wrong because credentials are not assigned to inventory groups in Tower; they are assigned to organizations, projects, or job templates, and the error is about credential permissions, not inventory group assignments. Option D is wrong because moving the credential to the project level does not change the fact that Team Beta lacks the 'Use' role; the credential would still require explicit role assignment for the team to use it.

12
Multi-Selecteasy

Which TWO statements are true regarding the deployment of Ansible Automation Platform in a highly available configuration?

Select 2 answers
A.The automation hub requires an external PostgreSQL database to store collections and execution environments.
B.Execution nodes must have direct network access to the automation controller database.
C.The automation controller requires a PostgreSQL database that must be configured with replication for high availability.
D.The automation controller can use an embedded SQLite database for production deployments.
E.The automation mesh component is used to provide resilient, fault-tolerant execution across multiple nodes.
AnswersC, E

The automation controller persists its configuration, jobs and credentials in PostgreSQL, so a highly available deployment requires that database to be replicated across nodes; without database replication, a controller node failure would lose or block access to this shared state.

Why this answer

Option C is correct because in a highly available Ansible Automation Platform deployment, the automation controller (the control plane) relies on an external PostgreSQL database, and HA is achieved by configuring that PostgreSQL instance with replication (e.g., streaming replication or a supported HA topology) so the controller can fail over without losing job data. Option E is correct because the automation mesh (based on receptor) is the component that provides resilient, fault-tolerant execution by routing jobs across hop nodes and execution nodes, allowing execution to continue even if individual nodes become unavailable. Option A is incorrect because automation hub's PostgreSQL database is not strictly required to be external for HA in the way described; hub can be deployed with its own supported database configuration, and the statement overstates the requirement.

Option B is incorrect because execution nodes do not need direct network access to the automation controller's database; they communicate with the controller through the mesh/receptor network, not by connecting to PostgreSQL directly. Option D is incorrect because SQLite is not supported for production automation controller deployments; PostgreSQL is required.

Exam trap

The trap here is that candidates often confuse the storage backend for automation hub (thinking it requires an external database for content storage) or assume execution nodes need direct database access, when in reality the architecture separates database access to the controller and uses API-based communication for execution nodes.

13
MCQmedium

An administrator needs to combine two dictionaries, `base_config` and `user_config`, where keys in `user_config` should override keys in `base_config`, and nested dictionaries should be merged recursively. Which filter syntax achieves this?

A.{{ base_config | combine(user_config, recursive=True) }}
B.{{ base_config | combine(user_config, deep=True) }}
C.{{ base_config | combine(user_config) }}
D.{{ base_config | combine(user_config, list_merge='replace') }}
AnswerA

The recursive=True parameter merges nested dictionaries key-by-key rather than replacing the whole sub-dictionary, while user_config values take precedence over base_config at each level. Without it, combine would overwrite entire nested blocks, losing base_config keys the stem requires to be preserved.

Why this answer

The `combine` filter in Ansible with `recursive=True` merges two dictionaries, with `user_config` overriding `base_config`, and recursively merges nested dictionaries. This matches the requirement exactly, as `recursive=True` ensures that nested structures are combined rather than replaced outright.

Exam trap

The trap here is that candidates often confuse `recursive=True` with `deep=True` (which does not exist) or assume that the default `combine` behavior (shallow merge) is sufficient for nested dictionaries, leading them to pick option B or C.

How to eliminate wrong answers

Option B is wrong because `deep=True` is not a valid parameter for the `combine` filter; the correct parameter for recursive merging is `recursive=True`. Option C is wrong because using `combine` without any parameters performs a shallow merge, where nested dictionaries are replaced entirely by the `user_config` values, not merged recursively. Option D is wrong because `list_merge='replace'` controls how lists are merged (replacing the base list with the user list), but it does not enable recursive merging of nested dictionaries, so nested dicts would still be replaced.

14
MCQmedium

An administrator is deploying a redundant Ansible Automation Platform 2.4 cluster with two controller nodes and one database node. They want to ensure that the automation controller remains available if one controller node fails. Which configuration should they implement?

A.Deploy a single controller node with a hot standby that is manually activated during an outage.
B.Install the automation controller on both nodes and use a shared NFS mount for the project directory.
C.Configure the two controller nodes behind a load balancer that performs health checks on port 443.
D.Set up database replication between the two controller nodes and configure automatic failover.
AnswerC

In a redundant AAP cluster, controller nodes are placed behind a load balancer that distributes traffic and monitors node health. If one node fails, the load balancer routes traffic to the remaining healthy node, maintaining availability. This is the standard high-availability configuration for the automation controller component.

Why this answer

High availability for the automation controller in AAP is achieved by deploying multiple controller nodes behind a load balancer that performs health checks. This ensures that if one node becomes unavailable, traffic is automatically routed to the remaining healthy node, minimizing downtime. Other options do not provide automatic failover for the controller service.

Exam trap

The trap here is confusing database high availability with controller node high availability; they are separate components with different redundancy strategies.

15
Multi-Selecthard

Which THREE of the following are best practices for managing credentials in Ansible Automation Controller?

Select 3 answers
A.Avoid using external secret management systems; keep all secrets in Automation Controller
B.Share the same credential across multiple organizations for simplicity
C.Restrict credential 'Use' permissions to specific users or teams
D.Use custom credential types to store secrets for third-party APIs
E.Use Vault credentials to store and encrypt sensitive variables in playbooks
AnswersC, D, E

This ensures only authorized users can use the credential.

Why this answer

Ansible Automation Controller's Role-Based Access Control (RBAC) allows administrators to assign granular 'Use' permissions to specific users or teams, ensuring that only authorized entities can leverage a credential for job runs. This prevents unauthorized access to sensitive secrets and aligns with the principle of least privilege, which is a core security best practice in automation environments.

Exam trap

The trap here is that candidates may think storing all secrets inside Automation Controller is safer than using an external vault, but Red Hat specifically recommends integrating with external secret managers for centralized control and rotation, making Option A a common misconception.

16
Multi-Selectmedium

A playbook must normalize a list of dictionaries read from a YAML file. Each dictionary has keys 'name' and 'ports', where 'ports' is a comma-separated string such as '80,443'. You need to produce a new list where each dictionary has the same 'name' but 'ports' is a list of integers. Which TWO filter usages are required to accomplish this transformation? (Choose two.)

Select 2 answers
A.select('match', '^[0-9]+$') applied to the tokens to filter valid ports.
B.json_query('ports') applied to each dictionary to extract the ports field as a list.
C.map('int') applied to the resulting token list to convert each string to an integer.
D.combine() applied to the dictionaries to merge the new ports list into each entry.
E.split(',') applied to the ports string to produce a list of string tokens.
AnswersC, E

After splitting, the tokens are still strings. The map filter applies the int filter to every element, converting each token into an integer. This produces the required list of numeric ports. Combining map with int is the idiomatic way to transform all elements of a list without writing an explicit loop in the playbook.

Why this answer

Converting a comma-separated string into a list of integers requires two distinct operations. Splitting on the comma produces string tokens, and mapping the int filter over those tokens converts each to a number. Together they yield the desired list of integer ports, which can then be assembled into each dictionary entry, satisfying the normalization requirement without manual iteration.

Exam trap

The trap here is thinking a single filter such as json_query or combine can both split and convert the port string.

17
MCQeasy

An Ansible playbook is designed to run on a group of database servers. The administrator wants to ensure that a task runs only on the primary database server, which is defined in the inventory with a variable 'primary: true'. Which conditional should be used?

A.ignore_errors: yes
B.when: primary
C.run_once: true
D.delegate_to: "{{ primary }}"
AnswerB

Using `when: primary` evaluates the host variable directly as a boolean condition, so the task executes only where the inventory sets `primary: true`. This satisfies the stem's constraint of restricting execution to the primary database server, since Ansible treats the variable's truthiness as the conditional test without requiring an explicit comparison.

Why this answer

The `when` conditional in Ansible evaluates a Jinja2 expression to determine whether a task should execute. By using `when: primary`, the task will run only on hosts where the inventory variable `primary` is defined and evaluates to `true` (a truthy value). This directly meets the requirement to target the primary database server.

Exam trap

The trap here is that candidates confuse `run_once: true` with a conditional that selects a specific host, not realizing `run_once` merely limits execution to a single arbitrary host in the group, not the one defined by a variable like `primary: true`.

How to eliminate wrong answers

Option A is wrong because `ignore_errors: yes` does not control task execution based on a condition; it merely continues playbook execution if the task fails, which is irrelevant to targeting a specific host. Option C is wrong because `run_once: true` ensures a task runs only once across the entire batch of hosts (typically on the first host in the group), but it does not select a specific host based on a variable like `primary: true`; it could run on any host, not necessarily the primary. Option D is wrong because `delegate_to: "{{ primary }}"` attempts to delegate the task to a host named by the variable `primary`, but this is not a conditional; it changes the target host for execution and would fail if `primary` is not a valid hostname or group, and it does not evaluate a boolean variable.

18
MCQmedium

During a rolling update using an Ansible playbook with serial: 2, one host in the first batch becomes unreachable. The playbook fails with an unreachable host error. How should the administrator proceed to complete the update on the remaining hosts while excluding the problematic host?

A.Use 'ansible-playbook playbook.yml --forks 1' to slow down the update.
B.Use 'ansible-playbook playbook.yml --limit all:!hostname' to exclude the unreachable host.
C.Add 'any_errors_fatal: false' to the playbook and rerun.
D.Rerun the playbook with the same command; it will skip the unreachable host automatically.
AnswerB

The `--limit all:!hostname` pattern applies an inventory exclusion, so Ansible targets every host except the unreachable one. This satisfies the requirement to continue the rolling update on remaining hosts while excluding the problematic host, without editing the playbook's serial setting or inventory file.

Why this answer

The `--limit` flag with the pattern `all:!hostname` uses Ansible's inventory host pattern syntax to exclude a specific host from the playbook run. This allows the administrator to rerun the playbook against all hosts except the unreachable one, completing the rolling update without re-attempting the failed host. The `serial: 2` setting is irrelevant once the host is excluded, as the playbook will only target the remaining reachable hosts.

Exam trap

The trap here is that candidates assume Ansible automatically retries or skips unreachable hosts on subsequent runs, when in fact it will fail again unless the host is explicitly excluded using `--limit` or the connectivity issue is resolved.

How to eliminate wrong answers

Option A is wrong because `--forks 1` reduces the number of parallel connections to 1, which slows down execution but does not exclude the unreachable host; the playbook will still fail when it attempts to connect to that host. Option C is wrong because `any_errors_fatal: false` (the default) does not prevent failure from an unreachable host; unreachable hosts cause a fatal error regardless of this setting, and the playbook will still abort. Option D is wrong because Ansible does not automatically skip unreachable hosts on a rerun; the playbook will fail again on the same host unless it is explicitly excluded or the connectivity issue is resolved.

19
Multi-Selectmedium

An administrator needs to store sensitive credentials for a playbook that will be run from a control node. The credentials include an SSH password and a sudo password. The administrator wants to keep these encrypted at rest and avoid hardcoding them in the playbook. Which TWO methods are valid for providing these credentials securely? (Choose two.)

Select 2 answers
A.Define the passwords as extra variables using the -e option on the command line, like -e "ansible_password=secret".
B.Set the passwords as environment variables on the control node and reference them with lookup('env', 'SSH_PASSWORD') in the playbook.
C.Use the ansible.builtin.debug module to print the passwords from a vault-encrypted file, then manually copy them into the playbook.
D.Store the passwords in the inventory file as host variables, and encrypt the inventory file with ansible-vault.
E.Use ansible-vault to encrypt a vars file containing the passwords, and include it with vars_files in the playbook.
AnswersD, E

Inventory files can contain host variables, including ansible_password and ansible_become_password. Encrypting the entire inventory file with ansible-vault protects the credentials at rest. Ansible can decrypt the inventory at runtime if the vault password is provided. This method is valid and keeps sensitive data encrypted, meeting the requirement.

Why this answer

Ansible Vault is the primary tool for encrypting sensitive data at rest. Encrypting a vars file and including it with vars_files, or encrypting an inventory file that contains host variables, both securely provide passwords to playbooks. The vault password can be supplied separately.

Command-line extra vars, debug printing, and environment variables either expose secrets or fail to encrypt them at rest, so they are not valid secure methods.

Exam trap

The trap here is thinking that any method that supplies the password value is acceptable, ignoring the need for encryption at rest and avoidance of exposure in logs or process lists.

20
MCQeasy

Which command publishes a collection to Automation Hub?

A.ansible-galaxy collection import ./namespace-name-1.0.0.tar.gz
B.ansible-galaxy collection upload ./namespace-name-1.0.0.tar.gz
C.ansible-galaxy collection push ./namespace-name-1.0.0.tar.gz
D.ansible-galaxy collection publish ./namespace-name-1.0.0.tar.gz --token MYTOKEN
AnswerD

The ansible-galaxy collection publish subcommand uploads the built tarball to Automation Hub, authenticating with the API token via --token. This satisfies the requirement to push a collection artefact to the Hub, since the tarball must already exist before publishing.

Why this answer

`ansible-galaxy collection publish` is the specific command used to upload a collection tarball to Automation Hub (or any Galaxy server). The `--token` flag provides the required API authentication token for the publish operation. This command sends the tarball to the server's API endpoint, which validates and imports the collection.

Exam trap

The trap here is that candidates confuse the `ansible-galaxy role push` command (used for roles) with the collection workflow, mistakenly assuming 'push' or 'upload' are valid for collections, when only `publish` is correct.

How to eliminate wrong answers

Option A is wrong because `ansible-galaxy collection import` is not a valid command; the correct command for importing a collection from a source (like a Git repository) is `ansible-galaxy collection build` followed by `publish`, and `import` is used for roles, not collections. Option B is wrong because `ansible-galaxy collection upload` does not exist; the verb 'upload' is not used in the Ansible Galaxy CLI for collections. Option C is wrong because `ansible-galaxy collection push` is not a valid subcommand; 'push' is used with `ansible-galaxy role` (e.g., `ansible-galaxy role push`), not for collections.

21
MCQeasy

A template must emit a comma-separated string of hostnames from a list variable `web_nodes`, sorted alphabetically, for use in a configuration file. Which expression produces that string?

A.{{ web_nodes | unique | join(',') }}
B.{{ web_nodes | flatten | join(',') }}
C.{{ web_nodes | sort | join(',') }}
D.{{ web_nodes | join(',') | sort }}
AnswerC

The `sort` filter returns a new list ordered alphabetically, and `join` concatenates its elements using the comma delimiter. Chaining them yields a single string with hostnames in sorted order separated by commas, which is exactly the format the configuration file expects. Both filters are standard Ansible/Jinja2 filters available in templates.

Why this answer

The order of filters matters: sorting must happen while the data is still a list, then joining converts it to a string. Applying join before sort would sort characters, and filters like unique or flatten do not impose alphabetical order. Only sorting the list first and then joining with a comma delimiter meets the requirement.

Exam trap

The trap here is applying filters in the wrong sequence, so the join collapses the list before sorting can order its elements.

22
Drag & Dropmedium

Drag and drop the steps to configure a network bond (bond0) using nmcli 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 order to configure a network bond using nmcli is: create the bond connection first, then add slave interfaces to it, set the bonding mode (e.g., active-backup), activate the bond, and finally verify the bond status. This sequence ensures that the bond interface exists before adding slaves and that the mode is set before activation so that the bond operates correctly from the start.

23
MCQmedium

You have a list `my_list` containing `[0, 1, 2, '', 'hello']`. You want to extract the first truthy element that exists. Which chain achieves this?

A.`my_list | select('truthy') | first | default('')`
B.`my_list | list | first | default('')`
C.`my_list | select('string') | first | default('')`
D.`my_list | first | default('')`
AnswerA

Correct; select truthy, then first, then default.

Why this answer

`select('truthy')` filters the list to include only elements that evaluate to `true` in Ansible/Jinja2 (non-zero numbers, non-empty strings, etc.), and `first` returns the first such element. The `default('')` provides a fallback if no truthy element exists. This chain correctly extracts `1` from the list `[0, 1, 2, '', 'hello']`.

Exam trap

The trap here is that candidates may think `first` alone returns the first truthy element, but it actually returns the first element regardless of its truthiness, leading to a falsy result like `0` or `''`.

How to eliminate wrong answers

Option B is wrong because `list` is redundant (the input is already a list) and `first` without `select` returns the first element `0`, which is falsy, not the first truthy element. Option C is wrong because `select('string')` filters only elements that are strings, returning `''` and `'hello'`; `first` then returns `''`, which is falsy, not the first truthy element. Option D is wrong because `first` alone returns the first element `0`, which is falsy, and `default('')` only applies if the list is empty, not if the first element is falsy.

24
MCQmedium

A team is writing an Ansible role to configure a web server. They want to include default variables that can be easily overridden by playbook variables. Which directory and file should they use to define these variables?

A.vars/defaults.yml
B.defaults/main.yml
C.default_vars/main.yml
D.vars/main.yml
AnswerB

Placing variables in defaults/main.yml gives them the lowest precedence in Ansible's variable hierarchy, so playbook vars, host vars and role params all override them automatically. This satisfies the stem's requirement for easily overridden role defaults, unlike vars/main.yml, whose higher precedence resists such overrides.

Why this answer

In Ansible roles, default variables are defined in the `defaults/main.yml` file. These variables have the lowest precedence, meaning they can be easily overridden by playbook variables, inventory variables, or any other variable source with higher precedence. This design allows role authors to provide sensible defaults while giving users the flexibility to customize behavior without modifying the role itself.

Exam trap

The trap here is that candidates confuse the `defaults/` directory (lowest precedence) with the `vars/` directory (higher precedence), or they invent non-standard directory names like `default_vars/`, because the exam tests precise knowledge of the Ansible role directory structure and variable precedence rules.

How to eliminate wrong answers

Option A is wrong because `vars/defaults.yml` is not a standard Ansible role directory structure; Ansible expects default variables in a `defaults` directory, not a `vars` directory. Option C is wrong because `default_vars/main.yml` uses an incorrect directory name; the correct directory is `defaults`, not `default_vars`. Option D is wrong because `vars/main.yml` is used for role variables that have higher precedence and are not intended to be easily overridden by playbook variables; placing defaults in `vars/` would make them harder to override, defeating the purpose of easily overridable defaults.

25
MCQhard

An automation administrator is configuring an Ansible Automation Platform 2.4 controller to use an external PostgreSQL database. They have set `pg_host`, `pg_port`, `pg_database`, `pg_username`, and `pg_password` in the installer inventory. The installation fails with an error that the database user lacks the `CREATEDB` privilege. Which action should the administrator take?

A.Add `pg_sslmode='disable'` to the inventory to bypass SSL certificate validation.
B.Change `pg_host` to `localhost` to use a local socket connection instead of TCP.
C.Set `pg_username` to `postgres` and `pg_password` to the postgres superuser password.
D.Grant the `CREATEDB` privilege to the database user and re-run the installer.
AnswerD

The AAP installer requires the database user to have the `CREATEDB` privilege to create the necessary databases and schemas during installation. Without it, the installer cannot proceed. Granting this privilege to the specified user resolves the error and allows the installation to complete successfully. This is a documented requirement for external database configurations.

Why this answer

The installer requires the external database user to have the `CREATEDB` privilege to create the automation controller and hub databases. Granting this privilege is the correct fix. Other options either ignore the privilege requirement, use an insecure workaround, or modify unrelated connection parameters.

Exam trap

The trap here is thinking that any valid database user can be used, when the installer specifically requires elevated privileges like `CREATEDB` for initial setup.

26
MCQeasy

An administrator wants to run a specific set of tasks only on hosts that are members of the 'webservers' group. Which Ansible construct should be used to conditionally execute those tasks based on group membership?

A.Use the 'delegate_to' keyword to run tasks on a representative host from the group.
B.Use the 'when' condition with the 'group_names' variable.
C.Use the 'hosts' keyword in the play to target the 'webservers' group.
D.Use the 'when' condition with the inventory_hostname variable.
AnswerB

The group_names variable is a list of all groups the current host belongs to. A condition such as "'webservers' in group_names" will evaluate to true only on hosts in that group. This is the standard, dynamic way to conditionally run tasks based on inventory group membership without hardcoding hostnames.

Why this answer

The group_names variable contains the list of groups the current host belongs to. Using a when condition like "'webservers' in group_names" ensures the tasks run only on hosts in that group, regardless of the play's target. This is dynamic and adapts to inventory changes.

Exam trap

The trap here is confusing play-level targeting with task-level conditionals; targeting a group in the play runs all tasks on those hosts, but conditional execution requires a when clause.

27
MCQmedium

A Red Hat Certified Engineer is deploying Ansible Automation Platform 2.4 on a RHEL 9 server. They extract the installer tarball and edit the inventory file. They set `registry_username` and `registry_password` in the inventory, then run `./setup.sh`. The installation fails early with an error that the subscription-manager repositories are not enabled. Which action most directly resolves this failure?

A.Set `ansible_connection=local` in the installer inventory so the setup script uses the local RPM database.
B.Run the setup script with the `--skip-tags validation` flag to bypass the repository check.
C.Disable the firewall and SELinux on the server before rerunning the installer.
D.Ensure the RHEL system is registered with Red Hat Subscription Manager and the `ansible-automation-platform-2.4-for-rhel-9-x86_64-rpms` repository is enabled.
AnswerD

The AAP installer requires the system to be registered with RHSM and the correct AAP repository enabled so that required RPMs (e.g., ansible-core, receptor) can be installed. Without this repository, the setup script cannot resolve dependencies. Enabling the version-specific repository for RHEL 9 is the documented prerequisite before running the installer.

Why this answer

The AAP setup script depends on RHEL subscription repositories to install required packages. The system must be registered with RHSM and the appropriate AAP repository enabled. Without this, dependency resolution fails before configuration begins.

Enabling the correct version-specific repository is the documented prerequisite and directly resolves the reported error.

Exam trap

The trap here is assuming that providing registry credentials alone is sufficient for a disconnected or unregistered installation, when the installer also requires RHSM repositories to be enabled.

28
MCQmedium

A playbook uses serial: 2 and sets any_errors_fatal: true. The first batch of 2 hosts both fail. What happens?

A.The playbook continues with the next batch.
B.The playbook aborts and no further batches run.
C.The playbook marks the batch as unreachable and continues.
D.The playbook retries the failed hosts.
AnswerB

With any_errors_fatal set, a task failure on any host halts the entire play for all hosts. Since both hosts in the first serial batch of two fail, the play aborts immediately, so the remaining batches never execute.

Why this answer

When `any_errors_fatal: true` is set and a batch of hosts fails, Ansible immediately aborts the entire playbook run for all remaining hosts, regardless of the `serial` setting. Since the first batch of 2 hosts both fail, no further batches are executed. This behavior is designed to prevent cascading failures in critical deployments.

Exam trap

In Red Hat RHCE exams, candidates are often tested on the interaction between `serial` and `any_errors_fatal`, trapping those who assume `serial` batches always run independently, forgetting that `any_errors_fatal` forces a global abort on the first failure.

How to eliminate wrong answers

Option A is wrong because `any_errors_fatal: true` overrides the default batch-continue behavior of `serial`; Ansible does not proceed to the next batch after a failure in the current batch. Option C is wrong because the hosts are not marked as unreachable (which would require a connectivity failure, not a task failure), and the playbook does not continue; it aborts. Option D is wrong because `any_errors_fatal: true` does not trigger automatic retries; retry behavior is controlled by `retries` and `until` on individual tasks, not by this directive.

29
MCQmedium

An administrator wants to run a playbook that executes tasks in parallel across multiple hosts but wants to limit the number of simultaneous hosts to 5. Which directive should be set?

A.poll
B.serial
C.throttle
D.forks
AnswerB

The serial directive controls how many hosts Ansible targets per play iteration, so setting serial: 5 runs tasks across at most five hosts simultaneously. It bounds parallelism while still completing all hosts in successive batches.

Why this answer

The `serial` directive in Ansible controls the number of hosts that execute a play at a time, allowing you to limit concurrency. Setting `serial: 5` ensures that only 5 hosts run tasks simultaneously, with the playbook completing in batches of 5 until all hosts are processed.

Exam trap

The trap here is confusing `forks` (which controls connection parallelism) with `serial` (which controls play-level batch execution), leading candidates to incorrectly choose `forks` when they need to limit simultaneous host execution per play.

How to eliminate wrong answers

Option A is wrong because `poll` is used with asynchronous tasks to set the interval for checking job status, not to limit simultaneous host execution. Option C is wrong because `throttle` limits the number of concurrent task executions per task or block, but it does not control the batch size of hosts across an entire play; it applies at a finer granularity. Option D is wrong because `forks` defines the maximum number of parallel connections Ansible makes to hosts, but it does not enforce a strict batch limit; with `forks` set to 5, Ansible could still start tasks on more than 5 hosts if the play has multiple tasks, as it controls parallelism at the connection level, not the play-level batch size.

30
Multi-Selecthard

Which two statements about ansible-vault are true? (Select exactly 2.)

Select 2 answers
A.Vault-encrypted files cannot be used with include_vars.
B.Vault can encrypt entire files or individual variables.
C.Vault uses AES-128 encryption by default.
D.Vault passwords can be stored directly in ansible.cfg.
E.Vault supports multiple passwords with vault IDs.
AnswersB, E

ansible-vault encrypts at file level; variable encryption requires specific syntax.

Why this answer

Ansible-vault can encrypt either entire files (e.g., vars files, role defaults) or individual variables within a YAML file using the `!vault` tag. This flexibility allows you to protect sensitive data at the granularity you choose, without requiring separate encrypted files for each secret.

Exam trap

The trap here is that candidates often confuse the encryption algorithm (AES-128 vs AES-256) or assume vault-encrypted files cannot be dynamically included, when in fact include_vars works seamlessly with decryption.

31
Drag & Dropmedium

Drag and drop the steps to configure a firewall rule using firewalld to allow HTTPS traffic in the correct order.

Drag or tap steps into the slots.

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

Why this order

Firewalld commands: check zone, add service with --permanent, reload, verify, test.

32
MCQhard

Refer to the exhibit. An administrator runs the playbook but the wait_for task fails. What is the most likely cause?

A.The ansible_facts variable may not be available because fact gathering is disabled.
B.The http_port variable is misspelled.
C.The wait_for module requires the 'port' parameter to be an integer.
D.The delegate_to should be set to the remote host.
AnswerA

Correct: without gather_facts: yes, ansible_facts is empty.

Why this answer

The playbook uses `ansible_facts['ansible_tcpip_socket']['port']` to supply the port number to the `wait_for` module. If fact gathering is disabled (e.g., via `gather_facts: no` at the play level or `ANSIBLE_GATHERING=explicit`), the `ansible_facts` dictionary is empty, so the variable resolves to `None` or an undefined value, causing the task to fail. The error is not a syntax or type issue but a missing fact dependency.

Exam trap

The EX294 exam often tests the dependency between fact gathering and fact-based variables, trapping candidates who assume the error is a simple type mismatch or misspelling rather than a missing fact collection step.

How to eliminate wrong answers

Option B is wrong because the variable name `http_port` is not used in the playbook; the task references `ansible_facts['ansible_tcpip_socket']['port']`, so a misspelling of `http_port` is irrelevant. Option C is wrong because the `wait_for` module does accept the `port` parameter as a string (e.g., `'80'`) and will convert it internally; the error is not due to type mismatch. Option D is wrong because `delegate_to` is used to run a task on a different host, but the `wait_for` task is already targeting the remote host via `hosts: all`; delegating to the remote host would be redundant and not fix the missing fact issue.

33
MCQhard

An organization uses multiple Satellite servers for inventory. They want to combine data from all satellites into one unified inventory in Ansible Tower. Which approach is best?

A.Use a custom script to fetch and merge data from all Satellites into a single inventory source.
B.Create a smart inventory that includes all satellites.
C.Use a single Satellite server that aggregates data from all other Satellites.
D.Create one inventory with multiple inventory sources, each pointing to a different Satellite.
AnswerD

A single inventory with multiple sources lets Tower merge hosts from every Satellite into one unified view, satisfying the requirement to combine all satellites' data. Each source syncs independently, and Tower deduplicates hosts sharing a name, so overlapping entries collapse rather than duplicate.

Why this answer

Ansible Tower allows you to create a single inventory with multiple inventory sources, each configured to sync from a different Satellite server. This approach consolidates all host data into one unified inventory without custom scripting or requiring a central aggregator, leveraging Tower's native multi-source inventory capabilities.

Exam trap

The trap here is that candidates may confuse 'smart inventory' with the ability to aggregate external sources, but smart inventories only filter existing inventory data and cannot import from multiple external sources directly.

How to eliminate wrong answers

Option A is wrong because using a custom script to fetch and merge data introduces unnecessary complexity, maintenance overhead, and bypasses Tower's built-in inventory source management, which is designed for this exact use case. Option B is wrong because a smart inventory filters hosts based on existing inventory data and cannot directly import data from multiple external sources like Satellite servers; it requires a pre-populated inventory. Option C is wrong because requiring a single Satellite server to aggregate data from others adds an extra layer of infrastructure and defeats the purpose of using multiple independent Satellite servers, which Tower can directly query.

34
MCQeasy

In OpenShift, a DeploymentConfig uses the RollingUpdate strategy. Which parameter controls the maximum number of pods that can be unavailable during an update?

A.minReadySeconds
B.maxSurge
C.revisionHistoryLimit
D.maxUnavailable
E.progressDeadlineSeconds
AnswerD

maxUnavailable caps how many pods may be taken down simultaneously during a rolling update, directly satisfying the stem's constraint on maximum unavailable pods. It works alongside maxSurge, which governs extra pods created above the desired replica count.

Why this answer

In OpenShift, the RollingUpdate strategy for a DeploymentConfig uses the `maxUnavailable` parameter to specify the maximum number or percentage of pods that can be unavailable during the update process. This ensures that the desired number of pods remain available to serve traffic while the update rolls out, controlling the trade-off between update speed and availability.

Exam trap

The trap here is that candidates often confuse `maxUnavailable` with `maxSurge`, mistakenly thinking that controlling how many extra pods are created is the same as controlling how many can be unavailable, but `maxSurge` limits overshoot while `maxUnavailable` limits undershoot.

How to eliminate wrong answers

Option A is wrong because `minReadySeconds` controls how long a pod must be ready before it is considered available, not the number of unavailable pods during an update. Option B is wrong because `maxSurge` controls the maximum number of pods that can be created above the desired count during an update, not the number that can be unavailable. Option C is wrong because `revisionHistoryLimit` controls how many old ReplicationControllers are retained for rollback, not the update availability threshold.

Option E is wrong because `progressDeadlineSeconds` sets the maximum time for the deployment to make progress before it is considered failed, not the number of unavailable pods.

35
Multi-Selectmedium

Which THREE of the following are valid ways to define host variables in an Ansible inventory? (Choose exactly three.)

Select 3 answers
A.In the 'extra_vars' field of the job template.
B.Inline in the inventory file, e.g., 'myhost ansible_host=192.168.1.1 http_port=8080'.
C.In a credential's 'Input Configuration' as a secret variable.
D.In a 'group_vars/<groupname>' file, if the host belongs to that group.
E.In a 'host_vars/<hostname>' file within the project.
AnswersB, D, E

Variables can be assigned directly in the inventory file.

Why this answer

Ansible allows inline host variable definitions directly in the inventory file using key=value pairs after the hostname. This is a standard syntax where variables like 'http_port=8080' are assigned to the host 'myhost' and become available as Ansible facts during playbook execution. The 'ansible_host' special variable is also defined this way to override the connection address.

Exam trap

The trap here is that candidates confuse runtime variable injection methods (like extra_vars or credentials) with static inventory variable definitions, leading them to select options that are valid for passing variables but not for defining host variables in an inventory.

36
MCQmedium

An automation engineer stores a sudo password inside a project variable file that is committed to Git. The team requires that the cleartext value never appears in the repository and that playbooks still consume the variable transparently. Which approach meets this requirement?

A.Encrypt the variable file with ansible-vault encrypt and reference it from the playbook with vars_files; commit the encrypted file to Git.
B.Run ansible-vault encrypt_string on the variable and store the resulting inline value directly in group_vars/all.yml.
C.Add the variable file to .gitignore and distribute it manually to each control node's home directory before running the playbook.
D.Store the password in an environment variable on the control node and reference it with lookup('env', 'SUDO_PASS') inside the playbook.
AnswerA

Encrypting the variable file with ansible-vault encrypt keeps the plaintext password out of the Git repository while the playbook still loads the variables through vars_files at runtime, prompting for or receiving the vault password via --vault-password-file or --ask-vault-pass. This satisfies both the storage requirement and transparent consumption.

Why this answer

Ansible Vault encrypts files and individual values using AES-256 so that secrets can be safely stored in source control. Encrypting the whole variable file with ansible-vault encrypt and loading it through vars_files keeps the plaintext out of Git while playbooks still resolve the variable normally. Decryption happens at runtime using a vault password provided interactively or through a password file.

Exam trap

The trap here is assuming that .gitignore or environment variables provide equivalent protection to Ansible Vault, when only vault encryption keeps the secret usable by Ansible while remaining unreadable in the repository.

37
MCQhard

An administrator needs to securely pass a database password to a playbook without exposing it in logs or the command line. Which approach is the most secure?

A.Store the password in an Ansible Vault-encrypted variable file and include it.
B.Set the password in a variable and use 'no_log: true' on tasks that use it.
C.Store the password in a host_vars file with restricted file permissions.
D.Prompt for the password and pass it as an extra variable using -e.
AnswerA

Ansible Vault encrypts the variable file at rest with AES-256, so the password is decrypted only in memory during playbook execution and never appears in logs, process listings or command-line arguments. This satisfies the stem's requirement to avoid exposure in logs or on the command line.

Why this answer

Ansible Vault encrypts the variable file at rest, and including it via `vars_files` or `include_vars` decrypts it only in memory during playbook execution. This prevents the password from appearing in logs, the command line, or the process table, meeting the security requirement.

Exam trap

The trap here is that candidates often confuse `no_log: true` with actual encryption, thinking it hides the secret from all exposure, when in fact it only suppresses output and does not protect the secret from being visible in the process table or module internals.

How to eliminate wrong answers

Option B is wrong because `no_log: true` only hides the task output from logs, but the password is still passed in plaintext to the module and could be exposed via the process table or debug output if the module itself logs it. Option C is wrong because `host_vars` files with restricted file permissions still store the password in plaintext on disk, and any user with read access to the file or a backup can retrieve it. Option D is wrong because passing the password as an extra variable with `-e` exposes it in the command line, which is visible in the process list and shell history, and it may also appear in logs if the playbook uses `--log-level` or `ANSIBLE_LOG_PATH`.

38
MCQeasy

An administrator is deploying Ansible Automation Platform 2.4 on a RHEL 9 server. They have downloaded the bundled installer tarball and extracted it. Which file must be edited to specify the PostgreSQL admin password, the automation controller admin password, and the receptor connection settings before running the setup script?

A.setup.sh
B.ansible.cfg
C.inventory
D./etc/tower/conf.d/credentials.py
AnswerC

The bundled installer uses an INI-style inventory file where variables such as admin_password, pg_password, and receptor parameters are defined under the [automationcontroller] and [all:vars] sections. Editing this file is the documented step before running setup.sh, making it the correct place to set these deployment-wide credentials and connection details.

Why this answer

The AAP bundled installer reads all deployment variables, including database and admin passwords plus receptor settings, from the inventory file. Editing that file before executing setup.sh is the supported method. Configuration files like ansible.cfg and legacy paths are not consulted for these values, and altering the installer script itself is unsupported.

Exam trap

The trap here is assuming Ansible runtime configuration files such as ansible.cfg supply installer credentials, when the bundled installer actually reads them from its inventory file.

39
Matchingmedium

Match each Linux file system path to its typical content.

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

Concepts
Matches

Configuration files

Variable data (logs, databases)

User system resources (binaries, libraries)

Temporary files

Process and kernel information

Why these pairings

In Red Hat Enterprise Linux, standard directories follow the Filesystem Hierarchy Standard (FHS). /etc holds configuration files, /home stores user home directories, and /boot contains boot loader files and kernel images. Common confusions include mixing /var (variable data like logs) with /tmp (temporary files) and associating log files incorrectly with /tmp.

40
MCQmedium

Refer to the exhibit. A user runs a playbook that creates hosts and then attempts to use a constructed inventory plugin. However, the constructed inventory does not group hosts by OS distribution. What is the most likely cause?

A.The constructed plugin cannot be used with the add_host module.
B.The 'strict: false' setting ignores missing variables, causing the group to be empty.
C.The constructed inventory runs before add_host tasks, so the hosts are not yet created.
D.The variable ansible_distribution is not defined because gather_facts is set to no.
AnswerC

Constructed inventory plugins parse existing inventory sources at the start of a play; hosts added mid-play via add_host exist only in memory and are never written back. Because the inventory is built before those tasks execute, the OS distribution groups cannot be populated.

Why this answer

The constructed inventory plugin processes inventory sources and applies Jinja2 conditions to group hosts based on variables. However, when used in a playbook alongside the `add_host` module, the constructed inventory is evaluated at the start of the play, before any tasks (including `add_host`) run. Therefore, hosts added dynamically via `add_host` do not exist when the constructed plugin attempts to group them, causing the groups to be empty.

Option C correctly identifies this ordering issue.

Exam trap

Red Hat often tests the misconception that inventory plugins and dynamic host creation (`add_host`) operate in the same phase, when in fact the constructed plugin runs during inventory loading (pre-task) while `add_host` runs during task execution, creating a timing mismatch that candidates overlook.

How to eliminate wrong answers

Option A is wrong because the constructed plugin can absolutely be used with hosts created by `add_host` — the issue is not compatibility but execution order. Option B is wrong because `strict: false` does not cause groups to be empty; it merely suppresses errors when a variable is undefined, but if the hosts themselves are not yet present, no grouping can occur regardless of strict mode. Option D is wrong because even if `gather_facts` is set to `no`, the constructed plugin can still use other variables or static facts; the core problem remains that the hosts are not yet added to the inventory at the time the plugin runs.

41
MCQhard

A job template runs successfully on some hosts but fails on others with 'Permission denied' for the same task. The admin has verified that the credential is correct. What is the most likely cause?

A.The package repository is not accessible from those hosts.
B.The privilege escalation method (become method) differs among hosts.
C.The credential's username is incorrect for some hosts.
D.The SSH key is not accepted on some hosts.
AnswerB

Differing become methods across hosts break privilege escalation: sudo, su and doas require distinct configuration and password handling, so a task succeeding where sudo is configured fails elsewhere with 'Permission denied' despite valid credentials. Aligning the become method with each host's available escalation tooling resolves the inconsistency.

Why this answer

B is correct because the 'Permission denied' error on a task that runs successfully on some hosts but not others, despite a verified credential, typically indicates a privilege escalation issue. The become method (e.g., sudo, su, pbrun) may be configured differently or unsupported on the failing hosts, causing Ansible to fail when attempting to escalate privileges for the task. Since the credential is correct, the failure occurs during the become process, not authentication.

Exam trap

The trap here is that candidates often assume 'Permission denied' always means an SSH key or credential issue, overlooking that privilege escalation (become) is a separate step that can fail even when the initial SSH connection succeeds.

How to eliminate wrong answers

Option A is wrong because a package repository being inaccessible would cause a different error (e.g., 'Could not resolve host' or 'Failed to download metadata'), not 'Permission denied' for a task. Option C is wrong because the admin has verified the credential is correct, so the username is not incorrect; a wrong username would cause an authentication failure, not a permission error after authentication. Option D is wrong because an SSH key not being accepted would cause an SSH connection failure (e.g., 'Permission denied (publickey)') before any task runs, not a 'Permission denied' error on a specific task after connection is established.

42
Multi-Selectmedium

An organization is designing a high-availability Automation Platform deployment. Which TWO practices are essential for achieving high availability?

Select 2 answers
A.Use a single instance of PostgreSQL on the controller node.
B.Installation on a single powerful node.
C.Deploy multiple automation controllers behind a load balancer.
D.Store all secrets in the Automation Platform vault.
E.Use an external PostgreSQL database with replication.
AnswersC, E

Running multiple automation controllers behind a load balancer removes the single point of failure, distributing API and job traffic across nodes so one controller outage does not halt automation. This directly satisfies the high-availability design constraint.

Why this answer

Option C is correct because deploying multiple automation controllers behind a load balancer eliminates a single point of failure for the control plane, allowing traffic to be redistributed if one controller node becomes unavailable, which is fundamental to high availability. Option E is correct because using an external PostgreSQL database with replication ensures the shared data layer (job history, credentials metadata, inventories, etc.) remains available even if a database node fails, and externalizing it also decouples database lifecycle from controller nodes. Option A is incorrect because a single PostgreSQL instance on the controller node creates a single point of failure and couples the database to that node, undermining HA.

Option B is incorrect because consolidating everything on one powerful node still leaves a single point of failure regardless of performance. Option D is incorrect because storing secrets in the Automation Platform vault is a security best practice for credential management, not a high-availability mechanism.

Exam trap

The trap here is that candidates confuse 'high availability' with 'performance scaling' or 'security hardening', leading them to select a single powerful node (Option B) or vault storage (Option D) instead of recognizing that redundancy of both controllers and the database is required.

43
Multi-Selecthard

Which THREE components are typically included in an execution environment?

Select 3 answers
A.Base OS image
B.Ansible Navigator
C.Ansible Core and collections
D.Python interpreter and dependencies
E.Ansible Tower/AWX
AnswersA, C, D

Every execution environment is built FROM a base OS image, which supplies the filesystem, package manager and libraries upon which the Ansible runtime and Python dependencies are layered. It forms the foundational layer of the container definition.

Why this answer

An execution environment is a container image that bundles everything needed to run Ansible automation, so option A (Base OS image) is correct because the container must be built on a base operating system layer such as a UBI or Debian image. Option C (Ansible Core and collections) is correct because the execution environment packages ansible-core together with the required collections so playbooks and roles have their modules and plugins available. Option D (Python interpreter and dependencies) is correct because Ansible runs on Python, and the environment must include the Python interpreter plus any Python libraries the modules and collections depend on.

Option B (Ansible Navigator) is not included; it is a separate command-line tool used to build, run, and inspect execution environments, not a component inside them. Option E (Ansible Tower/AWX) is not included either, since AWX and Tower are automation controller platforms that consume execution environments rather than being packaged within one.

Exam trap

Red Hat often tests the distinction between tools that manage execution environments (like Ansible Navigator) versus components that are actually inside the execution environment, leading candidates to mistakenly include Navigator or Tower/AWX as part of the image.

44
MCQmedium

An automation engineer is preparing an execution environment for a project that requires the `community.general` collection and the `netaddr` Python library. The engineer has created an `execution-environment.yml` file in the project directory. Which command should be used to build the execution environment image?

A.ansible-galaxy collection build
B.ansible-navigator build execution-environment.yml
C.podman build -t my-ee:latest .
D.ansible-builder build --file execution-environment.yml
AnswerD

The `ansible-builder build` command reads the execution environment definition file (by default `execution-environment.yml` in the current directory) and builds a container image. The `--file` flag can explicitly specify the definition file, though it is optional when the file has the default name. This command is the standard way to create an execution environment image from a definition.

Why this answer

The `ansible-builder build` command is the correct tool to create an execution environment image from an `execution-environment.yml` definition. It parses the definition, installs collections and Python dependencies, and produces a container image. Other commands like `ansible-galaxy collection build` or `podman build` serve different purposes and do not automate the execution environment creation process.

Exam trap

The trap here is confusing the collection packaging command `ansible-galaxy collection build` with the execution environment build command `ansible-builder build`.

45
MCQeasy

An administrator is creating a new execution environment and wants to use a minimal base image provided by Red Hat that includes `ansible-core` and essential Python libraries. Which base image should be specified in the `execution-environment.yml` file?

A.`quay.io/ansible/ansible-runner:latest`
B.`registry.redhat.io/ansible-automation-platform-23/ee-minimal-rhel8:latest`
C.`registry.access.redhat.com/ubi8/ubi:latest`
D.`docker.io/library/python:3.9-slim`
AnswerB

Red Hat provides minimal execution environment base images under the `ansible-automation-platform` namespace. The `ee-minimal-rhel8` image includes `ansible-core` and essential Python libraries, optimized for building custom execution environments. It is maintained and supported by Red Hat. Specifying this image as the base ensures a minimal footprint and compatibility with Ansible Automation Platform.

Why this answer

Red Hat offers minimal execution environment base images specifically designed for Ansible Automation Platform. The `ee-minimal-rhel8` image includes `ansible-core` and required Python libraries, providing a supported and optimized foundation. Other images either lack Ansible components or are not minimal for this purpose.

Using the Red Hat-provided minimal image simplifies the build and ensures compatibility.

Exam trap

The trap here is assuming any UBI or Python image is sufficient as a base for an execution environment, when Red Hat provides a dedicated minimal EE base image.

46
MCQmedium

A playbook reads a YAML file containing a list of dictionaries named `packages`, where each dictionary has keys `name`, `version`, and `enabled`. You need to produce a comma-separated string of only the `name` values for all entries where `enabled` is true. Which Jinja2 expression accomplishes this in a single task variable assignment?

A.{{ packages | json_query('[?enabled].name') | join(',') }}
B.{{ packages | select('enabled') | map(attribute='name') | join(',') }}
C.{{ packages | selectattr('enabled') | map(attribute='name') | join(',') }}
D.{{ packages | map(attribute='name') | selectattr('enabled') | join(',') }}
AnswerC

The `selectattr` filter keeps only items whose `enabled` attribute is truthy, then `map(attribute='name')` extracts the name from each remaining dictionary, and `join(',')` collapses the resulting list into a comma-separated string. This matches the requirement exactly without needing a loop or extra variable.

Why this answer

Filtering a list of dictionaries by a boolean attribute and then extracting a specific key is a common data transformation. The `selectattr` filter is designed to filter by attribute, `map(attribute=...)` extracts the desired key, and `join` combines the results into a string. The order of operations is critical: filter first, then map, then join.

Exam trap

The trap here is assuming that `map` and `selectattr` can be used in any order, when in fact `map` transforms the data structure and must come after attribute-based filtering.

47
Multi-Selecteasy

Which TWO of the following are advantages of using 'ansible-pull' over 'ansible-playbook'?

Select 2 answers
A.It can be used in environments where a central control node is not desired.
B.It eliminates the need for an inventory file.
C.Nodes can self-configure by pulling playbooks from a git repository.
D.It supports a different syntax for playbooks that is more efficient.
E.It reduces load on the control node because it runs locally on each node.
AnswersA, C

ansible-pull runs locally on each managed node, fetching playbooks from git rather than receiving them from a central controller. This satisfies the stem's constraint of operating without a central control node, which ansible-playbook cannot do since it requires a controller to push tasks.

Why this answer

Option A is correct because ansible-pull is designed for decentralized setups: each managed host runs the ansible-pull command itself, fetching and executing a playbook from a git repository, so no persistent central control node is required to push configurations. Option C is correct because ansible-pull's core behavior is exactly that nodes self-configure by cloning or updating a playbook from a git repository (via the -U/--url option) and then running it locally with ansible-playbook under the hood. Option B is not a real advantage: ansible-pull still relies on an inventory (typically localhost or a local inventory file) to determine targets, so it does not eliminate inventory usage.

Option D is false because ansible-pull uses the same YAML playbook syntax as ansible-playbook; there is no separate, more efficient syntax. Option E is misleading: although execution happens locally, ansible-pull does not inherently reduce control-node load as a designed advantage, and the question asks for advantages over ansible-playbook, which is not established by this option.

Exam trap

The trap here is that candidates often confuse 'eliminating the need for a control node' with 'eliminating the need for inventory,' or incorrectly assume that running locally automatically reduces load, when in fact the load is redistributed rather than reduced.

48
Matchingmedium

Match each systemd unit type to its description.

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

Concepts
Matches

Background daemon or process

IPC or network socket

Time-based activation

Filesystem mount point

Group of units for synchronization

Why these pairings

Common systemd unit types include service (manages daemons), socket (manages IPC/network sockets), timer (schedules events), and mount (controls mount points). Be careful not to confuse timer with service.

49
Multi-Selecteasy

Which TWO factors should be considered when choosing a base container image for an execution environment?

Select 2 answers
A.The date of the last update.
B.The presence of ansible-core and ansible-runner.
C.The size of the image.
D.The base operating system version.
E.The number of layers.
AnswersB, D

A suitable base image must already provide ansible-core and ansible-runner, since execution environments rely on these to execute playbooks and communicate with the controller. Choosing an image lacking them forces manual installation and risks version incompatibilities.

Why this answer

Option B is correct because an execution environment must contain ansible-core and ansible-runner to actually execute Ansible playbooks and roles; without these packages the image cannot function as an automation execution environment. Option D is correct because the base operating system version determines package availability, supported Python versions, and compatibility with the ansible-core and collection dependencies you install, so it must be chosen deliberately. Option A is not a primary selection factor because a recent update date alone does not guarantee the required Ansible tooling or OS compatibility.

Option C is not a primary factor because image size affects pull time and storage but does not determine whether the environment can run Ansible content. Option E is not a primary factor because the number of layers is an optimization detail, not a functional requirement for an execution environment.

Exam trap

Red Hat often tests the misconception that image size or layer count are critical selection criteria, when in fact the mandatory technical requirement is the presence of `ansible-core` and `ansible-runner` to ensure the container can actually run Ansible jobs.

50
MCQeasy

An admin needs to restrict which users can launch specific job templates. Which AAP feature should be used?

A.Execution environments with custom modules.
B.Machine credentials with different users.
C.Inventory groups with host restrictions.
D.Role-based access control (RBAC) on job templates.
AnswerD

RBAC on job templates grants or denies execute permission to named users or teams, directly satisfying the requirement to restrict who can launch specific templates. Unlike organisation-wide roles, template-level role assignments scope access per template, so only explicitly authorised principals can run it.

Why this answer

Role-based access control (RBAC) on job templates is the correct feature because it allows an administrator to assign specific permissions (e.g., execute, read, or admin) to users or teams for individual job templates in Ansible Automation Platform (AAP). This directly restricts which users can launch specific job templates without affecting other resources.

Exam trap

The trap here is that candidates confuse operational features (like execution environments or credentials) with access control mechanisms, assuming that restricting execution environments or credentials indirectly controls user access, when AAP explicitly uses RBAC for granular user permissions on job templates.

How to eliminate wrong answers

Option A is wrong because execution environments are containerized runtime environments for Ansible playbooks, not a mechanism for user-level access control; custom modules extend functionality but do not restrict job template launches. Option B is wrong because machine credentials authenticate to target hosts (e.g., SSH keys or passwords) and do not control which users can launch job templates in AAP. Option C is wrong because inventory groups organize hosts for targeting playbooks, but they do not enforce user permissions on job templates; host restrictions limit which hosts are affected, not who can launch the job.

51
Multi-Selecthard

An administrator is debugging a playbook that uses multiple roles and wants to limit execution to a specific set of tasks. Which three methods can be used to filter task execution? (Choose three.)

Select 3 answers
A.Use the '--tags' command-line option.
B.Use the '--skip-tags' command-line option.
C.Use the '--check' command-line option.
D.Use the '--step' command-line option.
E.Use the '--start-at-task' command-line option.
AnswersA, B, E

The --tags option restricts execution to tasks and roles carrying the named tags, so only those tagged tasks run. This filters execution without editing the playbook, satisfying the requirement to limit a multi-role playbook to a specific set of tasks.

Why this answer

Option A is correct because the '--tags' command-line option filters execution so that only tasks (and roles) tagged with the specified tag names are run, which directly limits a playbook to a specific set of tasks. Option B is correct because '--skip-tags' performs the inverse filtering, excluding tasks carrying the given tags while running everything else, another valid way to narrow execution. Option E is correct because '--start-at-task' begins execution at the first task whose name matches the given value, effectively limiting the run to that task and those following it.

Option C is not a filtering method: '--check' runs the playbook in dry-run/check mode, reporting changes without applying them. Option D is also not a filter: '--step' prompts interactively before each task, allowing the operator to confirm or skip tasks one at a time rather than selecting a task set.

Exam trap

The trap here is confusing options that control execution flow (like '--step' or '--check') with options that actually filter which tasks are included or excluded from the run, leading candidates to select non-filtering options.

52
MCQhard

An Ansible role uses a variable "server_list" which is a list of dictionaries. Each dictionary has a key "ports" which should be a list of integers. However, due to inconsistent input, "ports" could be a comma-separated string (e.g., "80,443") or already a list of integers (e.g., [80,443]). The engineer wants to normalize "ports" to always be a list of integers for further processing. Which of the following tasks correctly normalizes the "ports" field?

A.- set_fact: server_list: "{{ server_list | map('combine', {'ports': item.ports | split(',')}) }}" loop: "{{ server_list }}"
B.- set_fact: server_list: "{{ server_list | map('combine', {'ports': [item.ports] | flatten}) }}" loop: "{{ server_list }}"
C.- set_fact: server_list: "{{ server_list | map('combine', {'ports': item.ports}) }}" loop: "{{ server_list }}"
D.- set_fact: server_list: "{{ server_list | map('combine', {'ports': (item.ports is string) | ternary(item.ports | split(','), item.ports)}) }}" loop: "{{ server_list }}"
AnswerD

Correctly uses ternary to conditionally split string or keep list.

Why this answer

It uses the `ternary` filter to check if `item.ports` is a string; if true, it splits the string by commas into a list, otherwise it keeps the existing list. This ensures the `ports` field is always normalized to a list of integers, handling both inconsistent input formats.

Exam trap

The trap here is that candidates often overlook the need to conditionally handle both string and list inputs, picking options that either always split (breaking lists) or never split (breaking strings), rather than using a conditional filter like `ternary`.

How to eliminate wrong answers

Option A is wrong because `split(',')` will always produce a list of strings, not integers, and it does not handle the case where `ports` is already a list; also, `map('combine', ...)` with a loop is redundant and incorrectly replaces the entire list. Option B is wrong because `[item.ports] | flatten` will wrap a list in another list and then flatten it, but if `item.ports` is a string, it will create a list containing that single string, not splitting it; it fails to normalize strings into separate integer elements. Option C is wrong because it simply reassigns the `ports` field without any transformation, leaving strings unchanged and not converting them to lists.

53
MCQhard

A playbook includes a long-running task that should not block the rest of the playbook. The administrator wants to start the task and later check its status. Which method should be used?

A.Use the 'async' keyword with 'poll: 0' and then use async_status module.
B.Use 'delegate_to: localhost' and 'run_once'.
C.Use a separate playbook invoked with 'ansible-playbook' via command module.
D.Use 'throttle' to limit execution.
AnswerA

Fire-and-forget execution requires async with poll: 0, which returns immediately without blocking subsequent tasks. The async_status module then queries the job by its async job ID to retrieve completion state, satisfying the requirement to start the task and check its status later.

Why this answer

Setting `poll: 0` with the `async` keyword launches the task in the background without waiting for it to complete, and the `async_status` module can then be used later to check the task's status by referencing its job ID. This allows the playbook to continue executing other tasks while the long-running task runs asynchronously.

Exam trap

The trap here is that candidates confuse `async` with `throttle` or `delegate_to`, thinking any concurrency-related keyword will make a task non-blocking, when only `async` with `poll: 0` achieves true background execution.

How to eliminate wrong answers

Option B is wrong because `delegate_to: localhost` and `run_once` control where a task runs and how many times it executes, but they do not prevent a long-running task from blocking the playbook; the task still runs synchronously. Option C is wrong because using a separate playbook invoked via the `command` module with `ansible-playbook` is an anti-pattern that bypasses Ansible's built-in async support, adds unnecessary complexity, and still blocks until the subprocess finishes unless manually backgrounded. Option D is wrong because `throttle` limits the number of concurrent task executions but does not make a task non-blocking; the task still runs synchronously within its throttle slot.

54
Multi-Selectmedium

Which TWO of the following are best practices for securing automation controller secrets and credentials?

Select 2 answers
A.Store secrets in plain text in inventory files for simplicity
B.Use Ansible Vault to encrypt sensitive data like passwords and API keys
C.Disable logging to prevent exposure of sensitive data in logs
D.Use OAuth2 tokens for API authentication instead of static credentials
E.Grant all users admin access to reduce permission complexity
AnswersB, D

Ansible Vault encrypts variables and files at rest using AES-256, so passwords and API keys stored in playbooks or variable files remain unreadable without the vault password. This satisfies the requirement to protect sensitive data rather than leaving it in plaintext.

Why this answer

Option B is correct because Ansible Vault encrypts sensitive variables, passwords, and API keys at rest with AES-256, so playbooks and variable files can be safely stored in version control without exposing plaintext secrets. Option D is correct because OAuth2 tokens provide scoped, time-limited, and revocable API authentication, which is far safer than long-lived static credentials that, if leaked, grant persistent access. Option A is wrong because storing secrets in plaintext in inventory files exposes them to anyone with file or repository access.

Option C is wrong because disabling logging reduces auditability and does not actually secure secrets; instead, you should use no_log and vaulted variables to keep sensitive data out of logs. Option E is wrong because granting all users admin access violates least privilege and dramatically increases the blast radius of any compromised account.

Exam trap

Red Hat often tests the misconception that disabling logging is a valid security measure, but the correct approach is to use selective data masking with no_log rather than eliminating logs entirely, which hinders auditing and troubleshooting.

55
MCQmedium

A company is deploying Ansible Automation Platform (AAP) in a three-node cluster: one automation controller node, one private automation hub node, and one database node (PostgreSQL). The deployment uses an execution environment that pulls from the private automation hub. After a successful installation, all nodes are reachable and services are running. However, when launching a job template that uses the execution environment, the job fails with the error: 'Unable to pull execution environment image from automation-hub.example.com:5000/ee/my-ee:latest - request to registry failed with status 403 Forbidden'. The administrator confirms that the execution environment image exists in the private automation hub and that the automation controller node can reach the registry via curl. What is the most likely cause and solution?

A.The private automation hub is configured to allow unauthenticated access; change the hub configuration to disable authentication.
B.SELinux on the controller node is blocking container pulls; temporarily set SELinux to permissive.
C.Create a container registry credential in automation controller that uses the pull token from private automation hub, and associate it with the execution environment.
D.The execution environment definition in the controller is missing the 'pull' field; add 'pull: always' to the job template.
AnswerC

The 403 Forbidden comes from the registry rejecting an unauthenticated pull, not from network reachability. Automation controller needs a container registry credential holding the private automation hub pull token, associated with the execution environment, so it can authenticate.

Why this answer

The 403 Forbidden error indicates that the automation controller cannot authenticate to the private automation hub container registry. Even though the image exists and network connectivity works, the controller needs a container registry credential configured with the pull token from the private automation hub. This credential must be associated with the execution environment.

Option A is wrong because disabling authentication compromises security and is not the intended solution. Option B is wrong because SELinux would produce a different error (e.g., permission denied), not a 403. Option D is wrong because the 'pull' field does not affect authentication; the error is about authentication, not pull policy.

56
MCQeasy

A playbook needs to generate a default value for a variable if it is undefined or empty. Which filter with a default value should be used?

A.my_var | fail('fallback')
B.my_var | ternary('fallback', my_var)
C.my_var | default('fallback')
D.my_var | coalesce('fallback')
AnswerC

default filter returns 'fallback' if my_var is undefined.

Why this answer

The `default` filter in Ansible is specifically designed to provide a fallback value when a variable is undefined or evaluates to an empty string (with the `omit` parameter). It is the idiomatic way to handle missing or empty variables in Jinja2 templates within Ansible playbooks, ensuring idempotency and avoiding undefined variable errors.

Exam trap

Red Hat often tests the distinction between filters that handle undefined variables (`default`) versus filters that perform conditional logic (`ternary`) or error handling (`fail`), and the trap here is that candidates may confuse `coalesce` (a common SQL function) with a valid Ansible filter, leading them to select option D.

How to eliminate wrong answers

Option A is wrong because `fail` is a filter that raises an error, not a filter that provides a default value; using `fail('fallback')` would cause the playbook to fail instead of supplying a fallback. Option B is wrong because `ternary` is a conditional filter that returns one of two values based on a condition, but it does not check for undefined or empty variables; it requires an explicit boolean expression and will error if `my_var` is undefined. Option D is wrong because `coalesce` is not a valid Ansible filter; it is a function in some databases (like SQL) or Jinja2 extensions, but Ansible does not provide a `coalesce` filter for defaulting variables.

57
Drag & Dropmedium

Drag and drop the steps to configure SELinux to allow Apache to read a custom web 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

SELinux for web: create dir, set context, verify, configure Apache, restart and test.

58
MCQhard

You run 'ansible-playbook -i inventory site.yml' and notice that a host defined in the inventory file is not targeted by a play with 'hosts: all'. The inventory file contains a group named 'ungrouped' with several hosts and a group named 'all_servers' with the same hosts. Which command most directly reveals whether Ansible is parsing the intended inventory source and listing that host under the expected groups?

A.ansible-config dump --only-changed
B.ansible-inventory -i inventory --list
C.ansible all -i inventory -m ping
D.ansible-doc -t inventory -l
AnswerB

The ansible-inventory --list command parses the specified inventory and outputs a JSON representation of all groups and hosts, showing exactly which groups each host belongs to. It confirms whether the host is present and under which group names, making it the most direct diagnostic for inventory parsing issues.

Why this answer

The ansible-inventory --list command is designed to parse an inventory source and emit the resulting groups, hosts, and variables as JSON. It is the definitive tool for confirming how Ansible interprets an inventory file, including group membership and host listing.

Exam trap

The trap here is reaching for connectivity tests or configuration dumps when the issue is inventory parsing, whereas ansible-inventory directly exposes the parsed inventory structure.

59
MCQmedium

An administrator needs to connect to a set of servers that use different SSH users: 'admin' for the 'web' group and 'deploy' for the 'db' group. The inventory file contains these groups. The administrator wants to avoid specifying the user in the playbook and wants the correct user to be used automatically for each group. Which method should be used?

A.Set the remote_user directive in the playbook and use a variable that changes per group.
B.Define ansible_user in host_vars for each host individually, using the correct user for that host's group.
C.Use the --user command-line option with a comma-separated list of users for each group.
D.Set ansible_user in the [web:vars] and [db:vars] sections of the inventory file.
AnswerD

Inventory files support group variables via [group:vars] sections. Setting ansible_user in [web:vars] and [db:vars] assigns the correct SSH user to all hosts in each group automatically. This is a clean, inventory-based solution that requires no playbook changes and ensures the right user is used per group.

Why this answer

Setting ansible_user in [group:vars] sections of the inventory file assigns the correct SSH user to all hosts in each group. This is a standard inventory feature that automatically applies group-specific connection variables. It requires no playbook modifications and ensures the right user is used for web and db hosts without manual per-host configuration.

Exam trap

The trap here is assuming that command-line options like --user can specify different users per group, when they apply globally to the entire playbook run.

60
MCQeasy

An Ansible task uses the variable `{{ my_var | default(required=true) }}`. What happens if `my_var` is undefined?

A.The task fails with an error message
B.The task skips the host
C.The task uses an empty string
D.The task uses the string 'required'
AnswerA

The `default` filter with `required=true` raises an undefined-variable error when `my_var` is absent, halting the task immediately. This satisfies the stem's constraint that an undefined variable must not silently fall back to a substitute value, unlike a plain `default('x')` which would return the fallback instead.

Why this answer

The `default(required=true)` filter in Ansible explicitly marks the variable as required. If `my_var` is undefined, the filter raises an error because it enforces that the variable must be provided, causing the task to fail with an error message. This is a deliberate mechanism to catch missing mandatory variables early in playbook execution.

Exam trap

The trap here is that candidates often confuse `default(required=true)` with setting a default value, thinking it will use the string 'required' or an empty string, when in fact it enforces mandatory variable definition and causes a failure.

How to eliminate wrong answers

Option B is wrong because the `required=true` parameter does not cause the task to skip the host; skipping occurs only with conditionals like `when: my_var is undefined` or `ignore_errors: yes`. Option C is wrong because an empty string is only used if `default('')` is specified without `required=true`. Option D is wrong because the string 'required' is not used as a fallback value; the `required=true` parameter is a boolean flag that triggers an error, not a default value.

61
MCQeasy

An automation engineer has written a custom Ansible role called `db_deploy` and wants to package it inside a new collection named `acme.database`. Which command initializes the collection skeleton with the correct directory layout for roles, modules, and plugins?

A.ansible-galaxy role init acme.database
B.ansible-galaxy collection init acme.database
C.ansible-galaxy collection build acme.database
D.ansible-galaxy collection install acme.database
AnswerB

The `ansible-galaxy collection init` subcommand scaffolds a new collection directory tree containing `plugins/`, `roles/`, `docs/`, `meta/`, and a `galaxy.yml` manifest. Running it with `acme.database` creates `acme/database/` with the namespace and name already populated in `galaxy.yml`, which is exactly what is needed before dropping the `db_deploy` role into the `roles/` directory.

Why this answer

Scaffolding a new collection requires the dedicated `ansible-galaxy collection init` subcommand, which generates the namespace/name directory tree plus a `galaxy.yml` manifest. Role initialization, building, and installing all operate on artifacts that already exist and therefore cannot produce the initial skeleton needed before a custom role is placed under `roles/`.

Exam trap

The trap here is confusing `ansible-galaxy role init` with `ansible-galaxy collection init`, since both create directory skeletons but only one produces a collection manifest and namespace layout.

62
MCQeasy

A playbook uses the copy module to deploy a configuration file. The file should be templated with variables, but the engineer mistakenly uses the 'src' parameter with a static file instead of 'content' or a template module. What is the most likely outcome?

A.The module automatically renders the Jinja2 template before copying.
B.The file is copied without variable substitution, resulting in literal Jinja2 syntax in the destination.
C.The playbook fails because the source file contains undefined variables.
D.The task is skipped because copy cannot handle variables.
AnswerB

The copy module's src parameter transfers the file verbatim, so Jinja2 placeholders such as {{ variable }} remain unrendered. Variable substitution only occurs through the template module or the content parameter, satisfying the stem's templating requirement.

Why this answer

The copy module with the 'src' parameter copies a file without any processing of Jinja2 templates. It does not perform variable substitution. Therefore, if the source file contains Jinja2 syntax (e.g., {{ variable }}), it will be copied literally to the destination.

The correct answer is B. Option A is incorrect because the copy module does not automatically render templates. Option C is incorrect because the playbook will not fail due to undefined variables; it simply copies the file as-is.

Option D is incorrect because the task will execute and copy the file, not skip.

63
MCQmedium

An Ansible playbook needs to convert a list of server names into a comma-separated string for an API call. Which filter should be applied to the list variable 'server_list'?

A.map('regex_replace', '^', '')
B.combine(',')
C.join(',')
D.regex_replace('\n', ',')
AnswerC

The join filter concatenates list elements into a single string using the supplied separator, so join(',') converts server_list into the comma-separated value the API expects. It operates directly on the list without requiring a loop.

Why this answer

The `join` filter in Ansible is designed to concatenate list elements into a single string using a specified delimiter. Applying `join(',')` to `server_list` will produce a comma-separated string, exactly as required for the API call.

Exam trap

The trap here is that candidates may confuse `join` with `combine` (which works on dicts) or attempt to use regex filters on lists, not realizing that `join` is the only filter that directly converts a list to a delimited string.

How to eliminate wrong answers

Option A is wrong because `map('regex_replace', '^', '')` applies a regex replacement to each element, but the pattern `^` (start of string) with an empty replacement does nothing—it returns the list unchanged, not a string. Option B is wrong because `combine` is a filter for merging dictionaries, not for joining list elements into a string. Option D is wrong because `regex_replace('

', ',')` is intended for strings, not lists; applying it to a list would cause an error or unexpected behavior, and it does not convert a list to a comma-separated string.

64
Multi-Selectmedium

A company uses Ansible to perform a rolling update of 10 web servers behind an HAProxy load balancer. The playbook uses the `serial` keyword and includes tasks to disable a host from the load balancer, update the web server package, and re-enable the host. Which TWO best practices should the administrator apply to minimize downtime and ensure a successful rolling update?

Select 2 answers
A.Use `any_errors_fatal: true` to stop the playbook if any host fails.
B.Set `serial: 1` to update one host at a time.
C.Use `throttle: 1` to limit the number of concurrent tasks across all hosts.
D.Ensure the load balancer draining timeout is longer than the maximum expected update time per host.
E.Use `async` and `poll` to run the update tasks in the background while proceeding to the next host immediately.
AnswersB, D

Updating one host at a time minimizes the impact on the load balancer pool and ensures continuous service availability.

Why this answer

Setting `serial: 1` ensures that only one host is updated at a time, which is the safest way to perform a rolling update without overwhelming the load balancer or causing a service outage. This allows the playbook to complete the full update cycle (disable, update, re-enable) for each host before moving to the next, minimizing the number of hosts out of service simultaneously.

Exam trap

The trap here is confusing `serial` with `throttle` or `async`; candidates often think `throttle` or `async` can achieve the same serialization, but only `serial` ensures one host completes the entire update cycle before the next begins, which is essential for minimizing downtime in a rolling update scenario.

65
MCQhard

Refer to the exhibit. A developer builds an execution environment using this execution-environment.yml. After building, the container starts but ansible-navigator cannot connect to the container because the required SSH packages are missing. Which file most likely needs to be updated?

A.The base image itself
B.requirements.yml
C.requirements.txt
D.bindep.txt
AnswerD

bindep.txt declares system-level RPM and DEB packages installed into the execution environment image during build. Missing SSH binaries such as openssh-clients must be listed there, since requirements.yml and requirements.txt cover only collections and Python packages respectively.

Why this answer

D is correct because `bindep.txt` specifies system-level package dependencies (like `openssh-clients` or `sshpass`) that must be installed in the container image. When building an execution environment, `ansible-builder` reads `bindep.txt` to install RPM packages via `dnf` (or `apt` on Debian-based images). If SSH packages are missing, the `bindep.txt` file is the most likely place to add them, as it directly controls which system packages are included in the final image.

Exam trap

Red Hat often tests the distinction between system-level dependencies (`bindep.txt`), Python dependencies (`requirements.txt`), and Ansible collections (`requirements.yml`), and the trap here is that candidates confuse `requirements.txt` (Python packages) with system packages, leading them to incorrectly select option C.

How to eliminate wrong answers

Option A is wrong because the base image itself (e.g., `quay.io/ansible/ansible-runner:latest`) is a pre-built container that already includes Ansible and Python but does not include SSH client packages by default; modifying the base image is not the standard approach—`bindep.txt` is the intended mechanism. Option B is wrong because `requirements.yml` is used to install Ansible collections from Galaxy or Automation Hub, not system packages like SSH clients. Option C is wrong because `requirements.txt` is used to install Python packages via `pip` (e.g., `ansible-core`, `pywinrm`), not RPM-level dependencies like `openssh-clients`.

66
MCQhard

Refer to the exhibit. The playbook fails because the httpd package is not found. Which is the most likely cause?

A.The inventory does not define 'webservers' group.
B.The role path is incorrectly configured in ansible.cfg.
C.The target host does not have the necessary repositories enabled.
D.The 'yum' module should use 'name=httpd' instead of YAML syntax.
AnswerC

Missing or disabled repositories leave the package manager unable to resolve the httpd package name, so the task fails at dependency resolution rather than at installation. Enabling the correct RHEL subscription or custom repository on the managed host restores package availability, satisfying the stem's constraint that the package simply cannot be found.

Why this answer

The error indicates the package is not available. This is typically due to missing or incorrect repository configuration. The playbook itself and role syntax are valid.

67
MCQmedium

Your organization uses Ansible Automation Platform 2.2 with private Automation Hub. You have developed a custom collection named 'my_company.network' that depends on 'cisco.ios' and 'vyos.vyos'. The collection is published in your private hub. You are building an execution environment using ansible-builder. The execution-environment.yml specifies 'EE_BASE_IMAGE: registry.redhat.io/ansible-automation-platform-22/ee-supported-rhel8:latest'. The dependencies section points to a requirements.yml file that includes your collection. When you run 'ansible-builder build', the build succeeds, but when running a playbook that uses modules from 'cisco.ios', you get an error 'module not found'. What is the most likely reason and the correct action to resolve it?

A.Reinstall the collection on the controller node using 'ansible-galaxy collection install'
B.Use a different base image that includes 'cisco.ios'
C.Update the collection metadata to include dependencies and rebuild
D.Add 'cisco.ios' to the requirements.yml file used during the execution environment build
AnswerD

Adding `cisco.ios` to the build-time `requirements.yml` lets ansible-builder resolve and install the transitive dependency into the execution environment image, satisfying the constraint that the module must exist inside the container. Private Automation Hub must host it, since the build pulls collections from configured sources.

Why this answer

The execution environment build process uses the requirements.yml file to determine which collections to include in the image. If the custom collection 'my_company.network' depends on 'cisco.ios', but that dependency is not explicitly listed in the requirements.yml, the builder will not include 'cisco.ios' in the execution environment. Adding 'cisco.ios' to the requirements.yml ensures it is installed during the build, making the module available at runtime.

Exam trap

The trap here is that candidates assume collection dependencies declared in metadata are automatically resolved during the execution environment build, but ansible-builder only installs collections explicitly listed in requirements.yml, not their transitive dependencies.

How to eliminate wrong answers

Option A is wrong because reinstalling the collection on the controller node does not affect the execution environment; the controller uses the execution environment's content, not locally installed collections. Option B is wrong because the base image 'ee-supported-rhel8' already includes many supported collections, but 'cisco.ios' is not guaranteed to be included; the issue is the build process, not the base image selection. Option C is wrong because updating the collection metadata to declare dependencies only affects the collection's metadata, but the execution environment builder does not automatically resolve transitive dependencies from the metadata; it only installs what is explicitly listed in requirements.yml.

68
MCQmedium

Ansible Tower is configured with a dynamic inventory source from VMware vCenter. The playbook needs to limit execution to hosts with a specific custom attribute. How should this be achieved?

A.Modify the VMware inventory script to filter hosts.
B.Use a smart inventory filter.
C.Add the required hosts manually.
D.Create a new inventory source with a filter.
AnswerB

Smart inventory filters let you define host criteria using facts and attributes, so the playbook runs only against vCenter hosts matching the custom attribute. A static group would not track the dynamic inventory source's changing membership.

Why this answer

Smart inventories in Ansible Tower allow you to apply a filter (using Jinja2-style syntax) against an existing inventory source, such as a dynamic VMware vCenter source, to limit execution to hosts matching specific criteria like a custom attribute. This approach avoids modifying the source script or creating duplicate inventory sources, preserving the dynamic nature of the inventory while enabling targeted host selection.

Exam trap

The trap here is that candidates may think they need to modify the inventory source or script to filter hosts, not realizing that Tower's smart inventories provide a built-in, non-destructive way to apply filters on top of any existing inventory source.

How to eliminate wrong answers

Option A is wrong because modifying the VMware inventory script is not a supported or scalable method in Tower; it would break the dynamic inventory source and require manual maintenance. Option C is wrong because manually adding hosts defeats the purpose of using a dynamic inventory from vCenter and introduces management overhead. Option D is wrong because creating a new inventory source with a filter is unnecessary; smart inventories provide the filtering capability without duplicating the source, and filters are applied at the smart inventory level, not at the source level.

69
MCQhard

Refer to the exhibit. A user attempts to download the collection using the download URL but the signature verification fails. What is the most likely reason?

A.The collection version does not match.
B.The user's client does not have the corresponding public key.
C.The collection is not properly signed.
D.The download URL is invalid.
AnswerB

Signature verification requires the signer's public key imported into the local GPG keyring. Without that corresponding public key, ansible-galaxy cannot validate the detached signature, so verification fails even when the collection archive itself is intact.

Why this answer

B is correct because signature verification of a downloaded collection requires the client to have the corresponding public key that was used to sign the collection. If the user's client lacks this public key, the verification process will fail, even if the collection itself is properly signed and the URL is valid.

Exam trap

Red Hat often tests the misconception that signature verification failures are always due to a corrupted or unsigned collection, when in reality the client-side public key management is a common oversight.

How to eliminate wrong answers

Option A is wrong because a version mismatch would not cause a signature verification failure; it would instead result in a different collection being downloaded or a version conflict error. Option C is wrong because if the collection were not properly signed, the signature verification would fail for that reason, but the question states the user attempts to download using the download URL, implying the collection exists and is signed; the most likely reason is the missing public key on the client side. Option D is wrong because an invalid download URL would prevent the download from starting or return a 404 error, not cause a signature verification failure after the download completes.

70
Multi-Selecthard

Which THREE considerations are important when using dynamic inventories in Ansible Tower?

Select 3 answers
A.Dynamic inventory groups can be nested under static groups.
B.Each inventory source can be assigned to multiple inventories.
C.The inventory source must have a defined credential for authentication to the cloud provider.
D.Custom inventory scripts must be placed in the Tower home directory.
E.Inventory sources can update automatically on a schedule.
AnswersA, C, E

Group hierarchies can mix static and dynamic groups.

Why this answer

Ansible Tower allows dynamic inventory groups to be nested under static groups, enabling a hybrid inventory structure where cloud-sourced hosts can be organized within manually defined static groups for more flexible automation targeting. This is supported by the Tower inventory model, which merges static and dynamic sources into a unified group hierarchy.

Exam trap

The trap here is that candidates may confuse the one-to-many relationship of inventory sources to inventories (Option B) with the actual one-to-one constraint, or assume custom scripts must reside in a specific directory (Option D) when Tower actually supports flexible script paths via projects or absolute paths.

71
MCQeasy

A playbook must retrieve a secret from an external vault service at runtime instead of storing it in the repository. The team wants the value available as a variable named db_password. Which Ansible feature should be used?

A.An ansible-vault encrypted file committed to the project and decrypted with a password file.
B.A fact gathered by the setup module from the managed node's /etc/shadow file.
C.A lookup plugin such as community.hashi_vault.hashi_vault referenced in a set_fact task.
D.A host variable defined in the inventory and marked with no_log on the consuming task.
AnswerC

Lookup plugins query external systems at execution time, so a HashiCorp Vault lookup can fetch db_password dynamically without persisting it in the repository. Assigning the result with set_fact makes the value available to subsequent tasks, which matches the requirement for runtime secret retrieval from an external vault service.

Why this answer

Lookup plugins execute on the control node and query external data sources during a play run, which is the supported way to pull secrets from services such as HashiCorp Vault. Assigning the lookup result to a variable with set_fact makes the secret usable by later tasks while keeping it out of the repository entirely.

Exam trap

The trap here is confusing Ansible Vault, which encrypts secrets stored in the project, with lookup plugins that retrieve secrets from an external service at run time.

72
MCQhard

A Red Hat Ansible Automation Platform installation uses a custom execution environment. The playbook runs fail with 'execution environment not found'. The execution environment is stored in a private registry requiring authentication. What must be configured?

A.Set the execution_environment_image variable in the playbook
B.Configure the execution environment in the inventory
C.Add the registry URL to the automation controller's container registry credentials
D.Add the registry to the project's source control
AnswerC

The controller must authenticate to the private registry before pulling the execution environment image, so adding the registry URL and credentials under container registry credentials satisfies that constraint. Without this, image pulls fail with 'not found' despite the image existing.

Why this answer

When an execution environment is stored in a private registry that requires authentication, the automation controller must have the registry's URL and credentials configured as a container registry credential. This credential is then used by the controller to authenticate and pull the execution environment image during job runs. Without this, the controller cannot access the private registry, resulting in the 'execution environment not found' error.

Exam trap

The trap here is that candidates often confuse setting the image name (Option A) with providing registry authentication, or they mistakenly think inventory or project settings can handle container registry access, when in fact only a dedicated container registry credential in automation controller can authenticate to a private registry.

How to eliminate wrong answers

Option A is wrong because setting the execution_environment_image variable in the playbook only specifies the image name/tag, but does not provide authentication credentials for a private registry. Option B is wrong because configuring the execution environment in the inventory is not a valid method; execution environments are defined at the job template or controller level, not in inventory files. Option D is wrong because adding the registry URL to the project's source control is unrelated to container registry authentication; source control handles playbook code, not container image access.

73
MCQmedium

An organization uses a private Automation Hub. A user has configured the server in ansible.cfg. Which command installs a collection from this server?

A.ansible-galaxy collection install my_namespace.my_collection --api-key=mykey
B.ansible-galaxy collection install my_namespace.my_collection --server=https://privatehub.example.com
C.ansible-galaxy collection download my_namespace.my_collection
D.ansible-galaxy collection install my_namespace.my_collection
AnswerD

Once the private Automation Hub server is configured in ansible.cfg, ansible-galaxy resolves the collection from that configured source automatically, so the standard install command with the fully qualified collection name retrieves it without extra flags.

Why this answer

When the Automation Hub server is already configured in ansible.cfg under the [galaxy] section with the server_url and auth_url, the ansible-galaxy collection install command will automatically use that server and its authentication. No additional flags are needed; the command simply specifies the collection name in the format namespace.collection.

Exam trap

The trap here is that candidates may think they need to specify the server URL or API key on the command line, but the EX294 exam expects you to know that the server is pre-configured in ansible.cfg, so only the collection name is required.

How to eliminate wrong answers

Option A is wrong because the --api-key flag is not a valid argument for ansible-galaxy collection install; authentication is handled via the server configuration in ansible.cfg or the GALAXY_TOKEN environment variable, not a command-line API key. Option B is wrong because the --server flag is not a valid option for ansible-galaxy collection install; the server URL is defined in ansible.cfg, not passed as a command-line argument. Option C is wrong because ansible-galaxy collection download is used to download a collection without installing it, not to install it from a configured server.

74
Multi-Selecthard

An Ansible Tower administrator needs to create a custom credential type that uses an SSH private key and a username. Which THREE components should be defined in the credential type's configuration?

Select 3 answers
A."fields": [{"id": "ssh_key_data", "type": "string", "label": "SSH Private Key", "multiline": true, "secret": true}]
B."fields": [{"id": "password", "type": "string", "label": "Password"}]
C."fields": [{"id": "key_type", "type": "string", "label": "Key Type"}]
D."fields": [{"id": "username", "type": "string", "label": "Username"}]
E."injectors": {"extra_vars": {"ansible_user": "{{ username }}", "ansible_ssh_private_key_file": "{{ ssh_key_data }}"}}
AnswersA, D, E

Input field for SSH private key content.

Why this answer

The SSH private key must be defined as a field with `"type": "string"`, `"multiline": true` (since SSH keys are multi-line), and `"secret": true` (to encrypt the value in the database). This matches the standard Ansible Tower custom credential type schema for storing sensitive key material.

Exam trap

The trap here is that candidates often add unnecessary fields like 'password' or 'key type' because they confuse SSH key-based authentication with password-based authentication, or they think the key format must be explicitly specified.

75
MCQmedium

An administrator is writing a role where a task should only execute when the variable `web_package` is defined and its value is `httpd`. The role must not fail if the variable is undefined. Which task condition is correct?

A.when: web_package is defined and web_package == "httpd"
B.when: web_package == "httpd"
C.when: web_package | default("httpd") == "httpd"
D.when: web_package is defined or web_package == "httpd"
AnswerA

This condition first checks if the variable is defined, short-circuiting safely if it is not, then compares its value. Because Ansible evaluates conditions with Jinja2 and short-circuiting, referencing an undefined variable in the second part is avoided. This meets the requirement of not failing when the variable is missing and only running when the value is exactly httpd.

Why this answer

The task must run only when web_package is defined and its value is httpd, without failing if undefined. The condition using 'is defined' followed by 'and' correctly short-circuits so that the variable is only compared when it exists. The other conditions either fail on undefined variables, run when the variable is missing, or use incorrect logic.

Exam trap

The trap here is assuming that a simple equality check or a default filter safely handles undefined variables, but only the defined test with and short-circuits to prevent errors.

Page 1 of 6

Page 2

All pages