Heredoc with a conditional statement in terraform

Hello,

I’m not able to use a HEREDOC in a conditional statement as follows:

#cloud-config
${yamlencode({
  users = [
    {
      name   = "root"
      groups = "users"
      ssh_authorized_keys = [
        root_ssh_key,
      ]
      shell = "/bin/bash"
    },
  ]
  apt = {
    sources = {
      kubernetes = [
        {
        source = "deb https://apt.kubernetes.io/ kubernetes-xenial main"
        key = kubernetes_repo_pgp
        }
      ]
    }
  }
  packages = [
  ]
  write_files = [
        {
        content = consul_config
        path = "/etc/consul.d/consul.hcl",
        },
        {
        content = ssh_template
        path = "/etc/consul-template.d/ssh-template.json"
        },
        (can(regex("^kube-.+", node_name)) ? <<EOT
        {
        content = kubeadm_config_file,
        path = "/root/.config/kubeadm-config.yaml"
        }
        EOT :
        "something"
        )
  ]
})}

The error is:

Call to function “templatefile” failed: ./files/kubernetes/userdata.tpl:44,1-1: Unterminated template string; No closing marker was found for the string…

What is the context syntax?

Thanks!

As per Strings and Templates - Configuration Language | Terraform | HashiCorp Developer, the ending marker of a heredoc must appear alone on a line.

HOWEVER, heredocs are strings - but what you’re trying to put inside your heredoc is not a string - it’s another piece of Terraform expression language!

This means that even if you get your heredoc syntax correct, it’s still not a working solution to the problem you present here.

You’re probably looking for something closer to

    write_files = concat([
      { content = "foo", path = "bar" },
      { content = "foo", path = "baz" },
      ],
      (true ? [
        { content = "foo", path = "quux" },
      ] : [])
    )
1 Like

You’re using true there just as an example, right? There’s no particular logic to it, I’m guessing. I should be able to use can(regex("^kube-.+", node_name) instead, I suppose?

Indeed, it works as expected:

  write_files = concat([
        {
        content = consul_config
        path = "/etc/consul.d/consul.hcl",
        },
        {
        content = ssh_template
        path = "/etc/consul-template.d/ssh-template.json"
        },
        ],
        (can(regex("^kube-.+", node_name)) ? [
        { content = kubeadm_config_file, path = "/root/.config/kubeadm-config.yaml" }
        ] : [])
  )

So I test if the node_name starts with “kube”, it writes the content of that file, and concat makes sure that it’s another item of the list write_files. If I don’t use concat, I see that it adds yet another dash, so it’s as if it defined a separate list.

Rather complicated, but I appreciate it :slight_smile: I just need to weigh things and how I can make the code as succinct as possible while also keeping it easily legible.