Ansible Inventory Management: From Basics to Advanced Usage (Part 4)

Ansible Inventory

The inventory is used to define which hosts are managed by Ansible. The inventory supports the following formats:

  • • IP addresses
  • • Hostnames
  • • Ranges (<span>server[b:c]</span>)
  • • Host groups (<span>webserver</span>)
  • • Subgroups (<span>lnmp:children</span>)

Inventory

172.25.250.10

[webserver]
server[b:c]

[mysql]
172.25.250.1[3:4]

[lnmp:children]
webserver
mysql
  • • Directly defining a hostname or address, currently <span>172.25.250.10</span> does not belong to any group.
172.25.250.10
  • • Defining a host group, the <span>webserver</span> group includes <span>serverb</span> to <span>serverc</span>
[webserver]
server[b:c]
  • • Groups can be nested
[lnmp:children]
webserver
mysql
  • • Using ranges to match hosts
server[b:c]
172.25.250.1[3:4]

Selecting Hosts and Host Groups

Matching All Hosts

ansible all --list-hosts
  hosts (5):
    172.25.250.10
    serverb
    serverc
    172.25.250.13
    172.25.250.14

Matching Specific Hosts or Host Groups

ansible serverc --list-hosts
  hosts (1):
    serverc

ansible lnmp --list-hosts
  hosts (4):
    serverb
    serverc
    172.25.250.13
    172.25.250.14

Matching Multiple Hosts and Host Groups

ansible serverb,serverc --list-hosts
  hosts (2):
    serverb
    serverc

ansible webserver,mysql --list-hosts
  hosts (4):
    serverb
    serverc
    172.25.250.13
    172.25.250.14

Matching Ungrouped Hosts

ansible ungrouped --list-hosts
  hosts (1):
    172.25.250.10

Using Wildcards to Select Hosts

ansible server* --list-hosts
  hosts (2):
    serverb
    serverc

ansible *25.* --list-hosts
  hosts (3):
    172.25.250.10
    172.25.250.13
    172.25.250.14

Wildcard Logical Combinations

  • <span>&</span>: Intersection
  • <span>!</span>: Negation
  • <span>,</span>: Union
# Match all hosts starting with server, excluding serverc
ansible 'server*,!serverc' --list-hosts
  hosts (1):
    serverb

# Match hosts common to both groups webserver and lnmp
ansible 'webserver,&amp;lnmp' --list-hosts
  hosts (2):
    serverb
    serverc

# Exclude serverc in the previous example
ansible 'webserver,&amp;lnmp,!serverc' --list-hosts
  hosts (1):
    serverb

Using Regular Expressions for Matching

# '~' followed by a regex, the example below matches hosts starting with se
ansible '~^se' --list-hosts
  hosts (2):
    serverb
    serverc

Matching Hosts with Limit

ansible all --limit serverb,172.25.250.13 --list-hosts
  hosts (2):
    serverb
    172.25.250.13

# Using file matching
cat &lt;&lt;EOF &gt; ip.txt
serverb
serverc
172.25.250.14
EOF

ansible all --limit @/home/student/ansible/ip.txt --list-hosts
  hosts (3):
    serverb
    serverc
    172.25.250.14

Special Host: localhost

Finally, let’s talk about a special host <span>localhost</span>, which is a special host that can be used without being declared in the inventory.

<span>localhost</span> refers to the local machine, and when not declared in the inventory, Ansible will connect using <span>local</span>, which is equivalent to executing commands locally. Below is the difference between it and SSH connection:

Item local ssh
Execution Location Executed locally on the control node Executed remotely via ssh
Network Usage No Yes
Permission Control Current user Can specify remote user
Common Use Cases Control node configuration, local debugging Production environments, managing multiple hosts

You can explicitly specify <span>localhost</span> in the inventory to set the connection method to <span>ssh</span>.

<span>local</span> and <span>ssh</span> connections have one major difference: <span>local</span> will ignore the <span>remote_user</span> option, as shown in the following example:

# Configuration file
[test@awx-1 ansible]$ cat ansible.cfg
[defaults]
inventory      = ./inventory
fork          = 20
ask_pass       = False
remote_user    =  remote-manager
host_key_checking = False
ansible_python_interpreter = /usr/bin/python3.9
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

# Current user
[test@awx-1 ansible]$ id
uid=1000(test) gid=1000(test) groups=1000(test) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

# View inventory, current localhost is commented out
[test@awx-1 ansible]$ cat inventory
#localhost ansible_ssh_password=redhat

# Test
[test@awx-1 ansible]$ ansible localhost -b -m command -a 'id'
localhost | CHANGED | rc=0 &gt;&gt;
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
# It can be seen that it executed successfully

# Remove the comment from the inventory
[test@awx-1 ansible]$ cat inventory
localhost ansible_ssh_password=redhat

# Test again
[test@awx-1 ansible]$ ansible localhost -b -m command -a 'id'
localhost | UNREACHABLE! =&gt; {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: remote-manager@localhost: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password,keyboard-interactive).",
    "unreachable": true
}
# It can be seen that an error occurred because test cannot directly ssh as remote-manager user

It can be seen that the <span>local</span> method ignores the <span>remote_user</span> option, while <span>ssh</span> does not.

Leave a Comment