Skip to content

Commit 8556433

Browse files
committed
2 parents 37b7e43 + dc2fd3e commit 8556433

8 files changed

Lines changed: 418 additions & 1 deletion

File tree

mmv1/products/identityplatform/Config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ properties:
378378
The allowed number of adjacent intervals that will be used for verification to avoid clock skew.
379379
- name: 'multiTenant'
380380
type: NestedObject
381+
default_from_api: true
381382
description: |
382383
Configuration related to multi-tenant functionality.
383384
custom_flatten: 'templates/terraform/custom_flatten/identity_platform_config_multi_tenant.go.tmpl'

mmv1/third_party/terraform/fwprovider/framework_provider_mmv1_resources.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ var generatedListResources = []func() list.ListResource{}
1616

1717
var handwrittenListResources = []func() list.ListResource{
1818
listResourceFunc(resourcemanager.NewGoogleServiceAccountListResource()),
19+
listResourceFunc(resourcemanager.NewGoogleProjectServiceListResource()),
1920
}

mmv1/third_party/terraform/services/identityplatform/resource_identity_platform_config_test.go

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
)
1212

1313
func TestAccIdentityPlatformConfig_update(t *testing.T) {
14-
acctest.SkipIfVcr(t)
1514
t.Parallel()
1615

1716
context := map[string]interface{}{
@@ -34,6 +33,15 @@ func TestAccIdentityPlatformConfig_update(t *testing.T) {
3433
ImportStateVerify: true,
3534
ImportStateVerifyIgnore: []string{"client.0.api_key", "client.0.firebase_subdomain"},
3635
},
36+
{
37+
Config: testAccIdentityPlatformConfig_disallowTenant(context),
38+
},
39+
{
40+
ResourceName: "google_identity_platform_config.basic",
41+
ImportState: true,
42+
ImportStateVerify: true,
43+
ImportStateVerifyIgnore: []string{"client.0.api_key", "client.0.firebase_subdomain"},
44+
},
3745
{
3846
Config: testAccIdentityPlatformConfig_update(context),
3947
},
@@ -122,6 +130,88 @@ resource "google_identity_platform_config" "basic" {
122130
allow_tenants = true
123131
default_tenant_location = "organizations/%{org_id}"
124132
}
133+
134+
depends_on = [google_project_service.identitytoolkit]
135+
}
136+
`, context)
137+
}
138+
139+
func testAccIdentityPlatformConfig_disallowTenant(context map[string]interface{}) string {
140+
return acctest.Nprintf(`
141+
resource "google_project" "basic" {
142+
project_id = "tf-test-my-project%{random_suffix}"
143+
name = "tf-test-my-project%{random_suffix}"
144+
org_id = "%{org_id}"
145+
billing_account = "%{billing_acct}"
146+
deletion_policy = "DELETE"
147+
labels = {
148+
firebase = "enabled"
149+
}
150+
}
151+
152+
resource "google_project_service" "identitytoolkit" {
153+
project = google_project.basic.project_id
154+
service = "identitytoolkit.googleapis.com"
155+
}
156+
157+
resource "google_identity_platform_config" "basic" {
158+
project = google_project.basic.project_id
159+
autodelete_anonymous_users = true
160+
sign_in {
161+
allow_duplicate_emails = true
162+
163+
anonymous {
164+
enabled = true
165+
}
166+
email {
167+
enabled = true
168+
password_required = false
169+
}
170+
phone_number {
171+
enabled = true
172+
test_phone_numbers = {
173+
"+11231231234" = "000000"
174+
}
175+
}
176+
}
177+
sms_region_config {
178+
allow_by_default {
179+
disallowed_regions = [
180+
"CA",
181+
"US",
182+
]
183+
}
184+
}
185+
186+
client {
187+
permissions {
188+
disabled_user_deletion = true
189+
disabled_user_signup = true
190+
}
191+
}
192+
193+
mfa {
194+
enabled_providers = ["PHONE_SMS"]
195+
provider_configs {
196+
state = "ENABLED"
197+
totp_provider_config {
198+
adjacent_intervals = 3
199+
}
200+
}
201+
state = "ENABLED"
202+
}
203+
204+
monitoring {
205+
request_logging {
206+
enabled = true
207+
}
208+
}
209+
210+
multi_tenant {
211+
allow_tenants = false
212+
}
213+
214+
depends_on = [google_project_service.identitytoolkit]
125215
}
126216
`, context)
127217
}
@@ -188,6 +278,8 @@ resource "google_identity_platform_config" "basic" {
188278
enabled = false
189279
}
190280
}
281+
282+
depends_on = [google_project_service.identitytoolkit]
191283
}
192284
`, context)
193285
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) IBM Corp. 2014, 2026
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package resourcemanager
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/hashicorp/terraform-plugin-framework/diag"
11+
"github.com/hashicorp/terraform-plugin-framework/list"
12+
"github.com/hashicorp/terraform-plugin-framework/types"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
14+
15+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
16+
)
17+
18+
type GoogleProjectServiceListResource struct {
19+
tpgresource.ListResourceMetadata
20+
}
21+
22+
// GoogleProjectServiceListModel matches [ListResourceMetadata.ListConfigFields] (tfsdk names and types).
23+
type GoogleProjectServiceListModel struct {
24+
Project types.String `tfsdk:"project"`
25+
}
26+
27+
func NewGoogleProjectServiceListResource() list.ListResource {
28+
listR := &GoogleProjectServiceListResource{}
29+
listR.TypeName = "google_project_service"
30+
listR.SDKv2Resource = ResourceGoogleProjectService()
31+
listR.ListConfigFields = []tpgresource.ListConfigField{{Name: "project", Kind: tpgresource.ListConfigKindString, Optional: true}}
32+
return listR
33+
}
34+
35+
func (listR *GoogleProjectServiceListResource) List(ctx context.Context, listReq list.ListRequest, stream *list.ListResultsStream) {
36+
var data GoogleProjectServiceListModel
37+
diags := listReq.Config.Get(ctx, &data)
38+
if diags.HasError() {
39+
stream.Results = list.ListResultsStreamDiagnostics(diags)
40+
return
41+
}
42+
if listR.Client == nil {
43+
diags = append(diags, diag.NewErrorDiagnostic(
44+
"Provider not configured",
45+
"The Google provider client is not available; ensure the provider is configured (e.g. credentials and default project).",
46+
))
47+
stream.Results = list.ListResultsStreamDiagnostics(diags)
48+
return
49+
}
50+
project := tpgresource.GetResourceNameFromSelfLink(listR.GetProject(data.Project))
51+
52+
tempData := ResourceGoogleProjectService().Data(&terraform.InstanceState{})
53+
if err := tempData.Set("project", project); err != nil {
54+
diags.AddError("Config Error", fmt.Sprintf("Error setting project: %s", err))
55+
stream.Results = list.ListResultsStreamDiagnostics(diags)
56+
return
57+
}
58+
59+
// BatchRequestReadServices (serviceusage_batching.go) calls ListCurrentlyEnabledServices
60+
// in resource_google_project.go, which uses Service Usage Services.List(...).Pages(...)
61+
servicesRaw, err := BatchRequestReadServices(project, tempData, listR.Client)
62+
if err != nil {
63+
diags.AddError("API Error", err.Error())
64+
stream.Results = list.ListResultsStreamDiagnostics(diags)
65+
return
66+
}
67+
servicesList := servicesRaw.(map[string]struct{})
68+
69+
stream.Results = func(push func(list.ListResult) bool) {
70+
for serviceName := range servicesList {
71+
rd := ResourceGoogleProjectService().Data(&terraform.InstanceState{})
72+
if err := rd.Set("project", project); err != nil {
73+
diags.AddError("Config Error", fmt.Sprintf("Error setting project: %s", err))
74+
stream.Results = list.ListResultsStreamDiagnostics(diags)
75+
return
76+
}
77+
if err := rd.Set("service", serviceName); err != nil {
78+
diags.AddError("Config Error", fmt.Sprintf("Error setting service: %s", err))
79+
stream.Results = list.ListResultsStreamDiagnostics(diags)
80+
return
81+
}
82+
rd.SetId(fmt.Sprintf("%s/%s", project, serviceName))
83+
84+
result := listReq.NewListResult(ctx)
85+
if err := listR.SetResult(ctx, listReq.IncludeResource, &result, rd, "service"); err != nil {
86+
diags.AddError("Schema Error", err.Error())
87+
stream.Results = list.ListResultsStreamDiagnostics(diags)
88+
return
89+
}
90+
if !push(result) {
91+
stream.Results = list.ListResultsStreamDiagnostics(diags)
92+
return
93+
}
94+
}
95+
stream.Results = list.ListResultsStreamDiagnostics(diags)
96+
}
97+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package resourcemanager_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
9+
"github.com/hashicorp/terraform-plugin-testing/querycheck"
10+
"github.com/hashicorp/terraform-plugin-testing/tfversion"
11+
12+
"github.com/hashicorp/terraform-provider-google/google/acctest"
13+
"github.com/hashicorp/terraform-provider-google/google/envvar"
14+
)
15+
16+
// TestAccProjectServiceListResource_queryIdentity lists enabled project services via the
17+
// provider list resource API and asserts a known identity appears (Terraform 1.14+).
18+
func TestAccProjectServiceListResource_queryIdentity(t *testing.T) {
19+
t.Parallel()
20+
21+
project := envvar.GetTestProjectFromEnv()
22+
service := "iam.googleapis.com"
23+
24+
acctest.VcrTest(t, resource.TestCase{
25+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
26+
tfversion.SkipBelow(tfversion.Version1_14_0),
27+
},
28+
PreCheck: func() { acctest.AccTestPreCheck(t) },
29+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
30+
Steps: []resource.TestStep{
31+
{
32+
Config: testAccProjectServiceList_prereq(project, service),
33+
Check: resource.ComposeTestCheckFunc(
34+
resource.TestCheckResourceAttr("google_project_service.prereq", "service", service),
35+
resource.TestCheckResourceAttr("google_project_service.prereq", "project", project),
36+
),
37+
},
38+
{
39+
Query: true,
40+
Config: testAccProjectServiceListQuery(project),
41+
QueryResultChecks: []querycheck.QueryResultCheck{
42+
querycheck.ExpectIdentity("google_project_service.all_in_project", map[string]knownvalue.Check{
43+
"service": knownvalue.StringExact(service),
44+
"project": knownvalue.StringExact(project),
45+
}),
46+
querycheck.ExpectLengthAtLeast("google_project_service.all_in_project", 1),
47+
},
48+
},
49+
},
50+
})
51+
}
52+
53+
func testAccProjectServiceList_prereq(project, service string) string {
54+
return fmt.Sprintf(`
55+
resource "google_project_service" "prereq" {
56+
project = %q
57+
service = %q
58+
}
59+
`, project, service)
60+
}
61+
62+
func testAccProjectServiceListQuery(project string) string {
63+
return fmt.Sprintf(`
64+
list "google_project_service" "all_in_project" {
65+
provider = google
66+
67+
config {
68+
project = %q
69+
}
70+
}
71+
`, project)
72+
}

0 commit comments

Comments
 (0)