]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / node_resource_abstract.go
1 package terraform
2
3 import (
4 "fmt"
5 "strings"
6
7 "github.com/hashicorp/terraform/config"
8 "github.com/hashicorp/terraform/dag"
9 )
10
11 // ConcreteResourceNodeFunc is a callback type used to convert an
12 // abstract resource to a concrete one of some type.
13 type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex
14
15 // GraphNodeResource is implemented by any nodes that represent a resource.
16 // The type of operation cannot be assumed, only that this node represents
17 // the given resource.
18 type GraphNodeResource interface {
19 ResourceAddr() *ResourceAddress
20 }
21
22 // NodeAbstractResource represents a resource that has no associated
23 // operations. It registers all the interfaces for a resource that common
24 // across multiple operation types.
25 type NodeAbstractResource struct {
26 Addr *ResourceAddress // Addr is the address for this resource
27
28 // The fields below will be automatically set using the Attach
29 // interfaces if you're running those transforms, but also be explicitly
30 // set if you already have that information.
31
32 Config *config.Resource // Config is the resource in the config
33 ResourceState *ResourceState // ResourceState is the ResourceState for this
34
35 Targets []ResourceAddress // Set from GraphNodeTargetable
36 }
37
38 func (n *NodeAbstractResource) Name() string {
39 return n.Addr.String()
40 }
41
42 // GraphNodeSubPath
43 func (n *NodeAbstractResource) Path() []string {
44 return n.Addr.Path
45 }
46
47 // GraphNodeReferenceable
48 func (n *NodeAbstractResource) ReferenceableName() []string {
49 // We always are referenceable as "type.name" as long as
50 // we have a config or address. Determine what that value is.
51 var id string
52 if n.Config != nil {
53 id = n.Config.Id()
54 } else if n.Addr != nil {
55 addrCopy := n.Addr.Copy()
56 addrCopy.Path = nil // ReferenceTransformer handles paths
57 addrCopy.Index = -1 // We handle indexes below
58 id = addrCopy.String()
59 } else {
60 // No way to determine our type.name, just return
61 return nil
62 }
63
64 var result []string
65
66 // Always include our own ID. This is primarily for backwards
67 // compatibility with states that didn't yet support the more
68 // specific dep string.
69 result = append(result, id)
70
71 // We represent all multi-access
72 result = append(result, fmt.Sprintf("%s.*", id))
73
74 // We represent either a specific number, or all numbers
75 suffix := "N"
76 if n.Addr != nil {
77 idx := n.Addr.Index
78 if idx == -1 {
79 idx = 0
80 }
81
82 suffix = fmt.Sprintf("%d", idx)
83 }
84 result = append(result, fmt.Sprintf("%s.%s", id, suffix))
85
86 return result
87 }
88
89 // GraphNodeReferencer
90 func (n *NodeAbstractResource) References() []string {
91 // If we have a config, that is our source of truth
92 if c := n.Config; c != nil {
93 // Grab all the references
94 var result []string
95 result = append(result, c.DependsOn...)
96 result = append(result, ReferencesFromConfig(c.RawCount)...)
97 result = append(result, ReferencesFromConfig(c.RawConfig)...)
98 for _, p := range c.Provisioners {
99 if p.When == config.ProvisionerWhenCreate {
100 result = append(result, ReferencesFromConfig(p.ConnInfo)...)
101 result = append(result, ReferencesFromConfig(p.RawConfig)...)
102 }
103 }
104
105 return uniqueStrings(result)
106 }
107
108 // If we have state, that is our next source
109 if s := n.ResourceState; s != nil {
110 return s.Dependencies
111 }
112
113 return nil
114 }
115
116 // StateReferences returns the dependencies to put into the state for
117 // this resource.
118 func (n *NodeAbstractResource) StateReferences() []string {
119 self := n.ReferenceableName()
120
121 // Determine what our "prefix" is for checking for references to
122 // ourself.
123 addrCopy := n.Addr.Copy()
124 addrCopy.Index = -1
125 selfPrefix := addrCopy.String() + "."
126
127 depsRaw := n.References()
128 deps := make([]string, 0, len(depsRaw))
129 for _, d := range depsRaw {
130 // Ignore any variable dependencies
131 if strings.HasPrefix(d, "var.") {
132 continue
133 }
134
135 // If this has a backup ref, ignore those for now. The old state
136 // file never contained those and I'd rather store the rich types we
137 // add in the future.
138 if idx := strings.IndexRune(d, '/'); idx != -1 {
139 d = d[:idx]
140 }
141
142 // If we're referencing ourself, then ignore it
143 found := false
144 for _, s := range self {
145 if d == s {
146 found = true
147 }
148 }
149 if found {
150 continue
151 }
152
153 // If this is a reference to ourself and a specific index, we keep
154 // it. For example, if this resource is "foo.bar" and the reference
155 // is "foo.bar.0" then we keep it exact. Otherwise, we strip it.
156 if strings.HasSuffix(d, ".0") && !strings.HasPrefix(d, selfPrefix) {
157 d = d[:len(d)-2]
158 }
159
160 // This is sad. The dependencies are currently in the format of
161 // "module.foo.bar" (the full field). This strips the field off.
162 if strings.HasPrefix(d, "module.") {
163 parts := strings.SplitN(d, ".", 3)
164 d = strings.Join(parts[0:2], ".")
165 }
166
167 deps = append(deps, d)
168 }
169
170 return deps
171 }
172
173 // GraphNodeProviderConsumer
174 func (n *NodeAbstractResource) ProvidedBy() []string {
175 // If we have a config we prefer that above all else
176 if n.Config != nil {
177 return []string{resourceProvider(n.Config.Type, n.Config.Provider)}
178 }
179
180 // If we have state, then we will use the provider from there
181 if n.ResourceState != nil && n.ResourceState.Provider != "" {
182 return []string{n.ResourceState.Provider}
183 }
184
185 // Use our type
186 return []string{resourceProvider(n.Addr.Type, "")}
187 }
188
189 // GraphNodeProvisionerConsumer
190 func (n *NodeAbstractResource) ProvisionedBy() []string {
191 // If we have no configuration, then we have no provisioners
192 if n.Config == nil {
193 return nil
194 }
195
196 // Build the list of provisioners we need based on the configuration.
197 // It is okay to have duplicates here.
198 result := make([]string, len(n.Config.Provisioners))
199 for i, p := range n.Config.Provisioners {
200 result[i] = p.Type
201 }
202
203 return result
204 }
205
206 // GraphNodeResource, GraphNodeAttachResourceState
207 func (n *NodeAbstractResource) ResourceAddr() *ResourceAddress {
208 return n.Addr
209 }
210
211 // GraphNodeAddressable, TODO: remove, used by target, should unify
212 func (n *NodeAbstractResource) ResourceAddress() *ResourceAddress {
213 return n.ResourceAddr()
214 }
215
216 // GraphNodeTargetable
217 func (n *NodeAbstractResource) SetTargets(targets []ResourceAddress) {
218 n.Targets = targets
219 }
220
221 // GraphNodeAttachResourceState
222 func (n *NodeAbstractResource) AttachResourceState(s *ResourceState) {
223 n.ResourceState = s
224 }
225
226 // GraphNodeAttachResourceConfig
227 func (n *NodeAbstractResource) AttachResourceConfig(c *config.Resource) {
228 n.Config = c
229 }
230
231 // GraphNodeDotter impl.
232 func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
233 return &dag.DotNode{
234 Name: name,
235 Attrs: map[string]string{
236 "label": n.Name(),
237 "shape": "box",
238 },
239 }
240 }