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

Side by Side Diff: worker/uniter/modes.go

Issue 6489083: combine charm and hook states as uniter state
Patch Set: combine charm and hook states as uniter state Created 11 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:
View unified diff | Download patch
« no previous file with comments | « worker/uniter/hook/hook_test.go ('k') | worker/uniter/state.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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" 9 "launchpad.net/juju-core/state/watcher"
10 "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 errorContextf(&err, "ModeInit")
22
23 log.Printf("updating unit addresses") 21 log.Printf("updating unit addresses")
24 cfg, err := u.st.EnvironConfig() 22 cfg, err := u.st.EnvironConfig()
25 if err != nil { 23 if err != nil {
26 return nil, err 24 return nil, err
27 } 25 }
28 provider, err := environs.Provider(cfg.Type()) 26 provider, err := environs.Provider(cfg.Type())
29 if err != nil { 27 if err != nil {
30 return nil, err 28 return nil, err
31 } 29 }
32 if private, err := provider.PrivateAddress(); err != nil { 30 if private, err := provider.PrivateAddress(); err != nil {
33 return nil, err 31 return nil, err
34 } else if err = u.unit.SetPrivateAddress(private); err != nil { 32 } else if err = u.unit.SetPrivateAddress(private); err != nil {
35 return nil, err 33 return nil, err
36 } 34 }
37 if public, err := provider.PublicAddress(); err != nil { 35 if public, err := provider.PublicAddress(); err != nil {
38 return nil, err 36 return nil, err
39 } else if err = u.unit.SetPublicAddress(public); err != nil { 37 } else if err = u.unit.SetPublicAddress(public); err != nil {
40 return nil, err 38 return nil, err
41 } 39 }
40 return ModeContinue, nil
41 }
42 42
43 » log.Printf("examining charm state...") 43 // ModeContinue determines what action to take based on persistent uniter state.
44 » var sch *state.Charm 44 func ModeContinue(u *Uniter) (next Mode, err error) {
45 » cs, err := u.charm.ReadState() 45 » defer errorContextf(&err, "ModeContinue")
46 » if err == charm.ErrMissing { 46
47 » // When no charm exists, install it.
48 » log.Printf("reading uniter state from disk...")
49 » s, err := u.sf.Read()
50 » if err == ErrNoStateFile {
47 log.Printf("charm is not deployed") 51 log.Printf("charm is not deployed")
48 » » if sch, _, err = u.service.Charm(); err != nil { 52 » » sch, _, err := u.service.Charm()
53 » » if err != nil {
49 return nil, err 54 return nil, err
50 } 55 }
51 return ModeInstalling(sch), nil 56 return ModeInstalling(sch), nil
52 } else if err != nil { 57 } else if err != nil {
53 return nil, err 58 return nil, err
54 } 59 }
55 » if cs.Status == charm.Deployed { 60
56 » » log.Printf("charm is deployed") 61 » // Filter out states not related to charm deployment.
57 » » return ModeContinue, nil 62 » switch s.Op {
58 » } else if sch, err = u.st.Charm(cs.URL); err != nil { 63 » case Abide:
59 » » return nil, err 64 » » log.Printf("continuing after %q hook", s.Hook.Kind)
65 » » if s.Hook.Kind == hook.Install {
66 » » » return ModeStarting, nil
67 » » }
68 » » return ModeStarted, nil
69 » case RunHook:
70 » » if s.OpStep == Queued {
71 » » » log.Printf("running queued %q hook", s.Hook.Kind)
72 » » » if err := u.runHook(*s.Hook); err != nil {
73 » » » » if err != errHookFailed {
74 » » » » » return nil, err
75 » » » » }
76 » » » }
77 » » » return ModeContinue, nil
78 » » }
79 » » if s.OpStep == Done {
80 » » » log.Printf("recovering uncommitted %q hook", s.Hook.Kind )
81 » » » if err = u.commitHook(*s.Hook); err != nil {
82 » » » » return nil, err
83 » » » }
84 » » » return ModeContinue, nil
85 » » }
86 » » log.Printf("awaiting error resolution for %q hook", s.Hook.Kind)
87 » » return ModeHookError, nil
60 } 88 }
61 switch cs.Status {
62 case charm.Installing:
63 log.Printf("resuming charm install")
64 return ModeInstalling(sch), nil
65 case charm.Upgrading, charm.Conflicted:
66 panic("not implemented")
67 }
68 panic("unreachable")
69 }
70 89
71 // ModeContinue determines what action to take based on hook status. 90 » // Resume interrupted deployment operations.
72 func ModeContinue(u *Uniter) (next Mode, err error) { 91 » sch, err := u.st.Charm(s.CharmURL)
73 » defer errorContextf(&err, "ModeContinue")
74 » log.Printf("examining hook state...")
75 » hs, err := u.hook.Read()
76 if err != nil { 92 if err != nil {
77 return nil, err 93 return nil, err
78 } 94 }
79 » switch hs.Status { 95 » if s.Op == Install {
80 » case hook.Pending: 96 » » log.Printf("resuming charm install")
81 » » log.Printf("awaiting error resolution for %q hook", hs.Info.Kind ) 97 » » return ModeInstalling(sch), nil
82 » » return ModeHookError, nil
83 » case hook.Committing:
84 » » log.Printf("recovering uncommitted %q hook", hs.Info.Kind)
85 » » if err = u.commitHook(hs.Info); err != nil {
86 » » » return nil, err
87 » » }
88 » » return ModeContinue, nil
89 » case hook.Queued:
90 » » log.Printf("running queued %q hook", hs.Info.Kind)
91 » » if err := u.runHook(hs.Info); err != nil {
92 » » » if err == errHookFailed {
93 » » » » return ModeHookError, nil
94 » » » }
95 » » » return nil, err
96 » » }
97 » » return ModeContinue, nil
98 » case hook.Complete:
99 » » log.Printf("continuing after %q hook", hs.Info.Kind)
100 » » if hs.Info.Kind == hook.Install {
101 » » » return ModeStarting, nil
102 » » }
103 » » return ModeStarted, nil
104 } 98 }
105 » panic(fmt.Errorf("unhandled hook status %q", hs.Status)) 99 » panic(fmt.Errorf("unhandled operation %q", s.Op))
106 } 100 }
107 101
108 // ModeInstalling is responsible for creating the charm directory and running 102 // ModeInstalling is responsible for creating the charm directory and running
109 // the "install" hook. 103 // the "install" hook.
110 func ModeInstalling(sch *state.Charm) Mode { 104 func ModeInstalling(sch *state.Charm) Mode {
111 return func(u *Uniter) (next Mode, err error) { 105 return func(u *Uniter) (next Mode, err error) {
112 defer errorContextf(&err, "ModeInstalling") 106 defer errorContextf(&err, "ModeInstalling")
113 » » if err = u.changeCharm(sch, charm.Installing); err != nil { 107 » » if err = u.deploy(sch, Install); err != nil {
114 return nil, err 108 return nil, err
115 } 109 }
116 return ModeContinue, nil 110 return ModeContinue, nil
117 } 111 }
118 } 112 }
119 113
120 // ModeStarting is responsible for running the "start" hook. 114 // ModeStarting is responsible for running the "start" hook.
121 func ModeStarting(u *Uniter) (next Mode, err error) { 115 func ModeStarting(u *Uniter) (next Mode, err error) {
122 defer errorContextf(&err, "ModeStarting") 116 defer errorContextf(&err, "ModeStarting")
123 if err := u.unit.SetStatus(state.UnitInstalled, ""); err != nil { 117 if err := u.unit.SetStatus(state.UnitInstalled, ""); err != nil {
124 return nil, err 118 return nil, err
125 } 119 }
126 hi := hook.Info{Kind: hook.Start} 120 hi := hook.Info{Kind: hook.Start}
127 if err := u.runHook(hi); err != nil && err != errHookFailed { 121 if err := u.runHook(hi); err != nil && err != errHookFailed {
128 return nil, err 122 return nil, err
129 } 123 }
130 return ModeContinue, nil 124 return ModeContinue, nil
131 } 125 }
132 126
133 // ModeStarted is the Uniter's usual steady state. It watches for and responds t o: 127 // ModeStarted is the Uniter's usual steady state. It watches for and responds t o:
134 // * service configuration changes 128 // * service configuration changes
135 // * charm upgrade requests (not implemented) 129 // * charm upgrade requests (not implemented)
136 // * relation changes (not implemented) 130 // * relation changes (not implemented)
137 // * unit death (not implemented) 131 // * unit death (not implemented)
138 func ModeStarted(u *Uniter) (next Mode, err error) { 132 func ModeStarted(u *Uniter) (next Mode, err error) {
139 defer errorContextf(&err, "ModeStarted") 133 defer errorContextf(&err, "ModeStarted")
134 s, err := u.sf.Read()
135 if err != nil {
136 return nil, err
137 }
138 if s.Op != Abide {
139 return nil, fmt.Errorf("insane uniter state: %#v", s)
140 }
140 if err = u.unit.SetStatus(state.UnitStarted, ""); err != nil { 141 if err = u.unit.SetStatus(state.UnitStarted, ""); err != nil {
141 return nil, err 142 return nil, err
142 } 143 }
143 » config := u.service.WatchConfig() 144 » configw := u.service.WatchConfig()
144 » defer stop(config, &next, &err) 145 » defer stop(configw, &next, &err)
145 for { 146 for {
146 select { 147 select {
147 case <-u.tomb.Dying(): 148 case <-u.tomb.Dying():
148 return nil, tomb.ErrDying 149 return nil, tomb.ErrDying
149 » » case _, ok := <-config.Changes(): 150 » » case _, ok := <-configw.Changes():
150 if !ok { 151 if !ok {
151 » » » » return nil, watcher.MustErr(config) 152 » » » » return nil, watcher.MustErr(configw)
152 } 153 }
153 hi := hook.Info{Kind: hook.ConfigChanged} 154 hi := hook.Info{Kind: hook.ConfigChanged}
154 if err = u.runHook(hi); err != nil { 155 if err = u.runHook(hi); err != nil {
155 if err == errHookFailed { 156 if err == errHookFailed {
156 return ModeHookError, nil 157 return ModeHookError, nil
157 } 158 }
158 return nil, err 159 return nil, err
159 } 160 }
160 // TODO once we've run the initial config-changed, start other watches. 161 // TODO once we've run the initial config-changed, start other watches.
161 } 162 }
162 // TODO: unit death; charm upgrades; relations. 163 // TODO: unit death; charm upgrades; relations.
163 } 164 }
164 panic("unreachable") 165 panic("unreachable")
165 } 166 }
166 167
167 // ModeHookError is responsible for watching and responding to: 168 // ModeHookError is responsible for watching and responding to:
168 // * user resolution of hook errors 169 // * user resolution of hook errors
169 // * forced charm upgrade requests (not implemented) 170 // * forced charm upgrade requests (not implemented)
170 // * unit death (not implemented) 171 // * unit death (not implemented)
171 func ModeHookError(u *Uniter) (next Mode, err error) { 172 func ModeHookError(u *Uniter) (next Mode, err error) {
172 defer errorContextf(&err, "ModeHookError") 173 defer errorContextf(&err, "ModeHookError")
173 » hs, err := u.hook.Read() 174 » s, err := u.sf.Read()
174 if err != nil { 175 if err != nil {
175 return nil, err 176 return nil, err
176 } 177 }
177 » if hs.Status != hook.Pending { 178 » if s.Op != RunHook || s.OpStep != Pending {
178 » » return nil, fmt.Errorf("inconsistent hook status %q", hs.Status) 179 » » return nil, fmt.Errorf("insane uniter state: %#v", s)
179 } 180 }
180 » msg := fmt.Sprintf("hook failed: %q", hs.Info.Kind) 181 » msg := fmt.Sprintf("hook failed: %q", s.Hook.Kind)
181 if err = u.unit.SetStatus(state.UnitError, msg); err != nil { 182 if err = u.unit.SetStatus(state.UnitError, msg); err != nil {
182 return nil, err 183 return nil, err
183 } 184 }
184 // Wait for shutdown, error resolution, or forced charm upgrade. 185 // Wait for shutdown, error resolution, or forced charm upgrade.
185 » resolved := u.unit.WatchResolved() 186 » resolvedw := u.unit.WatchResolved()
186 » defer stop(resolved, &next, &err) 187 » defer stop(resolvedw, &next, &err)
187 for { 188 for {
188 select { 189 select {
189 case <-u.tomb.Dying(): 190 case <-u.tomb.Dying():
190 return nil, tomb.ErrDying 191 return nil, tomb.ErrDying
191 » » case rm, ok := <-resolved.Changes(): 192 » » case rm, ok := <-resolvedw.Changes():
192 if !ok { 193 if !ok {
193 » » » » return nil, watcher.MustErr(resolved) 194 » » » » return nil, watcher.MustErr(resolvedw)
194 } 195 }
195 switch rm { 196 switch rm {
196 case state.ResolvedNone: 197 case state.ResolvedNone:
197 continue 198 continue
198 case state.ResolvedRetryHooks: 199 case state.ResolvedRetryHooks:
199 » » » » err = u.runHook(hs.Info) 200 » » » » err = u.runHook(*s.Hook)
200 case state.ResolvedNoHooks: 201 case state.ResolvedNoHooks:
201 » » » » err = u.commitHook(hs.Info) 202 » » » » err = u.commitHook(*s.Hook)
202 default: 203 default:
203 panic(fmt.Errorf("unhandled resolved mode %q", r m)) 204 panic(fmt.Errorf("unhandled resolved mode %q", r m))
204 } 205 }
205 if e := u.unit.ClearResolved(); e != nil { 206 if e := u.unit.ClearResolved(); e != nil {
206 err = e 207 err = e
207 } 208 }
208 if err == errHookFailed { 209 if err == errHookFailed {
209 continue 210 continue
210 } else if err != nil { 211 } else if err != nil {
211 return nil, err 212 return nil, err
(...skipping 12 matching lines...) Expand all
224 *err = e 225 *err = e
225 } 226 }
226 } 227 }
227 228
228 type stopper interface { 229 type stopper interface {
229 Stop() error 230 Stop() error
230 } 231 }
231 232
232 // errorContextf prefixes the error stored in err with text formatted 233 // errorContextf prefixes the error stored in err with text formatted
233 // according to the format specifier. If err does not contain an error, 234 // according to the format specifier. If err does not contain an error,
234 // or if err is tome.ErrDying, errorContextf does nothing. 235 // or if err is tomb.ErrDying, errorContextf does nothing.
235 func errorContextf(err *error, format string, args ...interface{}) { 236 func errorContextf(err *error, format string, args ...interface{}) {
236 if *err != nil && *err != tomb.ErrDying { 237 if *err != nil && *err != tomb.ErrDying {
237 *err = errors.New(fmt.Sprintf(format, args...) + ": " + (*err).E rror()) 238 *err = errors.New(fmt.Sprintf(format, args...) + ": " + (*err).E rror())
238 } 239 }
239 } 240 }
OLDNEW
« no previous file with comments | « worker/uniter/hook/hook_test.go ('k') | worker/uniter/state.go » ('j') | no next file with comments »

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