diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/states/state.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/states/state.go | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/states/state.go b/vendor/github.com/hashicorp/terraform/states/state.go new file mode 100644 index 0000000..1f84235 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/states/state.go | |||
@@ -0,0 +1,229 @@ | |||
1 | package states | ||
2 | |||
3 | import ( | ||
4 | "sort" | ||
5 | |||
6 | "github.com/zclconf/go-cty/cty" | ||
7 | |||
8 | "github.com/hashicorp/terraform/addrs" | ||
9 | ) | ||
10 | |||
11 | // State is the top-level type of a Terraform state. | ||
12 | // | ||
13 | // A state should be mutated only via its accessor methods, to ensure that | ||
14 | // invariants are preserved. | ||
15 | // | ||
16 | // Access to State and the nested values within it is not concurrency-safe, | ||
17 | // so when accessing a State object concurrently it is the caller's | ||
18 | // responsibility to ensure that only one write is in progress at a time | ||
19 | // and that reads only occur when no write is in progress. The most common | ||
20 | // way to acheive this is to wrap the State in a SyncState and use the | ||
21 | // higher-level atomic operations supported by that type. | ||
22 | type State struct { | ||
23 | // Modules contains the state for each module. The keys in this map are | ||
24 | // an implementation detail and must not be used by outside callers. | ||
25 | Modules map[string]*Module | ||
26 | } | ||
27 | |||
28 | // NewState constructs a minimal empty state, containing an empty root module. | ||
29 | func NewState() *State { | ||
30 | modules := map[string]*Module{} | ||
31 | modules[addrs.RootModuleInstance.String()] = NewModule(addrs.RootModuleInstance) | ||
32 | return &State{ | ||
33 | Modules: modules, | ||
34 | } | ||
35 | } | ||
36 | |||
37 | // BuildState is a helper -- primarily intended for tests -- to build a state | ||
38 | // using imperative code against the StateSync type while still acting as | ||
39 | // an expression of type *State to assign into a containing struct. | ||
40 | func BuildState(cb func(*SyncState)) *State { | ||
41 | s := NewState() | ||
42 | cb(s.SyncWrapper()) | ||
43 | return s | ||
44 | } | ||
45 | |||
46 | // Empty returns true if there are no resources or populated output values | ||
47 | // in the receiver. In other words, if this state could be safely replaced | ||
48 | // with the return value of NewState and be functionally equivalent. | ||
49 | func (s *State) Empty() bool { | ||
50 | if s == nil { | ||
51 | return true | ||
52 | } | ||
53 | for _, ms := range s.Modules { | ||
54 | if len(ms.Resources) != 0 { | ||
55 | return false | ||
56 | } | ||
57 | if len(ms.OutputValues) != 0 { | ||
58 | return false | ||
59 | } | ||
60 | } | ||
61 | return true | ||
62 | } | ||
63 | |||
64 | // Module returns the state for the module with the given address, or nil if | ||
65 | // the requested module is not tracked in the state. | ||
66 | func (s *State) Module(addr addrs.ModuleInstance) *Module { | ||
67 | if s == nil { | ||
68 | panic("State.Module on nil *State") | ||
69 | } | ||
70 | return s.Modules[addr.String()] | ||
71 | } | ||
72 | |||
73 | // RemoveModule removes the module with the given address from the state, | ||
74 | // unless it is the root module. The root module cannot be deleted, and so | ||
75 | // this method will panic if that is attempted. | ||
76 | // | ||
77 | // Removing a module implicitly discards all of the resources, outputs and | ||
78 | // local values within it, and so this should usually be done only for empty | ||
79 | // modules. For callers accessing the state through a SyncState wrapper, modules | ||
80 | // are automatically pruned if they are empty after one of their contained | ||
81 | // elements is removed. | ||
82 | func (s *State) RemoveModule(addr addrs.ModuleInstance) { | ||
83 | if addr.IsRoot() { | ||
84 | panic("attempted to remove root module") | ||
85 | } | ||
86 | |||
87 | delete(s.Modules, addr.String()) | ||
88 | } | ||
89 | |||
90 | // RootModule is a convenient alias for Module(addrs.RootModuleInstance). | ||
91 | func (s *State) RootModule() *Module { | ||
92 | if s == nil { | ||
93 | panic("RootModule called on nil State") | ||
94 | } | ||
95 | return s.Modules[addrs.RootModuleInstance.String()] | ||
96 | } | ||
97 | |||
98 | // EnsureModule returns the state for the module with the given address, | ||
99 | // creating and adding a new one if necessary. | ||
100 | // | ||
101 | // Since this might modify the state to add a new instance, it is considered | ||
102 | // to be a write operation. | ||
103 | func (s *State) EnsureModule(addr addrs.ModuleInstance) *Module { | ||
104 | ms := s.Module(addr) | ||
105 | if ms == nil { | ||
106 | ms = NewModule(addr) | ||
107 | s.Modules[addr.String()] = ms | ||
108 | } | ||
109 | return ms | ||
110 | } | ||
111 | |||
112 | // HasResources returns true if there is at least one resource (of any mode) | ||
113 | // present in the receiving state. | ||
114 | func (s *State) HasResources() bool { | ||
115 | if s == nil { | ||
116 | return false | ||
117 | } | ||
118 | for _, ms := range s.Modules { | ||
119 | if len(ms.Resources) > 0 { | ||
120 | return true | ||
121 | } | ||
122 | } | ||
123 | return false | ||
124 | } | ||
125 | |||
126 | // Resource returns the state for the resource with the given address, or nil | ||
127 | // if no such resource is tracked in the state. | ||
128 | func (s *State) Resource(addr addrs.AbsResource) *Resource { | ||
129 | ms := s.Module(addr.Module) | ||
130 | if ms == nil { | ||
131 | return nil | ||
132 | } | ||
133 | return ms.Resource(addr.Resource) | ||
134 | } | ||
135 | |||
136 | // ResourceInstance returns the state for the resource instance with the given | ||
137 | // address, or nil if no such resource is tracked in the state. | ||
138 | func (s *State) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance { | ||
139 | if s == nil { | ||
140 | panic("State.ResourceInstance on nil *State") | ||
141 | } | ||
142 | ms := s.Module(addr.Module) | ||
143 | if ms == nil { | ||
144 | return nil | ||
145 | } | ||
146 | return ms.ResourceInstance(addr.Resource) | ||
147 | } | ||
148 | |||
149 | // OutputValue returns the state for the output value with the given address, | ||
150 | // or nil if no such output value is tracked in the state. | ||
151 | func (s *State) OutputValue(addr addrs.AbsOutputValue) *OutputValue { | ||
152 | ms := s.Module(addr.Module) | ||
153 | if ms == nil { | ||
154 | return nil | ||
155 | } | ||
156 | return ms.OutputValues[addr.OutputValue.Name] | ||
157 | } | ||
158 | |||
159 | // LocalValue returns the value of the named local value with the given address, | ||
160 | // or cty.NilVal if no such value is tracked in the state. | ||
161 | func (s *State) LocalValue(addr addrs.AbsLocalValue) cty.Value { | ||
162 | ms := s.Module(addr.Module) | ||
163 | if ms == nil { | ||
164 | return cty.NilVal | ||
165 | } | ||
166 | return ms.LocalValues[addr.LocalValue.Name] | ||
167 | } | ||
168 | |||
169 | // ProviderAddrs returns a list of all of the provider configuration addresses | ||
170 | // referenced throughout the receiving state. | ||
171 | // | ||
172 | // The result is de-duplicated so that each distinct address appears only once. | ||
173 | func (s *State) ProviderAddrs() []addrs.AbsProviderConfig { | ||
174 | if s == nil { | ||
175 | return nil | ||
176 | } | ||
177 | |||
178 | m := map[string]addrs.AbsProviderConfig{} | ||
179 | for _, ms := range s.Modules { | ||
180 | for _, rc := range ms.Resources { | ||
181 | m[rc.ProviderConfig.String()] = rc.ProviderConfig | ||
182 | } | ||
183 | } | ||
184 | if len(m) == 0 { | ||
185 | return nil | ||
186 | } | ||
187 | |||
188 | // This is mainly just so we'll get stable results for testing purposes. | ||
189 | keys := make([]string, 0, len(m)) | ||
190 | for k := range m { | ||
191 | keys = append(keys, k) | ||
192 | } | ||
193 | sort.Strings(keys) | ||
194 | |||
195 | ret := make([]addrs.AbsProviderConfig, len(keys)) | ||
196 | for i, key := range keys { | ||
197 | ret[i] = m[key] | ||
198 | } | ||
199 | |||
200 | return ret | ||
201 | } | ||
202 | |||
203 | // PruneResourceHusks is a specialized method that will remove any Resource | ||
204 | // objects that do not contain any instances, even if they have an EachMode. | ||
205 | // | ||
206 | // This should generally be used only after a "terraform destroy" operation, | ||
207 | // to finalize the cleanup of the state. It is not correct to use this after | ||
208 | // other operations because if a resource has "count = 0" or "for_each" over | ||
209 | // an empty collection then we want to retain it in the state so that references | ||
210 | // to it, particularly in "strange" contexts like "terraform console", can be | ||
211 | // properly resolved. | ||
212 | // | ||
213 | // This method MUST NOT be called concurrently with other readers and writers | ||
214 | // of the receiving state. | ||
215 | func (s *State) PruneResourceHusks() { | ||
216 | for _, m := range s.Modules { | ||
217 | m.PruneResourceHusks() | ||
218 | if len(m.Resources) == 0 && !m.Addr.IsRoot() { | ||
219 | s.RemoveModule(m.Addr) | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | // SyncWrapper returns a SyncState object wrapping the receiver. | ||
225 | func (s *State) SyncWrapper() *SyncState { | ||
226 | return &SyncState{ | ||
227 | state: s, | ||
228 | } | ||
229 | } | ||