PL - 001 — Installation ansible-core and Ad-hoc commands

Ansible Ad-Hoc Commands

Ansible ad-hoc commands are quick, one-line commands executed from the control node using the ansible command-line tool.

They are useful for performing a single task across one or more managed hosts without writing a reusable Ansible playbook.

Ad-hoc commands are particularly useful for:

  • Testing connectivity to managed hosts
  • Gathering system information
  • Managing users and groups
  • Managing files and directories
  • Installing or removing packages
  • Starting, stopping, or restarting services
  • Executing commands on multiple hosts
  • Performing quick administrative tasks

1. Basic Syntax

The general syntax of an Ansible ad-hoc command is:

   ansible <host-pattern> -m <module-name> -a "<module-arguments>" [options]
<pattern>	     --->  Specifies which managed hosts should be targeted
-m	             --->  Specifies the Ansible module to use
<module>	     --->  The module that performs the task
-a	             --->  Provides arguments to the module
<module arguments>   --->  Parameters required by that module

 # Install required packages on the Control Node
 
[cnode@control-node ~]$ hostname
control-node

[cnode@control-node ~]$ hostname -I
192.168.254.15 

[cnode@control-node ~]$ rpm -q ansible-core
package ansible-core is not installed

[cnode@control-node ~]$ ls /etc/yum.repos.d/
centos-addons.repo  centos.repo

[cnode@control-node ~]$ su - root
...

[root@control-node ~]# dnf install -y ansible-core
...
Installed:
  ansible-core-1:2.16.19-2.el10.noarch     git-core-2.52.0-1.el10.x86_64             python3-cffi-1.16.0-7.el10.x86_64       python3-cryptography-49.0.0-1.el10.x86_64   
  python3-jinja2-3.1.6-1.el10.noarch       python3-markupsafe-2.1.3-6.el10.x86_64    python3-packaging-24.2-2.el10.noarch    python3-ply-3.11-25.el10.noarch             
  python3-pycparser-2.20-16.el10.noarch    python3-resolvelib-1.0.1-6.el10.noarch   

Complete!
[root@control-node ~]# 

[root@control-node ~]# rpm -q ansible-core
ansible-core-2.16.19-2.el10.noarch

