Ansible - Inventory, Variables, and Modules (Part 2.1 of 14)

Welcome to part 2 of my Ansible series. If this is your first time here, you might consider starting with part 1 I’ve broken this part into two post to make it easier to consume. Part 2 will cover inventory, variables, modules and plays. These components are critical to understanding how Ansible works and the components of playbooks. This part covers mostly oncepts with supporting examples. When we get to Ad-hoc Ansible examples, we’ll get to see Ansible in action. So without further ado, lets get started.

Inventory

Ansible needs to know what hosts to execute modules against. This list of hosts is called an inventory file. It’s a flat text file format, but does support some grouping and organization options. Here’s a simple sample.

1
2
3
4
5
6
7
8
9
10
11
12
13
webserver1.softwarecorp.com
webserver2.softwarecorp.com
devwebserver1.softwarecorp.com
devwebserver2.softwarecorp.com
sql1.softwarecorp.com
devsql1.softwarecorp.com
appserver1.softwarecorp.com
appserver2.softwarecorp.com
devappserver1.softwarecorp.com
devappserver2.softwarecorp.com
mail.softwarecorp.com
dc1.softwarecorp.com
dc2.softwarecorp.com

Our simple sample has 13 hosts without any organiation. This is simpe enough to start running ad-hoc ansible commands against, but what it can’t do is target a specific server or specific servers. What we need is a bit more organization to our inventory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[web_servers]
webserver1.softwarecorp.com
webserver2.softwarecorp.com
devwebserver1.softwarecorp.com
devwebserver2.softwarecorp.com
[database_servers]
sql1.softwarecorp.com
devsql1.softwarecorp.com
[app_servers]
appserver1.softwarecorp.com
appserver2.softwarecorp.com
devappserver1.softwarecorp.com
devappserver2.softwarecorp.com
[mail_server]
mail.softwarecorp.com
[domain_controllers]
dc1.softwarecorp.com
dc2.softwarecorp.com
[production_servers]
webserver1.softwarecorp.com
webserver2.softwarecorp.com
sql1.softwarecorp.com
appserver1.softwarecorp.com
appserver2.softwarecorp.com
[dev_servers]
devwebserver1.softwarecorp.com
devwebserver2.softwarecorp.com
devsql1.softwarecorp.com
devappserver1.softwarecorp.com
devappserver2.softwarecorp.com

Well that looks a lot better. We have a bunch of meaningful groups, but you’ll notice in the above example that a number of hosts that exist in multiple groups. Ansible support is perfectly happy with this, but can result in some unexpected behavior related to variables (we’ll cover these later in this post). While the above is a functional inventory file, odds are we don’t really want to repeat hostnames across multiple groups as this leads to added maintenance costs and possibility of maintenance errors. Luckily Ansible supports groups within groups.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[prodweb_servers]
webserver1.softwarecorp.com
webserver2.softwarecorp.com
[devweb_servers]
devwebserver1.softwarecorp.com
devwebserver2.softwarecorp.com
[proddatabase_servers]
sql1.softwarecorp.com
[devdatabase_servers]
devsql1.softwarecorp.com
[prodapp_servers]
appserver1.softwarecorp.com
appserver2.softwarecorp.com
[devapp_servers]
devappserver1.softwarecorp.com
devappserver2.softwarecorp.com
[mail_server]
mail.softwarecorp.com
[domain_controllers]
dc1.softwarecorp.com
dc2.softwarecorp.com
[production_servers:children]
prodweb_servers
prodapp_servers
proddatabase_servers
[dev_servers:children]
devweb_servers
devapp_servers
devdatabase_servers
[webserver:children]
prodweb_servers
devweb_servers
[appserver:children]
prodapp_servers
devapp_servers
[databaseserver:children]
proddatabase_servers
devdatabase_servers

While this looks a bit more complex, it is actually far easier to maintain and use. If you have a new server, or retire a server, you simple add or remove the hostname from the appropriate group and the associated groups are automatically updated when used. It does require some up front planning and organization when setting up groups. Ansible can also handle multiple inventory files, which allows you to create separate inventory files which aids when maintaining larger inventories. Ansible allows you to specify multiple inventory files via passing -i followed by a comma separated list of inventory files.

1
ansible -i /etc/ansilbe/inventory/databases,/etc/ansible/webservers

Note: Groups can have multiple parents and multiple children, but cannot have circular relationships.

In the real work, especially in a large enterprise, it’s unlikely that you are going to want to maintain large inventories by hand. It’s not easily maintained, it doesn’t scale and has a high risk of being inaccurate. In addition, complex grouping can become challenging to maintain properly. Fortunately, ansible has the concept of dynamic inventory.

Dynamic Inventory

Ansible provides a method for gathering inventory from various cloud providers, LDAP, Cobbler, or enterprise CMDB (Configuration Management database) software. To use dynamic inventory, you specify a path to a script file that when executed returns inventory information in a JSON format instead of passing a path to an inventory file. Ansible ships with a number of provider scripts for systems like EC2/Eucalyptus, Rackspace Cloud, and OpenStack. Each of these require some initial setup and can be used along with parameter’s to generate inventory files with just the hosts you want. Here’s a couple of example calls for cobbler, Amazon EC2 and Openstack.

1
2
3
ansible webserver -m ping
ansible -i ec2.py -u ubuntu us-east-1d -m ping
ansible -i openstack.py all -m ping

Setting up these dynamic inventory providers is a bit out of the scope of this article and outside my experience. More information about dynamic inventory and examples can be found in Ansible’s documentation as well as documentation on how to create your own custom dynamic inventory source

Another option is to create inventory files thought an ansible module. This gives a great deal of flexibility to create inventory files with just the hosts and variables needed. It also allows you to check the content and helps troubleshooting. This is the method my company has gone with as we interfacing with a custom CMDB (and different instances of the CMBD) and operate across multiple datacenters. We’ll cover building modules in part 12

Lastly there are 2 built in groups: all and ungrouped. All contains all hosts while ungrouped contains only hosts that are not defined in a group.

The second post of part 2 will cover Host and Group Variables, Modules and Plays. Click here to continue