diff --git a/terraform/context_validate_test.go b/terraform/context_validate_test.go index 1b6d571afb..aae8da0906 100644 --- a/terraform/context_validate_test.go +++ b/terraform/context_validate_test.go @@ -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) } } diff --git a/terraform/evaluate.go b/terraform/evaluate.go index 38fe876734..ab65d475b1 100644 --- a/terraform/evaluate.go +++ b/terraform/evaluate.go @@ -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 {