[root@control-node ~]# which ansible-core
/usr/bin/which: no ansible-core in (/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin)
[root@control-node ~]# ansible --version
ansible [core 2.16.19]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.12/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.12.13 (main, Apr 16 2026, 00:00:00) [GCC 14.3.1 20251022 (Red Hat 14.3.1-4)] (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True
[root@control-node ~]# 

[root@control-node ~]# exit
logout
[cnode@control-node ~]$ whoami
cnode
[cnode@control-node ~]$ hostname
control-node
[cnode@control-node ~]$ 

[cnode@control-node ~]$ ls
validate_nodes.sh
[cnode@control-node ~]$ ./validate_nodes.sh
----- dev1 -----
dev1
root

----- dev2 -----
dev2
root

----- testserver -----
testserver
root

----- prodserver -----
prodserver
root

[cnode@control-node ~]$ 

# Create ansible project

[cnode@control-node ~]$ mkdir ansible-lab

[cnode@control-node ~]$ cd ansible-lab/

[cnode@control-node ansible-lab]$ vi inventory

[cnode@control-node ansible-lab]$ cat inventory
192.168.254.16
192.168.254.17
192.168.254.18
192.168.254.19
[cnode@control-node ansible-lab]$
[cnode@control-node ansible-lab]$ cat /etc/hosts
# Loopback entries; do not change.
# For historical reasons, localhost precedes localhost.localdomain:
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# See hosts(5) for proper format and other examples:
# 192.168.1.10 foo.example.org foo
# 192.168.1.13 bar.example.org bar

# add IPs for 5 nodes
192.168.254.15 control-node
192.168.254.16 dev1
192.168.254.17 dev2
192.168.254.18 testserver
192.168.254.19 prodserver
[cnode@control-node ansible-lab]$

[cnode@control-node ansible-lab]$ vim inventory 

[cnode@control-node ansible-lab]$ cat inventory 
[develop]
dev1
dev2

[test]
testserver

[production]
prodserver

[all:vars]
ansible_user=cnode
ansible_become=true
ansible_become_method=sudo
[cnode@control-node ansible-lab]$ vim inventory 

[cnode@control-node ansible-lab]$ cat inventory 
[develop]
dev1 ansible_host=192.168.254.16
dev2 ansible_host=192.168.254.17

[test]
testserver

[production]
prodserver

[all:vars]
ansible_user=cnode
ansible_become=true
ansible_become_method=sudo
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ vim inventory 

[cnode@control-node ansible-lab]$ cat inventory 
[develop]
dev1
dev2

[test]
testserver

[production]
prodserver

[all:vars]
ansible_user=cnode
ansible_become=true
ansible_become_method=sudo
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ls
inventory
[cnode@control-node ansible-lab]$ ansible-inventory --graph
@all:
  |--@ungrouped:
[cnode@control-node ansible-lab]$ ansible-inventory -i inventory --graph
@all:
  |--@ungrouped:
  |--@develop:
  |  |--dev1
  |  |--dev2
  |--@test:
  |  |--testserver
  |--@production:
  |  |--prodserver
  
[cnode@control-node ansible-lab]$ ansible all -i inventory -m ping
testserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
dev2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
prodserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
dev1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ansible develop -i inventory -m ping
dev1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
dev2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
[cnode@control-node ansible-lab]$ ansible test -i inventory -m ping
testserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
[cnode@control-node ansible-lab]$

[cnode@control-node ansible-lab]$ pwd
/home/cnode/ansible-lab
[cnode@control-node ansible-lab]$ ansible develop -i inventory --list-hosts
  hosts (2):
    dev1
    dev2
[cnode@control-node ansible-lab]$ ansible production -i inventory --list-hosts
  hosts (1):
    prodserver
[cnode@control-node ansible-lab]$ ansible all -i inventory --list-hosts
  hosts (4):
    dev1
    dev2
    testserver
    prodserver
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ansible test,production -i inventory --list-hosts
  hosts (2):
    testserver
    prodserver
[cnode@control-node ansible-lab]$

 # Creating Ansible config file
 
[cnode@control-node ansible-lab]$ ls
inventory
[cnode@control-node ansible-lab]$ pwd
/home/cnode/ansible-lab
[cnode@control-node ansible-lab]$ vim ansible.cfg
[cnode@control-node ansible-lab]$ ls
ansible.cfg  inventory
[cnode@control-node ansible-lab]$ cat ansible.cfg 
[defaults]
inventory=/home/cnode/ansible-lab/inventory
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ansible develop --list-hosts
  hosts (2):
    dev1
    dev2
[cnode@control-node ansible-lab]$ ansible all --list-hosts
  hosts (4):
    dev1
    dev2
    testserver
    prodserver
    
[cnode@control-node ansible-lab]$ ansible all -m ping
dev2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
prodserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
testserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
dev1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
[cnode@control-node ansible-lab]$   

[cnode@control-node ansible-lab]$ ansible --version
ansible [core 2.16.19]
  config file = /home/cnode/ansible-lab/ansible.cfg
  configured module search path = ['/home/cnode/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.12/site-packages/ansible
  ansible collection location = /home/cnode/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.12.13 (main, Apr 16 2026, 00:00:00) [GCC 14.3.1 20251022 (Red Hat 14.3.1-4)] (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ls /etc/ansible/
ansible.cfg  hosts  roles
[cnode@control-node ansible-lab]$

[cnode@control-node ansible-lab]$ cat /etc/ansible/ansible.cfg 
# Since Ansible 2.12 (core):
# To generate an example config file (a "disabled" one with all default settings, commented out):
#               $ ansible-config init --disabled > ansible.cfg
#
# Also you can now have a more complete file by including existing plugins:
# ansible-config init --disabled -t all > ansible.cfg

# For previous versions of Ansible you can check for examples in the 'stable' branches of each version
# Note that this file was always incomplete  and lagging changes to configuration settings

# for example, for 2.9: https://github.com/ansible/ansible/blob/stable-2.9/examples/ansible.cfg
[cnode@control-node ansible-lab]$

Getting help of Ansible modules

[cnode@control-node ansible-lab]$ ansible-doc user

[cnode@control-node ansible-lab]$ ansible-doc ansible.builtin.user
...
/EXAMPLES
...
:q

[cnode@control-node ansible-lab]$ vi ansible.cfg 
[cnode@control-node ansible-lab]$ cat ansible.cfg 
[defaults]
inventory=/home/cnode/ansible-lab/inventory
remote_user=cnode
[cnode@control-node ansible-lab]$ vi ansible.cfg 
[cnode@control-node ansible-lab]$ vim ansible.cfg 
[cnode@control-node ansible-lab]$ cat ansible.cfg 
[defaults]
inventory=/home/cnode/ansible-lab/inventory
remote_user=cnode

[privilege_escalation]
become=true
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ansible test -m ansible.builtin.user -a 'name=testuser'
testserver | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "comment": "",
    "create_home": true,
    "group": 1001,
    "home": "/home/testuser",
    "name": "testuser",
    "shell": "/bin/bash",
    "state": "present",
    "system": false,
    "uid": 1001
}
[cnode@control-node ansible-lab]$ 

[cnode@control-node ansible-lab]$ ansible test -m ansible.builtin.user -a 'name=testuser'
testserver | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "append": false,
    "changed": false,
    "comment": "",
    "group": 1001,
    "home": "/home/testuser",
    "move_home": false,
    "name": "testuser",
    "shell": "/bin/bash",
    "state": "present",
    "uid": 1001
}
[cnode@control-node ansible-lab]$ 

# In managed node: testserver

[cnode@testserver ~]$ grep testuser /etc/passwd
testuser:x:1001:1001::/home/testuser:/bin/bash
[cnode@testserver ~]$