Control whole blocks in external template files

Hi all,

I’m wondering if it’s possible to control the inclusion of whole text blocks in external template files?

In this use case I’d like to conditionally include specific lines in a cloud-init user-data config file, like shown in the following (shortened) example:

user_data = templatefile("${path.module}/user-data.tpl", {
              admin_email = "admin@example.net"
              local_mailer_enabled = true
              process_accounting_enabled = false
            })

And the template user-data.tpl (contains pseudo code!):

#cloud-config

packages:
  - firewalld
  - htop
  - lsof
  - psmisc
  - tar
{ if local_mailer_enabled }
  - mailx
  - postfix
{ endif }
{ if process_accounting_enabled }
  - psacct
  - sysstat
{ endif }

runcmd:
  - systemctl enable --now firewalld
{ if local_mailer_enabled }
  - 'sed -i -e ''s/^#\?\(root:\s\+\).*/\1${admin_email}/'' /etc/aliases'
  - newaliases
  - systemctl enable --now postfix.service
{ endif }
{ if process_accounting_enabled }
  - systemctl enable --now psacct.service
  - systemctl enable --now sysstat.service
{ endif }

While I understand that the sample above can possibly be worked around using yamlencode, what if I have a pure text file? Would this be possible at all?

Just a follow-up for others having the same use case, at least for cloud-init data - it’s probably less effort to just use the built-in Jinja templating engine, for example:

## template: jinja
#cloud-config
{% set local_mailer = ${local_mailer_enabled} %}
{% set process_accounting = ${process_accounting_enabled} %}

packages:
  - firewalld
  - htop
  - lsof
  - psmisc
  - tar
{% if local_mailer %}
  - mailx
  - postfix
{% endif %}
{% if process_accounting %}
  - psacct
  - sysstat
{% endif %}

users:
  - name: cloudadm
    gecos: Cloud Administrator
    ssh_authorized_keys: {{ public_ssh_keys }}
    sudo: ALL=(ALL) NOPASSWD:ALL

runcmd:
  - [systemctl, enable, --now, firewalld]
{% if local_mailer %}
  - [systemctl, enable, --now, postfix.service]
  - [sed, -i, -e, 's/^#\?\(root:\s\+\).*/\1${admin_email}/', /etc/aliases]
  - [newaliases]
{% endif %}
{% if process_accounting %}
  - [systemctl, enable, --now, psacct.service]
  - [systemctl, enable, --now, sysstat.service]
{% endif %}

If you don’t want to use yamlencode for some reason then what you have available to you in a templatefile template file is Terraform’s template language, which includes directives for conditional segments and repeated segments.

Whether it’s better to do the templating inside Terraform using Terraform’s template language or inside cloud-init using the Jinja template language is not something I personally have a strong opinion on; both template languages have similar expressive power and mostly just differ in syntax details, but doing it in Terraform means that the template will have direct access to data from Terraform, while a Jinja template in cloud-init will only have access to data cloud-init can see. Using a Terraform template to generate a Jinja template feels extra complex to me though, and potentially confusing to future maintainers as to which parts are being evaluated where.

Hi,

thanks for the references.

Not sure why, but I totally missed the if conditional and that it can span multiple lines. :frowning:

You’re completely right that mixing template engines is a bad idea.

Thanks for pointing me to the right direction!