terraform: start implementing interfaces for semantic checks
This commit is contained in:
parent
b48a0cc3b9
commit
21e4501edb
|
@ -0,0 +1,14 @@
|
||||||
|
package dag
|
||||||
|
|
||||||
|
// AcyclicGraph is a specialization of Graph that cannot have cycles. With
|
||||||
|
// this property, we get the property of sane graph traversal.
|
||||||
|
type AcyclicGraph struct {
|
||||||
|
*Graph
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkFunc is the callback used for walking the graph.
|
||||||
|
type WalkFunc func(Vertex)
|
||||||
|
|
||||||
|
// Walk walks the graph, calling your callback as each node is visited.
|
||||||
|
func (g *AcyclicGraph) Walk(cb WalkFunc) {
|
||||||
|
}
|
|
@ -26,9 +26,6 @@ type NamedVertex interface {
|
||||||
Name() string
|
Name() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// WalkFunc is the callback used for walking the graph.
|
|
||||||
type WalkFunc func(Vertex)
|
|
||||||
|
|
||||||
// Vertices returns the list of all the vertices in the graph.
|
// Vertices returns the list of all the vertices in the graph.
|
||||||
func (g *Graph) Vertices() []Vertex {
|
func (g *Graph) Vertices() []Vertex {
|
||||||
return g.vertices
|
return g.vertices
|
||||||
|
@ -81,10 +78,6 @@ func (g *Graph) Connect(edge Edge) {
|
||||||
s.Add(source)
|
s.Add(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk walks the graph, calling your callback as each node is visited.
|
|
||||||
func (g *Graph) Walk(cb WalkFunc) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// String outputs some human-friendly output for the graph structure.
|
// String outputs some human-friendly output for the graph structure.
|
||||||
func (g *Graph) String() string {
|
func (g *Graph) String() string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
|
@ -39,8 +39,12 @@ func Graph2(mod *module.Tree) (*dag.Graph, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all the modules out
|
// Write all the modules out
|
||||||
|
children := mod.Children()
|
||||||
for _, m := range config.Modules {
|
for _, m := range config.Modules {
|
||||||
nodes = append(nodes, &GraphNodeConfigModule{Module: m})
|
nodes = append(nodes, &GraphNodeConfigModule{
|
||||||
|
Module: m,
|
||||||
|
Tree: children[m.Name],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the full map of the var names to the nodes.
|
// Build the full map of the var names to the nodes.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
|
"github.com/hashicorp/terraform/config/module"
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ type graphNodeConfig interface {
|
||||||
// GraphNodeConfigModule represents a module within the configuration graph.
|
// GraphNodeConfigModule represents a module within the configuration graph.
|
||||||
type GraphNodeConfigModule struct {
|
type GraphNodeConfigModule struct {
|
||||||
Module *config.Module
|
Module *config.Module
|
||||||
|
Tree *module.Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *GraphNodeConfigModule) Name() string {
|
func (n *GraphNodeConfigModule) Name() string {
|
||||||
|
|
|
@ -3,9 +3,70 @@ package terraform
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GraphSemanticChecker is the interface that semantic checks across
|
||||||
|
// the entire Terraform graph implement.
|
||||||
|
//
|
||||||
|
// The graph should NOT be modified by the semantic checker.
|
||||||
|
type GraphSemanticChecker interface {
|
||||||
|
Check(*dag.Graph) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnorderedSemanticCheckRunner is an implementation of GraphSemanticChecker
|
||||||
|
// that runs a list of SemanticCheckers against the vertices of the graph
|
||||||
|
// in no specified order.
|
||||||
|
type UnorderedSemanticCheckRunner struct {
|
||||||
|
Checks []SemanticChecker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *UnorderedSemanticCheckRunner) Check(g *dag.Graph) error {
|
||||||
|
var err error
|
||||||
|
for _, v := range g.Vertices() {
|
||||||
|
for _, check := range sc.Checks {
|
||||||
|
if e := check.Check(g, v); e != nil {
|
||||||
|
err = multierror.Append(err, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemanticChecker is the interface that semantic checks across the
|
||||||
|
// Terraform graph implement. Errors are accumulated. Even after an error
|
||||||
|
// is returned, child vertices in the graph will still be visited.
|
||||||
|
//
|
||||||
|
// The graph should NOT be modified by the semantic checker.
|
||||||
|
//
|
||||||
|
// The order in which vertices are visited is left unspecified, so the
|
||||||
|
// semantic checks should not rely on that.
|
||||||
|
type SemanticChecker interface {
|
||||||
|
Check(*dag.Graph, dag.Vertex) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemanticCheckModulesExist is an implementation of SemanticChecker that
|
||||||
|
// verifies that all the modules that are referenced in the graph exist.
|
||||||
|
type SemanticCheckModulesExist struct{}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
func (*SemanticCheckModulesExist) Check(g *dag.Graph, v dag.Vertex) error {
|
||||||
|
mn, ok := v.(*GraphNodeConfigModule)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if mn.Tree == nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"module '%s' not found", mn.Module.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// smcUserVariables does all the semantic checks to verify that the
|
// smcUserVariables does all the semantic checks to verify that the
|
||||||
// variables given satisfy the configuration itself.
|
// variables given satisfy the configuration itself.
|
||||||
func smcUserVariables(c *config.Config, vs map[string]string) []error {
|
func smcUserVariables(c *config.Config, vs map[string]string) []error {
|
||||||
|
|
Loading…
Reference in New Issue