Abstract
| Goal |
Manage inventories by using advanced features of Ansible. |
| Objectives |
|
| Sections |
|
| Lab |
|
Describe what dynamic inventories are, and install and use an existing script or plug-in as an Ansible dynamic inventory source.
The static inventory files you have worked with so far are easy to write and are convenient for managing small infrastructures. However, these static lists require manual administration to keep them up-to-date. This can be inconvenient or challenging, especially when an organization wants to run the playbooks against hosts that are dynamically created in a virtual or cloud computing environment.
In that scenario, it is useful to use a dynamically generated inventory.
Dynamic inventories are scripts which, when run, dynamically determine which hosts and host groups should be in the inventory, based on information from an external source. These can include the API for cloud providers, Cobbler, LDAP directories, or other third-party configuration management database (CMDB) software. Using a dynamically generated inventory is a recommended practice in a large and rapidly changing IT environment, where systems are frequently deployed, tested, and then removed.
Ansible supports two types of dynamically generated inventories:
Inventory plug-ins
Inventory scripts
An inventory plug-in is a piece of Python code that generates an inventory object from a dynamic source. Ansible ships with inventory plug-ins for a number of external inventory sources, including:
Amazon Web Services EC2
Google Compute Engine
Microsoft Azure Resource Manager
Red Hat OpenStack Platform
VMware vCenter
Red Hat Satellite 6
Red Hat Virtualization
Red Hat OpenShift
Ansible provides inventory plug-ins through Ansible Content Collections. Third-party content collections provide additional inventory plug-ins for specific products.
Developing inventory plug-ins is beyond the scope of this course.
For most inventory plug-ins you must prepare a configuration file in YAML format. This configuration file usually provides the connection parameters that the plug-in requires to access the external source.
For example, the following satellite.yml configuration file provides the connection parameters to access a Red Hat Satellite Server installation.
plugin: redhat.satellite.foremanurl: https://satellite.example.com
user: ansibleinventory password: Sup3r53cr3t host_filters: 'organization="Development"'
The required | |
The connection parameters are specific to the plug-in. This example provides the Red Hat Satellite Server URL, the username, and the password to use to access the API endpoint. | |
Some plug-ins provide mechanisms to filter the list of hosts.
This example uses the |
Every inventory plug-in has documentation with examples.
You can access that documentation with the ansible-navigator doc command.
Use the --type inventory (or -t inventory) option to look up documentation for inventory plug-ins.
Use the --list (or -l) option to list all the inventory plug-ins available in your automation execution environment:
[user@host ~]$ ansible-navigator doc --mode stdout --type inventory --list
...output omitted...
ini Uses an Ansible INI file as inventory source
script Executes an inventory script that returns JSON
redhat.satellite.foreman Foreman inventory source
toml Uses a specific TOML file as an inventory source
yaml Uses a specific YAML file as an inventory sourceNotice that the command only lists the plug-ins from installed Ansible Content Collections.
By default, those are the content collections installed in the execution environment, or the collections in the directories you define in your ansible.cfg configuration file by setting the collections_paths directive.
To access the documentation for a specific plug-in, use the ansible-navigator doc command and provide the FQCN for the plug-in as an argument:
[user@host ~]$ansible-navigator doc --mode stdout --type inventory \>redhat.satellite.foreman
To run a playbook that targets hosts in that dynamic inventory, use the ansible-navigator run command with the --inventory (or -i) option to provide the plug-in configuration file:
[user@host ~]$ ansible-navigator run --inventory ./satellite.yml my_playbook.ymlRemember that you also use that same option for static inventory files.
Because Ansible uses the --inventory option for different inventory formats, it parses the file you provide in the following order by default:
If the file is executable, then Ansible uses it as an inventory script, as described in the following section.
Otherwise, Ansible tries to parse the given file as a configuration file for inventory plug-ins.
If that fails, then Ansible uses the file as a static inventory file.
You can control that order by setting the enable_plugins directive under the inventory section in your ansible.cfg configuration file.
An inventory script is a program that collects information from an external source and returns the inventory in JSON format. You can write the custom program in any programming language as long as it returns inventory information in JSON format.
Red Hat recommends developing inventory plug-ins instead of inventory scripts.
Use inventory scripts when you already have legacy scripts that you want to reuse or when you do not want to use Python for your development.
The ansible-navigator inventory command is a helpful tool for learning how to write Ansible inventories in JSON format.
This command takes an inventory file and returns it in JSON format.
To display the contents of an inventory file in JSON format, use the --list option.
You can also add the --inventory (or -i) option to specify the location of the inventory file to process instead of the default inventory set by the current Ansible configuration.
The following example runs the ansible-navigator inventory command to process an inventory file in INI format and output it in JSON format.
[user@host ~]$cat inventorymonitor.example.com [webservers] web1.example.com web2.example.com [databases] db1.example.com db2.example.com [user@host ~]$ansible-navigator inventory --mode stdout -i inventory --list{ "_meta": { "hostvars": {} }, "all": { "children": [ "databases", "ungrouped", "webservers" ] }, "databases": { "hosts": [ "db1.example.com", "db2.example.com" ] }, "ungrouped": { "hosts": [ "monitor.example.com" ] }, "webservers": { "hosts": [ "web1.example.com", "web2.example.com" ] } }
To develop your own dynamic inventory script, refer to Inventory scripts in the Ansible Developer Guide.
Start the script with an appropriate interpreter line (for example, #!/usr/bin/python) and make sure that it is executable so that Ansible can run it.
The script must support the --list and --host options.managed-host
When called with the --list option, the script must print a JSON dictionary of all the hosts and groups in the inventory.
In its simplest form, a group is a list of managed hosts.
In the following example, the webservers group includes the web1.example.com and web2.example.com hosts.
The databases group includes the db1.example.com and db2.example.com hosts.
[user@host ~]$ ./inventoryscript --list
{
"webservers": [ "web1.example.com", "web2.example.com" ],
"databases": [ "db1.example.com", "db2.example.com" ]
}Alternatively, each group value can be a JSON dictionary containing a list of managed hosts, a list of child groups, and group variables that might be set.
The following example shows the JSON output for a more complex dynamic inventory.
The boston group has two child groups, backup and ipa, three managed hosts, and a group variable set (example_host: false).
{
"boston": {
"children": [
"backup",
"ipa"
],
"vars": {
"example_host": false
},
"hosts": [
"server1.example.com",
"server2.example.com",
"server3.example.com"
]
},
"backup": [
"server4.example.com"
],
"ipa": [
"server5.example.com"
]
}The script must also support the --host option.
When you run the script with that option, it must print a JSON dictionary consisting of the variables associated with the host, or an empty JSON dictionary if there are no variables for that host.managed-host
[user@host ~]$ ./inventoryscript --host server5.example.com
{
"ntpserver": "ntp.example.com",
"dnsserver": "dns.example.com"
}For each host in the inventory, Ansible calls the script with the --host option to retrieve the host variables.
When the inventory is very long, calling the script for each host can consume a lot of time and system resources.
To improve performance, you can directly provide the variables for all the hosts when the script is called with the --list option.
To do so, the script must return a top-level element called _meta, which lists all the hosts and their variables.
In that case, Ansible does not make the --host calls.
See the Tuning the External Inventory Script documentation for more information.
You use dynamic inventory scripts just like static inventory text files.
Specify the location of the inventory script either in the ansible.cfg file or by using the --inventory (or -i) option.
If the inventory file is executable, then Ansible treats it as a dynamic inventory program and attempts to run it to generate the inventory. If the file is not executable, then Ansible treats it as a static inventory.
[user@host ~]$ ansible-navigator run --inventory ./inventoryscript my_playbook.ymlAnsible supports the use of multiple inventories in the same run.
If the location of the inventory is a directory (whether set by the -i option, the value of the inventory parameter, or in some other way), then all inventory files included in the directory, either static or dynamic, are combined to determine the inventory.
The executable files within that directory are used to retrieve dynamic inventories, and the other files are used as static inventories or configuration files for inventory plug-ins.
Inventory files should not depend on other inventory files or scripts in order to resolve.
For example, if a static inventory file specifies that a particular group should be a child of another group, then it also needs to have a placeholder entry for that group, even if all members of that group come from the dynamic inventory.
Consider the cloud-east group in the following example:
[cloud-east] [servers] test.example.com [servers:children] cloud-east
This ensures that no matter the order in which inventory files are parsed, they are all internally consistent.
The order in which inventory files are parsed is not specified by the documentation. Currently, when multiple inventory files exist, they are parsed in alphabetical order. If one inventory source depends on information from another inventory source, then the order in which they are loaded determines if the inventory file works as expected or throws an error. Therefore, it is important to make sure that all files are self-consistent to avoid unexpected errors.
Ansible ignores files in an inventory directory if they end with certain suffixes.
This can be controlled with the inventory_ignore_extensions directive in the Ansible configuration file.
That directive defaults to .pyc, .pyo, .swp, .bak, ~, .rpm, .md, .txt, .rst, .orig, .ini, .cfg, and .retry.