OLD | NEW |
1 // Copyright 2012, 2013 Canonical Ltd. | 1 // Copyright 2012, 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package apiuniter | 4 package apiuniter |
5 | 5 |
6 import ( | 6 import ( |
7 stderrors "errors" | 7 stderrors "errors" |
8 "fmt" | 8 "fmt" |
9 | 9 |
10 "launchpad.net/tomb" | 10 "launchpad.net/tomb" |
11 | 11 |
12 "launchpad.net/juju-core/charm" | 12 "launchpad.net/juju-core/charm" |
13 "launchpad.net/juju-core/charm/hooks" | 13 "launchpad.net/juju-core/charm/hooks" |
14 "launchpad.net/juju-core/environs" | 14 "launchpad.net/juju-core/environs" |
15 "launchpad.net/juju-core/errors" | |
16 "launchpad.net/juju-core/state" | |
17 "launchpad.net/juju-core/state/api/params" | 15 "launchpad.net/juju-core/state/api/params" |
18 "launchpad.net/juju-core/state/watcher" | 16 "launchpad.net/juju-core/state/watcher" |
19 "launchpad.net/juju-core/worker" | 17 "launchpad.net/juju-core/worker" |
20 ucharm "launchpad.net/juju-core/worker/apiuniter/charm" | 18 ucharm "launchpad.net/juju-core/worker/apiuniter/charm" |
21 "launchpad.net/juju-core/worker/apiuniter/hook" | 19 "launchpad.net/juju-core/worker/apiuniter/hook" |
22 ) | 20 ) |
23 | 21 |
24 // Mode defines the signature of the functions that implement the possible | 22 // Mode defines the signature of the functions that implement the possible |
25 // states of a running Uniter. | 23 // states of a running Uniter. |
26 type Mode func(u *Uniter) (Mode, error) | 24 type Mode func(u *Uniter) (Mode, error) |
27 | 25 |
28 // ModeInit is the initial Uniter mode. | 26 // ModeInit is the initial Uniter mode. |
29 func ModeInit(u *Uniter) (next Mode, err error) { | 27 func ModeInit(u *Uniter) (next Mode, err error) { |
30 defer modeContext("ModeInit", &err)() | 28 defer modeContext("ModeInit", &err)() |
31 logger.Infof("updating unit addresses") | 29 logger.Infof("updating unit addresses") |
32 » // TODO(dimitern): Once the uniter is using the API, change the | 30 » // TODO(dimitern): We might be able to drop all this address stuff |
33 » // following block to use st.ProviderType() instead of calling | 31 » // entirely once we have machine addresses. |
34 » // st.EnvironConfig. Also, We might be able to drop all this | 32 » providerType, err := u.st.ProviderType() |
35 » // address stuff entirely once we have machine addresses. | |
36 » cfg, err := u.st.EnvironConfig() | |
37 if err != nil { | 33 if err != nil { |
38 return nil, err | 34 return nil, err |
39 } | 35 } |
40 » provider, err := environs.Provider(cfg.Type()) | 36 » provider, err := environs.Provider(providerType) |
41 if err != nil { | 37 if err != nil { |
42 return nil, err | 38 return nil, err |
43 } | 39 } |
44 if private, err := provider.PrivateAddress(); err != nil { | 40 if private, err := provider.PrivateAddress(); err != nil { |
| 41 logger.Errorf("cannot get unit's private address: %v", err) |
45 return nil, err | 42 return nil, err |
46 } else if err = u.unit.SetPrivateAddress(private); err != nil { | 43 } else if err = u.unit.SetPrivateAddress(private); err != nil { |
| 44 logger.Errorf("cannot set unit's private address: %v", err) |
47 return nil, err | 45 return nil, err |
48 } | 46 } |
49 if public, err := provider.PublicAddress(); err != nil { | 47 if public, err := provider.PublicAddress(); err != nil { |
| 48 logger.Errorf("cannot get unit's public address: %v", err) |
50 return nil, err | 49 return nil, err |
51 } else if err = u.unit.SetPublicAddress(public); err != nil { | 50 } else if err = u.unit.SetPublicAddress(public); err != nil { |
| 51 logger.Errorf("cannot set unit's public address: %v", err) |
52 return nil, err | 52 return nil, err |
53 } | 53 } |
54 logger.Infof("reconciling relation state") | 54 logger.Infof("reconciling relation state") |
55 if err := u.restoreRelations(); err != nil { | 55 if err := u.restoreRelations(); err != nil { |
56 return nil, err | 56 return nil, err |
57 } | 57 } |
58 return ModeContinue, nil | 58 return ModeContinue, nil |
59 } | 59 } |
60 | 60 |
61 // ModeContinue determines what action to take based on persistent uniter state. | 61 // ModeContinue determines what action to take based on persistent uniter state. |
62 func ModeContinue(u *Uniter) (next Mode, err error) { | 62 func ModeContinue(u *Uniter) (next Mode, err error) { |
63 defer modeContext("ModeContinue", &err)() | 63 defer modeContext("ModeContinue", &err)() |
64 | 64 |
65 // If we haven't yet loaded state, do so. | 65 // If we haven't yet loaded state, do so. |
66 if u.s == nil { | 66 if u.s == nil { |
67 logger.Infof("loading uniter state") | 67 logger.Infof("loading uniter state") |
68 if u.s, err = u.sf.Read(); err == ErrNoStateFile { | 68 if u.s, err = u.sf.Read(); err == ErrNoStateFile { |
69 // When no state exists, start from scratch. | 69 // When no state exists, start from scratch. |
70 logger.Infof("charm is not deployed") | 70 logger.Infof("charm is not deployed") |
71 » » » curl, _ := u.service.CharmURL() | 71 » » » curl, _, err := u.service.CharmURL() |
| 72 » » » if err != nil { |
| 73 » » » » return nil, err |
| 74 » » » } |
72 return ModeInstalling(curl), nil | 75 return ModeInstalling(curl), nil |
73 } else if err != nil { | 76 } else if err != nil { |
74 return nil, err | 77 return nil, err |
75 } | 78 } |
76 } | 79 } |
77 | 80 |
78 // Filter out states not related to charm deployment. | 81 // Filter out states not related to charm deployment. |
79 switch u.s.Op { | 82 switch u.s.Op { |
80 case Continue: | 83 case Continue: |
81 logger.Infof("continuing after %q hook", u.s.Hook.Kind) | 84 logger.Infof("continuing after %q hook", u.s.Hook.Kind) |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 } | 191 } |
189 return ModeContinue, nil | 192 return ModeContinue, nil |
190 } | 193 } |
191 | 194 |
192 // ModeTerminating marks the unit dead and returns ErrTerminateAgent. | 195 // ModeTerminating marks the unit dead and returns ErrTerminateAgent. |
193 func ModeTerminating(u *Uniter) (next Mode, err error) { | 196 func ModeTerminating(u *Uniter) (next Mode, err error) { |
194 defer modeContext("ModeTerminating", &err)() | 197 defer modeContext("ModeTerminating", &err)() |
195 if err = u.unit.SetStatus(params.StatusStopped, ""); err != nil { | 198 if err = u.unit.SetStatus(params.StatusStopped, ""); err != nil { |
196 return nil, err | 199 return nil, err |
197 } | 200 } |
198 » w := u.unit.Watch() | 201 » w, err := u.unit.Watch() |
| 202 » if err != nil { |
| 203 » » return nil, err |
| 204 » } |
199 defer watcher.Stop(w, &u.tomb) | 205 defer watcher.Stop(w, &u.tomb) |
200 for { | 206 for { |
201 select { | 207 select { |
202 case <-u.tomb.Dying(): | 208 case <-u.tomb.Dying(): |
203 return nil, tomb.ErrDying | 209 return nil, tomb.ErrDying |
204 case _, ok := <-w.Changes(): | 210 case _, ok := <-w.Changes(): |
205 if !ok { | 211 if !ok { |
206 return nil, watcher.MustErr(w) | 212 return nil, watcher.MustErr(w) |
207 } | 213 } |
208 if err := u.unit.Refresh(); err != nil { | 214 if err := u.unit.Refresh(); err != nil { |
209 return nil, err | 215 return nil, err |
210 } | 216 } |
211 » » » // TODO(dimitern): Once the uniter uses the API, call | 217 » » » if hasSubs, err := u.unit.HasSubordinates(); err != nil
{ |
212 » » » // u.unit.HasSubordinates() here instead. | 218 » » » » return nil, err |
213 » » » if len(u.unit.SubordinateNames()) > 0 { | 219 » » » } else if hasSubs { |
214 continue | 220 continue |
215 } | 221 } |
216 // The unit is known to be Dying; so if it didn't have s
ubordinates | 222 // The unit is known to be Dying; so if it didn't have s
ubordinates |
217 // just above, it can't acquire new ones before this cal
l. | 223 // just above, it can't acquire new ones before this cal
l. |
218 if err := u.unit.EnsureDead(); err != nil { | 224 if err := u.unit.EnsureDead(); err != nil { |
219 return nil, err | 225 return nil, err |
220 } | 226 } |
221 return nil, worker.ErrTerminateAgent | 227 return nil, worker.ErrTerminateAgent |
222 } | 228 } |
223 } | 229 } |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 } | 293 } |
288 } | 294 } |
289 } | 295 } |
290 | 296 |
291 // modeAbideDyingLoop handles the proper termination of all relations in | 297 // modeAbideDyingLoop handles the proper termination of all relations in |
292 // response to a Dying unit. | 298 // response to a Dying unit. |
293 func modeAbideDyingLoop(u *Uniter) (next Mode, err error) { | 299 func modeAbideDyingLoop(u *Uniter) (next Mode, err error) { |
294 if err := u.unit.Refresh(); err != nil { | 300 if err := u.unit.Refresh(); err != nil { |
295 return nil, err | 301 return nil, err |
296 } | 302 } |
297 » // TODO(dimitern): Once the uniter uses the API, use | 303 » if err = u.unit.DestroyAllSubordinates(); err != nil { |
298 » // u.unit.DestroyAllSubordinates() here, instead of going | 304 » » return nil, err |
299 » // through each subordinate calling Destroy() on it. | |
300 » for _, name := range u.unit.SubordinateNames() { | |
301 » » if sub, err := u.st.Unit(name); errors.IsNotFoundError(err) { | |
302 » » » continue | |
303 » » } else if err != nil { | |
304 » » » return nil, err | |
305 » » } else if err = sub.Destroy(); err != nil { | |
306 » » » return nil, err | |
307 » » } | |
308 } | 305 } |
309 for id, r := range u.relationers { | 306 for id, r := range u.relationers { |
310 if err := r.SetDying(); err != nil { | 307 if err := r.SetDying(); err != nil { |
311 return nil, err | 308 return nil, err |
312 } else if r.IsImplicit() { | 309 } else if r.IsImplicit() { |
313 delete(u.relationers, id) | 310 delete(u.relationers, id) |
314 } | 311 } |
315 } | 312 } |
316 for { | 313 for { |
317 if len(u.relationers) == 0 { | 314 if len(u.relationers) == 0 { |
(...skipping 28 matching lines...) Expand all Loading... |
346 return nil, err | 343 return nil, err |
347 } | 344 } |
348 u.f.WantResolvedEvent() | 345 u.f.WantResolvedEvent() |
349 u.f.WantUpgradeEvent(true) | 346 u.f.WantUpgradeEvent(true) |
350 for { | 347 for { |
351 select { | 348 select { |
352 case <-u.tomb.Dying(): | 349 case <-u.tomb.Dying(): |
353 return nil, tomb.ErrDying | 350 return nil, tomb.ErrDying |
354 case rm := <-u.f.ResolvedEvents(): | 351 case rm := <-u.f.ResolvedEvents(): |
355 switch rm { | 352 switch rm { |
356 » » » case state.ResolvedRetryHooks: | 353 » » » case params.ResolvedRetryHooks: |
357 err = u.runHook(*u.s.Hook) | 354 err = u.runHook(*u.s.Hook) |
358 » » » case state.ResolvedNoHooks: | 355 » » » case params.ResolvedNoHooks: |
359 err = u.commitHook(*u.s.Hook) | 356 err = u.commitHook(*u.s.Hook) |
360 default: | 357 default: |
361 return nil, fmt.Errorf("unknown resolved mode %q
", rm) | 358 return nil, fmt.Errorf("unknown resolved mode %q
", rm) |
362 } | 359 } |
363 if e := u.f.ClearResolved(); e != nil { | 360 if e := u.f.ClearResolved(); e != nil { |
364 return nil, e | 361 return nil, e |
365 } | 362 } |
366 if err == errHookFailed { | 363 if err == errHookFailed { |
367 continue | 364 continue |
368 } else if err != nil { | 365 } else if err != nil { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 logger.Infof("%s starting", name) | 412 logger.Infof("%s starting", name) |
416 return func() { | 413 return func() { |
417 logger.Debugf("%s exiting", name) | 414 logger.Debugf("%s exiting", name) |
418 switch *err { | 415 switch *err { |
419 case nil, tomb.ErrDying, worker.ErrTerminateAgent: | 416 case nil, tomb.ErrDying, worker.ErrTerminateAgent: |
420 default: | 417 default: |
421 *err = stderrors.New(name + ": " + (*err).Error()) | 418 *err = stderrors.New(name + ": " + (*err).Error()) |
422 } | 419 } |
423 } | 420 } |
424 } | 421 } |
OLD | NEW |