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.29k stars 1.72k forks source link

google_compute_instance: ephemeral ip address and splat syntax #3089

Open Alexhha opened 5 years ago

Alexhha commented 5 years ago

Community Note

Terraform Version

$ terraform -v
Terraform v0.11.11
+ provider.google v1.20.0

Affected Resource(s)

Terraform Configuration Files

resource "google_compute_instance" "gce-test" {
    machine_type = "f1-micro"
    name = "gce-test"
    count = "${var.gce_enabled == "true" ? "1": "0" }"

    boot_disk {
        initialize_params {
            image = "ubuntu-os-cloud/ubuntu-1404-lts"
        }
    }

    network_interface {
        subnetwork = "default"
        access_config {
            nat_ip = ""
        }
    }

    service_account {
        scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }
}

And the output.tf looks like

output "gce_public_ip" {
    value = "${google_compute_instance.gce-test.network_interface.0.access_config.0.assigned_nat_ip}"
}

Debug Output

Panic Output

Expected Behavior

The output should be empty as with google_compute_address resource

Actual Behavior

  1. terraform apply
    
    $ terraform plan -var gce_enabled=false
    Refreshing Terraform state in-memory prior to plan...
    The refreshed state will be used to calculate this plan, but will not be
    persisted to local or remote state storage.

Error: Error running plan: 1 error(s) occurred:

I have tried a different combinations

"${google_compute_instance.gce-test.network_interface.*.access_config.0.assigned_nat_ip}"
"${google_compute_instance.gce-test.network_interface.*.access_config.*.assigned_nat_ip}"

but without success. If I replace ephemeral ip address with a static one - everything works fine.

Steps to Reproduce

$ terraform init
$ terraform apply

Important Factoids

References

b/308755570

Chupaka commented 5 years ago

Probably you need nat_ip, not assigned_nat_ip? https://www.terraform.io/docs/providers/google/r/compute_instance.html#network_interface-0-access_config-0-nat_ip

rileykarson commented 5 years ago

I believe this is a variant of https://github.com/hashicorp/terraform/issues/17048. If so, it could be fixed with a computed convenience field or by 0.12.

Alexhha commented 5 years ago

I have tried nat_ip

output "gce_public_ip" {
    value = "${join("",google_compute_instance.test.network_interface.*.access_config.*.nat_ip)}"
}

But it gives me the same error

Error: Error running plan: 1 error(s) occurred:

* output.gce_public_ip: Resource 'google_compute_instance.gce-test' not found for variable 'google_compute_instance.gce-test.network_interface.*.access_config.*.nat_ip'
MrDanao commented 5 years ago

If you wanted an ephemeral IP address, you should have used an empty access_config {} block:

resource "google_compute_instance" "gce-test" {

    [...]

    network_interface {
        subnetwork = "default"
        access_config {}
    }

    [...]

}

Then, for the output:

output "gce_public_ip" {
    value = "${google_compute_instance.gce-test.network_interface.0.access_config.0.nat_ip}"
}
Alexhha commented 5 years ago

It will give an error if resource does not exist.

resource "google_compute_instance" "gce-test1" {
    machine_type = "f1-micro"
    name = "gce-test1"
    count = "${var.gce1_enabled == "true" ? "1": "0" }"
...
}

resource "google_compute_instance" "gce-test2" {
    machine_type = "f1-micro"
    name = "gce-test2"
    count = "${var.gce2_enabled == "true" ? "1": "0" }"
...
}

With the following output

output "gce1-public-ip" {
    value = "${google_compute_instance.gce-test1.network_interface.0.access_config.0.nat_ip}"
}

output "gce2-public-ip" {
    value = "${google_compute_instance.gce-test2.network_interface.0.access_config.0.nat_ip}"
}

For e.g.

$ terraform apply -var 'gce1_enabled=true' -var 'gce2_enabled=false'
data.google_compute_zones.available: Refreshing state...

Error: Error running plan: 1 error(s) occurred:

* output.gce2-public-ip: Resource 'google_compute_instance.gce-test2' not found for variable 'google_compute_instance.gce-test2.network_interface.0.access_config.0.nat_ip'

and that's the root of the issue

MrDanao commented 5 years ago

Okay. According to hashicorp/terraform#16726, this output should work:

output "gce_public_ip" {
    value = "${element(concat(google_compute_instance.gce-test.*.network_interface.0.access_config.0.nat_ip, list("")), 0)}"
}

I have just tested it and it seems to work.

Alexhha commented 5 years ago

Yes, works fine. Thanks. But the syntax looks weird

paddycarver commented 5 years ago

Has this been fixed in 0.12?

tillias commented 3 years ago

In newer versions (e.g. 0.13.5) syntax is changed

Warning: Interpolation-only expressions are deprecated

  on main.tf line 45, in output "gce_public_ip":
  45:     value = "${element(concat(google_compute_instance.vm_instance.*.network_interface.0.access_config.0.nat_ip, list("")), 0)}"

For those who interested following won't show any warning:

output "gce_public_ip" {
    value = element(concat(google_compute_instance.vm_instance.*.network_interface.0.access_config.0.nat_ip, list("")), 0)
}
Chupaka commented 3 years ago

@tillias Also, list("") can be shortened to [""] :)

luckeyca commented 3 years ago

I have no problem with the public ip output as per documentation. I use a blank access_config {} block, then in outputs.tf Don't remember exactly when I started to use this format, could be 0.11.x, then 0.12.x and now still works on 0.14.7, current google provider version is 3.57.0

output "instances_info" {
  description = "Compute instance information"
  value = [
     for instance in google_compute_instance.default :
     [instance.network_interface.0.access_config.0.nat_ip]
  ]
}
bro2020 commented 2 years ago

In Terraform v1.2.4 worked

output "instances_info" {
  description = "Compute instance information"
  value = {
     for instance in google_compute_instance.instance_name : instance.network_interface.0.access_config.0.nat_ip
  }
}

and

output "instances_info" {
  description = "Compute instance information"
  value = google_compute_instance.instance_name[*].network_interface.0.access_config.0.nat_ip
}
karolgorc commented 2 weeks ago

Is this still an issue?