# 013 Tags and custom groups.

Extending example 010.

## 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

- Use the property notes to create tags:

  - Add the property ‘notes: “vmm={{ inventory_hostname }}”’

  - In the inventory plugin, compose iocage_tags

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

- 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

- Module vbotka.freebsd.iocage

- Inventory vbotka.freebsd.iocage

- root privilege on the iocage hosts

- Activated iocage

- Fetched releases

## 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-test.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 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