200 Create iocage templates. Clone jails.

Use case

Create iocage templates for Ansible clients. Clone jails.

Tree

shell> tree .
.
├── ansible.cfg
├── files
│   ├── pk_admins.txt
│   └── pkgs.json
├── hosts
│   ├── 02_iocage.yml
│   ├── 04_iocage.yml
│   └── 99_constructed.yml
├── host_vars
│   ├── iocage_02
│   │   └── iocage.yml
│   └── iocage_04
│       └── iocage.yml
├── iocage.ini
└── pb-test.yml

Synopsis

  • At two managed nodes:

    • iocage_02

    • iocage_04

    In the playbook vbotka.freebsd.pb_iocage_template.yml, use the modules:

    • vbotka.freebsd.iocage to create, start, stop, and convert jails to templates.

    • vbotka.freebsd.iocage exec tasks to create a user and set .ssh ownership.

    • ansible.posix.authorized_key to configure public keys.

    • community.general.sysrc to configure /etc/rc.conf

    • ansible.builtin.lineinfile to configure /usr/local/etc/sudoers

    In the playbook vbotka.freebsd.pb_iocage_ansible_clients.yml, use the module vbotka.freebsd.iocage to:

    • create jails from the iocage templates

    • start all jails

    • optionally, display the lists of jails.

  • At all created jails:

    In the playbook pb-test.yml:

    • connect created jails

    • display basic configuration of the jails.

Requirements

Notes

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

files

files/pkgs.json
{
    "pkgs": [
        "python311",
        "sudo"
        ]
}

host_vars

host_vars/iocage_02/iocage.yml
freebsd_iocage_pool: zroot
freebsd_iocage_pool_mount: /zroot
freebsd_iocage_mount: /zroot/iocage

templates:
  ansible_client:
    release: 14.3-RELEASE
    properties:
      bpf: 'on'
      dhcp: 'on'
      vnet: 'on'
    dhclient: "{{ act_dhclient | dict2items }}"
    rcconf: "{{ act_rcconf | dict2items }}"
    pkglist: /tmp/ansible/ansible_client/pkgs.json

# ansible client template defaults
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() }}"

iocage_env:
  CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
host_vars/iocage_04/iocage.yml
freebsd_iocage_pool: iocage
freebsd_iocage_pool_mount: /iocage
freebsd_iocage_mount: /iocage/iocage

templates:
  ansible_client:
    release: 15.0-RELEASE
    properties:
      bpf: 'on'
      dhcp: 'on'
      vnet: 'on'
    dhclient: "{{ act_dhclient | dict2items }}"
    rcconf: "{{ act_rcconf | dict2items }}"
    pkglist: /tmp/ansible/ansible_client/pkgs.json

# ansible client template defaults
act_user: admin
act_pk: pk_admins.txt
act_sudo: true
act_rcconf:
  iocage_enable: "YES"
  sshd_enable: "YES"
act_dhclient: {}

clones:
  test_131:
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.131/24'
  test_132:
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.132/24'
  test_133:
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.133/24'

# clones default properties
properties:
  bpf: 'on'
  notes: "vmm={{ inventory_hostname }}"

start: "{{ clones.keys() }}"

Note

The variables act_* are used to configure the template

  • 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 in a jail.

Warning

  • The user act_user must exist on the iocage host. Otherwise, the module ansible.posix.authorized_key will crash. See playbooks/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
    

Playbook output - Create templates

(env) > ansible-playbook vbotka.freebsd.pb_iocage_template.yml -i iocage.ini
PLAY [Create Ansible client templates.] ****************************************

TASK [Setup: Get iocage list of templates.] ************************************
ok: [iocage_04]
ok: [iocage_02]

TASK [Setup: Set dictionary iocage_templates] **********************************
ok: [iocage_04]
ok: [iocage_02]

TASK [Pkglist: Create directories for pkglist files.] **************************
ok: [iocage_04] => (item=ansible_client /tmp/ansible/ansible_client/pkgs.json)
ok: [iocage_02] => (item=ansible_client /tmp/ansible/ansible_client/pkgs.json)

TASK [Pkglist: Copy pkglist files.] ********************************************
ok: [iocage_04] => (item=ansible_client /tmp/ansible/ansible_client/pkgs.json)
ok: [iocage_02] => (item=ansible_client /tmp/ansible/ansible_client/pkgs.json)

