hashicorp / terraform-provider-google

Terraform Provider for Google Cloud Platform
https://registry.terraform.io/providers/hashicorp/google/latest/docs
Mozilla Public License 2.0
2.33k stars 1.73k forks source link

Idempotent failure for google_compute_router_nat when using URLs as values from subnet #2745

Closed RaghavendraP closed 5 years ago

RaghavendraP commented 5 years ago

Terraform Version

Terraform v0.11.11

google_compute_router_nat

Terraform Configuration Files

resource "google_compute_router_nat" "nat" { name = "nat" region = "${var.region}" router = "${google_compute_router.router.name}" nat_ip_allocate_option = "MANUAL_ONLY" nat_ips = ["${google_compute_address.nat-address.*.self_link}"] source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS"

subnetwork { name = "${google_compute_subnetwork.subnet.self_link}" } }

Debug Output

subnetwork.321339854.name: "" => "https://www.googleapis.com/compute/v1/projects/{project}/regions/us-central1/subnetworks/{subnet}" (forces new resource) subnetwork.84126378.name: "https://www.googleapis.com/compute/v1/projects/{project}/regions/us-central1/subnetworks/{subnet}" => "" (forces new resource)

Expected Behavior

there should not be any change in resources during plan or apply execution.

Actual Behavior

updating internal subnet id during each time run which is causing the idempotent failure.

Steps to Reproduce

RaghavendraP commented 5 years ago

After trying couple more times it seems the entry in tfstate file and the output of terraform apply are not matching. tfstate always showing subnetwork id as 84126378 whereas the apply command output is showing the value as 321339854. This is causing idempotent issue.

edit 1: Tried by updating tfstate entry but terraform apply still giving me option of destroying resource and creating it again.

RaghavendraP commented 5 years ago

I did further more testing using windows and linux terraform (0.11.11) versions.

"subnetwork.#": "1", "subnetwork.84126378.name": "https://www.googleapis.com/compute/v1/projects/{project}/regions/us-central1/subnetworks/{subnet}", "subnetwork.84126378.secondary_ip_range_names.#": "0", "subnetwork.84126378.source_ip_ranges_to_nat.#": "1", "subnetwork.84126378.source_ip_ranges_to_nat.2943096726": "ALL_IP_RANGES"

subnetwork.#: "1" => "1" subnetwork.321339854.name: "" => "https://www.googleapis.com/compute/v1/projects/{project}/regions/us-central1/subnetworks/{subnet}" (forces new resource) subnetwork.321339854.secondary_ip_range_names.#: "" => "0" subnetwork.321339854.source_ip_ranges_to_nat.#: "" => "0" subnetwork.84126378.name: "https://www.googleapis.com/compute/v1/projects/{project}/regions/us-central1/subnetworks/{subnet}" => "" (forces new resource) subnetwork.84126378.secondary_ip_range_names.#: "0" => "0" subnetwork.84126378.source_ip_ranges_to_nat.#: "1" => "0" (forces new resource) subnetwork.84126378.source_ip_ranges_to_nat.2943096726: "ALL_IP_RANGES" => "" (forces new resource)

Because of this, I can't keep the router_nat resource within terraform logic.

If anyone can help me with workaround that would be great.

rileykarson commented 5 years ago

Sorry about the unintuitive diff here & thanks for including the entire result! The hash value (321339854, 84126378) is based on the entire contents of the field so a minor change in any value will cause an unintuitive diff like you experienced unfortunately.

It looks like source_ip_ranges_to_nat isn't being read from upstream correctly, I'll investigate & (hopefully) get that fixed on our side for our next release.

rileykarson commented 5 years ago

I misspoke, looks like this is a problem with how we're able to handle "complex" (object/list/set nested) defaults in the API. You can fix it by explicitly setting source_ip_ranges_to_nat in your subnetwork block to include the API-side default of ALL_IP_RANGES. We have an example in our acceptance tests for the resource.

Since we're still prepping 2.0.0 and can make breaking changes, I'm going to fix this by requiring that attribute to be explicitly specified in configs.

RaghavendraP commented 5 years ago

Thanks for explaining. But I still have a doubt. Why during apply and plan, terraform is showing one value but after apply the tfstate is being updated with different value?

rileykarson commented 5 years ago

Once we've created a resource, we do a GET against the GCP API and store those values in state. They're the values shown on the left side of the diff. For source_ip_ranges_to_nat, the API will always return a value even if the user didn't provide one, and so we record that value in state. We effectively need to always read that value- there are a few ways we could avoid it which we manage to do sometimes, but not in this case.

The problem is, the right side of the diff is generated by exactly mapping your config -> a state; we don't have an opportunity to modify the config other than in a few small ways, and specifically with values with defaults inside nested blocks like subnetwork that can lead to some weird diffs.

Does that make sense?

RaghavendraP commented 5 years ago

yes. Thanks for the detailed explanation.

ghost commented 5 years ago

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 feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 hashibot-feedback@hashicorp.com. Thanks!