Skip to main content
Knowledge Base

How to convert template_file to local variable

Answer

I have a related question to #350. We have the following `template_file` code that we are trying to convert to a local variable. ``` data "template_file" "port_mappings" { template = <<EOF { "containerPort": ${var.container_port}, "hostPort": ${var.container_port}, "protocol": "tcp" } EOF } ``` It's used later on in ``` locals { ecs_task_container_definitions = templatefile( "${path.module}/container-definition/container-definition.json", { container_name = var.service_name image = var.image version = var.image_version cpu = var.cpu memory = var.memory port_mappings = "[${join(",", data.template_file.port_mappings.*.rendered)}]" env_vars = "[${join(",", data.template_file.all_env_vars.*.rendered)}]" log_group = aws_cloudwatch_log_group.ecs_task_log_group.name region = var.aws_region log_stream_prefix = "${var.service_name}-ecs-fargate" } ) } ``` I tried changing it to a local variable as a map and as a string but I keep getting an error when running `terragrunt apply`. ``` Error: Invalid function argument on main.tf line 225, in locals: 225: port_mappings = "[${join(",", local.port_mappings)}]" ├──────────────── │ local.port_mappings is object with 3 attributes Invalid value for "lists" parameter: list of string required. ``` We also have: ``` data "template_file" "all_env_vars" { count = length(local.all_env_vars) template = <<EOF { "name": "${element(keys(local.all_env_vars), count.index)}", "value": "${lookup(local.all_env_vars, element(keys(local.all_env_vars), count.index))}" } EOF } ``` `local.all_env_vars` comes from another local variable: ``` locals { all_env_vars = merge(local.default_env_vars, var.extra_env_vars) } ``` This gets used in a similar way as the other template file in `"[${join(",", data.template_file.all_env_vars.*.rendered)}]"` as referenced in the `ecs_task_container_definitions` local variable in the above code. Do you have a suggestion on how best to convert the`template_file` instances to local variables? We've been successful in all of our other conversions but are stumped with this one. --- <ins datetime="2022-07-13T21:16:40Z"> <p><a href="https://support.gruntwork.io/hc/requests/108979">Tracked in ticket #108979</a></p> </ins>

Did you set port_mappings to the raw object? E.g. ```hcl port_mappings = { "containerPort": ${var.container_port}, "hostPort": ${var.container_port}, "protocol": "tcp" } ``` If so, the main issue is because port_mappings is now an object instead of a string. My best recommendation for addressing this is to do the following: ```hcl locals { # Convert to list of objects port_mappings = [{ containerPort = var.container_port hostPort = var.container_port protocol = "tcp" }] ecs_task_container_definitions = templatefile( "${path.module}/container-definition/container-definition.json", { # ... other args omitted for brevity ... # Turn port_mappings into a json string port_mappings = jsonencode(local.port_mappings) } ) } ``` You can do a similar thing (use HCL object to construct the data, and then `jsonencode` to pass it to the template) for the env vars: ```hcl locals { all_env_vars_encoded = [ for key, val in local.all_env_vars : { name = key value = val } ] ecs_task_container_definitions = templatefile( "${path.module}/container-definition/container-definition.json", { # ... other args omitted for brevity ... # Turn env_vars into a json string env_vars = jsonencode(local.all_env_vars_encoded) } ) } ```