Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

google_compute_instance network_ip selflink reference causes re-creation. #7841

Closed
toumorokoshi opened this issue Nov 18, 2020 · 4 comments
Closed
Assignees
Labels

Comments

@toumorokoshi
Copy link

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request.
  • Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment.
  • If an issue is assigned to the modular-magician user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to hashibot, a community member has claimed the issue already.

Terraform Version

Terraform v0.13.5
+ provider registry.terraform.io/hashicorp/google v3.48.

Affected Resource(s)

  • google_compute_instance

Terraform Configuration Files

provider "google" {
 project     = "cnrm-yusuketsutsumi"
 region      = "us-west1"
}

resource "google_compute_instance" "default" {
  provider     =  google
  name         = "gh-293-2"
  machine_type = "n1-standard-1"
  zone         = "us-west1-a"
  allow_stopping_for_update = true

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }

  network_interface {
    subnetwork = "https://www.googleapis.com/compute/v1/projects/cnrm-yusuketsutsumi/regions/us-west1/subnetworks/computeinstance-dep-cloudmachine"
    network_ip = "https://www.googleapis.com/compute/v1/projects/cnrm-yusuketsutsumi/regions/us-west1/addresses/gh-239"
  }
}

Debug Output

https://gist.github.com/toumorokoshi/9646615be1173a522c432daba06a4a43

Expected Behavior

An apply with the exact same input values, that resolve to the exact same final values, should not force replacement.

Actual Behavior

When running apply on a google_compute_instance that is using a selflink value in network_interface.network_ip, re-running an apply results in a replacement of the whole compute_instance, as the selflink resolved to the actual IP address.

You can see the output of the TF plan here:

      ~ network_interface {
          ~ name               = "nic0" -> (known after apply)
          ~ network            = "https://www.googleapis.com/compute/v1/projects/cnrm-yusuketsutsumi/global/networks/computeinstance-dep-cloudmachine" -> (known after apply)
          ~ network_ip         = "10.2.0.2" -> "https://www.googleapis.com/compute/v1/projects/cnrm-yusuketsutsumi/regions/us-west1/addresses/gh-239" # forces replacement
            subnetwork         = "https://www.googleapis.com/compute/v1/projects/cnrm-yusuketsutsumi/regions/us-west1/subnetworks/computeinstance-dep-cloudmachine"
          ~ subnetwork_project = "cnrm-yusuketsutsumi" -> (known after apply)
        }

This happens after every apply.

Steps to Reproduce

  1. terraform apply

Important Factoids

I believe there's actually a broad range of times when this issue occurs, but haven't investigated too deeply. Anytime a selfLink is used in this manner (replaced with a different string) with a field that requires replacement to be modified, there will be an unneeded forced replacement.

Another one worth looking into is boot_disk.initialize_params.image, which expands families of images into the fully qualified name.

References

@ghost ghost added the bug label Nov 18, 2020
@edwardmedia edwardmedia self-assigned this Nov 18, 2020
@edwardmedia
Copy link
Contributor

edwardmedia commented Nov 18, 2020

Given the fact that the state only keeps the ip data instead of the reference, I am not sure if that is possible for not recreating the instance. I am not aware of any methods in the Terraform that can handle this

@toumorokoshi
Copy link
Author

Thanks for the reply! If that's the case, I might consider actively discouraging this practice.

The detected mutation isn't the end of the world, but the main issue is that re-creating the instance can lead to downtime. I feel like it severely limits the scenarios where leveraging the selflink is useful, if this is the case.

@rileykarson
Copy link
Collaborator

rileykarson commented Nov 24, 2020

I believe there's actually a broad range of times when this issue occurs, but haven't investigated too deeply. Anytime a selfLink is used in this manner (replaced with a different string) with a field that requires replacement to be modified, there will be an unneeded forced replacement.

It's a little less dire than that! In many cases the API converts a reference to a canonical format (whether the self link format or the partial URI format) and the provider handles those. This is a little different. There's no way to tell if the returned IP corresponds to the provided self link. That leaves us with a few options:

  1. Never record the value returned from the API into state. This has the obvious downside that for users that didn't provide an IP, an IP will never be recorded. We could try writing it only if no value was provided, but Terraform makes it hard to tell when that's the case.

  2. Record the value returned from the API into state, and use a DiffSuppressFunc to only cause a diff when the values on both sides are IPs that mismatch. This would cause any reference to match any IP and not cause a diff, fixing this case- but would also mean that changing the reference wouldn't cause one either.

  3. Record the value from the API, expect the user to provide an IP. This is the behaviour today. This is pretty natural to write in Terraform, particularly because referencing an address value is easy. For example:

resource "google_compute_address" "static" {
  name = "internal-address"
}

data "google_compute_image" "debian_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_instance" "instance_with_network_ip" {
  name         = "vm-instance"
  machine_type = "f1-micro"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = data.google_compute_image.debian_image.self_link
    }
  }

  network_interface {
    network = "default"
    network_ip = google_compute_address.static.address
  }
}

You could also use a datasource to fetch information about an address without managing it.

I'm closing this out as both other approaches have strong downsides, and 3) works well today.

@ghost
Copy link

ghost commented Dec 25, 2020

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!

@ghost ghost locked as resolved and limited conversation to collaborators Dec 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants