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

"URL has empty component" error when creating google_cloudfunctions2_function #13550

Open chase-replicated opened 1 year ago

chase-replicated commented 1 year ago

Community Note

Terraform Version

1.3.7

Affected Resource(s)

google_cloudfunctions2_function

https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloudfunctions2_function#nested_build_config

Terraform Configuration Files

Root module:

# Resource to force archiving of file during apply step
resource "null_resource" "trigger" {
  triggers = {
    timestamp = timestamp()
  }
}

data "archive_file" "handler_function_zip" {
  type        = "zip"
  source_dir  = var.handler_path
  output_path = "${path.root}/handler_function.zip"

  depends_on = [resource.null_resource.trigger]
}

resource "google_pubsub_schema" "event_schema" {
  name       = "event_schema_${var.name}"
  type       = "AVRO"
  definition = var.event_schema
}

resource "google_pubsub_topic" "event_topic" {
  name         = "event_topic_${var.name}"
  kms_key_name = var.kms_key_name == "" ? null : var.kms_key_name

  schema_settings {
    schema   = google_pubsub_schema.event_schema.id
    encoding = var.schema_encoding
  }

  labels = {
    owner      = var.owner
    managed-by = "terraform"
  }

  depends_on = [google_pubsub_schema.event_schema]
}

resource "google_pubsub_subscription" "event_subscription" {
  name  = "event_subscription_${var.name}"
  topic = google_pubsub_topic.event_topic.name

  depends_on = [google_pubsub_topic.event_topic]
}

resource "google_storage_bucket" "handler_storage_bucket" {
  name                        = "handler_storage_bucket-${var.name}"
  location                    = "US"
  uniform_bucket_level_access = true

  dynamic "logging" {
    for_each = var.storage_bucket_access_logs_bucket != null ? toset([1]) : toset([])

    content {
      log_bucket = var.storage_bucket_access_logs_bucket
    }
  }

  versioning {
    enabled = true
  }

  labels = {
    owner      = var.owner
    managed-by = "terraform"
  }
}

resource "google_storage_bucket_object" "handler_object" {
  name         = "handler_storage_bucket_object-${var.name}"
  bucket       = google_storage_bucket.handler_storage_bucket.name
  source       = data.archive_file.handler_function_zip.output_path
  content_type = "application/zip"
  depends_on   = [google_storage_bucket.handler_storage_bucket]
}

resource "google_cloudfunctions2_function" "handler_function" {
  name        = "handler_function-${var.name}"

  build_config {
    runtime = var.handler_runtime
    entry_point = var.handler_entrypoint
    source {
      storage_source {
        bucket = google_storage_bucket.handler_storage_bucket.name
        object = google_storage_bucket_object.handler_object.name
      }
    }
  }

  event_trigger {
    event_type   = "google.cloud.pubsub.topic.v1.messagePublished"
    pubsub_topic = google_pubsub_topic.event_topic.name
  }

  labels = {
    owner      = var.owner
    managed-by = "terraform"
  }
}

child module

terraform {
  backend "gcs" {
    bucket = "chase-test-custodian-custodian-tf-state"
    prefix = "terraform/state"
  }
  required_version = ">= 1.3.7"
}

module "gcp-event-handler" {
  source = "github.com/replicatedhq/gcp-event-handler-terraform-module"

  name  = "cloud-custodian"
  owner = "sre"
  event_schema = jsonencode({
    "type" : "record",
    "name" : "Avro",
    "fields" : [
      {
        "name" : "kind",
        "type" : "string"
      },
      {
        "name" : "id",
        "type" : "string"
      },
      {
        "name" : "name",
        "type" : "string"
      },
    ]
  })
  schema_encoding    = "JSON"
  gcp_project_id     = "chase-test-custodian"
  gcp_project_region = "us-central1"
  handler_path       = "../../../../scripts/gcp"
  handler_runtime    = "python37"
  handler_entrypoint = "print_decoded"
}

Debug Output

https://gist.github.com/chase-replicated/47d1f18c8ae77e923d0ec398992fec24

Panic Output

X

Expected Behavior

Should have created a cloudfunctions function

Actual Behavior

Errored out with "URL has empty component"

Steps to Reproduce

  1. terraform apply

Important Factoids

References

edwardmedia commented 1 year ago

@chase-replicated can you add location in your config to see if it solves the problem?

chase-replicated commented 1 year ago

Ah, thank you, that got me past that error. In that case, Should location be a required argument on this page? I didn't provide the providers file initially, so I've provided it below, but it would seem to me it should inherit what was set for "region" in the providers file by default.

provider "google" {
  project = "chase-test-custodian"
  # also tried 'us-central1-a'
  region  = "us-central1" 
}
edwardmedia commented 1 year ago

@chase-replicated For most resources, either region or zone is required since they are regional or zonal resources. The reason it becomes optional on each individual resource doc is they are set in the provider block as you found out above. Should we close this issue then?

chase-replicated commented 1 year ago

@edwardmedia I think I maybe explained incorrectly, I already have the region set in my provider but it won't work unless I also specify the region in the google_cloudfunctions2_function or else I encounter the error.

edwardmedia commented 1 year ago

The location validation like getLocation() is needed. That could be implemented in a shared code, and requires through investigation.