Terraform interpolation syntax error for data template_file - terraform

In my lambda.tf, I have a data resource
data "template_file" "handler" {
template = "${file("${path.module}/templates/handler.js")}"
vars = {
ENDPOINT = "${var.domain}"
PASSWORD = "${var.password}"
}
}
However - I'm encountering a syntax error:
Error: failed to render : <template_file>:280,49-50: Extra characters after interpolation expression; Expected a closing brace to end the interpolation expression, but found extra characters.
on ../docs/lambda.tf line 1, in data "template_file" "handler":
1: data "template_file" "handler" {
Is interpolation inside an interpolation allowed for Terraform? If so - any suggestions on pointing towards where the error is would be greatly appreciated.
Terraform v0.12.9.
Provider "aws" version "~> 2.7"

Not exactly clear what your template file looks like or what you are trying to do, so here are a couple different answers.
You can escape interpolation with double dollar signs: $${foo} will be rendered as a literal ${foo}.
Terraform does not allow dynamic construction of variable names, because it needs to be able to analyze the configuration statically (that is, without evaluating any expressions) in order to determine which order the expressions must be resolved in.
Terraform supports a map data structure that can be used to achieve this effect.
variable "var1" {
default = "value1"
}
variable "var2" {
default = "value2"
}
locals {
var3 = "${var.var1}_${var.var2}"
values = {
"value1_value2" = "local1"
"value2_value3" = "local2"
"value3_value4" = "local3"
}
}
output "val_output" {
value = "${local.values[local.var3]}"
}
If neither is what you are looking for, you need to share your template file or a modified version that duplicates the error.

The template_file data source continues to exist for users of Terraform 0.11 and earlier, but since you are using a Terraform 0.12 release I'd recommend using the templatefile function instead. Because it's built directly into Terraform, it is able to produce better error messages.
To use it, you can replace your references to data.template_file.handler.rendered with a direct call to templatefile. If you are using that rendered result in multiple locations, you can assign the templatefile result to a local value and reference that in multiple places instead.
templatefile("${path.module}/templates/handler.js", {
ENDPOINT = var.domain
PASSWORD = var.password
})
The error message you saw suggests that there's a syntax error in your template itself, but because template_file is implemented in a separate provider it's reporting that syntax error in an unhelpful way, pointing to a particular source location but not including the relevant source code snippet.
If you use templatefile instead, Terraform can hopefully report this syntax error itself and give better information about it.
Either way, it seems like the syntax error is on line 280 column 49 of your handler.js file and is caused by Terraform's template engine expecting to find the } to close a ${ ... } interpolation sequence but finding something else instead. If you correct that syntax error, template rendering should succeed by either approach.

Related

Conditional outputs on data sources in terraform

I have a sql server terraform module that outputs the name of a sql server for the databases to get created in. However, some environments should use an external server outside of the terraform project instead. Most datacenters we have do not have this external server, just a few.
I've set up the external server using data sources as usual, and made both the output, normal server and datasource conditional on a variable thats passed in like this:
variable "use_external_sql_server" {
type = bool
}
resource "azurerm_mssql_server" "sqlserver" {
count = var.use_external_sql_server ? 0 : 1
name = "sql-interal-sql_server"
....
}
data "azurerm_mssql_server" "external_sql_server" {
count = var.use_external_sql_server ? 1 : 0
name = "sql-${var.env}-${var.location}"
resource_group_name = "rg-${var.env}-${var.location}"
}
output "sql_server_name" {
value = var.use_external_sql_server ? data.azurerm_mssql_server.external_sql_server.name : azurerm_mssql_server.sqlserver[0].name
depends_on = [
azurerm_mssql_server.sqlserver,
data.azurerm_mssql_server.external_sql_server
]
}
However, I'm running into issues with the output. It requires data.azurerm_mssql_server.external_sql_server to exist to evaulate the condition, even if "use_external_server" is false. This is not ideal as I have to manual create dummy servers to fix this condition, so that that conditional can evaulate to true.
Is there a way to do this conditional without having to have "data.azurerm_mssql_server.external_sql_server" actually exist?
You could get rid of the conditional in the output and just use a try.
try evaluates all of its argument expressions in turn and returns the result of the first one that does not produce any errors.
This is a special function that is able to catch errors produced when evaluating its arguments, which is particularly useful when working with complex data structures whose shape is not well-known at implementation time.
You could then possibly write something like
output "sql_server_name" {
value = try(data.azurerm_mssql_server.external_sql_server[0].name, azurerm_mssql_server.sqlserver[0].name, "")
depends_on = [
azurerm_mssql_server.sqlserver,
data.azurerm_mssql_server.external_sql_server
]
}

variable scanning procedure of tflint

I'm newbie to tflint and other scanning tools. I'm trying to understand the scanning procedure.
In my example, I have variable.tf file where i'm passing variable names like azure storage account name, account tier etc.
my variable.tf file has which i gave intentionally.
variable "storage_account_name"{
type = string
default = "test-sa-123"
}
and in main.tf, i'm using as var.storage_account_name.
if I do tflint, normally it should throw error as storage account name should not have special characters but it is not throwing any errors.
So I want to understand whether tflint is capable to take that variable from variables.tf file and throw error in main.tf?
I tried checkov also but it is not throwing error for this mistake.
Is there any other tool which can scan the variables.tf and throw error in main.tf? Or do we need write our own rule for this in tflint?
thanks,
Santosh
Underscores in Terraform variables are valid. Tflint won't identify that as far as I know.
It won't throw an error with this. Even if the variable is passed through to the provider and references a storage account I wouldn't expect that to throw an error.
There are plugins as rulsets like this azure one for tflint which might increase what it catches but I still wouldn't rely on it for this purpose.
The way I'd handle this would be through Terraform variable validation.
The rules around storage accounts seem to be (source):
length: 3-24
type: Lowercase letters and numbers.
To identify that as a regex value you could use: ^[a-z0-9]*$
See tests
Here's a a very rough example:
variable "storage_account_name" {
type = string
validation {
condition = (
length(var.storage_account_name) > 3 && length(var.storage_account_name) < 25
)
error_message = "The storage_account_name value must be between 3 and 24 characters."
}
validation {
condition = (
regex('/^[a-z0-9]*$/g', var.storage_account_name)
)
error_message = "The storage account name must be only lowercase letters and numbers."
}
}

Terraform: Inspect module variables and outputs

One of my modules - let it be a - has an output definition as
output "data_table_arn" {
value = aws_dynamodb_table.data_table.*.arn
}
This is accessed one level above in module b
module "b" {
source = "../c"
data_lookup_table_arn = module.a.data_table_arn
The code above makes the variable module.a.data_table_arn accessible to module c through the variable data_lookup_table_arn. And now I am trying to access it in module c in an aws policy document definition
data "aws_iam_policy_document" "dynamo-read-policy-document" {
count = local.one_if_uses_dynamo
statement {
actions = ["dynamodb:GetItem"]
resources = [
var.data_table_arn
]
}
}
The exception I am getting is
Inappropriate value for attribute "resources": element 0: string required.
I want to debug this thing somehow and I cannot find a way to inspect the outputs or the variables defined inside a module. I can list the resources using terraform state list <resource_name> but this is not what I really want to do here.
How can I inspect the variables and outputs of a TF module?
Is this even possible?
Can you see anything faulty with my approach
I though of also using a heredoc instead of a aws_iam_policy_document but I would still need to make use of the output mentioned above - but this time in an interpolation I guess. Is this better or worse? They should be the same thing right?

Is it possible to report error on a condition with terraform 0.12?

Original reference - Quit condition on Terraform blueprint
Is it still possible to make conditional check like in the above question
resource "null_resource" "condition_checker" {
count = "${var.variable == 1 ? 0 : 1}"
"Insert your custom error message" = true
}
Similar format does not work in terraform 0.12 and 0.13 and I could not find any reference to removal of this feature. Is it possible to make a check like this 0.12 or 0.13?
Currently it is still not possible to validate inputs that require access to more than a variable. (The validation block only allows access to the validated variable.)
A hacky validation is still possible using the external data source:
data "external" "check_valid" {
count = var.to_test == true && some_other_condition ? 1 : 0
program = ["sh", "-c", ">&2 echo Condition must be satisfied when to_test is true; exit 1"]
}
This condition is checked before terraform asks for approval of a plan.
On the output it looks like this:
Error: failed to execute "sh": Condition must be satisfied when to_test is true
on variables.tf line 1, in data "external" "check_valid":
1: data "external" "check_valid" {
What you're referring to here was never an actual Terraform feature, but rather an example of exploiting a bug in an earlier version of Terraform to get a result that Terraform had no explicit support for.
With that said, modern versions of Terraform have support for custom variable validation rules which allow you to write out variable validation checks directly inside the corresponding variable block. For example:
variable "variable" {
type = number
validation {
condition = var.variable == 1
error_message = "Variable value must always be 1."
}
}
With that said, I just copied your contrived example from the question here, so this would require some adaptation for a real example. Note also that variable validation rules can only depend on the variable value and other constants, so you can't use this for more complicated checks such as those which involve two different variables. For that sort of situation, I'd recommend refactoring so that the values that are related arrive in a single variable of a object type, and then the validation can be for whether that object is valid.

terraform local & lookup help for azure

Just a quick question to understand whats the best way to use this. To fetch values off "locals" in terraform do i use lookup(local.this) or local.this or example below i got:
locals {
array = {"this" = data.something.output, "this02" = data.something.output }
}
You can reference each declaration within a locals block just as you would a normal variable, but as local.name instead of var.name.
So for your example you could use lookup(local.array,"this","defaultvalue"), or any of the other ways to access a map variable.

Resources