Skip to content

Commit 3fad89c

Browse files
committed
fix: mark optional fields with API defaults as computed_optional
- Mark recursive field as computed_optional for all source connectors - Mark anonymous field as computed_optional for S3 connector - Mark id_column field as computed_optional for Postgres connector - Fix inconsistent result after apply errors for optional fields with defaults - Update generated schemas to reflect computed_optional attributes - Ensure Terraform handles API defaults correctly without manual state management
1 parent e9d3db7 commit 3fad89c

File tree

10 files changed

+81
-44
lines changed

10 files changed

+81
-44
lines changed

docs/resources/source.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ Required:
284284
- `batch_size` (Number)
285285
- `database` (String)
286286
- `host` (String)
287-
- `id_column` (String)
288287
- `password` (String)
289288
- `port` (Number)
290289
- `table_name` (String)
@@ -293,6 +292,7 @@ Required:
293292
Optional:
294293

295294
- `fields` (List of String)
295+
- `id_column` (String)
296296

297297

298298
<a id="nestedatt--s3"></a>

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/aws-gopher/terraform-provider-unstructured
33
go 1.24.5
44

55
require (
6-
github.com/aws-gopher/unstructured-sdk-go v0.0.0-20250724184133-ccde280fa6f9
6+
github.com/aws-gopher/unstructured-sdk-go v0.0.0-20250725191739-6b617f948c15
77
github.com/hashicorp/go-uuid v1.0.3
88
github.com/hashicorp/terraform-plugin-framework v1.15.0
99
github.com/hashicorp/terraform-plugin-framework-validators v0.18.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
2222
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
2323
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
2424
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
25-
github.com/aws-gopher/unstructured-sdk-go v0.0.0-20250724184133-ccde280fa6f9 h1:UoGWbBKL/2fc1EWLI8ZbdojWWFvxXJthEAS80CXPYpM=
26-
github.com/aws-gopher/unstructured-sdk-go v0.0.0-20250724184133-ccde280fa6f9/go.mod h1:8Bqqw5vVDyfb9yO1ncn5fF32DU2J0QCZJPtFdrFQtdY=
25+
github.com/aws-gopher/unstructured-sdk-go v0.0.0-20250725191739-6b617f948c15 h1:WrQVdckBk6RnTraGV6pQEjIq2VDqmrZZo5NWx0LYgSQ=
26+
github.com/aws-gopher/unstructured-sdk-go v0.0.0-20250725191739-6b617f948c15/go.mod h1:8Bqqw5vVDyfb9yO1ncn5fF32DU2J0QCZJPtFdrFQtdY=
2727
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
2828
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
2929
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=

internal/provider/source_data_source.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66

77
"github.com/aws-gopher/terraform-provider-unstructured/internal/datasource_source"
8-
"github.com/aws-gopher/terraform-provider-unstructured/internal/resource_source"
98
"github.com/aws-gopher/unstructured-sdk-go"
109
"github.com/hashicorp/terraform-plugin-framework/datasource"
1110
)
@@ -64,7 +63,7 @@ func (d *sourceDataSource) Read(ctx context.Context, req datasource.ReadRequest,
6463
}
6564

6665
// Set state
67-
resp.Diagnostics.Append(resp.State.Set(ctx, resource_source.SourceToModel(ctx, source, resp.Diagnostics))...)
66+
resp.Diagnostics.Append(resp.State.Set(ctx, datasource_source.SourceToModel(ctx, source, resp.Diagnostics))...)
6867
if resp.Diagnostics.HasError() {
6968
return
7069
}

internal/provider/source_resource.go

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,28 @@ func (r *sourceResource) getSourceConfig(data *resource_source.SourceModel) (uns
8282
}
8383

