Saturday, 6 December 2025

Ansible - 10. Adhoc command

Ansible ad hoc commands are great for tasks you repeat rarely. For example, if you want to power off all the machines in your lab for Christmas vacation, you could execute a quick one-liner in Ansible without writing a playbook. An ad hoc command looks like this:

$ ansible [pattern] -m [module] -a "[module options]"

inventory used for this exercise is,

[oracle@oel01db ansible-project]$ cat ./inventory/hosts
[db_servers]
192.168.0.156
[oracle@oel01db ansible-project]$
[root@oel02db ~]# hostname -i
192.168.0.156
[root@oel02db ~]#


1. Run a command as a specific SSH user

Run some command on all host 

[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -m ping
192.168.0.156 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
[oracle@oel01db ansible-project]$

Here all means , every host listed in the inventory file .

We can also specify a user if you want.

[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -u oracle  -m ping
192.168.0.156 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
[oracle@oel01db ansible-project]$


The default module for the ansible command-line utility is the ansible.builtin.command module

[oracle@oel01db ansible-project]$ ansible all -i inventory/hosts -m command -a "hostname"
192.168.0.156 | CHANGED | rc=0 >>
oel02db.mydb.com
[oracle@oel01db ansible-project]$

Above command is equivalent to ,

[oracle@oel01db ansible-project]$ ansible all -i inventory/hosts  -a "hostname"
192.168.0.156 | CHANGED | rc=0 >>
oel02db.mydb.com
[oracle@oel01db ansible-project]$

So If you do not specify -m , ansible will use the default module which is "command"

[oracle@oel01db ansible-project]$ ansible all -i inventory/hosts  -a "df -h"
192.168.0.156 | CHANGED | rc=0 >>
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             831M     0  831M   0% /dev
tmpfs                850M  1.1M  849M   1% /dev/shm
tmpfs                850M  9.4M  840M   2% /run
tmpfs                850M     0  850M   0% /sys/fs/cgroup
/dev/mapper/ol-root   36G   11G   26G  29% /
/dev/mapper/ol-u01    38G   33M   38G   1% /u01
/dev/sda1            1.9G  235M  1.7G  13% /boot
tmpfs                170M   12K  170M   1% /run/user/42
tmpfs                170M     0  170M   0% /run/user/0
tmpfs                170M     0  170M   0% /run/user/54321
[oracle@oel01db ansible-project]$
[oracle@oel01db ansible-project]$


2. Run as a user WITH privilege escalation (become)


[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -u oracle -b -m command -a "useradd demouser"
192.168.0.156 | CHANGED | rc=0 >>

Here -b stands for become (sudo) and by default become_user = root

[oracle@oel01db ansible-project]$ 

[oracle@oel01db ansible-project]$ ssh oel02db
Last login: Fri Dec  5 14:16:42 2025 from oel01db
[oracle@oel02db ~]$ id demouser
uid=54322(demouser) gid=54331(demouser) groups=54331(demouser)
[oracle@oel02db ~]$

[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -u oracle -b -m command -a "userdel demouser"
192.168.0.156 | CHANGED | rc=0 >>

[oracle@oel01db ansible-project]$
[oracle@oel01db ansible-project]$ ssh oel02db
Last login: Fri Dec  5 14:17:27 2025 from oel01db
[oracle@oel02db ~]$  id demouser
id: demouser: no such user
[oracle@oel02db ~]$

3. Run as a custom become user


[oracle@oel01db ansible-project]$ ansible  all -i ./inventory/hosts  -u oracle -b --become-user postgres -m command -a "psql --version"
192.168.0.156 | CHANGED | rc=0 >>
psql (PostgreSQL) 15.13
[oracle@oel01db ansible-project]$
[oracle@oel01db ansible-project]$ ssh postgres@192.168.0.156 
postgres@oel02db's password:
Last login: Wed Jul 30 02:51:15 2025
postgres@oel02db:~$ psql --version
psql (PostgreSQL) 15.13
postgres@oel02db:~$

4. Use other modules with -m (copy, ping, shell, file etc.)

[oracle@oel01db ansible-project]$ ansible  all -i ./inventory/hosts   -m copy -a "src=/etc/passwd dest=/tmp/passwdcpy mode=400"
192.168.0.156 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "156fbdff85f587ca530a8ef7328617db780908fb",
    "dest": "/tmp/passwdcpy",
    "gid": 54321,
    "group": "oinstall",
    "md5sum": "e55bc27acc7a0b0967cda8138c83fae3",
    "mode": "0400",
    "owner": "oracle",
    "size": 2666,
    "src": "/home/oracle/.ansible/tmp/ansible-tmp-1764925249.91-16590-272209402254394/source",
    "state": "file",
    "uid": 54321
}
[oracle@oel01db ansible-project]$

copy module’s src is ALWAYS from the controller machine, unless you set remote_src=yes .

[oracle@oel01db ansible-project]$ ansible  all -i ./inventory/hosts  -b -m copy -a "src=/etc/sudoers dest=/tmp/sudocopy mode=400"
192.168.0.156 | FAILED! => {
    "msg": "an error occurred while trying to read the file '/etc/sudoers': [Errno 13] Permission denied: '/etc/sudoers'"
}
[oracle@oel01db ansible-project]$


[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -b -m copy -a "src=/etc/sudoers dest=
 mode=400 remote_src=yes"
192.168.0.156 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "ba1f3b25864284f7c3263d58a10cfc5f066b1295",
    "dest": "/tmp/sudocopy",
    "gid": 0,
    "group": "root",
    "md5sum": "bbe8e958f79e54033ea95dbc3663a537",
    "mode": "0400",
    "owner": "root",
    "size": 4528,
    "src": "/etc/sudoers",
    "state": "file",
    "uid": 0
}
[oracle@oel01db ansible-project]$

[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -a "ls -lrt /tmp/sudocopy"
192.168.0.156 | CHANGED | rc=0 >>
-r-------- 1 root root 4528 Dec  5 12:37 /tmp/sudocopy
[oracle@oel01db ansible-project]$

✅ 5 . Some more example 

1)  How to reboot all the machine under dbserver group 

[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -m ansible.builtin.reboot --become


192.168.0.156 | CHANGED => {
    "changed": true,
    "elapsed": 76,
    "rebooted": true
}
[oracle@oel01db ansible-project]$

2) How to remove httpd 

[oracle@oel01db ansible-project]$  ansible all -i ./inventory/hosts -b -m yum -a "name=httpd state=absent"
192.168.0.156 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "changes": {
        "removed": [
            "httpd"
        ]
    },
    "msg": "",
    "rc": 0,
    "results": [
        "Loaded plugins: langpacks, ulninfo\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-99.0.5.el7_9.1 will be erased\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package     Arch         Version                       Repository         Size\n================================================================================\nRemoving:\n httpd       x86_64       2.4.6-99.0.5.el7_9.1          @ol7_latest       3.7 M\n\nTransaction Summary\n================================================================================\nRemove  1 Package\n\nInstalled size: 3.7 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Erasing    : httpd-2.4.6-99.0.5.el7_9.1.x86_64                            1/1 \n  Verifying  : httpd-2.4.6-99.0.5.el7_9.1.x86_64                            1/1 \n\nRemoved:\n  httpd.x86_64 0:2.4.6-99.0.5.el7_9.1                                           \n\nComplete!\n"
    ]
}
[oracle@oel01db ansible-project]$

3) How to create/drop user on managed node using user module 

[oracle@oel01db ansible-project]$  ansible all -i ./inventory/hosts -b -m ansible.builtin.user -a "name=foo password=foo123"
[WARNING]: The input password appears not to have been hashed. The 'password' argument must be encrypted for this module to work properly.
192.168.0.156 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "comment": "",
    "create_home": true,
    "group": 54331,
    "home": "/home/foo",
    "name": "foo",
    "password": "NOT_LOGGING_PASSWORD",
    "shell": "/bin/bash",
    "state": "present",
    "system": false,
    "uid": 54322
}
[oracle@oel01db ansible-project]$
[oracle@oel01db ansible-project]$  ansible all -i ./inventory/hosts -b -m ansible.builtin.user -a "name=foo state=absent"
192.168.0.156 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "force": false,
    "name": "foo",
    "remove": false,
    "state": "absent"
}
[oracle@oel01db ansible-project]$

5) How to start httpd service 

ansible all -i ./inventory/hosts -b  -m ansible.builtin.service -a "name=httpd state=started"

6) ansible.builtin.setup is a built-in Ansible module that is used to gather facts about remote hosts.

[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -b  -m  ansible.builtin.setup | grep -i family
        "ansible_os_family": "RedHat",
[oracle@oel01db ansible-project]$

or
[oracle@oel01db ansible-project]$ ansible all -i ./inventory/hosts -b  -m  ansible.builtin.setup -a "filter=ansible_os_family"
192.168.0.156 | SUCCESS => {
    "ansible_facts": {
        "ansible_os_family": "RedHat",
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
[oracle@oel01db ansible-project]$



No comments:

Post a Comment

Building a Safer PostgreSQL CI/CD Pipeline with GitHub Actions: Dev → PR Review → Test Promotion

In my previous post, we explored a simple push-to-main deployment strategy . While functional, that model is not considered an industry best...