terraform: new Graph API that can return the graph for each op

This commit is contained in:
Mitchell Hashimoto 2016-12-02 22:38:49 -05:00
parent 9197422881
commit fb8f2e2753
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
6 changed files with 111 additions and 38 deletions

View File

@ -189,13 +189,55 @@ func NewContext(opts *ContextOpts) (*Context, error) {
}
type ContextGraphOpts struct {
// If true, validates the graph structure (checks for cycles).
Validate bool
Verbose bool
// Legacy graphs only: won't prune the graph
Verbose bool
}
// Graph returns the graph for this config.
func (c *Context) Graph(g *ContextGraphOpts) (*Graph, error) {
return c.graphBuilder(g).Build(RootModulePath)
// Graph returns the graph used for the given operation type.
//
// The most extensive or complex graph type is GraphTypePlan.
func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, error) {
if opts == nil {
opts = &ContextGraphOpts{Validate: true}
}
switch typ {
case GraphTypeApply:
return (&ApplyGraphBuilder{
Module: c.module,
Diff: c.diff,
State: c.state,
Providers: c.components.ResourceProviders(),
Provisioners: c.components.ResourceProvisioners(),
Destroy: c.destroy,
Validate: opts.Validate,
}).Build(RootModulePath)
case GraphTypePlan:
return (&PlanGraphBuilder{
Module: c.module,
State: c.state,
Providers: c.components.ResourceProviders(),
Targets: c.targets,
Validate: opts.Validate,
}).Build(RootModulePath)
case GraphTypePlanDestroy:
return (&DestroyPlanGraphBuilder{
Module: c.module,
State: c.state,
Targets: c.targets,
Validate: opts.Validate,
}).Build(RootModulePath)
case GraphTypeLegacy:
return c.graphBuilder(opts).Build(RootModulePath)
}
return nil, fmt.Errorf("unknown graph type: %s", typ)
}
// GraphBuilder returns the GraphBuilder that will be used to create
@ -360,7 +402,7 @@ func (c *Context) Input(mode InputMode) error {
if mode&InputModeProvider != 0 {
// Build the graph
graph, err := c.Graph(&ContextGraphOpts{Validate: true})
graph, err := c.Graph(GraphTypeLegacy, nil)
if err != nil {
return err
}
@ -390,20 +432,11 @@ func (c *Context) Apply() (*State, error) {
X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph)
// Build the graph.
var graph *Graph
var err error
graphType := GraphTypeLegacy
if !X_legacyGraph {
graph, err = (&ApplyGraphBuilder{
Module: c.module,
Diff: c.diff,
State: c.state,
Providers: c.components.ResourceProviders(),
Provisioners: c.components.ResourceProvisioners(),
Destroy: c.destroy,
}).Build(RootModulePath)
} else {
graph, err = c.Graph(&ContextGraphOpts{Validate: true})
graphType = GraphTypeApply
}
graph, err := c.Graph(graphType, nil)
if err != nil {
return nil, err
}
@ -475,26 +508,15 @@ func (c *Context) Plan() (*Plan, error) {
X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph)
// Build the graph.
var graph *Graph
var err error
graphType := GraphTypeLegacy
if !X_legacyGraph {
if c.destroy {
graph, err = (&DestroyPlanGraphBuilder{
Module: c.module,
State: c.state,
Targets: c.targets,
}).Build(RootModulePath)
graphType = GraphTypePlanDestroy
} else {
graph, err = (&PlanGraphBuilder{
Module: c.module,
State: c.state,
Providers: c.components.ResourceProviders(),
Targets: c.targets,
}).Build(RootModulePath)
graphType = GraphTypePlan
}
} else {
graph, err = c.Graph(&ContextGraphOpts{Validate: true})
}
graph, err := c.Graph(graphType, nil)
if err != nil {
return nil, err
}
@ -522,7 +544,7 @@ func (c *Context) Plan() (*Plan, error) {
if X_legacyGraph {
// Now that we have a diff, we can build the exact graph that Apply will use
// and catch any possible cycles during the Plan phase.
if _, err := c.Graph(&ContextGraphOpts{Validate: true}); err != nil {
if _, err := c.Graph(GraphTypeLegacy, nil); err != nil {
return nil, err
}
}
@ -548,7 +570,7 @@ func (c *Context) Refresh() (*State, error) {
c.state = c.state.DeepCopy()
// Build the graph
graph, err := c.Graph(&ContextGraphOpts{Validate: true})
graph, err := c.Graph(GraphTypeLegacy, nil)
if err != nil {
return nil, err
}
@ -619,7 +641,7 @@ func (c *Context) Validate() ([]string, []error) {
// We also validate the graph generated here, but this graph doesn't
// necessarily match the graph that Plan will generate, so we'll validate the
// graph again later after Planning.
graph, err := c.Graph(&ContextGraphOpts{Validate: true})
graph, err := c.Graph(GraphTypeLegacy, nil)
if err != nil {
return nil, []error{err}
}

View File

@ -0,0 +1,26 @@
package terraform
//go:generate stringer -type=GraphType context_graph_type.go
// GraphType is an enum of the type of graph to create with a Context.
// The values of the constants may change so they shouldn't be depended on;
// always use the constant name.
type GraphType byte
const (
GraphTypeInvalid GraphType = 0
GraphTypeLegacy GraphType = iota
GraphTypePlan
GraphTypePlanDestroy
GraphTypeApply
)
// GraphTypeMap is a mapping of human-readable string to GraphType. This
// is useful to use as the mechanism for human input for configurable
// graph types.
var GraphTypeMap = map[string]GraphType{
"apply": GraphTypeApply,
"plan": GraphTypePlan,
"plan-destroy": GraphTypePlanDestroy,
"legacy": GraphTypeLegacy,
}

View File

@ -33,13 +33,16 @@ type ApplyGraphBuilder struct {
// Destroy, if true, represents a pure destroy operation
Destroy bool
// Validate will do structural validation of the graph.
Validate bool
}
// See GraphBuilder
func (b *ApplyGraphBuilder) Build(path []string) (*Graph, error) {
return (&BasicGraphBuilder{
Steps: b.Steps(),
Validate: true,
Validate: b.Validate,
Name: "ApplyGraphBuilder",
}).Build(path)
}

View File

@ -19,13 +19,16 @@ type DestroyPlanGraphBuilder struct {
// Targets are resources to target
Targets []string
// Validate will do structural validation of the graph.
Validate bool
}
// See GraphBuilder
func (b *DestroyPlanGraphBuilder) Build(path []string) (*Graph, error) {
return (&BasicGraphBuilder{
Steps: b.Steps(),
Validate: true,
Validate: b.Validate,
Name: "DestroyPlanGraphBuilder",
}).Build(path)
}

View File

@ -31,13 +31,16 @@ type PlanGraphBuilder struct {
// DisableReduce, if true, will not reduce the graph. Great for testing.
DisableReduce bool
// Validate will do structural validation of the graph.
Validate bool
}
// See GraphBuilder
func (b *PlanGraphBuilder) Build(path []string) (*Graph, error) {
return (&BasicGraphBuilder{
Steps: b.Steps(),
Validate: true,
Validate: b.Validate,
Name: "PlanGraphBuilder",
}).Build(path)
}

View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT
package terraform
import "fmt"
const _GraphType_name = "GraphTypeInvalidGraphTypeLegacyGraphTypePlanGraphTypePlanDestroyGraphTypeApply"
var _GraphType_index = [...]uint8{0, 16, 31, 44, 64, 78}
func (i GraphType) String() string {
if i >= GraphType(len(_GraphType_index)-1) {
return fmt.Sprintf("GraphType(%d)", i)
}
return _GraphType_name[_GraphType_index[i]:_GraphType_index[i+1]]
}