020 Get inventory aliases from notes

Extending example 016 Multiple inventory constructed.

Use case

Get the inventory aliases from the iocage property notes. In the inventory plugin vbotka.freebsd.iocage, use the option inventory_hostname_tag to tell the plugin which tag to use.

Tree

shell> tree .
.
├── ansible.cfg
├── group_vars
│   └── all
│       └── swarms.yml
├── hosts
│   ├── 02_iocage.yml
│   ├── 04_iocage.yml
│   └── 99_constructed.yml
├── host_vars
│   ├── iocage_02
│   │   └── iocage.yml
│   └── iocage_04
│       └── iocage.yml
├── iocage.ini
├── pb-iocage-swarms-create.yml
├── pb-iocage-swarms-destroy.yml
├── pb-test-all.yml
└── pb-test-db.yml

Synopsis

  • At two managed nodes:

    • create jails using a template and the option --count

    • at each jail, create property notes in the format tag1=val1 tag2=val2 ...

    • put the inventory alias into the tag alias=<alias>

  • In the inventory plugin vbotka.freebsd.iocage, get the inventory aliases from the tag alias

  • In the inventory plugin ansible.builtin.constructed, create the inventory groups.

  • Display the jails and groups.

Requirements

Notes

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

Templates at iocage_02

[iocage_02]# iocage list -lt
+------+----------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
| JID  |      NAME      | BOOT | STATE |   TYPE   |     RELEASE     |        IP4         | IP6 | TEMPLATE | BASEJAIL |
+======+================+======+=======+==========+=================+====================+=====+==========+==========+
| None | ansible_client | off  | down  | template | 14.3-RELEASE-p8 | DHCP (not running) | -   | -        | no       |
+------+----------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+

Templates at iocage_04

[iocage_04]# iocage list -lt
+------+-----------------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
| JID  |         NAME          | BOOT | STATE |   TYPE   |     RELEASE     |        IP4         | IP6 | TEMPLATE | BASEJAIL |
+======+=======================+======+=======+==========+=================+====================+=====+==========+==========+
| None | ansible_client        | off  | down  | template | 15.0-RELEASE-p3 | DHCP (not running) | -   | -        | no       |
+------+-----------------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
| None | ansible_client_apache | off  | down  | template | 15.0-RELEASE-p3 | DHCP (not running) | -   | -        | no       |
+------+-----------------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
| None | ansible_client_pull   | off  | down  | template | 15.0-RELEASE-p3 | DHCP (not running) | -   | -        | no       |
+------+-----------------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+

ansible.cfg

[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
host_key_checking = false

[connection]
pipelining = true

Inventory iocage.ini

iocage_02 ansible_host=10.1.0.73
iocage_04 ansible_host=10.1.0.29

[iocage]
iocage_02
iocage_04

[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent

group_vars

group_vars/all/swarms.yml
project: example_020
properties: "bpf=1 dhcp=1 vnet=1"

host_vars

host_vars/iocage_02/iocage.yml
names: [www_p1, www_p2, www_p3, www_d1, www_d2]
swarms:
  www_prod:
    count: 3
    template: ansible_client
  www_devel:
    count: 2
    template: ansible_client
host_vars/iocage_04/iocage.yml
names: [db1, db2]
swarms:
  db:
    count: 2
    template: ansible_client

Inventory hosts

The value of the iocage tag alias is used as the inventory alias. If the iocage list is slow use the cache.

hosts/02_iocage.yml
plugin: vbotka.freebsd.iocage
host: 10.1.0.73
user: admin
cache: true
cache_plugin: ansible.builtin.jsonfile
cache_connection: /var/tmp/inventory_cache
cache_timeout: 3600
cache_prefix: iocage_02_
get_properties: true
inventory_hostname_tag: alias
hooks_results:
  - /var/db/dhclient-hook.address.epair0b
compose:
  ansible_host: (iocage_hooks.0 == '-') | ternary(iocage_ip4, iocage_hooks.0)
  iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)'))
hosts/04_iocage.yml
plugin: vbotka.freebsd.iocage
host: 10.1.0.29
user: admin
cache: true
cache_plugin: ansible.builtin.jsonfile
cache_connection: /var/tmp/inventory_cache
cache_timeout: 3600
cache_prefix: iocage_04_
get_properties: true
inventory_hostname_tag: alias
hooks_results:
  - /var/db/dhclient-hook.address.epair0b
compose:
  ansible_host: (iocage_hooks.0 == '-') | ternary(iocage_ip4, iocage_hooks.0)
  iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)'))
