pb_iocage_template

Synopsis

This playbook creates iocage templates from the dictionary templates. For example,

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

creates the template ansible_client

shell> iocage list -lt
+------+----------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+
| JID  |      NAME      | BOOT | STATE |   TYPE   |     RELEASE     |        IP4         | IP6 | TEMPLATE | BASEJAIL |
+======+================+======+=======+==========+=================+====================+=====+==========+==========+
| None | ansible_client | off  | down  | template | 14.3-RELEASE-p1 | DHCP (not running) | -   | -        | no       |
+------+----------------+------+-------+----------+-----------------+--------------------+-----+----------+----------+

Note

  • The attributes release and properties are mandatory.

  • The lists dhclient and rcconf can be empty.

  • The attribute pkglist is optional.

Hint

Look at the Index and search the playbook pb_iocage_template.yml what examples are available.

Ansible Client Template variables

A few variables are required to configure a template for Ansible clients. See the playbook tasks to learn details.

act_pkg: []
act_pkg_install: false
act_user: ''
act_pk: ''
act_sudo: false
act_rcconf: {}
act_dhclient: {}

act_pkg

Install a list of packages. Put the list into the template attribute act_pkg. For example,

templates:
  ansible_client:
    act_pkg:
      - security/sudo
      - lang/python311
    ...

If this attribute is missing, the variable act_pkg is used. Below is the minimal list for an ansible client. Set the Python version to your needs

act_pkg:
  - security/sudo
  - lang/python311

Fit the list to your needs. Usually, you want to add gtar and other archivers. See the module ansible.builtin.unarchive. If you want to use the collection community.crypto add py-openssl

act_pkg:
  - lang/python311
  - security/sudo
  - archivers/gtar
  - security/py-openssl

Enable the installation by setting act_pkg_install=true (default=false).

Notes:

  • As a first choice, use pkglist. Use act_pkg to install additional packages in an already created jail.

  • The module community.general.pkgng is jail-aware. Quoting:

    jail: Pkg will execute in the given jail name or ID.
    
  • It seems that a short UUID doesn’t work as a name. Use the ID instead

    jail: "{{ iocage_jails[item.key]['jid'] }}"
    

act_user

Create a user in the jail. Usually, this user is used as the remote_user to connect to the jail.

act_user: admin

act_pk

A path to a file comprising the public keys allowed to connect to the act_user in the jail.

act_pk: pk_admins.txt

Warning

The module ansible.posix.authorized_key, used in this task, is not jail-aware. The user act_user must exist on the iocage host. Otherwise, the module ansible.posix.authorized_key will crash.

act_sudo

Add act_user to <dataset>/root/usr/local/etc/sudoers

act_sudo: true

The below passwordless entry will be created

line: "{{ _act_user }} ALL=(ALL) NOPASSWD: ALL"

act_rcconf

Configure <dataset>/root/etc/rc.conf

act_rcconf:
  iocage_enable: "YES"
  sshd_enable: "YES"

act_dhclient

Create dhclient hooks in <dataset>/root/etc/

act_dhclient:
  dhclient-exit-hooks: |
    case "$reason" in
        "BOUND"|"REBIND"|"REBOOT"|"RENEW")
        echo $new_ip_address > /var/db/dhclient-hook.address.$interface
        ;;
    esac

Note

pkglist

pkglist is an optional attribute of the dictionary templates. The value is a path on the iocage host where the file pkgs.json will be copied to. See the option --pkglist in man iocage

templates:
  ansible_client:
    pkglist: /tmp/ansible/ansible_client/pkgs.json
    ...

Create the file files/pkgs.json. For example,

{
    "pkgs": [
        "python311",
        "sudo"
        ]
}

The playbook tasks pkglist.yml expects the path files/pkgs.json to be relative to the inventory

- name: Copy pkglist files.
  ansible.builtin.copy:
    src: "{{ inventory_dir }}/files/{{ item.value.pkglist | basename }}"
    dest: "{{ item.value.pkglist }}"
  loop: "{{ _templates }}"
  vars:
    _templates: "{{ templates | dict2items
                              | selectattr('value.pkglist', 'defined') }}"

Fit the list to your needs. Usually, you want to add gtar and other archivers. See the module ansible.builtin.unarchive. Add py-openssl if you want to use the collection community.crypto

{
    "pkgs": [
        "python311",
        "sudo",
        "gtar",
        "py-openssl"
        ]
}

Note

iocage tests DNS on installing the packages:

Testing Host DNS response to pkg.freebsd.org
2025/08/06 01:18:12 (INFO) Testing ansible_client's SRV response to pkg.freebsd.org
2025/08/06 01:18:12 (INFO) Testing ansible_client's DNSSEC response to pkg.freebsd.org

Workflow

The last tasks template.yml convert the jails to templates. If you start the play again the first tasks setup.yml ends the host(s) if all templates have already been created. If you want to reconfigure already created template set template=0 manually. For example,

shell> iocage set template=0 ansible_client

If a running jail is needed start it

shell> iocage start ansible_client

Then, use the playbook tags to execute selected tasks. For example, to install additional packages, create the list of the packages act_pkg and run the play

(env) > ansible-playbook pb_iocage_template.yml -t pkg -e act_pkg_install=true

After the reconfiguration stop the jail and convert it to the template manually

shell> iocage stop ansible_client
shell> iocage set template=1 ansible_client

, or by the play

(env) > ansible-playbook pb_iocage_template.yml -t stop,template