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 { type ContextGraphOpts struct {
// If true, validates the graph structure (checks for cycles).
Validate bool Validate bool
// Legacy graphs only: won't prune the graph
Verbose bool Verbose bool
} }
// Graph returns the graph for this config. // Graph returns the graph used for the given operation type.
func (c *Context) Graph(g *ContextGraphOpts) (*Graph, error) { //
return c.graphBuilder(g).Build(RootModulePath) // 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 // 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 { if mode&InputModeProvider != 0 {
// Build the graph // Build the graph
graph, err := c.Graph(&ContextGraphOpts{Validate: true}) graph, err := c.Graph(GraphTypeLegacy, nil)
if err != nil { if err != nil {
return err return err
} }
@ -390,20 +432,11 @@ func (c *Context) Apply() (*State, error) {
X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph) X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph)
// Build the graph. // Build the graph.
var graph *Graph graphType := GraphTypeLegacy
var err error
if !X_legacyGraph { if !X_legacyGraph {
graph, err = (&ApplyGraphBuilder{ graphType = GraphTypeApply
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})
} }
graph, err := c.Graph(graphType, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -475,26 +508,15 @@ func (c *Context) Plan() (*Plan, error) {
X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph) X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph)
// Build the graph. // Build the graph.
var graph *Graph graphType := GraphTypeLegacy
var err error
if !X_legacyGraph { if !X_legacyGraph {
if c.destroy { if c.destroy {
graph, err = (&DestroyPlanGraphBuilder{ graphType = GraphTypePlanDestroy
Module: c.module,
State: c.state,
Targets: c.targets,
}).Build(RootModulePath)
} else { } else {
graph, err = (&PlanGraphBuilder{ graphType = GraphTypePlan
Module: c.module,
State: c.state,
Providers: c.components.ResourceProviders(),
Targets: c.targets,
}).Build(RootModulePath)
} }
} else {
graph, err = c.Graph(&ContextGraphOpts{Validate: true})
} }
graph, err := c.Graph(graphType, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -522,7 +544,7 @@ func (c *Context) Plan() (*Plan, error) {
if X_legacyGraph { if X_legacyGraph {
// Now that we have a diff, we can build the exact graph that Apply will use // 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. // 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 return nil, err
} }
} }
@ -548,7 +570,7 @@ func (c *Context) Refresh() (*State, error) {
c.state = c.state.DeepCopy() c.state = c.state.DeepCopy()
// Build the graph // Build the graph
graph, err := c.Graph(&ContextGraphOpts{Validate: true}) graph, err := c.Graph(GraphTypeLegacy, nil)
if err != nil { if err != nil {
return nil, err 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 // 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 // necessarily match the graph that Plan will generate, so we'll validate the
// graph again later after Planning. // graph again later after Planning.
graph, err := c.Graph(&ContextGraphOpts{Validate: true}) graph, err := c.Graph(GraphTypeLegacy, nil)
if err != nil { if err != nil {
return nil, []error{err} 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, if true, represents a pure destroy operation
Destroy bool Destroy bool
// Validate will do structural validation of the graph.
Validate bool
} }
// See GraphBuilder // See GraphBuilder
func (b *ApplyGraphBuilder) Build(path []string) (*Graph, error) { func (b *ApplyGraphBuilder) Build(path []string) (*Graph, error) {
return (&BasicGraphBuilder{ return (&BasicGraphBuilder{
Steps: b.Steps(), Steps: b.Steps(),
Validate: true, Validate: b.Validate,
Name: "ApplyGraphBuilder", Name: "ApplyGraphBuilder",
}).Build(path) }).Build(path)
} }

View File

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

View File

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