hosts/99_constructed.yml
plugin: ansible.builtin.constructed
keyed_groups:
  - prefix: vmm
    key: iocage_tags.vmm
  - prefix: project
    key: iocage_tags.project
  - prefix: swarm
    key: iocage_tags.swarm

Playbook pb-iocage-swarms-create.yml

# This play is not idempotent! New jails are created each time this play runs.
- name: Create swarms (not idempotent!)
  hosts: iocage
  environment: "{{ iocage_env | d({}) }}"

  vars:

    debug: false

  tasks:

    - name: Create swarms.
      register: out_swarms
      ansible.builtin.command:
        cmd: >-
          iocage create
          --short
          --count {{ item.value.count }}
          --template {{ item.value.template }}
          {{ properties }}
      loop: "{{ swarms | dict2items }}"

    - name: Debug iocage create.
      when: debug | bool
      ansible.builtin.debug:
        var: out_swarms

    - name: Create tags.
      register: out_tags
      vars:
        jail_name: "{{ item.1 | split | first }}"
        iocage_tags: >-
          vmm={{ inventory_hostname}}
          project={{ project }}
          swarm={{ item.0.item.key }}
          alias={{ names[idx] }}
      ansible.builtin.command:
        cmd: >-
          iocage set
          notes="{{ iocage_tags }}"
          {{ jail_name }}
      loop: "{{ out_swarms.results | subelements('stdout_lines') }}"
      loop_control:
        index_var: idx
        label: "{{ jail_name }} {{ iocage_tags }}"

    - name: Debug create tags.
      when: debug | bool
      ansible.builtin.debug:
        var: out_tags

Playbook output - Create swarms

(env) > ansible-playbook pb-iocage-swarms-create.yml -i iocage.ini
PLAY [Create swarms (not idempotent!)] *****************************************

TASK [Create swarms.] **********************************************************
changed: [iocage_04] => (item={'key': 'db', 'value': {'count': 2, 'template': 'ansible_client'}})
changed: [iocage_02] => (item={'key': 'www_prod', 'value': {'count': 3, 'template': 'ansible_client'}})
changed: [iocage_02] => (item={'key': 'www_devel', 'value': {'count': 2, 'template': 'ansible_client'}})

TASK [Create tags.] ************************************************************
changed: [iocage_04] => (item=026a1357 vmm=iocage_04 project=example_020 swarm=db alias=db1)
changed: [iocage_04] => (item=ff5a1f63 vmm=iocage_04 project=example_020 swarm=db alias=db2)
changed: [iocage_02] => (item=29712c80 vmm=iocage_02 project=example_020 swarm=www_prod alias=www_p1)
changed: [iocage_02] => (item=24ceb6f1 vmm=iocage_02 project=example_020 swarm=www_prod alias=www_p2)
changed: [iocage_02] => (item=b65059d4 vmm=iocage_02 project=example_020 swarm=www_prod alias=www_p3)
changed: [iocage_02] => (item=fba6f241 vmm=iocage_02 project=example_020 swarm=www_devel alias=www_d1)
changed: [iocage_02] => (item=d58e1d10 vmm=iocage_02 project=example_020 swarm=www_devel alias=www_d2)

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

Hint

Run the below command to see the complete inventory

shell> ansible-inventory -i hosts --list --yaml

Jails at iocage_02

[iocage_02]# iocage list -l
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| JID  |   NAME   | BOOT | STATE | TYPE |     RELEASE     |        IP4         | IP6 |    TEMPLATE    | BASEJAIL |
+======+==========+======+=======+======+=================+====================+=====+================+==========+
| None | 24ceb6f1 | off  | down  | jail | 14.3-RELEASE-p8 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| None | 29712c80 | off  | down  | jail | 14.3-RELEASE-p8 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| None | b65059d4 | off  | down  | jail | 14.3-RELEASE-p8 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| None | d58e1d10 | off  | down  | jail | 14.3-RELEASE-p8 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| None | fba6f241 | off  | down  | jail | 14.3-RELEASE-p8 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+

Jails at iocage_04

[iocage_04]# iocage list -l
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| JID  |   NAME   | BOOT | STATE | TYPE |     RELEASE     |        IP4         | IP6 |    TEMPLATE    | BASEJAIL |
+======+==========+======+=======+======+=================+====================+=====+================+==========+
| None | 026a1357 | off  | down  | jail | 15.0-RELEASE-p3 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| None | ff5a1f63 | off  | down  | jail | 15.0-RELEASE-p3 | DHCP (not running) | -   | ansible_client | no       |
+------+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+

Playbook pb-test-all.yml