TASK [Create: Create templates.] ***********************************************
changed: [iocage_04] => (item=ansible_client 15.0-RELEASE)
changed: [iocage_02] => (item=ansible_client 14.3-RELEASE)

TASK [Start: Start jails.] *****************************************************
ok: [iocage_04]
ok: [iocage_02]

TASK [User: Create user.] ******************************************************
changed: [iocage_04] => (item=ansible_client admin)
changed: [iocage_02] => (item=ansible_client admin)

TASK [Pk: The keys are valid.] *************************************************
ok: [iocage_02] => 
    changed: false
    msg: All assertions passed
ok: [iocage_04] => 
    changed: false
    msg: All assertions passed

TASK [Pk: Configure public keys.] **********************************************
changed: [iocage_04] => (item=ansible_client admin)
changed: [iocage_02] => (item=ansible_client admin)

TASK [Pk: Chown .ssh] **********************************************************
ok: [iocage_04] => (item=ansible_client admin)
ok: [iocage_02] => (item=ansible_client admin)

TASK [Sudo: Configure sudo.] ***************************************************
changed: [iocage_04] => (item=ansible_client admin)
changed: [iocage_02] => (item=ansible_client admin)

TASK [Rcconf: Configure /etc/rc.conf] ******************************************
changed: [iocage_04] => (item=ansible_client iocage_enable YES)
changed: [iocage_02] => (item=ansible_client iocage_enable YES)
changed: [iocage_04] => (item=ansible_client sshd_enable YES)
changed: [iocage_02] => (item=ansible_client sshd_enable YES)

TASK [Stop: Stop jails.] *******************************************************
ok: [iocage_04]
ok: [iocage_02]

TASK [Template: Set template.] *************************************************
ok: [iocage_04] => (item=ansible_client)
ok: [iocage_02] => (item=ansible_client)

PLAY RECAP *********************************************************************
iocage_02                  : ok=14   changed=5    unreachable=0    failed=0    skipped=28   rescued=0    ignored=0   
iocage_04                  : ok=14   changed=5    unreachable=0    failed=0    skipped=28   rescued=0    ignored=0   

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       |
+------+-----------------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+

Playbook output - Clone and start jails

(env) > ansible-playbook vbotka.freebsd.pb_iocage_ansible_clients.yml \
                         -i iocage.ini \
                         -t clone \
                         -e clone=true
PLAY [Create and start jails. Optionally stop and destroy jails.] **************

TASK [Create clones from template] *********************************************
changed: [iocage_04] => (item=test_131 ansible_client)
changed: [iocage_04] => (item=test_132 ansible_client)
changed: [iocage_04] => (item=test_133 ansible_client)
changed: [iocage_02] => (item=test_111 ansible_client)
changed: [iocage_02] => (item=test_112 ansible_client)
changed: [iocage_02] => (item=test_113 ansible_client)

TASK [Start clones] ************************************************************
changed: [iocage_04]
changed: [iocage_02]

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   

Playbook output - List jails

(env) > ansible-playbook vbotka.freebsd.pb_iocage_ansible_clients.yml \
                         -i iocage.ini \
                         -t list \
                         -e debug=true
PLAY [Create and start jails. Optionally stop and destroy jails.] **************

TASK [Get iocage facts] ********************************************************
ok: [iocage_04]
ok: [iocage_02]

TASK [Display iocage_jails keys debug=true] ************************************
ok: [iocage_02] => 
    ansible_facts.iocage_jails.keys():
    - test_111
    - test_112
    - test_113
ok: [iocage_04] => 
    ansible_facts.iocage_jails.keys():
    - test_131
    - test_132
    - test_133

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

Jails at iocage_02

[iocage_02]# iocage list -l
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
| JID |   NAME   | BOOT | STATE | TYPE |     RELEASE     |        IP4        | IP6 |    TEMPLATE    | BASEJAIL |
+=====+==========+======+=======+======+=================+===================+=====+================+==========+
| 74  | test_111 | off  | up    | jail | 14.3-RELEASE-p8 | em0|10.1.0.111/24 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
| 75  | test_112 | off  | up    | jail | 14.3-RELEASE-p8 | em0|10.1.0.112/24 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
| 76  | test_113 | off  | up    | jail | 14.3-RELEASE-p8 | em0|10.1.0.113/24 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+-------------------+-----+----------------+----------+

