Escaping dollar character with $$ fails to avoid interpolation of $${data.kubernetes.container.id} in template_file resource

Terraform Version

Terraform v1.2.5

Expected Behavior

There should be a way to escape any character in ${data.kubernetes.container.id} in a template_file to avoid erroneously referencing a template variable data.kubernetes.container.id.

Actual Behavior

This kind of template_file :

data "template_file" "values" {
  template = <<EOF
---
  filebeatConfig:
    filebeat.yml: |
      filebeat.autodiscover:
        providers:
          - type: kubernetes
            templates:
              - condition:
                  equals:
                    kubernetes.namespace: kube-system
                config:
                  - type: container
                    paths:
                      - /var/log/containers/*-$${data.kubernetes.container.id}.log
                    exclude_lines: ["^\\s+[\\-`('.|_]"]  # drop asciiart lines
EOF  
}

Renders a message like this or similar:

Error: failed to render : <template_file>:41,49-53: Unknown variable; There is no variable named "data"., and 1 other diagnostic(s)

Hi @nomopo45,

The problem in this case is that your template argument is subject to two levels of template processing here: first Terraform itself treats the argument expression as a template to produce the value to send to the provider, and then the template provider itself evaluates the string it was sent as a template.

Your current escaping is handling the first template evaluation in Terraform, but then the string that the provider evaluates now contains ${, which the provider will therefore try to expand as an interpolation.

One way to avoid this would be two apply double escaping by writing three dollar signs: $$${. Terraform will then replace that with $${ before passing it to the provider, and then the provider will replace it with literal ${ to get the result you want.

The deprecated template_file data source, and the built-in templatefile function that replaced it, were both intended for rendering templates from external files rather than templates specified inline, which is why this inline approach is quite awkward. If possible I would suggest either moving the template into an external file and using the templatefile function to render it instead, or just writing the template inline in your module without using the provider or any special function at all. Mixing an inline template string with a data source intended for rendering from an external file is what causes this awkward double-evaluation situation.

1 Like