Skip to content

Commit 4362e23

Browse files
Plugin Framework feature branch merge (#14977) (#10602)
[upstream:fd62c38302087df4545b6a3496df8aef38a9e02a] Signed-off-by: Modular Magician <[email protected]>
1 parent f4cc6fd commit 4362e23

29 files changed

+3516
-1027
lines changed

.changelog/14977.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
```release-note:breaking-change
2+
storage: added validation requiring the `topic` field to be in the form "projects/<project>/topics/<topic>" in `google_storage_notification`
3+
```
4+
```release-note:breaking-change
5+
apigee: changed `certs_info` field in `google_apigee_keystores_aliases_key_cert_file` to be output-only
6+
```
7+
```release-note:breaking-change
8+
apigee: migrated `google_apigee_keystores_aliases_key_cert_file` to the plugin framework
9+
```
10+
```release-note:breaking-change
11+
storage: migrated `google_storage_notification` to the plugin framework
12+
```

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require (
2020
github.com/hashicorp/go-version v1.7.0
2121
github.com/hashicorp/terraform-json v0.25.0
2222
github.com/hashicorp/terraform-plugin-framework v1.15.0
23+
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0
2324
github.com/hashicorp/terraform-plugin-framework-validators v0.9.0
2425
github.com/hashicorp/terraform-plugin-go v0.28.0
2526
github.com/hashicorp/terraform-plugin-log v0.9.0

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,20 @@ github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3q
162162
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
163163
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
164164
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
165+
github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8l+uRmZHj64=
166+
github.com/hashicorp/terraform-exec v0.22.0/go.mod h1:bjVbsncaeh8jVdhttWYZuBGj21FcYw6Ia/XfHcNO7lQ=
165167
github.com/hashicorp/terraform-exec v0.23.0 h1:MUiBM1s0CNlRFsCLJuM5wXZrzA3MnPYEsiXmzATMW/I=
166168
github.com/hashicorp/terraform-exec v0.23.0/go.mod h1:mA+qnx1R8eePycfwKkCRk3Wy65mwInvlpAeOwmA7vlY=
169+
github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q=
170+
github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow=
167171
github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGoxseG1hLhoQ=
168172
github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc=
173+
github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw=
174+
github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU=
169175
github.com/hashicorp/terraform-plugin-framework v1.15.0 h1:LQ2rsOfmDLxcn5EeIwdXFtr03FVsNktbbBci8cOKdb4=
170176
github.com/hashicorp/terraform-plugin-framework v1.15.0/go.mod h1:hxrNI/GY32KPISpWqlCoTLM9JZsGH3CyYlir09bD/fI=
177+
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0 h1:I/N0g/eLZ1ZkLZXUQ0oRSXa8YG/EF0CEuQP1wXdrzKw=
178+
github.com/hashicorp/terraform-plugin-framework-timeouts v0.5.0/go.mod h1:t339KhmxnaF4SzdpxmqW8HnQBHVGYazwtfxU0qCs4eE=
171179
github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 h1:LYz4bXh3t7bTEydXOmPDPupRRnA480B/9+jV8yZvxBA=
172180
github.com/hashicorp/terraform-plugin-framework-validators v0.9.0/go.mod h1:+BVERsnfdlhYR2YkXMBtPnmn9UsL19U3qUtSZ+Y/5MY=
173181
github.com/hashicorp/terraform-plugin-go v0.28.0 h1:zJmu2UDwhVN0J+J20RE5huiF3XXlTYVIleaevHZgKPA=

google-beta/acctest/vcr_utils.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,18 @@ import (
3838

3939
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwprovider"
4040
tpgprovider "github.com/hashicorp/terraform-provider-google-beta/google-beta/provider"
41+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/compute"
42+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/pubsublite"
43+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/sql"
4144
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
4245
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
4346

4447
"github.com/dnaeon/go-vcr/cassette"
4548
"github.com/dnaeon/go-vcr/recorder"
4649

4750
"github.com/hashicorp/terraform-plugin-framework/datasource"
51+
fwResource "github.com/hashicorp/terraform-plugin-framework/resource"
52+
4853
fwDiags "github.com/hashicorp/terraform-plugin-framework/diag"
4954
"github.com/hashicorp/terraform-plugin-framework/provider"
5055
"github.com/hashicorp/terraform-plugin-log/tflog"
@@ -355,9 +360,16 @@ func (p *frameworkTestProvider) Configure(ctx context.Context, req provider.Conf
355360
func (p *frameworkTestProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
356361
ds := p.FrameworkProvider.DataSources(ctx)
357362
ds = append(ds, fwprovider.NewGoogleProviderConfigPluginFrameworkDataSource) // google_provider_config_plugin_framework
363+
ds = append(ds, compute.NewComputeNetworkFWDataSource) // google_fw_compute_network
358364
return ds
359365
}
360366

367+
func (p *frameworkTestProvider) Resources(ctx context.Context) []func() fwResource.Resource {
368+
r := p.FrameworkProvider.Resources(ctx)
369+
r = append(r, pubsublite.NewGooglePubsubLiteReservationFWResource, sql.NewSQLUserFWResource) // google_fwprovider_pubsub_lite_reservation
370+
return r
371+
}
372+
361373
// GetSDKProvider gets the SDK provider for use in acceptance tests
362374
// If VCR is in use, the configure function is overwritten.
363375
// See usage in MuxedProviders

google-beta/fwprovider/framework_provider.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ import (
3636
"github.com/hashicorp/terraform-provider-google-beta/google-beta/functions"
3737
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwmodels"
3838
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwvalidators"
39-
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/firebase"
39+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/apigee"
4040
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/resourcemanager"
41+
42+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/firebase"
43+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/storage"
4144
"github.com/hashicorp/terraform-provider-google-beta/version"
4245

4346
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
@@ -1310,7 +1313,10 @@ func (p *FrameworkProvider) DataSources(_ context.Context) []func() datasource.D
13101313

13111314
// Resources defines the resources implemented in the provider.
13121315
func (p *FrameworkProvider) Resources(_ context.Context) []func() resource.Resource {
1313-
return nil
1316+
return []func() resource.Resource{
1317+
apigee.NewApigeeKeystoresAliasesKeyCertFileResource,
1318+
storage.NewStorageNotificationResource,
1319+
}
13141320
}
13151321

13161322
// Functions defines the provider functions implemented in the provider.

google-beta/fwresource/field_helpers.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,18 @@ import (
3333
// back to the provider's value if not given. If the provider's value is not
3434
// given, an error is returned.
3535
func GetProjectFramework(rVal, pVal types.String, diags *diag.Diagnostics) types.String {
36-
return getProjectFromFrameworkSchema("project", rVal, pVal, diags)
36+
return getProviderDefaultFromFrameworkSchema("project", rVal, pVal, diags)
3737
}
3838

39-
func getProjectFromFrameworkSchema(projectSchemaField string, rVal, pVal types.String, diags *diag.Diagnostics) types.String {
39+
func GetRegionFramework(rVal, pVal types.String, diags *diag.Diagnostics) types.String {
40+
return getProviderDefaultFromFrameworkSchema("region", rVal, pVal, diags)
41+
}
42+
43+
func GetZoneFramework(rVal, pVal types.String, diags *diag.Diagnostics) types.String {
44+
return getProviderDefaultFromFrameworkSchema("zone", rVal, pVal, diags)
45+
}
46+
47+
func getProviderDefaultFromFrameworkSchema(schemaField string, rVal, pVal types.String, diags *diag.Diagnostics) types.String {
4048
if !rVal.IsNull() && rVal.ValueString() != "" {
4149
return rVal
4250
}
@@ -45,7 +53,7 @@ func getProjectFromFrameworkSchema(projectSchemaField string, rVal, pVal types.S
4553
return pVal
4654
}
4755

48-
diags.AddError("required field is not set", fmt.Sprintf("%s is not set", projectSchemaField))
56+
diags.AddError("required field is not set", fmt.Sprintf("%s is not set", schemaField))
4957
return types.String{}
5058
}
5159

@@ -70,7 +78,7 @@ func ParseProjectFieldValueFramework(resourceType, fieldValue, projectSchemaFiel
7078
}
7179
}
7280

73-
project := getProjectFromFrameworkSchema(projectSchemaField, rVal, pVal, diags)
81+
project := getProviderDefaultFromFrameworkSchema(projectSchemaField, rVal, pVal, diags)
7482
if diags.HasError() {
7583
return nil
7684
}
@@ -127,3 +135,10 @@ func ReplaceVarsForFrameworkTest(prov *transport_tpg.Config, rs *terraform.Resou
127135

128136
return re.ReplaceAllStringFunc(linkTmpl, replaceFunc), nil
129137
}
138+
139+
func FlattenStringEmptyToNull(configuredValue types.String, apiValue string) types.String {
140+
if configuredValue.IsNull() && apiValue == "" {
141+
return types.StringNull()
142+
}
143+
return types.StringValue(apiValue)
144+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
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/fwresource/framework_import.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 fwresource
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"regexp"
23+
"strconv"
24+
"strings"
25+
26+
"github.com/hashicorp/terraform-plugin-framework/attr"
27+
"github.com/hashicorp/terraform-plugin-framework/diag"
28+
"github.com/hashicorp/terraform-plugin-framework/resource"
29+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
30+
"github.com/hashicorp/terraform-plugin-framework/types"
31+
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
32+
)
33+
34+
// ParseImportId uses a list of regular expressions to parse a resource's import ID.
35+
// It extracts named capture groups from the regex and converts them to their
36+
// corresponding type-safe attribute values based on the provided resource schema.
37+
// It also handles setting default values (project, region, etc) if they are not
38+
// present in the import ID.
39+
func ParseImportId(
40+
ctx context.Context,
41+
req resource.ImportStateRequest,
42+
resourceSchema schema.Schema,
43+
providerConfig *transport_tpg.Config,
44+
idRegexes []string,
45+
) (map[string]attr.Value, diag.Diagnostics) {
46+
var diags diag.Diagnostics
47+
parsedAttributes := make(map[string]attr.Value)
48+
49+
var matchFound bool
50+
for _, idFormat := range idRegexes {
51+
re, err := regexp.Compile(idFormat)
52+
if err != nil {
53+
diags.AddError(
54+
"Invalid Import Regex",
55+
fmt.Sprintf("Provider developer error: could not compile regex %q. Please report this issue. Error: %s", idFormat, err),
56+
)
57+
// This is a developer error, so we stop immediately.
58+
return nil, diags
59+
}
60+
61+
if match := re.FindStringSubmatch(req.ID); match != nil {
62+
matchFound = true
63+
subexpNames := re.SubexpNames()
64+
for i, valueStr := range match {
65+
// Index 0 is the full match, so we skip it.
66+
if i == 0 {
67+
continue
68+
}
69+
70+
fieldName := subexpNames[i]
71+
if fieldName == "" {
72+
continue
73+
}
74+
75+
// Look up the attribute in the resource's schema.
76+
attribute, ok := resourceSchema.Attributes[fieldName]
77+
if !ok {
78+
diags.AddWarning(
79+
"Unknown Import Field",
80+
fmt.Sprintf("Parsed field %q from import ID but it is not defined in the resource schema.", fieldName),
81+
)
82+
continue
83+
}
84+
85+
// Convert the parsed string value to the correct attr.Value type.
86+
attrVal, conversionDiags := convertToAttrValue(valueStr, attribute)
87+
diags.Append(conversionDiags...)
88+
if conversionDiags.HasError() {
89+
continue
90+
}
91+
parsedAttributes[fieldName] = attrVal
92+
}
93+
// Once a match is found, we stop. The most specific regex should be first.
94+
break
95+
}
96+
}
97+
98+
if !matchFound {
99+
diags.AddError(
100+
"Invalid Import ID",
101+
fmt.Sprintf("Import ID %q doesn't match any of the accepted formats: %v", req.ID, idRegexes),
102+
)
103+
return nil, diags
104+
}
105+
106+
// Handle default values like project, region, and zone.
107+
defaultDiags := addDefaultValues(ctx, parsedAttributes, providerConfig, resourceSchema, idRegexes[0])
108+
diags.Append(defaultDiags...)
109+
110+
return parsedAttributes, diags
111+
}
112+
113+
// convertToAttrValue converts a string to the appropriate attr.Value based on the schema attribute type.
114+
func convertToAttrValue(valueStr string, attr schema.Attribute) (attr.Value, diag.Diagnostics) {
115+
var diags diag.Diagnostics
116+
117+
switch attr.(type) {
118+
case schema.StringAttribute:
119+
return types.StringValue(valueStr), nil
120+
case schema.Int64Attribute:
121+
intVal, err := strconv.ParseInt(valueStr, 10, 64)
122+
if err != nil {
123+
diags.AddError(
124+
"Import Value Conversion Error",
125+
fmt.Sprintf("Failed to parse %q as an integer: %s", valueStr, err),
126+
)
127+
return nil, diags
128+
}
129+
return types.Int64Value(intVal), nil
130+
case schema.BoolAttribute:
131+
boolVal, err := strconv.ParseBool(valueStr)
132+
if err != nil {
133+
diags.AddError(
134+
"Import Value Conversion Error",
135+
fmt.Sprintf("Failed to parse %q as a boolean: %s", valueStr, err),
136+
)
137+
return nil, diags
138+
}
139+
return types.BoolValue(boolVal), nil
140+
case schema.Float64Attribute:
141+
floatVal, err := strconv.ParseFloat(valueStr, 64)
142+
if err != nil {
143+
diags.AddError(
144+
"Import Value Conversion Error",
145+
fmt.Sprintf("Failed to parse %q as a float: %s", valueStr, err),
146+
)
147+
return nil, diags
148+
}
149+
return types.Float64Value(floatVal), nil
150+
default:
151+
// For complex types like List, Object, etc., a simple string conversion is not feasible.
152+
// The assumption is that import IDs will only contain primitive types.
153+
diags.AddError(
154+
"Unsupported Import Attribute Type",
155+
fmt.Sprintf("Importing attributes of type %T is not supported. This is a provider developer issue.", attr),
156+
)
157+
return nil, diags
158+
}
159+
}
160+
161+
// addDefaultValues checks for common provider-level defaults (project, region, zone)
162+
// and adds them to the parsed attributes map if they were not already set from the import ID.
163+
func addDefaultValues(
164+
ctx context.Context,
165+
parsedAttributes map[string]attr.Value,
166+
config *transport_tpg.Config,
167+
resourceSchema schema.Schema,
168+
primaryRegex string,
169+
) diag.Diagnostics {
170+
var diags diag.Diagnostics
171+
172+
defaults := map[string]func(*transport_tpg.Config) (string, error){
173+
"project": func(c *transport_tpg.Config) (string, error) { return c.Project, nil },
174+
"region": func(c *transport_tpg.Config) (string, error) { return c.Region, nil },
175+
"zone": func(c *transport_tpg.Config) (string, error) { return c.Zone, nil },
176+
}
177+
178+
for field, getDefault := range defaults {
179+
// Check if the primary regex expects this field.
180+
if !strings.Contains(primaryRegex, fmt.Sprintf("(?P<%s>", field)) {
181+
continue
182+
}
183+
// Check if the resource schema actually has this attribute.
184+
if _, ok := resourceSchema.Attributes[field]; !ok {
185+
continue
186+
}
187+
// Check if the value was already parsed from the import ID.
188+
if _, ok := parsedAttributes[field]; ok {
189+
continue
190+
}
191+
192+
// Get the default value from the provider configuration.
193+
value, err := getDefault(config)
194+
if err != nil {
195+
diags.AddError(
196+
fmt.Sprintf("Failed to get default value for %s", field),
197+
err.Error(),
198+
)
199+
continue
200+
}
201+
202+
if value != "" {
203+
parsedAttributes[field] = types.StringValue(value)
204+
}
205+
}
206+
207+
return diags
208+
}

0 commit comments

Comments
 (0)