github.com/pbthorste/terraform@v0.8.6-0.20170127005045-deb56bd93da2/terraform/node_resource_validate.go (about)

     1  package terraform
     2  
     3  import (
     4  	"github.com/hashicorp/terraform/dag"
     5  )
     6  
     7  // NodeValidatableResource represents a resource that is used for validation
     8  // only.
     9  type NodeValidatableResource struct {
    10  	*NodeAbstractCountResource
    11  }
    12  
    13  // GraphNodeEvalable
    14  func (n *NodeValidatableResource) EvalTree() EvalNode {
    15  	// Ensure we're validating
    16  	c := n.NodeAbstractCountResource
    17  	c.Validate = true
    18  	return c.EvalTree()
    19  }
    20  
    21  // GraphNodeDynamicExpandable
    22  func (n *NodeValidatableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
    23  	// Grab the state which we read
    24  	state, lock := ctx.State()
    25  	lock.RLock()
    26  	defer lock.RUnlock()
    27  
    28  	// Expand the resource count which must be available by now from EvalTree
    29  	count, err := n.Config.Count()
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  
    34  	// The concrete resource factory we'll use
    35  	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
    36  		// Add the config and state since we don't do that via transforms
    37  		a.Config = n.Config
    38  
    39  		return &NodeValidatableResourceInstance{
    40  			NodeAbstractResource: a,
    41  		}
    42  	}
    43  
    44  	// Start creating the steps
    45  	steps := []GraphTransformer{
    46  		// Expand the count.
    47  		&ResourceCountTransformer{
    48  			Concrete: concreteResource,
    49  			Count:    count,
    50  			Addr:     n.ResourceAddr(),
    51  		},
    52  
    53  		// Attach the state
    54  		&AttachStateTransformer{State: state},
    55  
    56  		// Targeting
    57  		&TargetsTransformer{ParsedTargets: n.Targets},
    58  
    59  		// Connect references so ordering is correct
    60  		&ReferenceTransformer{},
    61  
    62  		// Make sure there is a single root
    63  		&RootTransformer{},
    64  	}
    65  
    66  	// Build the graph
    67  	b := &BasicGraphBuilder{
    68  		Steps:    steps,
    69  		Validate: true,
    70  		Name:     "NodeValidatableResource",
    71  	}
    72  
    73  	return b.Build(ctx.Path())
    74  }
    75  
    76  // This represents a _single_ resource instance to validate.
    77  type NodeValidatableResourceInstance struct {
    78  	*NodeAbstractResource
    79  }
    80  
    81  // GraphNodeEvalable
    82  func (n *NodeValidatableResourceInstance) EvalTree() EvalNode {
    83  	addr := n.NodeAbstractResource.Addr
    84  
    85  	// Build the resource for eval
    86  	resource := &Resource{
    87  		Name:       addr.Name,
    88  		Type:       addr.Type,
    89  		CountIndex: addr.Index,
    90  	}
    91  	if resource.CountIndex < 0 {
    92  		resource.CountIndex = 0
    93  	}
    94  
    95  	// Declare a bunch of variables that are used for state during
    96  	// evaluation. Most of this are written to by-address below.
    97  	var config *ResourceConfig
    98  	var provider ResourceProvider
    99  
   100  	seq := &EvalSequence{
   101  		Nodes: []EvalNode{
   102  			&EvalValidateResourceSelfRef{
   103  				Addr:   &addr,
   104  				Config: &n.Config.RawConfig,
   105  			},
   106  			&EvalGetProvider{
   107  				Name:   n.ProvidedBy()[0],
   108  				Output: &provider,
   109  			},
   110  			&EvalInterpolate{
   111  				Config:   n.Config.RawConfig.Copy(),
   112  				Resource: resource,
   113  				Output:   &config,
   114  			},
   115  			&EvalValidateResource{
   116  				Provider:     &provider,
   117  				Config:       &config,
   118  				ResourceName: n.Config.Name,
   119  				ResourceType: n.Config.Type,
   120  				ResourceMode: n.Config.Mode,
   121  			},
   122  		},
   123  	}
   124  
   125  	// Validate all the provisioners
   126  	for _, p := range n.Config.Provisioners {
   127  		var provisioner ResourceProvisioner
   128  		seq.Nodes = append(seq.Nodes, &EvalGetProvisioner{
   129  			Name:   p.Type,
   130  			Output: &provisioner,
   131  		}, &EvalInterpolate{
   132  			Config:   p.RawConfig.Copy(),
   133  			Resource: resource,
   134  			Output:   &config,
   135  		}, &EvalValidateProvisioner{
   136  			Provisioner: &provisioner,
   137  			Config:      &config,
   138  		})
   139  	}
   140  
   141  	return seq
   142  }