Hi there,
I stumbled upon the below use case of the splat syntax, and am wondering if this is considered normal behavior we can rely on, or rather a bug that will probably disappear in future versions of terraform.
In the former case, I believe some additional documentation would be great.
Terraform v0.9.5
Not resource specific.
variable "general" {
default {
project = "myproject"
region = "europe-west1"
}
}
resource "google_container_cluster" "gke_cluster0" {
name = "${var.general["project"]}-${var.general["region"]}-cluster0"
zone = "${var.general["region"]}-${var.gke["main_zone"]}"
initial_node_count = "${var.gke["initial_node_count"]}"
network = "${var.infra["net0_name"]}"
subnetwork = "${var.infra["subnet0_name"]}"
additional_zones = "${formatlist(format("%s-%%s", var.general["region"]), compact(split(",", var.gke["additional_zones"])))}"
master_auth {
username = "${var.gke["username"]}"
password = "${var.gke["password"]}"
}
node_config {
machine_type = "${var.gke["machine_type"]}"
}
}
resource "google_compute_health_check" "ilb_hc" {
name = "${var.general["project"]}-${var.general["region"]}-ilb-hc"
check_interval_sec = 30
timeout_sec = 30
tcp_health_check {
port = "31181"
}
}
resource "google_compute_region_backend_service" "ilb_rbs" {
name = "${var.general["project"]}-${var.general["region"]}-ilb-rbs"
protocol = "TCP"
timeout_sec = 10
session_affinity = "NONE"
backend {
group = "${element(google_container_cluster.gke_cluster0.instance_group_urls, 0)}"
}
backend {
group = "${element(google_container_cluster.gke_cluster0.instance_group_urls, 1)}"
}
backend {
group = "${element(google_container_cluster.gke_cluster0.instance_group_urls, 2)}"
}
health_checks = ["${google_compute_health_check.ilb_hc.self_link}"]
}
Env A:
variable "gke" {
default {
username = "" //use terraform.tfvars
password = "" //use terraform.tfvars
machine_type = "n1-standard-2"
initial_node_count = 3
main_zone = "b"
additional_zones = ""
}
}
Env B:
variable "gke" {
default {
username = "" //use terraform.tfvars
password = "" //use terraform.tfvars
machine_type = "n1-standard-4"
initial_node_count = 3
main_zone = "b"
additional_zones = "c,d"
}
}
Not sure, hence this issue.
Terraform dynamically handles backend blocks on the google_compute_region_backend_service resource, as env A has only one instance group backend while env B has 3.
terraform applyHi @pdecat!
This is an interesting case. Let's walk through what's happening:
The backend field of the google_compute_region_backend_service resource is a set. That means each distinct backend will end up in the list no matter how many times it's listed in the resource. Meaning the following has only one backend in the set, no matter how many times it's specified:
resource "google_compute_region_backend_service" "foo" {
backend {
group = "bar"
description = "baz"
}
backend {
group = "bar"
description = "baz"
}
}
Right now, backends are considered distinct only if their description or group is distinct.
element function. As documented, if the element function accesses an index that is past the end of the list, the index will wrap around to the beginning.The two of these combine to mean that when you have three distinct groups in your list, the set of backends has three distinct items--one per group. However, when you only have one backend, the element function wraps around one the second two backend blocks, meaning the same backend is used in all three blocks. Meaning the set only has one item in it.
So I wouldn't call this a "bug", in that all the pieces are working as intended. I would not, however, call this a "feature", in that overall it's not a designed behaviour. If, in the future, the backend block has a different way of determining if backends are unique, or we switch to using a list instead of a set, this would almost certainly break, as the backends would no longer be deduplicated.
I can't answer whether you should rely on it directly, because only you know the level of risk you're comfortable with. I can tell you that, in my mind, this is working as intended, but I also do not consider it a contract, so it's not being tested for. Hopefully that's enough information to help you make an informed decision. :)
I'm going to close this out, as I think I answered the question. If you want to dig more into this, have a use case you need a more reliable contract for that you're using this as a workaround on right now, or need to talk more about it, feel free to reply below and we'll continue the conversation, or feel free to open a new issue. Thanks!
Hi @paddycarver,
I was not aware of blocks like the backend field of the google_compute_region_backend_service resource being sets, I thought they were lists of maps.
Now it makes perfect sense, thanks for the detailed explanation!
I guess that also kind of explains why we do not have count at the block level.
Complex types in Terraform are, for lack of a better word, complex. :) I know @apparentlymart has that on his radar and has a lot of thoughts on that, but I don't think we have anything to say about it, officially, just yet.
I don't even know that _every_ block like backend is a Set; I _think_ they could be a list or a map? But I'm not sure. I've mostly seen them as sets.
But yeah, count only works on resources, so it can't be used on fields, which is what blocks are. There was some discussion and talk about how to fix this, but I think it got really thorny really quickly. I think it's still something we want to do, but again, no official promise to do it or any timeline. :)
I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
Most helpful comment
Complex types in Terraform are, for lack of a better word, complex. :) I know @apparentlymart has that on his radar and has a lot of thoughts on that, but I don't think we have anything to say about it, officially, just yet.
I don't even know that _every_ block like
backendis a Set; I _think_ they could be a list or a map? But I'm not sure. I've mostly seen them as sets.But yeah,
countonly works on resources, so it can't be used on fields, which is what blocks are. There was some discussion and talk about how to fix this, but I think it got really thorny really quickly. I think it's still something we want to do, but again, no official promise to do it or any timeline. :)