Jails at iocage_04

[iocage_04]# iocage list -l
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
| JID |   NAME   | BOOT | STATE | TYPE |     RELEASE     |         IP4         | IP6 |    TEMPLATE    | BASEJAIL |
+=====+==========+======+=======+======+=================+=====================+=====+================+==========+
| 53  | test_131 | off  | up    | jail | 15.0-RELEASE-p3 | vnet0|10.1.0.131/24 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
| 54  | test_132 | off  | up    | jail | 15.0-RELEASE-p3 | vnet0|10.1.0.132/24 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+
| 55  | test_133 | off  | up    | jail | 15.0-RELEASE-p3 | vnet0|10.1.0.133/24 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+---------------------+-----+----------------+----------+

Inventory hosts

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')
hosts/04_iocage.yml
plugin: vbotka.freebsd.iocage
host: 10.1.0.29
user: admin
get_properties: true
compose:
  ansible_host: iocage_ip4
groups:
  test_04: inventory_hostname.startswith('test')
hosts/99_constructed.yml
plugin: ansible.builtin.constructed
groups:
    test: inventory_hostname.startswith('test')

Display inventory

(env) > ansible-inventory -i hosts --graph
@all:
  |--@ungrouped:
  |--@test_02:
  |  |--test_111
  |  |--test_112
  |  |--test_113
  |--@test_04:
  |  |--test_131
  |  |--test_132
  |  |--test_133
  |--@test:
  |  |--test_111
  |  |--test_112
  |  |--test_113
  |  |--test_131
  |  |--test_132
  |  |--test_133

Playbook pb-test.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 }}
          {{ ansible_facts.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 - Display test vars

(env) > ansible-playbook pb-test.yml -i hosts
PLAY [Connect to the group test.] **********************************************

TASK [Gathering Facts] *********************************************************
ok: [test_113]
ok: [test_112]
ok: [test_111]
ok: [test_133]
[ERROR]: Task failed: Failed to connect to the host via ssh: ssh: connect to host 10.1.0.132 port 22: Connection timed out

Task failed.

<<< caused by >>>

Failed to connect to the host via ssh: ssh: connect to host 10.1.0.132 port 22: Connection timed out

fatal: [test_132]: UNREACHABLE! => 
    changed: false
    msg: 'Task failed: Failed to connect to the host via ssh: ssh: connect to host 10.1.0.132
        port 22: Connection timed out'
    unreachable: true
[ERROR]: Task failed: Failed to connect to the host via ssh: ssh: connect to host 10.1.0.131 port 22: Connection timed out

Task failed.

<<< caused by >>>

Failed to connect to the host via ssh: ssh: connect to host 10.1.0.131 port 22: Connection timed out

fatal: [test_131]: UNREACHABLE! => 
    changed: false
    msg: 'Task failed: Failed to connect to the host via ssh: ssh: connect to host 10.1.0.131
        port 22: Connection timed out'
    unreachable: true

TASK [ansible.builtin.command] *************************************************
changed: [test_133]
changed: [test_113]
changed: [test_111]
changed: [test_112]

TASK [ansible.builtin.debug] ***************************************************
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
ok: [test_133] => 
    msg: |-
        test-133 test_133 d6add9ad-8b6e-4316-a226-345a60532b41 /usr/local/bin/python3.11

TASK [ansible.builtin.command] *************************************************
changed: [test_133]
changed: [test_111]
changed: [test_112]
changed: [test_113]

TASK [ansible.builtin.command] *************************************************
changed: [test_133]
changed: [test_111]
changed: [test_112]
changed: [test_113]

TASK [ansible.builtin.debug] ***************************************************
ok: [test_111] => 
    msg: |-
        test-111 admin root
ok: [test_112] => 
    msg: |-
        test-112 admin root
ok: [test_113] => 
    msg: |-
        test-113 admin root
ok: [test_133] => 
    msg: |-
        test-133 admin root

PLAY RECAP *********************************************************************
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   
test_131                   : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
test_132                   : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
test_133                   : 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 vbotka.freebsd.pb_iocage_ansible_clients.yml \
                 -i iocage.ini \
                 -t clone_destroy \
                 -e clone_destroy=true