Skip to content

Commit

Permalink
tfsdk: Return null value when missing from Config, Plan, and State Ge…
Browse files Browse the repository at this point in the history
…tAttribute() method (#185)

Reference: #150
  • Loading branch information
bflad authored Sep 29, 2021
1 parent 05d6b6f commit 4b382e2
Show file tree
Hide file tree
Showing 8 changed files with 2,357 additions and 303 deletions.
3 changes: 3 additions & 0 deletions .changelog/185.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
tfsdk: Fetch null values from valid missing `Config`, `Plan`, and `State` paths in `GetAttribute()` method
```
63 changes: 35 additions & 28 deletions tfsdk/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,15 +708,15 @@ func TestAttributeModifyPlan(t *testing.T) {
Config: Config{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand Down Expand Up @@ -766,7 +766,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"Configuration Read Error",
"An unexpected error was encountered trying to read an attribute from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand All @@ -777,15 +778,15 @@ func TestAttributeModifyPlan(t *testing.T) {
Config: Config{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand Down Expand Up @@ -845,7 +846,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"Configuration Read Error",
"An unexpected error was encountered trying to read an attribute from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down Expand Up @@ -873,15 +875,15 @@ func TestAttributeModifyPlan(t *testing.T) {
Plan: Plan{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand Down Expand Up @@ -914,7 +916,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"Plan Read Error",
"An unexpected error was encountered trying to read an attribute from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down Expand Up @@ -942,15 +945,15 @@ func TestAttributeModifyPlan(t *testing.T) {
Plan: Plan{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand Down Expand Up @@ -993,7 +996,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"Plan Read Error",
"An unexpected error was encountered trying to read an attribute from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down Expand Up @@ -1038,15 +1042,15 @@ func TestAttributeModifyPlan(t *testing.T) {
State: State{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand All @@ -1062,7 +1066,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"State Read Error",
"An unexpected error was encountered trying to read an attribute from the state. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the state. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down Expand Up @@ -1107,15 +1112,15 @@ func TestAttributeModifyPlan(t *testing.T) {
State: State{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand All @@ -1141,7 +1146,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"State Read Error",
"An unexpected error was encountered trying to read an attribute from the state. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the state. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down Expand Up @@ -2151,15 +2157,15 @@ func TestAttributeValidate(t *testing.T) {
Config: Config{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"nottest": tftypes.String,
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"nottest": tftypes.NewValue(tftypes.String, "testvalue"),
"test": tftypes.NewValue(tftypes.String, "testvalue"),
}),
Schema: Schema{
Attributes: map[string]Attribute{
"test": {
Type: types.StringType,
Type: types.ListType{ElemType: types.StringType},
Required: true,
},
},
Expand All @@ -2171,7 +2177,8 @@ func TestAttributeValidate(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
tftypes.NewAttributePath().WithAttributeName("test"),
"Configuration Read Error",
"An unexpected error was encountered trying to read an attribute from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\nAttributeName(\"test\") still remains in the path: step cannot be applied to this value",
"An unexpected error was encountered trying to read an attribute from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down
9 changes: 8 additions & 1 deletion tfsdk/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tfsdk

import (
"context"
"errors"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/attr"
Expand Down Expand Up @@ -44,7 +45,9 @@ func (c Config) GetAttribute(ctx context.Context, path *tftypes.AttributePath) (
}

tfValue, err := c.terraformValueAtPath(path)
if err != nil {

// Ignoring ErrInvalidStep will allow this method to return a null value of the type.
if err != nil && !errors.Is(err, tftypes.ErrInvalidStep) {
diags.AddAttributeError(
path,
"Configuration Read Error",
Expand All @@ -53,6 +56,10 @@ func (c Config) GetAttribute(ctx context.Context, path *tftypes.AttributePath) (
return nil, diags
}

// TODO: If ErrInvalidStep, check parent paths for unknown value.
// If found, convert this value to an unknown value.
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186

if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok {
diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...)

Expand Down
Loading

0 comments on commit 4b382e2

Please sign in to comment.