7 // EvalReadState is an EvalNode implementation that reads the
8 // primary InstanceState for a specific resource out of the state.
9 type EvalReadState struct {
11 Output **InstanceState
14 func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
15 return readInstanceFromState(ctx, n.Name, n.Output, func(rs *ResourceState) (*InstanceState, error) {
16 return rs.Primary, nil
20 // EvalReadStateDeposed is an EvalNode implementation that reads the
21 // deposed InstanceState for a specific resource out of the state
22 type EvalReadStateDeposed struct {
24 Output **InstanceState
25 // Index indicates which instance in the Deposed list to target, or -1 for
30 func (n *EvalReadStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
31 return readInstanceFromState(ctx, n.Name, n.Output, func(rs *ResourceState) (*InstanceState, error) {
32 // Get the index. If it is negative, then we get the last one
35 idx = len(rs.Deposed) - 1
37 if idx >= 0 && idx < len(rs.Deposed) {
38 return rs.Deposed[idx], nil
40 return nil, fmt.Errorf("bad deposed index: %d, for resource: %#v", idx, rs)
45 // Does the bulk of the work for the various flavors of ReadState eval nodes.
46 // Each node just provides a reader function to get from the ResourceState to the
47 // InstanceState, and this takes care of all the plumbing.
48 func readInstanceFromState(
51 output **InstanceState,
52 readerFn func(*ResourceState) (*InstanceState, error),
53 ) (*InstanceState, error) {
54 state, lock := ctx.State()
56 // Get a read lock so we can access this instance
60 // Look for the module state. If we don't have one, then it doesn't matter.
61 mod := state.ModuleByPath(ctx.Path())
66 // Look for the resource state. If we don't have one, then it is okay.
67 rs := mod.Resources[resourceName]
72 // Use the delegate function to get the instance state from the resource state
73 is, err := readerFn(rs)
78 // Write the result to the output pointer
86 // EvalRequireState is an EvalNode implementation that early exits
87 // if the state doesn't have an ID.
88 type EvalRequireState struct {
92 func (n *EvalRequireState) Eval(ctx EvalContext) (interface{}, error) {
94 return nil, EvalEarlyExitError{}
98 if state == nil || state.ID == "" {
99 return nil, EvalEarlyExitError{}
105 // EvalUpdateStateHook is an EvalNode implementation that calls the
106 // PostStateUpdate hook with the current state.
107 type EvalUpdateStateHook struct{}
109 func (n *EvalUpdateStateHook) Eval(ctx EvalContext) (interface{}, error) {
110 state, lock := ctx.State()
112 // Get a full lock. Even calling something like WriteState can modify
113 // (prune) the state, so we need the full lock.
118 err := ctx.Hook(func(h Hook) (HookAction, error) {
119 return h.PostStateUpdate(state)
128 // EvalWriteState is an EvalNode implementation that writes the
129 // primary InstanceState for a specific resource into the state.
130 type EvalWriteState struct {
134 Dependencies []string
135 State **InstanceState
138 func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
139 return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
140 func(rs *ResourceState) error {
141 rs.Primary = *n.State
147 // EvalWriteStateDeposed is an EvalNode implementation that writes
148 // an InstanceState out to the Deposed list of a resource in the state.
149 type EvalWriteStateDeposed struct {
153 Dependencies []string
154 State **InstanceState
155 // Index indicates which instance in the Deposed list to target, or -1 to append.
159 func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
160 return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
161 func(rs *ResourceState) error {
163 rs.Deposed = append(rs.Deposed, *n.State)
165 rs.Deposed[n.Index] = *n.State
172 // Pulls together the common tasks of the EvalWriteState nodes. All the args
173 // are passed directly down from the EvalNode along with a `writer` function
174 // which is yielded the *ResourceState and is responsible for writing an
175 // InstanceState to the proper field in the ResourceState.
176 func writeInstanceToState(
181 dependencies []string,
182 writerFn func(*ResourceState) error,
183 ) (*InstanceState, error) {
184 state, lock := ctx.State()
186 return nil, fmt.Errorf("cannot write state to nil state")
189 // Get a write lock so we can access this instance
193 // Look for the module state. If we don't have one, create it.
194 mod := state.ModuleByPath(ctx.Path())
196 mod = state.AddModule(ctx.Path())
199 // Look for the resource state.
200 rs := mod.Resources[resourceName]
202 rs = &ResourceState{}
204 mod.Resources[resourceName] = rs
206 rs.Type = resourceType
207 rs.Dependencies = dependencies
208 rs.Provider = provider
210 if err := writerFn(rs); err != nil {
217 // EvalDeposeState is an EvalNode implementation that takes the primary
218 // out of a state and makes it Deposed. This is done at the beginning of
219 // create-before-destroy calls so that the create can create while preserving
220 // the old state of the to-be-destroyed resource.
221 type EvalDeposeState struct {
226 func (n *EvalDeposeState) Eval(ctx EvalContext) (interface{}, error) {
227 state, lock := ctx.State()
229 // Get a read lock so we can access this instance
233 // Look for the module state. If we don't have one, then it doesn't matter.
234 mod := state.ModuleByPath(ctx.Path())
239 // Look for the resource state. If we don't have one, then it is okay.
240 rs := mod.Resources[n.Name]
245 // If we don't have a primary, we have nothing to depose
246 if rs.Primary == nil {
251 rs.Deposed = append(rs.Deposed, rs.Primary)
257 // EvalUndeposeState is an EvalNode implementation that reads the
258 // InstanceState for a specific resource out of the state.
259 type EvalUndeposeState struct {
261 State **InstanceState
265 func (n *EvalUndeposeState) Eval(ctx EvalContext) (interface{}, error) {
266 state, lock := ctx.State()
268 // Get a read lock so we can access this instance
272 // Look for the module state. If we don't have one, then it doesn't matter.
273 mod := state.ModuleByPath(ctx.Path())
278 // Look for the resource state. If we don't have one, then it is okay.
279 rs := mod.Resources[n.Name]
284 // If we don't have any desposed resource, then we don't have anything to do
285 if len(rs.Deposed) == 0 {
290 idx := len(rs.Deposed) - 1
291 rs.Primary = rs.Deposed[idx]
292 rs.Deposed[idx] = *n.State