8484
if !data.S3.Anonymous.IsNull() && !data.S3.Anonymous.IsUnknown() {
85-
config.Anonymous = &[]bool{data.S3.Anonymous.ValueBool()}[0]
85+
anonymous := data.S3.Anonymous.ValueBool()
86+
config.Anonymous = &anonymous
8687
}
8788
if !data.S3.Key.IsNull() && !data.S3.Key.IsUnknown() {
88-
config.Key = &[]string{data.S3.Key.ValueString()}[0]
89+
key := data.S3.Key.ValueString()
90+
config.Key = &key
8991
}
9092
if !data.S3.Secret.IsNull() && !data.S3.Secret.IsUnknown() {
91-
config.Secret = &[]string{data.S3.Secret.ValueString()}[0]
93+
secret := data.S3.Secret.ValueString()
94+
config.Secret = &secret
9295
}
9396
if !data.S3.Token.IsNull() && !data.S3.Token.IsUnknown() {
94-
config.Token = &[]string{data.S3.Token.ValueString()}[0]
97+
token := data.S3.Token.ValueString()
98+
config.Token = &token
9599
}
96100
if !data.S3.EndpointUrl.IsNull() && !data.S3.EndpointUrl.IsUnknown() {
97-
config.EndpointURL = &[]string{data.S3.EndpointUrl.ValueString()}[0]
101+
endpointUrl := data.S3.EndpointUrl.ValueString()
102+
config.EndpointURL = &endpointUrl
98103
}
99104
if !data.S3.Recursive.IsNull() && !data.S3.Recursive.IsUnknown() {
100-
config.Recursive = &[]bool{data.S3.Recursive.ValueBool()}[0]
105+
recursive := data.S3.Recursive.ValueBool()
106+
config.Recursive = &recursive
101107
}
102108

103109
return config, nil
@@ -112,7 +118,10 @@ func (r *sourceResource) getSourceConfig(data *resource_source.SourceModel) (uns
112118
Password: data.Postgres.Password.ValueString(),
113119
TableName: data.Postgres.TableName.ValueString(),
114120
BatchSize: int(data.Postgres.BatchSize.ValueInt64()),
115-
IDColumn: &[]string{data.Postgres.IdColumn.ValueString()}[0],
121+
}
122+
if !data.Postgres.IdColumn.IsNull() && !data.Postgres.IdColumn.IsUnknown() {
123+
idColumn := data.Postgres.IdColumn.ValueString()
124+
config.IDColumn = &idColumn
116125
}
117126

