# Ansible Modules and Ad Hoc Commands

> Chapter 4 of the Courseiva REDHAT-RHCE curriculum — https://courseiva.com/learn/redhat-rhce/ansible-modules-and-ad-hoc-commands

**Official objective:** 3.1 — Use Ansible modules and ad hoc commands to manage systems

## Introduction

Ansible modules and ad hoc commands. They are the building blocks and the quick-fix tools that let you manage hundreds of servers from a single terminal without logging in manually. For the EX294 exam, you must understand how to use these to perform immediate tasks and how they fit into the larger automation framework.

## The 12-Ingredient Recipe Analogy

You have a recipe that calls for 12 ingredients to make a lasagna. You have already prepared the tomato sauce, grated the cheese, and boiled the noodles. Now the recipe says: "Spread a layer of sauce over the noodles." This is a specific module in your cooking playbook. Now imagine you don't want to cook the whole lasagna; you just want to taste the sauce to check the salt. You reach into the bowl, dip in a spoon, and taste it immediately. That single, one-off taste test is an ad hoc command. You are not following the full recipe; you are performing one small, immediate action. In IT, managers often need to check a single setting on a server without running the entire automation script. An ad hoc command is that single spoonful — quick, direct, no ceremony. The complete recipe, with all its steps, is like a playbook. The individual action of spreading sauce is a module. When a system administrator wants to see if a service is running on 200 servers, they use an ad hoc command with the service module. They give one instruction: "Check the status of the httpd service." That is the exact equivalent of tasting the sauce. No full meal, just one quick check. This analogy is specific because lasagna recipes have many discrete steps (modules) and you sometimes just want one taste (ad hoc command) without cooking the whole dish. Other IT analogies (like a traffic cop) are too generic and don't capture the "one quick action versus a full procedure" distinction.

Now imagine you taste the sauce and it is bland. You do not rewrite the entire recipe; you add a pinch of salt. That is another ad hoc command: "Add salt to the sauce." In IT, if a server's time is off, you do not rewrite the entire configuration management script; you run an ad hoc command to synchronise the clock. The module is the action (spreading sauce, adding salt, checking time). The ad hoc command is the decision to do only that one action right now.

## Core explanation

Ansible is an automation tool. It runs on your control node (your laptop or a management server) and connects to managed nodes (the servers you want to configure). It uses SSH, a secure way to log into remote computers. Ansible modules are pre-written pieces of code that perform a specific task. For example, the `copy` module copies a file from the control node to the managed node. The `yum` module installs or removes software on systems that use the yum package manager (like Red Hat Enterprise Linux). The `service` module starts, stops, or checks the status of a service (like a web server). 

An ad hoc command is a single Ansible command that runs one module against one or many managed nodes. You do not write a full script (called a playbook). You type a command directly in your terminal. The structure is: `ansible [target] -m [module] -a '[module arguments]'`. The target can be a hostname, a group of hosts defined in your inventory file, or the keyword `all` to run on every managed node. `-m` specifies the module. `-a` passes arguments to that module.

Why does this exist? Before automation, administrators would SSH into each server individually, run commands, and repeat for every machine. That is slow, error-prone, and boring. Ad hoc commands let you change 50 servers at once with one line. Modules ensure the task is done correctly every time because they are tested code, not a human typing commands by memory.

Here are the most common modules tested on EX294:

- `command`: runs a simple command on the managed node. It does not process the command through the shell, so variables and redirects do not work.
- `shell`: runs a command through the shell, so pipes, redirects, and environment variables work.
- `copy`: copies a file from the control node to the managed node.
- `file`: manages file attributes like permissions, ownership, and whether the path is a file or directory.
- `yum`: installs, removes, updates, or queries packages using the yum package manager.
- `service`: manages services: start, stop, restart, enable (start on boot), or check status.
- `user`: creates, modifies, or deletes user accounts.
- `ping`: tests connectivity to managed nodes. It does not ping like ICMP; it connects via SSH and returns a success message.

