Skip to content

Commit

Permalink
noop orphan change has nothing to apply
Browse files Browse the repository at this point in the history
An orphaned resource which plans as a NoOp change will have no config.
This is not an error, but there is nothing to do since there are also
no checks to validate. We still leave the change in the plan to keep the
plan as complete as possible, noting all possible changes.

Preventing the node from being added to the graph is awkward, because
the config is attached separately from the diff transformer. This should
not pose any problems however, because there is no longer any state or
config linking the instance to any dependencies in the graph.
  • Loading branch information
jbardin committed Oct 11, 2022
1 parent 73c3994 commit 3779dbc
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 5 deletions.
43 changes: 43 additions & 0 deletions internal/terraform/context_apply2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1442,3 +1442,46 @@ resource "test_object" "x" {
t.Fatalf("apply: %s", diags.Err())
}
}

func TestContext2Apply_missingOrphanedResource(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
# changed resource address to create a new object
resource "test_object" "y" {
test_string = "y"
}
`,
})

p := simpleMockProvider()

// report the prior value is missing
p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
resp.NewState = cty.NullVal(req.PriorState.Type())
return resp
}

state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.x").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"test_string":"x"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)

ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})

opts := SimplePlanOpts(plans.NormalMode, nil)
plan, diags := ctx.Plan(m, state, opts)
assertNoErrors(t, diags)

_, diags = ctx.Apply(plan, m)
assertNoErrors(t, diags)
}
15 changes: 10 additions & 5 deletions internal/terraform/node_resource_apply_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,16 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio
addr := n.ResourceInstanceAddr()

if n.Config == nil {
// This should not be possible, but we've got here in at least one
// case as discussed in the following issue:
// https://github.com/hashicorp/terraform/issues/21258
// To avoid an outright crash here, we'll instead return an explicit
// error.
// If there is no config, and there is no change, then we have nothing
// to do and the change was left in the plan for informational
// purposes only.
changes := ctx.Changes()
csrc := changes.GetResourceInstanceChange(n.ResourceInstanceAddr(), states.CurrentGen)
if csrc == nil || csrc.Action == plans.NoOp {
log.Printf("[DEBUG] NodeApplyableResourceInstance: No config or planned change recorded for %s", n.Addr)
return nil
}

diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Resource node has no configuration attached",
Expand Down

0 comments on commit 3779dbc

Please sign in to comment.