core: Improve warnings for legacy SDK apply-time inconsistencies

We've allowed the legacy SDK an opt-out from the post-apply safety checks,
but previously we produced only a generic warning message in that case.
Now instead we'll still run the safety checks, but report the results in
the logs instead of as error diagnostics.

This should allow developers who are debugging strange interactions
between buggy legacy providers to get better insight into what's going
on upstream in order to help explain what's going on when these problems
inevitably get caught by other downstream safety checks when trying to
make use of these invalid results.
This commit is contained in:
Martin Atkins 2019-02-08 20:27:49 -08:00
parent 419f5e58cd
commit 5649ae6abf
1 changed files with 32 additions and 23 deletions

View File

@ -3,6 +3,7 @@ package terraform
import (
"fmt"
"log"
"strings"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl2/hcl"
@ -172,34 +173,42 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
newVal = cty.UnknownAsNull(newVal)
}
if resp.LegacyTypeSystem {
// The shimming of the old type system in the legacy SDK is not precise
// enough to pass this consistency check, so we'll give it a pass here,
// but we will generate a warning about it so that we are more likely
// to notice in the logs if an inconsistency beyond the type system
// leads to a downstream provider failure.
log.Printf("[WARN] Provider %s is using the legacy provider SDK, so we cannot check the result value for consistency with the plan; downstream errors about inconsistent plans may actually be caused by incorrect values from %s", n.ProviderAddr.ProviderConfig.Type, absAddr)
// The sort of inconsistency we won't catch here is if a known value
// in the plan is changed during apply. That can cause downstream
// problems because a dependent resource would make its own plan based
// on the planned value, and thus get a different result during the
// apply phase. This will usually lead to a "Provider produced invalid plan"
// error that incorrectly blames the downstream resource for the change.
} else if change.Action != plans.Delete {
if change.Action != plans.Delete {
// Only values that were marked as unknown in the planned value are allowed
// to change during the apply operation. (We do this after the unknown-ness
// check above so that we also catch anything that became unknown after
// being known during plan.)
if errs := objchange.AssertObjectCompatible(schema, change.After, newVal); len(errs) > 0 {
for _, err := range errs {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider produced inconsistent result after apply",
fmt.Sprintf(
"When applying changes to %s, provider %q produced an unexpected new value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
absAddr, n.ProviderAddr.ProviderConfig.Type, tfdiags.FormatError(err),
),
))
if resp.LegacyTypeSystem {
// The shimming of the old type system in the legacy SDK is not precise
// enough to pass this consistency check, so we'll give it a pass here,
// but we will generate a warning about it so that we are more likely
// to notice in the logs if an inconsistency beyond the type system
// leads to a downstream provider failure.
var buf strings.Builder
fmt.Fprintf(&buf, "[WARN] Provider %q produced an unexpected new value for %s, but we are tolerating it because it is using the legacy plugin SDK.\n The following problems may be the cause of any confusing errors from downstream operations:", n.ProviderAddr.ProviderConfig.Type, absAddr)
for _, err := range errs {
fmt.Fprintf(&buf, "\n - %s", tfdiags.FormatError(err))
}
log.Print(buf.String())
// The sort of inconsistency we won't catch here is if a known value
// in the plan is changed during apply. That can cause downstream
// problems because a dependent resource would make its own plan based
// on the planned value, and thus get a different result during the
// apply phase. This will usually lead to a "Provider produced invalid plan"
// error that incorrectly blames the downstream resource for the change.
} else {
for _, err := range errs {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider produced inconsistent result after apply",
fmt.Sprintf(
"When applying changes to %s, provider %q produced an unexpected new value for %s.\n\nThis is a bug in the provider, which should be reported in the provider's own issue tracker.",
absAddr, n.ProviderAddr.ProviderConfig.Type, tfdiags.FormatError(err),
),
))
}
}
}
}