Skip to content

Commit

Permalink
terraform: Graph nodes can belong to partial-expanded module prefixes
Browse files Browse the repository at this point in the history
The new interface GraphNodePartialExpandedModule is a mutually-exclusive
alternative to GraphNodeModuleInstance for graph nodes that represent
the unbounded set of as-yet-unknown instances sharing a common known
module prefix.

For nodes that implement this interface, their Execute and DynamicExpand
methods will receive an EvalContext that is configured to perform
expression evaluation using safe placeholder values instead of using
the real state and plan, since (once implemented in future commits) the
graph nodes of this sort will be used for situations where we're deferring
part of the plan until we have more information to use while planning.
  • Loading branch information
apparentlymart committed Jan 25, 2024
1 parent 5a2b1bf commit 75e1fde
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 9 deletions.
31 changes: 22 additions & 9 deletions internal/terraform/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,34 @@ func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics {
}
}()

// vertexCtx is the context that we use when evaluating. This
// is normally the context of our graph but can be overridden
// with a GraphNodeModuleInstance impl.
vertexCtx := ctx
if pn, ok := v.(GraphNodeModuleInstance); ok {
vertexCtx = walker.EnterPath(pn.Path())
defer walker.ExitPath(pn.Path())
}

if g.checkAndApplyOverrides(ctx.Overrides(), v) {
// We can skip whole vertices if they are in a module that has been
// overridden.
log.Printf("[TRACE] vertex %q: overridden by a test double, so skipping", dag.VertexName(v))
return
}

// vertexCtx is the context that we use when evaluating. This
// is normally the global context but can be overridden
// with a GraphNodeModuleInstance or GraphNodePartialExpandedModule
// impl. (The two interfaces are intentionally mutually-exclusive by
// both having the same method name but with different signatures,
// since a node can't belong to two different contexts at once.)
vertexCtx := ctx
if pn, ok := v.(GraphNodeModuleInstance); ok {
moduleAddr := pn.Path() // An addrs.ModuleInstance
log.Printf("[TRACE] vertex %q: belongs to %s", dag.VertexName(v), moduleAddr)
vertexCtx = walker.EnterPath(moduleAddr)
defer walker.ExitPath(pn.Path())
} else if pn, ok := v.(GraphNodePartialExpandedModule); ok {
moduleAddr := pn.Path() // An addrs.PartialExpandedModule
log.Printf("[TRACE] vertex %q: belongs to all of %s", dag.VertexName(v), moduleAddr)
vertexCtx = walker.EnterPartialExpandedPath(pn.Path())
defer walker.ExitPartialExpandedPath(pn.Path())
} else {
log.Printf("[TRACE] vertex %q: does not belong to any module instance", dag.VertexName(v))
}

// If the node is exec-able, then execute it.
if ev, ok := v.(GraphNodeExecutable); ok {
diags = diags.Append(walker.Execute(vertexCtx, ev))
Expand Down
18 changes: 18 additions & 0 deletions internal/terraform/graph_interface_subgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,21 @@ type GraphNodeModuleInstance interface {
type GraphNodeModulePath interface {
ModulePath() addrs.Module
}

// GraphNodePartialExpandedModule says that a node represents an unbounded
// set of objects within an unbounded set of module instances that happen
// to share a known address prefix.
//
// Nodes of this type typically produce placeholder data to support partial
// evaluation despite the full analysis of a module being deferred to a future
// plan when more information will be available. They might also perform
// checks and raise errors when something can be proven to be definitely
// invalid regardless of what the final set of module instances turns out to
// be.
//
// Node types implementing this interface cannot also implement
// [GraphNodeModuleInstance], because it is not possible to evaluate a
// node in two different contexts at once.
type GraphNodePartialExpandedModule interface {
Path() addrs.PartialExpandedModule
}
4 changes: 4 additions & 0 deletions internal/terraform/node_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,8 @@ type nodeLocalInPartialModule struct {
Config *configs.Local
}

func (n *nodeLocalInPartialModule) Path() addrs.PartialExpandedModule {
return n.Addr.Module
}

// TODO: Implement nodeLocalUnexpandedPlaceholder.Execute
4 changes: 4 additions & 0 deletions internal/terraform/node_module_variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,4 +323,8 @@ type nodeModuleVariableInPartialModule struct {
DestroyApply bool
}

func (n *nodeModuleVariableInPartialModule) Path() addrs.PartialExpandedModule {
return n.Addr.Module
}

// TODO: Implement nodeModuleVariableInPartialModule.Execute
4 changes: 4 additions & 0 deletions internal/terraform/node_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,10 @@ type nodeOutputInPartialModule struct {
RefreshOnly bool
}

func (n *nodeOutputInPartialModule) Path() addrs.PartialExpandedModule {
return n.Addr.Module
}

// TODO: Implement nodeOutputInPartialModule.Execute

// NodeDestroyableOutput represents an output that is "destroyable":
Expand Down

0 comments on commit 75e1fde

Please sign in to comment.