Terraform is a powerful infrastructure as code (IaC) tool, but even experienced users sometimes encounter challenges with what seems like basic operations. One such operation is simple string concatenation, which can be perplexing if you’re not familiar with the specific syntax and functions available in Terraform. In this article, we’ll address a common issue that many Terraform users encounter and provide a clear solution to it.
Table of Contents
The Problem
Consider the scenario where you need to create a string that varies based on the value of a Terraform variable. Specifically, you want to create a URL that should have a dot ("."
) separator between two parts of the string, but only when a certain condition is met. Let’s say you have a variable env_name
, and you want to create a URL like app.api.mydomain.com
when env_name
is set to "prod"
and app.api.staging.mydomain.com
for any other value of env_name
.
An extremely simple string concatenation would work using the following code, but wont work for this more complex scenario:
main_api_gw = "app.api.${var.env_name}"
For this more complex scenario though, including an if/then evaluation, you might initially try to achieve this string concatenation using the following code:
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = "app.api.${var.env_name == "prod" ? "" : var.env_name}mydomain.com"
}
}
However, there’s a problem with this approach. When env_name
is not "prod"
, the code results in app.api.stagingmydomain.com
instead of the desired app.api.staging.mydomain.com
because the dot separator is missing.
To address this issue, you might attempt to concatenate the dot when env_name
is not "prod"
using the +
operator:
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = "app.api.${var.env_name == "prod" ? "" : var.env_name + "."}mydomain.com"
}
}
However, this approach will lead to an error: __builtin_StringToInt: strconv.ParseInt: parsing ""
.
The problem here is that Terraform tries to convert the result of the conditional expression into an integer, leading to an error since it’s attempting to convert an empty string ""
to an integer.
The Solution
In Terraform, more complex string concatenation scenarios can be achieved using the join
function. This function is quite flexible and allows you to concatenate a list of strings using a separator. To use it in this case, you can convert the string parts you want to concatenate into a list and then use join
with a dot separator.
Here’s how you can do it:
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = join(".", ["app.api", var.env_name == "prod" ? "" : var.env_name, "mydomain.com"])
}
}
In this code, we create a list containing three elements: "app.api"
, var.env_name
, and "mydomain.com"
. The join
function concatenates these elements with a dot separator, producing the desired URL.
Practical Example: Using join
function
Here’s a complete practical example of how you can use the solution in a Terraform configuration file:
variable "env_name" {
description = "Environment name"
type = string
default = "staging"
}
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = join(".", ["app.api", var.env_name == "prod" ? "" : var.env_name, "mydomain.com"])
}
}
output "api_gateway_url" {
value = data.null_data_source.api_gw_url.inputs.main_api_gw
}
In this example, we define a variable env_name
with a default value of “staging.” The null_data_source
block then uses the join
function to concatenate the parts of the URL, and we output the resulting API gateway URL.
Now, Terraform will correctly handle the string concatenation, and you will get the expected output depending on the value of env_name
. If env_name
is “prod,” you’ll get app.api.mydomain.com
, and for any other value of env_name
, you’ll get the appropriate URL with the dot separator.
Practical Example: Using locals
Here’s another practical example of how you can use a local
varable in addition to use simple string concatenation to get the job done without the need for the join
function at all:
variable "env_name" {
description = "Environment name"
type = string
default = "staging"
}
local {
gateway_environment = var.env_name == "prod" ? "" : "${var.env_name}."
}
data "null_data_source" "api_gw_url" {
inputs = {
main_api_gw = "app.api.${local.gateway_environment}mydomain.com"
}
}
output "api_gateway_url" {
value = data.null_data_source.api_gw_url.inputs.main_api_gw
}
Conclusion
While string concatenation in Terraform may seem straightforward, it’s essential to be aware of the available functions like join
to handle various scenarios effectively. The join
function provides a flexible way to concatenate strings and is especially useful when dealing with conditional concatenation, as shown in this article.