core: Warn when creating and applying with -target
The documentation for the -target option warns that it's intended for exceptional circumstances only and not for routine use, but that's not a very prominent location for that warning and so some users miss it. Here we make the warning more prominent by including it directly in the Terraform output when -target is in use. We first warn during planning that the plan might be incomplete, and then warn again after apply concludes and direct the user to run "terraform plan" to make sure that there are no further changes outstanding. The latter message is intended to reinforce that -target should only be a one-off operation and that you should always run without it soon after to ensure that the workspace is left in a consistent, converged state.
This commit is contained in:
parent
3145171caf
commit
7e29b9b5d4
|
@ -76,9 +76,9 @@ func (b *Local) opApply(
|
|||
|
||||
// Perform the plan
|
||||
log.Printf("[INFO] backend/local: apply calling Plan")
|
||||
plan, err := tfCtx.Plan()
|
||||
if err != nil {
|
||||
diags = diags.Append(err)
|
||||
plan, planDiags := tfCtx.Plan()
|
||||
diags = diags.Append(planDiags)
|
||||
if planDiags.HasErrors() {
|
||||
b.ReportResult(runningOp, diags)
|
||||
return
|
||||
}
|
||||
|
@ -112,6 +112,13 @@ func (b *Local) opApply(
|
|||
b.CLI.Output("")
|
||||
}
|
||||
|
||||
// We'll show any accumulated warnings before we display the prompt,
|
||||
// so the user can consider them when deciding how to answer.
|
||||
if len(diags) > 0 {
|
||||
b.ShowDiagnostics(diags)
|
||||
diags = nil // reset so we won't show the same diagnostics again later
|
||||
}
|
||||
|
||||
v, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{
|
||||
Id: "approve",
|
||||
Query: query,
|
||||
|
|
|
@ -467,6 +467,17 @@ func (c *Context) Apply() (*states.State, tfdiags.Diagnostics) {
|
|||
c.state.PruneResourceHusks()
|
||||
}
|
||||
|
||||
if len(c.targets) > 0 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Warning,
|
||||
"Applied changes may be incomplete",
|
||||
`The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the following command to verify that no other changes are pending:
|
||||
terraform plan
|
||||
|
||||
Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
|
||||
))
|
||||
}
|
||||
|
||||
return c.state, diags
|
||||
}
|
||||
|
||||
|
@ -483,6 +494,16 @@ func (c *Context) Plan() (*plans.Plan, tfdiags.Diagnostics) {
|
|||
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if len(c.targets) > 0 {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Warning,
|
||||
"Resource targeting is in effect",
|
||||
`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
|
||||
|
||||
The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
|
||||
))
|
||||
}
|
||||
|
||||
varVals := make(map[string]plans.DynamicValue, len(c.variables))
|
||||
for k, iv := range c.variables {
|
||||
// We use cty.DynamicPseudoType here so that we'll save both the
|
||||
|
|
|
@ -6824,15 +6824,34 @@ func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) {
|
|||
},
|
||||
})
|
||||
|
||||
_, err := ctx.Plan()
|
||||
if err != nil {
|
||||
t.Fatalf("plan err: %s", err)
|
||||
_, diags := ctx.Plan()
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("plan err: %s", diags)
|
||||
}
|
||||
if len(diags) != 1 {
|
||||
// Should have one warning that -target is in effect.
|
||||
t.Fatalf("got %d diagnostics in plan; want 1", len(diags))
|
||||
}
|
||||
if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
|
||||
t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
|
||||
}
|
||||
if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
|
||||
t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
|
||||
}
|
||||
|
||||
// Destroy, targeting the module explicitly
|
||||
state, err = ctx.Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("destroy apply err: %s", err)
|
||||
state, diags = ctx.Apply()
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("destroy apply err: %s", diags)
|
||||
}
|
||||
if len(diags) != 1 {
|
||||
t.Fatalf("got %d diagnostics; want 1", len(diags))
|
||||
}
|
||||
if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
|
||||
t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
|
||||
}
|
||||
if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want {
|
||||
t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4690,9 +4690,18 @@ func TestContext2Plan_outputContainsTargetedResource(t *testing.T) {
|
|||
},
|
||||
})
|
||||
|
||||
_, err := ctx.Plan()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
_, diags := ctx.Plan()
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("err: %s", diags)
|
||||
}
|
||||
if len(diags) != 1 {
|
||||
t.Fatalf("got %d diagnostics; want 1", diags)
|
||||
}
|
||||
if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
|
||||
t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
|
||||
}
|
||||
if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
|
||||
t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue