0

I have the following terraform resources in a file

resource "google_project_service" "cloud_resource_manager" {
  project = var.tf_project_id
  service = "cloudresourcemanager.googleapis.com"
  disable_dependent_services = true
}

resource "google_project_service" "artifact_registry" {
  project = var.tf_project_id
  service = "artifactregistry.googleapis.com"
  disable_dependent_services = true
  depends_on = [google_project_service.cloud_resource_manager]
}

resource "google_artifact_registry_repository" "el" {
  provider = google-beta
  project = var.tf_project_id
  location = var.region
  repository_id = "el"
  description = "Repository for extract/load docker images"
  format = "DOCKER"
  depends_on = [google_project_service.artifact_registry]
}

However, when I run terraform plan, I get this

Terraform will perform the following actions:

  # google_artifact_registry_repository.el will be created
  + resource "google_artifact_registry_repository" "el" {
      + create_time   = (known after apply)
      + description   = "Repository for extract/load docker images"
      + format        = "DOCKER"
      + id            = (known after apply)
      + location      = "us-central1"
      + name          = (known after apply)
      + project       = "backbone-third-party-data"
      + repository_id = "el"
      + update_time   = (known after apply)
    }

  # google_project_iam_member.ingest_sa_roles["cloudscheduler.serviceAgent"] will be created
  + resource "google_project_iam_member" "ingest_sa_roles" {
      + etag    = (known after apply)
      + id      = (known after apply)
      + member  = (known after apply)
      + project = "backbone-third-party-data"
      + role    = "roles/cloudscheduler.serviceAgent"
    }

  # google_project_iam_member.ingest_sa_roles["run.invoker"] will be created
  + resource "google_project_iam_member" "ingest_sa_roles" {
      + etag    = (known after apply)
      + id      = (known after apply)
      + member  = (known after apply)
      + project = <my project id>
      + role    = "roles/run.invoker"
    }

  # google_project_service.artifact_registry will be created
  + resource "google_project_service" "artifact_registry" {
      + disable_dependent_services = true
      + disable_on_destroy         = true
      + id                         = (known after apply)
      + project                    = <my project id>
      + service                    = "artifactregistry.googleapis.com"
    }

See how google_project_service.artifact_registry is created after google_artifact_registry_repository.el. I was hoping that my depends_on in resource google_artifact_registry_repository.el would make it so the service was created first. Am I misunderstanding how depends_on works? Or does the ordering of resources listed from terraform plan not actually mean that thats the order they are created in?

Edit: when I run terraform apply it errors out with

Error 403: Cloud Resource Manager API has not been used in project 521986354168 before or it is disabled

Even though it is enabled. I think it's doing this because its running the artifact registry resource creation before creating the terraform services?

BigBoy1337
  • 4,735
  • 16
  • 70
  • 138
  • 1
    Plan output is unrelated to creation order. I don't see any reasons these resources should depend on one another, but im not that familar with gcloud. – jordanm Jun 06 '22 at 23:01
  • 2
    This is just a plan. Did you actually apply the changes? – Marcin Jun 06 '22 at 23:08
  • @Marcin see my edits. It errors out I think because the resources are being applied in the wrong order? – BigBoy1337 Jun 07 '22 at 15:22
  • there is also an implicit depends on as soon as one resource is using a output variable from another resource, afaik. – The Fool Jun 07 '22 at 15:42
  • When Terraform is running the apply step after you accept the plan it will announce the start and end of each operation as part of the output, which should appear just before the error message you saw. Does the order of operations Terraform announced there seem correct? If you're not sure, can you share that part of the output (everything that appeared after you answered `yes` to apply the plan) as part of your question? – Martin Atkins Jun 08 '22 at 19:40

2 Answers2

1

I don't think that it will be possible to enable this particular API this way, as google_project_service resource depends on Resource Manager API (and maybe also on Service Usage API?) being enabled. So you could either enable those manually or use null_resource with local-exec provisioner to do it automatically:

resource "null_resource" "enable_cloudresourcesmanager_api" {
  provisioner "local-exec" {
    command = "gcloud services enable cloudresourcesmanager.googleapis.com cloudresourcemanager.googleapis.com --project ${var.project_id}"
  }
}

Another issue you might find is that enabling an API takes some time, depending on a service. So sometimes even though your resources depend on a resource enabling an API, you will still get the same error message. Then you can just reapply your configuration and as an API had time to initialize, second apply will work. In some cases this is good enough, but if you are building a reusable module you might want to avoid those reapplies. Then you can use time_sleep resources to wait for API initialization:

resource "time_sleep" "wait_for_cloudresourcemanager_api" {
  depends_on = [null_resource.enable_cloudresourcesmanager_api]
  # or: depends_on = [google_project_service.some_other_api]

  create_duration = "30s"
}
0

A terraform plan output does not reflect actual execution order, the dependency depends_on = [google_project_service.cloud_resource_manager] is thus correct in my opition.

The error you are getting during the terraform apply execution is due to GCP API activation issues. This answer explains how API activation can be orchestrated correctly: https://stackoverflow.com/a/76721580/3062971

vpgcloud
  • 1,294
  • 2
  • 10
  • 19