When you run an ad hoc command, Ansible connects to each node, transfers the module code (a small Python script) to the node, executes it there, and returns the result. The module runs on the managed node, not the control node. That is important for the exam: modules are idempotent wherever possible. Idempotent means running the module multiple times has the same effect as running it once. If a package is already installed, the `yum` module will not reinstall it; it will report "success" but do nothing. This is a huge advantage over shell scripts that might break something if run twice.

Ad hoc commands are not ideal for complex tasks because you cannot use conditionals, loops, or variables easily. For that, you write a playbook. But for quick checks, restarting a service across 100 servers, or patching a single issue, ad hoc commands are perfect.

On the EX294 exam, you will be asked to write ad hoc commands that use specific modules with correct arguments. You must know the module names and what they do. You must also know the difference between the `command` and `shell` modules. The `command` module is safer because it does not interpret shell syntax. The `shell` module is more flexible but riskier. The exam often tests this distinction.

You also need to understand the `ansible` command's flags. The `-k` flag asks for the SSH password (never use in production; use SSH keys). `-b` or `--become` runs the module with privilege escalation (like sudo). `-K` asks for the become password. `-i` specifies the inventory file. `-u` specifies the remote user. You must know these for the exam.

Finally, know the `setup` module. This gathers facts about the managed node (OS version, IP address, CPU architecture, etc.) and returns them as variables. You can run it with `ansible all -m setup` to see everything about your nodes. Facts are used in playbooks to make decisions based on the target system's configuration.

## Real-world context

Alice is a junior system administrator at a mid-sized company that runs 150 Linux servers. A developer reports that a web application on the production server is returning errors. Alice needs to check if the Apache web server (the httpd service) is running on all 150 application servers. She does not want to SSH into each one — that would take hours. She opens her terminal, types `ansible app-servers -m service -a 'name=httpd state=started'` and presses Enter. In 10 seconds, Ansible connects to every server in the `app-servers` group, checks if httpd is running, and returns a colour-coded result for each. One server shows red: the service is stopped. She then runs `ansible app-servers -m service -a 'name=httpd state=started'` again, and this time the failed server turns green. The problem is solved in under a minute.

Later that week, the security team mandates that the `root` user must be renamed on all database servers. Alice does not want to write a full playbook for this one-time change. She uses the `user` module: `ansible db-servers -m user -a 'name=root uid=0 state=present'`. Wait — that does not rename the user. She needs to create a new user, then lock the old one. She runs two ad hoc commands:

- `ansible db-servers -m user -a 'name=legacy_admin uid=0 state=present'`
- `ansible db-servers -m command -a 'passwd -l root'`

She locks the root account by running the `passwd -l` command via the `command` module. She uses `command` because it is a one-off system command, not a standard Ansible operation. She did not need a playbook; two ad hoc commands were faster.

Another common scenario: a developer needs to deploy a configuration file to every web server. Alice copies a new `httpd.conf` file from her control node to the servers: `ansible web-servers -m copy -a 'src=/home/alice/httpd.conf dest=/etc/httpd/conf/httpd.conf owner=root group=root mode=0644'`. The `copy` module ensures the file is placed with the correct ownership and permissions. If the file already exists with the same content, Ansible does nothing — it is idempotent.

Alice also uses ad hoc commands for inventory management. She adds a new server to the `[web-servers]` group in her inventory file, then runs `ansible all -m ping` to verify all nodes are reachable. The `ping` module returns "pong" for each successful connection. This is her go-to test after any change to the inventory.

She uses the `setup` module to gather facts before a migration projec: `ansible all -m setup -a 'filter=ansible_os_family'`. This returns only the OS family of all nodes, helping her identify which servers run Red Hat versus Ubuntu. She uses that information to decide which package manager to use.

