From c872cd6d96f5c1d5b6c8fd961508ce3827d8bb30 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 5 Apr 2023 10:19:26 -0400 Subject: [PATCH] the destroy plan should use correct type When we plan to destroy an instance, the change recorded should use the correct type for the resource rather than `DynamicPseudoType`. Most of the time this is hidden when the change is encoded in the plan, because any `null` is always encoded to the same value, and when decoded it will be converted to the schema type. However when apply requires creating a second plan for an instance's replacement that value is not going to be encoded, and remains a dynamic value which is sent to the provider. Most providers won't see that either, as the grpc request also encodes and decodes the value to conform with the correct schema. The builtin terraform provider does get the raw cty value though, and when that dynamic value is returned validation fails when the type does not match. --- .../terraform/node_resource_abstract_instance.go | 2 +- internal/terraform/provider_mock.go | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/internal/terraform/node_resource_abstract_instance.go b/internal/terraform/node_resource_abstract_instance.go index 01a8cc76bf07..8b5ed87f11e1 100644 --- a/internal/terraform/node_resource_abstract_instance.go +++ b/internal/terraform/node_resource_abstract_instance.go @@ -440,7 +440,7 @@ func (n *NodeAbstractResourceInstance) planDestroy(ctx EvalContext, currentState Change: plans.Change{ Action: plans.Delete, Before: currentState.Value, - After: cty.NullVal(cty.DynamicPseudoType), + After: nullVal, }, Private: resp.PlannedPrivate, ProviderAddr: n.ResolvedProvider, diff --git a/internal/terraform/provider_mock.go b/internal/terraform/provider_mock.go index 23ce9be5b5c7..e10f8b98b75b 100644 --- a/internal/terraform/provider_mock.go +++ b/internal/terraform/provider_mock.go @@ -435,28 +435,16 @@ func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeReques return *p.ApplyResourceChangeResponse } - schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] - if !ok { - resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) - return resp - } - // if the value is nil, we return that directly to correspond to a delete if r.PlannedState.IsNull() { - resp.NewState = cty.NullVal(schema.Block.ImpliedType()) - return resp - } - - val, err := schema.Block.CoerceValue(r.PlannedState) - if err != nil { - resp.Diagnostics = resp.Diagnostics.Append(err) + resp.NewState = r.PlannedState return resp } // the default behavior will be to create the minimal valid apply value by // setting unknowns (which correspond to computed attributes) to a zero // value. - val, _ = cty.Transform(val, func(path cty.Path, v cty.Value) (cty.Value, error) { + val, _ := cty.Transform(r.PlannedState, func(path cty.Path, v cty.Value) (cty.Value, error) { if !v.IsKnown() { ty := v.Type() switch {