Get more flexibility with the constructed inventory feature
The Scenario
You might remember the concept of Smart Inventories. They allowed us to create inventories over multiple inventory sources and optionally combine them with some built-in filters. However, smart inventories also had some severe limitations, most notably, smart inventories lost host group membership information.
Therefore, the concept of smart inventories, although still available in automation execution, is deprecated and replaced by constructed inventories. They are far more flexible and of course, they maintain the group membership information of your hosts.
If you’ve skipped any of the previous chapters, run cd ~/playbooks-adv-controller && ansible-navigator run add-dyn-inventory.yml in a terminal to set the pre-requisites for the next steps.
|
Create a basis
Let’s create our first constructed inventory:
-
Access your AAP UI from the AAP tab in Showroom, or open https://MYCTLHOST.apps.ocpvdev01.rhdp.net in a browser tab.
-
Log in as
MYCTLUSERwith passwordMYCTLPASSWORD(if not already done). -
Open .
-
Click ⊕ Create inventory, then choose Create constructed inventory.
-
Name:
Constructed Inventory -
Organization:
Default -
Open the Input Inventories drop-down and select:
-
Cloud inventory
-
Lab inventory
-
-
Close the drop-down list by clicking on an empty area of the UI.
-
In Source variables, add the following:
--- plugin: ansible.builtin.constructed strict: falseThe first line informs the automation execution that we want to use the constructed inventory plugin. The strict setting set to "false" allows us to use variables later, which don’t have to be defined. With strict set to "true" automation execution will fail to parse the constructed inventory, if a variable is not defined for any particular host.
-
-
Click Create inventory.
Now while in the details view of the Constructed Inventory:
-
Click Sync inventory.
-
After the sync has finished, open the Hosts tab of the Constructed inventory. You should see all hosts from the
Cloud inventoryand theLab inventorycombined. -
In the Groups tab you should also see a group called
dyngroupwhich was imported from our dynamic inventoryCloud inventory.
Add Compose
In historically grown environments you often have the problem that your inventory source has some legacy information, which you want to beautify or have to fix so Ansible can actually reach the remote host. In our first example, let’s assume you have an inventory source which returns some hostnames with upper case characters. To make everything work smoothly, we want all fully qualified domain names to be converted to lower case characters.
Let’s expand our configuration to the following, edit again the Source variables of the Constructed Inventory to look as follows:
---
plugin: ansible.builtin.constructed
strict: false
compose:
ansible_host: inventory_hostname | lower()
When connecting to a remote host Ansible is using the ansible_host variable - this is different from the inventory_hostname which is what we for example see in the UI when we click on Hosts.
|
Click Save inventory, then Sync inventory, to apply the constructed inventory.
After the sync has completed, check the Hosts tab.
You should see a host CLOUD3.cloud.example.com and if you click on it, you will see it has a variable ansible_host with the FQDN converted to lower case characters.
Add Groups
Many organizations use a strict naming convention for hostnames. Often a hostname indicates the purpose and the stage of a given system. In our case we have a couple of hosts which are in the prod and in the dev sub domain. We can use this information to automatically add the hosts to the respective group. Let’s extend our constructed inventory configuration.
-
Open again.
-
Edit Constructed Inventory using the pencil icon on the right.
-
Replace Source variables with the following:
--- plugin: ansible.builtin.constructed strict: false compose: ansible_host: inventory_hostname | lower() groups: production: inventory_hostname is search('prod') development: inventory_hostname is search('dev') -
Click Save inventory and Sync inventory again.
-
When you navigate to the Hosts tab of the
Constructed Inventory, you should not notice any difference. -
However, in the Groups tab you should see two new groups
developmentandproductionand you should find the respective hosts in those groups.
Add Keyed Groups
In this last example we want to use host variables to automatically add systems to specific groups. Instead of hard coding the group names, we want to use the value of the variables as group names.
Let’s assume your systems have a variable architecture with the CPU architecture (like ARM and x86_64) and a variable type showing the role of the system (web or database). Instead of manually assigning these groups, we can use the value of these variables. An added benefit of this approach is, if you ever introduce new CPU architectures or roles, the groups will automatically update accordingly.
As an example here are the variables assigned to host cloud1.cloud.example.com:
{
"ansible_host": "cloud1.cloud.example.com",
"architecture": "x86_64",
"type": "web"
}
As before, change the settings for your constructed inventory. You should know by now, how to get to the menu and apply the change:
---
plugin: ansible.builtin.constructed
strict: false
compose:
ansible_host: inventory_hostname | lower()
name: inventory_hostname | lower()
groups:
production: inventory_hostname is search('prod')
development: inventory_hostname is search('dev')
keyed_groups:
- prefix: ""
separator: ""
key: architecture
- prefix: "server_type"
separator: "-"
key: type
After you have saved and synced the changes, have a look at the new groups that were created:
-
You should see new groups per CPU architecture with the respective hosts showing up. The group name is taken from the
architecturevariable of the hosts. -
The second keyed groups entry is creating groups according to the
typevariable of the host. This time the group name is prefixed with the stringserver_typeand a separator.
If a host has multiple matching keys (like database and web), the separator is used to separate them in the group name. In our example, each host is in only one group so the separator is only seen in front of the type.
| Have you noticed what happened to the separator? The dash ("-") automatically became an underscore ("_"). Dashes used to be allowed in group names but not anymore. Name your groups (and roles and playbooks, as part of collections) like Python variables, with only letters, digits and underscores. |
Conclusion
Constructed inventories are a great way to automatically organize hosts in groups, apply naming standards and much more. It’s worth spending some time experimenting with this new capability.
If you want to learn more about constructed inventories, there is a great Blog Post and of course the Using automation execution documentation.