// RunCommands exists to satisfy the Runner interface. func (runner *runner) RunCommands(commands string) (*utilexec.ExecResponse, error) { srv, err := runner.startJujucServer() if err != nil { return nil, err } defer srv.Close() env, err := runner.context.HookVars(runner.paths) if err != nil { return nil, errors.Trace(err) } command := utilexec.RunParams{ Commands: commands, WorkingDir: runner.paths.GetCharmDir(), Environment: env, } err = command.Run() if err != nil { return nil, err } runner.context.SetProcess(command.Process()) // Block and wait for process to finish result, err := command.Wait() return result, runner.context.Flush("run commands", err) }
func (s *execSuite) TestKillAbortedIfUnsuccessfull(c *gc.C) { killCalled := false mockChan := make(chan time.Time, 1) defer close(mockChan) params := exec.RunParams{ Commands: "sleep 100", WorkingDir: "", Environment: []string{}, Clock: &mockClock{C: mockChan}, KillProcess: func(*os.Process) error { killCalled = true return nil }, } err := params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) cancelChan := make(chan struct{}, 1) defer close(cancelChan) cancelChan <- struct{}{} mockChan <- time.Now() res, err := params.WaitWithCancel(cancelChan) c.Assert(err, gc.ErrorMatches, fmt.Sprintf("tried to kill process %d, but timed out", params.Process().Pid)) c.Assert(res, gc.IsNil) c.Assert(killCalled, jc.IsTrue) }
func (s *InterfaceSuite) startProcess(c *gc.C) *os.Process { command := exec.RunParams{ Commands: "trap 'exit 0' SIGTERM; while true;do sleep 1;done", } err := command.Run() c.Assert(err, jc.ErrorIsNil) p := command.Process() s.AddCleanup(func(c *gc.C) { p.Kill() }) return p }
func (*execSuite) TestWaitWithCancel(c *gc.C) { params := exec.RunParams{ Commands: "sleep 100", Clock: &mockClock{C: make(chan time.Time)}, } err := params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) cancelChan := make(chan struct{}, 1) defer close(cancelChan) cancelChan <- struct{}{} result, err := params.WaitWithCancel(cancelChan) c.Assert(err, gc.Equals, exec.ErrCancelled) c.Assert(string(result.Stdout), gc.Equals, "") c.Assert(string(result.Stderr), gc.Equals, "") c.Assert(result.Code, gc.Equals, cancelErrCode) }
// runScript executes the given lines in bash func (c *Client) runScript(lines ...string) error { p := exec.RunParams{ Commands: strings.Join(lines, "\n"), } os.MkdirAll(c.SccDir, 0755) p.WorkingDir = c.SccDir if err := p.Run(); err != nil { return err } if r, err := p.Wait(); err != nil { return err } else { os.Stderr.Write(r.Stderr) os.Stdout.Write(r.Stdout) if r.Code != 0 { return errors.New("Script failed") } return nil } }
// runCommandsWithTimeout is a helper to abstract common code between run commands and // juju-run as an action func (runner *runner) runCommandsWithTimeout(commands string, timeout time.Duration, clock clock.Clock) (*utilexec.ExecResponse, error) { srv, err := runner.startJujucServer() if err != nil { return nil, err } defer srv.Close() env, err := runner.context.HookVars(runner.paths) if err != nil { return nil, errors.Trace(err) } command := utilexec.RunParams{ Commands: commands, WorkingDir: runner.paths.GetCharmDir(), Environment: env, Clock: clock, } err = command.Run() if err != nil { return nil, err } runner.context.SetProcess(hookProcess{command.Process()}) var cancel chan struct{} if timeout != 0 { cancel = make(chan struct{}) go func() { <-clock.After(timeout) close(cancel) }() } // Block and wait for process to finish return command.WaitWithCancel(cancel) }
func (*execSuite) TestRunCommands(c *gc.C) { newDir, err := longPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) for i, test := range []struct { message string commands string workingDir string environment []string stdout string stderr string code int }{ { message: "test stdout capture", commands: "echo 'testing stdout'", stdout: "testing stdout\r\n", }, { message: "test stderr capture", commands: "Write-Error 'testing stderr'", stderr: "testing stderr\r\n", }, { message: "test return code", commands: "exit 42", code: 42, }, { message: "test working dir", commands: "(pwd).Path", workingDir: newDir, stdout: filepath.FromSlash(newDir) + "\r\n", }, { message: "test environment", commands: "echo $env:OMG_IT_WORKS", environment: []string{"OMG_IT_WORKS=like magic"}, stdout: "like magic\r\n", }, } { c.Logf("%v: %s", i, test.message) params := exec.RunParams{ Commands: test.commands, WorkingDir: test.workingDir, Environment: test.environment, } result, err := exec.RunCommands(params) c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), jc.Contains, test.stderr) c.Assert(result.Code, gc.Equals, test.code) err = params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) result, err = params.Wait() c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), jc.Contains, test.stderr) c.Assert(result.Code, gc.Equals, test.code) } }
func (*execSuite) TestRunCommands(c *gc.C) { newDir := c.MkDir() for i, test := range []struct { message string commands string workingDir string environment []string stdout string stderr string code int }{ { message: "test stdout capture", commands: "echo testing stdout", stdout: "testing stdout\n", }, { message: "test stderr capture", commands: "echo testing stderr >&2", stderr: "testing stderr\n", }, { message: "test return code", commands: "exit 42", code: 42, }, { message: "test working dir", commands: "pwd", workingDir: newDir, stdout: newDir + "\n", }, { message: "test environment", commands: "echo $OMG_IT_WORKS", environment: []string{"OMG_IT_WORKS=like magic"}, stdout: "like magic\n", }, { message: "multiple commands", commands: "cat\necho 123", stdout: "123\n", }, } { c.Logf("%v: %s", i, test.message) params := exec.RunParams{ Commands: test.commands, WorkingDir: test.workingDir, Environment: test.environment, } result, err := exec.RunCommands(params) c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), gc.Equals, test.stderr) c.Assert(result.Code, gc.Equals, test.code) err = params.Run() c.Assert(err, gc.IsNil) c.Assert(params.Process(), gc.Not(gc.IsNil)) result, err = params.Wait() c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), gc.Equals, test.stderr) c.Assert(result.Code, gc.Equals, test.code) } }