013 Tags and custom groups

Extending example 010.

Use case

Use the property notes to create tags:

  • Add the property notes: "vmm={{ inventory_hostname }}"

  • In the inventory plugin, compose the variable iocage_tags

  • In the inventory plugin, create groups vmm_* from the attribute iocage_tags.vmm

Tree

shell> tree .
.
├── ansible.cfg
├── hosts
│   ├── 01_iocage.yml
│   └── 02_iocage.yml
├── host_vars
│   ├── iocage_01
│   │   └── iocage.yml
│   └── iocage_02
│       └── iocage.yml
├── iocage-hosts.ini
├── pb-all.yml
├── pb-ansible-client.yml
├── pb-iocage-base.yml
├── pb-iocage-clone.yml
└── pb-test.yml

Synopsis

  • On two iocage hosts:

    • iocage_01

    • iocage_02

    In the playbook pb-iocage-base.yml, use the module vbotka.freebsd.iocage to:

    • create basejail ansible_client

    In the playbook pb-iocage-clone.yml, use the module vbotka.freebsd.iocage to:

    • clone 3 jails from the basejail ansible_client

    In the playbooks:

    • pb-all.yml

    • pb-ansible-client.yml

    • pb-test.yml

    use the inventory plugin vbotka.freebsd.iocage to:

    • create the inventory groups and compose variables.

    • create the dictionary iocage_tags from iocage_properties.notes

    • display hosts, composed variables, and groups.

    • comment on hosts potentially overriding each other silently.

Requirements

Configuration ansible.cfg

[defaults]
gathering = explicit
callback_result_format = yaml

[connection]
pipelining = true

hosts/01_iocage.yml

Enable get_properties: True to create the dictionary iocage_properties. Then, the dictionary iocage_tags can be created from iocage_properties.notes

plugin: vbotka.freebsd.iocage
host: 10.1.0.18
user: admin
env:
  CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
get_properties: True
cache: False
strict: True
compose:
  ansible_host: iocage_ip4
  release: iocage_release | split('-') | first
  iocage_tags: dict(iocage_properties.notes | split | map('split', '='))
groups:
    test_01: inventory_hostname.startswith('test')
keyed_groups:
  - prefix: distro_01
    key: iocage_release
  - prefix: state_01
    key: iocage_state
  - prefix: vmm
    key: iocage_tags.vmm

hosts/02_iocage.yml

Enable ‘get_properties: True’

plugin: vbotka.freebsd.iocage
host: 10.1.0.73
user: admin
env:
  CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
get_properties: True
cache: False
strict: True
compose:
  ansible_host: iocage_ip4
  release: iocage_release | split('-') | first
  iocage_tags: dict(iocage_properties.notes | split | map('split', '='))
groups:
    test_02: inventory_hostname.startswith('test')
keyed_groups:
  - prefix: distro_02
    key: iocage_release
  - prefix: state_02
    key: iocage_state
  - prefix: vmm
    key: iocage_tags.vmm

host_vars/iocage_01/iocage.yml

ansible_python_interpreter: /usr/local/bin/python3.9

properties:
  vnet: 'on'
  defaultrouter: 10.1.0.10
  notes: "vmm={{ inventory_hostname }}"

basejails:
  - name: ansible_client
    release: 13.4-RELEASE
    properties:
      ip4_addr: 'vnet0|10.1.0.198/24'

clones:
  - name: test_101
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.101/24'
  - name: test_102
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.102/24'
  - name: test_103
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.103/24'

host_vars/iocage_02/iocage.yml

ansible_python_interpreter: /usr/local/bin/python3.11

properties:
  notes: "vmm={{ inventory_hostname }}"

basejails:
  - name: ansible_client
    release: 14.1-RELEASE
    properties:
      ip4_addr: 'em0|10.1.0.199/24'

clones:
  - name: test_111
    clone_from: ansible_client
    properties:
      ip4_addr: 'em0|10.1.0.111/24'
  - name: test_112
    clone_from: ansible_client
    properties:
      ip4_addr: 'em0|10.1.0.112/24'
  - name: test_113
    clone_from: ansible_client
    properties:
      ip4_addr: 'em0|10.1.0.113/24'

Note

The structure of notes is up to you. If you change it fit the declaration of iocage_tags in the inventory.

Playbook pb-iocage-base.yml

- hosts: iocage
  environment:
    CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1

  tasks:

    - name: Create basejail
      register: out
      vbotka.freebsd.iocage:
        state: basejail
        name: "{{ item.name }}"
        release: "{{ item.release }}"
        properties: "{{ [properties, item.properties] | combine }}"
      loop: "{{ basejails }}"
      loop_control:
        label: "{{ item.name }} {{ item.release }}"

    - name: Debug
      when: debug | d(false) | bool
      ansible.builtin.debug:
        var: out
      
    - name: Display lists of bases, plugins, templates, and jails.
      ansible.builtin.debug:
        msg: |-
          releases: {{ iocage_releases }}
          plugins: {{ iocage_plugins.keys() | list }}
          templates: {{ iocage_templates.keys() | list }}
          jails: {{ iocage_jails.keys() | list }}

Playbook output

(env) > ansible-playbook pb-iocage-base.yml -i iocage-hosts.ini

PLAY [iocage] **********************************************************************************

TASK [Create basejail] *************************************************************************
changed: [iocage_02] => (item=ansible_client 14.1-RELEASE)
changed: [iocage_01] => (item=ansible_client 13.4-RELEASE)

TASK [Debug] ***********************************************************************************
skipping: [iocage_01]
skipping: [iocage_02]

TASK [Display lists of bases, plugins, templates, and jails.] **********************************
ok: [iocage_01] => 
  msg: |-
    releases: ['13.3-RELEASE', '13.4-RELEASE']
    plugins: []
    templates: []
    jails: ['ansible_client']
ok: [iocage_02] => 
  msg: |-
    releases: ['14.1-RELEASE']
    plugins: []
    templates: []
    jails: ['ansible_client']

PLAY RECAP *************************************************************************************
iocage_01: ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
iocage_02: ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Playbook pb-iocage-clone.yml

- hosts: iocage
  environment:
    CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1

  tasks:

    - name: Clone from basejail
      register: out
      vbotka.freebsd.iocage:
        state: cloned
        clone_from: "{{ item.clone_from }}"
        name: "{{ item.name }}"
        properties: "{{ [properties, item.properties] | combine }}"
      loop: "{{ clones }}"
      loop_control:
        label: "{{ item.name }} {{ item.clone_from }}"

    - name: Debug
      when: debug | d(false) | bool
      ansible.builtin.debug:
        var: out
      
    - name: Display lists of bases, plugins, templates, and jails.
      ansible.builtin.debug:
        msg: |-
          releases: {{ iocage_releases }}
          plugins: {{ iocage_plugins.keys() | list }}
          templates: {{ iocage_templates.keys() | list }}
          jails: {{ iocage_jails.keys() | list }}

Playbook output

(env) > ansible-playbook pb-iocage-clone.yml -i iocage-hosts.ini

PLAY [iocage] **********************************************************************************

TASK [Clone from basejail] *********************************************************************
changed: [iocage_01] => (item=test_101 ansible_client)
changed: [iocage_01] => (item=test_102 ansible_client)
changed: [iocage_02] => (item=test_111 ansible_client)
changed: [iocage_01] => (item=test_103 ansible_client)
changed: [iocage_02] => (item=test_112 ansible_client)
changed: [iocage_02] => (item=test_113 ansible_client)

TASK [Debug] ***********************************************************************************
skipping: [iocage_01]
skipping: [iocage_02]

TASK [Display lists of bases, plugins, templates, and jails.] **********************************
ok: [iocage_01] => 
  msg: |-
    releases: ['13.3-RELEASE', '13.4-RELEASE']
    plugins: []
    templates: []
    jails: ['ansible_client', 'test_101', 'test_102', 'test_103']
ok: [iocage_02] => 
  msg: |-
    releases: ['14.1-RELEASE']
    plugins: []
    templates: []
    jails: ['ansible_client', 'test_111', 'test_112', 'test_113']

PLAY RECAP *************************************************************************************
iocage_01: ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
iocage_02: ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Playbook pb-all.yml

- hosts: all

  tasks:

    - debug:
        msg: |
          inventory_hostname: {{ inventory_hostname }}
          ansible_host: {{ ansible_host }}
          release: {{ release }}
          iocage_tags: {{ iocage_tags }}

    - debug:
        msg: |
          groups:
            {{ groups | to_yaml(indent=2) | indent(2) }}
      run_once: true

Playbook output

(env) > ansible-playbook pb-all.yml -i hosts

PLAY [all] ******************************************************************************************

TASK [debug] ****************************************************************************************
ok: [ansible_client] => 
  msg: |-
    inventory_hostname: ansible_client
    ansible_host: 10.1.0.199
    release: 14.1
    iocage_tags: {'vmm': 'iocage_02'}
