| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 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/state/watcher" | |
| 10 "launchpad.net/juju-core/worker/uniter/charm" | 9 "launchpad.net/juju-core/worker/uniter/charm" |
| 11 "launchpad.net/juju-core/worker/uniter/hook" | 10 "launchpad.net/juju-core/worker/uniter/hook" |
| 12 "launchpad.net/tomb" | 11 "launchpad.net/tomb" |
| 13 ) | 12 ) |
| 14 | 13 |
| 15 // Mode defines the signature of the functions that implement the possible | 14 // Mode defines the signature of the functions that implement the possible |
| 16 // states of a running Uniter. | 15 // states of a running Uniter. |
| 17 type Mode func(u *Uniter) (Mode, error) | 16 type Mode func(u *Uniter) (Mode, error) |
| 18 | 17 |
| 19 // ModeInit is the initial Uniter mode. | 18 // ModeInit is the initial Uniter mode. |
| 20 func ModeInit(u *Uniter) (next Mode, err error) { | 19 func ModeInit(u *Uniter) (next Mode, err error) { |
| 21 » defer errorContextf(&err, "ModeInit") | 20 » defer modeContext("ModeInit", &next, &err)() |
| 22 log.Printf("updating unit addresses") | 21 log.Printf("updating unit addresses") |
| 23 cfg, err := u.st.EnvironConfig() | 22 cfg, err := u.st.EnvironConfig() |
| 24 if err != nil { | 23 if err != nil { |
| 25 return nil, err | 24 return nil, err |
| 26 } | 25 } |
| 27 provider, err := environs.Provider(cfg.Type()) | 26 provider, err := environs.Provider(cfg.Type()) |
| 28 if err != nil { | 27 if err != nil { |
| 29 return nil, err | 28 return nil, err |
| 30 } | 29 } |
| 31 if private, err := provider.PrivateAddress(); err != nil { | 30 if private, err := provider.PrivateAddress(); err != nil { |
| 32 return nil, err | 31 return nil, err |
| 33 } else if err = u.unit.SetPrivateAddress(private); err != nil { | 32 } else if err = u.unit.SetPrivateAddress(private); err != nil { |
| 34 return nil, err | 33 return nil, err |
| 35 } | 34 } |
| 36 if public, err := provider.PublicAddress(); err != nil { | 35 if public, err := provider.PublicAddress(); err != nil { |
| 37 return nil, err | 36 return nil, err |
| 38 } else if err = u.unit.SetPublicAddress(public); err != nil { | 37 } else if err = u.unit.SetPublicAddress(public); err != nil { |
| 39 return nil, err | 38 return nil, err |
| 40 } | 39 } |
| 41 return ModeContinue, nil | 40 return ModeContinue, nil |
| 42 } | 41 } |
| 43 | 42 |
| 44 // ModeContinue determines what action to take based on persistent uniter state. | 43 // ModeContinue determines what action to take based on persistent uniter state. |
| 45 func ModeContinue(u *Uniter) (next Mode, err error) { | 44 func ModeContinue(u *Uniter) (next Mode, err error) { |
| 46 » defer errorContextf(&err, "ModeContinue") | 45 » defer modeContext("ModeContinue", &next, &err)() |
| 47 | 46 |
| 48 // When no charm exists, install it. | 47 // When no charm exists, install it. |
| 49 log.Printf("reading uniter state from disk...") | |
| 50 s, err := u.sf.Read() | 48 s, err := u.sf.Read() |
| 51 if err == ErrNoStateFile { | 49 if err == ErrNoStateFile { |
| 52 log.Printf("charm is not deployed") | 50 log.Printf("charm is not deployed") |
| 53 sch, _, err := u.service.Charm() | 51 sch, _, err := u.service.Charm() |
| 54 if err != nil { | 52 if err != nil { |
| 55 return nil, err | 53 return nil, err |
| 56 } | 54 } |
| 57 return ModeInstalling(sch), nil | 55 return ModeInstalling(sch), nil |
| 58 } else if err != nil { | 56 } else if err != nil { |
| 59 return nil, err | 57 return nil, err |
| 60 } | 58 } |
| 61 | 59 |
| 62 // Filter out states not related to charm deployment. | 60 // Filter out states not related to charm deployment. |
| 63 switch s.Op { | 61 switch s.Op { |
| 64 case Abide: | 62 case Abide: |
| 65 log.Printf("continuing after %q hook", s.Hook.Kind) | 63 log.Printf("continuing after %q hook", s.Hook.Kind) |
| 66 » » if s.Hook.Kind == hook.Install { | 64 » » switch s.Hook.Kind { |
| 65 » » case hook.Install: | |
| 67 return ModeStarting, nil | 66 return ModeStarting, nil |
| 67 case hook.Stop: | |
| 68 return ModeTerminating, nil | |
| 68 } | 69 } |
| 69 » » return ModeStarted, nil | 70 » » return ModeAbide, nil |
| 70 case RunHook: | 71 case RunHook: |
| 71 if s.OpStep == Queued { | 72 if s.OpStep == Queued { |
| 72 » » » log.Printf("running queued %q hook", s.Hook.Kind) | 73 » » » log.Printf("found queued %q hook", s.Hook.Kind) |
| 73 » » » if err := u.runHook(*s.Hook); err != nil { | 74 » » » return nil, u.runHook(*s.Hook) |
| 74 » » » » if err != errHookFailed { | |
| 75 » » » » » return nil, err | |
| 76 » » » » } | |
| 77 » » » } | |
| 78 » » » return ModeContinue, nil | |
| 79 } | 75 } |
| 80 if s.OpStep == Done { | 76 if s.OpStep == Done { |
| 81 » » » log.Printf("recovering uncommitted %q hook", s.Hook.Kind ) | 77 » » » log.Printf("found uncommitted %q hook", s.Hook.Kind) |
| 82 » » » if err = u.commitHook(*s.Hook); err != nil { | 78 » » » return nil, u.commitHook(*s.Hook) |
| 83 » » » » return nil, err | |
| 84 » » » } | |
| 85 » » » return ModeContinue, nil | |
| 86 } | 79 } |
| 87 log.Printf("awaiting error resolution for %q hook", s.Hook.Kind) | 80 log.Printf("awaiting error resolution for %q hook", s.Hook.Kind) |
| 88 return ModeHookError, nil | 81 return ModeHookError, nil |
| 89 } | 82 } |
| 90 | 83 |
| 91 // Resume interrupted deployment operations. | 84 // Resume interrupted deployment operations. |
| 92 sch, err := u.st.Charm(s.CharmURL) | 85 sch, err := u.st.Charm(s.CharmURL) |
| 93 if err != nil { | 86 if err != nil { |
| 94 return nil, err | 87 return nil, err |
| 95 } | 88 } |
| 96 if s.Op == Install { | 89 if s.Op == Install { |
| 97 log.Printf("resuming charm install") | 90 log.Printf("resuming charm install") |
| 98 return ModeInstalling(sch), nil | 91 return ModeInstalling(sch), nil |
| 99 } else if s.Op == Upgrade { | 92 } else if s.Op == Upgrade { |
| 100 log.Printf("resuming charm upgrade") | 93 log.Printf("resuming charm upgrade") |
| 101 return ModeUpgrading(sch), nil | 94 return ModeUpgrading(sch), nil |
| 102 } | 95 } |
| 103 panic(fmt.Errorf("unhandled uniter operation %q", s.Op)) | 96 panic(fmt.Errorf("unhandled uniter operation %q", s.Op)) |
| 104 } | 97 } |
| 105 | 98 |
| 106 // ModeInstalling is responsible for the initial charm deployment. | 99 // ModeInstalling is responsible for the initial charm deployment. |
| 107 func ModeInstalling(sch *state.Charm) Mode { | 100 func ModeInstalling(sch *state.Charm) Mode { |
| 108 return func(u *Uniter) (next Mode, err error) { | 101 return func(u *Uniter) (next Mode, err error) { |
| 109 » » defer errorContextf(&err, "ModeInstalling") | 102 » » name := fmt.Sprintf("ModeInstalling %s", sch.URL()) |
| 110 » » if err = u.deploy(sch, Install); err != nil { | 103 » » defer modeContext(name, &next, &err)() |
| 111 » » » return nil, err | 104 » » return nil, u.deploy(sch, Install) |
| 112 » » } | |
| 113 » » return ModeContinue, nil | |
| 114 } | 105 } |
| 115 } | 106 } |
| 116 | 107 |
| 117 // ModeStarting is responsible for running the "start" hook. | 108 // ModeUpgrading is responsible for upgrading the charm. |
| 118 func ModeStarting(u *Uniter) (next Mode, err error) { | 109 func ModeUpgrading(sch *state.Charm) Mode { |
| 119 » defer errorContextf(&err, "ModeStarting") | 110 » return func(u *Uniter) (next Mode, err error) { |
| 120 » if err := u.unit.SetStatus(state.UnitInstalled, ""); err != nil { | 111 » » name := fmt.Sprintf("ModeUpgrading %s", sch.URL()) |
| 112 » » defer modeContext(name, &next, &err)() | |
| 113 » » if err = u.deploy(sch, Upgrade); err == charm.ErrConflict { | |
| 114 » » » return ModeConflicted(sch), nil | |
| 115 » » } | |
| 121 return nil, err | 116 return nil, err |
| 122 } | 117 } |
| 123 » hi := hook.Info{Kind: hook.Start} | 118 } |
| 124 » if err := u.runHook(hi); err != nil && err != errHookFailed { | 119 |
| 120 // ModeStarting runs the "start" hook. | |
| 121 func ModeStarting(u *Uniter) (next Mode, err error) { | |
| 122 » defer modeContext("ModeStarting", &next, &err)() | |
| 123 » if err = u.unit.SetStatus(state.UnitInstalled, ""); err != nil { | |
| 125 return nil, err | 124 return nil, err |
| 126 } | 125 } |
| 127 » return ModeContinue, nil | 126 » return nil, u.runHook(hook.Info{Kind: hook.Start}) |
| 128 } | 127 } |
| 129 | 128 |
| 130 // ModeStarted is the Uniter's usual steady state. It watches for and responds t o: | 129 // ModeStopping runs the "stop" hook. |
| 130 func ModeStopping(u *Uniter) (next Mode, err error) { | |
| 131 » defer modeContext("ModeStopping", &next, &err)() | |
| 132 » return nil, u.runHook(hook.Info{Kind: hook.Stop}) | |
| 133 } | |
| 134 | |
| 135 // ModeTerminating marks the unit dead and returns ErrDead. | |
| 136 func ModeTerminating(u *Uniter) (next Mode, err error) { | |
| 137 » defer modeContext("ModeTerminating", &next, &err)() | |
| 138 » if err = u.unit.SetStatus(state.UnitStopped, ""); err != nil { | |
| 139 » » return nil, err | |
| 140 » } | |
| 141 » if err = u.unit.EnsureDead(); err != nil { | |
| 142 » » return nil, err | |
| 143 » } | |
| 144 » return nil, ErrDead | |
| 145 } | |
| 146 | |
| 147 // ModeAbide is the Uniter's usual steady state. It watches for and responds to: | |
| 131 // * service configuration changes | 148 // * service configuration changes |
| 132 // * charm upgrade requests (not implemented) | 149 // * charm upgrade requests |
| 133 // * relation changes (not implemented) | 150 // * relation changes (not implemented) |
| 134 // * unit death (not implemented) | 151 // * unit death |
| 135 func ModeStarted(u *Uniter) (next Mode, err error) { | 152 func ModeAbide(u *Uniter) (next Mode, err error) { |
| 136 » defer errorContextf(&err, "ModeStarted") | 153 » defer modeContext("ModeAbide", &next, &err)() |
| 137 s, err := u.sf.Read() | 154 s, err := u.sf.Read() |
| 138 if err != nil { | 155 if err != nil { |
| 139 return nil, err | 156 return nil, err |
| 140 } | 157 } |
| 141 if s.Op != Abide { | 158 if s.Op != Abide { |
| 142 return nil, fmt.Errorf("insane uniter state: %#v", s) | 159 return nil, fmt.Errorf("insane uniter state: %#v", s) |
|
rog
2012/10/01 11:02:58
"insane uniter state; expected Abide, got %#v", s)
| |
| 143 } | 160 } |
| 144 if err = u.unit.SetStatus(state.UnitStarted, ""); err != nil { | 161 if err = u.unit.SetStatus(state.UnitStarted, ""); err != nil { |
| 145 return nil, err | 162 return nil, err |
| 146 } | 163 } |
| 147 | 164 |
| 148 » // To begin with, only watch for config changes, and exploit the | 165 » // Execute an initial config-changed hook regardless of state. |
|
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
| |
| 149 » // guaranteed initial send to ensure we run a config-changed hook | 166 » cc := hook.Info{Kind: hook.ConfigChanged} |
| 150 » // before starting any other watches. | 167 » u.wantConfigEvent() |
| 151 » starting := true | 168 » select { |
| 152 » configw := u.service.WatchConfig() | 169 » case <-u.Dying(): |
| 153 » defer stop(configw, &next, &err) | 170 » » return nil, tomb.ErrDying |
| 154 » var servicew *state.ServiceWatcher | 171 » case <-u.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
| |
| 155 » var serviceChanges <-chan *state.Service | 172 » » if err = u.runHook(cc); err != nil { |
| 173 » » » return nil, err | |
| 174 » » } | |
| 175 » } | |
| 176 | |
| 177 » // Watch for everything else (including further config changes). | |
|
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() | |
| 156 for { | 179 for { |
| 157 select { | 180 select { |
| 158 » » case <-u.tomb.Dying(): | 181 » » case <-u.Dying(): |
| 159 return nil, tomb.ErrDying | 182 return nil, tomb.ErrDying |
| 160 » » case _, ok := <-configw.Changes(): | 183 » » case <-u.unitDying(): |
| 161 » » » if !ok { | 184 » » » // TODO don't stop until all relations broken. |
| 162 » » » » return nil, watcher.MustErr(configw) | 185 » » » return ModeStopping, nil |
| 163 » » » } | 186 » » case <-u.configEvents(): |
| 164 » » » hi := hook.Info{Kind: hook.ConfigChanged} | 187 » » » if err = u.runHook(cc); err != nil { |
| 165 » » » if err = u.runHook(hi); err != nil { | |
| 166 » » » » if err == errHookFailed { | |
| 167 » » » » » return ModeHookError, nil | |
| 168 » » » » } | |
| 169 return nil, err | 188 return nil, err |
| 170 } | 189 } |
| 171 » » » if starting { | 190 » » case ch := <-u.charmEvents(): |
| 172 » » » » // If we haven't already set up additional watch es, do so now. | 191 » » » upgrade, err := u.getUpgrade(ch, false) |
| 173 » » » » starting = false | 192 » » » if err == errNoUpgrade { |
| 174 » » » » servicew = u.service.Watch() | 193 » » » » continue |
| 175 » » » » defer stop(servicew, &next, &err) | 194 » » » } else if err != nil { |
| 176 » » » » serviceChanges = servicew.Changes() | |
| 177 » » » } | |
| 178 » » case service, ok := <-serviceChanges: | |
| 179 » » » if !ok { | |
| 180 » » » » return nil, watcher.MustErr(servicew) | |
| 181 » » » } | |
| 182 » » » ch, _, err := service.Charm() | |
| 183 » » » if err != nil { | |
| 184 return nil, err | 195 return nil, err |
| 185 } | 196 } |
| 186 » » » url, err := charm.ReadCharmURL(u.charm) | 197 » » » return ModeUpgrading(upgrade), nil |
| 187 » » » if err != nil { | |
| 188 » » » » return nil, err | |
| 189 » » » } | |
| 190 » » » if *ch.URL() != *url { | |
| 191 » » » » return ModeUpgrading(ch), nil | |
| 192 » » » } | |
| 193 } | 198 } |
| 194 // TODO: unit death; relations. | |
| 195 } | 199 } |
| 196 panic("unreachable") | 200 panic("unreachable") |
| 197 } | 201 } |
| 198 | 202 |
| 199 // ModeHookError is responsible for watching and responding to: | 203 // ModeHookError is responsible for watching and responding to: |
| 200 // * user resolution of hook errors | 204 // * user resolution of hook errors |
| 201 // * forced charm upgrade requests (not implemented) | 205 // * charm upgrade requests |
| 202 // * unit death (not implemented) | |
| 203 func ModeHookError(u *Uniter) (next Mode, err error) { | 206 func ModeHookError(u *Uniter) (next Mode, err error) { |
| 204 » defer errorContextf(&err, "ModeHookError") | 207 » defer modeContext("ModeHookError", &next, &err)() |
| 205 s, err := u.sf.Read() | 208 s, err := u.sf.Read() |
| 206 if err != nil { | 209 if err != nil { |
| 207 return nil, err | 210 return nil, err |
| 208 } | 211 } |
| 209 if s.Op != RunHook || s.OpStep != Pending { | 212 if s.Op != RunHook || s.OpStep != Pending { |
| 210 return nil, fmt.Errorf("insane uniter state: %#v", s) | 213 return nil, fmt.Errorf("insane uniter state: %#v", s) |
| 211 } | 214 } |
| 212 msg := fmt.Sprintf("hook failed: %q", s.Hook.Kind) | 215 msg := fmt.Sprintf("hook failed: %q", s.Hook.Kind) |
| 213 if err = u.unit.SetStatus(state.UnitError, msg); err != nil { | 216 if err = u.unit.SetStatus(state.UnitError, msg); err != nil { |
| 214 return nil, err | 217 return nil, err |
| 215 } | 218 } |
| 216 | 219 » resolveHook := getResolveHook(*s.Hook) |
| 217 » // Wait for shutdown, error resolution, or forced charm upgrade. | 220 » u.wantResolvedEvent() |
| 218 » unitw := u.unit.Watch() | 221 » u.wantCharmEvent() |
| 219 » defer stop(unitw, &next, &err) | |
| 220 » servicew := u.service.Watch() | |
| 221 » defer stop(servicew, &next, &err) | |
| 222 for { | 222 for { |
| 223 select { | 223 select { |
| 224 » » case <-u.tomb.Dying(): | 224 » » case <-u.Dying(): |
| 225 return nil, tomb.ErrDying | 225 return nil, tomb.ErrDying |
| 226 » » case unit, ok := <-unitw.Changes(): | 226 » » case rm := <-u.resolvedEvents(): |
| 227 » » » // TODO: unit death. | 227 » » » if success, err := u.resolveError(*rm, resolveHook); suc cess { |
| 228 » » » if !ok { | 228 » » » » return ModeContinue, nil |
| 229 » » » » return nil, watcher.MustErr(unitw) | 229 » » » } else if err != nil && err != errHookFailed { |
| 230 » » » » return nil, err | |
| 230 } | 231 } |
| 231 » » » switch unit.Resolved() { | 232 » » case ch := <-u.charmEvents(): |
| 232 » » » case state.ResolvedNone: | 233 » » » upgrade, err := u.getUpgrade(ch, true) |
| 233 » » » » continue | 234 » » » if err == errNoUpgrade { |
| 234 » » » case state.ResolvedRetryHooks: | |
| 235 » » » » err = u.runHook(*s.Hook) | |
| 236 » » » case state.ResolvedNoHooks: | |
| 237 » » » » err = u.commitHook(*s.Hook) | |
| 238 » » » default: | |
| 239 » » » » panic(fmt.Errorf("unhandled resolved mode %q", u nit.Resolved())) | |
| 240 » » » } | |
| 241 » » » if e := unit.ClearResolved(); e != nil { | |
| 242 » » » » err = e | |
| 243 » » » } | |
| 244 » » » if err == errHookFailed { | |
| 245 continue | 235 continue |
| 246 } else if err != nil { | 236 } else if err != nil { |
| 247 return nil, err | 237 return nil, err |
| 248 } | 238 } |
| 249 » » » return ModeContinue, nil | 239 » » » return ModeUpgrading(upgrade), nil |
| 250 » » case service, ok := <-servicew.Changes(): | |
| 251 » » » if !ok { | |
| 252 » » » » return nil, watcher.MustErr(servicew) | |
| 253 » » » } | |
| 254 » » » ch, force, err := service.Charm() | |
| 255 » » » if err != nil { | |
| 256 » » » » return nil, err | |
| 257 » » » } | |
| 258 » » » url, err := charm.ReadCharmURL(u.charm) | |
| 259 » » » if err != nil { | |
| 260 » » » » return nil, err | |
| 261 » » » } | |
| 262 » » » if force && *ch.URL() != *url { | |
| 263 » » » » return ModeUpgrading(ch), nil | |
| 264 » » » } | |
| 265 } | 240 } |
| 266 } | 241 } |
| 267 panic("unreachable") | 242 panic("unreachable") |
| 268 } | 243 } |
| 269 | 244 |
| 270 // ModeUpgrading is responsible for upgrading the charm. | 245 // ModeConflicted is responsible for watching and responding to: |
| 271 func ModeUpgrading(sch *state.Charm) Mode { | 246 // * user resolution of charm upgrade conflicts |
| 272 » return func(u *Uniter) (Mode, error) { | 247 // * forced charm upgrade requests |
| 273 » » log.Printf("upgrading charm to %q", sch.URL()) | |
| 274 » » if err := u.deploy(sch, Upgrade); err != nil { | |
| 275 » » » if err == charm.ErrConflict { | |
| 276 » » » » return ModeConflicted(sch), nil | |
| 277 » » » } | |
| 278 » » » return nil, err | |
| 279 » » } | |
| 280 » » return ModeContinue, nil | |
| 281 » } | |
| 282 } | |
| 283 | |
| 284 // ModeConflicted waits for the user to resolve an error encountered when | |
| 285 // upgrading a charm. This may be done either by manually resolving errors | |
| 286 // and then setting the resolved flag, or by forcing an upgrade to a | |
| 287 // different charm. | |
| 288 func ModeConflicted(sch *state.Charm) Mode { | 248 func ModeConflicted(sch *state.Charm) Mode { |
| 289 return func(u *Uniter) (next Mode, err error) { | 249 return func(u *Uniter) (next Mode, err error) { |
| 250 defer modeContext("ModeConflicted", &next, &err)() | |
| 290 if err = u.unit.SetStatus(state.UnitError, "upgrade failed"); er r != nil { | 251 if err = u.unit.SetStatus(state.UnitError, "upgrade failed"); er r != nil { |
| 291 return nil, err | 252 return nil, err |
| 292 } | 253 } |
| 293 » » unitw := u.unit.Watch() | 254 » » u.wantResolvedEvent() |
| 294 » » defer stop(unitw, &next, &err) | 255 » » u.wantCharmEvent() |
| 295 » » servicew := u.service.Watch() | |
| 296 » » defer stop(servicew, &next, &err) | |
| 297 for { | 256 for { |
| 298 select { | 257 select { |
| 299 » » » case <-u.tomb.Dying(): | 258 » » » case <-u.Dying(): |
| 300 return nil, tomb.ErrDying | 259 return nil, tomb.ErrDying |
| 301 » » » case service, ok := <-servicew.Changes(): | 260 » » » case rm := <-u.resolvedEvents(): |
| 302 » » » » if !ok { | 261 » » » » if success, err := u.resolveError(*rm, resolveCo nflict); success { |
| 303 » » » » » return nil, watcher.MustErr(servicew) | 262 » » » » » return ModeUpgrading(sch), nil |
| 304 » » » » } | 263 » » » » } else if err != nil { |
| 305 » » » » ch, force, err := service.Charm() | |
| 306 » » » » if err != nil { | |
| 307 return nil, err | 264 return nil, err |
| 308 } | 265 } |
| 309 » » » » if force && *ch.URL() != *sch.URL() { | 266 » » » case ch := <-u.charmEvents(): |
| 310 » » » » » if err := u.charm.Revert(); err != nil { | 267 » » » » upgrade, err := u.getUpgrade(ch, true) |
| 311 » » » » » » return nil, err | 268 » » » » if err != nil { |
| 269 » » » » » if err == errNoUpgrade { | |
| 270 » » » » » » continue | |
| 312 } | 271 } |
| 313 return ModeUpgrading(ch), nil | |
| 314 } | |
| 315 case unit, ok := <-unitw.Changes(): | |
| 316 if !ok { | |
| 317 return nil, watcher.MustErr(unitw) | |
| 318 } | |
| 319 if unit.Resolved() == state.ResolvedNone { | |
| 320 continue | |
| 321 } | |
| 322 err := u.charm.Snapshotf("Upgrade conflict resol ved.") | |
| 323 if e := u.unit.ClearResolved(); e != nil && err == nil { | |
| 324 err = e | |
| 325 } | |
| 326 if err != nil { | |
| 327 return nil, err | 272 return nil, err |
| 328 } | 273 } |
| 329 » » » » return ModeUpgrading(sch), nil | 274 » » » » if err := u.charm.Revert(); err != nil { |
| 275 » » » » » return nil, err | |
| 276 » » » » } | |
| 277 » » » » return ModeUpgrading(upgrade), nil | |
| 330 } | 278 } |
| 331 // TODO: unit death. | |
| 332 } | 279 } |
| 333 panic("unreachable") | 280 panic("unreachable") |
| 334 } | 281 } |
| 335 } | 282 } |
| 336 | 283 |
| 337 // stop is used by Mode funcs to shut down watchers on return. | 284 // modeContext returns a function that implements logging and common error |
| 338 func stop(s stopper, next *Mode, err *error) { | 285 // manipulation for Mode funcs. |
| 339 » if e := s.Stop(); e != nil && *err == nil { | 286 func modeContext(name string, next *Mode, 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
| |
| 340 » » *next = nil | 287 » log.Printf(name + " starting") |
| 341 » » *err = e | 288 » return func() { |
| 289 » » log.Debugf(name + " exiting") | |
| 290 » » switch *err { | |
| 291 » » case nil: | |
| 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: | |
| 300 » » » *err = errors.New(name + ": " + (*err).Error()) | |
| 301 » » } | |
| 342 } | 302 } |
| 343 } | 303 } |
| 344 | |
| 345 type stopper interface { | |
| 346 Stop() error | |
| 347 } | |
| 348 | |
| 349 // errorContextf prefixes the error stored in err with text formatted | |
| 350 // according to the format specifier. If err does not contain an error, | |
| 351 // or if err is tomb.ErrDying, errorContextf does nothing. | |
| 352 func errorContextf(err *error, format string, args ...interface{}) { | |
| 353 if *err != nil && *err != tomb.ErrDying { | |
| 354 *err = errors.New(fmt.Sprintf(format, args...) + ": " + (*err).E rror()) | |
| 355 } | |
| 356 } | |
| OLD | NEW |