-
Notifications
You must be signed in to change notification settings - Fork 9.6k
/
plan.go
71 lines (64 loc) · 2.71 KB
/
plan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package statemgr
import (
"fmt"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/states/statefile"
)
// PlannedStateUpdate is a special helper to obtain a statefile representation
// of a not-yet-written state snapshot that can be written later by a call
// to the companion function WritePlannedStateUpdate.
//
// The statefile object returned here has an unusual interpretation of its
// metadata that is understood only by WritePlannedStateUpdate, and so the
// returned object should not be used for any other purpose.
//
// If the state manager implements Locker then it is the caller's
// responsibility to hold the lock at least for the duration of this call.
// It is not safe to modify the given state concurrently while
// PlannedStateUpdate is running.
func PlannedStateUpdate(mgr Transient, planned *states.State) *statefile.File {
ret := &statefile.File{
State: planned.DeepCopy(),
}
// If the given manager uses snapshot metadata then we'll save that
// in our file so we can check it again during WritePlannedStateUpdate.
if mr, ok := mgr.(PersistentMeta); ok {
m := mr.StateSnapshotMeta()
ret.Lineage = m.Lineage
ret.Serial = m.Serial
}
return ret
}
// WritePlannedStateUpdate is a companion to PlannedStateUpdate that attempts
// to apply a state update that was planned earlier to the given state
// manager.
//
// An error is returned if this function detects that a new state snapshot
// has been written to the backend since the update was planned, since that
// invalidates the plan. An error is returned also if the manager itself
// rejects the given state when asked to store it.
//
// If the returned error is nil, the given manager's transient state snapshot
// is updated to match what was planned. It is the caller's responsibility
// to then persist that state if the manager also implements Persistent and
// the snapshot should be written to the persistent store.
//
// If the state manager implements Locker then it is the caller's
// responsibility to hold the lock at least for the duration of this call.
func WritePlannedStateUpdate(mgr Transient, planned *statefile.File) error {
// If the given manager uses snapshot metadata then we'll check to make
// sure no new snapshots have been created since we planned to write
// the given state file.
if mr, ok := mgr.(PersistentMeta); ok {
m := mr.StateSnapshotMeta()
if planned.Lineage != "" {
if planned.Lineage != m.Lineage {
return fmt.Errorf("planned state update is from an unrelated state lineage than the current state")
}
if planned.Serial != m.Serial {
return fmt.Errorf("stored state has been changed by another operation since the given update was planned")
}
}
}
return mgr.WriteState(planned.State)
}