030 Create Ansible client templates and clone Ansible client jails.

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.yml
├── pb-iocage-template.yml
├── pb-test-01.yml
└── tasks
    ├── create.yml
    ├── pkg.yml
    ├── pk.yml
    ├── rc_conf.yml
    ├── setup.yml
    ├── start.yml
    ├── stop.yml
    ├── sudo.yml
    ├── template.yml
    └── user.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

  • module vbotka.freebsd.iocage

  • inventory plugin vbotka.freebsd.iocage

  • root privilege on the iocage hosts

  • activated iocage

  • fetched releases

Notes

Configuration ansible.cfg

[defaults]
gathering = explicit
stdout_callback = 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"

properties:
  vnet: 'on'
  defaultrouter: 10.1.0.10
  notes: "vmm={{ inventory_hostname }}"

jails:
  - name: ansible_client
    release: 13.4-RELEASE
    properties:
      ip4_addr: 'vnet0|10.1.0.198/24'

clones:
  - name: test_101
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.101/24'
  - name: test_102
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.102/24'
  - name: test_103
    clone_from: ansible_client
    properties:
      ip4_addr: 'vnet0|10.1.0.103/24'

start: [test_101, test_102, test_103]

# ansible client template

act_user: admin
act_pkg:
  - security/sudo
  - lang/python39
act_pk: pk_admins.txt

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"

properties:
  notes: "vmm={{ inventory_hostname }}"

jails:
  - name: ansible_client
    release: 14.1-RELEASE
    properties:
      ip4_addr: 'em0|10.1.0.199/24'

clones:
  - name: test_111
    clone_from: ansible_client
    properties:
      ip4_addr: 'em0|10.1.0.111/24'
  - name: test_112
    clone_from: ansible_client
    properties:
      ip4_addr: 'em0|10.1.0.112/24'
  - name: test_113
    clone_from: ansible_client
    properties:
      ip4_addr: 'em0|10.1.0.113/24'

start: [test_111, test_112, test_113]

# ansible client template

act_user: admin
act_pkg:
  - security/sudo
  - lang/python311
act_pk: pk_admins.txt

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 tasks/pk.yml

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]
      import_tasks: tasks/setup.yml

    - name: Create jails
      tags: create
      import_tasks: tasks/create.yml

    - name: Start jails
      tags: start
      import_tasks: tasks/start.yml

    - name: Install packages
      tags: pkg
      import_tasks: tasks/pkg.yml

    - name: Create user
      tags: user
      import_tasks: tasks/user.yml

    - name: Configure public keys
      tags: pk
      import_tasks: tasks/pk.yml

    - name: Configure sudo
      tags: sudo
      import_tasks: tasks/sudo.yml

    - name: Configure /etc/rc.conf
      tags: rc_conf
      import_tasks: tasks/rc_conf.yml

    - name: Stop jails
      tags: stop
      import_tasks: tasks/stop.yml

    - name: Convert jails to templates
      tags: template
      import_tasks: tasks/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 ansible clients.
  hosts: iocage
  environment: "{{ freebsd_iocage_runner_env | d({}) }}"

  vars:

    debug: false
    debug2: false
    destroy: false

  tasks:

    - name: Create and start jails
      tags: create
      block:

        - name: Create jails from template
          register: out
          vbotka.freebsd.iocage:
            state: cloned
            clone_from: ansible_client
            name: "{{ item.name }}"
            properties: "{{ [properties, item.properties] | combine }}"
          loop: "{{ clones }}"
          loop_control:
            label: "{{ item.name }} {{ item.clone_from }}"

        - name: "Debug clone jails from template debug2={{ debug2 }}"
          when: debug2 | bool
          ansible.builtin.debug:
            var: out

        - name: Start jails
          register: out
          vbotka.freebsd.iocage:
            state: started
            name: "{{ item }}"
          loop: "{{ start }}"

        - name: "Debug start jails debug2={{ debug2 }}"
          when: debug2 | bool
          ansible.builtin.debug:
            var: out

    - name: Stop and destroy jails
      when: destroy | bool
      tags: destroy
      block:

        - name: Stop jails
          register: out
          vbotka.freebsd.iocage:
            state: stopped
            name: "{{ item.name }}"
          loop: "{{ clones }}"
          loop_control:
            label: "{{ item.name }}"

        - name: "Debug stop jails debug2={{ debug2 }}"
          when: debug2 | bool
          ansible.builtin.debug:
            var: out

        - name: Destroy jails
          register: out
          vbotka.freebsd.iocage:
            state: absent
            name: "{{ item.name }}"
          loop: "{{ clones }}"
          loop_control:
            label: "{{ item.name }}"

        - name: "Debug destroy jails debug2={{ debug2 }}"
          when: debug2 | bool
          ansible.builtin.debug:
            var: out

    - name: "Display jails dictionary debug2={{ debug2 }}"
      when: debug2 | bool
      ansible.builtin.debug:
        var: iocage_jails

    - name: "Display jails list debug={{ debug }}"
      when: debug | bool
      ansible.builtin.debug:
        var: iocage_jails.keys()

Playbook output

(env) > ansible-playbook pb-iocage-ansible-clients.yml -i iocage-hosts.ini -e debug=true

PLAY [Create and start ansible clients.] *******************************************************

TASK [Create jails 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 clone jails from template debug2=False] ********************************************
skipping: [iocage_01]
skipping: [iocage_02]

TASK [Start jails] *****************************************************************************
changed: [iocage_01] => (item=test_101)
changed: [iocage_01] => (item=test_102)
changed: [iocage_02] => (item=test_111)
changed: [iocage_01] => (item=test_103)
changed: [iocage_02] => (item=test_112)
changed: [iocage_02] => (item=test_113)

TASK [Debug start jails debug2=False] **********************************************************
skipping: [iocage_01]
skipping: [iocage_02]

  ...

TASK [Display jails list 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=3    changed=2    unreachable=0    failed=0    skipped=7    rescued=0    ignored=0   
iocage_02: ok=3    changed=2    unreachable=0    failed=0    skipped=7    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
env:
  CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
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