Skip to content

Commit

Permalink
Amend Plan Resource Change To Allow For Optional Blocks (#552)
Browse files Browse the repository at this point in the history
Reference: #551

Modifying handling of blocks during plan resource change to allow optional blocks to be present within configuration
  • Loading branch information
bendbennett committed Nov 28, 2022
1 parent 4bd82c9 commit 486e611
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/552.txt
@@ -0,0 +1,3 @@
```release-note:bug
internal/fwserver: Ensured blocks are ignored when marking computed nils as unknown during resource change planning
```
6 changes: 6 additions & 0 deletions internal/fwserver/server_planresourcechange.go
Expand Up @@ -291,6 +291,12 @@ func MarkComputedNilsAsUnknown(ctx context.Context, config tftypes.Value, resour
return val, nil
}

if errors.Is(err, tfsdk.ErrPathIsBlock) {
// ignore blocks, they do not have a computed field
logging.FrameworkTrace(ctx, "attribute is a block, not marking unknown")
return val, nil
}

logging.FrameworkError(ctx, "couldn't find attribute in resource schema")

return tftypes.Value{}, fmt.Errorf("couldn't find attribute in resource schema: %w", err)
Expand Down
111 changes: 111 additions & 0 deletions internal/fwserver/server_planresourcechange_test.go
Expand Up @@ -274,6 +274,18 @@ func TestServerPlanResourceChange(t *testing.T) {
},
}

testSchemaBlockType := tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_required": tftypes.String,
"test_optional_block": tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_optional_one": tftypes.String,
"test_optional_two": tftypes.String,
},
},
},
}

testSchemaTypeComputed := tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_computed": tftypes.String,
Expand All @@ -293,6 +305,30 @@ func TestServerPlanResourceChange(t *testing.T) {
},
}

testSchemaBlock := tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
"test_required": {
Required: true,
Type: types.StringType,
},
},
Blocks: map[string]tfsdk.Block{
"test_optional_block": {
Attributes: map[string]tfsdk.Attribute{
"test_optional_one": {
Type: types.StringType,
Optional: true,
},
"test_optional_two": {
Type: types.StringType,
Optional: true,
},
},
NestingMode: tfsdk.BlockNestingModeSingle,
},
},
}

testEmptyPlan := &tfsdk.Plan{
Raw: tftypes.NewValue(testSchemaType, nil),
Schema: testSchema,
Expand All @@ -308,6 +344,11 @@ func TestServerPlanResourceChange(t *testing.T) {
TestRequired types.String `tfsdk:"test_required"`
}

type testSchemaDataBlock struct {
TestRequired types.String `tfsdk:"test_required"`
TestOptionalBlock types.Object `tfsdk:"test_optional_block"`
}

testSchemaAttributePlanModifierAttributePlan := tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
"test_computed": {
Expand Down Expand Up @@ -1935,6 +1976,76 @@ func TestServerPlanResourceChange(t *testing.T) {
PlannedPrivate: testEmptyPrivate,
},
},
"update-resourcewithmodifyplan-request-config-nil-block": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
},
request: &fwserver.PlanResourceChangeRequest{
Config: &tfsdk.Config{
Raw: tftypes.NewValue(testSchemaBlockType, map[string]tftypes.Value{
"test_required": tftypes.NewValue(tftypes.String, "test-new-value"),
"test_optional_block": tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_optional_one": tftypes.String,
"test_optional_two": tftypes.String,
},
}, nil),
}),
Schema: testSchemaBlock,
},
ProposedNewState: &tfsdk.Plan{
Raw: tftypes.NewValue(testSchemaBlockType, map[string]tftypes.Value{
"test_required": tftypes.NewValue(tftypes.String, "test-new-value"),
"test_optional_block": tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_optional_one": tftypes.String,
"test_optional_two": tftypes.String,
},
}, nil),
}),
Schema: testSchemaBlock,
},
PriorState: &tfsdk.State{
Raw: tftypes.NewValue(testSchemaBlockType, map[string]tftypes.Value{
"test_required": tftypes.NewValue(tftypes.String, "test-old-value"),
"test_optional_block": tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_optional_one": tftypes.String,
"test_optional_two": tftypes.String,
},
}, nil),
}),
Schema: testSchemaBlock,
},
ResourceSchema: testSchemaBlock,
Resource: &testprovider.ResourceWithModifyPlan{
ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
var data testSchemaDataBlock

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

if data.TestRequired.ValueString() != "test-new-value" {
resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.ValueString())
}
},
},
},
expectedResponse: &fwserver.PlanResourceChangeResponse{
PlannedState: &tfsdk.State{
Raw: tftypes.NewValue(testSchemaBlockType, map[string]tftypes.Value{
"test_required": tftypes.NewValue(tftypes.String, "test-new-value"),
"test_optional_block": tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test_optional_one": tftypes.String,
"test_optional_two": tftypes.String,
},
}, nil),
}),
Schema: testSchemaBlock,
},
PlannedPrivate: testEmptyPrivate,
},
},
"update-resourcewithmodifyplan-request-proposednewstate": {
server: &fwserver.Server{
Provider: &testprovider.Provider{},
Expand Down

0 comments on commit 486e611

Please sign in to comment.