Merge pull request #30656 from hashicorp/jbardin/always-validate

Always validate the graph
This commit is contained in:
James Bardin 2022-03-11 10:37:30 -05:00 committed by GitHub
commit 45e2a410f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 21 additions and 54 deletions

View File

@ -110,7 +110,6 @@ func (c *Context) applyGraph(plan *plans.Plan, config *configs.Config, validate
Plugins: c.plugins, Plugins: c.plugins,
Targets: plan.TargetAddrs, Targets: plan.TargetAddrs,
ForceReplace: plan.ForceReplaceAddrs, ForceReplace: plan.ForceReplaceAddrs,
Validate: validate,
}).Build(addrs.RootModuleInstance) }).Build(addrs.RootModuleInstance)
diags = diags.Append(moreDiags) diags = diags.Append(moreDiags)
if moreDiags.HasErrors() { if moreDiags.HasErrors() {

View File

@ -21,8 +21,7 @@ type GraphBuilder interface {
// series of transforms and (optionally) validates the graph is a valid // series of transforms and (optionally) validates the graph is a valid
// structure. // structure.
type BasicGraphBuilder struct { type BasicGraphBuilder struct {
Steps []GraphTransformer Steps []GraphTransformer
Validate bool
// Optional name to add to the graph debug log // Optional name to add to the graph debug log
Name string Name string
} }
@ -56,13 +55,10 @@ func (b *BasicGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Di
} }
} }
// Validate the graph structure if err := g.Validate(); err != nil {
if b.Validate { log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String())
if err := g.Validate(); err != nil { diags = diags.Append(err)
log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String()) return nil, diags
diags = diags.Append(err)
return nil, diags
}
} }
return g, diags return g, diags

View File

@ -46,17 +46,13 @@ type ApplyGraphBuilder struct {
// The apply step refers to these as part of verifying that the planned // The apply step refers to these as part of verifying that the planned
// actions remain consistent between plan and apply. // actions remain consistent between plan and apply.
ForceReplace []addrs.AbsResourceInstance ForceReplace []addrs.AbsResourceInstance
// Validate will do structural validation of the graph.
Validate bool
} }
// See GraphBuilder // See GraphBuilder
func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
return (&BasicGraphBuilder{ return (&BasicGraphBuilder{
Steps: b.Steps(), Steps: b.Steps(),
Validate: b.Validate, Name: "ApplyGraphBuilder",
Name: "ApplyGraphBuilder",
}).Build(path) }).Build(path)
} }

View File

