Skip to content

Commit 9be2b54

Browse files
Add ephemeral google_client_config resource (#15099) (#10975)
[upstream:f6729dbcd82096cfe94668197b5accf0027ddaa3] Signed-off-by: Modular Magician <[email protected]>
1 parent 2252591 commit 9be2b54

File tree

8 files changed

+432
-15
lines changed

8 files changed

+432
-15
lines changed

.changelog/15099.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-resource
2+
resourcemanager: added ephemeral `google_client_config` resource
3+
```

google-beta/fwprovider/data_source_provider_config_plugin_framework.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,7 @@ func (d *GoogleProviderConfigPluginFrameworkDataSource) Read(ctx context.Context
246246
data.RequestReason = types.StringValue(d.providerConfig.RequestReason)
247247
data.RequestTimeout = types.StringValue(d.providerConfig.RequestTimeout.String())
248248

249-
lbs := make(map[string]attr.Value, len(d.providerConfig.DefaultLabels))
250-
for k, v := range d.providerConfig.DefaultLabels {
251-
lbs[k] = types.StringValue(v)
252-
}
253-
labels, di := types.MapValueFrom(ctx, types.StringType, lbs)
249+
labels, di := types.MapValueFrom(ctx, types.StringType, d.providerConfig.DefaultLabels)
254250
if di.HasError() {
255251
resp.Diagnostics.Append(di...)
256252
}

google-beta/fwprovider/framework_provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,7 @@ func (p *FrameworkProvider) Functions(_ context.Context) []func() function.Funct
13581358
// EphemeralResources defines the resources that are of ephemeral type implemented in the provider.
13591359
func (p *FrameworkProvider) EphemeralResources(_ context.Context) []func() ephemeral.EphemeralResource {
13601360
return []func() ephemeral.EphemeralResource{
1361+
resourcemanager.GoogleEphemeralClientConfig,
13611362
resourcemanager.GoogleEphemeralServiceAccountAccessToken,
13621363
resourcemanager.GoogleEphemeralServiceAccountIdToken,
13631364
resourcemanager.GoogleEphemeralServiceAccountJwt,

google-beta/services/resourcemanager/data_source_google_client_config.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,7 @@ func (d *GoogleClientConfigDataSource) Read(ctx context.Context, req datasource.
139139
data.Region = types.StringValue(d.providerConfig.Region)
140140
data.Zone = types.StringValue(d.providerConfig.Zone)
141141

142-
// Convert default labels from SDK type system to plugin-framework data type
143-
m := map[string]*string{}
144-
for k, v := range d.providerConfig.DefaultLabels {
145-
// m[k] = types.StringValue(v)
146-
val := v
147-
m[k] = &val
148-
}
149-
dls, diags := types.MapValueFrom(ctx, types.StringType, m)
142+
dls, diags := types.MapValueFrom(ctx, types.StringType, d.providerConfig.DefaultLabels)
150143
resp.Diagnostics.Append(diags...)
151144
if resp.Diagnostics.HasError() {
152145
return
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
// ----------------------------------------------------------------------------
4+
//
5+
// *** AUTO GENERATED CODE *** Type: Handwritten ***
6+
//
7+
// ----------------------------------------------------------------------------
8+
//
9+
// This code is generated by Magic Modules using the following:
10+
//
11+
// Source file: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_client_config.go
12+
//
13+
// DO NOT EDIT this file directly. Any changes made to this file will be
14+
// overwritten during the next generation cycle.
15+
//
16+
// ----------------------------------------------------------------------------
17+
package resourcemanager
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
24+
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
25+
"github.com/hashicorp/terraform-plugin-framework/types"
26+
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
27+
)
28+
29+
// Ensure the ephemeral resource satisfies the expected interfaces.
30+
var (
31+
_ ephemeral.EphemeralResource = &GoogleClientConfigEphemeralResource{}
32+
_ ephemeral.EphemeralResourceWithConfigure = &GoogleClientConfigEphemeralResource{}
33+
)
34+
35+
func GoogleEphemeralClientConfig() ephemeral.EphemeralResource {
36+
return &GoogleClientConfigEphemeralResource{}
37+
}
38+
39+
type GoogleClientConfigEphemeralResource struct {
40+
providerConfig *transport_tpg.Config
41+
}
42+
43+
type GoogleClientConfigEphemeralModel struct {
44+
// Id could/should be removed in future as it's not necessary in the plugin framework
45+
// https://github.com/hashicorp/terraform-plugin-testing/issues/84
46+
Id types.String `tfsdk:"id"`
47+
Project types.String `tfsdk:"project"`
48+
Region types.String `tfsdk:"region"`
49+
Zone types.String `tfsdk:"zone"`
50+
AccessToken types.String `tfsdk:"access_token"`
51+
DefaultLabels types.Map `tfsdk:"default_labels"`
52+
}
53+
54+
func (e *GoogleClientConfigEphemeralResource) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
55+
resp.TypeName = req.ProviderTypeName + "_client_config"
56+
}
57+
58+
func (e *GoogleClientConfigEphemeralResource) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) {
59+
60+
resp.Schema = schema.Schema{
61+
62+
Description: "Use this ephemeral resource to access the configuration of the Google Cloud provider.",
63+
MarkdownDescription: "Use this ephemeral resource to access the configuration of the Google Cloud provider.",
64+
Attributes: map[string]schema.Attribute{
65+
"id": schema.StringAttribute{
66+
Computed: true,
67+
Description: "The ID of this ephemeral resource in Terraform state. It is created in a projects/{{project}}/regions/{{region}}/zones/{{zone}} format and is NOT used by the ephemeral resource in requests to Google APIs.",
68+
MarkdownDescription: "The ID of this ephemeral resource in Terraform state. It is created in a projects/{{project}}/regions/{{region}}/zones/{{zone}} format and is NOT used by the ephemeral resource in requests to Google APIs.",
69+
},
70+
"project": schema.StringAttribute{
71+
Description: "The ID of the project to apply any resources to.",
72+
MarkdownDescription: "The ID of the project to apply any resources to.",
73+
Computed: true,
74+
},
75+
"region": schema.StringAttribute{
76+
Description: "The region to operate under.",
77+
MarkdownDescription: "The region to operate under.",
78+
Computed: true,
79+
},
80+
"zone": schema.StringAttribute{
81+
Description: "The zone to operate under.",
82+
MarkdownDescription: "The zone to operate under.",
83+
Computed: true,
84+
},
85+
"access_token": schema.StringAttribute{
86+
Description: "The OAuth2 access token used by the client to authenticate against the Google Cloud API.",
87+
MarkdownDescription: "The OAuth2 access token used by the client to authenticate against the Google Cloud API.",
88+
Computed: true,
89+
Sensitive: true,
90+
},
91+
"default_labels": schema.MapAttribute{
92+
Description: "The default labels configured on the provider.",
93+
MarkdownDescription: "The default labels configured on the provider.",
94+
Computed: true,
95+
ElementType: types.StringType,
96+
},
97+
},
98+
}
99+
}
100+
101+
func (e *GoogleClientConfigEphemeralResource) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) {
102+
// Prevent panic if the provider has not been configured.
103+
if req.ProviderData == nil {
104+
return
105+
}
106+
107+
p, ok := req.ProviderData.(*transport_tpg.Config)
108+
if !ok {
109+
resp.Diagnostics.AddError(
110+
"Unexpected Ephemeral Resource Configure Type",
111+
fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
112+
)
113+
return
114+
}
115+
116+
// Required for accessing project, region, zone and tokenSource
117+
e.providerConfig = p
118+
}
119+
120+
func (e *GoogleClientConfigEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
121+
var data GoogleClientConfigEphemeralModel
122+
123+
// Read Terraform configuration data into the model
124+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
125+
if resp.Diagnostics.HasError() {
126+
return
127+
}
128+
129+
data.Id = types.StringValue(fmt.Sprintf("projects/%s/regions/%s/zones/%s", e.providerConfig.Project, e.providerConfig.Region, e.providerConfig.Zone))
130+
data.Project = types.StringValue(e.providerConfig.Project)
131+
data.Region = types.StringValue(e.providerConfig.Region)
132+
data.Zone = types.StringValue(e.providerConfig.Zone)
133+
134+
dls, diags := types.MapValueFrom(ctx, types.StringType, e.providerConfig.DefaultLabels)
135+
resp.Diagnostics.Append(diags...)
136+
if resp.Diagnostics.HasError() {
137+
return
138+
}
139+
140+
data.DefaultLabels = dls
141+
142+
token, err := e.providerConfig.TokenSource.Token()
143+
if err != nil {
144+
resp.Diagnostics.AddError("Error setting access_token", err.Error())
145+
return
146+
}
147+
data.AccessToken = types.StringValue(token.AccessToken)
148+
149+
// Save data into ephemeral resource result
150+
resp.Diagnostics.Append(resp.Result.Set(ctx, &data)...)
151+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
// ----------------------------------------------------------------------------
4+
//
5+
// *** AUTO GENERATED CODE *** Type: Handwritten ***
6+
//
7+
// ----------------------------------------------------------------------------
8+
//
9+
// This code is generated by Magic Modules using the following:
10+
//
11+
// Source file: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_client_config_test.go
12+
//
13+
// DO NOT EDIT this file directly. Any changes made to this file will be
14+
// overwritten during the next generation cycle.
15+
//
16+
// ----------------------------------------------------------------------------
17+
package resourcemanager_test
18+
19+
import (
20+
"regexp"
21+
"testing"
22+
23+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
24+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
25+
)
26+
27+
func TestAccEphemeralGoogleClientConfig_basic(t *testing.T) {
28+
t.Parallel()
29+
30+
resource.Test(t, resource.TestCase{
31+
PreCheck: func() { acctest.AccTestPreCheck(t) },
32+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
33+
Steps: []resource.TestStep{
34+
{
35+
// Note: For ephemeral resources, we can't directly check attributes
36+
// since they don't persist in state. Instead, we verify the configuration
37+
// compiles and runs without error.
38+
Config: testAccCheckEphemeralGoogleClientConfig_basic,
39+
},
40+
},
41+
})
42+
}
43+
44+
func TestAccEphemeralGoogleClientConfig_omitLocation(t *testing.T) {
45+
t.Setenv("GOOGLE_REGION", "")
46+
t.Setenv("GOOGLE_ZONE", "")
47+
48+
resource.Test(t, resource.TestCase{
49+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
50+
Steps: []resource.TestStep{
51+
{
52+
// Note: For ephemeral resources, we can't directly check attributes
53+
// since they don't persist in state. Instead, we verify the configuration
54+
// compiles and runs without error.
55+
Config: testAccCheckEphemeralGoogleClientConfig_basic,
56+
},
57+
},
58+
})
59+
}
60+
61+
func TestAccEphemeralGoogleClientConfig_invalidCredentials(t *testing.T) {
62+
badCreds := acctest.GenerateFakeCredentialsJson("test")
63+
t.Setenv("GOOGLE_CREDENTIALS", badCreds)
64+
65+
resource.Test(t, resource.TestCase{
66+
PreCheck: func() { acctest.AccTestPreCheck(t) },
67+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
68+
Steps: []resource.TestStep{
69+
{
70+
Config: testAccCheckEphemeralGoogleClientConfig_basic,
71+
ExpectError: regexp.MustCompile("Error setting access_token"),
72+
},
73+
},
74+
})
75+
}
76+
77+
func TestAccEphemeralGoogleClientConfig_usedInProvider(t *testing.T) {
78+
t.Parallel()
79+
80+
resource.Test(t, resource.TestCase{
81+
PreCheck: func() { acctest.AccTestPreCheck(t) },
82+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
83+
Steps: []resource.TestStep{
84+
{
85+
Config: testAccCheckEphemeralGoogleClientConfig_usedInProvider,
86+
Check: resource.ComposeTestCheckFunc(
87+
// Verify that the ephemeral resource can be used to configure a provider
88+
// and that the provider works correctly
89+
resource.TestCheckResourceAttrSet("data.google_client_openid_userinfo.me", "email"),
90+
),
91+
},
92+
},
93+
})
94+
}
95+
96+
const testAccCheckEphemeralGoogleClientConfig_basic = `
97+
provider "google" {
98+
default_labels = {
99+
default_key = "default_value"
100+
}
101+
}
102+
103+
ephemeral "google_client_config" "current" { }
104+
`
105+
106+
const testAccCheckEphemeralGoogleClientConfig_usedInProvider = `
107+
provider "google" {
108+
default_labels = {
109+
default_key = "default_value"
110+
}
111+
}
112+
113+
ephemeral "google_client_config" "current" { }
114+
115+
provider "google" {
116+
alias = "ephemeral_configured"
117+
access_token = ephemeral.google_client_config.current.access_token
118+
project = ephemeral.google_client_config.current.project
119+
region = ephemeral.google_client_config.current.region
120+
zone = ephemeral.google_client_config.current.zone
121+
}
122+
123+
data "google_client_openid_userinfo" "me" {
124+
provider = google.ephemeral_configured
125+
}
126+
`

0 commit comments

Comments
 (0)