Verify PHX Environment Group Check

Verify and review the implementation of an environment check to ensure nodes are in exactly one environment group.

Projects:  c2platform/phx/ansible


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:

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
[:ansible-phx]└2 master(+2/-1)* 130 ± ansible -m debug -a 'msg={{group_names}}' pxd-ubuntu-devtop
ini_path: /home/onknows/git/gitlab/c2/ansible-phx/hosts.ini
pxd-ubuntu-devtop | SUCCESS => {
    "msg": [
        "desktop",
        "development",
        "linux",
        "lxd",
        "radix_guardian",
        "ubuntu",
        "ubuntu24",
        "ubuntu_devtop"
    ]
}
θ65° [:ansible-phx]└2 master(+2/-1)* ±

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.

 Vagrantfile.yml

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
θ65° [:ansible-phx]└2 master(+2/-1)* ± ansible -m debug -a 'msg={{group_names}}' pxt-ubuntu-devtop
ini_path: /home/onknows/git/gitlab/c2/ansible-phx/hosts.ini
pxt-ubuntu-devtop | SUCCESS => {
    "msg": [
        "desktop",
        "linux",
        "lxd",
        "radix_guardian",
        "test",
        "ubuntu",
        "ubuntu24",
        "ubuntu_devtop"
    ]
}

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.

 group_vars/all/env.yml

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:

 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_envs variable lists allowed environment groups (test and development).
  • The px_envs_node variable identifies which of these groups the current host belongs to by intersecting the host’s group names with px_envs.
  • The px_envs_node_count counts these intersections.
  • The px_envs_check configures 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.

 group_vars/linux/main.yml

---
linux_resources:
  0_bootstrap:
    - "{{ px_envs_check }}"

 group_vars/win/main.yml

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.