206 Create DHCP and fixed IP jails from template¶
Extending example 203 Create DHCP jails from template. Auto UUID, iocage_tags.
Use case¶
In the inventory plugin vbotka.freebsd.iocage configuration file, use the option hooks_results to get the DHCP IP address. This option is common for all jails
hooks_results:
- /var/db/dhclient-hook.address.epair0b
It will silently fail in jails with fixed IP addresses. If the item fails the result is a dash character ‘-’
iocage_hooks:
- '-'
This use-case demonstrates the advantage of silently ignoring failed items over the potential explicit error handling. Let the option compose pick what is needed
compose:
ansible_host: (iocage_hooks.0 == '-') | ternary(iocage_ip4, iocage_hooks.0)
Fixed IP
In this example, one jail with fixed IP will be created from the template ansible_client
clones:
test_111:
clone_from: ansible_client
properties:
ip4_addr: "em0|10.1.0.111/24"
notes: "swarm=sw_01"
Automatically generated UUID
Two DHCP jails with generated UUID will be created from the template ansible_client
swarms:
sw_01:
count: 3
template: ansible_client
properties:
bpf: 1
dhcp: 1
vnet: 1
Note
The clone test_111 belongs to the swarm sw_01. Set count: 3 to create two more jails in the swarm sw_01.
The module vbotka.freebsd.iocage doesn’t work with multiple names. We will use ansible.builtin.command instead. Anyway, such a task is not idempotent if the UUID is generated automatically. Example of the commands
iocage create --short --template ansible_client --count 2 bpf=1 dhcp=1 vnet=1 notes="vmm=iocage_02 swarm=sw_01"
iocage start cd31c2a2 d254f889
The variable iocage_tags
The inventory plugin composes the variable iocage_tags
iocage_tags: dict(iocage_properties.notes | split | map('split', '='))
For example,
iocage_tags:
vmm: iocage_02
swarm: sw_01
This option is used to create groups from iocage_tags
keyed_groups:
- prefix: swarm
key: iocage_tags.swarm
- prefix: vmm
key: iocage_tags.vmm
Tree¶
shell> tree .
.
├── ansible.cfg
├── hosts
│ └── 02_iocage.yml
├── host_vars
│ └── iocage_02
│ └── iocage.yml
├── iocage-hosts.ini
├── pb-iocage-ansible-clients -> ../../../../playbooks/pb-iocage-ansible-clients
├── pb-iocage-ansible-clients.yml -> ../../../../playbooks/pb-iocage-ansible-clients.yml
└── pb-test-01.yml
Synopsis¶
On one iocage hosts:
iocage_02
In the playbook pb-iocage-ansible-clients.yml, use the module:
vbotka.freebsd.iocage to:
create one jail with fixed IP
start the jail
ansible.builtin.command to:
create two DHCP jails with generated UUID
start the jails
On all created jails:
In the playbook pb-test-01.yml:
connect created jails
display basic configuration of the jails.
Requirements¶
root privilege on the iocage hosts
activated iocage
fetched releases
templates created in example 205
Notes¶
Templates created in 205 Create Ansible client templates v2 are used in this example.
The dash “-” is used in binary iocage to represent a missing value. See for example:
inventory plugin vbotka.freebsd.iocage uses it too
if iocage_ip4_dict['ip4']: iocage_ip4 = ','.join([d['ip'] for d in iocage_ip4_dict['ip4']]) else: iocage_ip4 = '-'
See also
List 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.1-RELEASE-p6 | em0|10.1.0.199/24 | - | - | no |
+------+----------------+------+-------+----------+-----------------+-------------------+-----+----------+----------+
Configuration ansible.cfg¶
[defaults]
gathering = explicit
callback_result_format = yaml
[connection]
pipelining = true
host_vars/iocage_02/iocage.yml¶
ansible_python_interpreter: /usr/local/bin/python3.11
freebsd_iocage_runner_env:
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
properties:
notes: "vmm={{ inventory_hostname }}"
clones:
test_111:
clone_from: ansible_client
properties:
ip4_addr: "em0|10.1.0.111/24"
notes: "swarm=sw_01"
start: [test_111]
swarms:
sw_01:
count: 3
template: ansible_client
properties:
bpf: 1
dhcp: 1
vnet: 1
Inventory iocage-hosts.ini¶
iocage_01 ansible_host=10.1.0.18
iocage_02 ansible_host=10.1.0.73
iocage_03 ansible_host=10.1.0.17
[iocage]
iocage_01
iocage_02
iocage_03
[iocage:vars]
ansible_user=admin
ansible_become=true
Playbook pb-iocage-ansible-clients.yml¶
- name: Create and start jails. Optionally stop and destroy jails.
hosts: iocage
environment: "{{ freebsd_iocage_runner_env | d({}) }}"
vars:
debug: false
debug2: false
dry_run: false
swarm: false
swarm_destroy: false
clone: false
clone_destroy: false
_tags: "{{ dict(iocage_jails.keys()
| zip(iocage_jails.values()
| map(attribute='properties.notes')
| map('split')
| map('map', 'split', '=')
| map('community.general.dict'))) }}"
_started: "{{ iocage_jails | dict2items
| selectattr('value.state', 'eq', 'up')
| map(attribute='key') }}"
tasks:
- name: Create and start swarms
when: swarm | bool
tags: swarm
ansible.builtin.import_tasks: pb-iocage-ansible-clients/swarm.yml
- name: Stop and destroy swarms
when: swarm_destroy | bool
tags: swarm_destroy
ansible.builtin.import_tasks: pb-iocage-ansible-clients/swarm_destroy.yml
- name: Create and start clones
when: clone | bool
tags: clone
ansible.builtin.import_tasks: pb-iocage-ansible-clients/clone.yml
- name: Stop and destroy clones
when: clone_destroy | bool
tags: clone_destroy
ansible.builtin.import_tasks: pb-iocage-ansible-clients/clone_destroy.yml
- name: Display iocage_jails
when: debug | bool or debug2 | bool
tags: list
ansible.builtin.import_tasks: pb-iocage-ansible-clients/list.yml
Create and start clones¶
(env) > ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini \
-l iocage_02 \
-t clone \
-e clone=true
PLAY [Create and start jails. Optionally stop and destroy jails.] ******************************
TASK [Create clones from template] *************************************************************
changed: [iocage_02] => (item=test_111 ansible_client)
TASK [Debug clones from template debug2=False] *************************************************
skipping: [iocage_02]
TASK [Start clones] ****************************************************************************
changed: [iocage_02] => (item=test_111)
TASK [Debug start clones debug2=False] *********************************************************
skipping: [iocage_02]
PLAY RECAP *************************************************************************************
iocage_02: ok=2 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
Create and start swarms¶
(env) > ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini \
-l iocage_02 \
-t swarm \
-e swarm=true \
-e debug=true
PLAY [Create and start jails. Optionally stop and destroy jails.] ******************************
TASK [Get iocage facts] ************************************************************************
ok: [iocage_02]
TASK [Debug iocage_jails] **********************************************************************
skipping: [iocage_02]
TASK [Debug _tags] *****************************************************************************
ok: [iocage_02] =>
_tags:
test_111:
swarm: sw_01
vmm: iocage_02
TASK [Debug cmd_create] ************************************************************************
ok: [iocage_02] => (item=sw_01) =>
msg: |-
iocage create --short --template ansible_client --count 2 notes="vmm=iocage_02 swarm=sw_01" bpf=1 dhcp=1 vnet=1
TASK [Create swarms] ***************************************************************************
changed: [iocage_02] => (item=sw_01)
TASK [Debug create swarms] *********************************************************************
ok: [iocage_02] =>
out:
changed: true
msg: All items completed
results:
- ansible_loop_var: item
changed: true
cmd:
- iocage
- create
- --short
- --template
- ansible_client
- --count
- '2'
- notes=vmm=iocage_02 swarm=sw_01
- bpf=1
- dhcp=1
- vnet=1
delta: '0:00:03.748798'
end: '2025-02-09 15:09:33.960064'
failed: false
invocation:
module_args:
_raw_params: |-
iocage create --short --template ansible_client --count 2 notes="vmm=iocage_02 swarm=sw_01" bpf=1 dhcp=1 vnet=1
_uses_shell: false
argv: null
chdir: null
creates: null
executable: null
expand_argument_vars: true
removes: null
stdin: null
stdin_add_newline: true
strip_empty_ends: true
item:
key: sw_01
value:
count: 3
properties:
bpf: 1
dhcp: 1
vnet: 1
template: ansible_client
msg: ''
rc: 0
start: '2025-02-09 15:09:30.211266'
stderr: ''
stderr_lines: []
stdout: |-
7509aed0 successfully created!
e3c34e4f successfully created!
stdout_lines:
- 7509aed0 successfully created!
- e3c34e4f successfully created!
skipped: false
TASK [Get iocage facts] ************************************************************************
ok: [iocage_02]
TASK [Debug iocage_jails] **********************************************************************
skipping: [iocage_02]
TASK [Debug cmd_start] *************************************************************************
ok: [iocage_02] => (item=sw_01) =>
msg: |-
iocage start 7509aed0 e3c34e4f
TASK [Start swarms] ****************************************************************************
changed: [iocage_02] => (item=sw_01)
TASK [Debug start swarms] **********************************************************************
ok: [iocage_02] =>
out:
changed: true
msg: All items completed
results:
- ansible_loop_var: item
changed: true
cmd:
- iocage
- start
- 7509aed0
- e3c34e4f
delta: '0:00:25.409272'
end: '2025-02-09 15:10:20.381974'
failed: false
invocation:
module_args:
_raw_params: |-
iocage start 7509aed0 e3c34e4f
_uses_shell: false
argv: null
chdir: null
creates: null
executable: null
expand_argument_vars: true
removes: null
stdin: null
stdin_add_newline: true
strip_empty_ends: true
item:
key: sw_01
value:
count: 3
properties:
bpf: 1
dhcp: 1
vnet: 1
template: ansible_client
msg: ''
rc: 0
start: '2025-02-09 15:09:54.972702'
stderr: |-
No default gateway found for ipv6.
No default gateway found for ipv6.
stderr_lines:
- No default gateway found for ipv6.
- No default gateway found for ipv6.
stdout: |-
* Starting 7509aed0
+ Started OK
+ Using devfs_ruleset: 1001 (iocage generated default)
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
+ DHCP Address: 10.1.0.156/24
* Starting e3c34e4f
+ Started OK
+ Using devfs_ruleset: 1002 (iocage generated default)
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
+ DHCP Address: 10.1.0.243/24
stdout_lines:
- '* Starting 7509aed0'
- ' + Started OK'
- ' + Using devfs_ruleset: 1001 (iocage generated default)'
- ' + Configuring VNET OK'
- ' + Using IP options: vnet'
- ' + Starting services OK'
- ' + Executing poststart OK'
- ' + DHCP Address: 10.1.0.156/24'
- '* Starting e3c34e4f'
- ' + Started OK'
- ' + Using devfs_ruleset: 1002 (iocage generated default)'
- ' + Configuring VNET OK'
- ' + Using IP options: vnet'
- ' + Starting services OK'
- ' + Executing poststart OK'
- ' + DHCP Address: 10.1.0.243/24'
skipped: false
PLAY RECAP *************************************************************************************
iocage_02: ok=9 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
List jails at iocage_02¶
[iocage_02]# iocage list -l
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+=====+==========+======+=======+======+=================+====================+=====+================+==========+
| 88 | 7509aed0 | off | up | jail | 14.1-RELEASE-p6 | epair0b|10.1.0.156 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| 89 | e3c34e4f | off | up | jail | 14.1-RELEASE-p6 | epair0b|10.1.0.243 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| 87 | test_111 | off | up | jail | 14.1-RELEASE-p6 | em0|10.1.0.111/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
Inventory hosts/02_iocage.yml¶
plugin: vbotka.freebsd.iocage
host: 10.1.0.73
user: admin
env:
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
get_properties: True
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 | split | map('split', '='))
keyed_groups:
- prefix: swarm
key: iocage_tags.swarm
- prefix: vmm
key: iocage_tags.vmm
Note
The option “get_properties: True” is needed to get the dictionary iocage_properties
Display inventory¶
(env) > ansible-inventory -i hosts --graph
@all:
|--@ungrouped:
|--@swarm_sw_01:
| |--7509aed0
| |--e3c34e4f
| |--test_111
|--@vmm_iocage_02:
| |--7509aed0
| |--e3c34e4f
| |--test_111
Playbook pb-test-01.yml¶
- hosts: swarm_sw_01
remote_user: admin
vars:
ansible_python_interpreter: auto_silent
tasks:
- ansible.builtin.command: hostname
register: out
- ansible.builtin.debug:
msg: |
out.stdout: {{ out.stdout }}
ansible_host: {{ ansible_host }}
iocage_hooks: {{ iocage_hooks }}
iocage_tags:
{{ iocage_tags | to_nice_yaml(2) | indent(2) }}
Playbook output¶
(env) > ansible-playbook pb-test-01.yml -i hosts
PLAY [swarm_sw_01] ****************************************************************************
TASK [ansible.builtin.command] ****************************************************************
changed: [test_111]
changed: [e3c34e4f]
changed: [7509aed0]
TASK [ansible.builtin.debug] ******************************************************************
ok: [7509aed0] =>
msg: |-
out.stdout: 7509aed0
ansible_host: 10.1.0.156
iocage_hooks: ['10.1.0.156']
iocage_tags:
swarm: sw_01
vmm: iocage_02
ok: [e3c34e4f] =>
msg: |-
out.stdout: e3c34e4f
ansible_host: 10.1.0.243
iocage_hooks: ['10.1.0.243']
iocage_tags:
swarm: sw_01
vmm: iocage_02
ok: [test_111] =>
msg: |-
out.stdout: test-111
ansible_host: 10.1.0.111
iocage_hooks: ['-']
iocage_tags:
swarm: sw_01
vmm: iocage_02
PLAY RECAP ************************************************************************************
7509aed0: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
e3c34e4f: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_111: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Hint
The below command stops and destroys the jails in swarms
ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini \
-l iocage_02 \
-t swarm_destroy \
-e swarm_destroy=true