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

`google_service_networking_connection` fails with `project: required field is not set` #18729

Closed arun-narayanan-db closed 1 month ago

arun-narayanan-db commented 1 month ago

Community Note

Terraform Version & Provider Version(s)

Terraform v1.5.7
on linux_amd64
+ provider registry.terraform.io/hashicorp/archive v2.4.2
+ provider registry.terraform.io/hashicorp/google v4.85.0
+ provider registry.terraform.io/hashicorp/google-beta v4.85.0
+ provider registry.terraform.io/hashicorp/null v3.2.2
+ provider registry.terraform.io/hashicorp/random v3.6.2

Affected Resource(s)

google_service_networking_connection

Terraform Configuration

The following code block is what is failing [called inside a module];

resource "google_service_networking_connection" "connection" {
  provider = google-beta
  count    = length(keys(local.address_ranges)) > 0 ? 1 : 0

  network                 = var.network
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [for range in google_compute_global_address.ranges : range.name]
}

Debug Output

I am unable to attach the debug output, due to certain restrictions in my organization.

Expected Behavior

The resource should be created.

Actual Behavior

β”‚ 
β”‚ Error: Failed to find Service Networking Connection, err: Failed to retrieve network field value, err: project: required field is not set
β”‚ 
β”‚   with module.service_networking_vpc_02.google_service_networking_connection.connection[0],
β”‚   on .terraform/modules/service_networking_vpc_02/main.tf line 50, in resource "google_service_networking_connection" "connection":
β”‚   50: resource "google_service_networking_connection" "connection" {
β”‚ 

Steps to reproduce

No response

Important Factoids

No response

References

No response

ggtisc commented 1 month ago

Hi @arun-narayanan-db!

I tried to replicate this issue, but you are not sharing the full code, since you are using for loops, locals, variables among other things that we can't see it is not possible to identify the cause of the error.

I've tested the general resource based in this terraform registry configuration and everything was successful without errors. This is the used code, maybe you could identify something to adapt your current code configuration:

provider "google" {
  #your-project-configuration
}

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google-beta"
      version = "4.85.0"
    }
  }
}

resource "google_compute_network" "cn_18729" {
  name = "cn-18729"
  auto_create_subnetworks = false
}

resource "google_compute_global_address" "cga_18729" {
  name          = "cga-18729"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = google_compute_network.cn_18729.id
}

resource "google_service_networking_connection" "snc_18729" {
  network                 = google_compute_network.cn_18729.name
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.cga_18729.name]
}

If you continue having problems, share the complete code to help you. You could protect sensitive data with examples like:

arun-narayanan-db commented 1 month ago

Hey @ggtisc: Thanks for getting back. Elaborating on the codebase,

Workspace [user-driven]; locals.tf

locals {
  project_id = "project01"
  network = {
    vpc = {
      id = "projects/project01/global/networks/vpc01"
      name = "vpc01"
      self_link = "https://www.googleapis.com/compute/v1/projects/project01/global/networks/vpc01"
    }
  }
  service_networking_ranges = {
    cloudsql = [
      {
        region   = "asia-south2"
        ip_range = "192.168.254.0/24"
      },
    ]
  }
}

service_networking.tf

module "service_networking" {
  source  = "privatefqdn/pmr/service-networking/google" # we utilized modules published in a private registry
  version = "X.X.X"

  project_id     = local.project_id
  network        = local.network.vpc.name
  address_ranges = local.service_networking_ranges
}

versions.tf

terraform {
  required_version = ">= 1.5.7"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "!= 4.53.0"
    }
    google-beta = {
      version = "!= 4.53.0"
    }
    null = {
      source  = "hashicorp/null"
      version = ">= 3.1.1"
    }
  }
}

Module: variables.tf:

variable "network" {
  description = "Self link of the VPC for the address range allocation"
  type        = string
}

variable "project_id" {
  description = "Project ID for this resource"
  type        = string
}

variable "address_ranges" {
  description = "IP address ranges to allocate, by purpose"
  type = map(list(object({
    ip_range = string
    region   = string
  })))
}

locals.tf

  # address_ranges map is converted to a list
  address_ranges_list = flatten([
    for p, a_list in var.address_ranges : [
      for a in a_list : {
        region   = a.region
        ip_range = a.ip_range
        purpose  = p
      }
    ]
  ])

  # ... and back to a map to be consumed by google_compute_global_address
  address_ranges = {
    for a in local.address_ranges_list :
    format("sa-%s-%s", a.purpose, replace(a.ip_range, "/\\.|\\//", "-")) => {
      address       = split("/", a.ip_range)[0]
      prefix_length = split("/", a.ip_range)[1]
    }
  }

main.tf

resource "google_compute_global_address" "ranges" {
  provider = google-beta
  for_each = local.address_ranges

  labels = merge(var.labels, local.labels) #CNE-15526

  name          = each.key
  purpose       = "VPC_PEERING"
  project       = var.project_id
  address_type  = "INTERNAL"
  address       = each.value.address
  prefix_length = each.value.prefix_length
  network       = var.network
}

resource "google_service_networking_connection" "connection" {
  provider = google-beta
  count    = length(keys(local.address_ranges)) > 0 ? 1 : 0

  network                 = var.network
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [for range in google_compute_global_address.ranges : range.name]
}

versions.tf

terraform {
  required_version = ">= 0.13.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 3.44.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = ">= 3.44.0"
    }
  }
}

The google_compute_address resource gets created just fine. Strangely, this code [in its same form] worked fine when carving out a connection to a servicenetworking producer project [~ 15 days ago].

If you are able to identify anything, do let me know. I have also opened up a ticket with GCP, in parallel, to see if they can identify the issue.

arun-narayanan-db commented 1 month ago

So, basically a doh moment;

What I originally went with;

module "service_networking" {
  source  = "privatefqdn/pmr/service-networking/google" # we utilized modules published in a private registry
  version = "X.X.X"

  project_id     = local.project_id
  network        = local.network.vpc.name # here
  address_ranges = local.service_networking_ranges
}

What I should have gone with;

module "service_networking" {
  source  = "privatefqdn/pmr/service-networking/google" # we utilized modules published in a private registry
  version = "X.X.X"

  project_id     = local.project_id
  network        = local.network.vpc.id # here
  address_ranges = local.service_networking_ranges
}

Basically, I used name incorrectly in the place of id. This change creeped in when I was refactoring the code, and strangely, did/does not pose a problem if the google_service_network_connection resource already exists.

Closing this bug as human error.

github-actions[bot] commented 2 weeks 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 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.