In production, Alice never uses the `--ask-pass` flag because passwords are insecure. She relies on SSH keys. She also uses `--become` with a dedicated automation user that has sudo privileges. She documents her most common ad hoc commands in a shared wiki so her team can reuse them.

When a critical vulnerability is announced, Alice can patch 150 servers in minutes: `ansible all -m yum -a 'name=openssl state=latest' --become`. She runs that, and Ansible updates the OpenSSL package across every server. She does not need to log in to each machine, type `sudo yum update openssl`, and manually confirm. One line, done.

## Exam focus

EX294 tests ad hoc commands heavily. Expect at least 3-5 questions on this topic. The exam presents scenarios and asks you to construct the correct ad hoc command from memory. You must know the exact syntax and module names.

Key exam topics:

- The structure of an ad hoc command: `ansible [host-pattern] -m [module] -a '[arguments]'`.
- The difference between `command` and `shell` modules. The exam will ask you to pick the right module for a task. If the task uses pipes (`|`), redirects (`>`), or environment variables (`$HOME`), the answer is `shell`. If it is a simple command without shell features, use `command`.
- The `module` argument syntax. For the `yum` module, arguments are `name=package_name state=latest`. You must know that `state=present` ensures a package is installed but does not update it. `state=latest` ensures the most recent version.
- The `service` module: arguments `name=service_name state=started|stopped|restarted|reloaded enabled=yes|no`.
- The `copy` module: `src=<local_path> dest=<remote_path> owner= user= group= mode=`.
- The `file` module: `path= state=directory|file|absent owner= group= mode=`.
- The `user` module: `name= state=present|absent uid= group= shell=`.
- The `ping` module: no arguments, just `ansible all -m ping`.
- The `setup` module: no arguments required, but can filter with `filter=ansible_*`.

Traps in the exam:

- They will give you a scenario where you need to use `--become` but the question does not mention "with elevated privileges." You must infer it. Any task that requires root, like installing packages or managing services, implicitly needs `--become`. If the answer choice includes `--become` and everything else is correct, it is likely correct.
- They will test the difference between the `raw` module and `command`/`shell`. The `raw` module does not use the Ansible module system; it works over SSH without Python on the remote node. It is rarely needed and the exam may include it as a distractor.
- They will ask about idempotence. If a question asks: "What happens if you run the same ad hoc command twice?" the correct answer is that the module will report "ok" and do nothing because the desired state is already met.
- They will include the `-a` argument syntax with single quotes vs double quotes. The exam uses single quotes around the arguments string: `-a 'name=httpd state=started'`. Double quotes are also valid in some shells, but single quotes are safer and the exam uses them.
- They will test the target pattern. If the inventory has a group `[webservers]`, the target is `webservers` (no brackets). The keyword `all` targets every host in the inventory.

Key definitions to memorise:

- Module: a pre-written, idempotent unit of code that performs a specific system management task.
- Ad hoc command: a one-line Ansible command that runs a single module against one or more hosts.
- Idempotence: property where running an operation multiple times produces the same result as running it once.
- Control node: the machine where Ansible is installed and commands are executed.
- Managed node: the remote system being configured by Ansible.

## Step by step

1. **Decide on the target hosts** — Identify the managed nodes you want to affect. They are defined in your inventory file. You can target a single host by its hostname, a group by its group name, or use the keyword `all` for every host. This determines the first part of your ad hoc command: `ansible all` or `ansible webservers`.
2. **Choose the correct module** — Select the module that performs the specific task you need. If you are managing software packages, choose `yum`. If you are managing files, choose `copy` or `file`. If you are checking a service, choose `service`. The wrong module will not do what you expect. Memorise the common modules and their purposes.
3. **Supply module arguments with `-a`** — Arguments tell the module exactly what to do. For the `service` module, arguments are `name=httpd state=started`. For the `yum` module, `name=nginx state=present`. Wrap the arguments in single quotes: `-a 'name=httpd state=started'`. If you omit the quotes, the shell may misinterpret spaces.
4. **Add privilege escalation if needed** — Many system tasks require root or sudo privileges. Add `--become` to your command to escalate privileges. If you need to provide a password for escalation, add `--ask-become-pass` (often written as `-K`). Do not forget this step: an ad hoc command that tries to install a package without `--become` will fail with a permission error.
5. **Execute the command and interpret the output** — Press Enter. Ansible connects to each target node, runs the module, and returns a summary. A green or "ok" result means the desired state was already present. A yellow "changed" result means Ansible had to make a change. A red "failed" result means something went wrong — read the error message to troubleshoot.

## Comparisons

### Ad Hoc Command vs Playbook

**Ad Hoc Command:**
- Run directly from the terminal, no file needed.
- Best for single tasks like checking a service status.
- Cannot use variables, loops, or conditionals easily.

**Playbook:**
- Written in a YAML file and executed with `ansible-playbook`.
- Best for multi-step, repeatable automation tasks.
- Supports variables, loops, conditionals, and error handling.

### command Module vs shell Module

**command Module:**
- Does not use the shell, so pipes and redirects do not work.
- Safer because it does not interpret shell metacharacters.
- Quicker to execute as it uses direct system calls.

**shell Module:**
- Uses the shell, so pipes, redirects, and environment variables work.
- Riskier as shell injection is possible if arguments are not sanitised.
- Slower because it spawns a shell process on the managed node.

### state=present (yum) vs state=latest (yum)

**state=present (yum):**
- Ensures the package is installed but does not update it.
- Will not upgrade a package that is already present.
- Useful for ensuring a baseline version is installed.

**state=latest (yum):**
- Ensures the most recent version of the package is installed.
- Will upgrade the package if an older version is present.
- Useful when you want the latest security patches.

### SSH Keys vs Password Authentication

**SSH Keys:**
- More secure because keys are stored on the control node.
- Ad hoc commands can run without prompting for a password.
- Standard for production automation.

**Password Authentication:**
- Passwords must be typed or passed with `--ask-pass`.
- Passwords can be intercepted; not recommended for automation.
- Used only in test environments or when keys are not set up.

## Diagram

_Ansible control node connects to multiple managed nodes via SSH and runs modules directly on each node._

```mermaid
graph LR
    A[Control Node] -->|SSH| B[Managed Node 1]
    A -->|SSH| C[Managed Node 2]
    A -->|SSH| D[Managed Node 3]
    B --> E[Module runs locally]
    C --> E
    D --> E
    A --> F[Inventory file defines targets]
```

## Common misconceptions

- **Misconception:** Ad hoc commands can only be run against a single host at a time. **Reality:** Ad hoc commands can target multiple hosts, groups of hosts, or all hosts in the inventory using patterns like `all` or a group name. (Beginners often think Ansible is for individual machines like SSH. They do not realise `ansible all -m ping` runs on every host in the inventory.)
- **Misconception:** The `shell` module is always better than the `command` module because it does more. **Reality:** The `command` module is safer and more predictable because it does not pass commands through the shell, avoiding shell injection and quoting issues. Use `shell` only when you need shell features like pipes. (New users see that `shell` works for everything and assume it is a superset. They miss that the exam explicitly tests the security trade-off.)
- **Misconception:** Modules run on the control node. **Reality:** Modules are transferred to and executed on the managed node. Ansible pushes the module code (a Python script) to the remote machine, runs it, and collects the result. (This misconception comes from other tools that run centrally. Understanding where execution happens is crucial for designing secure automation.)
- **Misconception:** You always need to write a playbook; ad hoc commands are useless in production. **Reality:** Ad hoc commands are essential for quick troubleshooting, one-off tasks, and verifying state across many servers. They are not a replacement for playbooks but a complementary tool. (Beginners often read that playbooks are the "real" automation and dismiss ad hoc commands as training wheels. In practice, sysadmins use ad hoc commands daily.)
- **Misconception:** The `setup` module is only for gathering facts, and you cannot use it in ad hoc commands. **Reality:** You can run `ansible all -m setup` as an ad hoc command to quickly view facts from all managed nodes. It is a valid and useful ad hoc command. (Many learners treat `setup` as a playbook-only feature. But it is a module like any other and works with the `-m` flag.)

