terraform-provider-google: Creation of Endpoints for Cloud Functions causes circular dependency between ESP and Endpoint services

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 -v
Terraform v0.12.20
+ provider.google v3.5.0

Affected Resource(s)

google_cloud_run_service google_endpoints_service

Terraform Configuration Files

resource "google_cloud_run_service" "run" {
  name = var.name
  location = var.location

  template {
    spec {
      containers {
        image = "gcr.io/endpoints-release/endpoints-runtime-serverless:2"
        env {
          name = "ENDPOINTS_SERVICE_NAME"
          value = google_endpoints_service.openapi_service.service_name
        }
      }
    }
  }
}

resource "google_endpoints_service" "openapi_service" {
  service_name = replace(google_cloud_run_service.run.status[0].url,  "https://", "")
  project = var.project_id
  openapi_config = var.config
}

Debug Output

Panic Output

Expected Behavior

Please note that I do not expect this deployment with circular dependency to work. But there must be a working scenario for creating Endpoints for Google Function possibly followed different approach or with different API. Current API seem not to permit such cases.

Actual Behavior

The circular dependency error appears

Steps to Reproduce

  1. terraform apply

Important Factoids

Google Cloud endpoint documentation from here - https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions reads the following steps to create Endpoint for Google Function

  1. Create ESP service with Google Run and remember the URL address allocated by Google for this service
  2. Crete Endpoint service (Use that URL address obtained on previous step to build the endpoint openapi config)
  3. Update the ESP service created on step 1 with the name of the Endpoint

But these steps make both resources dependent on each other and inevitably bring to circular dependency error in Terraform. There must be a working scenario for creating Endpoints for Google Function.

References

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 42
  • Comments: 34 (4 by maintainers)

Commits related to this issue

Most upvoted comments

The only thing we really need to not deploy 2 images to Cloud Run - which is the big thing messing with terraform - is the HASH in the url: https://my-cloud-run-HASH-LOC.a.run.app. If we can compute this value, or retrieve it through an API before a new image is deployed, we can make this work. We would need a data source, data.cloud_run_hash, that has as output that HASH value. The steps would be :

  1. terraform calculates the hash
  2. terraform deploys the endpoint with the swagger.yaml with the correct URL
  3. You build and push the image with the swagger included with local-exec (as google is really saying “run this bash script”, there’s not really any way around using local-exec)
  4. terraform creates the cloud run resource.

So now the problem is reduced to: how to get the HASH value?

  • Does anyone know about an API that yields this value (other then deploying a dummy image)? Mentioning @chrisst as he seems to know something about the APIs.
  • Is it the HASH even unique per GCP project, or is it per Cloud Run deployment?
  • If these methods don’t exist, what’s the proper place to request this feature?

Also a friendly reminder to anyone coming accross this issue to +1 the original post, as it indicates the importance of the issue to the developers working on this repository.

I ran into this issue recently, and resolved it using custom domains similarly as just https://github.com/hashicorp/terraform-provider-google/issues/5528#issuecomment-953184386 mentioned.

Here is the cherry-picked code in my scripts. Note that I didn’t deploy a dummy Cloud Run service to fix the domain: deployed only the final ESPv2 instance after the Cloud Entpoints service has been deployed successfully.

resource "google_endpoints_service" "openapi_service" {
  service_name   = var.endpoint_name
  project        = var.project
  openapi_config = ...config with the custom domain decided before configuring...
}

resource "null_resource" "openapi_proxy_image" {
  triggers = {
    config_id = google_endpoints_service.openapi_service.config_id
  }

  # Script obtained from:
  # https://github.com/GoogleCloudPlatform/esp-v2/blob/master/docker/serverless/gcloud_build_image
  provisioner "local-exec" {
    command = <<EOS
      bash gcloud_build_image \
        -c ${google_endpoints_service.openapi_service.config_id} \
        -s ${var.endpoint_name} \
        -p ${var.project} \
        -v ${var.espv2_version}
    EOS
  }
}

resource "google_cloud_run_service" "endpoint" {
  template {
    spec {
      containers {
        image = format(
          "gcr.io/%s/endpoints-runtime-serverless:%s-%s-%s",
          var.project,
          var.espv2_version,
          var.endpoint_name,
          google_endpoints_service.openapi_service.config_id,
        )
        ...
      }
      ...
    }
    ...
  }
  ...
  depends_on = [null_resource.openapi_proxy_image]
}

resource "google_cloud_run_domain_mapping" "endpoint" {
  location = var.region
  name     = var.endpoint_name
  metadata {
    namespace = var.project
  }
  spec {
    route_name = google_cloud_run_service.endpoint.name
  }
}

resource "google_dns_record_set" "endpoint" {
  name         = "${var.endpoint_name}."
  managed_zone = var.dns_zone
  type         = "CNAME"
  ttl          = 300
  rrdatas      = ["ghs.googlehosted.com."]
}

Nope, there’s no step closer to a solution, and the circular dependency is still a problem. The problem is still the same: the cloud run documentation requires overwriting a previously deployed ESP container which introduces a circular dependency which terraform can’t handle.