Skip to content

Group Taxonomy & Priority

Both the AWS and Azure inventories produce a consistent, lowercase set of groups so that variables can be scoped the same way regardless of cloud. There are three tiers, plus a small overlay that controls precedence between them.

The three tiers

Tier Groups Answers Where defined
Platform (cloud) platform_aws, platform_azure Which cloud is this host in? Source inventory (inventory.aws_ec2.yml / inventory.azure_rm.yml)
OS os_linux, os_windows Which operating system? Source inventory
Application app_kuiper, app_nginx, app_systempulse, … What does this host run? Source inventory (inventory.aws_ec2.yml / inventory.azure_rm.yml), keyed on the application VM tag

Each managed host lands in exactly one platform group, one OS group, and (usually) one app group. Shared variables live in group_vars/<group>/vars.yml for the tier they belong to:

  • Cloud-specific settings (e.g. ansible_connection details, cloud image users) → group_vars/platform_*
  • OS-specific settings (e.g. ansible_shell_type, WinRM ports) → group_vars/os_*
  • Application settings (e.g. firewall zones, cert paths, role vars) → group_vars/app_*

On top of these three, both clouds add environment-scoped groups keyed on the environment VM tag — <env>_<cloud>_platform (every host in one environment) and <env>_<cloud>_app_<application> (one app in one environment), e.g. dev_aws_platform / dev_aws_app_kuiper and ire_copier_azure_platform / ire_copier_azure_app_kuiper. These carry cloud- and environment-specific config that the cross-cloud app_* groups can't. Full details of the app and environment tiers: Application & Environment Groups.

How membership is derived

The platform and OS groups are created by the cloud inventory plugins, which only ever see hosts from their own cloud:

Group AWS (aws_ec2) Azure (azure_rm)
platform_aws / platform_azure platform_aws: true platform_azure: true
os_windows 'Windows' in platform_details os_profile.system == 'windows'
os_linux 'Windows' not in platform_details os_profile.system == 'linux'

Why AWS matches a substring

AWS's platform_details returns a distro string on Linux (Red Hat Enterprise Linux, Linux/UNIX, …) and a string that starts with Windows on Windows (Windows, Windows with SQL Server Standard, …). Matching the Windows substring collapses every Linux distro into os_linux and catches the Windows SQL variants — a plain keyed_groups on the raw value would instead produce a group per distro. Azure's os_profile.system already returns exactly linux/windows, so it is compared directly.

The application and environment tiers are derived the same way on both clouds — keyed_groups on the Terraform application and environment VM tags, defined directly in the source inventory plugin (no separate constructed inventory). Tag a VM and it joins the right groups automatically. See Application & Environment Groups for the exact keyed_groups/compose blocks and the untagged-vs-empty-tag behavior.

Group priority

The platform and OS groups are broad defaults. More specific groups (app_* and the environment-scoped <env>_<cloud>_platform / <env>_<cloud>_app_<application> groups) should win when they define the same variable. That precedence is set in inventory.group_priority.yml:

all:
  children:
    platform_aws:              { vars: { ansible_group_priority: -1 } }
    platform_azure:            { vars: { ansible_group_priority: -1 } }
    os_linux:                  { vars: { ansible_group_priority: -1 } }
    os_windows:                { vars: { ansible_group_priority: -1 } }
    ire_copier_azure_platform: { vars: { ansible_group_priority: 0 } }
    dev_aws_platform:          { vars: { ansible_group_priority: 0 } }

ansible_group_priority defaults to 1, and groups merge in priority order, so the pinned values order the tiers from broadest to narrowest:

Priority Groups Scope
-1 platform_*, os_* One cloud, or one OS across clouds
0 <env>_<cloud>_platform Every host in one environment (dev_aws_platform, ire_copier_azure_platform)
1 (default) app_* One application, any cloud
1 (default) <env>_<cloud>_app_<application> One application in one environment — sorts after app_*, so it wins the tie

The app tiers are not listed in the file: their names are generated from VM tags, so they cannot be enumerated, and they keep the default priority of 1. The file is listed as an inventory source in both ansible.cfg and ansible-azure.cfg.

An <env>_<cloud>_platform group only needs an entry here once it has group_vars of its own — without the pin it would sort after <env>_<cloud>_app_<application> alphabetically and shadow the narrower app group. Add one line per environment (prod_aws_platform, etc.) as new environments appear.

The app-vs-env-app tie-break relies on name ordering

app_<app> and <env>_<cloud>_app_<app> are both at priority 1, so the more-specific env-scoped group wins only by the alphabetical name sort (app_ < <env>_…). This holds for normal environment names (dev, prod, ire_copier all sort after app), but an environment whose name sorts before app — e.g. one literally named ansible — would make its <env>_…_app_<app> group sort first and lose the tie to the bare app_<app>. Keep environment tag values from sorting ahead of app if both tiers ever define the same variable. (Giving the env-app tier an explicit priority 2 would fix this, but its names come from tags and can't be enumerated in inventory.group_priority.yml, so the alphabetical tie-break is the accepted trade-off.)

ansible_group_priority must live in an inventory source, not group_vars/

Ansible consumes ansible_group_priority while it is merging group_vars, so a value placed in group_vars/<group>/vars.yml is read too late and is silently ignored — you fall back to the alphabetical tiebreak. It only takes effect when set in an inventory source (a plugin config or a static YAML/INI inventory). inventory.group_priority.yml exists solely to carry these priority settings; the groups get their membership from the dynamic plugins.

Tie-break between platform and OS

platform_* and os_* are both at priority -1, and every host is in one of each. If the same variable is defined in both a platform_* and an os_* group, the priority tie falls back to alphabetical order, and platform_* sorts after os_* — so the cloud group wins. Keep cloud-specific vars in platform_* and OS-specific vars in os_* and this never bites.

The one to watch is ansible_user, which can differ by cloud and OS (e.g. AWS uses ec2-user on Linux but a domain admin on Windows). Don't define it in both tiers expecting OS to win. Today it is supplied uncontested by the legacy _Red_Hat_Enterprise_Linux / _Windows groups; if you ever move it into platform_* or os_*, verify the resolved value per host first.

Legacy groups (deprecated, still present)

The pre-existing groups are intentionally left in the inventories so existing --limit targets keep working:

Legacy group Replaced by
_Windows, _Red_Hat_Enterprise_Linux (AWS platform_details keyed groups) os_windows, os_linux
azure_rm, azure_rm_windows, azure_rm_linux platform_azure, os_windows, os_linux
state keyed groups (running, stopped, …) (no replacement — still keyed on state.name)

They carry no group_vars of their own anymore (those moved to the new tiers) and are expected to age off. Prefer the platform_* / os_* / app_* names in new playbooks and docs.

Verifying

ansible-inventory --graph platform_aws     # or platform_azure
ansible-inventory --graph os_linux
ansible-inventory --graph os_windows
ansible-inventory --host <hostname>        # confirm vars resolve across all three tiers