mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
terraform: GraphNodeDependent
This commit is contained in:
parent
8dc4c56b2e
commit
8bf725e746
@ -51,15 +51,21 @@ func (g *Graph) Add(v dag.Vertex) dag.Vertex {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectTo is a helper to create edges between a node and a list of
|
// ConnectDependent connects a GraphNodeDependent to all of its
|
||||||
// targets by their DependableNames.
|
// GraphNodeDependables. It returns the list of dependents it was
|
||||||
func (g *Graph) ConnectTo(source dag.Vertex, target []string) []string {
|
// unable to connect to.
|
||||||
|
func (g *Graph) ConnectDependent(raw dag.Vertex) []string {
|
||||||
g.once.Do(g.init)
|
g.once.Do(g.init)
|
||||||
|
|
||||||
|
v, ok := raw.(GraphNodeDependent)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var missing []string
|
var missing []string
|
||||||
for _, t := range target {
|
for _, t := range v.DependentOn() {
|
||||||
if dest := g.dependableMap[t]; dest != nil {
|
if dest := g.dependableMap[t]; dest != nil {
|
||||||
g.Connect(dag.BasicEdge(source, dest))
|
g.Connect(dag.BasicEdge(v, dest))
|
||||||
} else {
|
} else {
|
||||||
missing = append(missing, t)
|
missing = append(missing, t)
|
||||||
}
|
}
|
||||||
@ -68,6 +74,20 @@ func (g *Graph) ConnectTo(source dag.Vertex, target []string) []string {
|
|||||||
return missing
|
return missing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConnectDependents goes through the graph, connecting all the
|
||||||
|
// GraphNodeDependents to GraphNodeDependables. This is safe to call
|
||||||
|
// multiple times.
|
||||||
|
//
|
||||||
|
// To get details on whether dependencies could be found/made, the more
|
||||||
|
// specific ConnectDependent should be used.
|
||||||
|
func (g *Graph) ConnectDependents() {
|
||||||
|
for _, v := range g.Vertices() {
|
||||||
|
if dv, ok := v.(GraphNodeDependent); ok {
|
||||||
|
g.ConnectDependent(dv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Graph) init() {
|
func (g *Graph) init() {
|
||||||
if g.Graph == nil {
|
if g.Graph == nil {
|
||||||
g.Graph = new(dag.Graph)
|
g.Graph = new(dag.Graph)
|
||||||
@ -86,3 +106,11 @@ func (g *Graph) init() {
|
|||||||
type GraphNodeDependable interface {
|
type GraphNodeDependable interface {
|
||||||
DependableName() []string
|
DependableName() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GraphNodeDependent is an interface which says that a node depends
|
||||||
|
// on another GraphNodeDependable by some name. By implementing this
|
||||||
|
// interface, Graph.ConnectDependents() can be called multiple times
|
||||||
|
// safely and efficiently.
|
||||||
|
type GraphNodeDependent interface {
|
||||||
|
DependentOn() []string
|
||||||
|
}
|
||||||
|
@ -14,10 +14,10 @@ import (
|
|||||||
type graphNodeConfig interface {
|
type graphNodeConfig interface {
|
||||||
dag.NamedVertex
|
dag.NamedVertex
|
||||||
|
|
||||||
// Variables returns the full list of variables that this node
|
// All graph nodes should be dependent on other things, and able to
|
||||||
// depends on. The values within the slice should map to the VarName()
|
// be depended on.
|
||||||
// values that are returned by any nodes.
|
GraphNodeDependable
|
||||||
Variables() []string
|
GraphNodeDependent
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeConfigModule represents a module within the configuration graph.
|
// GraphNodeConfigModule represents a module within the configuration graph.
|
||||||
@ -29,20 +29,23 @@ type GraphNodeConfigModule struct {
|
|||||||
func (n *GraphNodeConfigModule) DependableName() []string {
|
func (n *GraphNodeConfigModule) DependableName() []string {
|
||||||
return []string{n.Name()}
|
return []string{n.Name()}
|
||||||
}
|
}
|
||||||
func (n *GraphNodeConfigModule) Name() string {
|
|
||||||
return fmt.Sprintf("module.%s", n.Module.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *GraphNodeConfigModule) Variables() []string {
|
func (n *GraphNodeConfigModule) DependentOn() []string {
|
||||||
vars := n.Module.RawConfig.Variables
|
vars := n.Module.RawConfig.Variables
|
||||||
result := make([]string, 0, len(vars))
|
result := make([]string, 0, len(vars))
|
||||||
for _, v := range vars {
|
for _, v := range vars {
|
||||||
result = append(result, varNameForVar(v))
|
if vn := varNameForVar(v); vn != "" {
|
||||||
|
result = append(result, vn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *GraphNodeConfigModule) Name() string {
|
||||||
|
return fmt.Sprintf("module.%s", n.Module.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeConfigProvider represents a configured provider within the
|
// GraphNodeConfigProvider represents a configured provider within the
|
||||||
// configuration graph. These are only immediately in the graph when an
|
// configuration graph. These are only immediately in the graph when an
|
||||||
// explicit `provider` configuration block is in the configuration.
|
// explicit `provider` configuration block is in the configuration.
|
||||||
@ -54,11 +57,17 @@ func (n *GraphNodeConfigProvider) Name() string {
|
|||||||
return fmt.Sprintf("provider.%s", n.Provider.Name)
|
return fmt.Sprintf("provider.%s", n.Provider.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *GraphNodeConfigProvider) Variables() []string {
|
func (n *GraphNodeConfigProvider) DependableName() []string {
|
||||||
|
return []string{n.Name()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *GraphNodeConfigProvider) DependentOn() []string {
|
||||||
vars := n.Provider.RawConfig.Variables
|
vars := n.Provider.RawConfig.Variables
|
||||||
result := make([]string, 0, len(vars))
|
result := make([]string, 0, len(vars))
|
||||||
for _, v := range vars {
|
for _, v := range vars {
|
||||||
result = append(result, varNameForVar(v))
|
if vn := varNameForVar(v); vn != "" {
|
||||||
|
result = append(result, vn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -73,22 +82,26 @@ func (n *GraphNodeConfigResource) DependableName() []string {
|
|||||||
return []string{n.Resource.Id()}
|
return []string{n.Resource.Id()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *GraphNodeConfigResource) Name() string {
|
func (n *GraphNodeConfigResource) DependentOn() []string {
|
||||||
return n.Resource.Id()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *GraphNodeConfigResource) Variables() []string {
|
|
||||||
result := make([]string, len(n.Resource.DependsOn),
|
result := make([]string, len(n.Resource.DependsOn),
|
||||||
len(n.Resource.RawCount.Variables)+
|
len(n.Resource.RawCount.Variables)+
|
||||||
len(n.Resource.RawConfig.Variables)+
|
len(n.Resource.RawConfig.Variables)+
|
||||||
len(n.Resource.DependsOn))
|
len(n.Resource.DependsOn))
|
||||||
copy(result, n.Resource.DependsOn)
|
copy(result, n.Resource.DependsOn)
|
||||||
for _, v := range n.Resource.RawCount.Variables {
|
for _, v := range n.Resource.RawCount.Variables {
|
||||||
result = append(result, varNameForVar(v))
|
if vn := varNameForVar(v); vn != "" {
|
||||||
|
result = append(result, vn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, v := range n.Resource.RawConfig.Variables {
|
for _, v := range n.Resource.RawConfig.Variables {
|
||||||
result = append(result, varNameForVar(v))
|
if vn := varNameForVar(v); vn != "" {
|
||||||
|
result = append(result, vn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *GraphNodeConfigResource) Name() string {
|
||||||
|
return n.Resource.Id()
|
||||||
|
}
|
||||||
|
@ -18,12 +18,15 @@ func TestGraphAdd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGraphConnectTo(t *testing.T) {
|
func TestGraphConnectDependent(t *testing.T) {
|
||||||
var g Graph
|
var g Graph
|
||||||
g.Add(&testGraphDependable{VertexName: "a", Mock: []string{"a"}})
|
g.Add(&testGraphDependable{VertexName: "a", Mock: []string{"a"}})
|
||||||
b := g.Add(&testGraphDependable{VertexName: "b"})
|
b := g.Add(&testGraphDependable{
|
||||||
|
VertexName: "b",
|
||||||
|
DependentOnMock: []string{"a"},
|
||||||
|
})
|
||||||
|
|
||||||
if missing := g.ConnectTo(b, []string{"a"}); len(missing) > 0 {
|
if missing := g.ConnectDependent(b); len(missing) > 0 {
|
||||||
t.Fatalf("bad: %#v", missing)
|
t.Fatalf("bad: %#v", missing)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,6 +39,7 @@ func TestGraphConnectTo(t *testing.T) {
|
|||||||
|
|
||||||
type testGraphDependable struct {
|
type testGraphDependable struct {
|
||||||
VertexName string
|
VertexName string
|
||||||
|
DependentOnMock []string
|
||||||
Mock []string
|
Mock []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +51,10 @@ func (v *testGraphDependable) DependableName() []string {
|
|||||||
return v.Mock
|
return v.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *testGraphDependable) DependentOn() []string {
|
||||||
|
return v.DependentOnMock
|
||||||
|
}
|
||||||
|
|
||||||
const testGraphAddStr = `
|
const testGraphAddStr = `
|
||||||
42
|
42
|
||||||
84
|
84
|
||||||
|
@ -63,14 +63,7 @@ func (t *ConfigTransformer) Transform(g *Graph) error {
|
|||||||
// Build up the dependencies. We have to do this outside of the above
|
// Build up the dependencies. We have to do this outside of the above
|
||||||
// loop since the nodes need to be in place for us to build the deps.
|
// loop since the nodes need to be in place for us to build the deps.
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
vars := n.Variables()
|
if missing := g.ConnectDependent(n); len(missing) > 0 {
|
||||||
targets := make([]string, 0, len(vars))
|
|
||||||
for _, t := range vars {
|
|
||||||
if t != "" {
|
|
||||||
targets = append(targets, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if missing := g.ConnectTo(n, targets); len(missing) > 0 {
|
|
||||||
for _, m := range missing {
|
for _, m := range missing {
|
||||||
err = multierror.Append(err, fmt.Errorf(
|
err = multierror.Append(err, fmt.Errorf(
|
||||||
"%s: missing dependency: %s", n.Name(), m))
|
"%s: missing dependency: %s", n.Name(), m))
|
||||||
|
@ -29,17 +29,21 @@ func (t *OrphanTransformer) Transform(g *Graph) error {
|
|||||||
resourceOrphans := state.Orphans(t.Config)
|
resourceOrphans := state.Orphans(t.Config)
|
||||||
resourceVertexes := make([]dag.Vertex, len(resourceOrphans))
|
resourceVertexes := make([]dag.Vertex, len(resourceOrphans))
|
||||||
for i, k := range resourceOrphans {
|
for i, k := range resourceOrphans {
|
||||||
resourceVertexes[i] = g.Add(&graphNodeOrphanResource{ResourceName: k})
|
resourceVertexes[i] = g.Add(&graphNodeOrphanResource{
|
||||||
|
ResourceName: k,
|
||||||
|
dependentOn: state.Resources[k].Dependencies,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go over each module orphan and add it to the graph. We store the
|
// Go over each module orphan and add it to the graph. We store the
|
||||||
// vertexes and states outside so that we can connect dependencies later.
|
// vertexes and states outside so that we can connect dependencies later.
|
||||||
moduleOrphans := t.State.ModuleOrphans(g.Path, t.Config)
|
moduleOrphans := t.State.ModuleOrphans(g.Path, t.Config)
|
||||||
moduleVertexes := make([]dag.Vertex, len(moduleOrphans))
|
moduleVertexes := make([]dag.Vertex, len(moduleOrphans))
|
||||||
moduleStates := make([]*ModuleState, len(moduleVertexes))
|
|
||||||
for i, path := range moduleOrphans {
|
for i, path := range moduleOrphans {
|
||||||
moduleVertexes[i] = g.Add(&graphNodeOrphanModule{Path: path})
|
moduleVertexes[i] = g.Add(&graphNodeOrphanModule{
|
||||||
moduleStates[i] = t.State.ModuleByPath(path)
|
Path: path,
|
||||||
|
dependentOn: t.State.ModuleByPath(path).Dependencies,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now do the dependencies. We do this _after_ adding all the orphan
|
// Now do the dependencies. We do this _after_ adding all the orphan
|
||||||
@ -47,13 +51,13 @@ func (t *OrphanTransformer) Transform(g *Graph) error {
|
|||||||
// depend on other orphans.
|
// depend on other orphans.
|
||||||
|
|
||||||
// Resource dependencies
|
// Resource dependencies
|
||||||
for i, v := range resourceVertexes {
|
for _, v := range resourceVertexes {
|
||||||
g.ConnectTo(v, state.Resources[resourceOrphans[i]].Dependencies)
|
g.ConnectDependent(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module dependencies
|
// Module dependencies
|
||||||
for i, v := range moduleVertexes {
|
for _, v := range moduleVertexes {
|
||||||
g.ConnectTo(v, moduleStates[i].Dependencies)
|
g.ConnectDependent(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -62,12 +66,18 @@ func (t *OrphanTransformer) Transform(g *Graph) error {
|
|||||||
// graphNodeOrphanModule is the graph vertex representing an orphan resource..
|
// graphNodeOrphanModule is the graph vertex representing an orphan resource..
|
||||||
type graphNodeOrphanModule struct {
|
type graphNodeOrphanModule struct {
|
||||||
Path []string
|
Path []string
|
||||||
|
|
||||||
|
dependentOn []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeOrphanModule) DependableName() []string {
|
func (n *graphNodeOrphanModule) DependableName() []string {
|
||||||
return []string{n.dependableName()}
|
return []string{n.dependableName()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *graphNodeOrphanModule) DependentOn() []string {
|
||||||
|
return n.dependentOn
|
||||||
|
}
|
||||||
|
|
||||||
func (n *graphNodeOrphanModule) Name() string {
|
func (n *graphNodeOrphanModule) Name() string {
|
||||||
return fmt.Sprintf("%s (orphan)", n.dependableName())
|
return fmt.Sprintf("%s (orphan)", n.dependableName())
|
||||||
}
|
}
|
||||||
@ -79,12 +89,18 @@ func (n *graphNodeOrphanModule) dependableName() string {
|
|||||||
// graphNodeOrphanResource is the graph vertex representing an orphan resource..
|
// graphNodeOrphanResource is the graph vertex representing an orphan resource..
|
||||||
type graphNodeOrphanResource struct {
|
type graphNodeOrphanResource struct {
|
||||||
ResourceName string
|
ResourceName string
|
||||||
|
|
||||||
|
dependentOn []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeOrphanResource) DependableName() []string {
|
func (n *graphNodeOrphanResource) DependableName() []string {
|
||||||
return []string{n.dependableName()}
|
return []string{n.dependableName()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *graphNodeOrphanResource) DependentOn() []string {
|
||||||
|
return n.dependentOn
|
||||||
|
}
|
||||||
|
|
||||||
func (n *graphNodeOrphanResource) Name() string {
|
func (n *graphNodeOrphanResource) Name() string {
|
||||||
return fmt.Sprintf("%s (orphan)", n.ResourceName)
|
return fmt.Sprintf("%s (orphan)", n.ResourceName)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user