- name: Display all groups.
  hosts: all

  tasks:

    - debug:
        msg: |
          {{ iocage_properties.host_hostuuid | d('UNDEFINED') }}
          {{ iocage_tags | d({}) | to_yaml }}

    - debug:
        msg: |
          {% for group in groups %}
          {{ group }}: {{ groups[group] }}
          {% endfor %}
      run_once: true

Playbook output - All groups

(env) > ansible-playbook pb-test-all.yml -i hosts
PLAY [Display all groups.] *****************************************************

TASK [debug] *******************************************************************
ok: [www_p2] => 
    msg: |-
        24ceb6f1
        {alias: www_p2, project: example_020, swarm: www_prod, vmm: iocage_02}
ok: [www_p1] => 
    msg: |-
        29712c80
        {alias: www_p1, project: example_020, swarm: www_prod, vmm: iocage_02}
ok: [www_d2] => 
    msg: |-
        d58e1d10
        {alias: www_d2, project: example_020, swarm: www_devel, vmm: iocage_02}
ok: [www_p3] => 
    msg: |-
        b65059d4
        {alias: www_p3, project: example_020, swarm: www_prod, vmm: iocage_02}
ok: [www_d1] => 
    msg: |-
        fba6f241
        {alias: www_d1, project: example_020, swarm: www_devel, vmm: iocage_02}
ok: [db1] => 
    msg: |-
        026a1357
        {alias: db1, project: example_020, swarm: db, vmm: iocage_04}
ok: [db2] => 
    msg: |-
        ff5a1f63
        {alias: db2, project: example_020, swarm: db, vmm: iocage_04}

TASK [debug] *******************************************************************
ok: [www_p2] => 
    msg: |-
        all: ['www_p2', 'www_p1', 'www_p3', 'www_d2', 'www_d1', 'db1', 'db2']
        ungrouped: []
        vmm_iocage_02: ['www_p2', 'www_p1', 'www_p3', 'www_d2', 'www_d1']
        project_example_020: ['www_p2', 'www_p1', 'www_p3', 'www_d2', 'www_d1', 'db1', 'db2']
        swarm_www_prod: ['www_p2', 'www_p1', 'www_p3']
        swarm_www_devel: ['www_d2', 'www_d1']
        vmm_iocage_04: ['db1', 'db2']
        swarm_db: ['db1', 'db2']

PLAY RECAP *********************************************************************
db1                        : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
db2                        : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
www_d1                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
www_d2                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
www_p1                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
www_p2                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
www_p3                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook pb-test-db.yml

- name: Test group swarm_db
  hosts: swarm_db

  tasks:

    - debug:
        var: iocage_properties.host_hostuuid

Playbook output - Group swarm_db

(env) > ansible-playbook pb-test-db.yml -i hosts
PLAY [Test group swarm_db] *****************************************************

TASK [debug] *******************************************************************
ok: [db1] => 
    iocage_properties.host_hostuuid: 026a1357
ok: [db2] => 
    iocage_properties.host_hostuuid: ff5a1f63

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

Playbook pb-iocage-swarms-destroy.yml

- name: Destroy swarms.
  hosts: iocage
  environment: "{{ iocage_env | d({}) }}"

  vars:

    debug: false

  tasks:

    - name: Stop and destroy swarms.
      vars:
        group: "swarm_{{ item }}"
        uuids: "{{ groups[group] | map('extract', hostvars, ['iocage_properties', 'host_hostuuid']) }}"
      block:

        - name: Stop swarms.
          register: out
          ansible.builtin.command: "iocage stop {{ uuids | join(' ') }}"
          loop: "{{ swarms.keys() }}"

        - name: Debug stop swarms.
          when: debug | bool
          ansible.builtin.debug:
            var: out

        - name: Destroy swarms.
          register: out
          ansible.builtin.command: "iocage destroy -f {{ uuids | join(' ') }}"
          loop: "{{ swarms.keys() }}"

        - name: Debug stop swarms.
          when: debug | bool
          ansible.builtin.debug:
            var: out

Playbook output - Destroy swarms

Destroy the swarms if you don’t need them any more.

(env) > ansible-playbook pb-iocage-swarms-destroy.yml -i iocage.ini -i hosts
PLAY [Destroy swarms.] *********************************************************

TASK [Stop swarms.] ************************************************************
changed: [iocage_04] => (item=db)
changed: [iocage_02] => (item=www_prod)
changed: [iocage_02] => (item=www_devel)

TASK [Destroy swarms.] *********************************************************
changed: [iocage_04] => (item=db)
changed: [iocage_02] => (item=www_prod)
changed: [iocage_02] => (item=www_devel)

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