Ansible OEL 8 DevOps · OEL 8 · Inventory

AnsibleInventory Plugins — constructed and generator

The plugin layer that lets you transform existing inventory: derive new groups from host facts with constructed, mass-produce hosts from templates with generator, and chain plugins together for layered inventory.

We've seen plugins that fetch hosts from a source (AWS, Azure, scripts). Two built-in plugins do something different — they transform existing inventory. Drop them into the same inventory directory and they layer on top.

Inventory plugins · pick the right source Cloud amazon.aws.aws_ec2 azure.azcollection.azure_rm google.cloud.gcp_compute openstack.cloud.openstack vmware.vmware_rest community.digitalocean Auto-discover by tag, region, security group Best for fleets Containers & K8s kubernetes.core.k8s community.docker.docker community.docker.compose community.podman Less common pattern, but useful for one-off container management Niche but powerful Generic ansible.builtin.ini ansible.builtin.yaml ansible.builtin.script ansible.builtin.constructed ansible.builtin.generator ansible.builtin.toml Static files, scripts, layered transformations Foundation tools

The constructed plugin reads each host's variables (or facts gathered earlier in the run) and builds new groups based on Jinja2 expressions. Useful when your hosts come from a flat source but you need them grouped by some derived attribute.

YAML — inventories/constructed.yml
---
plugin: ansible.builtin.constructed
strict: false

# 1. KEYED GROUPS — auto-create groups for each unique value
keyed_groups:
  # Group hosts by OS family (creates os_family_RedHat, os_family_Debian, …)
  - prefix: os_family
    key: ansible_os_family

  # Group hosts by datacenter (creates dc_mumbai, dc_singapore, …)
  - prefix: dc
    key: datacenter | default("unknown")

  # Group EC2 instances by instance type
  - prefix: instance
    key: ec2_instance_type

# 2. GROUPS — boolean expressions, hosts join if expr is true
groups:
  large_hosts: ansible_memtotal_mb >= 16000
  oel8_hosts:  ansible_distribution == "OracleLinux" and ansible_distribution_major_version == "8"
  primaries:   mysql_role | default("") == "primary"

# 3. COMPOSE — derived per-host variables
compose:
  is_oel8: 'ansible_distribution == "OracleLinux"'
  short_hostname: 'inventory_hostname.split(".")[0]'
BASH — see what constructed produced
# Combined inventory: AWS EC2 + constructed transforms
ansible-inventory -i inventories/aws_ec2.yml -i inventories/constructed.yml --graph

# Sample output
# @all:
#   |--@aws_ec2:
#   |--@os_family_RedHat:
#   |  |--ip-10-0-1-12.ap-south-1.compute.internal
#   |--@dc_mumbai:
#   |  |--ip-10-0-1-12.ap-south-1.compute.internal
#   |--@large_hosts:
#   |  |--ip-10-0-1-12.ap-south-1.compute.internal
#   |--@primaries:
#   |  |--db1.example.com

The generator plugin produces inventory by combining a template with a list of values. Useful for things like "I have 30 numbered worker hosts in N regions":

YAML — inventories/generator.yml
---
plugin: ansible.builtin.generator
hosts:
  name: "worker-{{{{ region }}}}-{{{{ shard }}}}"
  parents:
    - name: "region_{{{{ region }}}}"
      parents:
        - name: workers
    - name: "shard_{{{{ shard }}}}"

layers:
  region:
    - mumbai
    - singapore
    - frankfurt
  shard:
    - "01"
    - "02"
    - "03"

That config generates 9 hosts (3 regions × 3 shards), all in workers, plus per-region and per-shard groups:

BASH — what generator produced
ansible-inventory -i inventories/generator.yml --graph
# @all:
#   |--@workers:
#   |  |--worker-mumbai-01
#   |  |--worker-mumbai-02
#   |  |--worker-mumbai-03
#   |  |--worker-singapore-01
#   |  |--worker-singapore-02
#   |  |--worker-singapore-03
#   |  |--worker-frankfurt-01
#   |  |--worker-frankfurt-02
#   |  |--worker-frankfurt-03
#   |--@region_mumbai:
#   |--@region_singapore:
#   |--@region_frankfurt:
#   |--@shard_01:
#   |--@shard_02:
#   |--@shard_03:
💡 Tip: generator shines for synthetic / sharded fleets and labs — all the database labs in this series use it to produce numbered nodes for cluster setups.

The real power of inventory plugins is composition. Drop several plugin configs into the same directory and Ansible processes each, merging the result.

DIR — layered inventory composition
inventories/production/
├── 01-static.ini             # static bastion + control plane
├── 02-aws_ec2.yml            # AWS-discovered hosts
├── 03-constructed.yml        # derive groups from EC2 tags + facts
└── group_vars/
    ├── all.yml
    ├── os_family_RedHat.yml  # auto-applied to RHEL-family hosts
    └── primaries.yml          # auto-applied to anything in 'primaries'

Plugins run in alphabetical order, so the numeric prefixes guarantee that static sources are read first, dynamic ones second, and transforms last. The final inventory is the union.

BASH — discover plugins
# Show every inventory plugin Ansible can find
ansible-doc -t inventory -l

# Output (excerpt):
# amazon.aws.aws_ec2          - EC2 inventory source
# amazon.aws.aws_rds          - rds instances inventory
# ansible.builtin.constructed - Use Jinja2 to construct groups
# ansible.builtin.generator   - Generates an inventory from a definition
# ansible.builtin.host_list   - Parses host list from CLI
# ansible.builtin.ini         - Uses INI file
# ansible.builtin.script      - Executes inventory script
# ansible.builtin.toml        - Uses TOML file
# ansible.builtin.yaml        - Uses YAML file
# google.cloud.gcp_compute    - Google Cloud Compute Engine
# kubernetes.core.k8s         - Kubernetes inventory source

# Detailed docs for one plugin
ansible-doc -t inventory ansible.builtin.constructed

Built-in plugins (constructed, generator, ini, yaml, script) are always available. Plugins from collections need to be explicitly enabled in ansible.cfg:

INI — enable inventory plugins
[inventory]
enable_plugins = ini, yaml, constructed, generator,
                 amazon.aws.aws_ec2,
                 google.cloud.gcp_compute,
                 kubernetes.core.k8s
⚠ Warning: If your aws_ec2.yml isn't being picked up, check enable_plugins first. Forgetting this is the #1 reason a perfectly-written plugin config silently produces no hosts.
✅ Tip: Plugins are infinitely composable — static file + AWS + GCP + constructed + generator can all live in one inventory directory and Ansible builds the final host list from all sources. That's how you scale inventory without giving up reproducibility.