Hooks
^^^^^

The iocage utility internally opens a console to a jail to get the jail's DHCP address. This
requires root. If you run the command ``iocage list -l`` as unprivileged user, you'll see the message
``DHCP (running -- address requires root)``. If you are not granted the root privilege, use
``/etc/dhclient-exit-hooks``. For example,

.. code-block:: console

   shell> cat /zroot/iocage/jails/srv_1/root/etc/dhclient-exit-hooks

.. code-block:: sh

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

where ``/zroot/iocage`` is the activated pool

.. code-block:: console
   :emphasize-lines: 1

   shell> zfs list | grep /zroot/iocage
   zroot/iocage                                4.69G   446G  5.08M  /zroot/iocage
   zroot/iocage/download                        927M   446G   384K  /zroot/iocage/download
   zroot/iocage/download/14.1-RELEASE           465M   446G   465M  /zroot/iocage/download/14.1-RELEASE
   zroot/iocage/download/14.2-RELEASE           462M   446G   462M  /zroot/iocage/download/14.2-RELEASE
   zroot/iocage/images                          384K   446G   384K  /zroot/iocage/images
   zroot/iocage/jails                           189M   446G   480K  /zroot/iocage/jails
   zroot/iocage/jails/srv_1                    62.9M   446G   464K  /zroot/iocage/jails/srv_1
   zroot/iocage/jails/srv_1/root               62.4M   446G  3.53G  /zroot/iocage/jails/srv_1/root
   zroot/iocage/jails/srv_2                    62.8M   446G   464K  /zroot/iocage/jails/srv_2
   zroot/iocage/jails/srv_2/root               62.3M   446G  3.53G  /zroot/iocage/jails/srv_2/root
   zroot/iocage/jails/srv_3                    62.8M   446G   464K  /zroot/iocage/jails/srv_3
   zroot/iocage/jails/srv_3/root               62.3M   446G  3.53G  /zroot/iocage/jails/srv_3/root
   zroot/iocage/log                             688K   446G   688K  /zroot/iocage/log
   zroot/iocage/releases                       2.93G   446G   384K  /zroot/iocage/releases
   zroot/iocage/releases/14.2-RELEASE          2.93G   446G   384K  /zroot/iocage/releases/14.2-RELEASE
   zroot/iocage/releases/14.2-RELEASE/root     2.93G   446G  2.88G  /zroot/iocage/releases/14.2-RELEASE/root
   zroot/iocage/templates                       682M   446G   416K  /zroot/iocage/templates
   zroot/iocage/templates/ansible_client        681M   446G   432K  /zroot/iocage/templates/ansible_client
   zroot/iocage/templates/ansible_client/root   681M   446G  3.53G  /zroot/iocage/templates/ansible_client/root

.. seealso:: `man dhclient-script`_

Create the inventory configuration ``hosts/02_iocage.yml``. Use the option ``hooks_results`` instead
of ``sudo``

.. code-block:: yaml

   plugin: vbotka.freebsd.iocage
   host: 10.1.0.73
   user: admin
   hooks_results:
     - /var/db/dhclient-hook.address.epair0b

.. note::

   The option ``hooks_results`` expects the ``poolname`` to be mounted to ``/poolname``. For
   example, if you activate the pool ``zroot``, this plugin expects to find the ``hooks_results``
   items in the path ``/zroot/iocage/jails/<name>/root``. If you mount the ``poolname`` to a
   different path, the easiest remedy is to create a symlink.

As admin at the controller, display the inventory

.. code-block:: console

   (env) > ansible-inventory -i hosts/02_iocage.yml --list --yaml

.. code-block:: yaml

   all:
     children:
       ungrouped:
         hosts:
           srv_1:
             iocage_basejail: 'no'
             iocage_boot: 'off'
             iocage_hooks:
             - 10.1.0.183
             iocage_ip4: '-'
             iocage_ip4_dict:
               ip4: []
               msg: DHCP (running -- address requires root)
             iocage_ip6: '-'
             iocage_jid: '204'
             iocage_release: 14.2-RELEASE-p3
             iocage_state: up
             iocage_template: ansible_client
             iocage_type: jail
           srv_2:
             iocage_basejail: 'no'
             iocage_boot: 'off'
             iocage_hooks:
             - 10.1.0.204
             iocage_ip4: '-'
             iocage_ip4_dict:
               ip4: []
               msg: DHCP (running -- address requires root)
             iocage_ip6: '-'
             iocage_jid: '205'
             iocage_release: 14.2-RELEASE-p3
             iocage_state: up
             iocage_template: ansible_client
             iocage_type: jail
           srv_3:
             iocage_basejail: 'no'
             iocage_boot: 'off'
             iocage_hooks:
             - 10.1.0.169
             iocage_ip4: '-'
             iocage_ip4_dict:
               ip4: []
               msg: DHCP (running -- address requires root)
             iocage_ip6: '-'
             iocage_jid: '206'
             iocage_release: 14.2-RELEASE-p3
             iocage_state: up
             iocage_template: ansible_client
             iocage_type: jail

Update the inventory configuration ``hosts/02_iocage.yml``. Compose the variable ``ansible_host``

.. code-block:: yaml+jinja
   :emphasize-lines: 7

   plugin: vbotka.freebsd.iocage
   host: 10.1.0.73
   user: admin
   hooks_results:
     - /var/db/dhclient-hook.address.epair0b
   compose:
     ansible_host: (iocage_hooks.0 == '-') | ternary(iocage_ip4, iocage_hooks.0)

Test the jails. Create the playbook ``pb-test-uname.yml``

.. code-block:: yaml

   - hosts: all
     remote_user: admin

     vars:

       ansible_python_interpreter: auto_silent

     tasks:

       - command: uname -a
         register: out

       - debug:
           var: out.stdout

.. seealso:: `Managing BSD hosts with Ansible`_

Run the playbook

.. code-block:: console

   (env) > ansible-playbook -i hosts/02_iocage.yml pb-test-uname.yml

.. code-block:: yaml
   :force:

   PLAY [all] **********************************************************************************************************

   TASK [command] ******************************************************************************************************
   changed: [srv_3]
   changed: [srv_1]
   changed: [srv_2]

   TASK [debug] ********************************************************************************************************
   ok: [srv_1] =>
       out.stdout: FreeBSD srv-1 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64
   ok: [srv_3] =>
       out.stdout: FreeBSD srv-3 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64
   ok: [srv_2] =>
       out.stdout: FreeBSD srv-2 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64

   PLAY RECAP **********************************************************************************************************
   srv_1                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
   srv_2                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
   srv_3                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

.. note:: This playbook and the inventory configuration work also for the `Shared IP jails`_.


.. _man dhclient-script: https://man.freebsd.org/cgi/man.cgi?dhclient-script
.. _Managing BSD hosts with Ansible: https://docs.ansible.com/ansible/latest/os_guide/intro_bsd.html#managing-bsd-hosts-with-ansible
.. _Shared IP jails: https://freebsd.github.io/iocage/networking.html#configuring-a-shared-ip-jail