118127
// Convert fields list
@@ -127,16 +136,22 @@ func (r *sourceResource) getSourceConfig(data *resource_source.SourceModel) (uns
127136

128137
if !data.Azure.IsNull() {
129138
config := &unstructured.AzureSourceConnectorConfigInput{
130-
RemoteURL: data.Azure.RemoteUrl.ValueString(),
131-
ConnectionString: &[]string{data.Azure.ConnectionString.ValueString()}[0],
139+
RemoteURL: data.Azure.RemoteUrl.ValueString(),
140+
}
141+
if !data.Azure.ConnectionString.IsNull() && !data.Azure.ConnectionString.IsUnknown() {
142+
connectionString := data.Azure.ConnectionString.ValueString()
143+
config.ConnectionString = &connectionString
132144
}
133145
return config, nil
134146
}
135147

136148
if !data.GoogleDrive.IsNull() {
137149
config := &unstructured.GoogleDriveSourceConnectorConfigInput{
138-
DriveID: data.GoogleDrive.DriveId.ValueString(),
139-
ServiceAccountKey: &[]string{data.GoogleDrive.ServiceAccountKey.ValueString()}[0],
150+
DriveID: data.GoogleDrive.DriveId.ValueString(),
151+
}
152+
if !data.GoogleDrive.ServiceAccountKey.IsNull() && !data.GoogleDrive.ServiceAccountKey.IsUnknown() {
153+
serviceAccountKey := data.GoogleDrive.ServiceAccountKey.ValueString()
154+
config.ServiceAccountKey = &serviceAccountKey
140155
}
141156

142157
if !data.GoogleDrive.Extensions.IsNull() && !data.GoogleDrive.Extensions.IsUnknown() {
@@ -145,7 +160,8 @@ func (r *sourceResource) getSourceConfig(data *resource_source.SourceModel) (uns
145160
config.Extensions = extensions
146161
}
147162
if !data.GoogleDrive.Recursive.IsNull() && !data.GoogleDrive.Recursive.IsUnknown() {
148-
config.Recursive = &[]bool{data.GoogleDrive.Recursive.ValueBool()}[0]
163+
recursive := data.GoogleDrive.Recursive.ValueBool()
164+
config.Recursive = &recursive
149165
}
150166

151167
return config, nil
@@ -195,9 +211,8 @@ func (r *sourceResource) Create(ctx context.Context, req resource.CreateRequest,
195211

196212
// Create the source
197213
source, err := r.client.CreateSource(ctx, unstructured.CreateSourceRequest{
198-
Name: data.Name.ValueString(),
199-
Description: "Created by Terraform",
200-
Config: config,
214+
Name: data.Name.ValueString(),
215+
Config: config,
201216
})
202217
if err != nil {
203218
resp.Diagnostics.AddError("Error creating source", err.Error())
@@ -262,7 +277,7 @@ func (r *sourceResource) Update(ctx context.Context, req resource.UpdateRequest,
262277
}
263278

264279
// Update the source
265-
source, err := r.client.UpdateSource(ctx, state.Id.ValueString(), unstructured.UpdateSourceRequest{
280+
source, err := r.client.UpdateSource(ctx, unstructured.UpdateSourceRequest{
266281
Config: config,
267282
})
268283
if err != nil {

internal/provider/source_resource_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func testAccSourceResourceConfig(name string) string {
7575
resource "unstructured_source" "test" {
7676
name = %[1]q
7777
78-
s3 {
78+
s3 = {
7979
remote_url = "s3://example-bucket/"
8080
anonymous = true
8181
}

internal/provider/workflow_resource.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ func (r *workflowResource) Update(ctx context.Context, req resource.UpdateReques
266266

267267
// Create API call logic
268268
updateRequest := unstructured.UpdateWorkflowRequest{
269+
ID: state.Id.ValueString(),
269270
Name: name,
270271
SourceID: sourceID,
271272
DestinationID: destinationID,
@@ -275,7 +276,7 @@ func (r *workflowResource) Update(ctx context.Context, req resource.UpdateReques
275276
ReprocessAll: reprocessAll,
276277
}
277278

278-
workflow, err := r.client.UpdateWorkflow(ctx, state.Id.ValueString(), updateRequest)
279+
workflow, err := r.client.UpdateWorkflow(ctx, updateRequest)
279280
if err != nil {
280281
resp.Diagnostics.AddError("Error updating workflow", err.Error())
281282
return

internal/resource_source/source_resource.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"time"
66

77
"github.com/aws-gopher/unstructured-sdk-go"
8+
"github.com/hashicorp/terraform-plugin-framework/attr"
89
"github.com/hashicorp/terraform-plugin-framework/diag"
910
"github.com/hashicorp/terraform-plugin-framework/types"
1011
)
@@ -278,23 +279,33 @@ func SourceToModel(ctx context.Context, source *unstructured.Source, diagnostics
278279

279280
case unstructured.ConnectorTypeS3:
280281
if config, ok := source.Config.(*unstructured.S3SourceConnectorConfig); ok {
281-
model.S3 = S3Value{
282-
RemoteUrl: types.StringValue(config.RemoteURL),
283-
Anonymous: types.BoolValue(config.Anonymous),
284-
Recursive: types.BoolValue(config.Recursive),
282+
// Create attributes map for S3Value
283+
attributes := map[string]attr.Value{
284+
"remote_url": types.StringValue(config.RemoteURL),
285+
"anonymous": types.BoolValue(config.Anonymous),
286+
"recursive": types.BoolValue(config.Recursive),
287+
"endpoint_url": types.StringNull(),
288+
"key": types.StringNull(),
289+
"secret": types.StringNull(),
290+
"token": types.StringNull(),
285291
}
292+
293+
// Set optional fields if they exist
286294
if config.Key != nil {
287-
model.S3.Key = types.StringValue(*config.Key)
295+
attributes["key"] = types.StringValue(*config.Key)
288296
}
289297
if config.Secret != nil {
290-
model.S3.Secret = types.StringValue(*config.Secret)
298+
attributes["secret"] = types.StringValue(*config.Secret)
291299
}
292300
if config.Token != nil {
293-
model.S3.Token = types.StringValue(*config.Token)
301+
attributes["token"] = types.StringValue(*config.Token)
294302
}
295303
if config.EndpointURL != nil {
296-
model.S3.EndpointUrl = types.StringValue(*config.EndpointURL)
304+
attributes["endpoint_url"] = types.StringValue(*config.EndpointURL)
297305
}
306+
307+
// Use factory function to create S3Value
308+
model.S3 = NewS3ValueMust(S3Value{}.AttributeTypes(ctx), attributes)
298309
}
299310

300311
case unstructured.ConnectorTypeSalesforce:

internal/resource_source/source_resource_gen.go

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)