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 }