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