Merge lp:~thumper/juju-core/run-cmd-refactor into lp:~go-bot/juju-core/trunk
- run-cmd-refactor
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Tim Penhey |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2202 |
Proposed branch: | lp:~thumper/juju-core/run-cmd-refactor |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
683 lines (+235/-91) 19 files modified
cmd/juju/run_test.go (+3/-2) cmd/jujud/main.go (+2/-1) cmd/jujud/run.go (+2/-1) cmd/jujud/run_test.go (+3/-2) cmd/remote.go (+0/-12) state/api/params/internal.go (+2/-2) state/apiserver/client/run.go (+3/-3) state/apiserver/client/run_test.go (+15/-15) utils/exec/exec.go (+73/-0) utils/exec/exec_test.go (+82/-0) utils/exec/package_test.go (+24/-0) utils/ssh/run.go (+2/-2) worker/uniter/context.go (+7/-37) worker/uniter/jujuc/server.go (+2/-1) worker/uniter/jujuc/server_test.go (+3/-2) worker/uniter/runlistener.go (+4/-4) worker/uniter/runlistener_test.go (+4/-4) worker/uniter/uniter.go (+2/-1) worker/uniter/uniter_test.go (+2/-2) |
To merge this branch: | bzr merge lp:~thumper/juju-core/run-cmd-refactor |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+201680@code.launchpad.net |
Commit message
Refactor RunCommands function into a util package
As part of this work, the return structure has been
moved into the utils/exec package along with the
RunCommands function.
I didn't really like the return structure being in
the cmd package, but I didn't see a better place at
the time of making it.
The biggest part of this restructing is the renaming
of the call sites. A benefit is reduced package
dependencies by the users.
Description of the change
Refactor RunCommands function into a util package
As part of this work, the return structure has been
moved into the utils/exec package along with the
RunCommands function.
I didn't really like the return structure being in
the cmd package, but I didn't see a better place at
the time of making it.
The biggest part of this restructing is the renaming
of the call sites. A benefit is reduced package
dependencies by the users.
Tim Penhey (thumper) wrote : | # |
Ian Booth (wallyworld) wrote : | # |
Go Bot (go-bot) wrote : | # |
The attempt to merge lp:~thumper/juju-core/run-cmd-refactor into lp:juju-core failed. Below is the output from the failed tests.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
Preview Diff
1 | === modified file 'cmd/juju/run_test.go' |
2 | --- cmd/juju/run_test.go 2014-01-12 20:38:39 +0000 |
3 | +++ cmd/juju/run_test.go 2014-01-14 21:31:32 +0000 |
4 | @@ -13,6 +13,7 @@ |
5 | "launchpad.net/juju-core/state/api/params" |
6 | "launchpad.net/juju-core/testing" |
7 | jc "launchpad.net/juju-core/testing/checkers" |
8 | + "launchpad.net/juju-core/utils/exec" |
9 | ) |
10 | |
11 | type RunSuite struct { |
12 | @@ -191,7 +192,7 @@ |
13 | message: "stdout and stderr are base64 encoded if not valid utf8", |
14 | results: []params.RunResult{ |
15 | params.RunResult{ |
16 | - RemoteResponse: cmd.RemoteResponse{ |
17 | + ExecResponse: exec.ExecResponse{ |
18 | Stdout: []byte{0xff}, |
19 | Stderr: []byte{0xfe}, |
20 | }, |
21 | @@ -386,7 +387,7 @@ |
22 | |
23 | func makeRunResult(mock mockResponse) params.RunResult { |
24 | return params.RunResult{ |
25 | - RemoteResponse: cmd.RemoteResponse{ |
26 | + ExecResponse: exec.ExecResponse{ |
27 | Stdout: []byte(mock.stdout), |
28 | Stderr: []byte(mock.stderr), |
29 | Code: mock.code, |
30 | |
31 | === modified file 'cmd/jujud/main.go' |
32 | --- cmd/jujud/main.go 2013-12-12 22:54:02 +0000 |
33 | +++ cmd/jujud/main.go 2014-01-14 21:31:32 +0000 |
34 | @@ -10,6 +10,7 @@ |
35 | "path/filepath" |
36 | |
37 | "launchpad.net/juju-core/cmd" |
38 | + "launchpad.net/juju-core/utils/exec" |
39 | "launchpad.net/juju-core/worker/uniter/jujuc" |
40 | |
41 | // Import the providers. |
42 | @@ -76,7 +77,7 @@ |
43 | return |
44 | } |
45 | defer client.Close() |
46 | - var resp cmd.RemoteResponse |
47 | + var resp exec.ExecResponse |
48 | err = client.Call("Jujuc.Main", req, &resp) |
49 | if err != nil { |
50 | return |
51 | |
52 | === modified file 'cmd/jujud/run.go' |
53 | --- cmd/jujud/run.go 2013-12-13 04:40:41 +0000 |
54 | +++ cmd/jujud/run.go 2014-01-14 21:31:32 +0000 |
55 | @@ -13,6 +13,7 @@ |
56 | |
57 | "launchpad.net/juju-core/cmd" |
58 | "launchpad.net/juju-core/names" |
59 | + "launchpad.net/juju-core/utils/exec" |
60 | "launchpad.net/juju-core/worker/uniter" |
61 | ) |
62 | |
63 | @@ -96,7 +97,7 @@ |
64 | } |
65 | defer client.Close() |
66 | |
67 | - var result cmd.RemoteResponse |
68 | + var result exec.ExecResponse |
69 | err = client.Call(uniter.JujuRunEndpoint, c.commands, &result) |
70 | if err != nil { |
71 | return err |
72 | |
73 | === modified file 'cmd/jujud/run_test.go' |
74 | --- cmd/jujud/run_test.go 2013-12-13 03:37:01 +0000 |
75 | +++ cmd/jujud/run_test.go 2014-01-14 21:31:32 +0000 |
76 | @@ -15,6 +15,7 @@ |
77 | "launchpad.net/juju-core/testing" |
78 | jc "launchpad.net/juju-core/testing/checkers" |
79 | "launchpad.net/juju-core/testing/testbase" |
80 | + "launchpad.net/juju-core/utils/exec" |
81 | "launchpad.net/juju-core/worker/uniter" |
82 | ) |
83 | |
84 | @@ -125,9 +126,9 @@ |
85 | |
86 | var _ uniter.CommandRunner = (*mockRunner)(nil) |
87 | |
88 | -func (r *mockRunner) RunCommands(commands string) (results *cmd.RemoteResponse, err error) { |
89 | +func (r *mockRunner) RunCommands(commands string) (results *exec.ExecResponse, err error) { |
90 | r.c.Log("mock runner: " + commands) |
91 | - return &cmd.RemoteResponse{ |
92 | + return &exec.ExecResponse{ |
93 | Code: 42, |
94 | Stdout: []byte(commands + " stdout"), |
95 | Stderr: []byte(commands + " stderr"), |
96 | |
97 | === removed file 'cmd/remote.go' |
98 | --- cmd/remote.go 2013-12-12 04:31:01 +0000 |
99 | +++ cmd/remote.go 1970-01-01 00:00:00 +0000 |
100 | @@ -1,12 +0,0 @@ |
101 | -// Copyright 2013 Canonical Ltd. |
102 | -// Licensed under the AGPLv3, see LICENCE file for details. |
103 | - |
104 | -package cmd |
105 | - |
106 | -// RemoteResponse contains the return code and output generated by a remote |
107 | -// request. |
108 | -type RemoteResponse struct { |
109 | - Code int |
110 | - Stdout []byte |
111 | - Stderr []byte |
112 | -} |
113 | |
114 | === modified file 'state/api/params/internal.go' |
115 | --- state/api/params/internal.go 2014-01-12 20:07:40 +0000 |
116 | +++ state/api/params/internal.go 2014-01-14 21:31:32 +0000 |
117 | @@ -6,10 +6,10 @@ |
118 | import ( |
119 | "time" |
120 | |
121 | - "launchpad.net/juju-core/cmd" |
122 | "launchpad.net/juju-core/constraints" |
123 | "launchpad.net/juju-core/instance" |
124 | "launchpad.net/juju-core/tools" |
125 | + "launchpad.net/juju-core/utils/exec" |
126 | "launchpad.net/juju-core/version" |
127 | ) |
128 | |
129 | @@ -527,7 +527,7 @@ |
130 | // RunResult contains the result from an individual run call on a machine. |
131 | // UnitId is populated if the command was run inside the unit context. |
132 | type RunResult struct { |
133 | - cmd.RemoteResponse |
134 | + exec.ExecResponse |
135 | MachineId string |
136 | UnitId string |
137 | Error string |
138 | |
139 | === modified file 'state/apiserver/client/run.go' |
140 | --- state/apiserver/client/run.go 2014-01-12 20:28:43 +0000 |
141 | +++ state/apiserver/client/run.go 2014-01-14 21:31:32 +0000 |
142 | @@ -150,9 +150,9 @@ |
143 | response, err := ssh.ExecuteCommandOnMachine(param.ExecParams) |
144 | logger.Debugf("reponse from %s: %v (err:%v)", param.MachineId, response, err) |
145 | execResponse := params.RunResult{ |
146 | - RemoteResponse: response, |
147 | - MachineId: param.MachineId, |
148 | - UnitId: param.UnitId, |
149 | + ExecResponse: response, |
150 | + MachineId: param.MachineId, |
151 | + UnitId: param.UnitId, |
152 | } |
153 | if err != nil { |
154 | execResponse.Error = fmt.Sprint(err) |
155 | |
156 | === modified file 'state/apiserver/client/run_test.go' |
157 | --- state/apiserver/client/run_test.go 2014-01-12 20:28:43 +0000 |
158 | +++ state/apiserver/client/run_test.go 2014-01-14 21:31:32 +0000 |
159 | @@ -12,13 +12,13 @@ |
160 | |
161 | gc "launchpad.net/gocheck" |
162 | |
163 | - "launchpad.net/juju-core/cmd" |
164 | "launchpad.net/juju-core/instance" |
165 | "launchpad.net/juju-core/state" |
166 | "launchpad.net/juju-core/state/api/params" |
167 | "launchpad.net/juju-core/state/apiserver/client" |
168 | "launchpad.net/juju-core/testing" |
169 | jc "launchpad.net/juju-core/testing/checkers" |
170 | + "launchpad.net/juju-core/utils/exec" |
171 | "launchpad.net/juju-core/utils/ssh" |
172 | ) |
173 | |
174 | @@ -230,8 +230,8 @@ |
175 | for i := 0; i < 3; i++ { |
176 | expectedResults = append(expectedResults, |
177 | params.RunResult{ |
178 | - RemoteResponse: cmd.RemoteResponse{Stdout: []byte("hostname\n")}, |
179 | - MachineId: fmt.Sprint(i), |
180 | + ExecResponse: exec.ExecResponse{Stdout: []byte("hostname\n")}, |
181 | + MachineId: fmt.Sprint(i), |
182 | }) |
183 | } |
184 | |
185 | @@ -264,18 +264,18 @@ |
186 | c.Assert(results, gc.HasLen, 3) |
187 | expectedResults := []params.RunResult{ |
188 | params.RunResult{ |
189 | - RemoteResponse: cmd.RemoteResponse{Stdout: []byte("hostname\n")}, |
190 | - MachineId: "0", |
191 | - }, |
192 | - params.RunResult{ |
193 | - RemoteResponse: cmd.RemoteResponse{Stdout: []byte("juju-run magic/0 'hostname'\n")}, |
194 | - MachineId: "1", |
195 | - UnitId: "magic/0", |
196 | - }, |
197 | - params.RunResult{ |
198 | - RemoteResponse: cmd.RemoteResponse{Stdout: []byte("juju-run magic/1 'hostname'\n")}, |
199 | - MachineId: "2", |
200 | - UnitId: "magic/1", |
201 | + ExecResponse: exec.ExecResponse{Stdout: []byte("hostname\n")}, |
202 | + MachineId: "0", |
203 | + }, |
204 | + params.RunResult{ |
205 | + ExecResponse: exec.ExecResponse{Stdout: []byte("juju-run magic/0 'hostname'\n")}, |
206 | + MachineId: "1", |
207 | + UnitId: "magic/0", |
208 | + }, |
209 | + params.RunResult{ |
210 | + ExecResponse: exec.ExecResponse{Stdout: []byte("juju-run magic/1 'hostname'\n")}, |
211 | + MachineId: "2", |
212 | + UnitId: "magic/1", |
213 | }, |
214 | } |
215 | |
216 | |
217 | === added directory 'utils/exec' |
218 | === added file 'utils/exec/exec.go' |
219 | --- utils/exec/exec.go 1970-01-01 00:00:00 +0000 |
220 | +++ utils/exec/exec.go 2014-01-14 21:31:32 +0000 |
221 | @@ -0,0 +1,73 @@ |
222 | +// Copyright 2014 Canonical Ltd. |
223 | +// Licensed under the AGPLv3, see LICENCE file for details. |
224 | + |
225 | +package exec |
226 | + |
227 | +import ( |
228 | + "bytes" |
229 | + "os/exec" |
230 | + "syscall" |
231 | + |
232 | + "launchpad.net/loggo" |
233 | +) |
234 | + |
235 | +var logger = loggo.GetLogger("juju.util.exec") |
236 | + |
237 | +// Parameters for RunCommands. Commands contains one or more commands to be |
238 | +// executed using '/bin/bash -s'. If WorkingDir is set, this is passed |
239 | +// through to bash. Similarly if the Environment is specified, this is used |
240 | +// for executing the command. |
241 | +type RunParams struct { |
242 | + Commands string |
243 | + WorkingDir string |
244 | + Environment []string |
245 | +} |
246 | + |
247 | +// ExecResponse contains the return code and output generated by executing a |
248 | +// command. |
249 | +type ExecResponse struct { |
250 | + Code int |
251 | + Stdout []byte |
252 | + Stderr []byte |
253 | +} |
254 | + |
255 | +// RunCommands executes the Commands specified in the RunParams using |
256 | +// '/bin/bash -s', passing the commands through as stdin, and collecting |
257 | +// stdout and stderr. If a non-zero return code is returned, this is |
258 | +// collected as the code for the response and this does not classify as an |
259 | +// error. |
260 | +func RunCommands(run RunParams) (*ExecResponse, error) { |
261 | + ps := exec.Command("/bin/bash", "-s") |
262 | + if run.Environment != nil { |
263 | + ps.Env = run.Environment |
264 | + } |
265 | + if run.WorkingDir != "" { |
266 | + ps.Dir = run.WorkingDir |
267 | + } |
268 | + ps.Stdin = bytes.NewBufferString(run.Commands) |
269 | + |
270 | + stdout := &bytes.Buffer{} |
271 | + stderr := &bytes.Buffer{} |
272 | + |
273 | + ps.Stdout = stdout |
274 | + ps.Stderr = stderr |
275 | + |
276 | + err := ps.Start() |
277 | + if err == nil { |
278 | + err = ps.Wait() |
279 | + } |
280 | + result := &ExecResponse{ |
281 | + Stdout: stdout.Bytes(), |
282 | + Stderr: stderr.Bytes(), |
283 | + } |
284 | + if ee, ok := err.(*exec.ExitError); ok && err != nil { |
285 | + status := ee.ProcessState.Sys().(syscall.WaitStatus) |
286 | + if status.Exited() { |
287 | + // A non-zero return code isn't considered an error here. |
288 | + result.Code = status.ExitStatus() |
289 | + err = nil |
290 | + } |
291 | + logger.Infof("run result: %v", ee) |
292 | + } |
293 | + return result, err |
294 | +} |
295 | |
296 | === added file 'utils/exec/exec_test.go' |
297 | --- utils/exec/exec_test.go 1970-01-01 00:00:00 +0000 |
298 | +++ utils/exec/exec_test.go 2014-01-14 21:31:32 +0000 |
299 | @@ -0,0 +1,82 @@ |
300 | +// Copyright 2014 Canonical Ltd. |
301 | +// Licensed under the AGPLv3, see LICENCE file for details. |
302 | + |
303 | +package exec_test |
304 | + |
305 | +import ( |
306 | + gc "launchpad.net/gocheck" |
307 | + |
308 | + jc "launchpad.net/juju-core/testing/checkers" |
309 | + "launchpad.net/juju-core/testing/testbase" |
310 | + "launchpad.net/juju-core/utils/exec" |
311 | +) |
312 | + |
313 | +type execSuite struct { |
314 | + testbase.LoggingSuite |
315 | +} |
316 | + |
317 | +var _ = gc.Suite(&execSuite{}) |
318 | + |
319 | +func (*execSuite) TestRunCommands(c *gc.C) { |
320 | + newDir := c.MkDir() |
321 | + |
322 | + for i, test := range []struct { |
323 | + message string |
324 | + commands string |
325 | + workingDir string |
326 | + environment []string |
327 | + stdout string |
328 | + stderr string |
329 | + code int |
330 | + }{ |
331 | + { |
332 | + message: "test stdout capture", |
333 | + commands: "echo testing stdout", |
334 | + stdout: "testing stdout\n", |
335 | + }, { |
336 | + message: "test stderr capture", |
337 | + commands: "echo testing stderr >&2", |
338 | + stderr: "testing stderr\n", |
339 | + }, { |
340 | + message: "test return code", |
341 | + commands: "exit 42", |
342 | + code: 42, |
343 | + }, { |
344 | + message: "test working dir", |
345 | + commands: "pwd", |
346 | + workingDir: newDir, |
347 | + stdout: newDir + "\n", |
348 | + }, { |
349 | + message: "test environment", |
350 | + commands: "echo $OMG_IT_WORKS", |
351 | + environment: []string{"OMG_IT_WORKS=like magic"}, |
352 | + stdout: "like magic\n", |
353 | + }, |
354 | + } { |
355 | + c.Logf("%v: %s", i, test.message) |
356 | + |
357 | + result, err := exec.RunCommands( |
358 | + exec.RunParams{ |
359 | + Commands: test.commands, |
360 | + WorkingDir: test.workingDir, |
361 | + Environment: test.environment, |
362 | + }) |
363 | + c.Assert(err, gc.IsNil) |
364 | + c.Assert(string(result.Stdout), gc.Equals, test.stdout) |
365 | + c.Assert(string(result.Stderr), gc.Equals, test.stderr) |
366 | + c.Assert(result.Code, gc.Equals, test.code) |
367 | + } |
368 | +} |
369 | + |
370 | +func (*execSuite) TestExecUnknownCommand(c *gc.C) { |
371 | + result, err := exec.RunCommands( |
372 | + exec.RunParams{ |
373 | + Commands: "unknown-command", |
374 | + }, |
375 | + ) |
376 | + c.Assert(err, gc.IsNil) |
377 | + c.Assert(result.Stdout, gc.HasLen, 0) |
378 | + c.Assert(string(result.Stderr), jc.Contains, "unknown-command: command not found") |
379 | + // 127 is a special bash return code meaning command not found. |
380 | + c.Assert(result.Code, gc.Equals, 127) |
381 | +} |
382 | |
383 | === added file 'utils/exec/package_test.go' |
384 | --- utils/exec/package_test.go 1970-01-01 00:00:00 +0000 |
385 | +++ utils/exec/package_test.go 2014-01-14 21:31:32 +0000 |
386 | @@ -0,0 +1,24 @@ |
387 | +// Copyright 2014 Canonical Ltd. |
388 | +// Licensed under the AGPLv3, see LICENCE file for details. |
389 | + |
390 | +package exec_test |
391 | + |
392 | +import ( |
393 | + "testing" |
394 | + |
395 | + gc "launchpad.net/gocheck" |
396 | + |
397 | + "launchpad.net/juju-core/testing/testbase" |
398 | +) |
399 | + |
400 | +func Test(t *testing.T) { gc.TestingT(t) } |
401 | + |
402 | +type Dependencies struct{} |
403 | + |
404 | +var _ = gc.Suite(&Dependencies{}) |
405 | + |
406 | +func (*Dependencies) TestPackageDependencies(c *gc.C) { |
407 | + // This test is to ensure we don't bring in dependencies without thinking. |
408 | + c.Assert(testbase.FindJujuCoreImports(c, "launchpad.net/juju-core/utils/exec"), |
409 | + gc.HasLen, 0) |
410 | +} |
411 | |
412 | === modified file 'utils/ssh/run.go' |
413 | --- utils/ssh/run.go 2014-01-10 01:57:51 +0000 |
414 | +++ utils/ssh/run.go 2014-01-14 21:31:32 +0000 |
415 | @@ -11,7 +11,7 @@ |
416 | "syscall" |
417 | "time" |
418 | |
419 | - "launchpad.net/juju-core/cmd" |
420 | + utilexec "launchpad.net/juju-core/utils/exec" |
421 | ) |
422 | |
423 | // ExecParams are used for the parameters for ExecuteCommandOnMachine. |
424 | @@ -27,7 +27,7 @@ |
425 | // through /bin/bash. If the command is not finished within the timeout |
426 | // specified, an error is returned. Any output captured during that time |
427 | // is also returned in the remote response. |
428 | -func ExecuteCommandOnMachine(params ExecParams) (result cmd.RemoteResponse, err error) { |
429 | +func ExecuteCommandOnMachine(params ExecParams) (result utilexec.ExecResponse, err error) { |
430 | // execute bash accepting commands on stdin |
431 | if params.Host == "" { |
432 | return result, fmt.Errorf("missing host address") |
433 | |
434 | === modified file 'worker/uniter/context.go' |
435 | --- worker/uniter/context.go 2013-12-13 03:01:21 +0000 |
436 | +++ worker/uniter/context.go 2014-01-14 21:31:32 +0000 |
437 | @@ -5,7 +5,6 @@ |
438 | |
439 | import ( |
440 | "bufio" |
441 | - "bytes" |
442 | "fmt" |
443 | "io" |
444 | "os" |
445 | @@ -14,13 +13,12 @@ |
446 | "sort" |
447 | "strings" |
448 | "sync" |
449 | - "syscall" |
450 | "time" |
451 | |
452 | "launchpad.net/juju-core/charm" |
453 | - "launchpad.net/juju-core/cmd" |
454 | "launchpad.net/juju-core/state/api/params" |
455 | "launchpad.net/juju-core/state/api/uniter" |
456 | + utilexec "launchpad.net/juju-core/utils/exec" |
457 | unitdebug "launchpad.net/juju-core/worker/uniter/debug" |
458 | "launchpad.net/juju-core/worker/uniter/jujuc" |
459 | ) |
460 | @@ -212,9 +210,13 @@ |
461 | |
462 | // RunCommands executes the commands in an environment which allows it to to |
463 | // call back into the hook context to execute jujuc tools. |
464 | -func (ctx *HookContext) RunCommands(commands, charmDir, toolsDir, socketPath string) (*cmd.RemoteResponse, error) { |
465 | +func (ctx *HookContext) RunCommands(commands, charmDir, toolsDir, socketPath string) (*utilexec.ExecResponse, error) { |
466 | env := ctx.hookVars(charmDir, toolsDir, socketPath) |
467 | - result, err := runCommands(commands, charmDir, env) |
468 | + result, err := utilexec.RunCommands( |
469 | + utilexec.RunParams{ |
470 | + Commands: commands, |
471 | + WorkingDir: charmDir, |
472 | + Environment: env}) |
473 | return result, ctx.finalizeContext("run commands", err) |
474 | } |
475 | |
476 | @@ -264,38 +266,6 @@ |
477 | return err |
478 | } |
479 | |
480 | -func runCommands(commands, charmDir string, env []string) (*cmd.RemoteResponse, error) { |
481 | - ps := exec.Command("/bin/bash", "-s") |
482 | - ps.Env = env |
483 | - ps.Dir = charmDir |
484 | - ps.Stdin = bytes.NewBufferString(commands) |
485 | - |
486 | - stdout := &bytes.Buffer{} |
487 | - stderr := &bytes.Buffer{} |
488 | - |
489 | - ps.Stdout = stdout |
490 | - ps.Stderr = stderr |
491 | - |
492 | - err := ps.Start() |
493 | - if err == nil { |
494 | - err = ps.Wait() |
495 | - } |
496 | - result := &cmd.RemoteResponse{ |
497 | - Stdout: stdout.Bytes(), |
498 | - Stderr: stderr.Bytes(), |
499 | - } |
500 | - if ee, ok := err.(*exec.ExitError); ok && err != nil { |
501 | - status := ee.ProcessState.Sys().(syscall.WaitStatus) |
502 | - if status.Exited() { |
503 | - // A non-zero return code isn't considered an error here. |
504 | - result.Code = status.ExitStatus() |
505 | - err = nil |
506 | - } |
507 | - logger.Infof("run result: %v", ee) |
508 | - } |
509 | - return result, err |
510 | -} |
511 | - |
512 | type hookLogger struct { |
513 | r io.ReadCloser |
514 | done chan struct{} |
515 | |
516 | === modified file 'worker/uniter/jujuc/server.go' |
517 | --- worker/uniter/jujuc/server.go 2013-12-12 04:31:01 +0000 |
518 | +++ worker/uniter/jujuc/server.go 2014-01-14 21:31:32 +0000 |
519 | @@ -18,6 +18,7 @@ |
520 | "launchpad.net/loggo" |
521 | |
522 | "launchpad.net/juju-core/cmd" |
523 | + "launchpad.net/juju-core/utils/exec" |
524 | ) |
525 | |
526 | var logger = loggo.GetLogger("worker.uniter.jujuc") |
527 | @@ -79,7 +80,7 @@ |
528 | |
529 | // Main runs the Command specified by req, and fills in resp. A single command |
530 | // is run at a time. |
531 | -func (j *Jujuc) Main(req Request, resp *cmd.RemoteResponse) error { |
532 | +func (j *Jujuc) Main(req Request, resp *exec.ExecResponse) error { |
533 | if req.CommandName == "" { |
534 | return badReqErrorf("command not specified") |
535 | } |
536 | |
537 | === modified file 'worker/uniter/jujuc/server_test.go' |
538 | --- worker/uniter/jujuc/server_test.go 2013-12-12 04:31:01 +0000 |
539 | +++ worker/uniter/jujuc/server_test.go 2014-01-14 21:31:32 +0000 |
540 | @@ -20,6 +20,7 @@ |
541 | "launchpad.net/juju-core/testing" |
542 | jc "launchpad.net/juju-core/testing/checkers" |
543 | "launchpad.net/juju-core/testing/testbase" |
544 | + "launchpad.net/juju-core/utils/exec" |
545 | "launchpad.net/juju-core/worker/uniter/jujuc" |
546 | ) |
547 | |
548 | @@ -97,7 +98,7 @@ |
549 | s.LoggingSuite.TearDownTest(c) |
550 | } |
551 | |
552 | -func (s *ServerSuite) Call(c *gc.C, req jujuc.Request) (resp cmd.RemoteResponse, err error) { |
553 | +func (s *ServerSuite) Call(c *gc.C, req jujuc.Request) (resp exec.ExecResponse, err error) { |
554 | client, err := rpc.Dial("unix", s.sockPath) |
555 | c.Assert(err, gc.IsNil) |
556 | defer client.Close() |
557 | @@ -162,7 +163,7 @@ |
558 | c.Assert(err, gc.ErrorMatches, `bad request: unknown context "whatever"`) |
559 | } |
560 | |
561 | -func (s *ServerSuite) AssertBadCommand(c *gc.C, args []string, code int) cmd.RemoteResponse { |
562 | +func (s *ServerSuite) AssertBadCommand(c *gc.C, args []string, code int) exec.ExecResponse { |
563 | resp, err := s.Call(c, jujuc.Request{"validCtx", c.MkDir(), args[0], args[1:]}) |
564 | c.Assert(err, gc.IsNil) |
565 | c.Assert(resp.Code, gc.Equals, code) |
566 | |
567 | === modified file 'worker/uniter/runlistener.go' |
568 | --- worker/uniter/runlistener.go 2013-12-13 02:41:10 +0000 |
569 | +++ worker/uniter/runlistener.go 2014-01-14 21:31:32 +0000 |
570 | @@ -11,16 +11,16 @@ |
571 | "net/rpc" |
572 | "sync" |
573 | |
574 | - "launchpad.net/juju-core/cmd" |
575 | + "launchpad.net/juju-core/utils/exec" |
576 | ) |
577 | |
578 | const JujuRunEndpoint = "JujuRunServer.RunCommands" |
579 | |
580 | // A CommandRunner is something that will actually execute the commands and |
581 | -// return the results of that execution in the cmd.RemoteResponse (which |
582 | +// return the results of that execution in the exec.ExecResponse (which |
583 | // contains stdout, stderr, and return code). |
584 | type CommandRunner interface { |
585 | - RunCommands(commands string) (results *cmd.RemoteResponse, err error) |
586 | + RunCommands(commands string) (results *exec.ExecResponse, err error) |
587 | } |
588 | |
589 | // RunListener is responsible for listening on the network connection and |
590 | @@ -42,7 +42,7 @@ |
591 | |
592 | // RunCommands delegates the actual running to the runner and populates the |
593 | // response structure. |
594 | -func (r *JujuRunServer) RunCommands(commands string, result *cmd.RemoteResponse) error { |
595 | +func (r *JujuRunServer) RunCommands(commands string, result *exec.ExecResponse) error { |
596 | logger.Debugf("RunCommands: %q", commands) |
597 | runResult, err := r.runner.RunCommands(commands) |
598 | *result = *runResult |
599 | |
600 | === modified file 'worker/uniter/runlistener_test.go' |
601 | --- worker/uniter/runlistener_test.go 2013-12-13 02:41:10 +0000 |
602 | +++ worker/uniter/runlistener_test.go 2014-01-14 21:31:32 +0000 |
603 | @@ -9,8 +9,8 @@ |
604 | |
605 | gc "launchpad.net/gocheck" |
606 | |
607 | - "launchpad.net/juju-core/cmd" |
608 | "launchpad.net/juju-core/testing/testbase" |
609 | + "launchpad.net/juju-core/utils/exec" |
610 | "launchpad.net/juju-core/worker/uniter" |
611 | ) |
612 | |
613 | @@ -49,7 +49,7 @@ |
614 | c.Assert(err, gc.IsNil) |
615 | defer client.Close() |
616 | |
617 | - var result cmd.RemoteResponse |
618 | + var result exec.ExecResponse |
619 | err = client.Call(uniter.JujuRunEndpoint, "some-command", &result) |
620 | c.Assert(err, gc.IsNil) |
621 | |
622 | @@ -64,9 +64,9 @@ |
623 | |
624 | var _ uniter.CommandRunner = (*mockRunner)(nil) |
625 | |
626 | -func (r *mockRunner) RunCommands(commands string) (results *cmd.RemoteResponse, err error) { |
627 | +func (r *mockRunner) RunCommands(commands string) (results *exec.ExecResponse, err error) { |
628 | r.c.Log("mock runner: " + commands) |
629 | - return &cmd.RemoteResponse{ |
630 | + return &exec.ExecResponse{ |
631 | Code: 42, |
632 | Stdout: []byte(commands + " stdout"), |
633 | Stderr: []byte(commands + " stderr"), |
634 | |
635 | === modified file 'worker/uniter/uniter.go' |
636 | --- worker/uniter/uniter.go 2014-01-03 15:34:52 +0000 |
637 | +++ worker/uniter/uniter.go 2014-01-14 21:31:32 +0000 |
638 | @@ -23,6 +23,7 @@ |
639 | "launchpad.net/juju-core/state/api/uniter" |
640 | "launchpad.net/juju-core/state/watcher" |
641 | "launchpad.net/juju-core/utils" |
642 | + "launchpad.net/juju-core/utils/exec" |
643 | "launchpad.net/juju-core/utils/fslock" |
644 | "launchpad.net/juju-core/worker/uniter/charm" |
645 | "launchpad.net/juju-core/worker/uniter/hook" |
646 | @@ -365,7 +366,7 @@ |
647 | } |
648 | |
649 | // RunCommands executes the supplied commands in a hook context. |
650 | -func (u *Uniter) RunCommands(commands string) (results *cmd.RemoteResponse, err error) { |
651 | +func (u *Uniter) RunCommands(commands string) (results *exec.ExecResponse, err error) { |
652 | logger.Tracef("run commands: %s", commands) |
653 | hctxId := fmt.Sprintf("%s:run-commands:%d", u.unit.Name(), u.rand.Int63()) |
654 | lockMessage := fmt.Sprintf("%s: running commands", u.unit.Name()) |
655 | |
656 | === modified file 'worker/uniter/uniter_test.go' |
657 | --- worker/uniter/uniter_test.go 2014-01-14 14:36:31 +0000 |
658 | +++ worker/uniter/uniter_test.go 2014-01-14 21:31:32 +0000 |
659 | @@ -25,7 +25,6 @@ |
660 | |
661 | "launchpad.net/juju-core/agent/tools" |
662 | "launchpad.net/juju-core/charm" |
663 | - "launchpad.net/juju-core/cmd" |
664 | "launchpad.net/juju-core/errors" |
665 | "launchpad.net/juju-core/juju/testing" |
666 | "launchpad.net/juju-core/state" |
667 | @@ -35,6 +34,7 @@ |
668 | coretesting "launchpad.net/juju-core/testing" |
669 | jc "launchpad.net/juju-core/testing/checkers" |
670 | "launchpad.net/juju-core/utils" |
671 | + utilexec "launchpad.net/juju-core/utils/exec" |
672 | "launchpad.net/juju-core/utils/fslock" |
673 | "launchpad.net/juju-core/worker" |
674 | "launchpad.net/juju-core/worker/uniter" |
675 | @@ -1963,7 +1963,7 @@ |
676 | c.Assert(err, gc.IsNil) |
677 | defer client.Close() |
678 | |
679 | - var result cmd.RemoteResponse |
680 | + var result utilexec.ExecResponse |
681 | err = client.Call(uniter.JujuRunEndpoint, commands, &result) |
682 | c.Assert(err, gc.IsNil) |
683 | c.Check(result.Code, gc.Equals, 0) |
Reviewers: mp+201680_ code.launchpad. net,
Message:
Please take a look.
Description:
Refactor RunCommands function into a util package
As part of this work, the return structure has been
moved into the utils/exec package along with the
RunCommands function.
I didn't really like the return structure being in
the cmd package, but I didn't see a better place at
the time of making it.
The biggest part of this restructing is the renaming
of the call sites. A benefit is reduced package
dependencies by the users.
https:/ /code.launchpad .net/~thumper/ juju-core/ run-cmd- refactor/ +merge/ 201680
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/52300043/
Affected files (+237, -91 lines): run_test. go run_test. go params/ internal. go /client/ run.go /client/ run_test. go exec_test. go package_ test.go uniter/ context. go uniter/ jujuc/server. go uniter/ jujuc/server_ test.go uniter/ runlistener. go uniter/ runlistener_ test.go uniter/ uniter. go uniter/ uniter_ test.go
A [revision details]
M cmd/juju/
M cmd/jujud/main.go
M cmd/jujud/run.go
M cmd/jujud/
D cmd/remote.go
M state/api/
M state/apiserver
M state/apiserver
A utils/exec/exec.go
A utils/exec/
A utils/exec/
M utils/ssh/run.go
M worker/
M worker/
M worker/
M worker/
M worker/
M worker/
M worker/