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:
parent
c658fe173a
commit
c41eb0e6e4
|
@ -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) {
|
||||||
|
|
|
@ -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{
|
||||||
|
|
Loading…
Reference in New Issue