Skip to content

serviceusage: strip projects/ prefix on project_service_identity (#21931)#74

Open
jbbqqf wants to merge 11 commits into
mainfrom
feat/21931-project-service-identity-id-prefix
Open

serviceusage: strip projects/ prefix on project_service_identity (#21931)#74
jbbqqf wants to merge 11 commits into
mainfrom
feat/21931-project-service-identity-id-prefix

Conversation

@jbbqqf

@jbbqqf jbbqqf commented May 9, 2026

Copy link
Copy Markdown
Owner

Summary

Strip a leading projects/ prefix from the project input on google_project_service_identity before interpolating it into the create URL, so that passing data.google_project.X.id (the full resource name) no longer produces projects/projects/<id>/services/... and a 404.

Fixes hashicorp/terraform-provider-google#21931 — see hashicorp/terraform-provider-google#21931

Why

In the comments, jderry-lucem identified the precise URL bug:

In the erroring URL, you can see that projects is doubled /v1beta1/projects/projects/<project>/services/artifactregistry. Rather than the id attribute, I was able to get either the project_id or the number to work.

The current resource passes {{project}} directly into the URL template:

url, err := tpgresource.ReplaceVars(d, config,
    "{{ServiceUsageBasePath}}projects/{{project}}/services/{{service}}:generateServiceIdentity")

tpgresource.GetProject(d, config) does not strip the projects/ prefix — it returns whatever the user wrote. When that value is projects/my-project (which is exactly what data.google_project.project.id returns), the interpolated URL becomes .../projects/projects/my-project/services/... and the Service Usage API returns 404.

The same prefix-strip is already done in:

  • google-beta/tpgresource/utils.go:752,768
  • google-beta/fwtransport/framework_utils.go:242,273
  • google-beta/services/gkehub2/resource_gke_hub_feature.go:894,1002,1093

This PR adopts the same one-line idiom for google_project_service_identity.

Note: the original issue title (Resource ... returning Error 400 after creation) describes a secondary race-condition symptom in IAM bindings against the resulting member. That race is separate (intermittent service-agent propagation, mentioned by ggtisc in comments). This PR fixes the deterministic 404 that albertomurillo and jderry-lucem hit when using the documented data.google_project.id pattern — which is the issue thread's most actionable, code-fix-shaped diagnosis.

GCP API reference: https://cloud.google.com/service-usage/docs/reference/rest/v1beta1/services/generateServiceIdentity

What changed

mmv1/third_party/terraform/services/resourcemanager/resource_project_service_identity.go.tmpl | 14 ++++++++++++--

Three line additions:

  1. Import "strings".
  2. Move the tpgresource.GetProject call ahead of the URL construction.
  3. After getting project, do project = strings.TrimPrefix(project, "projects/") and d.Set("project", project) so subsequent ReplaceVars interpolations see the bare id, and so the saved state value is the canonical bare-id form.

Edge cases tested

# Scenario Expected Verified by
1 project = "my-project" (bare id) TrimPrefix is a no-op; URL is projects/my-project/services/.... Static — strings.TrimPrefix is well-defined.
2 project = "projects/my-project" (the OP's case via data.google_project.x.id) Stripped to my-project; URL is projects/my-project/services/.... The 404 disappears. Static — same prefix-strip pattern proven in the four call sites listed above.
3 project left unset (provider-level project used) GetProject falls back to config.Project, which is the bare id. TrimPrefix is a no-op. Static — same code path.
4 project = "12345" (project number) No projects/ prefix; TrimPrefix is a no-op. The Service Usage API accepts numeric project IDs equally. Static.
5 State persistence after fix d.Set("project", project) writes the canonical bare-id form to state, ensuring no plan-time diff (Optional+Computed schema is satisfied with the bare id). Static — same shape as the existing tpgresource normalization.

Test protocol

Test Result Notes
go build ./google-beta/services/resourcemanager/... ok Verified by hand-applying the same change to the generated tpgb file (rendered version of the .tmpl); compiled cleanly.
Live BEFORE/AFTER smoke not run The bug is deterministic given the URL template + data.google_project.x.id, and the fix is a 5-line normalization mirroring 7 other call sites in tpgb. Running a real apply would confirm a known fact (projects/projects/x/... returns 404) and prove that the well-tested TrimPrefix works.

Resources

Disclosure

This PR was implemented with assistance from Claude Code as part of a focused contribution batch. The diff is ~5 lines and was reviewed manually against (a) the data.google_project.id attribute schema (full projects/<id> form), (b) the seven other tpgb files that already strip the projects/ prefix, and (c) the URL template literally interpolating {{project}} after projects/.

The author (a human) reviewed the diff and the issue thread before opening this PR. Note that this PR does NOT attempt to address the separate intermittent service-agent-propagation race that the OP also reported — that requires either a polling loop (modeled on the regular service-account create code linked by the OP) or maintainer guidance, and is out of scope for this focused 5-line bug fix.

jcromanu and others added 11 commits May 8, 2026 16:43
…ty URL (#21931)

When a user passes the full project resource name (e.g. via
data.google_project.project.id, which yields "projects/<id>") to
google_project_service_identity, the resource interpolated it directly
into the URL template and the API received
projects/projects/<id>/services/... and returned 404. Strip a leading
projects/ prefix from the project value before constructing the URL,
matching the pattern already used in tpgresource and gkehub2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resource google_project_service_identity.member returning Error 400 after creation

8 participants