Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if variable exists - Terraform template syntax

I'm trying to check if a variable exists on a template file using terraform template syntax, but I get error that This object does not have an attribute named "proxy_set_header.

$ cat nginx.conf.tmpl

%{ for location in jsondecode(locations) }
location ${location.path} {
    %{ if location.proxy_set_header }
       proxy_set_header ${location.proxy_set_header};
    %{ endif }
}
%{ endfor }

I tried with if location.proxy_set_header != "" and if location.proxy_set_header without success.

How to check if a variable exists with the String Templates?

like image 498
Cae Vecchi Avatar asked Dec 31 '22 07:12

Cae Vecchi


2 Answers

If you are using Terraform 0.12.20 or later then you can use the new function can to concisely write a check like this:

%{ for location in jsondecode(locations) }
location ${location.path} {
    %{ if can(location.proxy_set_header) }
       proxy_set_header ${location.proxy_set_header};
    %{ endif }
}
%{ endfor }

The can function returns true if the given expression could evaluate without an error.


The documentation does suggest preferring try in most cases, but in this particular situation your goal is to show nothing at all if that attribute isn't present, and so this equivalent approach with try is, I think, harder to understand for a future reader:

%{ for location in jsondecode(locations) }
location ${location.path} {
    ${ try("proxy_set_header ${location.proxy_set_header};", "") }
}
%{ endfor }

As well as being (subjectively) more opaque as to the intent, this ignores the recommendation in the try docs of using it only with attribute lookup and type conversion expressions. Therefore I think the can usage above is justified due to its relative clarity, but either way should work.

like image 134
Martin Atkins Avatar answered Jan 02 '23 21:01

Martin Atkins


I would do something like the following, using contains and keys

%{ for location in jsondecode(locations) }
location ${location.path} {
    %{ if contains(keys(location), "proxy_set_header") }
       proxy_set_header ${location.proxy_set_header};
    %{ endif }
}
%{ endfor }

The parsed JSON essentially becomes a map which can be checked for key contents.

I tested this with the following code

data "template_file" "init" {
  template = file("${path.module}/file.template")
  vars = {
    locations = <<DOC
[
  {
    "path": "foo",
    "proxy_set_header": "foohdr"
  },
  {
    "path": "bar"
  }
]
DOC
  }
}

output "answer" {
  value = data.template_file.init.rendered
}

and it had the following output

Outputs:

answer = 
location foo {

       proxy_set_header foohdr;

}

location bar {

}

like image 22
mjgpy3 Avatar answered Jan 02 '23 21:01

mjgpy3