set state in deferred data read

The state was not being set, so the change was not evaluated correctly
for dependant resources.

Remove use of cty.NilVal in readDataSource, only one place was using it,
so the code could just be moved out.

Fix a bunch of places where warnings would be lost.
This commit is contained in:
James Bardin 2020-05-09 10:23:46 -04:00
parent 05575a863c
commit 44919641ef
3 changed files with 54 additions and 73 deletions

View File

@ -70,11 +70,8 @@ func (n *evalReadData) readDataSource(ctx EvalContext, configVal cty.Value) (cty
}
provider := *n.Provider
providerSchema := *n.ProviderSchema
forEach, _ := evaluateForEachExpression(config.ForEach, ctx)
keyData := EvalDataForInstanceKey(n.Addr.Key, forEach)
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
if schema == nil {
// Should be caught during validation, so we don't bother with a pretty error here
@ -82,15 +79,6 @@ func (n *evalReadData) readDataSource(ctx EvalContext, configVal cty.Value) (cty
return newVal, diags
}
if configVal == cty.NilVal {
val, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
diags = diags.Append(configDiags)
if configDiags.HasErrors() {
return newVal, diags
}
configVal = val
}
metaConfigVal, metaDiags := n.providerMetas(ctx)
diags = diags.Append(metaDiags)
if diags.HasErrors() {
@ -232,7 +220,7 @@ func (n *EvalReadDataRefresh) Eval(ctx EvalContext) (interface{}, error) {
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
diags = diags.Append(configDiags)
if configDiags.HasErrors() {
return nil, diags.Err()
return nil, diags.ErrWithWarnings()
}
configKnown := configVal.IsWhollyKnown()
@ -257,7 +245,7 @@ func (n *EvalReadDataRefresh) Eval(ctx EvalContext) (interface{}, error) {
// We need to store a change so tat other references to this data
// source can resolve correctly, since the state is not going to be up
// to date.
change := &plans.ResourceInstanceChange{
*n.OutputChange = &plans.ResourceInstanceChange{
Addr: absAddr,
ProviderAddr: n.ProviderAddr,
Change: plans.Change{
@ -267,15 +255,9 @@ func (n *EvalReadDataRefresh) Eval(ctx EvalContext) (interface{}, error) {
},
}
if n.OutputChange != nil {
*n.OutputChange = change
}
if n.State != nil {
*n.State = &states.ResourceInstanceObject{
Value: cty.NullVal(objTy),
Status: states.ObjectPlanned,
}
*n.State = &states.ResourceInstanceObject{
Value: cty.NullVal(objTy),
Status: states.ObjectPlanned,
}
return nil, diags.ErrWithWarnings()
@ -296,20 +278,15 @@ func (n *EvalReadDataRefresh) Eval(ctx EvalContext) (interface{}, error) {
// This may still have been refreshed with references to resources that
// will be updated, but that will be caught as a change during plan.
outputState := &states.ResourceInstanceObject{
*n.State = &states.ResourceInstanceObject{
Value: newVal,
Status: states.ObjectReady,
}
err := ctx.Hook(func(h Hook) (HookAction, error) {
if err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostRefresh(absAddr, states.CurrentGen, priorVal, newVal)
})
if err != nil {
return nil, err
}
if n.State != nil {
*n.State = outputState
}); err != nil {
diags = diags.Append(err)
}
return nil, diags.ErrWithWarnings()

View File

@ -6,7 +6,6 @@ import (
"github.com/hashicorp/terraform/plans"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags"
"github.com/zclconf/go-cty/cty"
)
// EvalReadDataApply is an EvalNode implementation that deals with the main part
@ -48,34 +47,43 @@ func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
// we have a change and it is complete, which means we read the data
// source during plan and only need to store it in state.
if planned.Action == plans.Update {
outputState := &states.ResourceInstanceObject{
if err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostApply(absAddr, states.CurrentGen, planned.After, nil)
}); err != nil {
diags = diags.Append(err)
}
*n.State = &states.ResourceInstanceObject{
Value: planned.After,
Status: states.ObjectReady,
}
err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostApply(absAddr, states.CurrentGen, planned.After, nil)
})
if err != nil {
return nil, err
}
if n.OutputChange != nil {
*n.OutputChange = planned
}
if n.State != nil {
*n.State = outputState
}
return nil, diags.ErrWithWarnings()
}
newVal, readDiags := n.readDataSource(ctx, cty.NilVal)
config := *n.Config
providerSchema := *n.ProviderSchema
schema, _ := providerSchema.SchemaForResourceAddr(n.Addr.ContainingResource())
if schema == nil {
// Should be caught during validation, so we don't bother with a pretty error here
return nil, fmt.Errorf("provider %q does not support data source %q", n.ProviderAddr.Provider.String(), n.Addr.Resource.Type)
}
forEach, _ := evaluateForEachExpression(config.ForEach, ctx)
keyData := EvalDataForInstanceKey(n.Addr.Key, forEach)
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
diags = diags.Append(configDiags)
if configDiags.HasErrors() {
return nil, diags.ErrWithWarnings()
}
newVal, readDiags := n.readDataSource(ctx, configVal)
diags = diags.Append(readDiags)
if diags.HasErrors() {
return nil, diags.ErrWithWarnings()
}
outputState := &states.ResourceInstanceObject{
*n.State = &states.ResourceInstanceObject{
Value: newVal,
Status: states.ObjectReady,
}
@ -83,11 +91,7 @@ func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
if err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostApply(absAddr, states.CurrentGen, newVal, diags.Err())
}); err != nil {
return nil, err
}
if n.State != nil {
*n.State = outputState
diags = diags.Append(err)
}
return nil, diags.ErrWithWarnings()

View File

@ -57,7 +57,7 @@ func (n *EvalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData)
diags = diags.Append(configDiags)
if configDiags.HasErrors() {
return nil, diags.Err()
return nil, diags.ErrWithWarnings()
}
configKnown := configVal.IsWhollyKnown()
@ -74,14 +74,14 @@ func (n *EvalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
proposedNewVal := objchange.PlannedDataResourceObject(schema, configVal)
err := ctx.Hook(func(h Hook) (HookAction, error) {
if err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PreDiff(absAddr, states.CurrentGen, priorVal, proposedNewVal)
})
if err != nil {
return nil, err
}); err != nil {
diags = diags.Append(err)
return nil, diags.ErrWithWarnings()
}
change := &plans.ResourceInstanceChange{
*n.OutputChange = &plans.ResourceInstanceChange{
Addr: absAddr,
ProviderAddr: n.ProviderAddr,
Change: plans.Change{
@ -91,14 +91,17 @@ func (n *EvalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
},
}
err = ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostDiff(absAddr, states.CurrentGen, change.Action, priorVal, proposedNewVal)
})
if err != nil {
return nil, err
*n.State = &states.ResourceInstanceObject{
Value: cty.NullVal(objTy),
Status: states.ObjectPlanned,
}
if err := ctx.Hook(func(h Hook) (HookAction, error) {
return h.PostDiff(absAddr, states.CurrentGen, plans.Read, priorVal, proposedNewVal)
}); err != nil {
diags = diags.Append(err)
}
*n.OutputChange = change
return nil, diags.ErrWithWarnings()
}
@ -122,7 +125,7 @@ func (n *EvalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
}
// Produce a change regardless of the outcome.
change := &plans.ResourceInstanceChange{
*n.OutputChange = &plans.ResourceInstanceChange{
Addr: absAddr,
ProviderAddr: n.ProviderAddr,
Change: plans.Change{
@ -132,7 +135,7 @@ func (n *EvalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
},
}
outputState := &states.ResourceInstanceObject{
*n.State = &states.ResourceInstanceObject{
Value: newVal,
Status: states.ObjectPlanned,
}
@ -143,9 +146,6 @@ func (n *EvalReadDataPlan) Eval(ctx EvalContext) (interface{}, error) {
return nil, err
}
*n.OutputChange = change
*n.State = outputState
return nil, diags.ErrWithWarnings()
}