github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/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 := 1 30 if n.Config.RawCount.Value() != unknownValue() { 31 var err error 32 count, err = n.Config.Count() 33 if err != nil { 34 return nil, err 35 } 36 } 37 38 // The concrete resource factory we'll use 39 concreteResource := func(a *NodeAbstractResource) dag.Vertex { 40 // Add the config and state since we don't do that via transforms 41 a.Config = n.Config 42 a.ResolvedProvider = n.ResolvedProvider 43 44 return &NodeValidatableResourceInstance{ 45 NodeAbstractResource: a, 46 } 47 } 48 49 // Start creating the steps 50 steps := []GraphTransformer{ 51 // Expand the count. 52 &ResourceCountTransformer{ 53 Concrete: concreteResource, 54 Count: count, 55 Addr: n.ResourceAddr(), 56 }, 57 58 // Attach the state 59 &AttachStateTransformer{State: state}, 60 61 // Targeting 62 &TargetsTransformer{ParsedTargets: n.Targets}, 63 64 // Connect references so ordering is correct 65 &ReferenceTransformer{}, 66 67 // Make sure there is a single root 68 &RootTransformer{}, 69 } 70 71 // Build the graph 72 b := &BasicGraphBuilder{ 73 Steps: steps, 74 Validate: true, 75 Name: "NodeValidatableResource", 76 } 77 78 return b.Build(ctx.Path()) 79 } 80 81 // This represents a _single_ resource instance to validate. 82 type NodeValidatableResourceInstance struct { 83 *NodeAbstractResource 84 } 85 86 // GraphNodeEvalable 87 func (n *NodeValidatableResourceInstance) EvalTree() EvalNode { 88 addr := n.NodeAbstractResource.Addr 89 90 // Build the resource for eval 91 resource := &Resource{ 92 Name: addr.Name, 93 Type: addr.Type, 94 CountIndex: addr.Index, 95 } 96 if resource.CountIndex < 0 { 97 resource.CountIndex = 0 98 } 99 100 // Declare a bunch of variables that are used for state during 101 // evaluation. Most of this are written to by-address below. 102 var config *ResourceConfig 103 var provider ResourceProvider 104 105 seq := &EvalSequence{ 106 Nodes: []EvalNode{ 107 &EvalValidateResourceSelfRef{ 108 Addr: &addr, 109 Config: &n.Config.RawConfig, 110 }, 111 &EvalGetProvider{ 112 Name: n.ResolvedProvider, 113 Output: &provider, 114 }, 115 &EvalInterpolate{ 116 Config: n.Config.RawConfig.Copy(), 117 Resource: resource, 118 Output: &config, 119 }, 120 &EvalValidateResource{ 121 Provider: &provider, 122 Config: &config, 123 ResourceName: n.Config.Name, 124 ResourceType: n.Config.Type, 125 ResourceMode: n.Config.Mode, 126 }, 127 }, 128 } 129 130 // Validate all the provisioners 131 for _, p := range n.Config.Provisioners { 132 var provisioner ResourceProvisioner 133 var connConfig *ResourceConfig 134 seq.Nodes = append( 135 seq.Nodes, 136 &EvalGetProvisioner{ 137 Name: p.Type, 138 Output: &provisioner, 139 }, 140 &EvalInterpolate{ 141 Config: p.RawConfig.Copy(), 142 Resource: resource, 143 Output: &config, 144 }, 145 &EvalInterpolate{ 146 Config: p.ConnInfo.Copy(), 147 Resource: resource, 148 Output: &connConfig, 149 }, 150 &EvalValidateProvisioner{ 151 Provisioner: &provisioner, 152 Config: &config, 153 ConnConfig: &connConfig, 154 }, 155 ) 156 } 157 158 return seq 159 }