5 // EvalReadState is an EvalNode implementation that reads the
6 // primary InstanceState for a specific resource out of the state.
7 type EvalReadState struct {
12 func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
13 return readInstanceFromState(ctx, n.Name, n.Output, func(rs *ResourceState) (*InstanceState, error) {
14 return rs.Primary, nil
18 // EvalReadStateDeposed is an EvalNode implementation that reads the
19 // deposed InstanceState for a specific resource out of the state
20 type EvalReadStateDeposed struct {
22 Output **InstanceState
23 // Index indicates which instance in the Deposed list to target, or -1 for
28 func (n *EvalReadStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
29 return readInstanceFromState(ctx, n.Name, n.Output, func(rs *ResourceState) (*InstanceState, error) {
30 // Get the index. If it is negative, then we get the last one
33 idx = len(rs.Deposed) - 1
35 if idx >= 0 && idx < len(rs.Deposed) {
36 return rs.Deposed[idx], nil
38 return nil, fmt.Errorf("bad deposed index: %d, for resource: %#v", idx, rs)
43 // Does the bulk of the work for the various flavors of ReadState eval nodes.
44 // Each node just provides a reader function to get from the ResourceState to the
45 // InstanceState, and this takes care of all the plumbing.
46 func readInstanceFromState(
49 output **InstanceState,
50 readerFn func(*ResourceState) (*InstanceState, error),
51 ) (*InstanceState, error) {
52 state, lock := ctx.State()
54 // Get a read lock so we can access this instance
58 // Look for the module state. If we don't have one, then it doesn't matter.
59 mod := state.ModuleByPath(ctx.Path())
64 // Look for the resource state. If we don't have one, then it is okay.
65 rs := mod.Resources[resourceName]
70 // Use the delegate function to get the instance state from the resource state
71 is, err := readerFn(rs)
76 // Write the result to the output pointer
84 // EvalRequireState is an EvalNode implementation that early exits
85 // if the state doesn't have an ID.
86 type EvalRequireState struct {
90 func (n *EvalRequireState) Eval(ctx EvalContext) (interface{}, error) {
92 return nil, EvalEarlyExitError{}
96 if state == nil || state.ID == "" {
97 return nil, EvalEarlyExitError{}
103 // EvalUpdateStateHook is an EvalNode implementation that calls the
104 // PostStateUpdate hook with the current state.
105 type EvalUpdateStateHook struct{}
107 func (n *EvalUpdateStateHook) Eval(ctx EvalContext) (interface{}, error) {
108 state, lock := ctx.State()
110 // Get a full lock. Even calling something like WriteState can modify
111 // (prune) the state, so we need the full lock.
116 err := ctx.Hook(func(h Hook) (HookAction, error) {
117 return h.PostStateUpdate(state)
126 // EvalWriteState is an EvalNode implementation that writes the
127 // primary InstanceState for a specific resource into the state.
128 type EvalWriteState struct {
132 Dependencies []string
133 State **InstanceState
136 func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
137 return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
138 func(rs *ResourceState) error {
139 rs.Primary = *n.State
145 // EvalWriteStateDeposed is an EvalNode implementation that writes
146 // an InstanceState out to the Deposed list of a resource in the state.
147 type EvalWriteStateDeposed struct {
151 Dependencies []string
152 State **InstanceState
153 // Index indicates which instance in the Deposed list to target, or -1 to append.
157 func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
158 return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
159 func(rs *ResourceState) error {
161 rs.Deposed = append(rs.Deposed, *n.State)
163 rs.Deposed[n.Index] = *n.State
170 // Pulls together the common tasks of the EvalWriteState nodes. All the args
171 // are passed directly down from the EvalNode along with a `writer` function
172 // which is yielded the *ResourceState and is responsible for writing an
173 // InstanceState to the proper field in the ResourceState.
174 func writeInstanceToState(
179 dependencies []string,
180 writerFn func(*ResourceState) error,
181 ) (*InstanceState, error) {
182 state, lock := ctx.State()
184 return nil, fmt.Errorf("cannot write state to nil state")
187 // Get a write lock so we can access this instance
191 // Look for the module state. If we don't have one, create it.
192 mod := state.ModuleByPath(ctx.Path())
194 mod = state.AddModule(ctx.Path())
197 // Look for the resource state.
198 rs := mod.Resources[resourceName]
200 rs = &ResourceState{}
202 mod.Resources[resourceName] = rs
204 rs.Type = resourceType
205 rs.Dependencies = dependencies
206 rs.Provider = provider
208 if err := writerFn(rs); err != nil {
215 // EvalClearPrimaryState is an EvalNode implementation that clears the primary
216 // instance from a resource state.
217 type EvalClearPrimaryState struct {
221 func (n *EvalClearPrimaryState) Eval(ctx EvalContext) (interface{}, error) {
222 state, lock := ctx.State()
224 // Get a read lock so we can access this instance
228 // Look for the module state. If we don't have one, then it doesn't matter.
229 mod := state.ModuleByPath(ctx.Path())
234 // Look for the resource state. If we don't have one, then it is okay.
235 rs := mod.Resources[n.Name]
240 // Clear primary from the resource state
246 // EvalDeposeState is an EvalNode implementation that takes the primary
247 // out of a state and makes it Deposed. This is done at the beginning of
248 // create-before-destroy calls so that the create can create while preserving
249 // the old state of the to-be-destroyed resource.
250 type EvalDeposeState struct {
255 func (n *EvalDeposeState) Eval(ctx EvalContext) (interface{}, error) {
256 state, lock := ctx.State()
258 // Get a read lock so we can access this instance
262 // Look for the module state. If we don't have one, then it doesn't matter.
263 mod := state.ModuleByPath(ctx.Path())
268 // Look for the resource state. If we don't have one, then it is okay.
269 rs := mod.Resources[n.Name]
274 // If we don't have a primary, we have nothing to depose
275 if rs.Primary == nil {
280 rs.Deposed = append(rs.Deposed, rs.Primary)
286 // EvalUndeposeState is an EvalNode implementation that reads the
287 // InstanceState for a specific resource out of the state.
288 type EvalUndeposeState struct {
290 State **InstanceState
294 func (n *EvalUndeposeState) Eval(ctx EvalContext) (interface{}, error) {
295 state, lock := ctx.State()
297 // Get a read lock so we can access this instance
301 // Look for the module state. If we don't have one, then it doesn't matter.
302 mod := state.ModuleByPath(ctx.Path())
307 // Look for the resource state. If we don't have one, then it is okay.
308 rs := mod.Resources[n.Name]
313 // If we don't have any desposed resource, then we don't have anything to do
314 if len(rs.Deposed) == 0 {
319 idx := len(rs.Deposed) - 1
320 rs.Primary = rs.Deposed[idx]
321 rs.Deposed[idx] = *n.State