@ -35,9 +35,6 @@ type DestroyPlanGraphBuilder struct {
// Targets are resources to target // Targets are resources to target
Targets []addrs.Targetable Targets []addrs.Targetable
// Validate will do structural validation of the graph.
Validate bool
// If set, skipRefresh will cause us stop skip refreshing any existing // If set, skipRefresh will cause us stop skip refreshing any existing
// resource instances as part of our planning. This will cause us to fail // resource instances as part of our planning. This will cause us to fail
// to detect if an object has already been deleted outside of Terraform. // to detect if an object has already been deleted outside of Terraform.
@ -47,9 +44,8 @@ type DestroyPlanGraphBuilder struct {
// See GraphBuilder // See GraphBuilder
func (b *DestroyPlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { func (b *DestroyPlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
return (&BasicGraphBuilder{ return (&BasicGraphBuilder{
Steps: b.Steps(), Steps: b.Steps(),
Validate: b.Validate, Name: "DestroyPlanGraphBuilder",
Name: "DestroyPlanGraphBuilder",
}).Build(path) }).Build(path)
} }

View File

@ -43,9 +43,8 @@ type EvalGraphBuilder struct {
// See GraphBuilder // See GraphBuilder
func (b *EvalGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { func (b *EvalGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
return (&BasicGraphBuilder{ return (&BasicGraphBuilder{
Steps: b.Steps(), Steps: b.Steps(),
Validate: true, Name: "EvalGraphBuilder",
Name: "EvalGraphBuilder",
}).Build(path) }).Build(path)
} }

View File

@ -30,9 +30,8 @@ type ImportGraphBuilder struct {
// Build builds the graph according to the steps returned by Steps. // Build builds the graph according to the steps returned by Steps.
func (b *ImportGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { func (b *ImportGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
return (&BasicGraphBuilder{ return (&BasicGraphBuilder{
Steps: b.Steps(), Steps: b.Steps(),
Validate: true, Name: "ImportGraphBuilder",
Name: "ImportGraphBuilder",
}).Build(path) }).Build(path)
} }

View File

@ -42,7 +42,6 @@ func TestBasicGraphBuilder_validate(t *testing.T) {
&testBasicGraphBuilderTransform{1}, &testBasicGraphBuilderTransform{1},
&testBasicGraphBuilderTransform{2}, &testBasicGraphBuilderTransform{2},
}, },
Validate: true,
} }
_, err := b.Build(addrs.RootModuleInstance) _, err := b.Build(addrs.RootModuleInstance)
@ -51,21 +50,6 @@ func TestBasicGraphBuilder_validate(t *testing.T) {
} }
} }
func TestBasicGraphBuilder_validateOff(t *testing.T) {
b := &BasicGraphBuilder{
Steps: []GraphTransformer{
&testBasicGraphBuilderTransform{1},
&testBasicGraphBuilderTransform{2},
},
Validate: false,
}
_, err := b.Build(addrs.RootModuleInstance)
if err != nil {
t.Fatalf("expected no error, got: %s", err)
}
}
type testBasicGraphBuilderTransform struct { type testBasicGraphBuilderTransform struct {
V dag.Vertex V dag.Vertex
} }

View File

@ -390,9 +390,8 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
// Build the graph // Build the graph
b := &BasicGraphBuilder{ b := &BasicGraphBuilder{
Steps: steps, Steps: steps,
Validate: true, Name: "NodePlannableResource",
Name: "NodePlannableResource",
} }
graph, diags := b.Build(ctx.Path()) graph, diags := b.Build(ctx.Path())
return graph, diags.ErrWithWarnings() return graph, diags.ErrWithWarnings()

View File

@ -46,7 +46,12 @@ func cbdTestSteps(steps []GraphTransformer) []GraphTransformer {
panic("CBDEdgeTransformer not found") panic("CBDEdgeTransformer not found")
} }
return steps[:i+1] // re-add the root node so we have a valid graph for a walk, then reduce
// the graph for less output
steps = append(steps[:i+1], &CloseRootModuleTransformer{})
steps = append(steps, &TransitiveReductionTransformer{})
return steps
} }
// remove extra nodes for easier test comparisons // remove extra nodes for easier test comparisons
@ -105,7 +110,6 @@ func TestCBDEdgeTransformer(t *testing.T) {
expected := regexp.MustCompile(strings.TrimSpace(` expected := regexp.MustCompile(strings.TrimSpace(`
(?m)test_object.A (?m)test_object.A
test_object.A \(destroy deposed \w+\) test_object.A \(destroy deposed \w+\)
test_object.A
test_object.B test_object.B
test_object.B test_object.B
test_object.A test_object.A
@ -178,11 +182,9 @@ func TestCBDEdgeTransformerMulti(t *testing.T) {
expected := regexp.MustCompile(strings.TrimSpace(` expected := regexp.MustCompile(strings.TrimSpace(`
(?m)test_object.A (?m)test_object.A
test_object.A \(destroy deposed \w+\) test_object.A \(destroy deposed \w+\)
test_object.A
test_object.C test_object.C
test_object.B test_object.B
test_object.B \(destroy deposed \w+\) test_object.B \(destroy deposed \w+\)
test_object.B
test_object.C test_object.C
test_object.C test_object.C
test_object.A test_object.A
@ -253,7 +255,6 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) {
expected := regexp.MustCompile(strings.TrimSpace(` expected := regexp.MustCompile(strings.TrimSpace(`
(?m)test_object.A (?m)test_object.A
test_object.A \(destroy deposed \w+\) test_object.A \(destroy deposed \w+\)
test_object.A
test_object.B\[0\] test_object.B\[0\]
test_object.B\[1\] test_object.B\[1\]
test_object.B\[0\] test_object.B\[0\]
@ -339,12 +340,10 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) {
expected := regexp.MustCompile(strings.TrimSpace(` expected := regexp.MustCompile(strings.TrimSpace(`
test_object.A\[0\] test_object.A\[0\]
test_object.A\[0\] \(destroy deposed \w+\) test_object.A\[0\] \(destroy deposed \w+\)
test_object.A\[0\]
test_object.B\[0\] test_object.B\[0\]
test_object.B\[1\] test_object.B\[1\]
test_object.A\[1\] test_object.A\[1\]
test_object.A\[1\] \(destroy deposed \w+\) test_object.A\[1\] \(destroy deposed \w+\)
test_object.A\[1\]
test_object.B\[0\] test_object.B\[0\]
test_object.B\[1\] test_object.B\[1\]
test_object.B\[0\] test_object.B\[0\]