]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/states/state.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / states / state.go
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 }