==========
Templating
==========

Warewulf uses the ``text/template`` engine to convert dynamic content
into static content and auto-populate files with the appropriate data
on demand.

In Warewulf, you can find templates both for the provisioning services
(e.g. ``/etc/warewulf/ipxe/``, ``/etc/warewulf/dhcp/``, and
``/etc/warewulf/hosts.tmpl``) as well as within the runtime and system
overlays.

(more documentation coming soon)

Examples
========

Comment
-------

.. code-block::

   {{  /* This comment won't show up in file, but an empty line /* }}
   {{  /* No empty line, line break removed at end of this line /* -}}
   {{-  /* No empty line, line break removed at front of this line /* }}

Range
-----

iterate over elements of an array

.. code-block::

   {{ range $devname, $netdev := .NetDevs }}
       # netdev = {{ $netdev.Hwaddr }}
   {{ end }}

Increment Variable In Loop
^^^^^^^^^^^^^^^^^^^^^^^^^^

iterate over elements of an array and increment ``i`` each loop cycle

.. code-block::

   {{ $i := 0 }}
   {{ range $devname, $netdev := .NetDevs }}
       # netdev{{$i}} = {{ $netdev.Hwaddr }}
       {{ $i = inc $i }}
   {{ end }}

Decrement
^^^^^^^^^

iterate over elements of an array and decrement ``i`` each loop cycle

.. code-block::

   {{ $i := 10 }}
   {{ range $devname, $netdev := .NetDevs }}
       # netdev{{$i}} = {{ $netdev.Hwaddr }}
       {{ $i = dec $i }}
   {{ end }}

Access Tag
----------

Acces the value of an individual tag ``foo``

.. code-block::

  foo: {{ index .Tags "foo" }}
  {{ if eq (index .Tags "foo") "baar" -}}
  foo: {{ index .Tags "foo" }}
  {{ end -}}

Create Multiple Files
---------------------

The following template will create a file called
``ifcfg-NETWORKNAME.xml`` for every network present on the node

.. code-block::

  {{- $host := .BuildHost }}
  {{- $time := .BuildTime }}
  {{- $source := .BuildSource }}
  {{range $devname, $netdev := .NetDevs -}}
  {{- $filename := print "ifcfg-" $devname ".xml" }}
  {{- file $filename }}
  <!--
  This file is autogenerated by warewulf
  Host:   {{ $host }}
  Time:   {{ $time }}
  Source: {{ $source }}
  -->
  <interface origin="static generated warewulf config">
    <name>{{$netdev.Device}}</name>
    {{ if $netdev.Type -}}
    <link-type>{{ $netdev.Type }}</link-type>
    {{ end -}}
    <control>
      <mode>boot</mode>
    </control>
    <firewall/>
    <link/>
    <ipv4>
      <enabled>true</enabled>
      <arp-verify>true</arp-verify>
    </ipv4>
    <ipv4:static>
      <address>
        <local>{{$netdev.IpCIDR}}</local>
      </address>
  {{ if $netdev.Gateway -}}
      <route>
        <nexthop>
          <gateway>{{$netdev.Gateway}}</gateway>
        </nexthop>
      </route>
  {{ end -}}
    </ipv4:static>
    <ipv6>
      <enabled>true</enabled>
      <privacy>prefer-public</privacy>
      <accept-redirects>false</accept-redirects>
    </ipv6>
  {{ if $netdev.Ipaddr6 -}}
    <ipv6:static>
      <address>
        <local>{{ $netdev.Ipaddr6 }}</local>
      </address>
    </ipv6:static>
  {{ end -}}
  </interface>
  {{ end -}}

Special Commands
----------------

Include
^^^^^^^

A file from the host can be include with following template

.. code-block::

  {{ Include file }}

IncludeFrom
^^^^^^^^^^^

With following snippet a file from a given container can be included

.. code-block::

  {{ IncludeFrom container file }}

IncludeBlock
^^^^^^^^^^^^

Includes a file up to the line where a abort string is found. This is
useful, e.g., for the hosts file, which can have local modifications
which are not controlled by warewulf. For this example the abort
string is "# Do not edit after this line"

.. code-block::

  {{ IncludeBlock "/etc/hosts" "# Do not edit after this line" }}
  # This block is autogenerated by warewulf
  # Host:   {{.BuildHost}}
  # Time:   {{.BuildTime}}
  # Source: {{.BuildSource}}


  # Warewulf Server
  {{$.Ipaddr}} warewulf {{$.BuildHost}}

  {{- range $node := $.AllNodes}}                  {{/* for each node */}}
  # Entry for {{$node.Id.Get}}
  {{- range $devname, $netdev := $node.NetDevs}} {{/* for each network device on the node */}}
  {{- if $netdev.Ipaddr.Defined}}                {{/* if we have an ip address on this network device */}}
  {{- /* emit the node name as hostname if this is the primary */}}
  {{$netdev.Ipaddr.Get}} {{$node.Id.Get}}-{{$devname}}
  {{- if $netdev.Device.Defined}} {{$node.Id.Get}}-{{$netdev.Device.Get}}{{end}}
  {{- if $netdev.Primary.GetB}} {{$node.Id.Get}}{{end}}
  {{- end}} {{/* end if ip */}}
  {{- end}} {{/* end for each network device */}}
  {{- end}} {{/* end for each node */}}

Abort
^^^^^
If ``{{ abort }}`` is found in a template, the resulting file isn't written.

Nobackup
^^^^^^^^

If a file exists on the target, a backup file is written with the
suffix ``.wwbackup``. This only happens for the ``host`` overlay, as
e.g. the ``/etc/hosts`` exists on the host. If this is not the
intended behavior, the ``{{ nobackup }}`` flag can be added to a
template.

Split
^^^^^

A given string can be split into substrings.

.. code-block::

  {{ $x := "a:b:c" -}}
  {{ $y := (split $x ":") -}}
  {{ range $y }} {{.}} {{ end }}


Node specific files
-------------------

Sometimes there is the need to have specific files for every node
which can't be generated by a template. You can include these files
with following template:

.. code-block::

  {{- $filename := print "/root/" .Id "-payload" }}
  {{ Include $filename }}
