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

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

Issue 6489083: combine charm and hook states as uniter state
Left Patch Set: combine charm and hook states as uniter state Created 11 years, 6 months ago
Right 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « worker/uniter/state_test.go ('k') | worker/uniter/uniter_test.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/cmd" 6 "launchpad.net/juju-core/cmd"
7 "launchpad.net/juju-core/cmd/jujuc/server" 7 "launchpad.net/juju-core/cmd/jujuc/server"
8 "launchpad.net/juju-core/environs"
9 "launchpad.net/juju-core/log" 8 "launchpad.net/juju-core/log"
10 "launchpad.net/juju-core/state" 9 "launchpad.net/juju-core/state"
11 "launchpad.net/juju-core/state/presence" 10 "launchpad.net/juju-core/state/presence"
12 "launchpad.net/juju-core/trivial" 11 "launchpad.net/juju-core/trivial"
13 "launchpad.net/juju-core/worker/uniter/charm" 12 "launchpad.net/juju-core/worker/uniter/charm"
14 "launchpad.net/juju-core/worker/uniter/hook" 13 "launchpad.net/juju-core/worker/uniter/hook"
15 "launchpad.net/tomb" 14 "launchpad.net/tomb"
16 "math/rand" 15 "math/rand"
17 "path/filepath" 16 "path/filepath"
18 "strings"
19 "time" 17 "time"
20 ) 18 )
21 19
22 // Uniter implements the capabilities of the unit agent. It is not intended to 20 // Uniter implements the capabilities of the unit agent. It is not intended to
23 // implement the actual *behaviour* of the unit agent; that responsibility is 21 // implement the actual *behaviour* of the unit agent; that responsibility is
24 // delegated to Mode values, which are expected to use the capabilities of the 22 // delegated to Mode values, which are expected to use the capabilities of the
25 // uniter to react appropriately to changes in the system. 23 // uniter to react appropriately to changes in the system.
26 type Uniter struct { 24 type Uniter struct {
27 tomb tomb.Tomb 25 tomb tomb.Tomb
28 st *state.State 26 st *state.State
29 unit *state.Unit 27 unit *state.Unit
30 service *state.Service 28 service *state.Service
31 pinger *presence.Pinger 29 pinger *presence.Pinger
32 30
33 baseDir string 31 baseDir string
34 charm *charm.GitDir 32 charm *charm.GitDir
35 bundles *charm.BundlesDir 33 bundles *charm.BundlesDir
36 deployer *charm.Deployer 34 deployer *charm.Deployer
37 » op *StateFile 35 » sf *StateFile
38 rand *rand.Rand 36 rand *rand.Rand
39 } 37 }
40 38
41 // NewUniter creates a new Uniter which will install, run, and upgrade a 39 // NewUniter creates a new Uniter which will install, run, and upgrade a
42 // charm on behalf of the named unit, by executing hooks and operations 40 // charm on behalf of the named unit, by executing hooks and operations
43 // provoked by changes in st. 41 // provoked by changes in st.
44 func NewUniter(st *state.State, name string) (u *Uniter, err error) { 42 func NewUniter(st *state.State, name string, dataDir string) (u *Uniter, err err or) {
45 defer trivial.ErrorContextf(&err, "failed to create uniter for unit %q", name) 43 defer trivial.ErrorContextf(&err, "failed to create uniter for unit %q", name)
46 baseDir, err := ensureFs(name)
47 if err != nil {
48 return nil, err
49 }
50 unit, err := st.Unit(name) 44 unit, err := st.Unit(name)
45 if err != nil {
46 return nil, err
47 }
48 baseDir, err := ensureFs(dataDir, unit)
51 if err != nil { 49 if err != nil {
52 return nil, err 50 return nil, err
53 } 51 }
54 service, err := st.Service(unit.ServiceName()) 52 service, err := st.Service(unit.ServiceName())
55 if err != nil { 53 if err != nil {
56 return nil, err 54 return nil, err
57 } 55 }
58 pinger, err := unit.SetAgentAlive() 56 pinger, err := unit.SetAgentAlive()
59 if err != nil { 57 if err != nil {
60 return nil, err 58 return nil, err
61 } 59 }
62 u = &Uniter{ 60 u = &Uniter{
63 st: st, 61 st: st,
64 unit: unit, 62 unit: unit,
65 service: service, 63 service: service,
66 pinger: pinger, 64 pinger: pinger,
67 baseDir: baseDir, 65 baseDir: baseDir,
68 charm: charm.NewGitDir(filepath.Join(baseDir, "charm")), 66 charm: charm.NewGitDir(filepath.Join(baseDir, "charm")),
69 bundles: charm.NewBundlesDir(filepath.Join(baseDir, "state", "b undles")), 67 bundles: charm.NewBundlesDir(filepath.Join(baseDir, "state", "b undles")),
70 deployer: charm.NewDeployer(filepath.Join(baseDir, "state", "dep loyer")), 68 deployer: charm.NewDeployer(filepath.Join(baseDir, "state", "dep loyer")),
71 » » op: NewStateFile(filepath.Join(baseDir, "state", "uniter") ), 69 » » sf: NewStateFile(filepath.Join(baseDir, "state", "uniter") ),
72 rand: rand.New(rand.NewSource(time.Now().Unix())), 70 rand: rand.New(rand.NewSource(time.Now().Unix())),
73 } 71 }
74 go u.loop() 72 go u.loop()
75 return u, nil 73 return u, nil
76 } 74 }
77 75
78 func (u *Uniter) loop() { 76 func (u *Uniter) loop() {
79 var err error 77 var err error
80 mode := ModeInit 78 mode := ModeInit
81 for mode != nil { 79 for mode != nil {
(...skipping 17 matching lines...) Expand all
99 func (u *Uniter) Wait() error { 97 func (u *Uniter) Wait() error {
100 return u.tomb.Wait() 98 return u.tomb.Wait()
101 } 99 }
102 100
103 // deploy deploys the supplied charm, and sets follow-up hook operation state 101 // deploy deploys the supplied charm, and sets follow-up hook operation state
104 // as indicated by reason. 102 // as indicated by reason.
105 func (u *Uniter) deploy(sch *state.Charm, reason Op) error { 103 func (u *Uniter) deploy(sch *state.Charm, reason Op) error {
106 if reason != Install { 104 if reason != Install {
107 panic(fmt.Errorf("unknown deploy operation %q", reason)) 105 panic(fmt.Errorf("unknown deploy operation %q", reason))
108 } 106 }
109 » op, err := u.op.Read() 107 » s, err := u.sf.Read()
niemeyer 2012/09/11 14:52:04 Feels like these are misnamed. We have an Op, and
110 if err != nil && err != ErrNoStateFile { 108 if err != nil && err != ErrNoStateFile {
111 return err 109 return err
112 } 110 }
113 url := sch.URL() 111 url := sch.URL()
114 » if op.Status != Committing { 112 » if s == nil || s.OpStep != Done {
115 log.Printf("fetching charm %q", url) 113 log.Printf("fetching charm %q", url)
116 bun, err := u.bundles.Read(sch, u.tomb.Dying()) 114 bun, err := u.bundles.Read(sch, u.tomb.Dying())
117 if err != nil { 115 if err != nil {
118 return err 116 return err
119 } 117 }
120 » » if err = u.deployer.SetCharm(bun, url); err != nil { 118 » » if err = u.deployer.Stage(bun, url); err != nil {
niemeyer 2012/09/11 14:52:04 Can we talk about this live somewhere? I'd appreci
fwereade 2012/09/12 15:16:40 Discussed live, agreed OK :).
121 return err 119 return err
122 } 120 }
123 log.Printf("deploying charm %q", url) 121 log.Printf("deploying charm %q", url)
124 » » if err = u.op.Write(reason, Pending, nil, url); err != nil { 122 » » if err = u.sf.Write(reason, Pending, nil, url); err != nil {
125 return err 123 return err
126 } 124 }
127 if err = u.deployer.Deploy(u.charm); err != nil { 125 if err = u.deployer.Deploy(u.charm); err != nil {
128 return err 126 return err
129 } 127 }
130 » » if err = u.op.Write(reason, Committing, nil, url); err != nil { 128 » » if err = u.sf.Write(reason, Done, nil, url); err != nil {
131 return err 129 return err
132 } 130 }
133 } 131 }
134 log.Printf("charm %q is deployed", url) 132 log.Printf("charm %q is deployed", url)
135 if err := u.unit.SetCharm(sch); err != nil { 133 if err := u.unit.SetCharm(sch); err != nil {
136 return err 134 return err
137 } 135 }
138 » return u.op.Write(RunHook, Queued, &hook.Info{Kind: hook.Install}, nil) 136 » return u.sf.Write(RunHook, Queued, &hook.Info{Kind: hook.Install}, nil)
139 } 137 }
140 138
141 // errHookFailed indicates that a hook failed to execute, but that the Uniter's 139 // errHookFailed indicates that a hook failed to execute, but that the Uniter's
142 // operation is not affected by the error. 140 // operation is not affected by the error.
143 var errHookFailed = errors.New("hook execution failed") 141 var errHookFailed = errors.New("hook execution failed")
144 142
145 // runHook executes the supplied hook.Info in an appropriate hook context. If 143 // runHook executes the supplied hook.Info in an appropriate hook context. If
146 // the hook itself fails to execute, it returns errHookFailed. 144 // the hook itself fails to execute, it returns errHookFailed.
147 func (u *Uniter) runHook(hi hook.Info) error { 145 func (u *Uniter) runHook(hi hook.Info) error {
148 // Prepare context. 146 // Prepare context.
(...skipping 21 matching lines...) Expand all
170 } 168 }
171 socketPath := filepath.Join(u.baseDir, "agent.socket") 169 socketPath := filepath.Join(u.baseDir, "agent.socket")
172 srv, err := server.NewServer(getCmd, socketPath) 170 srv, err := server.NewServer(getCmd, socketPath)
173 if err != nil { 171 if err != nil {
174 return err 172 return err
175 } 173 }
176 go srv.Run() 174 go srv.Run()
177 defer srv.Close() 175 defer srv.Close()
178 176
179 // Run the hook. 177 // Run the hook.
180 » if err := u.op.Write(RunHook, Pending, &hi, nil); err != nil { 178 » if err := u.sf.Write(RunHook, Pending, &hi, nil); err != nil {
181 return err 179 return err
182 } 180 }
183 log.Printf("running hook %q", hookName) 181 log.Printf("running hook %q", hookName)
184 if err := hctx.RunHook(hookName, u.charm.Path(), socketPath); err != nil { 182 if err := hctx.RunHook(hookName, u.charm.Path(), socketPath); err != nil {
185 log.Printf("hook failed: %s", err) 183 log.Printf("hook failed: %s", err)
186 return errHookFailed 184 return errHookFailed
187 } 185 }
188 log.Printf("hook succeeded") 186 log.Printf("hook succeeded")
189 return u.commitHook(hi) 187 return u.commitHook(hi)
190 } 188 }
191 189
192 // commitHook ensures that state is consistent with the supplied hook, and 190 // commitHook ensures that state is consistent with the supplied hook, and
193 // that the fact of the hook's completion is persisted. 191 // that the fact of the hook's completion is persisted.
194 func (u *Uniter) commitHook(hi hook.Info) error { 192 func (u *Uniter) commitHook(hi hook.Info) error {
195 » if err := u.op.Write(RunHook, Committing, &hi, nil); err != nil { 193 » if err := u.sf.Write(RunHook, Done, &hi, nil); err != nil {
196 return err 194 return err
197 } 195 }
198 if hi.Kind.IsRelation() { 196 if hi.Kind.IsRelation() {
199 panic("relation hooks are not yet supported") 197 panic("relation hooks are not yet supported")
200 // TODO: commit relation state changes. 198 // TODO: commit relation state changes.
201 } 199 }
202 if err := u.charm.Snapshotf("completed %q hook", hi.Kind); err != nil { 200 if err := u.charm.Snapshotf("completed %q hook", hi.Kind); err != nil {
niemeyer 2012/09/11 14:52:04 "Completed %q hook."
fwereade 2012/09/12 15:16:40 Fixed in followup.
203 return err 201 return err
204 } 202 }
205 » if err := u.op.Write(Abide, Pending, &hi, nil); err != nil { 203 » if err := u.sf.Write(Abide, Pending, &hi, nil); err != nil {
niemeyer 2012/09/11 14:52:04 Abide + Pending seems like a weird pair. Abide sho
fwereade 2012/09/12 15:16:40 Uncertain... the uniter is still abiding, right?
niemeyer 2012/09/12 20:58:17 Yeah, I guess. Feels a bit like there's an action
206 return err 204 return err
207 } 205 }
208 log.Printf("hook complete") 206 log.Printf("hook complete")
209 return nil 207 return nil
210 } 208 }
211 209
212 // ensureFs ensures that files and directories required by the named uniter 210 // ensureFs ensures that files and directories required by the named uniter
213 // exist. It returns the path to the directory within which the uniter must 211 // exist inside dataDir. It returns the path to the directory within which the u niter must
214 // store its data. 212 // store its data.
215 func ensureFs(name string) (string, error) { 213 func ensureFs(dataDir string, unit *state.Unit) (string, error) {
216 // TODO: do this OAOO at packaging time? 214 // TODO: do this OAOO at packaging time?
217 » if err := EnsureJujucSymlinks(name); err != nil { 215 » if err := EnsureJujucSymlinks(dataDir, unit.PathKey()); err != nil {
218 return "", err 216 return "", err
219 } 217 }
220 » path := filepath.Join(environs.VarDir, "units", strings.Replace(name, "/ ", "-", 1)) 218 » path := filepath.Join(dataDir, "agents", unit.PathKey())
221 if err := trivial.EnsureDir(filepath.Join(path, "state")); err != nil { 219 if err := trivial.EnsureDir(filepath.Join(path, "state")); err != nil {
222 return "", err 220 return "", err
223 } 221 }
224 return path, nil 222 return path, nil
225 } 223 }
LEFTRIGHT

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