## Key takeaways

- An ad hoc command starts with `ansible`, followed by a target pattern, `-m` for module, and `-a` for module arguments.
- Use the `command` module for simple commands that do not need shell features like pipes, redirects, or environment variables.
- Use the `shell` module only when you need shell-specific features; it is less secure than `command`.
- The `yum` module arguments `name=package state=latest` install or update a package; `state=present` installs it but does not update an existing one.
- The `service` module manages system services: `name=service state=started|stopped|restarted enabled=yes|no`.
- Modules are idempotent: running the same ad hoc command multiple times leaves the system in the same desired state without making unintended changes.
- Always use `--become` with tasks that require root privileges, such as installing packages or starting services.
- The `ping` module tests SSH connectivity and Python availability on managed nodes, not ICMP ping.

## FAQ

**What is the difference between an ad hoc command and a playbook?**

An ad hoc command runs one module immediately from the terminal. A playbook is a YAML file that can run multiple modules, include variables, conditionals, and loops. Use ad hoc commands for quick, one-time tasks and playbooks for repeatable, complex automation.

**Do I need to install Ansible on every managed node?**

No. Ansible only needs to be installed on the control node. It connects to managed nodes via SSH and runs modules directly on them without any agent software. However, the managed nodes must have Python 2.7 or Python 3 installed because modules are Python scripts.

**Can I use ad hoc commands to copy files from managed nodes to my control node?**

The `copy` module only copies files from the control node to managed nodes. To fetch files from managed nodes back to the control node, you must use the `fetch` module or a tool like `scp`. The `fetch` module is not commonly tested on EX294 for ad hoc commands, but you should know it exists.

**What happens if I run an ad hoc command and the module does not exist?**

Ansible will return an error stating the module was not found. You must use a module that is either built into Ansible (like the ones listed in this chapter) or installed as a collection. Built-in modules are always available. Check your module name spelling if you get this error.

**How do I pass multiple arguments to a module?**

Separate arguments with spaces inside the single-quoted string. For example: `ansible all -m yum -a 'name=httpd state=latest enablerepo=epel'`. Each key=value pair is separated by a space. Do not use commas or semicolons.

**Can I run an ad hoc command as a different user?**

Yes, use the `-u` flag followed by the username: `ansible all -m ping -u admin`. This tells Ansible to connect as `admin` instead of the current user. Combine with `--become` to escalate privileges after connecting as that user.

## Check your understanding

1. **Write an ad hoc command to check the status of the nginx service on all servers in the group 'web-servers'.**

   Answer: `ansible web-servers -m service -a 'name=nginx state=started'`

2. **What is the difference between `state=present` and `state=latest` for the yum module?**

   Answer: `state=present` ensures the package is installed but does not update it; `state=latest` ensures the package is installed and upgraded to the most recent version.

3. **Which module would you use to copy a file from your control node to managed nodes, and what is its basic syntax?**

   Answer: The `copy` module. Basic syntax: `ansible all -m copy -a 'src=/local/path dest=/remote/path'`.

4. **When should you use the `shell` module instead of the `command` module?**

   Answer: Use the `shell` module when you need shell features like pipes (|), redirects (>), or environment variables ($HOME). For simple commands without those, use `command`.

5. **What does the `ping` module actually do in Ansible?**

   Answer: It tests if Ansible can connect to the managed node via SSH and if Python is available on that node. It does not use ICMP ping. A successful connection returns a 'pong' message.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/redhat-rhce/ansible-modules-and-ad-hoc-commands
