Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1)

Delta Between Two Patch Sets: worker/uniter/modes.go

Issue 6588053: uniter: integrate filter type
Left Patch Set: uniter: integrate filter type Created 12 years, 6 months ago
Right Patch Set: uniter: integrate filter type Created 12 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « worker/uniter/filter_test.go ('k') | worker/uniter/uniter.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 package uniter 1 package uniter
2 2
3 import ( 3 import (
4 "errors" 4 "errors"
5 "fmt" 5 "fmt"
6 "launchpad.net/juju-core/environs" 6 "launchpad.net/juju-core/environs"
7 "launchpad.net/juju-core/log" 7 "launchpad.net/juju-core/log"
8 "launchpad.net/juju-core/state" 8 "launchpad.net/juju-core/state"
9 "launchpad.net/juju-core/worker"
9 "launchpad.net/juju-core/worker/uniter/charm" 10 "launchpad.net/juju-core/worker/uniter/charm"
10 "launchpad.net/juju-core/worker/uniter/hook" 11 "launchpad.net/juju-core/worker/uniter/hook"
11 "launchpad.net/tomb" 12 "launchpad.net/tomb"
12 ) 13 )
13 14
14 // Mode defines the signature of the functions that implement the possible 15 // Mode defines the signature of the functions that implement the possible
15 // states of a running Uniter. 16 // states of a running Uniter.
16 type Mode func(u *Uniter) (Mode, error) 17 type Mode func(u *Uniter) (Mode, error)
17 18
18 // ModeInit is the initial Uniter mode. 19 // ModeInit is the initial Uniter mode.
19 func ModeInit(u *Uniter) (next Mode, err error) { 20 func ModeInit(u *Uniter) (next Mode, err error) {
20 » defer modeContext("ModeInit", &next, &err)() 21 » defer modeContext("ModeInit", &err)()
21 log.Printf("updating unit addresses") 22 log.Printf("updating unit addresses")
22 cfg, err := u.st.EnvironConfig() 23 cfg, err := u.st.EnvironConfig()
23 if err != nil { 24 if err != nil {
24 return nil, err 25 return nil, err
25 } 26 }
26 provider, err := environs.Provider(cfg.Type()) 27 provider, err := environs.Provider(cfg.Type())
27 if err != nil { 28 if err != nil {
28 return nil, err 29 return nil, err
29 } 30 }
30 if private, err := provider.PrivateAddress(); err != nil { 31 if private, err := provider.PrivateAddress(); err != nil {
31 return nil, err 32 return nil, err
32 } else if err = u.unit.SetPrivateAddress(private); err != nil { 33 } else if err = u.unit.SetPrivateAddress(private); err != nil {
33 return nil, err 34 return nil, err
34 } 35 }
35 if public, err := provider.PublicAddress(); err != nil { 36 if public, err := provider.PublicAddress(); err != nil {
36 return nil, err 37 return nil, err
37 } else if err = u.unit.SetPublicAddress(public); err != nil { 38 } else if err = u.unit.SetPublicAddress(public); err != nil {
38 return nil, err 39 return nil, err
39 } 40 }
40 return ModeContinue, nil 41 return ModeContinue, nil
41 } 42 }
42 43
43 // ModeContinue determines what action to take based on persistent uniter state. 44 // ModeContinue determines what action to take based on persistent uniter state.
44 func ModeContinue(u *Uniter) (next Mode, err error) { 45 func ModeContinue(u *Uniter) (next Mode, err error) {
45 » defer modeContext("ModeContinue", &next, &err)() 46 » defer modeContext("ModeContinue", &err)()
46 47
47 // When no charm exists, install it. 48 // When no charm exists, install it.
48 s, err := u.sf.Read() 49 s, err := u.sf.Read()
49 if err == ErrNoStateFile { 50 if err == ErrNoStateFile {
50 log.Printf("charm is not deployed") 51 log.Printf("charm is not deployed")
51 sch, _, err := u.service.Charm() 52 sch, _, err := u.service.Charm()
52 if err != nil { 53 if err != nil {
53 return nil, err 54 return nil, err
54 } 55 }
55 return ModeInstalling(sch), nil 56 return ModeInstalling(sch), nil
56 } else if err != nil { 57 } else if err != nil {
57 return nil, err 58 return nil, err
58 } 59 }
59 60
60 // Filter out states not related to charm deployment. 61 // Filter out states not related to charm deployment.
61 switch s.Op { 62 switch s.Op {
62 case Abide: 63 case Abide:
63 log.Printf("continuing after %q hook", s.Hook.Kind) 64 log.Printf("continuing after %q hook", s.Hook.Kind)
64 switch s.Hook.Kind { 65 switch s.Hook.Kind {
65 case hook.Install: 66 case hook.Install:
66 return ModeStarting, nil 67 return ModeStarting, nil
67 case hook.Stop: 68 case hook.Stop:
68 return ModeTerminating, nil 69 return ModeTerminating, nil
69 } 70 }
70 return ModeAbide, nil 71 return ModeAbide, nil
71 case RunHook: 72 case RunHook:
72 if s.OpStep == Queued { 73 if s.OpStep == Queued {
73 log.Printf("found queued %q hook", s.Hook.Kind) 74 log.Printf("found queued %q hook", s.Hook.Kind)
74 » » » return nil, u.runHook(*s.Hook) 75 » » » if err = u.runHook(*s.Hook); err != nil && err != errHoo kFailed {
76 » » » » return nil, err
77 » » » }
78 » » » return ModeContinue, nil
75 } 79 }
76 if s.OpStep == Done { 80 if s.OpStep == Done {
77 log.Printf("found uncommitted %q hook", s.Hook.Kind) 81 log.Printf("found uncommitted %q hook", s.Hook.Kind)
78 » » » return nil, u.commitHook(*s.Hook) 82 » » » if err = u.commitHook(*s.Hook); err != nil {
83 » » » » return nil, err
84 » » » }
85 » » » return ModeContinue, nil
79 } 86 }
80 log.Printf("awaiting error resolution for %q hook", s.Hook.Kind) 87 log.Printf("awaiting error resolution for %q hook", s.Hook.Kind)
81 return ModeHookError, nil 88 return ModeHookError, nil
82 } 89 }
83 90
84 // Resume interrupted deployment operations. 91 // Resume interrupted deployment operations.
85 sch, err := u.st.Charm(s.CharmURL) 92 sch, err := u.st.Charm(s.CharmURL)
86 if err != nil { 93 if err != nil {
87 return nil, err 94 return nil, err
88 } 95 }
89 if s.Op == Install { 96 if s.Op == Install {
90 log.Printf("resuming charm install") 97 log.Printf("resuming charm install")
91 return ModeInstalling(sch), nil 98 return ModeInstalling(sch), nil
92 } else if s.Op == Upgrade { 99 } else if s.Op == Upgrade {
93 log.Printf("resuming charm upgrade") 100 log.Printf("resuming charm upgrade")
94 return ModeUpgrading(sch), nil 101 return ModeUpgrading(sch), nil
95 } 102 }
96 panic(fmt.Errorf("unhandled uniter operation %q", s.Op)) 103 panic(fmt.Errorf("unhandled uniter operation %q", s.Op))
97 } 104 }
98 105
99 // ModeInstalling is responsible for the initial charm deployment. 106 // ModeInstalling is responsible for the initial charm deployment.
100 func ModeInstalling(sch *state.Charm) Mode { 107 func ModeInstalling(sch *state.Charm) Mode {
108 name := fmt.Sprintf("ModeInstalling %s", sch.URL())
101 return func(u *Uniter) (next Mode, err error) { 109 return func(u *Uniter) (next Mode, err error) {
102 » » name := fmt.Sprintf("ModeInstalling %s", sch.URL()) 110 » » defer modeContext(name, &err)()
103 » » defer modeContext(name, &next, &err)() 111 » » if err = u.deploy(sch, Install); err != nil {
104 » » return nil, u.deploy(sch, Install) 112 » » » return nil, err
113 » » }
114 » » return ModeContinue, nil
105 } 115 }
106 } 116 }
107 117
108 // ModeUpgrading is responsible for upgrading the charm. 118 // ModeUpgrading is responsible for upgrading the charm.
109 func ModeUpgrading(sch *state.Charm) Mode { 119 func ModeUpgrading(sch *state.Charm) Mode {
120 name := fmt.Sprintf("ModeUpgrading %s", sch.URL())
110 return func(u *Uniter) (next Mode, err error) { 121 return func(u *Uniter) (next Mode, err error) {
111 » » name := fmt.Sprintf("ModeUpgrading %s", sch.URL()) 122 » » defer modeContext(name, &err)()
112 » » defer modeContext(name, &next, &err)()
113 if err = u.deploy(sch, Upgrade); err == charm.ErrConflict { 123 if err = u.deploy(sch, Upgrade); err == charm.ErrConflict {
114 return ModeConflicted(sch), nil 124 return ModeConflicted(sch), nil
115 » » } 125 » » } else if err != nil {
116 » » return nil, err 126 » » » return nil, err
127 » » }
128 » » return ModeContinue, nil
117 } 129 }
118 } 130 }
119 131
120 // ModeStarting runs the "start" hook. 132 // ModeStarting runs the "start" hook.
121 func ModeStarting(u *Uniter) (next Mode, err error) { 133 func ModeStarting(u *Uniter) (next Mode, err error) {
122 » defer modeContext("ModeStarting", &next, &err)() 134 » defer modeContext("ModeStarting", &err)()
123 if err = u.unit.SetStatus(state.UnitInstalled, ""); err != nil { 135 if err = u.unit.SetStatus(state.UnitInstalled, ""); err != nil {
124 return nil, err 136 return nil, err
125 } 137 }
126 » return nil, u.runHook(hook.Info{Kind: hook.Start}) 138 » if err := u.runHook(hook.Info{Kind: hook.Start}); err == errHookFailed {
139 » » return ModeHookError, nil
140 » } else if err != nil {
141 » » return nil, err
142 » }
143 » return ModeContinue, nil
127 } 144 }
128 145
129 // ModeStopping runs the "stop" hook. 146 // ModeStopping runs the "stop" hook.
130 func ModeStopping(u *Uniter) (next Mode, err error) { 147 func ModeStopping(u *Uniter) (next Mode, err error) {
131 » defer modeContext("ModeStopping", &next, &err)() 148 » defer modeContext("ModeStopping", &err)()
132 » return nil, u.runHook(hook.Info{Kind: hook.Stop}) 149 » if err := u.runHook(hook.Info{Kind: hook.Stop}); err == errHookFailed {
150 » » return ModeHookError, nil
151 » } else if err != nil {
152 » » return nil, err
153 » }
154 » return ModeContinue, nil
133 } 155 }
134 156
135 // ModeTerminating marks the unit dead and returns ErrDead. 157 // ModeTerminating marks the unit dead and returns ErrDead.
136 func ModeTerminating(u *Uniter) (next Mode, err error) { 158 func ModeTerminating(u *Uniter) (next Mode, err error) {
137 » defer modeContext("ModeTerminating", &next, &err)() 159 » defer modeContext("ModeTerminating", &err)()
138 if err = u.unit.SetStatus(state.UnitStopped, ""); err != nil { 160 if err = u.unit.SetStatus(state.UnitStopped, ""); err != nil {
139 return nil, err 161 return nil, err
140 } 162 }
141 if err = u.unit.EnsureDead(); err != nil { 163 if err = u.unit.EnsureDead(); err != nil {
142 return nil, err 164 return nil, err
143 } 165 }
144 » return nil, ErrDead 166 » return nil, worker.ErrDead
145 } 167 }
146 168
147 // ModeAbide is the Uniter's usual steady state. It watches for and responds to: 169 // ModeAbide is the Uniter's usual steady state. It watches for and responds to:
148 // * service configuration changes 170 // * service configuration changes
149 // * charm upgrade requests 171 // * charm upgrade requests
150 // * relation changes (not implemented) 172 // * relation changes (not implemented)
151 // * unit death 173 // * unit death
152 func ModeAbide(u *Uniter) (next Mode, err error) { 174 func ModeAbide(u *Uniter) (next Mode, err error) {
153 » defer modeContext("ModeAbide", &next, &err)() 175 » defer modeContext("ModeAbide", &err)()
154 s, err := u.sf.Read() 176 s, err := u.sf.Read()
155 if err != nil { 177 if err != nil {
156 return nil, err 178 return nil, err
157 } 179 }
158 if s.Op != Abide { 180 if s.Op != Abide {
159 return nil, fmt.Errorf("insane uniter state: %#v", s) 181 return nil, fmt.Errorf("insane uniter state: %#v", s)
rog 2012/10/01 11:02:58 "insane uniter state; expected Abide, got %#v", s)
160 } 182 }
161 if err = u.unit.SetStatus(state.UnitStarted, ""); err != nil { 183 if err = u.unit.SetStatus(state.UnitStarted, ""); err != nil {
162 return nil, err 184 return nil, err
163 } 185 }
164 186
165 » // Execute an initial config-changed hook regardless of state. 187 » // Prime the filter by requesting a config event, then handling it. This
niemeyer 2012/10/01 22:47:33 s/regardless of state//; We only got here after qu
fwereade 2012/10/02 07:01:35 SGTM
188 » // has two purposes: (1) run a config-change hook before doing anything
189 » // else and (2) ensure that subsequent config events received actually
190 » // correspond to changes relative to the state at the time we first ran
191 » // the hook.
166 cc := hook.Info{Kind: hook.ConfigChanged} 192 cc := hook.Info{Kind: hook.ConfigChanged}
167 » u.wantConfigEvent() 193 » u.f.WantConfigEvent()
168 select { 194 select {
169 case <-u.Dying(): 195 case <-u.Dying():
170 return nil, tomb.ErrDying 196 return nil, tomb.ErrDying
171 » case <-u.configEvents(): 197 » case <-u.f.ConfigEvents():
niemeyer 2012/10/01 22:47:33 It'd be good to have a comment explaining why we h
fwereade 2012/10/02 07:01:35 The rationale is that we want to run one config-ch
172 » » if err = u.runHook(cc); err != nil { 198 » » if err = u.runHook(cc); err == errHookFailed {
173 » » » return nil, err 199 » » » return ModeHookError, nil
174 » » } 200 » » } else if err != nil {
175 » } 201 » » » return nil, err
176 202 » » }
177 » // Watch for everything else (including further config changes). 203 » }
niemeyer 2012/10/01 22:47:33 d It's not watching everything else. It's watchin
fwereade 2012/10/02 07:01:35 Ha, yes.
178 » u.wantCharmEvent() 204
205 » url, err := charm.ReadCharmURL(u.charm)
206 » if err != nil {
207 » » return nil, err
208 » }
209 » u.f.WantUpgradeEvent(url, false)
179 for { 210 for {
180 select { 211 select {
181 case <-u.Dying(): 212 case <-u.Dying():
182 return nil, tomb.ErrDying 213 return nil, tomb.ErrDying
183 » » case <-u.unitDying(): 214 » » case <-u.f.UnitDying():
184 // TODO don't stop until all relations broken. 215 // TODO don't stop until all relations broken.
185 return ModeStopping, nil 216 return ModeStopping, nil
186 » » case <-u.configEvents(): 217 » » case <-u.f.ConfigEvents():
187 » » » if err = u.runHook(cc); err != nil { 218 » » » if err = u.runHook(cc); err == errHookFailed {
188 » » » » return nil, err 219 » » » » return ModeHookError, nil
189 » » » }
190 » » case ch := <-u.charmEvents():
191 » » » upgrade, err := u.getUpgrade(ch, false)
192 » » » if err == errNoUpgrade {
193 » » » » continue
194 } else if err != nil { 220 } else if err != nil {
195 return nil, err 221 return nil, err
196 } 222 }
223 case upgrade := <-u.f.UpgradeEvents():
197 return ModeUpgrading(upgrade), nil 224 return ModeUpgrading(upgrade), nil
198 } 225 }
199 } 226 }
200 panic("unreachable") 227 panic("unreachable")
201 } 228 }
202 229
203 // ModeHookError is responsible for watching and responding to: 230 // ModeHookError is responsible for watching and responding to:
204 // * user resolution of hook errors 231 // * user resolution of hook errors
205 // * charm upgrade requests 232 // * charm upgrade requests
206 func ModeHookError(u *Uniter) (next Mode, err error) { 233 func ModeHookError(u *Uniter) (next Mode, err error) {
207 » defer modeContext("ModeHookError", &next, &err)() 234 » defer modeContext("ModeHookError", &err)()
208 s, err := u.sf.Read() 235 s, err := u.sf.Read()
209 if err != nil { 236 if err != nil {
210 return nil, err 237 return nil, err
211 } 238 }
212 if s.Op != RunHook || s.OpStep != Pending { 239 if s.Op != RunHook || s.OpStep != Pending {
213 return nil, fmt.Errorf("insane uniter state: %#v", s) 240 return nil, fmt.Errorf("insane uniter state: %#v", s)
214 } 241 }
215 msg := fmt.Sprintf("hook failed: %q", s.Hook.Kind) 242 msg := fmt.Sprintf("hook failed: %q", s.Hook.Kind)
216 if err = u.unit.SetStatus(state.UnitError, msg); err != nil { 243 if err = u.unit.SetStatus(state.UnitError, msg); err != nil {
217 return nil, err 244 return nil, err
218 } 245 }
219 » resolveHook := getResolveHook(*s.Hook) 246 » url, err := charm.ReadCharmURL(u.charm)
220 » u.wantResolvedEvent() 247 » if err != nil {
221 » u.wantCharmEvent() 248 » » return nil, err
249 » }
250 » u.f.WantResolvedEvent()
251 » u.f.WantUpgradeEvent(url, true)
222 for { 252 for {
223 select { 253 select {
224 case <-u.Dying(): 254 case <-u.Dying():
225 return nil, tomb.ErrDying 255 return nil, tomb.ErrDying
226 » » case rm := <-u.resolvedEvents(): 256 » » case rm := <-u.f.ResolvedEvents():
227 » » » if success, err := u.resolveError(*rm, resolveHook); suc cess { 257 » » » switch rm {
228 » » » » return ModeContinue, nil 258 » » » case state.ResolvedRetryHooks:
229 » » » } else if err != nil && err != errHookFailed { 259 » » » » err = u.runHook(*s.Hook)
230 » » » » return nil, err 260 » » » case state.ResolvedNoHooks:
231 » » » } 261 » » » » err = u.commitHook(*s.Hook)
232 » » case ch := <-u.charmEvents(): 262 » » » default:
233 » » » upgrade, err := u.getUpgrade(ch, true) 263 » » » » return nil, fmt.Errorf("unknown resolved mode %q ", rm)
234 » » » if err == errNoUpgrade { 264 » » » }
265 » » » if e := u.unit.ClearResolved(); e != nil {
266 » » » » return nil, e
267 » » » }
268 » » » if err == errHookFailed {
235 continue 269 continue
236 } else if err != nil { 270 } else if err != nil {
237 return nil, err 271 return nil, err
238 } 272 }
273 return ModeContinue, nil
274 case upgrade := <-u.f.UpgradeEvents():
239 return ModeUpgrading(upgrade), nil 275 return ModeUpgrading(upgrade), nil
240 } 276 }
241 } 277 }
242 panic("unreachable") 278 panic("unreachable")
243 } 279 }
244 280
245 // ModeConflicted is responsible for watching and responding to: 281 // ModeConflicted is responsible for watching and responding to:
246 // * user resolution of charm upgrade conflicts 282 // * user resolution of charm upgrade conflicts
247 // * forced charm upgrade requests 283 // * forced charm upgrade requests
248 func ModeConflicted(sch *state.Charm) Mode { 284 func ModeConflicted(sch *state.Charm) Mode {
249 return func(u *Uniter) (next Mode, err error) { 285 return func(u *Uniter) (next Mode, err error) {
250 » » defer modeContext("ModeConflicted", &next, &err)() 286 » » defer modeContext("ModeConflicted", &err)()
251 if err = u.unit.SetStatus(state.UnitError, "upgrade failed"); er r != nil { 287 if err = u.unit.SetStatus(state.UnitError, "upgrade failed"); er r != nil {
252 return nil, err 288 return nil, err
253 } 289 }
254 » » u.wantResolvedEvent() 290 » » u.f.WantResolvedEvent()
255 » » u.wantCharmEvent() 291 » » u.f.WantUpgradeEvent(sch.URL(), true)
256 for { 292 for {
257 select { 293 select {
258 case <-u.Dying(): 294 case <-u.Dying():
259 return nil, tomb.ErrDying 295 return nil, tomb.ErrDying
260 » » » case rm := <-u.resolvedEvents(): 296 » » » case <-u.f.ResolvedEvents():
261 » » » » if success, err := u.resolveError(*rm, resolveCo nflict); success { 297 » » » » err = u.charm.Snapshotf("Upgrade conflict resolv ed.")
262 » » » » » return ModeUpgrading(sch), nil 298 » » » » if e := u.unit.ClearResolved(); e != nil {
263 » » » » } else if err != nil { 299 » » » » » return nil, e
300 » » » » }
301 » » » » if err != nil {
264 return nil, err 302 return nil, err
265 } 303 }
266 » » » case ch := <-u.charmEvents(): 304 » » » » return ModeUpgrading(sch), nil
267 » » » » upgrade, err := u.getUpgrade(ch, true) 305 » » » case upgrade := <-u.f.UpgradeEvents():
268 » » » » if err != nil {
269 » » » » » if err == errNoUpgrade {
270 » » » » » » continue
271 » » » » » }
272 » » » » » return nil, err
273 » » » » }
274 if err := u.charm.Revert(); err != nil { 306 if err := u.charm.Revert(); err != nil {
275 return nil, err 307 return nil, err
276 } 308 }
277 return ModeUpgrading(upgrade), nil 309 return ModeUpgrading(upgrade), nil
278 } 310 }
279 } 311 }
280 panic("unreachable") 312 panic("unreachable")
281 } 313 }
282 } 314 }
283 315
284 // modeContext returns a function that implements logging and common error 316 // modeContext returns a function that implements logging and common error
285 // manipulation for Mode funcs. 317 // manipulation for Mode funcs.
286 func modeContext(name string, next *Mode, err *error) func() { 318 func modeContext(name string, err *error) func() {
rog 2012/10/01 11:02:58 as discussed online, most/all of this could be mov
niemeyer 2012/10/01 22:47:33 +1 on turning this into straightforward code. Some
287 log.Printf(name + " starting") 319 log.Printf(name + " starting")
288 return func() { 320 return func() {
289 log.Debugf(name + " exiting") 321 log.Debugf(name + " exiting")
290 switch *err { 322 switch *err {
291 » » case nil: 323 » » case nil, tomb.ErrDying, worker.ErrDead:
292 » » » if *next == nil {
niemeyer 2012/10/01 22:47:33 This seems to obscure the logic without benefit. W
293 » » » » *next = ModeContinue
294 » » » }
295 » » case errHookFailed:
296 » » » *next, *err = ModeHookError, nil
niemeyer 2012/10/01 22:47:33 Same idea. The state machine is being hidden behin
fwereade 2012/10/02 07:01:35 Good points all. Will drop the ModeContinue bits e
niemeyer 2012/10/02 14:12:59 I'd much prefer having it close to the logic that
297 » » case tomb.ErrDying, ErrDead:
298 » » » log.Printf(name + " shutting down")
299 default: 324 default:
300 *err = errors.New(name + ": " + (*err).Error()) 325 *err = errors.New(name + ": " + (*err).Error())
301 } 326 }
302 } 327 }
303 } 328 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b