Merge pull request #27512 from hashicorp/jbardin/output-plans

Create and Delete actions for output plans
This commit is contained in:
James Bardin 2021-01-14 11:09:23 -05:00 committed by GitHub
commit 68b65cc98a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 7 deletions

View File

@ -6677,3 +6677,58 @@ func TestContext2Plan_variableCustomValidationsSensitive(t *testing.T) {
t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want)
}
}
func TestContext2Plan_nullOutputNoOp(t *testing.T) {
// this should always plan a NoOp change for the output
m := testModuleInline(t, map[string]string{
"main.tf": `
output "planned" {
value = false ? 1 : null
}
`,
})
ctx := testContext2(t, &ContextOpts{
Config: m,
State: states.BuildState(func(s *states.SyncState) {
r := s.Module(addrs.RootModuleInstance)
r.SetOutputValue("planned", cty.NullVal(cty.DynamicPseudoType), false)
}),
})
plan, diags := ctx.Plan()
if diags.HasErrors() {
t.Fatal(diags.Err())
}
for _, c := range plan.Changes.Outputs {
if c.Action != plans.NoOp {
t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
}
}
}
func TestContext2Plan_createOutput(t *testing.T) {
// this should always plan a NoOp change for the output
m := testModuleInline(t, map[string]string{
"main.tf": `
output "planned" {
value = 1
}
`,
})
ctx := testContext2(t, &ContextOpts{
Config: m,
State: states.NewState(),
})
plan, diags := ctx.Plan()
if diags.HasErrors() {
t.Fatal(diags.Err())
}
for _, c := range plan.Changes.Outputs {
if c.Action != plans.Create {
t.Fatalf("expected Create change, got %s for %q", c.Action, c.Addr)
}
}
}

View File

@ -432,12 +432,17 @@ func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.C
// the diff
sensitiveBefore := false
before := cty.NullVal(cty.DynamicPseudoType)
// is this output new to our state?
newOutput := true
mod := state.Module(n.Addr.Module)
if n.Addr.Module.IsRoot() && mod != nil {
for name, o := range mod.OutputValues {
if name == n.Addr.OutputValue.Name {
before = o.Value
sensitiveBefore = o.Sensitive
newOutput = false
break
}
}
@ -451,12 +456,15 @@ func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.C
// strip any marks here just to be sure we don't panic on the True comparison
val, _ = val.UnmarkDeep()
var action plans.Action
action := plans.Update
switch {
case val.IsNull():
action = plans.Delete
case val.IsNull() && before.IsNull():
// This is separate from the NoOp case below, since we can ignore
// sensitivity here when there are only null values.
action = plans.NoOp
case before.IsNull():
case newOutput:
// This output was just added to the configuration
action = plans.Create
case val.IsWhollyKnown() &&
@ -467,9 +475,6 @@ func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.C
// only one we can act on, and the state will have been loaded
// without any marks to consider.
action = plans.NoOp
default:
action = plans.Update
}
change := &plans.OutputChange{