Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

terraform plan errors when the provider's default project is unknown during plan #16133

Open
queeno opened this issue Oct 5, 2023 · 8 comments · May be fixed by #16135
Open

terraform plan errors when the provider's default project is unknown during plan #16133

queeno opened this issue Oct 5, 2023 · 8 comments · May be fixed by #16135

Comments

@queeno
Copy link

queeno commented Oct 5, 2023

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 plan -v
Terraform v1.6.0
on darwin_arm64
+ provider registry.terraform.io/hashicorp/google v5.0.0
+ provider registry.terraform.io/hashicorp/random v3.5.1

Affected Resource(s)

  • google_service_account

Terraform Configuration Files

provider "google" {}

provider "google" {
  alias = "test_project"
  project = google_project.test.project_id
}

resource "random_string" "string" {
  length = "6"
}

resource "google_project" "test" {
  name = "my-test-project"
  project_id = "my-test-project-${random_string.string.result}"
  org_id = "123456789"
}

resource "google_service_account" "test" {
  provider = google.test_project
  display_name = "test-service-account"
  account_id = "test-service-account"
}

Debug Output

TF plan output

Expected Behavior

A plan should have been created.

Actual Behavior

The following error is observed:

╷
│ Error: 1 error occurred:
│       * Failed to retrieve project, pid: , err: project: required field is not set
│
│
│
│   with google_service_account.test,
│   on project.tf line 26, in resource "google_service_account" "test":
│   26: resource "google_service_account" "test" {
│

Steps to Reproduce

  1. terraform plan
@queeno queeno added the bug label Oct 5, 2023
@github-actions github-actions bot added forward/review In review; remove label to forward service/iam-serviceaccount labels Oct 5, 2023
@edwardmedia edwardmedia self-assigned this Oct 5, 2023
@edwardmedia
Copy link
Contributor

edwardmedia commented Oct 5, 2023

@queeno in below config, do you intend to set provider?

resource "google_service_account" "test" {
  provider = google.test_project.      <------ project or provider?
  display_name = "test-service-account"
  account_id = "test-service-account"
}

queeno pushed a commit to queeno/terraform-provider-google that referenced this issue Oct 5, 2023
The DefaultProviderProject, DefaultProviderRegion and
DefaultProviderZone funcs set respectively the project, region and zone
in a diff if one is provided, unless they fetch the defaults from config.
However, at times, these value may not be available during a plan, as
they are dynamically computed at apply time.
We should avoid throwing an error if this is the case, but rather set
an empty value in the diff.

Resolves hashicorp#16133
@queeno
Copy link
Author

queeno commented Oct 5, 2023

@edwardmedia I intend to set the provider
This example might not make much sense, but in my use case, the google_service_account resource is part of a separate module using the "test_project" as default provider.

@shuyama1 shuyama1 removed the forward/review In review; remove label to forward label Oct 5, 2023
@rileykarson rileykarson added this to the Post-5.0.0 milestone Oct 5, 2023
@rileykarson rileykarson changed the title google_service_account fails when the provider's project is unknown during plan terraform plan errors when the provider's default project is unknown during plan Oct 5, 2023
@rileykarson
Copy link
Collaborator

We may want to guard this on a setting- with the current 5.0.0 behaviour as strict mode and a mode without errors as a relaxed mode. Which we default to is a bit of an open question given 5.0.0 is strict, so 5.X.0 could preserve that as the default or switch to relaxed mode. I'll gather some opinions from folks.

@queeno
Copy link
Author

queeno commented Oct 6, 2023

It appears that not all resources enforce this 'strict' mode. I've noticed that, out of 706 resources, only 312 seem to include the provider check. A list of non-supported resources is available here

I only realised because this check was introduced in 5.0.0 on the google_service_account resource. For example, the google_storage_bucket resource doesn't support this check.

I'd argue that, would we want to enforce a 'strict' mode on plan, we should make sure that the check is run on all resources.

Furthermore, I'm also wondering what the benefit of a 'strict' mode would be.

  • Do we want to avoid resources being provisioned in an unexpected project? - should the Google provider's project parameter be compulsory rather than optional?
  • Do we want to avoid the terraform apply failing because of unset project? - can we check whether the provider's project is set, but to be generated at apply time vs totally unset?

@NickElliot
Copy link
Collaborator

NickElliot commented Oct 6, 2023

To explain part of this as the one who implemented the change: the resources without the defaultprovider/region/zone displays were those that do not support using system default values on the project field or for which project was not a part of the schema. There was some false positives in making the list of resources to not apply including it to (google_storage_bucket being one of the only I can see going down the list of handwritten resources without it included), but this change to support displaying default provider values at plan-time is intended as universally reaching (within the mentioned conditions).

@rileykarson
Copy link
Collaborator

rileykarson commented Oct 6, 2023

Do we want to avoid resources being provisioned in an unexpected project?
Do we want to avoid the terraform apply failing because of unset project?

Yes to both! The change was made to help make plans more explicit about resources were going, and to improve the validation of users' configurations at plan time.

can we check whether the provider's project is set, but to be generated at apply time vs totally unset?

I believe we can reliably check this at the resource level, but not at the provider level where both unknown and unset are considered the same value. That's where guarding behind a flag could help, unless we can gather more information. For the majority of configurations where provider default projects are known we can move project validation up to plan time, and users who are using providers whose attributes are determined mid-apply could ignore that validation.

We didn't capture that flow correctly- I knew it was possible, having worked with the Kubernetes provider and GKE resources within a single config, but didn't think it would be relevant for this change.

We'll do some investigation and see if we can find a way to detect unknown values on the provider, and investigate a flag or alternative if we can't.

I only realised because this check was introduced in 5.0.0 on the google_service_account resource. For example, the google_storage_bucket resource doesn't support this check.

google_storage_bucket's project field is optional, unlike other resources' which is optional at the resource level but mandatory through either the resource or project. google_storage_bucket do need a project at creation, but can be imported without one as their Get method is just based on the globally unique bucket name.

Organization-level resources (google_access_context_manager_*, google_apigee_* etc) don't use any provider defaults, as they're generally global and organizations are above projects in the resource hierarchy.

There are similar complications throughout other resources that mean this check can't be universal. That's not a guarantee that we applied it to every possible resource, but I don't think we'd reliably be able to promise literally every resource behaved as expected (particularly because backfilling resources we missed will need to happen in major versions).

@markti
Copy link

markti commented Jan 15, 2024

I am getting all kinds of pain when I do something similar. but I do this:

resource "google_service_account" "cluster" { project = google_project.main.id account_id = "sa-gke-${var.application_name}-${var.environment_name}-${random_string.project_id.result}" display_name = "sa-gke-${var.application_name}-${var.environment_name}-${random_string.project_id.result}" }

I also create the project in my root module an I want to create this service account within the context of that project that is created within the current module (hence the reference to the project resource.

I get this very strange error:

<p><b>404.</b> <ins>That’s an error.</ins> │ <p>The requested URL <code>/v1/projects/projects/MY_PROJECT_ID/serviceAccounts?alt=json&amp;prettyPrint=false</code> was not found on this server. <ins>That’s all we know.</ins>

Seems like the project attribute of the the 'google_service_account' resource type is not building the correct path to the API it's calling. Not sure why.

@oscar-b
Copy link

oscar-b commented Apr 3, 2024

@rileykarson @NickElliot I'm seeing the same issues after upgrading to v5, using basically something like the below. What's the proper way to provision projects like this, as this doesn't seem to be "the way"?

resource "random_integer" "main" {
  min = 1
  max = 99999
}

locals {
  project_slug = "test"
  project_id = "${local.project_slug}-${random_integer.main.id}"
}

resource "google_project" "main" {
  project_id          = local.project_id
}

resource "google_project_service" "serviceusage-api" {
  service            = "serviceusage.googleapis.com"
  project            = local.project_id
  disable_on_destroy = false

  depends_on = [
    google_project.main
  ]
}

provider "google" {
  project                                       = local.project_id
}

https://cloud.google.com/docs/terraform/best-practices-for-terraform#randomize

@c2thorn c2thorn removed this from the Post-5.0.0 milestone May 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants