re-validate config during Plan

The config is statically validated early on for structural issues, but
the provider can't validate any inputs that were unknown at the time.
Run ValidateResourceTypeConfig during Plan, so that the provider can
validate the final config values, including those interpolated from
other resources.
This commit is contained in:
James Bardin 2019-05-31 20:09:20 -05:00
parent c658fe173a
commit c41eb0e6e4
2 changed files with 58 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package terraform
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"os" "os"
"reflect" "reflect"
@ -5724,6 +5725,49 @@ resource "aws_instance" "foo" {
} }
} }
func TestContext2Plan_variableValidation(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
variable "x" {
default = "bar"
}
resource "aws_instance" "foo" {
foo = var.x
}`,
})
p := testProvider("aws")
p.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) (resp providers.ValidateResourceTypeConfigResponse) {
foo := req.Config.GetAttr("foo").AsString()
if foo == "bar" {
resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo cannot be bar"))
}
return
}
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
resp.PlannedState = req.ProposedNewState
return
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
_, diags := ctx.Plan()
if !diags.HasErrors() {
// Should get this error:
// Unsupported attribute: This object does not have an attribute named "missing"
t.Fatal("succeeded; want errors")
}
}
func checkVals(t *testing.T, expected, got cty.Value) { func checkVals(t *testing.T, expected, got cty.Value) {
t.Helper() t.Helper()
if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) { if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) {

View File

@ -174,6 +174,20 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
} }
} }
log.Printf("[TRACE] Re-validating config for %q", n.Addr.Absolute(ctx.Path()))
// Allow the provider to validate the final set of values.
// The config was statically validated early on, but there may have been
// unknown values which the provider could not validate at the time.
validateResp := provider.ValidateResourceTypeConfig(
providers.ValidateResourceTypeConfigRequest{
TypeName: n.Addr.Resource.Type,
Config: configVal,
},
)
if validateResp.Diagnostics.HasErrors() {
return nil, validateResp.Diagnostics.InConfigBody(config.Config).Err()
}
// The provider gets an opportunity to customize the proposed new value, // The provider gets an opportunity to customize the proposed new value,
// which in turn produces the _planned_ new value. // which in turn produces the _planned_ new value.
resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{ resp := provider.PlanResourceChange(providers.PlanResourceChangeRequest{