Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tfsdk: Return null value when missing from Config, Plan, and State GetAttribute() method #185

Merged
merged 5 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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