-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add resource schema-based support for static default values (#674)
* Adding Default Value interfaces (#668) * Fixing docs (#668) * Adding framework-defined default value interfaces (#668) * Add framework schema interface (#668) * Add resource attribute interface (#668) * Adding TransformPlanDefaults for BoolAttribute (#668) * Modifying TransformDefaults and incorporating into PlanResourceChange (#668) * Add handling for float64, int64, number and string defaults in TransformDefaults (#668) * Add handling to prevent MarkComputedNilsAsUnknown overwriting default values (#668) * Add handling for list, map, object and set (#668) * Add handling for list, map, object and set in PlanResourceChange (#668) * Adding test coverage for list nested attribute (#668) * Refactoring func name to {TYPE}DefaultValue() (#668) * Removing TransformDefaults() from tfsdk.State so as not to expose it in the public API (#668) * Updating documentation for Default on resource schema attributes (#668) * Adding Default to remaining resource schema attributes (#668) * Adding further test coverage for TransformDefaults() for list, map, set, single nested attributes (#668) * Adding further test coverage for PlanResourceChange() for map, set and single nested attributes (#668) * Removing erroneous character (#668) * Updating tests to use Computed everywhere (#668) * Adding schema validation to only permit default values on computed attributes (#668) * Adding docs for default values (#668) * Further updates for docs (#668) * Apply suggestions from code review Co-authored-by: Brian Flad <[email protected]> * Updates following code review (#668) * Apply suggestions from code review Co-authored-by: Brian Flad <[email protected]> * Renaming test functions for consistency (#668) * Fixing link (#668) --------- Co-authored-by: Brian Flad <[email protected]>
- Loading branch information
1 parent
89889d8
commit cbd1cfe
Showing
97 changed files
with
13,326 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package fwschema | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" | ||
) | ||
|
||
// AttributeWithBoolDefaultValue is an optional interface on Attribute which | ||
// enables Bool default value support. | ||
type AttributeWithBoolDefaultValue interface { | ||
Attribute | ||
|
||
BoolDefaultValue() defaults.Bool | ||
} | ||
|
||
// AttributeWithFloat64DefaultValue is an optional interface on Attribute which | ||
// enables Float64 default value support. | ||
type AttributeWithFloat64DefaultValue interface { | ||
Attribute | ||
|
||
Float64DefaultValue() defaults.Float64 | ||
} | ||
|
||
// AttributeWithInt64DefaultValue is an optional interface on Attribute which | ||
// enables Int64 default value support. | ||
type AttributeWithInt64DefaultValue interface { | ||
Attribute | ||
|
||
Int64DefaultValue() defaults.Int64 | ||
} | ||
|
||
// AttributeWithListDefaultValue is an optional interface on Attribute which | ||
// enables List default value support. | ||
type AttributeWithListDefaultValue interface { | ||
Attribute | ||
|
||
ListDefaultValue() defaults.List | ||
} | ||
|
||
// AttributeWithMapDefaultValue is an optional interface on Attribute which | ||
// enables Map default value support. | ||
type AttributeWithMapDefaultValue interface { | ||
Attribute | ||
|
||
MapDefaultValue() defaults.Map | ||
} | ||
|
||
// AttributeWithNumberDefaultValue is an optional interface on Attribute which | ||
// enables Number default value support. | ||
type AttributeWithNumberDefaultValue interface { | ||
Attribute | ||
|
||
NumberDefaultValue() defaults.Number | ||
} | ||
|
||
// AttributeWithObjectDefaultValue is an optional interface on Attribute which | ||
// enables Object default value support. | ||
type AttributeWithObjectDefaultValue interface { | ||
Attribute | ||
|
||
ObjectDefaultValue() defaults.Object | ||
} | ||
|
||
// AttributeWithSetDefaultValue is an optional interface on Attribute which | ||
// enables Set default value support. | ||
type AttributeWithSetDefaultValue interface { | ||
Attribute | ||
|
||
SetDefaultValue() defaults.Set | ||
} | ||
|
||
// AttributeWithStringDefaultValue is an optional interface on Attribute which | ||
// enables String default value support. | ||
type AttributeWithStringDefaultValue interface { | ||
Attribute | ||
|
||
StringDefaultValue() defaults.String | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package fwschemadata | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/diag" | ||
"github.com/hashicorp/terraform-plugin-framework/internal/fromtftypes" | ||
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema" | ||
"github.com/hashicorp/terraform-plugin-framework/internal/logging" | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults" | ||
) | ||
|
||
// TransformDefaults walks the schema and applies schema defined default values | ||
// when configRaw contains a null value at the same path. | ||
func (d *Data) TransformDefaults(ctx context.Context, configRaw tftypes.Value) diag.Diagnostics { | ||
var diags diag.Diagnostics | ||
|
||
configData := Data{ | ||
Description: DataDescriptionConfiguration, | ||
Schema: d.Schema, | ||
TerraformValue: configRaw, | ||
} | ||
|
||
// Errors are handled as richer diag.Diagnostics instead. | ||
d.TerraformValue, _ = tftypes.Transform(d.TerraformValue, func(tfTypePath *tftypes.AttributePath, tfTypeValue tftypes.Value) (tftypes.Value, error) { | ||
fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, tfTypePath, d.Schema) | ||
|
||
diags.Append(fwPathDiags...) | ||
|
||
// Do not transform if path cannot be converted. | ||
// Checking against fwPathDiags will capture all errors. | ||
if fwPathDiags.HasError() { | ||
return tfTypeValue, nil | ||
} | ||
|
||
configValue, configValueDiags := configData.ValueAtPath(ctx, fwPath) | ||
|
||
diags.Append(configValueDiags...) | ||
|
||
// Do not transform if rawConfig value cannot be retrieved. | ||
if configValueDiags.HasError() { | ||
return tfTypeValue, nil | ||
} | ||
|
||
// Do not transform if rawConfig value is not null. | ||
if !configValue.IsNull() { | ||
return tfTypeValue, nil | ||
} | ||
|
||
attrAtPath, err := d.Schema.AttributeAtTerraformPath(ctx, tfTypePath) | ||
|
||
if err != nil { | ||
if errors.Is(err, fwschema.ErrPathInsideAtomicAttribute) { | ||
// ignore attributes/elements inside schema.Attributes, they have no schema of their own | ||
logging.FrameworkTrace(ctx, "attribute is a non-schema attribute, not setting default") | ||
return tfTypeValue, nil | ||
} | ||
|
||
if errors.Is(err, fwschema.ErrPathIsBlock) { | ||
// ignore blocks, they do not have a computed field | ||
logging.FrameworkTrace(ctx, "attribute is a block, not setting default") | ||
return tfTypeValue, nil | ||
} | ||
|
||
return tftypes.Value{}, fmt.Errorf("couldn't find attribute in resource schema: %w", err) | ||
} | ||
|
||
switch a := attrAtPath.(type) { | ||
case fwschema.AttributeWithBoolDefaultValue: | ||
defaultValue := a.BoolDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.BoolResponse{} | ||
defaultValue.DefaultBool(ctx, defaults.BoolRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithFloat64DefaultValue: | ||
defaultValue := a.Float64DefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.Float64Response{} | ||
defaultValue.DefaultFloat64(ctx, defaults.Float64Request{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithInt64DefaultValue: | ||
defaultValue := a.Int64DefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.Int64Response{} | ||
defaultValue.DefaultInt64(ctx, defaults.Int64Request{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithListDefaultValue: | ||
defaultValue := a.ListDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.ListResponse{} | ||
defaultValue.DefaultList(ctx, defaults.ListRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithMapDefaultValue: | ||
defaultValue := a.MapDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.MapResponse{} | ||
defaultValue.DefaultMap(ctx, defaults.MapRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithNumberDefaultValue: | ||
defaultValue := a.NumberDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.NumberResponse{} | ||
defaultValue.DefaultNumber(ctx, defaults.NumberRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithObjectDefaultValue: | ||
defaultValue := a.ObjectDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.ObjectResponse{} | ||
defaultValue.DefaultObject(ctx, defaults.ObjectRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithSetDefaultValue: | ||
defaultValue := a.SetDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.SetResponse{} | ||
defaultValue.DefaultSet(ctx, defaults.SetRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
case fwschema.AttributeWithStringDefaultValue: | ||
defaultValue := a.StringDefaultValue() | ||
if defaultValue != nil { | ||
resp := defaults.StringResponse{} | ||
defaultValue.DefaultString(ctx, defaults.StringRequest{}, &resp) | ||
logging.FrameworkTrace(ctx, fmt.Sprintf("setting attribute %s to default value: %s", fwPath.String(), resp.PlanValue.String())) | ||
return resp.PlanValue.ToTerraformValue(ctx) | ||
} | ||
} | ||
|
||
return tfTypeValue, nil | ||
}) | ||
|
||
return diags | ||
} |
Oops, something went wrong.