Skip to content

Commit

Permalink
tfsdk: Additional attribute logging, such as TypeWithValidate
Browse files Browse the repository at this point in the history
  • Loading branch information
bflad committed Apr 25, 2022
1 parent be47997 commit e5b70c3
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 15 deletions.
8 changes: 8 additions & 0 deletions internal/logging/framework.go
Expand Up @@ -30,3 +30,11 @@ func FrameworkTrace(ctx context.Context, msg string, additionalFields ...map[str
func FrameworkWarn(ctx context.Context, msg string, additionalFields ...map[string]interface{}) {
tfsdklog.SubsystemWarn(ctx, SubsystemFramework, msg, additionalFields...)
}

// FrameworkWithAttributePath returns a new Context with KeyAttributePath set.
// The attribute path is expected to be string, so the logging package does not
// need to import path handling code.
func FrameworkWithAttributePath(ctx context.Context, attributePath string) context.Context {
ctx = tfsdklog.SubsystemWith(ctx, SubsystemFramework, KeyAttributePath, attributePath)
return ctx
}
16 changes: 8 additions & 8 deletions tfsdk/attribute.go
Expand Up @@ -270,6 +270,8 @@ func (a Attribute) tfprotov6SchemaAttribute(ctx context.Context, name string, pa

// validate performs all Attribute validation.
func (a Attribute) validate(ctx context.Context, req ValidateAttributeRequest, resp *ValidateAttributeResponse) {
ctx = logging.FrameworkWithAttributePath(ctx, req.AttributePath.String())

if !a.definesAttributes() && a.Type == nil {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
Expand Down Expand Up @@ -314,17 +316,15 @@ func (a Attribute) validate(ctx context.Context, req ValidateAttributeRequest, r
ctx,
"Calling provider defined AttributeValidator",
map[string]interface{}{
logging.KeyAttributePath: req.AttributePath.String(),
logging.KeyDescription: validator.Description(ctx),
logging.KeyDescription: validator.Description(ctx),
},
)
validator.Validate(ctx, req, resp)
logging.FrameworkDebug(
ctx,
"Called provider defined AttributeValidator",
map[string]interface{}{
logging.KeyAttributePath: req.AttributePath.String(),
logging.KeyDescription: validator.Description(ctx),
logging.KeyDescription: validator.Description(ctx),
},
)
}
Expand Down Expand Up @@ -503,6 +503,8 @@ func (a Attribute) validateAttributes(ctx context.Context, req ValidateAttribute

// modifyPlan runs all AttributePlanModifiers
func (a Attribute) modifyPlan(ctx context.Context, req ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) {
ctx = logging.FrameworkWithAttributePath(ctx, req.AttributePath.String())

attrConfig, diags := req.Config.getAttributeValue(ctx, req.AttributePath)
resp.Diagnostics.Append(diags...)

Expand Down Expand Up @@ -541,17 +543,15 @@ func (a Attribute) modifyPlan(ctx context.Context, req ModifyAttributePlanReques
ctx,
"Calling provider defined AttributePlanModifier",
map[string]interface{}{
logging.KeyAttributePath: req.AttributePath.String(),
logging.KeyDescription: planModifier.Description(ctx),
logging.KeyDescription: planModifier.Description(ctx),
},
)
planModifier.Modify(ctx, req, modifyResp)
logging.FrameworkDebug(
ctx,
"Called provider defined AttributePlanModifier",
map[string]interface{}{
logging.KeyAttributePath: req.AttributePath.String(),
logging.KeyDescription: planModifier.Description(ctx),
logging.KeyDescription: planModifier.Description(ctx),
},
)

Expand Down
2 changes: 1 addition & 1 deletion tfsdk/attribute_plan_modification.go
Expand Up @@ -309,7 +309,7 @@ func (r RequiresReplaceIfModifier) Modify(ctx context.Context, req ModifyAttribu
if res {
resp.RequiresReplace = true
} else if resp.RequiresReplace {
logging.FrameworkDebug(ctx, "Keeping previous attribute replacement requirement", map[string]interface{}{logging.KeyAttributePath: req.AttributePath.String()})
logging.FrameworkDebug(ctx, "Keeping previous attribute replacement requirement")
}
}

Expand Down
6 changes: 6 additions & 0 deletions tfsdk/config.go
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/logging"
"github.com/hashicorp/terraform-plugin-framework/internal/reflect"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
Expand All @@ -25,6 +26,8 @@ func (c Config) Get(ctx context.Context, target interface{}) diag.Diagnostics {
// GetAttribute retrieves the attribute found at `path` and populates the
// `target` with the value.
func (c Config) GetAttribute(ctx context.Context, path *tftypes.AttributePath, target interface{}) diag.Diagnostics {
ctx = logging.FrameworkWithAttributePath(ctx, path.String())

attrValue, diags := c.getAttributeValue(ctx, path)

if diags.HasError() {
Expand Down Expand Up @@ -92,7 +95,10 @@ func (c Config) getAttributeValue(ctx context.Context, path *tftypes.AttributePa
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186

if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok {
logging.FrameworkTrace(ctx, "Type implements TypeWithValidate")
logging.FrameworkDebug(ctx, "Calling provider defined Type Validate")
diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...)
logging.FrameworkDebug(ctx, "Called provider defined Type Validate")

if diags.HasError() {
return nil, diags
Expand Down
11 changes: 11 additions & 0 deletions tfsdk/plan.go
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/logging"
"github.com/hashicorp/terraform-plugin-framework/internal/reflect"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
Expand All @@ -25,6 +26,8 @@ func (p Plan) Get(ctx context.Context, target interface{}) diag.Diagnostics {
// GetAttribute retrieves the attribute found at `path` and populates the
// `target` with the value.
func (p Plan) GetAttribute(ctx context.Context, path *tftypes.AttributePath, target interface{}) diag.Diagnostics {
ctx = logging.FrameworkWithAttributePath(ctx, path.String())

attrValue, diags := p.getAttributeValue(ctx, path)

if diags.HasError() {
Expand Down Expand Up @@ -92,7 +95,10 @@ func (p Plan) getAttributeValue(ctx context.Context, path *tftypes.AttributePath
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186

if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok {
logging.FrameworkTrace(ctx, "Type implements TypeWithValidate")
logging.FrameworkDebug(ctx, "Calling provider defined Type Validate")
diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...)
logging.FrameworkDebug(ctx, "Called provider defined Type Validate")

if diags.HasError() {
return nil, diags
Expand Down Expand Up @@ -147,6 +153,8 @@ func (p *Plan) Set(ctx context.Context, val interface{}) diag.Diagnostics {
func (p *Plan) SetAttribute(ctx context.Context, path *tftypes.AttributePath, val interface{}) diag.Diagnostics {
var diags diag.Diagnostics

ctx = logging.FrameworkWithAttributePath(ctx, path.String())

attrType, err := p.Schema.AttributeTypeAtPath(path)
if err != nil {
err = fmt.Errorf("error getting attribute type in schema: %w", err)
Expand Down Expand Up @@ -177,7 +185,10 @@ func (p *Plan) SetAttribute(ctx context.Context, path *tftypes.AttributePath, va
}

if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok {
logging.FrameworkTrace(ctx, "Type implements TypeWithValidate")
logging.FrameworkDebug(ctx, "Calling provider defined Type Validate")
diags.Append(attrTypeWithValidate.Validate(ctx, tfVal, path)...)
logging.FrameworkDebug(ctx, "Called provider defined Type Validate")

if diags.HasError() {
return diags
Expand Down
14 changes: 8 additions & 6 deletions tfsdk/serve.go
Expand Up @@ -917,33 +917,35 @@ func (s *server) readResource(ctx context.Context, req *tfprotov6.ReadResourceRe

func markComputedNilsAsUnknown(ctx context.Context, config tftypes.Value, resourceSchema Schema) func(*tftypes.AttributePath, tftypes.Value) (tftypes.Value, error) {
return func(path *tftypes.AttributePath, val tftypes.Value) (tftypes.Value, error) {
ctx = logging.FrameworkWithAttributePath(ctx, path.String())

// we are only modifying attributes, not the entire resource
if len(path.Steps()) < 1 {
return val, nil
}
configVal, _, err := tftypes.WalkAttributePath(config, path)
if err != tftypes.ErrInvalidStep && err != nil {
logging.FrameworkError(ctx, "error walking attribute path", map[string]interface{}{logging.KeyAttributePath: path})
logging.FrameworkError(ctx, "error walking attribute path")
return val, err
} else if err != tftypes.ErrInvalidStep && !configVal.(tftypes.Value).IsNull() {
logging.FrameworkTrace(ctx, "attribute not null in config, not marking unknown", map[string]interface{}{logging.KeyAttributePath: path})
logging.FrameworkTrace(ctx, "attribute not null in config, not marking unknown")
return val, nil
}
attribute, err := resourceSchema.AttributeAtPath(path)
if err != nil {
if errors.Is(err, ErrPathInsideAtomicAttribute) {
// ignore attributes/elements inside schema.Attributes, they have no schema of their own
logging.FrameworkTrace(ctx, "attribute is a non-schema attribute, not marking unknown", map[string]interface{}{logging.KeyAttributePath: path})
logging.FrameworkTrace(ctx, "attribute is a non-schema attribute, not marking unknown")
return val, nil
}
logging.FrameworkError(ctx, "couldn't find attribute in resource schema", map[string]interface{}{logging.KeyAttributePath: path})
logging.FrameworkError(ctx, "couldn't find attribute in resource schema")
return tftypes.Value{}, fmt.Errorf("couldn't find attribute in resource schema: %w", err)
}
if !attribute.Computed {
logging.FrameworkTrace(ctx, "attribute is not computed in schema, not marking unknown", map[string]interface{}{logging.KeyAttributePath: path})
logging.FrameworkTrace(ctx, "attribute is not computed in schema, not marking unknown")
return val, nil
}
logging.FrameworkDebug(ctx, "marking computed attribute that is null in the config as unknown", map[string]interface{}{logging.KeyAttributePath: path})
logging.FrameworkDebug(ctx, "marking computed attribute that is null in the config as unknown")
return tftypes.NewValue(val.Type(), tftypes.UnknownValue), nil
}
}
Expand Down
14 changes: 14 additions & 0 deletions tfsdk/state.go
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/logging"
"github.com/hashicorp/terraform-plugin-framework/internal/reflect"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
Expand Down Expand Up @@ -92,7 +93,11 @@ func (s State) getAttributeValue(ctx context.Context, path *tftypes.AttributePat
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/186

if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok {
attributePathCtx := logging.FrameworkWithAttributePath(ctx, path.String())
logging.FrameworkTrace(attributePathCtx, "Type implements TypeWithValidate")
logging.FrameworkDebug(attributePathCtx, "Calling provider defined Type Validate")
diags.Append(attrTypeWithValidate.Validate(ctx, tfValue, path)...)
logging.FrameworkDebug(attributePathCtx, "Called provider defined Type Validate")

if diags.HasError() {
return nil, diags
Expand Down Expand Up @@ -156,6 +161,8 @@ func (s *State) Set(ctx context.Context, val interface{}) diag.Diagnostics {
func (s *State) SetAttribute(ctx context.Context, path *tftypes.AttributePath, val interface{}) diag.Diagnostics {
var diags diag.Diagnostics

ctx = logging.FrameworkWithAttributePath(ctx, path.String())

attrType, err := s.Schema.AttributeTypeAtPath(path)
if err != nil {
err = fmt.Errorf("error getting attribute type in schema: %w", err)
Expand Down Expand Up @@ -186,7 +193,10 @@ func (s *State) SetAttribute(ctx context.Context, path *tftypes.AttributePath, v
}

if attrTypeWithValidate, ok := attrType.(attr.TypeWithValidate); ok {
logging.FrameworkTrace(ctx, "Type implements TypeWithValidate")
logging.FrameworkDebug(ctx, "Calling provider defined Type Validate")
diags.Append(attrTypeWithValidate.Validate(ctx, tfVal, path)...)
logging.FrameworkDebug(ctx, "Called provider defined Type Validate")

if diags.HasError() {
return diags
Expand Down Expand Up @@ -315,7 +325,11 @@ func (s State) setAttributeTransformFunc(ctx context.Context, path *tftypes.Attr
}

if attrTypeWithValidate, ok := parentAttrType.(attr.TypeWithValidate); ok {
attributePathCtx := logging.FrameworkWithAttributePath(ctx, path.String())
logging.FrameworkTrace(attributePathCtx, "Type implements TypeWithValidate")
logging.FrameworkDebug(attributePathCtx, "Calling provider defined Type Validate")
diags.Append(attrTypeWithValidate.Validate(ctx, parentValue, parentPath)...)
logging.FrameworkDebug(attributePathCtx, "Called provider defined Type Validate")

if diags.HasError() {
return nil, diags
Expand Down

0 comments on commit e5b70c3

Please sign in to comment.