Verify PHX Environment Group Check
Categories:
Projects: c2platform/phx/ansible
Note:
The
development environment of the open source PHX
reference implementation utilizes an
inventory plugin to generate host
information dynamically. This plugin ensures it is impossible to place a node in
two environments because the environment label is derived from the prefix—for
example, pxd for development, pxt for test, and so on. In other words,
it is hard and unlikely to make a configuration mistake.
In the air-gapped PHX domain / data center, “normal” static inventory is used, and as a result, it is possible for the Ansible engineer or operator to inadvertently place the node in “no” or more than one environment. It is not unlikely that configuration mistakes will be made.
In this how-to, we simulate a configuration error to validate that the environment check works correctly.
Prerequisites
For the purpose of this how-to, the specific node does not matter because the
environment check validates the complete
inventory project. We will use the
development desktop pxd-ubuntu-devtop. To create and start this node,
see:
- Ansible Development Desktop in PHX Domain: Set up and manage an Ansible development desktop simulating the setup in the air-gapped PHX domain.
Verify Environment Check
An environment check is implemented in the
inventory project of the PHX
project
c2platform/phx/ansible .
The check ensures that as part of a
group-based environments approach,
which is part of the inventory strategy of this project, a host can be in no
more than one and at least one
environment group. Let’s check if that is
working.
Active Groups
Run the following command to see the
Ansible groups the Vagrant node
pxd-ubuntu-devtop is part of. This will show that this node is part of
environment group development.
ansible -m debug -a 'msg={{group_names}}' pxd-ubuntu-devtop
Show me
As stated earlier, the “environment” is derived from the prefix. To check this
you can open the file Vagrantfile.yml, find the configuration of the node
pxd-ubuntu-devtop and add a line prefix: pxt below the line with name.
100 - name: ubuntu-devtop
101 description: Ansible Development Desktop
102 box: ubuntu24-lxd
103 ip-address: 192.168.60.11
104 plays:
105 - dev/desktop
106 labels:
107 - desktop
108 - ubuntu_devtop
109 - radix_guardian
With line added, the configuration should look something like:
- name: ubuntu-devtop
prefix: pxt
description: Ansible Development Desktop
box: ubuntu24-lxd
ip-address: 192.168.60.11
plays:
- dev/desktop
labels:
- desktop
- ubuntu_devtop
- radix_guardian
Running the debug command again, now for node pxt-ubuntu-devtop will now show
that pxt-ubuntu-devtop is part of test environment.
ansible -m debug -a 'msg={{group_names}}' pxt-ubuntu-devtop
Show me
No more than one
To validate the environment check is working, we intentionally introduce a
configuration error that would be impossible in normal dynamic inventory usage.
In the inventory project, a variable px_envs was introduced to define which
Ansible groups are of the special type
environment group.
3px_envs: ['test', 'development']
Open that file group_vars/all/env.yml and add linux.
px_envs: [test, development, linux]
Now with the node in two environment groups, provision again:
vagrant provision pxd-ubuntu-devtop
This will now fail with a message like below:
Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test, development, linux!
TASK [c2platform.core.linux : Fail with custom message] ************************
failed: [pxd-ubuntu-devtop] (item=Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test, development, linux!) => changed=false
ansible_loop_var: item
item:
msg: 'Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test, development, linux!'
name: Environment pxd-ubuntu-devtop → development, linux
resource_group: 0_bootstrap
type: fail
when: true
msg: 'Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test, development, linux!'
This verifies that - in case we use static inventory as is the case in
air-gapped PHX domain/data center, the environment check that uses the defined
environment groups variable px_envs will protect us from making config
mistakes.
At least one
To further verify the environment check, revert the previous change to
px_envs by removing linux, and also remove development from px_envs.
The updated variable should look like this:
px_envs: [test]
Now, with the node no longer associated with any environment group, provision again:
vagrant provision pxd-ubuntu-devtop
This will fail with a message like below, indicating that the node is not in any of the defined environment groups:
Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test!
TASK [c2platform.core.linux : Fail with custom message] ************************
failed: [pxd-ubuntu-devtop] (item=Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test!) => changed=false
ansible_loop_var: item
item:
msg: 'Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test!'
name: 'Environment pxd-ubuntu-devtop → '
resource_group: 0_bootstrap
type: fail
when: true
msg: 'Node pxd-ubuntu-devtop should be associated with exactly one environment group of: test!'
This step confirms that the environment check enforces not only the “no more than one” rule but also the “at least one” rule. By ensuring every node is assigned to exactly one environment group, it prevents configuration errors such as orphaned nodes or incomplete setups. In a production-like static inventory scenario, this validation is crucial for maintaining consistency and reliability across environments.
Review
Now, how is it implemented in the
inventory project in the
group_vars
folder? First, look at the group_vars/all/env.yml:
---
px_env: "{{ group_names | intersect(px_envs) | first }}"
px_envs: ['test', 'development']
px_envs_node: "{{ group_names | intersect(px_envs) }}"
px_envs_node_count: "{{ px_envs_node | length }}"
px_envs_check:
name: >-
Environment {{ inventory_hostname }} → {{ px_envs_node | join(', ') }}
type: fail
msg: >-
Node {{ inventory_hostname }} should be associated with exactly
one environment group of: {{ px_envs | join(', ') }}!
when: "{{ px_envs_node_count != '1' }}"
This YAML file defines variables to enforce the environment group policy as part of a group-based environments strategy:
- The
px_envsvariable lists allowed environment groups (testanddevelopment). - The
px_envs_nodevariable identifies which of these groups the current host belongs to by intersecting the host’s group names withpx_envs. - The
px_envs_node_countcounts these intersections. - The
px_envs_checkconfigures a failure condition: it triggers a fail task if the count is not exactly 1, with a message indicating the host must belong to exactly one environment group.
We can now use the variable px_envs_check to configure the check for Linux
systems (that are part of the linux group). And to configure the check for
Windows systems (that are part of the win group). Note that on both Linux and
Windows hosts we can use the ansible.builtin.fail module.
---
linux_resources:
0_bootstrap:
- "{{ px_envs_check }}"
26win_resources:
27 0_bootstrap:
28 - name: Apps folder
29 type: win_file
30 path: "{{ px_apps_dir }}"
31 state: directory
32 - "{{ px_envs_check }}"
Note, furthermore, that the variables linux_resources and win_resources that
are used to configure the environment check are part of respectively the Linux role
Ansible Linux Role ( c2platform.core.linux)
and the Windows role
Ansible Win Role ( c2platform.wincore.win).
Additional Information
For additional insights and guidance:
- Group-based Environments: Use a group-based approach to organize your Ansible inventory and variables for different environments.
- Ansible Inventory Project: A structured collection of files used for managing hosts and configurations. It typically includes inventory files, playbooks, host configurations, group variables, and Ansible vault files.
- Use Dynamic Inventory in Development: Guideline for using dynamic inventory in Ansible development environments as a concrete example to illustrate future full automation for organizations new to Ansible.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.