core: Input variables are always unknown during validate

Earlier on in the v0.12 development cycle we made the decision that the
validation walk should consider input values to always be unknown so that
validation is checking validity for all possible inputs rather than for
a specific set of inputs; checking for a specific set of inputs is the
responsibility of the plan walk.

However, we didn't implement that in the best way: we made the
"terraform validate" command force all of the input variables to unknown
but that was insufficient because it didn't also affect the implicit
validation walk we do as part of "terraform plan" and "terraform apply",
causing those to produce confusingly-different results.

Instead, we'll address the problem directly in the reference resolver code,
ensuring that all variable values will always be treated as an unknown
(of the declared type, so type checking is still possible) during any
validate walk, regardless of which command is running it.
pull/21043/head
Martin Atkins 7 years ago
parent d7f23f0beb
commit cbc8d1eba2

@ -1030,7 +1030,7 @@ func TestContext2Validate_targetedDestroy(t *testing.T) {
}
}
func TestContext2Validate_varRefFilled(t *testing.T) {
func TestContext2Validate_varRefUnknown(t *testing.T) {
m := testModule(t, "validate-variable-ref")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
@ -1064,7 +1064,11 @@ func TestContext2Validate_varRefFilled(t *testing.T) {
}
c.Validate()
if !value.RawEquals(cty.StringVal("bar")) {
// Input variables are always unknown during the validate walk, because
// we're checking for validity of all possible input values. Validity
// against specific input values is checked during the plan walk.
if !value.RawEquals(cty.UnknownVal(cty.String)) {
t.Fatalf("bad: %#v", value)
}
}

@ -215,6 +215,23 @@ func (d *evaluationStateData) GetInputVariable(addr addrs.InputVariable, rng tfd
d.Evaluator.VariableValuesLock.Lock()
defer d.Evaluator.VariableValuesLock.Unlock()
// During the validate walk, input variables are always unknown so
// that we are validating the configuration for all possible input values
// rather than for a specific set. Checking against a specific set of
// input values then happens during the plan walk.
//
// This is important because otherwise the validation walk will tend to be
// overly strict, requiring expressions throughout the configuration to
// be complicated to accommodate all possible inputs, whereas returning
// known here allows for simpler patterns like using input values as
// guards to broadly enable/disable resources, avoid processing things
// that are disabled, etc. Terraform's static validation leans towards
// being liberal in what it accepts because the subsequent plan walk has
// more information available and so can be more conservative.
if d.Operation == walkValidate {
return cty.UnknownVal(wantType), diags
}
moduleAddrStr := d.ModulePath.String()
vals := d.Evaluator.VariableValues[moduleAddrStr]
if vals == nil {

Loading…
Cancel
Save