| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 package uniter | |
| 2 | |
| 3 import ( | |
| 4 "errors" | |
| 5 "fmt" | |
| 6 "launchpad.net/juju-core/charm" | |
| 7 "launchpad.net/juju-core/trivial" | |
| 8 "launchpad.net/juju-core/worker/uniter/hook" | |
| 9 "os" | |
| 10 ) | |
| 11 | |
| 12 // Op enumerates the operations the uniter can perform. | |
| 13 type Op string | |
| 14 | |
| 15 const ( | |
| 16 // Install indicates that the uniter is installing the charm. | |
| 17 Install Op = "install" | |
| 18 | |
| 19 // RunHook indicates that the uniter is running a hook. | |
| 20 RunHook Op = "run-hook" | |
| 21 | |
| 22 // Upgrade indicates that the uniter is upgrading the charm. | |
| 23 Upgrade Op = "upgrade" | |
| 24 | |
| 25 // Abide indicates that the uniter is not currently executing | |
| 26 // any other operation. | |
| 27 Abide Op = "abide" | |
| 28 ) | |
| 29 | |
| 30 // Status enumerates the possible operation statuses. | |
| 31 type Status string | |
|
niemeyer
2012/09/11 14:52:04
Can we call this and the field in State as OpStep?
fwereade
2012/09/12 15:16:40
SGTM. Done.
| |
| 32 | |
| 33 const ( | |
| 34 // Queued indicates that the uniter should undertake the operation | |
| 35 // as soon as possible. | |
| 36 Queued Status = "queued" | |
| 37 | |
| 38 // Pending indicates that the uniter has started, but not completed, | |
| 39 // the operation. | |
| 40 Pending Status = "pending" | |
| 41 | |
| 42 // Committing indicates that the uniter has completed the operation, | |
|
niemeyer
2012/09/11 14:52:04
This status is feeling a bit awkward now. All of t
| |
| 43 // but has yet to synchronize all necessary state. | |
| 44 Committing Status = "committing" | |
| 45 ) | |
| 46 | |
| 47 // State defines the local persistent state of the uniter, excluding relation | |
| 48 // state. | |
| 49 type State struct { | |
| 50 // Op indicates the current operation. | |
| 51 Op Op | |
| 52 | |
| 53 // Status indicates the current operation's status. | |
| 54 Status Status | |
| 55 | |
| 56 // Hook holds hook information relevant to the current operation. If Op | |
| 57 // is Abide, it holds the last hook that was executed; if Op is RunHook, | |
| 58 // it holds the running hook; if Op is Upgrade, a non-nil hook indicates | |
| 59 // that the uniter should return to that hook's Pending state after the | |
| 60 // upgrade is complete (instead of running an upgrade-charm hook). | |
| 61 Hook *hook.Info `yaml:"hook,omitempty"` | |
| 62 | |
| 63 // Charm describes the charm being deployed by an Install or Upgrade | |
| 64 // operation, and is otherwise blank. | |
| 65 CharmURL *charm.URL `yaml:"charm,omitempty"` | |
| 66 } | |
| 67 | |
| 68 // validate returns an error if the state violates expectations. | |
| 69 func (st State) validate() error { | |
| 70 hasHook := st.Hook != nil | |
| 71 hasCharm := st.CharmURL != nil | |
| 72 switch st.Op { | |
| 73 case Install: | |
| 74 if hasHook { | |
| 75 return fmt.Errorf("unexpected hook info") | |
| 76 } | |
| 77 fallthrough | |
| 78 case Upgrade: | |
| 79 if !hasCharm { | |
| 80 return fmt.Errorf("missing charm URL") | |
| 81 } | |
| 82 case Abide, RunHook: | |
| 83 if !hasHook { | |
| 84 return fmt.Errorf("missing hook info") | |
| 85 } else if hasCharm { | |
| 86 return fmt.Errorf("unexpected charm URL") | |
| 87 } | |
| 88 default: | |
| 89 return fmt.Errorf("unknown operation %q", st.Op) | |
| 90 } | |
| 91 switch st.Status { | |
| 92 case Queued, Pending, Committing: | |
| 93 default: | |
| 94 return fmt.Errorf("unknown operation status %q", st.Status) | |
| 95 } | |
| 96 if hasHook { | |
| 97 return st.Hook.Validate() | |
| 98 } | |
| 99 return nil | |
| 100 } | |
| 101 | |
| 102 // StateFile reads and writes uniter operation state. | |
|
niemeyer
2012/09/11 14:52:04
// A StateFile holds the disk state for a uniter.
fwereade
2012/09/12 15:16:40
Done.
| |
| 103 type StateFile struct { | |
| 104 path string | |
| 105 } | |
| 106 | |
| 107 // NewStateFile returns a new StateFile using path. | |
| 108 func NewStateFile(path string) *StateFile { | |
| 109 return &StateFile{path} | |
| 110 } | |
| 111 | |
| 112 var ErrNoStateFile = errors.New("uniter state file does not exist") | |
| 113 | |
| 114 // Read reads a State from the file. If the file does not exist it returns | |
| 115 // ErrNoStateFile. | |
| 116 func (f *StateFile) Read() (State, error) { | |
|
niemeyer
2012/09/11 14:52:04
A *State here would be nice to work with and idiom
fwereade
2012/09/12 15:16:40
Done.
| |
| 117 var st State | |
| 118 if err := trivial.ReadYaml(f.path, &st); err != nil { | |
| 119 if os.IsNotExist(err) { | |
| 120 return State{}, ErrNoStateFile | |
| 121 } | |
| 122 } | |
| 123 if err := st.validate(); err != nil { | |
| 124 return State{}, fmt.Errorf("invalid uniter state at %s: %s", f.p ath, err) | |
|
niemeyer
2012/09/11 14:52:04
s/at %s: %s/at %q: %v/
fwereade
2012/09/12 15:16:40
Done.
| |
| 125 } | |
| 126 return st, nil | |
| 127 } | |
| 128 | |
| 129 // Write stores the supplied state to the file. | |
| 130 func (f *StateFile) Write(op Op, status Status, hi *hook.Info, url *charm.URL) e rror { | |
| 131 if hi != nil { | |
| 132 // Strip membership info: it's potentially large, and can | |
| 133 // be reconstructed from relation state when required. | |
|
niemeyer
2012/09/11 14:52:04
This reflects better the intended operation, and r
fwereade
2012/09/12 15:16:40
Nice. Done.
| |
| 134 hi = &hook.Info{ | |
| 135 Kind: hi.Kind, | |
| 136 RelationId: hi.RelationId, | |
| 137 RemoteUnit: hi.RemoteUnit, | |
| 138 ChangeVersion: hi.ChangeVersion, | |
| 139 } | |
| 140 } | |
| 141 st := &State{ | |
| 142 Op: op, | |
| 143 Status: status, | |
| 144 Hook: hi, | |
| 145 CharmURL: url, | |
| 146 } | |
| 147 if err := st.validate(); err != nil { | |
| 148 panic(err) | |
| 149 } | |
| 150 return trivial.WriteYaml(f.path, st) | |
| 151 } | |
| OLD | NEW |