200 Create Ansible client templates and clone Ansible client jails¶
Use case¶
Create templates for Ansible clients.
Tree¶
shell> tree .
.
├── ansible.cfg
├── files
│ └── pk_admins.txt
├── hosts
│ ├── 01_iocage.yml
│ ├── 02_iocage.yml
│ └── 03_constructed.yml
├── host_vars
│ ├── iocage_01
│ │ └── iocage.yml
│ └── 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-iocage-template -> ../../../../playbooks/pb-iocage-template
├── pb-iocage-template.yml -> ../../../../playbooks/pb-iocage-template.yml
└── pb-test-01.yml
Synopsis¶
On two iocage hosts:
iocage_01
iocage_02
In the playbook pb-iocage-template.yml, use the modules:
vbotka.freebsd.iocage to create, start, stop, and convert jails to templates.
vbotka.freebsd.iocage exec to create a user and set .ssh ownership.
community.general.pkgng to install packages.
ansible.posix.authorized_key to configure public keys.
ansible.builtin.lineinfile to configure /etc/rc.conf and /usr/local/etc/sudoers
In the playbook pb-iocage-ansible-clients.yml, use the module vbotka.freebsd.iocage to:
create jails from the Ansible client templates
start all jails
optionally display the lists of 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
Notes¶
Configuration ansible.cfg¶
[defaults]
gathering = explicit
callback_result_format = yaml
[connection]
pipelining = true
host_vars/iocage_01/iocage.yml¶
---
ansible_python_interpreter: /usr/local/bin/python3.9
ansible_become_password: admin
freebsd_iocage_pool: pool2
freebsd_iocage_pool_mount: /mnt/pool2
freebsd_iocage_mount: "{{ freebsd_iocage_pool_mount }}/iocage"
templates:
ansible_client:
release: 13.4-RELEASE
properties:
ip4_addr: 'vnet0|10.1.0.198/24'
dhclient: "{{ act_dhclient | dict2items }}"
rcconf: "{{ act_rcconf | dict2items }}"
# ansible client template defaults
act_pkg:
- security/sudo
- lang/python39
act_user: admin
act_pk: pk_admins.txt
act_sudo: true
act_rcconf:
iocage_enable: '"YES"'
sshd_enable: '"YES"'
act_dhclient: {}
clones:
test_101:
clone_from: ansible_client
properties:
ip4_addr: 'vnet0|10.1.0.101/24'
test_102:
clone_from: ansible_client
properties:
ip4_addr: 'vnet0|10.1.0.102/24'
test_103:
clone_from: ansible_client
properties:
ip4_addr: 'vnet0|10.1.0.103/24'
# clones default properties
properties:
vnet: 'on'
defaultrouter: 10.1.0.10
notes: "vmm={{ inventory_hostname }}"
start: "{{ clones.keys() }}"
host_vars/iocage_02/iocage.yml¶
---
ansible_python_interpreter: /usr/local/bin/python3.11
freebsd_iocage_runner_env:
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
freebsd_iocage_pool: zroot
freebsd_iocage_pool_mount: /zroot
freebsd_iocage_mount: "{{ freebsd_iocage_pool_mount }}/iocage"
templates:
ansible_client:
release: 14.1-RELEASE
properties:
ip4_addr: 'em0|10.1.0.199/24'
dhclient: "{{ act_dhclient | dict2items }}"
rcconf: "{{ act_rcconf | dict2items }}"
# ansible client template defaults
act_pkg:
- security/sudo
- lang/python311
act_user: admin
act_pk: pk_admins.txt
act_sudo: true
act_rcconf:
iocage_enable: '"YES"'
sshd_enable: '"YES"'
act_dhclient: {}
clones:
test_111:
clone_from: ansible_client
properties:
ip4_addr: 'em0|10.1.0.111/24'
test_112:
clone_from: ansible_client
properties:
ip4_addr: 'em0|10.1.0.112/24'
test_113:
clone_from: ansible_client
properties:
ip4_addr: 'em0|10.1.0.113/24'
# clones default properties
properties:
notes: "vmm={{ inventory_hostname }}"
start: "{{ clones.keys() }}"
Note
The user act_user will be created in the template.
The user act_user will serve as Ansible remote_user.
The file act_pk provides the public keys allowed to ssh to act_user.
Warning
The user act_user must exist on the iocage host. Otherwise, the module ansible.posix.authorized_key will crash. See pb-iocage-template/pk.yml
The file files/pk_admins.txt was sanitized. Fit the public keys to your needs
shell> cat files/pk_admins.txt ssh-rsa <sanitized> admin@controller
Inventory iocage-hosts.ini¶
iocage_01 ansible_host=10.1.0.18
iocage_02 ansible_host=10.1.0.73
[iocage]
iocage_01
iocage_02
[iocage:vars]
ansible_user=admin
ansible_become=true
Playbook pb-iocage-template.yml¶
- name: Create Ansible client templates.
hosts: iocage
environment: "{{ freebsd_iocage_runner_env | d({}) }}"
vars:
debug: false
debug2: false
tasks:
- name: Setup
tags: [always, setup]
ansible.builtin.import_tasks: pb-iocage-template/setup.yml
- name: Create jails
tags: create
ansible.builtin.import_tasks: pb-iocage-template/create.yml
- name: Start jails
tags: start
ansible.builtin.import_tasks: pb-iocage-template/start.yml
- name: Install packages
when: act_pkg | length > 0
tags: pkg
ansible.builtin.import_tasks: pb-iocage-template/pkg.yml
- name: Create user
when: act_user | length > 0
tags: user
ansible.builtin.import_tasks: pb-iocage-template/user.yml
- name: Configure public keys
when: act_pk | length > 0
tags: pk
ansible.builtin.import_tasks: pb-iocage-template/pk.yml
- name: Configure sudo
when: act_sudo | bool
tags: sudo
ansible.builtin.import_tasks: pb-iocage-template/sudo.yml
- name: Configure dhclient
when: act_dhclient | length > 0
tags: dhclient
ansible.builtin.import_tasks: pb-iocage-template/dhclient.yml
- name: Configure /etc/rc.conf
when: act_rcconf | length > 0
tags: rcconf
ansible.builtin.import_tasks: pb-iocage-template/rc_conf.yml
- name: Stop jails
tags: stop
ansible.builtin.import_tasks: pb-iocage-template/stop.yml
- name: Convert jails to templates
tags: template
ansible.builtin.import_tasks: pb-iocage-template/template.yml
Playbook output¶
(env) > ansible-playbook pb-iocage-template.yml -i iocage-hosts.ini -e debug=true
...
List 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.4-RELEASE-p2 | vnet0|10.1.0.198/24 | - | - | no |
+------+----------------+------+-------+----------+-----------------+---------------------+-----+----------+----------+
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 |
+------+----------------+------+-------+----------+-----------------+-------------------+-----+----------+----------+
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
Clone jails¶
(env) > ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini \
-t clone \
-e clone=true
PLAY [Create and start jails. Optionally stop and destroy jails.] ******************************
TASK [Create clones from template] *************************************************************
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 clones from template debug2=false] *************************************************
skipping: [iocage_01]
skipping: [iocage_02]
TASK [Start clones] ****************************************************************************
changed: [iocage_01] => (item=test_101)
changed: [iocage_02] => (item=test_111)
changed: [iocage_01] => (item=test_102)
changed: [iocage_01] => (item=test_103)
changed: [iocage_02] => (item=test_112)
changed: [iocage_02] => (item=test_113)
TASK [Debug start clones debug2=false] *********************************************************
skipping: [iocage_01]
skipping: [iocage_02]
PLAY RECAP *************************************************************************************
iocage_01: ok=2 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
iocage_02: ok=2 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
List jails¶
(env) > ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini \
-t list \
-e debug=true
PLAY [Create and start jails. Optionally stop and destroy jails.] ******************************
TASK [Get iocage facts] ************************************************************************
ok: [iocage_01]
ok: [iocage_02]
TASK [Display iocage_jails dictionary debug2=False] ********************************************
skipping: [iocage_01]
skipping: [iocage_02]
TASK [Display iocage_jails keys debug=true] ****************************************************
ok: [iocage_01] =>
iocage_jails.keys():
- test_101
- test_102
- test_103
ok: [iocage_02] =>
iocage_jails.keys():
- test_111
- test_112
- test_113
PLAY RECAP *************************************************************************************
iocage_01: ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
iocage_02: ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
List jails at iocage_01¶
[iocage_01]# iocage list -l
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+=====+==========+======+=======+======+=================+=====================+=====+================+==========+
| 134 | test_101 | off | up | jail | 13.4-RELEASE-p2 | vnet0|10.1.0.101/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
| 135 | test_102 | off | up | jail | 13.4-RELEASE-p2 | vnet0|10.1.0.102/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
| 136 | test_103 | off | up | jail | 13.4-RELEASE-p2 | vnet0|10.1.0.103/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
List jails at iocage_02¶
[iocage_02]# iocage list -l
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+=====+==========+======+=======+======+=================+===================+=====+================+==========+
| 170 | test_111 | off | up | jail | 14.1-RELEASE-p6 | em0|10.1.0.111/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
| 171 | test_112 | off | up | jail | 14.1-RELEASE-p6 | em0|10.1.0.112/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
| 172 | test_113 | off | up | jail | 14.1-RELEASE-p6 | em0|10.1.0.113/24 | - | ansible_client | no |
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
Inventory hosts/01_iocage.yml¶
plugin: vbotka.freebsd.iocage
host: 10.1.0.18
user: admin
get_properties: true
compose:
ansible_host: iocage_ip4
groups:
test_01: inventory_hostname.startswith('test')
Inventory hosts/02_iocage.yml¶
plugin: vbotka.freebsd.iocage
host: 10.1.0.73
user: admin
get_properties: true
env:
CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
compose:
ansible_host: iocage_ip4
groups:
test_02: inventory_hostname.startswith('test')
Inventory hosts/03_constructed.yml¶
plugin: ansible.builtin.constructed
groups:
test: inventory_hostname.startswith('test')
Display inventory¶
(env) > ansible-inventory -i hosts --graph
@all:
|--@ungrouped:
|--@test_01:
| |--test_101
| |--test_102
| |--test_103
|--@test_02:
| |--test_111
| |--test_112
| |--test_113
|--@test:
| |--test_101
| |--test_102
| |--test_103
| |--test_111
| |--test_112
| |--test_113
Playbook pb-test-01.yml¶
- name: Connect to the group test.
hosts: test
remote_user: admin
gather_facts: true
vars:
ansible_python_interpreter: auto_silent
tasks:
- ansible.builtin.command: hostname
register: out_host
- ansible.builtin.debug:
msg: >
{{ out_host.stdout }}
{{ iocage_properties.host_hostuuid }}
{{ iocage_properties.hostid }}
{{ discovered_interpreter_python }}
- ansible.builtin.command: whoami
register: out_user
- ansible.builtin.command: whoami
register: out_root
become: true
- ansible.builtin.debug:
msg: >
{{ out_host.stdout }}
{{ out_user.stdout }}
{{ out_root.stdout }}
Playbook output¶
(env) > ansible-playbook pb-test-01.yml -i hosts
PLAY [Connect to the group test.] *************************************************************
TASK [Gathering Facts] ************************************************************************
ok: [test_103]
ok: [test_101]
ok: [test_112]
ok: [test_102]
ok: [test_111]
ok: [test_113]
TASK [ansible.builtin.command] ****************************************************************
changed: [test_102]
changed: [test_103]
changed: [test_101]
changed: [test_112]
changed: [test_111]
changed: [test_113]
TASK [ansible.builtin.debug] ******************************************************************
ok: [test_101] =>
msg: |-
test-101 test_101 34333834-3734-5a43-3331-313342464631 /usr/local/bin/python3.9
ok: [test_102] =>
msg: |-
test-102 test_102 34333834-3734-5a43-3331-313342464631 /usr/local/bin/python3.9
ok: [test_103] =>
msg: |-
test-103 test_103 34333834-3734-5a43-3331-313342464631 /usr/local/bin/python3.9
ok: [test_111] =>
msg: |-
test-111 test_111 ea2ba7d1-4fcd-f13f-82e4-8b32c0a03403 /usr/local/bin/python3.11
ok: [test_112] =>
msg: |-
test-112 test_112 ea2ba7d1-4fcd-f13f-82e4-8b32c0a03403 /usr/local/bin/python3.11
ok: [test_113] =>
msg: |-
test-113 test_113 ea2ba7d1-4fcd-f13f-82e4-8b32c0a03403 /usr/local/bin/python3.11
TASK [ansible.builtin.command] ****************************************************************
changed: [test_101]
changed: [test_111]
changed: [test_112]
changed: [test_103]
changed: [test_102]
changed: [test_113]
TASK [ansible.builtin.command] ****************************************************************
changed: [test_101]
changed: [test_103]
changed: [test_102]
changed: [test_111]
changed: [test_112]
changed: [test_113]
TASK [ansible.builtin.debug] ******************************************************************
ok: [test_101] =>
msg: |-
test-101 admin root
ok: [test_102] =>
msg: |-
test-102 admin root
ok: [test_103] =>
msg: |-
test-103 admin root
ok: [test_111] =>
msg: |-
test-111 admin root
ok: [test_112] =>
msg: |-
test-112 admin root
ok: [test_113] =>
msg: |-
test-113 admin root
PLAY RECAP ************************************************************************************
test_101: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_102: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_103: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_111: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_112: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_113: ok=6 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Hint
The below command stops and destroys the cloned jails
ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini \
-t clone_destroy \
-e clone_destroy=true