Checks: Refactor existing check addrs and add new check block addr (#32733)

* Add support for scoped resources

* refactor existing checks addrs and add check block addr

* address comments
This commit is contained in:
Liam Cervante 2023-03-23 09:04:21 +01:00 committed by GitHub
parent d53cb81bed
commit 87c457781d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 446 additions and 272 deletions

View File

@ -1,251 +1,131 @@
package addrs
import (
"fmt"
import "fmt"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/tfdiags"
)
// Check is the address of a check rule within a checkable object.
// Check is the address of a check block within a module.
//
// This represents the check rule globally within a configuration, and is used
// during graph evaluation to identify a condition result object to update with
// the result of check rule evaluation.
//
// The check address is not distinct from resource traversals, and check rule
// values are not intended to be available to the language, so the address is
// not Referenceable.
//
// Note also that the check address is only relevant within the scope of a run,
// as reordering check blocks between runs will result in their addresses
// changing. Check is therefore for internal use only and should not be exposed
// in durable artifacts such as state snapshots.
// For now, checks do not support meta arguments such as "count" or "for_each"
// so this address uniquely describes a single check within a module.
type Check struct {
Container Checkable
Type CheckType
Index int
}
func NewCheck(container Checkable, typ CheckType, index int) Check {
return Check{
Container: container,
Type: typ,
Index: index,
}
referenceable
Name string
}
func (c Check) String() string {
container := c.Container.String()
switch c.Type {
case ResourcePrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
case ResourcePostcondition:
return fmt.Sprintf("%s.postcondition[%d]", container, c.Index)
case OutputPrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
default:
// This should not happen
return fmt.Sprintf("%s.condition[%d]", container, c.Index)
return fmt.Sprintf("check.%s", c.Name)
}
// InModule returns a ConfigCheck from the receiver and the given module
// address.
func (c Check) InModule(modAddr Module) ConfigCheck {
return ConfigCheck{
Module: modAddr,
Check: c,
}
}
// Absolute returns an AbsCheck from the receiver and the given module instance
// address.
func (c Check) Absolute(modAddr ModuleInstance) AbsCheck {
return AbsCheck{
Module: modAddr,
Check: c,
}
}
func (c Check) Equal(o Check) bool {
return c.Name == o.Name
}
func (c Check) UniqueKey() UniqueKey {
return checkKey{
ContainerKey: c.Container.UniqueKey(),
Type: c.Type,
Index: c.Index,
}
return c // A Check is its own UniqueKey
}
type checkKey struct {
ContainerKey UniqueKey
Type CheckType
Index int
}
func (c Check) uniqueKeySigil() {}
func (k checkKey) uniqueKeySigil() {}
// CheckType describes a category of check. We use this only to establish
// uniqueness for Check values, and do not expose this concept of "check types"
// (which is subject to change in future) in any durable artifacts such as
// state snapshots.
// ConfigCheck is an address for a check block within a configuration.
//
// (See [CheckableKind] for an enumeration that we _do_ use externally, to
// describe the type of object being checked rather than the type of the check
// itself.)
type CheckType int
// This contains a Check address and a Module address, meaning this describes
// a check block within the entire configuration.
type ConfigCheck struct {
Module Module
Check Check
}
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckType check.go
var _ ConfigCheckable = ConfigCheck{}
const (
InvalidCondition CheckType = 0
ResourcePrecondition CheckType = 1
ResourcePostcondition CheckType = 2
OutputPrecondition CheckType = 3
)
func (c ConfigCheck) UniqueKey() UniqueKey {
return configCheckUniqueKey(c.String())
}
// Description returns a human-readable description of the check type. This is
// presented in the user interface through a diagnostic summary.
func (c CheckType) Description() string {
switch c {
case ResourcePrecondition:
return "Resource precondition"
case ResourcePostcondition:
return "Resource postcondition"
case OutputPrecondition:
return "Module output value precondition"
default:
// This should not happen
return "Condition"
func (c ConfigCheck) configCheckableSigil() {}
func (c ConfigCheck) CheckableKind() CheckableKind {
return CheckableCheck
}
func (c ConfigCheck) String() string {
if len(c.Module) == 0 {
return c.Check.String()
}
return fmt.Sprintf("%s.%s", c.Module, c.Check)
}
// Checkable is an interface implemented by all address types that can contain
// condition blocks.
type Checkable interface {
UniqueKeyer
checkableSigil()
// Check returns the address of an individual check rule of a specified
// type and index within this checkable container.
Check(CheckType, int) Check
// ConfigCheckable returns the address of the configuration construct that
// this Checkable belongs to.
//
// Checkable objects can potentially be dynamically declared during a
// plan operation using constructs like resource for_each, and so
// ConfigCheckable gives us a way to talk about the static containers
// those dynamic objects belong to, in case we wish to group together
// dynamic checkable objects into their static checkable for reporting
// purposes.
ConfigCheckable() ConfigCheckable
CheckableKind() CheckableKind
String() string
}
var (
_ Checkable = AbsResourceInstance{}
_ Checkable = AbsOutputValue{}
)
// CheckableKind describes the different kinds of checkable objects.
type CheckableKind rune
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckableKind check.go
const (
CheckableKindInvalid CheckableKind = 0
CheckableResource CheckableKind = 'R'
CheckableOutputValue CheckableKind = 'O'
)
// ConfigCheckable is an interfaces implemented by address types that represent
// configuration constructs that can have Checkable addresses associated with
// them.
// AbsCheck is an absolute address for a check block under a given module path.
//
// This address type therefore in a sense represents a container for zero or
// more checkable objects all declared by the same configuration construct,
// so that we can talk about these groups of checkable objects before we're
// ready to decide how many checkable objects belong to each one.
type ConfigCheckable interface {
UniqueKeyer
configCheckableSigil()
CheckableKind() CheckableKind
String() string
// This contains an actual ModuleInstance address (compared to the Module within
// a ConfigCheck), meaning this uniquely describes a check block within the
// entire configuration after any "count" or "foreach" meta arguments have been
// evaluated on the containing module.
type AbsCheck struct {
Module ModuleInstance
Check Check
}
var (
_ ConfigCheckable = ConfigResource{}
_ ConfigCheckable = ConfigOutputValue{}
)
var _ Checkable = AbsCheck{}
// ParseCheckableStr attempts to parse the given string as a Checkable address
// of the given kind.
func (c AbsCheck) UniqueKey() UniqueKey {
return absCheckUniqueKey(c.String())
}
func (c AbsCheck) checkableSigil() {}
// CheckRule returns an address for a given rule type within the check block.
//
// This should be the opposite of Checkable.String for any Checkable address
// type, as long as "kind" is set to the value returned by the address's
// CheckableKind method.
//
// We do not typically expect users to write out checkable addresses as input,
// but we use them as part of some of our wire formats for persisting check
// results between runs.
func ParseCheckableStr(kind CheckableKind, src string) (Checkable, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(src), "", hcl.InitialPos)
diags = diags.Append(parseDiags)
if parseDiags.HasErrors() {
return nil, diags
}
path, remain, diags := parseModuleInstancePrefix(traversal)
if diags.HasErrors() {
return nil, diags
}
if remain.IsRelative() {
// (relative means that there's either nothing left or what's next isn't an identifier)
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Module path must be followed by either a resource instance address or an output value address.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
// We use "kind" to disambiguate here because unfortunately we've
// historically never reserved "output" as a possible resource type name
// and so it is in principle possible -- albeit unlikely -- that there
// might be a resource whose type is literally "output".
switch kind {
case CheckableResource:
riAddr, moreDiags := parseResourceInstanceUnderModule(path, remain)
diags = diags.Append(moreDiags)
if diags.HasErrors() {
return nil, diags
}
return riAddr, diags
case CheckableOutputValue:
if len(remain) != 2 {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Output address must have only one attribute part after the keyword 'output', giving the name of the output value.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
if remain.RootName() != "output" {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Output address must follow the module address with the keyword 'output'.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
if step, ok := remain[1].(hcl.TraverseAttr); !ok {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Output address must have only one attribute part after the keyword 'output', giving the name of the output value.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
} else {
return OutputValue{Name: step.Name}.Absolute(path), diags
}
default:
panic(fmt.Sprintf("unsupported CheckableKind %s", kind))
// There will be at most one CheckDataResource rule within a check block (with
// an index of 0). There will be at least one, but potentially many,
// CheckAssertion rules within a check block.
func (c AbsCheck) CheckRule(typ CheckRuleType, i int) CheckRule {
return CheckRule{
Container: c,
Type: typ,
Index: i,
}
}
// ConfigCheckable returns the ConfigCheck address for this absolute reference.
func (c AbsCheck) ConfigCheckable() ConfigCheckable {
return ConfigCheck{
Module: c.Module.Module(),
Check: c.Check,
}
}
func (c AbsCheck) CheckableKind() CheckableKind {
return CheckableCheck
}
func (c AbsCheck) String() string {
if len(c.Module) == 0 {
return c.Check.String()
}
return fmt.Sprintf("%s.%s", c.Module, c.Check)
}
type configCheckUniqueKey string
func (k configCheckUniqueKey) uniqueKeySigil() {}
type absCheckUniqueKey string
func (k absCheckUniqueKey) uniqueKeySigil() {}

View File

@ -0,0 +1,105 @@
package addrs
import (
"fmt"
)
// CheckRule is the address of a check rule within a checkable object.
//
// This represents the check rule globally within a configuration, and is used
// during graph evaluation to identify a condition result object to update with
// the result of check rule evaluation.
//
// The check address is not distinct from resource traversals, and check rule
// values are not intended to be available to the language, so the address is
// not Referenceable.
//
// Note also that the check address is only relevant within the scope of a run,
// as reordering check blocks between runs will result in their addresses
// changing. CheckRule is therefore for internal use only and should not be
// exposed in durable artifacts such as state snapshots.
type CheckRule struct {
Container Checkable
Type CheckRuleType
Index int
}
func NewCheckRule(container Checkable, typ CheckRuleType, index int) CheckRule {
return CheckRule{
Container: container,
Type: typ,
Index: index,
}
}
func (c CheckRule) String() string {
container := c.Container.String()
switch c.Type {
case ResourcePrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
case ResourcePostcondition:
return fmt.Sprintf("%s.postcondition[%d]", container, c.Index)
case OutputPrecondition:
return fmt.Sprintf("%s.precondition[%d]", container, c.Index)
default:
// This should not happen
return fmt.Sprintf("%s.condition[%d]", container, c.Index)
}
}
func (c CheckRule) UniqueKey() UniqueKey {
return checkRuleKey{
ContainerKey: c.Container.UniqueKey(),
Type: c.Type,
Index: c.Index,
}
}
type checkRuleKey struct {
ContainerKey UniqueKey
Type CheckRuleType
Index int
}
func (k checkRuleKey) uniqueKeySigil() {}
// CheckRuleType describes a category of check. We use this only to establish
// uniqueness for Check values, and do not expose this concept of "check types"
// (which is subject to change in future) in any durable artifacts such as
// state snapshots.
//
// (See [CheckableKind] for an enumeration that we _do_ use externally, to
// describe the type of object being checked rather than the type of the check
// itself.)
type CheckRuleType int
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckRuleType check_rule.go
const (
InvalidCondition CheckRuleType = 0
ResourcePrecondition CheckRuleType = 1
ResourcePostcondition CheckRuleType = 2
OutputPrecondition CheckRuleType = 3
CheckDataResource CheckRuleType = 4
CheckAssertion CheckRuleType = 5
)
// Description returns a human-readable description of the check type. This is
// presented in the user interface through a diagnostic summary.
func (c CheckRuleType) Description() string {
switch c {
case ResourcePrecondition:
return "Resource precondition"
case ResourcePostcondition:
return "Resource postcondition"
case OutputPrecondition:
return "Module output value precondition"
case CheckDataResource:
return "Check block data resource"
case CheckAssertion:
return "Check block assertion"
default:
// This should not happen
return "Condition"
}
}

182
internal/addrs/checkable.go Normal file
View File

@ -0,0 +1,182 @@
package addrs
import (
"fmt"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/tfdiags"
)
// Checkable is an interface implemented by all address types that can contain
// condition blocks.
type Checkable interface {
UniqueKeyer
checkableSigil()
// CheckRule returns the address of an individual check rule of a specified
// type and index within this checkable container.
CheckRule(CheckRuleType, int) CheckRule
// ConfigCheckable returns the address of the configuration construct that
// this Checkable belongs to.
//
// Checkable objects can potentially be dynamically declared during a
// plan operation using constructs like resource for_each, and so
// ConfigCheckable gives us a way to talk about the static containers
// those dynamic objects belong to, in case we wish to group together
// dynamic checkable objects into their static checkable for reporting
// purposes.
ConfigCheckable() ConfigCheckable
CheckableKind() CheckableKind
String() string
}
var (
_ Checkable = AbsResourceInstance{}
_ Checkable = AbsOutputValue{}
)
// CheckableKind describes the different kinds of checkable objects.
type CheckableKind rune
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckableKind checkable.go
const (
CheckableKindInvalid CheckableKind = 0
CheckableResource CheckableKind = 'R'
CheckableOutputValue CheckableKind = 'O'
CheckableCheck CheckableKind = 'C'
)
// ConfigCheckable is an interfaces implemented by address types that represent
// configuration constructs that can have Checkable addresses associated with
// them.
//
// This address type therefore in a sense represents a container for zero or
// more checkable objects all declared by the same configuration construct,
// so that we can talk about these groups of checkable objects before we're
// ready to decide how many checkable objects belong to each one.
type ConfigCheckable interface {
UniqueKeyer
configCheckableSigil()
CheckableKind() CheckableKind
String() string
}
var (
_ ConfigCheckable = ConfigResource{}
_ ConfigCheckable = ConfigOutputValue{}
)
// ParseCheckableStr attempts to parse the given string as a Checkable address
// of the given kind.
//
// This should be the opposite of Checkable.String for any Checkable address
// type, as long as "kind" is set to the value returned by the address's
// CheckableKind method.
//
// We do not typically expect users to write out checkable addresses as input,
// but we use them as part of some of our wire formats for persisting check
// results between runs.
func ParseCheckableStr(kind CheckableKind, src string) (Checkable, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(src), "", hcl.InitialPos)
diags = diags.Append(parseDiags)
if parseDiags.HasErrors() {
return nil, diags
}
path, remain, diags := parseModuleInstancePrefix(traversal)
if diags.HasErrors() {
return nil, diags
}
if remain.IsRelative() {
// (relative means that there's either nothing left or what's next isn't an identifier)
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: "Module path must be followed by either a resource instance address or an output value address.",
Subject: remain.SourceRange().Ptr(),
})
return nil, diags
}
getCheckableName := func(keyword string, descriptor string) (string, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var name string
if len(remain) != 2 {
diags = diags.Append(hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: fmt.Sprintf("%s address must have only one attribute part after the keyword '%s', giving the name of the %s.", cases.Title(language.English, cases.NoLower).String(keyword), keyword, descriptor),
Subject: remain.SourceRange().Ptr(),
})
}
if remain.RootName() != keyword {
diags = diags.Append(hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: fmt.Sprintf("%s address must follow the module address with the keyword '%s'.", cases.Title(language.English, cases.NoLower).String(keyword), keyword),
Subject: remain.SourceRange().Ptr(),
})
}
if step, ok := remain[1].(hcl.TraverseAttr); !ok {
diags = diags.Append(hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid checkable address",
Detail: fmt.Sprintf("%s address must have only one attribute part after the keyword '%s', giving the name of the %s.", cases.Title(language.English, cases.NoLower).String(keyword), keyword, descriptor),
Subject: remain.SourceRange().Ptr(),
})
} else {
name = step.Name
}
return name, diags
}
// We use "kind" to disambiguate here because unfortunately we've
// historically never reserved "output" as a possible resource type name
// and so it is in principle possible -- albeit unlikely -- that there
// might be a resource whose type is literally "output".
switch kind {
case CheckableResource:
riAddr, moreDiags := parseResourceInstanceUnderModule(path, remain)
diags = diags.Append(moreDiags)
if diags.HasErrors() {
return nil, diags
}
return riAddr, diags
case CheckableOutputValue:
name, nameDiags := getCheckableName("output", "output value")
diags = diags.Append(nameDiags)
if diags.HasErrors() {
return nil, diags
}
return OutputValue{Name: name}.Absolute(path), diags
case CheckableCheck:
name, nameDiags := getCheckableName("check", "check block")
diags = diags.Append(nameDiags)
if diags.HasErrors() {
return nil, diags
}
return Check{Name: name}.Absolute(path), diags
default:
panic(fmt.Sprintf("unsupported CheckableKind %s", kind))
}
}

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=CheckableKind check.go"; DO NOT EDIT.
// Code generated by "stringer -type=CheckableKind checkable.go"; DO NOT EDIT.
package addrs
@ -11,22 +11,26 @@ func _() {
_ = x[CheckableKindInvalid-0]
_ = x[CheckableResource-82]
_ = x[CheckableOutputValue-79]
_ = x[CheckableCheck-67]
}
const (
_CheckableKind_name_0 = "CheckableKindInvalid"
_CheckableKind_name_1 = "CheckableOutputValue"
_CheckableKind_name_2 = "CheckableResource"
_CheckableKind_name_1 = "CheckableCheck"
_CheckableKind_name_2 = "CheckableOutputValue"
_CheckableKind_name_3 = "CheckableResource"
)
func (i CheckableKind) String() string {
switch {
case i == 0:
return _CheckableKind_name_0
case i == 79:
case i == 67:
return _CheckableKind_name_1
case i == 82:
case i == 79:
return _CheckableKind_name_2
case i == 82:
return _CheckableKind_name_3
default:
return "CheckableKind(" + strconv.FormatInt(int64(i), 10) + ")"
}

View File

@ -0,0 +1,28 @@
// Code generated by "stringer -type=CheckRuleType check_rule.go"; DO NOT EDIT.
package addrs
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[InvalidCondition-0]
_ = x[ResourcePrecondition-1]
_ = x[ResourcePostcondition-2]
_ = x[OutputPrecondition-3]
_ = x[CheckDataResource-4]
_ = x[CheckAssertion-5]
}
const _CheckRuleType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPreconditionCheckDataResourceCheckAssertion"
var _CheckRuleType_index = [...]uint8{0, 16, 36, 57, 75, 92, 106}
func (i CheckRuleType) String() string {
if i < 0 || i >= CheckRuleType(len(_CheckRuleType_index)-1) {
return "CheckRuleType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CheckRuleType_name[_CheckRuleType_index[i]:_CheckRuleType_index[i+1]]
}

View File

@ -1,26 +0,0 @@
// Code generated by "stringer -type=CheckType check.go"; DO NOT EDIT.
package addrs
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[InvalidCondition-0]
_ = x[ResourcePrecondition-1]
_ = x[ResourcePostcondition-2]
_ = x[OutputPrecondition-3]
}
const _CheckType_name = "InvalidConditionResourcePreconditionResourcePostconditionOutputPrecondition"
var _CheckType_index = [...]uint8{0, 16, 36, 57, 75}
func (i CheckType) String() string {
if i < 0 || i >= CheckType(len(_CheckType_index)-1) {
return "CheckType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CheckType_name[_CheckType_index[i]:_CheckType_index[i+1]]
}

View File

@ -5,6 +5,7 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/tfdiags"
)
@ -62,8 +63,8 @@ func (m ModuleInstance) OutputValue(name string) AbsOutputValue {
}
}
func (v AbsOutputValue) Check(t CheckType, i int) Check {
return Check{
func (v AbsOutputValue) CheckRule(t CheckRuleType, i int) CheckRule {
return CheckRule{
Container: v,
Type: t,
Index: i,

View File

@ -329,8 +329,8 @@ func (r AbsResourceInstance) AffectedAbsResource() AbsResource {
}
}
func (r AbsResourceInstance) Check(t CheckType, i int) Check {
return Check{
func (r AbsResourceInstance) CheckRule(t CheckRuleType, i int) CheckRule {
return CheckRule{
Container: r,
Type: t,
Index: i,

View File

@ -33,7 +33,7 @@ type State struct {
mu sync.Mutex
statuses addrs.Map[addrs.ConfigCheckable, *configCheckableState]
failureMsgs addrs.Map[addrs.Check, string]
failureMsgs addrs.Map[addrs.CheckRule, string]
}
// configCheckableState is an internal part of type State that represents
@ -53,7 +53,7 @@ type configCheckableState struct {
// associated with object declared by this configuration construct. Since
// checks are statically declared (even though the checkable objects
// aren't) we can compute this only from the configuration.
checkTypes map[addrs.CheckType]int
checkTypes map[addrs.CheckRuleType]int
// objects represents the set of dynamic checkable objects associated
// with this configuration construct. This is initially nil to represent
@ -64,7 +64,7 @@ type configCheckableState struct {
// The leaf Status values will initially be StatusUnknown
// and then gradually updated by Terraform Core as it visits the
// individual checkable objects and reports their status.
objects addrs.Map[addrs.Checkable, map[addrs.CheckType][]Status]
objects addrs.Map[addrs.Checkable, map[addrs.CheckRuleType][]Status]
}
// NOTE: For the "Report"-prefixed methods that we use to gradually update
@ -253,7 +253,7 @@ func (c *State) ObjectFailureMessages(addr addrs.Checkable) []string {
for checkType, checks := range checksByType {
for i, status := range checks {
if status == StatusFail {
checkAddr := addrs.NewCheck(addr, checkType, i)
checkAddr := addrs.NewCheckRule(addr, checkType, i)
msg := c.failureMsgs.Get(checkAddr)
if msg != "" {
ret = append(ret, msg)

View File

@ -42,7 +42,7 @@ func collectInitialStatuses(into addrs.Map[addrs.ConfigCheckable, *configCheckab
st := &configCheckableState{}
st.checkTypes = map[addrs.CheckType]int{
st.checkTypes = map[addrs.CheckRuleType]int{
addrs.OutputPrecondition: ct,
}
@ -63,7 +63,7 @@ func collectInitialStatusForResource(into addrs.Map[addrs.ConfigCheckable, *conf
}
st := &configCheckableState{
checkTypes: make(map[addrs.CheckType]int),
checkTypes: make(map[addrs.CheckRuleType]int),
}
if ct := len(rc.Preconditions); ct > 0 {

View File

@ -32,14 +32,14 @@ func (c *State) ReportCheckableObjects(configAddr addrs.ConfigCheckable, objectA
// At this point we pre-populate all of the check results as StatusUnknown,
// so that even if we never hear from Terraform Core again we'll still
// remember that these results were all pending.
st.objects = addrs.MakeMap[addrs.Checkable, map[addrs.CheckType][]Status]()
st.objects = addrs.MakeMap[addrs.Checkable, map[addrs.CheckRuleType][]Status]()
for _, objectAddr := range objectAddrs {
if gotConfigAddr := objectAddr.ConfigCheckable(); !addrs.Equivalent(configAddr, gotConfigAddr) {
// All of the given object addresses must belong to the specified configuration address
panic(fmt.Sprintf("%s belongs to %s, not %s", objectAddr, gotConfigAddr, configAddr))
}
checks := make(map[addrs.CheckType][]Status, len(st.checkTypes))
checks := make(map[addrs.CheckRuleType][]Status, len(st.checkTypes))
for checkType, count := range st.checkTypes {
// NOTE: This is intentionally a slice of count of the zero value
// of Status, which is StatusUnknown to represent that we don't
@ -61,7 +61,7 @@ func (c *State) ReportCheckableObjects(configAddr addrs.ConfigCheckable, objectA
//
// This method will also panic if the specified check already had a known
// status; each check should have its result reported only once.
func (c *State) ReportCheckResult(objectAddr addrs.Checkable, checkType addrs.CheckType, index int, status Status) {
func (c *State) ReportCheckResult(objectAddr addrs.Checkable, checkType addrs.CheckRuleType, index int, status Status) {
c.mu.Lock()
defer c.mu.Unlock()
@ -76,21 +76,21 @@ func (c *State) ReportCheckResult(objectAddr addrs.Checkable, checkType addrs.Ch
// situations where the check condition was itself invalid, because that
// should be represented by StatusError instead, and the error signalled via
// diagnostics as normal.
func (c *State) ReportCheckFailure(objectAddr addrs.Checkable, checkType addrs.CheckType, index int, errorMessage string) {
func (c *State) ReportCheckFailure(objectAddr addrs.Checkable, checkType addrs.CheckRuleType, index int, errorMessage string) {
c.mu.Lock()
defer c.mu.Unlock()
c.reportCheckResult(objectAddr, checkType, index, StatusFail)
if c.failureMsgs.Elems == nil {
c.failureMsgs = addrs.MakeMap[addrs.Check, string]()
c.failureMsgs = addrs.MakeMap[addrs.CheckRule, string]()
}
checkAddr := addrs.NewCheck(objectAddr, checkType, index)
checkAddr := addrs.NewCheckRule(objectAddr, checkType, index)
c.failureMsgs.Put(checkAddr, errorMessage)
}
// reportCheckResult is shared between both ReportCheckResult and
// ReportCheckFailure, and assumes its caller already holds the mutex.
func (c *State) reportCheckResult(objectAddr addrs.Checkable, checkType addrs.CheckType, index int, status Status) {
func (c *State) reportCheckResult(objectAddr addrs.Checkable, checkType addrs.CheckRuleType, index int, status Status) {
configAddr := objectAddr.ConfigCheckable()
st, ok := c.statuses.GetOk(configAddr)

View File

@ -27,7 +27,7 @@ import (
//
// If any of the rules do not pass, the returned diagnostics will contain
// errors. Otherwise, it will either be empty or contain only warnings.
func evalCheckRules(typ addrs.CheckType, rules []*configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, diagSeverity tfdiags.Severity) tfdiags.Diagnostics {
func evalCheckRules(typ addrs.CheckRuleType, rules []*configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, diagSeverity tfdiags.Severity) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
checkState := ctx.Checks()
@ -67,7 +67,7 @@ type checkResult struct {
FailureMessage string
}
func evalCheckRule(typ addrs.CheckType, rule *configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, severity hcl.DiagnosticSeverity) (checkResult, tfdiags.Diagnostics) {
func evalCheckRule(typ addrs.CheckRuleType, rule *configs.CheckRule, ctx EvalContext, self addrs.Checkable, keyData instances.RepetitionData, severity hcl.DiagnosticSeverity) (checkResult, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
const errInvalidCondition = "Invalid condition result"