Users may want to activate many services simultaneously within a single Terraform config. The google_project_service.service
field only supports a single value, but Terraform itself provides list iteration with for_each.
For example:
variable "services" {
type = list(string)
}
resource "google_project_service" "services" {
for_each = toset(var.services)
project = "my-project"
service = each.value
}
For a more robust example, Google recommends the project_services module. The project_services
module simplifies configuring multiple services on a project at once as shown in this example.
The service management API called by the google_project_service resource uses request rate quota on the project of the account used to call the API (i.e. against the Terraform credentials) by default. That project (or a fixed billing_project
) may exceed your request rate quota in larger configurations. google_project_service
batches multiple changes into single requests when possible, see the batching
reference documentation for details.
Minimizing the number of total resources in root modules will help maximize the provider’s ability to batch requests. Oversized root modules slow Terraform’s execution time and can cause same-type requests to miss the batch window set by batching.send_after. See Google’s guidance on root modules.
Users may run into issues when activating a service with google_project_service
and immediately using the service in another resource. The most common error when doing so will look like:
Error: Error creating <Resource>: googleapi: Error 403: <Service> API has not been used in project <Project> before or it is disabled.
Activating a service is eventually consistent in GCP. Terraform attempts to mitigate this in google_project_service
by waiting for the activation API’s long-running operation to finish and verifying that the service appears in a list of activated services. Despite these checks, service activation is not guaranteed by the time the google_project_service
resource is done provisioning.
At the time of writing, there is no way for the provider to completely verify service activation. The time before google_project_service
returns successfully may vary depending on the service, GCP-internal caching, and other circumstances. In particular, just-created projects may experience longer service activation times. Further mitigations users can try are detailed below.
If you are experiencing significantly long activation time with a specific service, it would be best to file an issue in that service’s public issue tracker or speak to your customer representative.
A common way to deal with eventual consistency with Terraform is to implement a sleep in between resources.
The time provider offers a time_sleep resource. You can use the create_duration
field to provide a sleep duration.
resource "google_project" "my_project" {
name = "foo-bar-baz"
project_id = "foo-bar-baz-test"
org_id = var.organization_id
billing_account = var.billing_account_id
}
resource "time_sleep" "wait_30_seconds" {
depends_on = [google_project.my_project]
create_duration = "30s"
}
resource "google_project_service" "my_service" {
project = google_project.my_project.id
service = "firebase.googleapis.com"
disable_dependent_services = true
depends_on = [time_sleep.wait_30_seconds]
}
Terraform provides the local-exec provisioner to invoke a local executable after resource creation. Depending on the machine running Terraform, you may invoke some command to sleep for a duration.
resource "google_project" "my_project" {
name = "foo-bar-baz"
project_id = "foo-bar-baz-test"
org_id = var.organization_id
billing_account = var.billing_account_id
}
resource "null_resource" "delay" {
provisioner "local-exec" {
command = "sleep 60"
}
triggers = {
"project" = "${google_project.my_project.id}"
}
}
resource "google_project_service" "my_service" {
project = google_project.my_project.id
service = "firebase.googleapis.com"
disable_dependent_services = true
depends_on = [null_resource.delay]
}