Reputation: 5888
I'm trying to set up a Google Cloud Load Balancer and one step requires updating the named ports on the managed instance groups for which I need a formatted string to generate the command-line call. I feel like this should be something that I can automate with terraform, but I'm struggling with mapping data formats.
I have two sets of source data.
From the instance group resource:
data "google_compute_instance_group" "all" {
count = "${length(var.backend)}"
self_link = "${element(var.backend, count.index)}"
}
I get the existing named ports from data.google_compute_instance_group.all.*.named_port
in the format:
[
[
map[name:https port:30443],
map[name:http port:30080]
],
[
map[name:https port:30443],
map[port:30080 name:http]
]
]
I also have the ports that I want to make sure are defined in my own map:
variable "node_ports" {
type = "map"
default = {
"https" = "30443"
"monitor" = "30012"
}
}
There may be overlap between these; I want to select the value defined in the variable. (The named ports are the same for all instance groups.)
First, I want to combine the two maps into a single map to make sure that there is one port for each name. How can I convert the first list of lists of maps to a single map so that I get this?
{
"http" = "30080"
"https" = "30443"
"monitor" = "30012"
}
Second, I want to convert all of that to the format needed on the command line:
gcloud --project ${var.project} compute instance-groups set-named-ports ${basename(var.backend[count.index])} --named-ports=https:443,http:30080,monitor:30012
I think I could do that with a jsonencode
hack but I'd be interested in better solutions:
"${replace(jsonencode(named_ports), "/[\\{\\}\"\\s]/", "")}"
Upvotes: 1
Views: 3750
Reputation: 6248
I was able to use a for expression to rearrange the list of list of maps using terraform 0.12.x. To break down this statement
merge({ for l in local.lolom[0] : l.name => l.port }, { monitor = local.monitor })
for l in local.lolom[0]
{ https = 30443, http = 30080 }
The merge()
will then combine our map with the monitor
map to give us our intended result
{
"http" = "30080"
"https" = "30443"
"monitor" = "30012"
}
I couldn't find a way to convert the above into the arguments without using jsonencode
but the following seems to provide the intended result.
locals {
lolom = [
[
{ name : "https", port : 30443 },
{ name : "http", port : 30080 }
],
[
{ name : "https", port : 30443 },
{ port : 30080, name : "http" }
]
]
monitor = 30012
first = merge({ for l in local.lolom[0] : l.name => l.port }, { monitor = local.monitor })
second = merge({ for l in local.lolom[1] : l.name => l.port }, { monitor = local.monitor })
first_args = replace(jsonencode(local.first), "/[\\{\\}\"\\s]/", "")
second_args = replace(jsonencode(local.second), "/[\\{\\}\"\\s]/", "")
}
output "first_args" {
value = local.first_args
}
output "second_args" {
value = local.second_args
}
Apply
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
first_args = http:30080,https:30443,monitor:30012
second_args = http:30080,https:30443,monitor:30012
Upvotes: 2