Skip to content

Commit

Permalink
internal/fwschemadata: Replace fwserver duplicate logic, add data des…
Browse files Browse the repository at this point in the history
…cription (hashicorp#464)

Reference: hashicorp#365
Reference: hashicorp#366

This change represents another evolutionary step to move away from `tfsdk.Config`, `tfsdk.Plan`, and `tfsdk.State` types directly, where the temporarily duplicated logic in `internal/fwserver` which worked directly with those types is replaced with the shared data implementation.
  • Loading branch information
bflad committed Aug 30, 2022
1 parent 1a3f8fe commit 5810578
Show file tree
Hide file tree
Showing 19 changed files with 145 additions and 388 deletions.
4 changes: 4 additions & 0 deletions internal/fwschemadata/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
// Data is the shared storage implementation for schema-based values, such as
// configuration, plan, and state.
type Data struct {
// Description contains the human friendly type of the data. Used in error
// diagnostics.
Description DataDescription

// Schema contains the data structure and types for the value.
Schema fwschema.Schema

Expand Down
43 changes: 43 additions & 0 deletions internal/fwschemadata/data_description.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package fwschemadata

const (
// DataDescriptionConfiguration is used for Data that represents
// a configuration-based value.
DataDescriptionConfiguration DataDescription = "configuration"

// DataDescriptionPlan is used for Data that represents
// a plan-based value.
DataDescriptionPlan DataDescription = "plan"

// DataDescriptionState is used for Data that represents
// a state-based value.
DataDescriptionState DataDescription = "state"
)

// DataDescription is a human friendly type for Data. Used in error
// diagnostics.
type DataDescription string

// String returns the lowercase string of the description.
func (d DataDescription) String() string {
switch d {
case "":
return "data"
default:
return string(d)
}
}

// Title returns the titlecase string of the description.
func (d DataDescription) Title() string {
switch d {
case DataDescriptionConfiguration:
return "Configuration"
case DataDescriptionPlan:
return "Plan"
case DataDescriptionState:
return "State"
default:
return "Data"
}
}
6 changes: 3 additions & 3 deletions internal/fwschemadata/data_get_at_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ func (d Data) GetAtPath(ctx context.Context, schemaPath path.Path, target any) d
if attrValue == nil {
diags.AddAttributeError(
schemaPath,
"Config 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\n"+
d.Description.Title()+" Read Error",
"An unexpected error was encountered trying to read an attribute from the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Missing attribute value, however no error was returned. Preventing the panic from this situation.",
)
return diags
Expand All @@ -42,7 +42,7 @@ func (d Data) GetAtPath(ctx context.Context, schemaPath path.Path, target any) d
if err != nil {
diags.AddAttributeError(
schemaPath,
"Error converting value",
d.Description.Title()+" Value Conversion Error",
fmt.Sprintf("An unexpected error was encountered converting a %T to its equivalent Terraform representation. This is always a bug in the provider.\n\n"+
"Error: %s", attrValue, err),
)
Expand Down
6 changes: 3 additions & 3 deletions internal/fwschemadata/data_path_exists.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ func (d Data) PathExists(ctx context.Context, path path.Path) (bool, diag.Diagno

diags.AddAttributeError(
path,
"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\n"+
fmt.Sprintf("Cannot walk attribute path in state: %s", err),
d.Description.Title()+" Read Error",
"An unexpected error was encountered trying to read an attribute from the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+
fmt.Sprintf("Cannot walk attribute path in %s: %s", d.Description, err),
)
return false, diags
}
Expand Down
4 changes: 2 additions & 2 deletions internal/fwschemadata/data_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ func (d *Data) Set(ctx context.Context, val any) diag.Diagnostics {

if err != nil {
diags.AddError(
"Data Write Error",
"An unexpected error was encountered trying to write the data. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
d.Description.Title()+" Write Error",
"An unexpected error was encountered trying to write the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+
fmt.Sprintf("Error: Unable to run ToTerraformValue on new value: %s", err),
)
return diags
Expand Down
18 changes: 9 additions & 9 deletions internal/fwschemadata/data_set_at_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d
if err != nil {
diags.AddAttributeError(
path,
"Data Write Error",
d.Description.Title()+" Write Error",
"An unexpected error was encountered trying to retrieve type information at a given path. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: "+err.Error(),
)
Expand All @@ -59,8 +59,8 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d
if err != nil {
diags.AddAttributeError(
path,
"Data Write Error",
"An unexpected error was encountered trying to write an attribute to the data. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
d.Description.Title()+" Write Error",
"An unexpected error was encountered trying to write an attribute to the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: Cannot run ToTerraformValue on new data value: "+err.Error(),
)
return diags
Expand Down Expand Up @@ -89,8 +89,8 @@ func (d *Data) SetAtPath(ctx context.Context, path path.Path, val interface{}) d
if err != nil {
diags.AddAttributeError(
path,
"Data Write Error",
"An unexpected error was encountered trying to write an attribute to the data. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
d.Description.Title()+" Write Error",
"An unexpected error was encountered trying to write an attribute to the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: Cannot transform data: "+err.Error(),
)
return diags
Expand Down Expand Up @@ -137,8 +137,8 @@ func (d Data) SetAtPathTransformFunc(ctx context.Context, path path.Path, tfVal
err = fmt.Errorf("error getting parent attribute type in schema: %w", err)
diags.AddAttributeError(
parentPath,
"Plan Write Error",
"An unexpected error was encountered trying to write an attribute to the plan. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
d.Description.Title()+" Write Error",
"An unexpected error was encountered trying to write an attribute to the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
)
return nil, diags
}
Expand All @@ -148,8 +148,8 @@ func (d Data) SetAtPathTransformFunc(ctx context.Context, path path.Path, tfVal
if err != nil && !errors.Is(err, tftypes.ErrInvalidStep) {
diags.AddAttributeError(
parentPath,
"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\n"+err.Error(),
d.Description.Title()+" Read Error",
"An unexpected error was encountered trying to read an attribute from the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
)
return nil, diags
}
Expand Down
8 changes: 4 additions & 4 deletions internal/fwschemadata/data_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value
if err != nil {
diags.AddAttributeError(
schemaPath,
"Data Read Error",
d.Description.Title()+" Read Error",
"An unexpected error was encountered trying to retrieve type information at a given path. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: "+err.Error(),
)
Expand All @@ -51,7 +51,7 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value
if err != nil && !errors.Is(err, tftypes.ErrInvalidStep) {
diags.AddAttributeError(
schemaPath,
"Data Read Error",
d.Description.Title()+" Read Error",
"An unexpected error was encountered trying to retrieve an attribute value from the given path. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
)
return nil, diags
Expand All @@ -77,8 +77,8 @@ func (d Data) ValueAtPath(ctx context.Context, schemaPath path.Path) (attr.Value
if err != nil {
diags.AddAttributeError(
schemaPath,
"Data Read Error",
"An unexpected error was encountered trying to convert an attribute value from the data. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
d.Description.Title()+" Read Error",
"An unexpected error was encountered trying to convert an attribute value from the "+d.Description.String()+". This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: "+err.Error(),
)
return nil, diags
Expand Down
25 changes: 22 additions & 3 deletions internal/fwserver/attribute_plan_modification.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata"
"github.com/hashicorp/terraform-plugin-framework/internal/logging"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
Expand All @@ -21,7 +22,13 @@ import (
func AttributeModifyPlan(ctx context.Context, a fwschema.Attribute, req tfsdk.ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) {
ctx = logging.FrameworkWithAttributePath(ctx, req.AttributePath.String())

attrConfig, diags := ConfigGetAttributeValue(ctx, req.Config, req.AttributePath)
configData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: req.Config.Schema,
TerraformValue: req.Config.Raw,
}

attrConfig, diags := configData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

// Only on new errors.
Expand All @@ -30,7 +37,13 @@ func AttributeModifyPlan(ctx context.Context, a fwschema.Attribute, req tfsdk.Mo
}
req.AttributeConfig = attrConfig

attrState, diags := StateGetAttributeValue(ctx, req.State, req.AttributePath)
stateData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionState,
Schema: req.State.Schema,
TerraformValue: req.State.Raw,
}

attrState, diags := stateData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

// Only on new errors.
Expand All @@ -39,7 +52,13 @@ func AttributeModifyPlan(ctx context.Context, a fwschema.Attribute, req tfsdk.Mo
}
req.AttributeState = attrState

attrPlan, diags := PlanGetAttributeValue(ctx, req.Plan, req.AttributePath)
planData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionPlan,
Schema: req.Plan.Schema,
TerraformValue: req.Plan.Raw,
}

attrPlan, diags := planData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

// Only on new errors.
Expand Down
24 changes: 12 additions & 12 deletions internal/fwserver/attribute_plan_modification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
Plan: tfsdk.Plan{
Expand Down Expand Up @@ -188,8 +188,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
Plan: tfsdk.Plan{
Expand Down Expand Up @@ -272,8 +272,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
Plan: tfsdk.Plan{
Expand Down Expand Up @@ -367,8 +367,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the plan. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
Plan: tfsdk.Plan{
Expand Down Expand Up @@ -451,8 +451,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the state. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
Plan: tfsdk.Plan{
Expand Down Expand Up @@ -546,8 +546,8 @@ func TestAttributeModifyPlan(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the state. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
Plan: tfsdk.Plan{
Expand Down
9 changes: 8 additions & 1 deletion internal/fwserver/attribute_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata"
"github.com/hashicorp/terraform-plugin-framework/internal/logging"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand Down Expand Up @@ -50,7 +51,13 @@ func AttributeValidate(ctx context.Context, a fwschema.Attribute, req tfsdk.Vali
return
}

attributeConfig, diags := ConfigGetAttributeValue(ctx, req.Config, req.AttributePath)
configData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: req.Config.Schema,
TerraformValue: req.Config.Raw,
}

attributeConfig, diags := configData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

if diags.HasError() {
Expand Down
4 changes: 2 additions & 2 deletions internal/fwserver/attribute_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ func TestAttributeValidate(t *testing.T) {
diag.NewAttributeErrorDiagnostic(
path.Root("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\n"+
"can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
"An unexpected error was encountered trying to convert an attribute value from the configuration. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Error: can't use tftypes.String<\"testvalue\"> as value of List with ElementType types.primitive, can only use tftypes.String values",
),
},
},
Expand Down
25 changes: 22 additions & 3 deletions internal/fwserver/block_plan_modification.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand All @@ -18,7 +19,13 @@ import (
// package from the tfsdk package and not wanting to export the method.
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365
func BlockModifyPlan(ctx context.Context, b fwschema.Block, req tfsdk.ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) {
attributeConfig, diags := ConfigGetAttributeValue(ctx, req.Config, req.AttributePath)
configData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: req.Config.Schema,
TerraformValue: req.Config.Raw,
}

attributeConfig, diags := configData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

if diags.HasError() {
Expand All @@ -27,7 +34,13 @@ func BlockModifyPlan(ctx context.Context, b fwschema.Block, req tfsdk.ModifyAttr

req.AttributeConfig = attributeConfig

attributePlan, diags := PlanGetAttributeValue(ctx, req.Plan, req.AttributePath)
planData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionPlan,
Schema: req.Plan.Schema,
TerraformValue: req.Plan.Raw,
}

attributePlan, diags := planData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

if diags.HasError() {
Expand All @@ -36,7 +49,13 @@ func BlockModifyPlan(ctx context.Context, b fwschema.Block, req tfsdk.ModifyAttr

req.AttributePlan = attributePlan

attributeState, diags := StateGetAttributeValue(ctx, req.State, req.AttributePath)
stateData := &fwschemadata.Data{
Description: fwschemadata.DataDescriptionState,
Schema: req.State.Schema,
TerraformValue: req.State.Raw,
}

attributeState, diags := stateData.ValueAtPath(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

if diags.HasError() {
Expand Down
Loading

0 comments on commit 5810578

Please sign in to comment.