terraform: wip moving validation to new graph
This commit is contained in:
parent
66f6f70cdb
commit
1427075005
|
@ -219,15 +219,32 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, error) {
|
|||
case GraphTypeInput:
|
||||
// The input graph is just a slightly modified plan graph
|
||||
fallthrough
|
||||
case GraphTypeValidate:
|
||||
// The validate graph is just a slightly modified plan graph
|
||||
fallthrough
|
||||
case GraphTypePlan:
|
||||
return (&PlanGraphBuilder{
|
||||
// Create the plan graph builder
|
||||
p := &PlanGraphBuilder{
|
||||
Module: c.module,
|
||||
State: c.state,
|
||||
Providers: c.components.ResourceProviders(),
|
||||
Targets: c.targets,
|
||||
Validate: opts.Validate,
|
||||
Input: typ == GraphTypeInput,
|
||||
}).Build(RootModulePath)
|
||||
}
|
||||
|
||||
// Some special cases for other graph types shared with plan currently
|
||||
var b GraphBuilder = p
|
||||
switch typ {
|
||||
case GraphTypeInput:
|
||||
b = InputGraphBuilder(p)
|
||||
case GraphTypeValidate:
|
||||
// We need to set the provisioners so those can be validated
|
||||
p.Provisioners = c.components.ResourceProvisioners()
|
||||
|
||||
b = ValidateGraphBuilder(p)
|
||||
}
|
||||
|
||||
return b.Build(RootModulePath)
|
||||
|
||||
case GraphTypePlanDestroy:
|
||||
return (&DestroyPlanGraphBuilder{
|
||||
|
@ -661,7 +678,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(GraphTypeLegacy, nil)
|
||||
graph, err := c.Graph(GraphTypeValidate, nil)
|
||||
if err != nil {
|
||||
return nil, []error{err}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ const (
|
|||
GraphTypePlanDestroy
|
||||
GraphTypeApply
|
||||
GraphTypeInput
|
||||
GraphTypeValidate
|
||||
)
|
||||
|
||||
// GraphTypeMap is a mapping of human-readable string to GraphType. This
|
||||
|
@ -27,4 +28,5 @@ var GraphTypeMap = map[string]GraphType{
|
|||
"plan-destroy": GraphTypePlanDestroy,
|
||||
"refresh": GraphTypeRefresh,
|
||||
"legacy": GraphTypeLegacy,
|
||||
"validate": GraphTypeValidate,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
)
|
||||
|
||||
// InputGraphBuilder creates the graph for the input operation.
|
||||
//
|
||||
// Unlike other graph builders, this is a function since it currently modifies
|
||||
// and is based on the PlanGraphBuilder. The PlanGraphBuilder passed in will be
|
||||
// modified and should not be used for any other operations.
|
||||
func InputGraphBuilder(p *PlanGraphBuilder) GraphBuilder {
|
||||
// We're going to customize the concrete functions
|
||||
p.CustomConcrete = true
|
||||
|
||||
// Set the provider to the normal provider. This will ask for input.
|
||||
p.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
|
||||
return &NodeApplyableProvider{
|
||||
NodeAbstractProvider: a,
|
||||
}
|
||||
}
|
||||
|
||||
// We purposely don't set any more concrete fields since the remainder
|
||||
// should be no-ops.
|
||||
|
||||
return p
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/terraform/config/module"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
)
|
||||
|
@ -26,6 +28,9 @@ type PlanGraphBuilder struct {
|
|||
// Providers is the list of providers supported.
|
||||
Providers []string
|
||||
|
||||
// Provisioners is the list of provisioners supported.
|
||||
Provisioners []string
|
||||
|
||||
// Targets are resources to target
|
||||
Targets []string
|
||||
|
||||
|
@ -35,13 +40,15 @@ type PlanGraphBuilder struct {
|
|||
// Validate will do structural validation of the graph.
|
||||
Validate bool
|
||||
|
||||
// Input, if true, modifies this graph for inputs. There isn't a
|
||||
// dedicated input graph because asking for input is identical to
|
||||
// planning except for the operations done. You still need to know WHAT
|
||||
// you're going to plan since you only need to ask for input for things
|
||||
// that are necessary for planning. This requirement makes the graphs
|
||||
// very similar.
|
||||
Input bool
|
||||
// CustomConcrete can be set to customize the node types created
|
||||
// for various parts of the plan. This is useful in order to customize
|
||||
// the plan behavior.
|
||||
CustomConcrete bool
|
||||
ConcreteProvider ConcreteProviderNodeFunc
|
||||
ConcreteResource ConcreteResourceNodeFunc
|
||||
ConcreteResourceOrphan ConcreteResourceNodeFunc
|
||||
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// See GraphBuilder
|
||||
|
@ -55,32 +62,12 @@ func (b *PlanGraphBuilder) Build(path []string) (*Graph, error) {
|
|||
|
||||
// See GraphBuilder
|
||||
func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
||||
// Custom factory for creating providers.
|
||||
concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
|
||||
return &NodeApplyableProvider{
|
||||
NodeAbstractProvider: a,
|
||||
}
|
||||
}
|
||||
|
||||
var concreteResource, concreteResourceOrphan ConcreteResourceNodeFunc
|
||||
if !b.Input {
|
||||
concreteResource = func(a *NodeAbstractResource) dag.Vertex {
|
||||
return &NodePlannableResource{
|
||||
NodeAbstractResource: a,
|
||||
}
|
||||
}
|
||||
|
||||
concreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex {
|
||||
return &NodePlannableResourceOrphan{
|
||||
NodeAbstractResource: a,
|
||||
}
|
||||
}
|
||||
}
|
||||
b.once.Do(b.init)
|
||||
|
||||
steps := []GraphTransformer{
|
||||
// Creates all the resources represented in the config
|
||||
&ConfigTransformer{
|
||||
Concrete: concreteResource,
|
||||
Concrete: b.ConcreteResource,
|
||||
Module: b.Module,
|
||||
},
|
||||
|
||||
|
@ -89,7 +76,7 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
// Add orphan resources
|
||||
&OrphanResourceTransformer{
|
||||
Concrete: concreteResourceOrphan,
|
||||
Concrete: b.ConcreteResourceOrphan,
|
||||
State: b.State,
|
||||
Module: b.Module,
|
||||
},
|
||||
|
@ -104,12 +91,21 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||
&RootVariableTransformer{Module: b.Module},
|
||||
|
||||
// Create all the providers
|
||||
&MissingProviderTransformer{Providers: b.Providers, Concrete: concreteProvider},
|
||||
&MissingProviderTransformer{Providers: b.Providers, Concrete: b.ConcreteProvider},
|
||||
&ProviderTransformer{},
|
||||
&DisableProviderTransformer{},
|
||||
&ParentProviderTransformer{},
|
||||
&AttachProviderConfigTransformer{Module: b.Module},
|
||||
|
||||
// Provisioner-related transformations. Only add these if requested.
|
||||
GraphTransformIf(
|
||||
func() bool { return b.Provisioners != nil },
|
||||
GraphTransformMulti(
|
||||
&MissingProvisionerTransformer{Provisioners: b.Provisioners},
|
||||
&ProvisionerTransformer{},
|
||||
),
|
||||
),
|
||||
|
||||
// Add module variables
|
||||
&ModuleVariableTransformer{Module: b.Module},
|
||||
|
||||
|
@ -132,3 +128,28 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
return steps
|
||||
}
|
||||
|
||||
func (b *PlanGraphBuilder) init() {
|
||||
// Do nothing if the user requests customizing the fields
|
||||
if b.CustomConcrete {
|
||||
return
|
||||
}
|
||||
|
||||
b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
|
||||
return &NodeApplyableProvider{
|
||||
NodeAbstractProvider: a,
|
||||
}
|
||||
}
|
||||
|
||||
b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
|
||||
return &NodePlannableResource{
|
||||
NodeAbstractResource: a,
|
||||
}
|
||||
}
|
||||
|
||||
b.ConcreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex {
|
||||
return &NodePlannableResourceOrphan{
|
||||
NodeAbstractResource: a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
)
|
||||
|
||||
// ValidateGraphBuilder creates the graph for the validate operation.
|
||||
//
|
||||
// ValidateGraphBuilder is based on the PlanGraphBuilder. We do this so that
|
||||
// we only have to validate what we'd normally plan anyways. The
|
||||
// PlanGraphBuilder given will be modified so it shouldn't be used for anything
|
||||
// else after calling this function.
|
||||
func ValidateGraphBuilder(p *PlanGraphBuilder) GraphBuilder {
|
||||
// We're going to customize the concrete functions
|
||||
p.CustomConcrete = true
|
||||
|
||||
// Set the provider to the normal provider. This will ask for input.
|
||||
p.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
|
||||
return &NodeApplyableProvider{
|
||||
NodeAbstractProvider: a,
|
||||
}
|
||||
}
|
||||
|
||||
p.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
|
||||
return &NodeValidatableResource{
|
||||
NodeAbstractResource: a,
|
||||
}
|
||||
}
|
||||
|
||||
// We purposely don't set any other concrete types since they don't
|
||||
// require validation.
|
||||
|
||||
return p
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package terraform
|
||||
|
||||
// NodeValidatableResource represents a resource that is used for validation
|
||||
// only.
|
||||
type NodeValidatableResource struct {
|
||||
*NodeAbstractResource
|
||||
}
|
||||
|
||||
// GraphNodeEvalable
|
||||
func (n *NodeValidatableResource) EvalTree() EvalNode {
|
||||
addr := n.NodeAbstractResource.Addr
|
||||
|
||||
// Build the resource for eval
|
||||
resource := &Resource{
|
||||
Name: addr.Name,
|
||||
Type: addr.Type,
|
||||
CountIndex: addr.Index,
|
||||
}
|
||||
if resource.CountIndex < 0 {
|
||||
resource.CountIndex = 0
|
||||
}
|
||||
|
||||
// Declare a bunch of variables that are used for state during
|
||||
// evaluation. Most of this are written to by-address below.
|
||||
var config *ResourceConfig
|
||||
var provider ResourceProvider
|
||||
|
||||
seq := &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalGetProvider{
|
||||
Name: n.ProvidedBy()[0],
|
||||
Output: &provider,
|
||||
},
|
||||
&EvalInterpolate{
|
||||
Config: n.Config.RawConfig.Copy(),
|
||||
Resource: resource,
|
||||
Output: &config,
|
||||
},
|
||||
&EvalValidateResource{
|
||||
Provider: &provider,
|
||||
Config: &config,
|
||||
ResourceName: n.Config.Name,
|
||||
ResourceType: n.Config.Type,
|
||||
ResourceMode: n.Config.Mode,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Validate all the provisioners
|
||||
for _, p := range n.Config.Provisioners {
|
||||
var provisioner ResourceProvisioner
|
||||
seq.Nodes = append(seq.Nodes, &EvalGetProvisioner{
|
||||
Name: p.Type,
|
||||
Output: &provisioner,
|
||||
}, &EvalInterpolate{
|
||||
Config: p.RawConfig.Copy(),
|
||||
Resource: resource,
|
||||
Output: &config,
|
||||
}, &EvalValidateProvisioner{
|
||||
Provisioner: &provisioner,
|
||||
Config: &config,
|
||||
})
|
||||
}
|
||||
|
||||
return seq
|
||||
}
|
Loading…
Reference in New Issue