443 Plugin ansible-zero¶
Use case¶
Clone multiple jails from the iocage plugin ansible-zero. Use the connection
plugin vbotka.freebsd.jailexec to connect the jails.
Tree¶
shell> tree .
.
├── ansible.cfg
├── hosts
│ ├── 05_iocage.yml
│ └── 99_constructed.yml
├── host_vars
│ └── iocage_05.yml
├── iocage.ini
└── pb-test.yml
Synopsis¶
At a managed node:
In the playbook vbotka.freebsd.pb_iocage_plugins.yml:
Fetch the iocage plugin
ansible-zero
In the playbook vbotka.freebsd.pb_iocage_ansible_clients.yml:
Clone jails from the iocage plugin
ansible-zero
Create dynamic inventory to connect the jails by connection plugin vbotka.freebsd.jailexec
At all cloned jails:
In the playbook
pb-test.yml:Connect to the cloned jails
Display basic configuration of the jails.
Requirements¶
iocage plugin
ansible-zeroplaybook vbotka.freebsd.pb_iocage_plugins.yml
root privilege in the managed nodes
Notes¶
The iocage plugin
ansible-zerois used in the playbook vbotka.freebsd.pb_iocage_ansible_clients.yml to create theswarm.
See also
Example 050 Connection jailexec
GitHub repository iocage plugins
ansible.cfg¶
[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
deprecation_warnings=false
[connection]
pipelining = true
Inventory iocage.ini¶
iocage_05
[iocage]
iocage_05
[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent
host_vars¶
properties:
bpf: 1
dhcp: 1
vnet: 1
notes: "vmm={{ inventory_hostname }}"
swarms:
sw_01:
count: 3
plugin: ansible-zero
plugins:
ansible-zero:
git: https://github.com/vbotka/iocage-plugins
options: bpf=1 dhcp=1 vnet=1
Playbook output - Fetch plugins¶
(env) > ansible-playbook vbotka.freebsd.pb_iocage_plugins.yml \
-i iocage.ini \
-t required_plugins \
-e debug=true
PLAY [Fetch and stop iocage plugins.] ******************************************
TASK [Get already fetched plugins.] ********************************************
ok: [iocage_05]
TASK [Debug fetched plugins debug=true] ****************************************
ok: [iocage_05] =>
msg: |-
iocage_plugins:
{}
plugins:
ansible-zero:
git: https://github.com/vbotka/iocage-plugins
options: bpf=1 dhcp=1 vnet=1
TASK [Debug required plugins debug=true] ***************************************
ok: [iocage_05] =>
msg: |-
required_plugins:
- ansible-zero
selected_plugins:
- key: ansible-zero
value:
git: https://github.com/vbotka/iocage-plugins
options: bpf=1 dhcp=1 vnet=1
TASK [Check all required plugins are included in the dictionary plugins.] ******
ok: [iocage_05]
TASK [Debug commands debug=true] ***********************************************
ok: [iocage_05] => (item=ansible-zero) =>
msg: |-
iocage fetch --plugin-name ansible-zero --git_repository https://github.com/vbotka/iocage-plugins bpf=1 dhcp=1 vnet=1
TASK [Fetch required plaugins.] ************************************************
changed: [iocage_05] => (item=ansible-zero)
TASK [Stop fetched plugins.] ***************************************************
changed: [iocage_05]
PLAY RECAP *********************************************************************
iocage_05 : ok=7 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Note
The “Testing ansible-zero’s DNSSEC response to pkg.FreeBSD.org” by iocage fetch may take some time.
Plugins at iocage_05¶
[iocage_05]# iocage list -P
+------+--------------+------+-------+----------+--------------+--------------------+-----+----------+--------+---------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | PORTAL | DOC_URL |
+======+==============+======+=======+==========+==============+====================+=====+==========+========+=========+
| None | ansible-zero | on | down | pluginv2 | 15.0-RELEASE | DHCP (not running) | - | - | - | - |
+------+--------------+------+-------+----------+--------------+--------------------+-----+----------+--------+---------+
Playbook output - Create and start swarms¶
(env) > ansible-playbook vbotka.freebsd.pb_iocage_ansible_clients.yml \
-i iocage.ini \
-t swarm \
-e swarm=true \
-e debug=true
PLAY [Create and start jails. Optionally stop and destroy jails.] **************
TASK [Get iocage facts] ********************************************************
ok: [iocage_05]
TASK [Reject jails with empty notes] *******************************************
ok: [iocage_05]
TASK [Debug cmd_create debug=true] *********************************************
ok: [iocage_05] => (item=sw_01) =>
msg: |-
iocage clone ansible-zero --newmac --count 3 bpf=1 dhcp=1 vnet=1 notes="vmm=iocage_05 swarm=sw_01"
TASK [Create swarms] ***********************************************************
changed: [iocage_05] => (item=sw_01)
TASK [Debug create swarms debug=true] ******************************************
ok: [iocage_05] =>
out:
changed: true
msg: All items completed
results:
- ansible_loop_var: item
changed: true
cmd:
- iocage
- clone
- ansible-zero
- --newmac
- --count
- '3'
- bpf=1
- dhcp=1
- vnet=1
- notes=vmm=iocage_05 swarm=sw_01
delta: '0:00:00.897302'
end: '2026-04-23 09:40:13.174121'
failed: false
invocation:
module_args:
_raw_params: null
_uses_shell: false
argv: null
chdir: null
cmd: |-
iocage clone ansible-zero --newmac --count 3 bpf=1 dhcp=1 vnet=1 notes="vmm=iocage_05 swarm=sw_01"
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
plugin: ansible-zero
msg: ''
rc: 0
start: '2026-04-23 09:40:12.276819'
stderr: ''
stderr_lines: []
stdout: |-
4ddecd35-83a8-43fe-97c0-26ce93a9fb51 successfully cloned!
a59dc6c6-fda8-432a-95ae-fedb9bf2313e successfully cloned!
bd21d433-2685-4b53-be96-4b45cbb77ddc successfully cloned!
stdout_lines:
- 4ddecd35-83a8-43fe-97c0-26ce93a9fb51 successfully cloned!
- a59dc6c6-fda8-432a-95ae-fedb9bf2313e successfully cloned!
- bd21d433-2685-4b53-be96-4b45cbb77ddc successfully cloned!
skipped: false
TASK [Get iocage facts] ********************************************************
ok: [iocage_05]
TASK [Reject jails with empty notes] *******************************************
ok: [iocage_05]
TASK [Debug cmd_start debug=true] **********************************************
ok: [iocage_05] => (item=sw_01) =>
msg: |-
iocage start a59dc6c6-fda8-432a-95ae-fedb9bf2313e 4ddecd35-83a8-43fe-97c0-26ce93a9fb51 bd21d433-2685-4b53-be96-4b45cbb77ddc
TASK [Start swarms] ************************************************************
changed: [iocage_05] => (item=sw_01)
TASK [Debug start swarms debug=true] *******************************************
ok: [iocage_05] =>
out:
changed: true
msg: All items completed
results:
- ansible_loop_var: item
changed: true
cmd:
- iocage
- start
- a59dc6c6-fda8-432a-95ae-fedb9bf2313e
- 4ddecd35-83a8-43fe-97c0-26ce93a9fb51
- bd21d433-2685-4b53-be96-4b45cbb77ddc
delta: '0:00:07.051195'
end: '2026-04-23 09:40:26.189221'
failed: false
invocation:
module_args:
_raw_params: null
_uses_shell: false
argv: null
chdir: null
cmd: |-
iocage start a59dc6c6-fda8-432a-95ae-fedb9bf2313e 4ddecd35-83a8-43fe-97c0-26ce93a9fb51 bd21d433-2685-4b53-be96-4b45cbb77ddc
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
plugin: ansible-zero
msg: ''
rc: 0
start: '2026-04-23 09:40:19.138026'
stderr: |-
No default gateway found for ipv6.
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.
- No default gateway found for ipv6.
stdout: |-
* Starting a59dc6c6-fda8-432a-95ae-fedb9bf2313e
+ Started OK
+ Using devfs_ruleset: 1000 (iocage generated default)
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
+ DHCP Address: 10.10.99.120/24
* Starting 4ddecd35-83a8-43fe-97c0-26ce93a9fb51
+ 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.10.99.121/24
* Starting bd21d433-2685-4b53-be96-4b45cbb77ddc
+ 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.10.99.122/24
stdout_lines:
- '* Starting a59dc6c6-fda8-432a-95ae-fedb9bf2313e'
- ' + Started OK'
- ' + Using devfs_ruleset: 1000 (iocage generated default)'
- ' + Configuring VNET OK'
- ' + Using IP options: vnet'
- ' + Starting services OK'
- ' + Executing poststart OK'
- ' + DHCP Address: 10.10.99.120/24'
- '* Starting 4ddecd35-83a8-43fe-97c0-26ce93a9fb51'
- ' + 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.10.99.121/24'
- '* Starting bd21d433-2685-4b53-be96-4b45cbb77ddc'
- ' + 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.10.99.122/24'
skipped: false
PLAY RECAP *********************************************************************
iocage_05 : ok=10 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
Jails at iocage_05¶
[iocage_05]# iocage list -l
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+--------------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+======+======================================+======+=======+==========+==============+======================+=====+==============+==========+
| 6 | 4ddecd35-83a8-43fe-97c0-26ce93a9fb51 | on | up | pluginv2 | 15.0-RELEASE | epair0b|10.10.99.121 | - | ansible-zero | yes |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+--------------+----------+
| 5 | a59dc6c6-fda8-432a-95ae-fedb9bf2313e | on | up | pluginv2 | 15.0-RELEASE | epair0b|10.10.99.120 | - | ansible-zero | yes |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+--------------+----------+
| None | ansible-zero | on | down | pluginv2 | 15.0-RELEASE | DHCP (not running) | - | - | yes |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+--------------+----------+
| 7 | bd21d433-2685-4b53-be96-4b45cbb77ddc | on | up | pluginv2 | 15.0-RELEASE | epair0b|10.10.99.122 | - | ansible-zero | yes |
+------+--------------------------------------+------+-------+----------+--------------+----------------------+-----+--------------+----------+
Inventory hosts¶
plugin: vbotka.freebsd.iocage
host: iocage_05
user: admin
sudo: true
get_properties: true
hooks_results:
- /var/db/dhclient-hook.address.epair0b
compose:
ansible_connection: "'vbotka.freebsd.jailexec'"
ansible_jail_host: dict(iocage_properties.notes | regex_findall('(\w+)=(\w+)')).vmm | d('none')
ansible_jail_privilege_escalation: "'sudo'"
ansible_user: "'admin'"
ansible_python_interpreter: "'auto_silent'"
iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=(\w+)'))
plugin: ansible.builtin.constructed
keyed_groups:
- prefix: swarm
key: iocage_tags.swarm
- prefix: vmm
key: iocage_tags.vmm
Display inventory¶
(env) > ansible-inventory -i hosts --graph
@all:
|--@ungrouped:
| |--ansible-zero
|--@swarm_sw_01:
| |--4ddecd35-83a8-43fe-97c0-26ce93a9fb51
| |--a59dc6c6-fda8-432a-95ae-fedb9bf2313e
| |--bd21d433-2685-4b53-be96-4b45cbb77ddc
|--@vmm_iocage_05:
| |--4ddecd35-83a8-43fe-97c0-26ce93a9fb51
| |--a59dc6c6-fda8-432a-95ae-fedb9bf2313e
| |--bd21d433-2685-4b53-be96-4b45cbb77ddc
Playbook pb-test.yml¶
- name: Test the connection plugin jailexec.
hosts: swarm_sw_01
gather_facts: false
tasks:
- ansible.builtin.debug:
msg: |
ansible_connection: {{ ansible_connection }}
ansible_host: {{ ansible_host }}
ansible_user: {{ ansible_user }}
ansible_jail_host: {{ ansible_jail_host }}
ansible_jail_privilege_escalation: {{ ansible_jail_privilege_escalation }}
iocage_ip4: {{ iocage_ip4 }}
iocage_tags: {{ iocage_tags }}
Playbook output - Test jailexec connection plugin¶
(env) > ansible-playbook pb-test.yml -i hosts
PLAY [Test the connection plugin jailexec.] ************************************
TASK [ansible.builtin.debug] ***************************************************
ok: [4ddecd35-83a8-43fe-97c0-26ce93a9fb51] =>
msg: |-
ansible_connection: vbotka.freebsd.jailexec
ansible_host: 4ddecd35-83a8-43fe-97c0-26ce93a9fb51
ansible_user: admin
ansible_jail_host: iocage_05
ansible_jail_privilege_escalation: sudo
iocage_ip4: 10.10.99.121
iocage_tags: {'vmm': 'iocage_05', 'swarm': 'sw_01'}
ok: [bd21d433-2685-4b53-be96-4b45cbb77ddc] =>
msg: |-
ansible_connection: vbotka.freebsd.jailexec
ansible_host: bd21d433-2685-4b53-be96-4b45cbb77ddc
ansible_user: admin
ansible_jail_host: iocage_05
ansible_jail_privilege_escalation: sudo
iocage_ip4: 10.10.99.122
iocage_tags: {'vmm': 'iocage_05', 'swarm': 'sw_01'}
ok: [a59dc6c6-fda8-432a-95ae-fedb9bf2313e] =>
msg: |-
ansible_connection: vbotka.freebsd.jailexec
ansible_host: a59dc6c6-fda8-432a-95ae-fedb9bf2313e
ansible_user: admin
ansible_jail_host: iocage_05
ansible_jail_privilege_escalation: sudo
iocage_ip4: 10.10.99.120
iocage_tags: {'vmm': 'iocage_05', 'swarm': 'sw_01'}
PLAY RECAP *********************************************************************
4ddecd35-83a8-43fe-97c0-26ce93a9fb51 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
a59dc6c6-fda8-432a-95ae-fedb9bf2313e : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
bd21d433-2685-4b53-be96-4b45cbb77ddc : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Hint
The below play stops and destroys the jails in swarms
ansible-playbook vbotka.freebsd.pb_iocage_ansible_clients.yml \
-i iocage.ini \
-t swarm_destroy \
-e swarm_destroy=true