Bookmark this page

Chapter 5.  Managing Inventories

Abstract

Goal

Manage inventories by using advanced features of Ansible.

Objectives
  • Describe what dynamic inventories are, and install and use an existing script or plug-in as an Ansible dynamic inventory source.

  • Write static inventory files in YAML format.

  • Structure host and group variables by using multiple files per host or group, and use special variables to override the host, port, or remote user that Ansible uses for a specific host.

Sections
  • Managing Dynamic Inventories  (and Guided Exercise)

  • Writing YAML Inventory Files  (and Guided Exercise)

  • Managing Inventory Variables  (and Guided Exercise)

Lab
  • Managing Inventories

Managing Dynamic Inventories

Objectives

  • Describe what dynamic inventories are, and install and use an existing script or plug-in as an Ansible dynamic inventory source.

Generating Inventories Dynamically

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

Inventory Plug-ins

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.

Using Inventory Plug-ins

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.foreman   1
url: https://satellite.example.com 2
user: ansibleinventory
password: Sup3r53cr3t
host_filters: 'organization="Development"' 3

1

The required plugin keyword indicates which plug-in to use. You must provide its fully qualified collection name (FQCN).

2

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.

3

Some plug-ins provide mechanisms to filter the list of hosts. This example uses the host_filters parameter to only retrieve the hosts in the Development Red Hat Satellite organization.

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 source

Notice 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.yml

Remember 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:

  1. If the file is executable, then Ansible uses it as an inventory script, as described in the following section.

  2. Otherwise, Ansible tries to parse the given file as a configuration file for inventory plug-ins.

  3. 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.

Developing Inventory Scripts

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.

Important

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 inventory
monitor.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 managed-host options.

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 managed-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.

[user@host ~]$ ./inventoryscript --host server5.example.com
{
    "ntpserver": "ntp.example.com",
    "dnsserver": "dns.example.com"
}

Note

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.

Using Inventory Scripts

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.yml

Managing Multiple Inventories

Ansible 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.

Important

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.

Revision: do374-2.2-82dc0d7