Add input validation into the 'checks' outputs and tracking (#33481)

This commit is contained in:
Liam Cervante 2023-07-10 12:33:45 +02:00 committed by GitHub
parent f74a8d16cf
commit c9bc7e8479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 501 additions and 250 deletions

View File

@ -44,6 +44,12 @@ func (c CheckRule) String() string {
return fmt.Sprintf("%s.postcondition[%d]", container, c.Index)
case OutputPrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
case CheckDataResource:
return fmt.Sprintf("%s.data[%d]", container, c.Index)
case CheckAssertion:
return fmt.Sprintf("%s.assert[%d]", container, c.Index)
case InputValidation:
return fmt.Sprintf("%s.validation[%d]", container, c.Index)
default:
// This should not happen
return fmt.Sprintf("%s.condition[%d]", container, c.Index)
@ -85,6 +91,7 @@ const (
OutputPrecondition CheckRuleType = 3
CheckDataResource CheckRuleType = 4
CheckAssertion CheckRuleType = 5
InputValidation CheckRuleType = 6
)
// Description returns a human-readable description of the check type. This is
@ -101,6 +108,8 @@ func (c CheckRuleType) Description() string {
return "Check block data resource"
case CheckAssertion:
return "Check block assertion"
case InputValidation:
return "Input variable validation"
default:
// This should not happen
return "Condition"

View File

@ -56,6 +56,7 @@ const (
CheckableResource CheckableKind = 'R'
CheckableOutputValue CheckableKind = 'O'
CheckableCheck CheckableKind = 'C'
CheckableInputVariable CheckableKind = 'I'
)
// ConfigCheckable is an interfaces implemented by address types that represent
@ -179,6 +180,14 @@ func ParseCheckableStr(kind CheckableKind, src string) (Checkable, tfdiags.Diagn
}
return Check{Name: name}.Absolute(path), diags
case CheckableInputVariable:
name, nameDiags := getCheckableName("var", "variable value")
diags = diags.Append(nameDiags)
if diags.HasErrors() {
return nil, diags
}
return InputVariable{Name: name}.Absolute(path), diags
default:
panic(fmt.Sprintf("unsupported CheckableKind %s", kind))
}

View File

@ -12,13 +12,15 @@ func _() {
_ = x[CheckableResource-82]
_ = x[CheckableOutputValue-79]
_ = x[CheckableCheck-67]
_ = x[CheckableInputVariable-73]
}
const (
_CheckableKind_name_0 = "CheckableKindInvalid"
_CheckableKind_name_1 = "CheckableCheck"
_CheckableKind_name_2 = "CheckableOutputValue"
_CheckableKind_name_3 = "CheckableResource"
_CheckableKind_name_2 = "CheckableInputVariable"
_CheckableKind_name_3 = "CheckableOutputValue"
_CheckableKind_name_4 = "CheckableResource"
)
func (i CheckableKind) String() string {
@ -27,10 +29,12 @@ func (i CheckableKind) String() string {
return _CheckableKind_name_0
case i == 67:
return _CheckableKind_name_1
case i == 79:
case i == 73:
return _CheckableKind_name_2
case i == 82:
case i == 79:
return _CheckableKind_name_3
case i == 82:
return _CheckableKind_name_4
default:
return "CheckableKind(" + strconv.FormatInt(int64(i), 10) + ")"
}

View File

@ -14,11 +14,12 @@ func _() {
_ = x[OutputPrecondition-3]
_ = x[CheckDataResource-4]
_ = x[CheckAssertion-5]
_ = x[InputValidation-6]
}
const _CheckRuleType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPreconditionCheckDataResourceCheckAssertion"
const _CheckRuleType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPreconditionCheckDataResourceCheckAssertionInputValidation"
var _CheckRuleType_index = [...]uint8{0, 16, 36, 57, 75, 92, 106}
var _CheckRuleType_index = [...]uint8{0, 16, 36, 57, 75, 92, 106, 121}
func (i CheckRuleType) String() string {
if i < 0 || i >= CheckRuleType(len(_CheckRuleType_index)-1) {

View File

@ -32,6 +32,13 @@ func (v InputVariable) Absolute(m ModuleInstance) AbsInputVariableInstance {
}
}
func (v InputVariable) InModule(module Module) ConfigInputVariable {
return ConfigInputVariable{
Module: module,
Variable: v,
}
}
// AbsInputVariableInstance is the address of an input variable within a
// particular module instance.
type AbsInputVariableInstance struct {
@ -39,6 +46,8 @@ type AbsInputVariableInstance struct {
Variable InputVariable
}
var _ Checkable = AbsInputVariableInstance{}
// InputVariable returns the absolute address of the input variable of the
// given name inside the receiving module instance.
func (m ModuleInstance) InputVariable(name string) AbsInputVariableInstance {
@ -57,3 +66,61 @@ func (v AbsInputVariableInstance) String() string {
return fmt.Sprintf("%s.%s", v.Module.String(), v.Variable.String())
}
func (v AbsInputVariableInstance) UniqueKey() UniqueKey {
return absInputVariableInstanceUniqueKey(v.String())
}
func (v AbsInputVariableInstance) checkableSigil() {}
func (v AbsInputVariableInstance) CheckRule(typ CheckRuleType, i int) CheckRule {
return CheckRule{
Container: v,
Type: typ,
Index: i,
}
}
func (v AbsInputVariableInstance) ConfigCheckable() ConfigCheckable {
return ConfigInputVariable{
Module: v.Module.Module(),
Variable: v.Variable,
}
}
func (v AbsInputVariableInstance) CheckableKind() CheckableKind {
return CheckableInputVariable
}
type ConfigInputVariable struct {
Module Module
Variable InputVariable
}
var _ ConfigCheckable = ConfigInputVariable{}
func (v ConfigInputVariable) UniqueKey() UniqueKey {
return configInputVariableUniqueKey(v.String())
}
func (v ConfigInputVariable) configCheckableSigil() {}
func (v ConfigInputVariable) CheckableKind() CheckableKind {
return CheckableInputVariable
}
func (v ConfigInputVariable) String() string {
if len(v.Module) == 0 {
return v.Variable.String()
}
return fmt.Sprintf("%s.%s", v.Module.String(), v.Variable.String())
}
type configInputVariableUniqueKey string
func (k configInputVariableUniqueKey) uniqueKeySigil() {}
type absInputVariableInstanceUniqueKey string
func (k absInputVariableInstanceUniqueKey) uniqueKeySigil() {}

View File

@ -68,6 +68,22 @@ func collectInitialStatuses(into addrs.Map[addrs.ConfigCheckable, *configCheckab
into.Put(addr, st)
}
for _, v := range cfg.Module.Variables {
addr := v.Addr().InModule(moduleAddr)
vs := len(v.Validations)
if vs == 0 {
continue
}
st := &configCheckableState{}
st.checkTypes = map[addrs.CheckRuleType]int{
addrs.InputValidation: vs,
}
into.Put(addr, st)
}
// Must also visit child modules to collect everything
for _, child := range cfg.Children {
collectInitialStatuses(into, child)

View File

@ -59,6 +59,17 @@ func makeStaticObjectAddr(addr addrs.ConfigCheckable) staticObjectAddr {
if !addr.Module.IsRoot() {
ret["module"] = addr.Module.String()
}
case addrs.ConfigInputVariable:
if kind := addr.CheckableKind(); kind != addrs.CheckableInputVariable {
// Something has gone very wrong
panic(fmt.Sprintf("%T has CheckableKind %s", addr, kind))
}
ret["kind"] = "var"
ret["name"] = addr.Variable.Name
if !addr.Module.IsRoot() {
ret["module"] = addr.Module.String()
}
default:
panic(fmt.Sprintf("unsupported ConfigCheckable implementation %T", addr))
}
@ -89,6 +100,10 @@ func makeDynamicObjectAddr(addr addrs.Checkable) dynamicObjectAddr {
if !addr.Module.IsRoot() {
ret["module"] = addr.Module.String()
}
case addrs.AbsInputVariableInstance:
if !addr.Module.IsRoot() {
ret["module"] = addr.Module.String()
}
default:
panic(fmt.Sprintf("unsupported Checkable implementation %T", addr))
}

View File

@ -283,6 +283,7 @@ const (
CheckResults_RESOURCE CheckResults_ObjectKind = 1
CheckResults_OUTPUT_VALUE CheckResults_ObjectKind = 2
CheckResults_CHECK CheckResults_ObjectKind = 3
CheckResults_INPUT_VARIABLE CheckResults_ObjectKind = 4
)
// Enum value maps for CheckResults_ObjectKind.
@ -292,12 +293,14 @@ var (
1: "RESOURCE",
2: "OUTPUT_VALUE",
3: "CHECK",
4: "INPUT_VARIABLE",
}
CheckResults_ObjectKind_value = map[string]int32{
"UNSPECIFIED": 0,
"RESOURCE": 1,
"OUTPUT_VALUE": 2,
"CHECK": 3,
"INPUT_VARIABLE": 4,
}
)
@ -1449,7 +1452,7 @@ var file_planfile_proto_rawDesc = []byte{
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e,
0x67, 0x65, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65,
0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73,
0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0xe8, 0x03, 0x0a, 0x0c, 0x43, 0x68, 0x65,
0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x22, 0xfc, 0x03, 0x0a, 0x0c, 0x43, 0x68, 0x65,
0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x33, 0x0a, 0x04, 0x6b, 0x69, 0x6e,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e,
0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x4f, 0x62,
@ -1475,70 +1478,72 @@ var file_planfile_proto_rawDesc = []byte{
0x67, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a,
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x41,
0x53, 0x53, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x02, 0x12, 0x09,
0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0x48, 0x0a, 0x0a, 0x4f, 0x62, 0x6a,
0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0x5c, 0x0a, 0x0a, 0x4f, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45,
0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x53, 0x4f,
0x55, 0x52, 0x43, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54,
0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x48, 0x45, 0x43,
0x4b, 0x10, 0x03, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6b, 0x22, 0xa5, 0x01,
0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50,
0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x1a,
0x74, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x12, 0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44,
0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x65,
0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c,
0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x1b, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69,
0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
0x69, 0x64, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f,
0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f,
0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x5f, 0x4f,
0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45,
0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12,
0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44,
0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x45, 0x4c, 0x45, 0x54,
0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x06, 0x12,
0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x44,
0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x2a, 0xc8, 0x03, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45,
0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45,
0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12,
0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x52, 0x45,
0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50, 0x4c, 0x41,
0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x4e, 0x4f,
0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x44, 0x45,
0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f,
0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
0x04, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41,
0x55, 0x53, 0x45, 0x5f, 0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x54, 0x49,
0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x49,
0x4e, 0x44, 0x45, 0x58, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41, 0x43, 0x48, 0x5f, 0x4b, 0x45,
0x59, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45,
0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x10,
0x08, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f,
0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x53, 0x10, 0x09, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45,
0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49,
0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x12, 0x23, 0x0a, 0x1f, 0x52,
0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x45,
0x4e, 0x44, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0b,
0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45,
0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12,
0x21, 0x0a, 0x1d, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53,
0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54,
0x10, 0x0c, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61,
0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c,
0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61,
0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x4b, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f, 0x56, 0x41, 0x52,
0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x04, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, 0x6e, 0x61, 0x6d,
0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61,
0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, 0x70, 0x61, 0x63,
0x6b, 0x22, 0xa5, 0x01, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x73, 0x74,
0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x66, 0x70, 0x6c,
0x61, 0x6e, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74,
0x65, 0x70, 0x73, 0x1a, 0x74, 0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x27, 0x0a, 0x0e, 0x61,
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f,
0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c,
0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48,
0x00, 0x52, 0x0a, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a,
0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x1b, 0x0a, 0x09, 0x49, 0x6d, 0x70,
0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a,
0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45,
0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52, 0x45,
0x53, 0x48, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x06, 0x41, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a, 0x0a,
0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41,
0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12,
0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44,
0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54,
0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48,
0x45, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x2a, 0xc8, 0x03, 0x0a, 0x1c,
0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04,
0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43,
0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45,
0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42,
0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52,
0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43,
0x41, 0x4e, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x25,
0x0a, 0x21, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45,
0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e,
0x46, 0x49, 0x47, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f,
0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52, 0x45,
0x50, 0x45, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x45,
0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x55,
0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45,
0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41, 0x43,
0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45, 0x54,
0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x44,
0x55, 0x4c, 0x45, 0x10, 0x08, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45,
0x5f, 0x42, 0x59, 0x5f, 0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x53, 0x10, 0x09, 0x12, 0x1f,
0x0a, 0x1b, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43,
0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x12,
0x23, 0x0a, 0x1f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f,
0x44, 0x45, 0x50, 0x45, 0x4e, 0x44, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49,
0x4e, 0x47, 0x10, 0x0b, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43,
0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45,
0x44, 0x10, 0x0d, 0x12, 0x21, 0x0a, 0x1d, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45,
0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x41,
0x52, 0x47, 0x45, 0x54, 0x10, 0x0c, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74,
0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (

View File

@ -253,6 +253,7 @@ message CheckResults {
RESOURCE = 1;
OUTPUT_VALUE = 2;
CHECK = 3;
INPUT_VARIABLE = 4;
}
message ObjectResult {

View File

@ -120,6 +120,8 @@ func readTfplan(r io.Reader) (*plans.Plan, error) {
objKind = addrs.CheckableOutputValue
case planproto.CheckResults_CHECK:
objKind = addrs.CheckableCheck
case planproto.CheckResults_INPUT_VARIABLE:
objKind = addrs.CheckableInputVariable
default:
return nil, fmt.Errorf("aggregate check results for %s have unsupported object kind %s", rawCRs.ConfigAddr, objKind)
}
@ -545,6 +547,8 @@ func writeTfplan(plan *plans.Plan, w io.Writer) error {
pcrs.Kind = planproto.CheckResults_OUTPUT_VALUE
case addrs.CheckableCheck:
pcrs.Kind = planproto.CheckResults_CHECK
case addrs.CheckableInputVariable:
pcrs.Kind = planproto.CheckResults_INPUT_VARIABLE
default:
return fmt.Errorf("checkable configuration %s has unsupported object type kind %s", configElem.Key, kind)
}

View File

@ -643,6 +643,8 @@ func decodeCheckableObjectKindV4(in string) addrs.CheckableKind {
return addrs.CheckableOutputValue
case "check":
return addrs.CheckableCheck
case "var":
return addrs.CheckableInputVariable
default:
// We'll treat anything else as invalid just as a concession to
// forward-compatible parsing, in case a later version of Terraform
@ -659,6 +661,8 @@ func encodeCheckableObjectKindV4(in addrs.CheckableKind) string {
return "output"
case addrs.CheckableCheck:
return "check"
case addrs.CheckableInputVariable:
return "var"
default:
panic(fmt.Sprintf("unsupported checkable object kind %s", in))
}

View File

@ -10,12 +10,14 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/checks"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)
func prepareFinalInputVariableValue(addr addrs.AbsInputVariableInstance, raw *InputValue, cfg *configs.Variable) (cty.Value, tfdiags.Diagnostics) {
@ -202,6 +204,16 @@ func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *config
}
log.Printf("[TRACE] evalVariableValidations: validating %s", addr)
checkState := ctx.Checks()
if !checkState.ConfigHasChecks(addr.ConfigCheckable()) {
// We have nothing to do if this object doesn't have any checks,
// but the "rules" slice should agree that we don't.
if ct := len(config.Validations); ct != 0 {
panic(fmt.Sprintf("check state says that %s should have no rules, but it has %d", addr, ct))
}
return diags
}
// Variable nodes evaluate in the parent module to where they were declared
// because the value expression (n.Expr, if set) comes from the calling
// "module" block in the parent module.
@ -229,13 +241,28 @@ func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *config
Functions: ctx.EvaluationScope(nil, nil, EvalDataForNoInstanceKey).Functions(),
}
for _, validation := range config.Validations {
for ix, validation := range config.Validations {
result, ruleDiags := evalVariableValidation(validation, hclCtx, addr, config, expr)
diags = diags.Append(ruleDiags)
log.Printf("[TRACE] evalVariableValidations: %s status is now %s", addr, result.Status)
if result.Status == checks.StatusFail {
checkState.ReportCheckFailure(addr, addrs.InputValidation, ix, result.FailureMessage)
} else {
checkState.ReportCheckResult(addr, addrs.InputValidation, ix, result.Status)
}
}
return diags
}
func evalVariableValidation(validation *configs.CheckRule, hclCtx *hcl.EvalContext, addr addrs.AbsInputVariableInstance, config *configs.Variable, expr hcl.Expression) (checkResult, tfdiags.Diagnostics) {
const errInvalidCondition = "Invalid variable validation result"
const errInvalidValue = "Invalid value for variable"
var ruleDiags tfdiags.Diagnostics
var diags tfdiags.Diagnostics
result, moreDiags := validation.Condition.Value(hclCtx)
ruleDiags = ruleDiags.Append(moreDiags)
diags = diags.Append(moreDiags)
errorValue, errorDiags := validation.ErrorMessage.Value(hclCtx)
// The following error handling is a workaround to preserve backwards
@ -286,17 +313,16 @@ func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *config
// We want to either report the original diagnostics if the
// fallback failed, or the warning generated above if it succeeded.
ruleDiags = ruleDiags.Append(errorDiags)
diags = diags.Append(errorDiags)
}
diags = diags.Append(ruleDiags)
if ruleDiags.HasErrors() {
log.Printf("[TRACE] evalVariableValidations: %s rule %s check rule evaluation failed: %s", addr, validation.DeclRange, ruleDiags.Err().Error())
if diags.HasErrors() {
log.Printf("[TRACE] evalVariableValidations: %s rule %s check rule evaluation failed: %s", addr, validation.DeclRange, diags.Err().Error())
}
if !result.IsKnown() {
log.Printf("[TRACE] evalVariableValidations: %s rule %s condition value is unknown, so skipping validation for now", addr, validation.DeclRange)
continue // We'll wait until we've learned more, then.
return checkResult{Status: checks.StatusUnknown}, diags // We'll wait until we've learned more, then.
}
if result.IsNull() {
diags = diags.Append(&hcl.Diagnostic{
@ -307,7 +333,7 @@ func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *config
Expression: validation.Condition,
EvalContext: hclCtx,
})
continue
return checkResult{Status: checks.StatusError}, diags
}
var err error
result, err = convert.Convert(result, cty.Bool)
@ -320,16 +346,17 @@ func evalVariableValidations(addr addrs.AbsInputVariableInstance, config *config
Expression: validation.Condition,
EvalContext: hclCtx,
})
continue
return checkResult{Status: checks.StatusError}, diags
}
// Validation condition may be marked if the input variable is bound to
// a sensitive value. This is irrelevant to the validation process, so
// we discard the marks now.
result, _ = result.Unmark()
status := checks.StatusForCtyValue(result)
if result.True() {
continue
if status != checks.StatusFail {
return checkResult{Status: status}, diags
}
var errorMessage string
@ -391,7 +418,9 @@ You can correct this by removing references to sensitive values, or by carefully
EvalContext: hclCtx,
})
}
}
return diags
return checkResult{
Status: status,
FailureMessage: errorMessage,
}, diags
}

View File

@ -12,6 +12,7 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/checks"
"github.com/hashicorp/terraform/internal/lang"
"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/hashicorp/terraform/internal/tfdiags"
@ -1107,12 +1108,14 @@ func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) {
given cty.Value
wantErr []string
wantWarn []string
status checks.Status
}{
// Valid variable validation declaration, assigned value which passes
// the condition generates no diagnostics.
{
varName: "valid",
given: cty.StringVal("foo"),
status: checks.StatusPass,
},
// Assigning a value which fails the condition generates an error
// message with the expression successfully evaluated.
@ -1123,6 +1126,7 @@ func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) {
"Invalid value for variable",
"Valid template string bar",
},
status: checks.StatusFail,
},
// Invalid variable validation declaration due to an unparseable
// template string. Assigning a value which passes the condition
@ -1134,6 +1138,7 @@ func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) {
"Validation error message expression is invalid",
"Missing expression; Expected the start of an expression, but found the end of the file.",
},
status: checks.StatusPass,
},
// Assigning a value which fails the condition generates an error
// message including the configured string interpreted as a literal
@ -1149,6 +1154,7 @@ func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) {
"Validation error message expression is invalid",
"Missing expression; Expected the start of an expression, but found the end of the file.",
},
status: checks.StatusFail,
},
}
@ -1173,11 +1179,17 @@ func TestEvalVariableValidations_jsonErrorMessageEdgeCase(t *testing.T) {
}
return test.given
}
ctx.ChecksState = checks.NewState(cfg)
ctx.ChecksState.ReportCheckableObjects(varAddr.ConfigCheckable(), addrs.MakeSet[addrs.Checkable](varAddr))
gotDiags := evalVariableValidations(
varAddr, varCfg, nil, ctx,
)
if ctx.ChecksState.ObjectCheckStatus(varAddr) != test.status {
t.Errorf("expected check result %s but instead %s", test.status, ctx.ChecksState.ObjectCheckStatus(varAddr))
}
if len(test.wantErr) == 0 && len(test.wantWarn) == 0 {
if len(gotDiags) > 0 {
t.Errorf("no diags expected, got %s", gotDiags.Err().Error())
@ -1258,12 +1270,14 @@ variable "bar" {
varName string
given cty.Value
wantErr []string
status checks.Status
}{
// Validations pass on a sensitive variable with an error message which
// would generate a sensitive value
{
varName: "foo",
given: cty.StringVal("boop"),
status: checks.StatusPass,
},
// Assigning a value which fails the condition generates a sensitive
// error message, which is elided and generates another error
@ -1275,12 +1289,14 @@ variable "bar" {
"The error message included a sensitive value, so it will not be displayed.",
"Error message refers to sensitive values",
},
status: checks.StatusFail,
},
// Validations pass on a sensitive variable with a correctly defined
// error message
{
varName: "bar",
given: cty.StringVal("boop"),
status: checks.StatusPass,
},
// Assigning a value which fails the condition generates a nonsensitive
// error message, which is displayed
@ -1291,6 +1307,7 @@ variable "bar" {
"Invalid value for variable",
"Bar must be 4 characters, not 3.",
},
status: checks.StatusFail,
},
}
@ -1319,11 +1336,17 @@ variable "bar" {
return test.given
}
}
ctx.ChecksState = checks.NewState(cfg)
ctx.ChecksState.ReportCheckableObjects(varAddr.ConfigCheckable(), addrs.MakeSet[addrs.Checkable](varAddr))
gotDiags := evalVariableValidations(
varAddr, varCfg, nil, ctx,
)
if ctx.ChecksState.ObjectCheckStatus(varAddr) != test.status {
t.Errorf("expected check result %s but instead %s", test.status, ctx.ChecksState.ObjectCheckStatus(varAddr))
}
if len(test.wantErr) == 0 {
if len(gotDiags) > 0 {
t.Errorf("no diags expected, got %s", gotDiags.Err().Error())

View File

@ -67,8 +67,8 @@ func (b *EvalGraphBuilder) Steps() []GraphTransformer {
},
// Add dynamic values
&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
&ModuleVariableTransformer{Config: b.Config},
&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues, Planning: true},
&ModuleVariableTransformer{Config: b.Config, Planning: true},
&LocalTransformer{Config: b.Config},
&OutputTransformer{
Config: b.Config,

View File

@ -128,8 +128,8 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
},
// Add dynamic values
&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
&ModuleVariableTransformer{Config: b.Config},
&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues, Planning: true},
&ModuleVariableTransformer{Config: b.Config, Planning: true},
&LocalTransformer{Config: b.Config},
&OutputTransformer{
Config: b.Config,

View File

@ -25,6 +25,10 @@ type nodeExpandModuleVariable struct {
Module addrs.Module
Config *configs.Variable
Expr hcl.Expression
// Planning must be set to true when building a planning graph, and must be
// false when building an apply graph.
Planning bool
}
var (
@ -44,10 +48,27 @@ func (n *nodeExpandModuleVariable) temporaryValue() bool {
func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
var g Graph
// If this variable has preconditions, we need to report these checks now.
//
// We should only do this during planning as the apply phase starts with
// all the same checkable objects that were registered during the plan.
var checkableAddrs addrs.Set[addrs.Checkable]
if n.Planning {
if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(n.Module)) {
checkableAddrs = addrs.MakeSet[addrs.Checkable]()
}
}
expander := ctx.InstanceExpander()
for _, module := range expander.ExpandModule(n.Module) {
addr := n.Addr.Absolute(module)
if checkableAddrs != nil {
checkableAddrs.Add(addr)
}
o := &nodeModuleVariable{
Addr: n.Addr.Absolute(module),
Addr: addr,
Config: n.Config,
Expr: n.Expr,
ModuleInstance: module,
@ -55,6 +76,11 @@ func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error
g.Add(o)
}
addRootNodeToGraph(&g)
if checkableAddrs != nil {
ctx.Checks().ReportCheckableObjects(n.Addr.InModule(n.Module), checkableAddrs)
}
return &g, nil
}

View File

@ -6,11 +6,12 @@ package terraform
import (
"log"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/dag"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
)
// NodeRootVariable represents a root variable input.
@ -24,6 +25,10 @@ type NodeRootVariable struct {
// converted or validated, and can be nil for a variable that isn't
// set at all.
RawValue *InputValue
// Planning must be set to true when building a planning graph, and must be
// false when building an apply graph.
Planning bool
}
var (
@ -82,6 +87,14 @@ func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) tfdiags.Di
}
}
if n.Planning {
if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(addrs.RootModule)) {
ctx.Checks().ReportCheckableObjects(
n.Addr.InModule(addrs.RootModule),
addrs.MakeSet[addrs.Checkable](n.Addr.Absolute(addrs.RootModuleInstance)))
}
}
finalVal, moreDiags := prepareFinalInputVariableValue(
addr,
givenVal,

View File

@ -11,6 +11,7 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/checks"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/lang"
)
@ -115,8 +116,17 @@ func TestNodeRootVariableExecute(t *testing.T) {
Value: cty.StringVal("5"),
SourceType: ValueFromUnknown,
},
Planning: true,
}
ctx.ChecksState = checks.NewState(&configs.Config{
Module: &configs.Module{
Variables: map[string]*configs.Variable{
"foo": n.Config,
},
},
})
diags := n.Execute(ctx, walkApply)
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
@ -134,6 +144,9 @@ func TestNodeRootVariableExecute(t *testing.T) {
// as part of preparing the "final value".
t.Errorf("wrong value for ctx.SetRootModuleArgument\ngot: %#v\nwant: %#v", got, want)
}
if status := ctx.Checks().ObjectCheckStatus(n.Addr.Absolute(addrs.RootModuleInstance)); status != checks.StatusPass {
t.Errorf("expected checks to pass but go %s instead", status)
}
})
}

View File

@ -6,11 +6,13 @@ package terraform
import (
"fmt"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/configs"
)
@ -26,6 +28,10 @@ import (
// steps for validating module blocks, separate from this transform.
type ModuleVariableTransformer struct {
Config *configs.Config
// Planning must be set to true when building a planning graph, and must be
// false when building an apply graph.
Planning bool
}
func (t *ModuleVariableTransformer) Transform(g *Graph) error {
@ -107,6 +113,7 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs
Module: c.Path,
Config: v,
Expr: expr,
Planning: t.Planning,
}
g.Add(node)
}

View File

@ -18,6 +18,10 @@ type RootVariableTransformer struct {
Config *configs.Config
RawValues InputValues
// Planning must be set to true when building a planning graph, and must be
// false when building an apply graph.
Planning bool
}
func (t *RootVariableTransformer) Transform(g *Graph) error {
@ -38,6 +42,7 @@ func (t *RootVariableTransformer) Transform(g *Graph) error {
},
Config: v,
RawValue: t.RawValues[v.Name],
Planning: t.Planning,
}
g.Add(node)
}