ok: [test_101] => 
  msg: |-
    inventory_hostname: test_101
    ansible_host: 10.1.0.101
    release: 13.4
    iocage_tags: {'vmm': 'iocage_01'}
ok: [test_102] => 
  msg: |-
    inventory_hostname: test_102
    ansible_host: 10.1.0.102
    release: 13.4
    iocage_tags: {'vmm': 'iocage_01'}
ok: [test_103] => 
  msg: |-
    inventory_hostname: test_103
    ansible_host: 10.1.0.103
    release: 13.4
    iocage_tags: {'vmm': 'iocage_01'}
ok: [test_111] => 
  msg: |-
    inventory_hostname: test_111
    ansible_host: 10.1.0.111
    release: 14.1
    iocage_tags: {'vmm': 'iocage_02'}
ok: [test_112] => 
  msg: |-
    inventory_hostname: test_112
    ansible_host: 10.1.0.112
    release: 14.1
    iocage_tags: {'vmm': 'iocage_02'}
ok: [test_113] => 
  msg: |-
    inventory_hostname: test_113
    ansible_host: 10.1.0.113
    release: 14.1
    iocage_tags: {'vmm': 'iocage_02'}

TASK [debug] ****************************************************************************************
ok: [ansible_client] => 
  msg: |-
    groups:
      all: [ansible_client, test_101, test_102, test_103, test_111, test_112, test_113]
      distro_01_13_4_RELEASE_p2: [ansible_client, test_101, test_102, test_103]
      distro_02_14_1_RELEASE_p6: [ansible_client, test_111, test_112, test_113]
      state_01_down: [ansible_client, test_101, test_102, test_103]
      state_02_down: [ansible_client, test_111, test_112, test_113]
      test_01: [test_101, test_102, test_103]
      test_02: [test_111, test_112, test_113]
      ungrouped: []
      vmm_iocage_01: [ansible_client, test_101, test_102, test_103]
      vmm_iocage_02: [ansible_client, test_111, test_112, test_113]

PLAY RECAP ******************************************************************************************
ansible_client: ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_101      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_102      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_103      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_111      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_112      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_113      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Note

  • The inventory files in the directory hosts are evaluated in alphabetical order.

  • The jail ansible_client from iocage_02 overrides the one from iocage_01

  • See the special variable groups

Playbook pb-ansible-client.yml

- hosts: ansible_client

  tasks:

    - debug:
        msg: |
          inventory_hostname: {{ inventory_hostname }}
          ansible_host: {{ ansible_host }}
          release: {{ release }}

          iocage_tags:
            {{ iocage_tags | to_nice_yaml(indent=2) | indent(2) }}
          group_names:
            {{ group_names | to_nice_yaml(indent=2) | indent(2) }}

Playbook output

(env) > ansible-playbook pb-ansible-client.yml -i hosts

PLAY [ansible_client] *******************************************************************************

TASK [debug] ****************************************************************************************
ok: [ansible_client] => 
  msg: |-
    inventory_hostname: ansible_client
    ansible_host: 10.1.0.199
    release: 14.1
  
    iocage_tags:
      vmm: iocage_02
  
    group_names:
      - distro_01_13_4_RELEASE_p2
      - distro_02_14_1_RELEASE_p6
      - state_01_down
      - state_02_down
      - vmm_iocage_01
      - vmm_iocage_02

PLAY RECAP ******************************************************************************************
ansible_client: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Note

  • The structure of the inventory hosts and groups is flat. The jail(host) ansible-client in all groups is the same.

  • See the special variable group_names

Warning

There are no internal checks of the hosts overriding each other. The consistency is up to you.

Playbook pb-test.yml

- hosts: test_01,test_02

  tasks:

    - debug:
        msg: "{{ inventory_hostname }} running at {{ iocage_tags.vmm }}"

Playbook output

(env) > ansible-playbook pb-test.yml -i hosts

PLAY [test_01,test_02] ************************************************************************

TASK [debug] **********************************************************************************
ok: [test_101] => 
  msg: test_101 running at iocage_01
ok: [test_102] => 
  msg: test_102 running at iocage_01
ok: [test_111] => 
  msg: test_111 running at iocage_02
ok: [test_103] => 
  msg: test_103 running at iocage_01
ok: [test_112] => 
  msg: test_112 running at iocage_02
ok: [test_113] => 
  msg: test_113 running at iocage_02

PLAY RECAP ************************************************************************************
test_101: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_102: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_103: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_111: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_112: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_113: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0