aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/terraform/node_resource_validate.go
blob: f528f24b193f2e95c66b401fe3b45ebe502cf0ba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package terraform

import (
	"github.com/hashicorp/terraform/dag"
)

// NodeValidatableResource represents a resource that is used for validation
// only.
type NodeValidatableResource struct {
	*NodeAbstractCountResource
}

// GraphNodeEvalable
func (n *NodeValidatableResource) EvalTree() EvalNode {
	// Ensure we're validating
	c := n.NodeAbstractCountResource
	c.Validate = true
	return c.EvalTree()
}

// GraphNodeDynamicExpandable
func (n *NodeValidatableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
	// Grab the state which we read
	state, lock := ctx.State()
	lock.RLock()
	defer lock.RUnlock()

	// Expand the resource count which must be available by now from EvalTree
	count := 1
	if n.Config.RawCount.Value() != unknownValue() {
		var err error
		count, err = n.Config.Count()
		if err != nil {
			return nil, err
		}
	}

	// The concrete resource factory we'll use
	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
		// Add the config and state since we don't do that via transforms
		a.Config = n.Config

		return &NodeValidatableResourceInstance{
			NodeAbstractResource: a,
		}
	}

	// Start creating the steps
	steps := []GraphTransformer{
		// Expand the count.
		&ResourceCountTransformer{
			Concrete: concreteResource,
			Count:    count,
			Addr:     n.ResourceAddr(),
		},

		// Attach the state
		&AttachStateTransformer{State: state},

		// Targeting
		&TargetsTransformer{ParsedTargets: n.Targets},

		// Connect references so ordering is correct
		&ReferenceTransformer{},

		// Make sure there is a single root
		&RootTransformer{},
	}

	// Build the graph
	b := &BasicGraphBuilder{
		Steps:    steps,
		Validate: true,
		Name:     "NodeValidatableResource",
	}

	return b.Build(ctx.Path())
}

// This represents a _single_ resource instance to validate.
type NodeValidatableResourceInstance struct {
	*NodeAbstractResource
}

// GraphNodeEvalable
func (n *NodeValidatableResourceInstance) 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{
			&EvalValidateResourceSelfRef{
				Addr:   &addr,
				Config: &n.Config.RawConfig,
			},
			&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
		var connConfig *ResourceConfig
		seq.Nodes = append(
			seq.Nodes,
			&EvalGetProvisioner{
				Name:   p.Type,
				Output: &provisioner,
			},
			&EvalInterpolate{
				Config:   p.RawConfig.Copy(),
				Resource: resource,
				Output:   &config,
			},
			&EvalInterpolate{
				Config:   p.ConnInfo.Copy(),
				Resource: resource,
				Output:   &connConfig,
			},
			&EvalValidateProvisioner{
				Provisioner: &provisioner,
				Config:      &config,
				ConnConfig:  &connConfig,
			},
		)
	}

	return seq
}