opentofu/terraform/graph_walk.go
James Bardin 797a1b339d DebugInfo and DebugGraph
Implement debugInfo and the DebugGraph

DebugInfo will be a global variable through which graph debug
information can we written to a compressed archive. The DebugInfo
methods are all safe for concurrent use, and noop with a nil receiver.
The API outside of the terraform package will be to call SetDebugInfo
to create the archive, and CloseDebugInfo() to properly close the file.
Each write to the archive will be flushed and sync'ed individually, so
in the event of a crash or a missing call to Close, the archive can
still be recovered.

The DebugGraph is a representation of a terraform Graph to be written to
the debug archive, currently in dot format. The DebugGraph also contains
an internal buffer with Printf and Write methods to add to this buffer.
The buffer will be written to an accompanying file in the debug archive
along with the graph.

This also adds a GraphNodeDebugger interface. Any node implementing
`NodeDebug() string` can output information to annotate the debug graph
node, and add the data to the log. This interface may change or be
removed to provide richer options for debugging graph nodes.

The new graph builders all delegate the build to the BasicGraphBuilder.
Having a Name field lets us differentiate the actual builder
implementation in the debug graphs.
2016-11-04 11:30:51 -04:00

63 lines
2.3 KiB
Go

package terraform
import (
"github.com/hashicorp/terraform/dag"
)
// GraphWalker is an interface that can be implemented that when used
// with Graph.Walk will invoke the given callbacks under certain events.
type GraphWalker interface {
EnterPath([]string) EvalContext
ExitPath([]string)
EnterVertex(dag.Vertex)
ExitVertex(dag.Vertex, error)
EnterEvalTree(dag.Vertex, EvalNode) EvalNode
ExitEvalTree(dag.Vertex, interface{}, error) error
Debug() *DebugGraph
}
// GrpahWalkerPanicwrapper can be optionally implemented to catch panics
// that occur while walking the graph. This is not generally recommended
// since panics should crash Terraform and result in a bug report. However,
// this is particularly useful for situations like the shadow graph where
// you don't ever want to cause a panic.
type GraphWalkerPanicwrapper interface {
GraphWalker
// Panic is called when a panic occurs. This will halt the panic from
// propogating so if the walker wants it to crash still it should panic
// again. This is called from within a defer so runtime/debug.Stack can
// be used to get the stack trace of the panic.
Panic(dag.Vertex, interface{})
}
// GraphWalkerPanicwrap wraps an existing Graphwalker to wrap and swallow
// the panics. This doesn't lose the panics since the panics are still
// returned as errors as part of a graph walk.
func GraphWalkerPanicwrap(w GraphWalker) GraphWalkerPanicwrapper {
return &graphWalkerPanicwrapper{
GraphWalker: w,
}
}
type graphWalkerPanicwrapper struct {
GraphWalker
}
func (graphWalkerPanicwrapper) Panic(dag.Vertex, interface{}) {}
// NullGraphWalker is a GraphWalker implementation that does nothing.
// This can be embedded within other GraphWalker implementations for easily
// implementing all the required functions.
type NullGraphWalker struct{}
func (NullGraphWalker) EnterPath([]string) EvalContext { return new(MockEvalContext) }
func (NullGraphWalker) ExitPath([]string) {}
func (NullGraphWalker) EnterVertex(dag.Vertex) {}
func (NullGraphWalker) ExitVertex(dag.Vertex, error) {}
func (NullGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode { return n }
func (NullGraphWalker) ExitEvalTree(dag.Vertex, interface{}, error) error {
return nil
}
func (NullGraphWalker) Debug() *DebugGraph { return nil }