207 Create DHCP jails with auto UUID, iocage_tags, alias and class
Use case
At multiple iocage hosts, create and run VNET jails with a DHCP interface from the template
ansible_client. Use the dictionary iocage_tags and option inventory_hostname_tag to
create inventory aliases. Group the jails by iocage hosts, states, and classes. Declare the
project in a single dictionary. The dictionary keys are jails’ aliases. For example,
project:
logserv_1:
class: [logserv]
vmm: iocage_01
http_1:
class: [http, logclient]
vmm: iocage_02
db_1:
class: [db, logclient]
vmm: iocage_02
http_2:
class: [http, logclient]
vmm: iocage_04
db_2:
class: [db, logclient]
vmm: iocage_04
Tree
shell> tree .
.
├── ansible.cfg
├── group_vars
│ └── all
│ └── project.yml
├── hosts
│ ├── 01_iocage.yml
│ ├── 02_iocage.yml
│ ├── 04_iocage.yml
│ └── 99_constructed.yml
├── host_vars
│ ├── iocage_01
│ │ └── iocage.yml
│ ├── iocage_02
│ │ └── iocage.yml
│ └── iocage_04
│ └── iocage.yml
├── iocage.ini
└── pb-test-all.yml
Synopsis
At three managed nodes:
iocage_01
iocage_02
iocage_04
In the playbook
vbotka.freebsd.pb_iocage_project_create.yml, use:inventory plugin vbotka.freebsd.iocage to create inventory hosts
inventory plugin ansible.builtin.constructed to create groups and compose variables:
ansible_hostiocage_tagsiocage_classes
module
ansible.builtin.commandand the binary iocage to:create jails
set notes
start jails
At all jails:
In the playbook
pb-test-all.yml, display:variables:
ansible_hostiocage_properties.host_hostuuidiocage_tagsiocage_classes
inventory groups.
Requirements
root privilege in the managed nodes
templates created in 202 Create iocage templates. Clone DHCP jails.
Notes
Templates created in 202 Create iocage templates. Clone DHCP jails. are used in this example.
ansible.cfg
[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
host_key_checking = false
[connection]
pipelining = true
Inventory iocage.ini
iocage_01 ansible_host=10.1.0.18
iocage_02 ansible_host=10.1.0.73
iocage_04 ansible_host=10.1.0.29
[iocage]
iocage_01
iocage_02
iocage_04
[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent
Templates at iocage_01
[iocage_01]# iocage list -lt
+------+----------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+======+================+======+=======+==========+=================+====================+=====+==========+==========+
| None | ansible_client | off | down | template | 13.5-RELEASE-p1 | DHCP (not running) | - | - | no |
+------+----------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
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 |
+------+-----------------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
group_vars
# The project keys are jails aliases.
project:
logserv_1:
class: [logserv]
vmm: iocage_01
http_1:
class: [http, logclient]
vmm: iocage_02
db_1:
class: [db, logclient]
vmm: iocage_02
http_2:
class: [http, logclient]
vmm: iocage_04
db_2:
class: [db, logclient]
vmm: iocage_04
# Declare vmm. Dictionary of iocage hosts.
vmm_groups: "{{ dict(project | dict2items | groupby('value.vmm')) }}"
vmm: "{{ dict(vmm_groups.keys() | zip(vmm_groups.values() | map('items2dict'))) }}"
# Declare class. Dictionary of classes.
class_list: "{{ project | dict2items }}"
class_keys: "{{ class_list | map(attribute='value.class') | flatten | unique | sort }}"
class: |
{% filter from_yaml %}
{% for k in class_keys %}
{{ k }}: {{ class_list | selectattr('value.class', 'contains', k) | map(attribute='key') }}
{% endfor %}
{% endfilter %}
# Jail properties.
properties: "bpf=1 dhcp=1 vnet=1"
host_vars
# In production, put the password into the vault.
ansible_become_password: admin
# Add iocage_02 host specific varaiables here.
# Add iocage_04 host specific varaiables here.
Inventory hosts
plugin: vbotka.freebsd.iocage
host: 10.1.0.18
user: admin
cache: true
cache_plugin: ansible.builtin.jsonfile
cache_connection: /var/tmp/inventory_cache
cache_timeout: 3600
cache_prefix: iocage_01_
get_properties: true
inventory_hostname_tag: alias
hooks_results:
- /var/db/dhclient-hook.address.epair0b
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
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
plugin: ansible.builtin.constructed
compose:
ansible_host: (iocage_hooks.0 == '-') | ternary(iocage_ip4, iocage_hooks.0)
iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)'))
iocage_classes: iocage_properties.notes | regex_findall('class=(\w+)')
groups:
db: "'db' in iocage_classes"
http: "'http' in iocage_classes"
logclient: "'logclient' in iocage_classes"
logserv: "'logserv' in iocage_classes"
keyed_groups:
- prefix: state
key: iocage_state
- prefix: vmm
key: iocage_tags.vmm
Note
This example is tested with present jails
[iocage_01]# iocage list -h
- test_1 down 13.5-RELEASE -
[iocage_02]# iocage list -h
- test_2 down 14.2-RELEASE -
[iocage_04]# iocage list -h
- test_4 down 14.3-RELEASE -
Playbook output - Create and start project jails
(env) > ansible-playbook vbotka.freebsd.pb_iocage_project_create.yml \
-i hosts -i iocage.ini -e debug=true
See also
The playbook pb_iocage_project_create
Note
The inventory -i hosts provides the group of all created jails. The play can use it and
create only the missing project jails. This makes the play idempotent despite the module
ansible.builtin.command and iocage option --count being used.
PLAY [Create and start project jails.] *****************************************
TASK [Display vars.] ***********************************************************
ok: [iocage_01] =>
msg: |-
project_template: ansible_client
project_create_iocage_tags: False
vmm:
iocage_01:
logserv_1:
class: [logserv]
vmm: iocage_01
iocage_02:
db_1:
class: [db, logclient]
vmm: iocage_02
http_1:
class: [http, logclient]
vmm: iocage_02
iocage_04:
db_2:
class: [db, logclient]
vmm: iocage_04
http_2:
class: [http, logclient]
vmm: iocage_04
class:
db: [db_1, db_2]
http: [http_1, http_2]
logclient: [http_1, db_1, http_2, db_2]
logserv: [logserv_1]
groups.all: ['test_1', 'test_2', 'test_4', 'iocage_01', 'iocage_02', 'iocage_04']
project_jails_present: []
project_jails_absent: ['http_1', 'db_1', 'http_2', 'logserv_1', 'db_2']
TASK [Create jails.] ***********************************************************
changed: [iocage_04]
changed: [iocage_01]
changed: [iocage_02]
TASK [Set notes.] **************************************************************
changed: [iocage_04] => (item=http_2 alias=http_2 class=http,logclient vmm=iocage_04)
changed: [iocage_04] => (item=db_2 alias=db_2 class=db,logclient vmm=iocage_04)
changed: [iocage_01] => (item=logserv_1 alias=logserv_1 class=logserv vmm=iocage_01)
changed: [iocage_02] => (item=http_1 alias=http_1 class=http,logclient vmm=iocage_02)
changed: [iocage_02] => (item=db_1 alias=db_1 class=db,logclient vmm=iocage_02)
TASK [Start created jails.] ****************************************************
changed: [iocage_01]
changed: [iocage_04]
changed: [iocage_02]
PLAY RECAP *********************************************************************
iocage_01 : ok=4 changed=3 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
iocage_02 : ok=3 changed=3 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
iocage_04 : ok=3 changed=3 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
Playbook pb-test-all.yml
- name: Display all groups.
hosts: all
tasks:
- debug:
msg: |
ansible_host: {{ ansible_host | d('UNDEFINED') }}
iocage_properties.host_hostuuid: {{ iocage_properties.host_hostuuid | d('UNDEFINED') }}
iocage_classes: {{ iocage_classes | d([]) | to_yaml }}
iocage_tags: {{ iocage_tags | d({}) | to_yaml }}
- debug:
msg: |
{% for group in groups %}
{{ group }}: {{ groups[group] }}
{% endfor %}
run_once: true
See also
Playbook output - Display all groups
(env) > ansible-playbook -i hosts pb-test-all.yml --flush-cache
Note
The inventory configuration files
hosts/*.ymlenable cache.Flush the cache. Otherwise, the jails created in the previous play won’t be included.
PLAY [Display all groups.] *****************************************************
TASK [debug] *******************************************************************
ok: [test_1] =>
msg: |-
ansible_host: -
iocage_properties.host_hostuuid: test_1
iocage_classes: []
iocage_tags: {}
ok: [logserv_1] =>
msg: |-
ansible_host: 10.1.0.213
iocage_properties.host_hostuuid: fb342671
iocage_classes: [logserv]
iocage_tags: {alias: logserv_1, class: logserv, vmm: iocage_01}
ok: [test_2] =>
msg: |-
ansible_host: -
iocage_properties.host_hostuuid: test_2
iocage_classes: []
iocage_tags: {}
ok: [http_1] =>
msg: |-
ansible_host: 10.1.0.187
iocage_properties.host_hostuuid: 2355c7ca
iocage_classes: [http, logclient]
iocage_tags: {alias: http_1, class: 'http,logclient', vmm: iocage_02}
ok: [db_1] =>
msg: |-
ansible_host: 10.1.0.190
iocage_properties.host_hostuuid: a36ffb91
iocage_classes: [db, logclient]
iocage_tags: {alias: db_1, class: 'db,logclient', vmm: iocage_02}
ok: [test_4] =>
msg: |-
ansible_host: -
iocage_properties.host_hostuuid: test_4
iocage_classes: []
iocage_tags: {}
ok: [http_2] =>
msg: |-
ansible_host: 10.1.0.130
iocage_properties.host_hostuuid: 0353ff78
iocage_classes: [http, logclient]
iocage_tags: {alias: http_2, class: 'http,logclient', vmm: iocage_04}
ok: [db_2] =>
msg: |-
ansible_host: 10.1.0.101
iocage_properties.host_hostuuid: 48dc9d76
iocage_classes: [db, logclient]
iocage_tags: {alias: db_2, class: 'db,logclient', vmm: iocage_04}
TASK [debug] *******************************************************************
ok: [test_1] =>
msg: |-
all: ['test_1', 'logserv_1', 'test_2', 'http_1', 'db_1', 'test_4', 'http_2', 'db_2']
ungrouped: []
state_down: ['test_1', 'test_2', 'test_4']
logserv: ['logserv_1']
state_up: ['logserv_1', 'http_1', 'db_1', 'http_2', 'db_2']
vmm_iocage_01: ['logserv_1']
http: ['http_1', 'http_2']
logclient: ['http_1', 'db_1', 'http_2', 'db_2']
vmm_iocage_02: ['http_1', 'db_1']
db: ['db_1', 'db_2']
vmm_iocage_04: ['http_2', 'db_2']
PLAY RECAP *********************************************************************
db_1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
db_2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
http_1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
http_2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
logserv_1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_4 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook output - Stop and destroy jails
(env) > ansible-playbook vbotka.freebsd.pb_iocage_project_destroy.yml \
-i hosts -i iocage.ini -e debug=true
See also
The playbook pb_iocage_project_destroy
PLAY [Stop and destroy jails.] *************************************************
TASK [Display vars.] ***********************************************************
ok: [iocage_01] =>
msg: |-
vmm:
iocage_01:
logserv_1:
class: [logserv]
vmm: iocage_01
iocage_02:
db_1:
class: [db, logclient]
vmm: iocage_02
http_1:
class: [http, logclient]
vmm: iocage_02
iocage_04:
db_2:
class: [db, logclient]
vmm: iocage_04
http_2:
class: [http, logclient]
vmm: iocage_04
class:
db: [db_1, db_2]
http: [http_1, http_2]
logclient: [http_1, db_1, http_2, db_2]
logserv: [logserv_1]
groups.all: ['test_1', 'logserv_1', 'test_2', 'http_1', 'db_1', 'test_4', 'http_2', 'db_2', 'iocage_01', 'iocage_02', 'iocage_04']
project_jails_present: ['db_1', 'http_2', 'logserv_1', 'db_2', 'http_1']
TASK [Stop jails.] *************************************************************
changed: [iocage_01]
changed: [iocage_04]
changed: [iocage_02]
TASK [Destroy jails.] **********************************************************
changed: [iocage_04]
changed: [iocage_01]
changed: [iocage_02]
PLAY RECAP *********************************************************************
iocage_01 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
iocage_02 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
iocage_04 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook output - Display all groups
(env) > ansible-playbook -i hosts pb-test-all.yml --flush-cache
PLAY [Display all groups.] *****************************************************
TASK [debug] *******************************************************************
ok: [test_1] =>
msg: |-
ansible_host: -
iocage_properties.host_hostuuid: test_1
iocage_classes: []
iocage_tags: {}
ok: [test_2] =>
msg: |-
ansible_host: -
iocage_properties.host_hostuuid: test_2
iocage_classes: []
iocage_tags: {}
ok: [test_4] =>
msg: |-
ansible_host: -
iocage_properties.host_hostuuid: test_4
iocage_classes: []
iocage_tags: {}
TASK [debug] *******************************************************************
ok: [test_1] =>
msg: |-
all: ['test_1', 'test_2', 'test_4']
ungrouped: []
state_down: ['test_1', 'test_2', 'test_4']
PLAY RECAP *********************************************************************
test_1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_4 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0