// must be called at the end of the command, when there is nothing more to // read from stdout and stderr // will send a success or a failure report message through the given chanel func pushEndReport(cmd *exec.Cmd, jobId int64, reportChan chan message.Report) { if err := cmd.Wait(); err != nil { // we have a failure for the command. // we will now try to get the exit code if exiterr, ok := err.(*exec.ExitError); ok { // the error from cmd.Wait is an *exec.ExitError. It means that the // exit status is != 0 /* * here is a interesting comments getting from stackoverflow. I let it * */ // This works on both Unix and Windows. Although package // syscall is generally platform dependent, WaitStatus is // defined for both Unix and Windows and in both cases has // an ExitStatus() method with the same signature. if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { errMesg := fmt.Sprintf("Exit Status: %d", status.ExitStatus()) reportChan <- message.Report{jobId, message.FAILED, []string{errMesg}} } } else { errMesg := fmt.Sprintf("Unknow error : %v", err) reportChan <- message.Report{jobId, message.FAILED, []string{errMesg}} } } else { // the command is in success state. reportChan <- message.Report{jobId, message.SUCCESS, []string{}} } }
func RunAndListen(cmd *exec.Cmd, fn func(s string)) error { var stderr bytes.Buffer cmd.Stderr = &stderr r, err := cmd.StdoutPipe() if err != nil { return fmt.Errorf("%s: %s", err, stderr.String()) } scanner := bufio.NewScanner(r) go func() { for scanner.Scan() { fn(scanner.Text()) } }() err = cmd.Start() if err != nil { return fmt.Errorf("%s: %s", err, stderr.String()) } err = cmd.Wait() if err != nil { return fmt.Errorf("%s: %s", err, stderr.String()) } return nil }
// timedCommand executes the given command, terminating it forcefully // if it is still running after the given timeout elapses. func (e *executor) timedCommand(timeout time.Duration, opts opts, command *exec.Cmd) error { // Make the process of this command a new process group leader // to facilitate clean up of processes that time out. command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} // Kill this process group explicitly when receiving SIGTERM // or SIGINT signals. sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT) go func() { <-sigchan e.terminateProcessGroup(opts, command) }() if err := command.Start(); err != nil { e.printf(e.verboseStdout(opts), "FAILED: %v", err) return err } done := make(chan error, 1) go func() { done <- command.Wait() }() select { case <-time.After(timeout): // The command has timed out. e.terminateProcessGroup(opts, command) // Allow goroutine to exit. <-done e.printf(e.verboseStdout(opts), "TIMED OUT") return commandTimedOutErr case err := <-done: e.printf(e.verboseStdout(opts), okOrFailed(err)) return err } }
func CmdStream(cmd *exec.Cmd) (io.Reader, error) { stdout, err := cmd.StdoutPipe() if err != nil { return nil, err } stderr, err := cmd.StderrPipe() if err != nil { return nil, err } pipeR, pipeW := io.Pipe() go func() { _, err := io.Copy(pipeW, stdout) if err != nil { pipeW.CloseWithError(err) } errText, e := ioutil.ReadAll(stderr) if e != nil { errText = []byte("(...couldn't fetch stderr: " + e.Error() + ")") } if err := cmd.Wait(); err != nil { // FIXME: can this block if stderr outputs more than the size of StderrPipe()'s buffer? pipeW.CloseWithError(errors.New(err.Error() + ": " + string(errText))) } else { pipeW.Close() } }() if err := cmd.Start(); err != nil { return nil, err } return pipeR, nil }
// cmdTimeout runs the command c and returns a timeout if it doesn't complete // after time t. If a timeout occurs, cmdTimeout will kill the process. Blocks // until the process terminates. func cmdTimeout(c *exec.Cmd, t time.Duration) error { log.Debug("cmdTimeout: %v", c) start := time.Now() if err := c.Start(); err != nil { return fmt.Errorf("cmd start: %v", err) } done := make(chan error) go func() { done <- c.Wait() close(done) }() select { case <-time.After(t): log.Debug("killing cmd %v", c) err := c.Process.Kill() // Receive from done so that we don't leave the goroutine hanging err2 := <-done // Kill error takes precedence as they should be unexpected if err != nil { return err } return err2 case err := <-done: log.Debug("cmd %v completed in %v", c, time.Now().Sub(start)) return err } }
func wait(proc *exec.Cmd, ch chan *exec.Cmd) { err := proc.Wait() if err != nil { log.Fatal(err) } ch <- proc }
// Publish prints the result of a check to stdout. func (p *ExecPublisher) Publish(result *CheckResult) error { var cmd *exec.Cmd if len(p.cmd) > 1 { cmd = exec.Command(p.cmd[0], p.cmd[1:]...) } else { cmd = exec.Command(p.cmd[0]) } var b bytes.Buffer cmd.Stdout = &b cmd.Stderr = &b stdin, err := cmd.StdinPipe() if err != nil { return err } if err = cmd.Start(); err != nil { p.log.Error("Exec failed", "error", err) return err } if err = p.stdinTemplate.Execute(stdin, result); err != nil { p.log.Error("Failed to write template data to stdin", "error", err) return err } stdin.Close() if err = cmd.Wait(); err != nil { p.log.Error("Exec failed", "error", err, "output", b.String()) return err } return nil }
func (c Command) Run(s HookState) error { b, err := json.Marshal(s) if err != nil { return err } cmd := exec.Cmd{ Path: c.Path, Args: c.Args, Env: c.Env, Stdin: bytes.NewReader(b), } errC := make(chan error, 1) go func() { out, err := cmd.CombinedOutput() if err != nil { err = fmt.Errorf("%s: %s", err, out) } errC <- err }() if c.Timeout != nil { select { case err := <-errC: return err case <-time.After(*c.Timeout): cmd.Process.Kill() cmd.Wait() return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds()) } } return <-errC }
func callCont(c *exec.Cmd, cont func(io.Reader) error) error { _, callerFile, callerLine, _ := runtime.Caller(1) log.Printf("%15s:%.3d -> %s", path.Base(callerFile), callerLine, strings.Join(c.Args, " ")) var reader io.Reader var err error if cont != nil { reader, err = c.StdoutPipe() if err != nil { return err } } stderr, err := c.StderrPipe() if err != nil { return err } if err = c.Start(); err != nil { return err } if cont != nil { if err = cont(reader); err != nil { return err } } buffer := bytes.NewBuffer(nil) buffer.ReadFrom(stderr) if buffer.Len() != 0 { log.Print("Command had output on stderr.\n Cmd: ", strings.Join(c.Args, " "), "\nstderr: ", buffer) } return c.Wait() }
// runCommand runs the command with the given timeout, and returns any errors encountered and whether // the command timed out or not func runCommand(cmd *exec.Cmd, timeout time.Duration) (error, bool) { out := make(chan error) go func() { if err := cmd.Start(); err != nil { glog.V(4).Infof("Error starting execution: %v", err) } out <- cmd.Wait() }() if timeout == noCommandTimeout { select { case err := <-out: if err != nil { glog.V(4).Infof("Error executing command: %v", err) } return err, false } } else { select { case err := <-out: if err != nil { glog.V(4).Infof("Error executing command: %v", err) } return err, false case <-time.After(timeout): glog.V(4).Infof("Command execution timed out after %s", timeout) return nil, true } } }
// RunCommandWithStdoutStderr execs a command and returns its output. func RunCommandWithStdoutStderr(cmd *exec.Cmd) (bytes.Buffer, bytes.Buffer, error) { var stdout, stderr bytes.Buffer stderrPipe, err := cmd.StderrPipe() stdoutPipe, err := cmd.StdoutPipe() cmd.Env = os.Environ() if err != nil { fmt.Println("error at io pipes") } err = cmd.Start() if err != nil { fmt.Println("error at command start") } go func() { streamOutput(stdoutPipe, &stdout, os.Stdout) }() go func() { streamOutput(stderrPipe, &stderr, os.Stderr) }() err = cmd.Wait() if err != nil { fmt.Println("error at command wait") } return stdout, stderr, err }
// WaitCode gets the exit code for a running command // // Normally returns exit code, nil // // Error Conditions: // WaitCode takes err, so that it can be used on the result of Run{Cmd/Bash}. // All failures to run the process manifest as an exit code of -1, with additional error info func WaitCode(c *exec.Cmd, e error) (int, error) { if c == nil { return -1, e } return getCode(c.Wait()) }
func rsyncWebsocket(cmd *exec.Cmd, conn *websocket.Conn) error { stdin, err := cmd.StdinPipe() if err != nil { return err } stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } if err := cmd.Start(); err != nil { return err } shared.WebsocketMirror(conn, stdin, stdout) data, err2 := ioutil.ReadAll(stderr) if err2 != nil { shared.Debugf("error reading rsync stderr: %s", err2) return err2 } shared.Debugf("Stderr from rsync: %s", data) err = cmd.Wait() if err != nil { shared.Debugf("rsync recv error %s: %s", err, string(data)) } return err }
func TestServerWithBasicAuth(t *testing.T) { cmd := exec.Cmd{ Path: os.Getenv("GOPATH") + "/bin/docker-builder", Args: []string{"docker-builder", "serve", "--username", "foo", "--password", "bar"}, } if err := cmd.Start(); err != nil { t.Errorf("error start server: %s\n", err.Error()) } go func() { time.Sleep(100 * time.Millisecond) syscall.Kill(cmd.Process.Pid, syscall.SIGUSR1) time.Sleep(100 * time.Millisecond) syscall.Kill(cmd.Process.Pid, syscall.SIGTERM) }() if err := cmd.Wait(); err != nil { if exiterr, ok := err.(*exec.ExitError); ok { if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { if status.ExitStatus() != 166 { t.Errorf("server exited unexpectedly and/or did not start correctly") } } else { t.Errorf("unable to get process exit code") } } else { t.Errorf("error waiting on server: %s\n", err.Error()) } } }
func execCommand(cmd *exec.Cmd) error { cmdReader, err := cmd.StdoutPipe() if err != nil { fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err) return err } scanner := bufio.NewScanner(cmdReader) go func() { for scanner.Scan() { fmt.Printf("docker build out | %s\n", scanner.Text()) } }() var stderr bytes.Buffer cmd.Stdout = os.Stdout cmd.Stderr = &stderr err = cmd.Start() if err != nil { fmt.Printf("docker build out | %s\n", stderr.String()) return err } err = cmd.Wait() if err != nil { fmt.Printf("docker build out | %s\n", stderr.String()) return err } return err }
// send produces a binary diff stream and passes it to cont func send(repo, commit string, cont func(io.Reader) error) error { parent := GetMeta(path.Join(repo, commit), "parent") var cmd *exec.Cmd if parent == "" { cmd = exec.Command("btrfs", "send", FilePath(path.Join(repo, commit))) } else { cmd = exec.Command("btrfs", "send", "-p", FilePath(path.Join(repo, parent)), FilePath(path.Join(repo, commit))) } stdin, stdout := io.Pipe() stderr := bytes.NewBuffer(nil) cmd.Stdout = stdout if err := cmd.Start(); err != nil { return err } errC := make(chan error, 1) go func() { errC <- cont(stdin) }() waitErr := cmd.Wait() closeErr := stdout.Close() if waitErr != nil { return fmt.Errorf("%s %s", waitErr.Error(), stderr.String()) } if closeErr != nil { return closeErr } return <-errC }
func (c *EtcdAdapter) ExecWithLog(cmd *exec.Cmd, i int) { stdoutPipe, err := cmd.StdoutPipe() check(err) stderrPipe, err := cmd.StderrPipe() check(err) outFile, err := os.Create(fmt.Sprintf("/tmp/etcd_%d.out", i)) check(err) errFile, err := os.Create(fmt.Sprintf("/tmp/etcd_%d.err", i)) check(err) outWriter := bufio.NewWriter(outFile) errWriter := bufio.NewWriter(errFile) defer outWriter.Flush() defer errWriter.Flush() // Start the command err = cmd.Start() check(err) go io.Copy(outWriter, stdoutPipe) go io.Copy(errWriter, stderrPipe) c.launchProcess <- cmd.Process cmd.Wait() }
func (this *Start) reloadHAproxy() (err error) { var cmd *exec.Cmd = nil waitStartCh := make(chan struct{}) if this.starting { log.Info("haproxy starting") cmd = exec.Command(this.command, "-f", configFile) // TODO use absolute path this.starting = false go func() { <-waitStartCh log.Info("haproxy started") if err := cmd.Wait(); err != nil { log.Error("haproxy: %v", err) } }() } else { shellScript := fmt.Sprintf("%s -f %s/%s -sf `cat %s/%s`", this.command, this.root, configFile, this.root, haproxyPidFile) log.Info("haproxy reloading: %s", shellScript) cmd = exec.Command("/bin/sh", "-c", shellScript) go func() { <-waitStartCh log.Info("haproxy reloaded") if err := cmd.Wait(); err != nil { log.Error("haproxy: %v", err) } }() } if err = cmd.Start(); err == nil { waitStartCh <- struct{}{} } return err }
// Run() an instance of this container and return it's exec.Command reference and a // channel that sends the exit code, when the container exits func (c *Container) run() (*exec.Cmd, chan error) { // the container name is semi random because containers can get wedged // in docker and can not be removed until a reboot (or aufs trickery) containerName := c.Name + "-" + uuid() exitChan := make(chan error, 1) args := make([]string, 0) args = append(args, "run", "-rm", "-name", containerName) // attach all exported ports for _, port := range c.Ports { args = append(args, "-p", fmt.Sprintf("%d:%d", port, port)) } // attach resources directory to all containers args = append(args, "-v", resourcesDir()+":"+"/usr/local/serviced/resources") // attach all exported volumes for name, volume := range c.Volumes { hostDir := path.Join(c.VolumesDir(), c.Name, name) if exists, _ := isDir(hostDir); !exists { if err := os.MkdirAll(hostDir, 0777); err != nil { glog.Errorf("could not create %s on host: %s", hostDir, err) exitChan <- err return nil, exitChan } } args = append(args, "-v", hostDir+":"+volume) } // set the image and command to run args = append(args, c.Repo+":"+c.Tag, "/bin/sh", "-c", c.Command) glog.V(1).Infof("Executing docker %s", args) var cmd *exec.Cmd tries := 5 var err error for { if tries > 0 { cmd = exec.Command("docker", args...) if err := cmd.Start(); err != nil { glog.Errorf("Could not start: %s", c.Name) c.stop() c.rm() time.Sleep(time.Second * 1) } else { break } } else { exitChan <- err return cmd, exitChan } tries = -1 } go func() { exitChan <- cmd.Wait() }() return cmd, exitChan }
func writeGitRepositoryArchive(w io.Writer, path string, ref GitCommitRef) error { var cmd *exec.Cmd // TODO: Stream as tar with gzip if ref == EmptyGitCommitRef { cmd = exec.Command("/usr/bin/git", "archive", "--format", "zip", "master") } else { cmd = exec.Command("/usr/bin/git", "archive", "--format", "zip", string(ref)) } cmd.Env = []string{} cmd.Dir = path var stderr bytes.Buffer cmd.Stderr = utils.LimitWriter(&stderr, 20*1024) stdout, err := cmd.StdoutPipe() if err != nil { return err } if err := cmd.Start(); err != nil { return err } io.Copy(w, stdout) if err := cmd.Wait(); err != nil { return errors.New(fmt.Sprintf("Failed to archive repository: %s\n", err.Error()) + stderr.String()) } return nil }
// "run" let's the user execute arbitrary commands func runFn(args []interface{}) (interface{}, error) { if len(args) < 1 { return nil, errors.New("run takes at least one argument") } commands := []string{} for _, arg := range args { if s, ok := arg.(string); ok { commands = append(commands, s) } else { return nil, errors.New("run only takes string arguments") } } var cmd *exec.Cmd if len(commands) == 1 { cmd = exec.Command(commands[0]) } else { cmd = exec.Command(commands[0], commands[1:]...) } log.Printf("executing command '%s' with arguments: %s\n", commands[0], strings.Join(commands[1:], ",")) if err := cmd.Run(); err == nil { cmd.Wait() } return nil, nil }
// cmdStream executes a command, and returns its stdout as a stream. // If the command fails to run or doesn't complete successfully, an error // will be returned, including anything written on stderr. func cmdStream(cmd *exec.Cmd, input io.Reader) (io.ReadCloser, <-chan struct{}, error) { chdone := make(chan struct{}) cmd.Stdin = input pipeR, pipeW := io.Pipe() cmd.Stdout = pipeW var errBuf bytes.Buffer cmd.Stderr = &errBuf // Run the command and return the pipe if err := cmd.Start(); err != nil { return nil, nil, err } // Copy stdout to the returned pipe go func() { if err := cmd.Wait(); err != nil { pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String())) } else { pipeW.Close() } close(chdone) }() return pipeR, chdone, nil }
// RunCommandWithStdoutStderr execs a command and returns its output. func RunCommandWithStdoutStderr(cmd *exec.Cmd) (bytes.Buffer, bytes.Buffer, error) { var stdout, stderr bytes.Buffer stderrPipe, err := cmd.StderrPipe() stdoutPipe, err := cmd.StdoutPipe() cmd.Env = os.Environ() if err != nil { fmt.Println("error at io pipes") } err = cmd.Start() if err != nil { fmt.Println("error at command start") } go func() { io.Copy(&stdout, stdoutPipe) fmt.Println(stdout.String()) }() go func() { io.Copy(&stderr, stderrPipe) fmt.Println(stderr.String()) }() time.Sleep(2000 * time.Millisecond) err = cmd.Wait() if err != nil { fmt.Println("error at command wait") } return stdout, stderr, err }
func waitSimple(command *Command, cmd *osexec.Cmd) error { err := cmd.Wait() if err != nil { glog.Errorf("Command exited with %s: %s", err, DebugString(command)) } return err }
func runTest(test test) (passed bool, err error) { prog := path.Join(*buildDir, test[0]) args := test[1:] var cmd *exec.Cmd if *useValgrind { cmd = valgrindOf(false, prog, args...) } else { cmd = exec.Command(prog, args...) } var stdoutBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { return false, err } if err := cmd.Wait(); err != nil { return false, err } // Account for Windows line-endings. stdout := bytes.Replace(stdoutBuf.Bytes(), []byte("\r\n"), []byte("\n"), -1) if bytes.HasSuffix(stdout, []byte("PASS\n")) && (len(stdout) == 5 || stdout[len(stdout)-6] == '\n') { return true, nil } return false, nil }
// runInContext runs a command in the context of a Vagrantfile (from the same dir) func runInContext(cmd *exec.Cmd) error { // run the command from ~/.nanobox/apps/<config.App>. Running the command from // the directory that contains the Vagratfile ensure that the command can // atleast run (especially in cases like 'create' where a VM hadn't been created // yet, and a UUID isn't available) setContext(config.AppDir) // handleCMDout(cmd) // start the command; we need this to 'fire and forget' so that we can manually // capture and modify the commands output above if err := cmd.Start(); err != nil { return err } // wait for the command to complete/fail and exit, giving us a chance to scan // the output if err := cmd.Wait(); err != nil { return err } // switch back to project dir setContext(config.CWDir) return nil }
func (w *Worker) CmdRunWithTimeout(cmd *exec.Cmd, timeout time.Duration) (error, bool) { done := make(chan error) go func() { done <- cmd.Wait() }() var err error select { case <-time.After(timeout): // timeout if err = cmd.Process.Kill(); err != nil { golog.Error("worker", "CmdRunTimeout", "kill error", 0, "path", cmd.Path, "error", err.Error(), ) } golog.Info("worker", "CmdRunWithTimeout", "kill process", 0, "path", cmd.Path, "error", errors.ErrExecTimeout.Error(), ) go func() { <-done // allow goroutine to exit }() return errors.ErrExecTimeout, true case err = <-done: return err, false } }
func (run execCmdRunner) runCmd(cmd *exec.Cmd) (stdout, stderr string, err error) { cmdString := strings.Join(cmd.Args, " ") run.logger.Debug("Cmd Runner", "Running command: %s", cmdString) stdoutWriter := bytes.NewBufferString("") stderrWriter := bytes.NewBufferString("") cmd.Stdout = stdoutWriter cmd.Stderr = stderrWriter err = cmd.Start() if err != nil { err = bosherr.WrapError(err, "Starting command %s", cmdString) return } err = cmd.Wait() stdout = string(stdoutWriter.Bytes()) stderr = string(stderrWriter.Bytes()) run.logger.Debug("Cmd Runner", "Stdout: %s", stdout) run.logger.Debug("Cmd Runner", "Stderr: %s", stderr) run.logger.Debug("Cmd Runner", "Successful: %t", err == nil) if err != nil { err = bosherr.WrapError(err, "Running command: '%s', stdout: '%s', stderr: '%s'", cmdString, stdout, stderr) } return }
func execCommand(cmd *exec.Cmd, prefix string, name string) (bool, *string, *string) { out, err := cmd.StdoutPipe() outE, errE := cmd.StderrPipe() if err != nil { log.Warnf("[command] %s err: %s", prefix, out) log.Warnf("[command] %s err: %s", prefix, err) return false, nil, nil } if errE != nil { log.Warnf("[command] %s err: %s", prefix, outE) log.Warnf("[command] %s err: %s", prefix, errE) return false, nil, nil } err = cmd.Start() if err != nil { log.Warnf("[command] %s err: %s", prefix, err) return false, nil, nil } outResult := copyStream(out, prefix, name) errResult := copyStream(outE, prefix, name) err = cmd.Wait() if err != nil { log.Warnf("[command] %s err: %s", prefix, err) return false, &outResult, &errResult } return true, &outResult, &errResult }
// Run runs the command and returns a channel of output lines, errors and result of cmd.Wait func Run(cmd *exec.Cmd, lines chan string) (error, error) { stdout, err := cmd.StdoutPipe() if err != nil { return nil, err } stderr, err := cmd.StderrPipe() if err != nil { return nil, err } err = cmd.Start() if err != nil { return nil, err } var wg sync.WaitGroup errCh := make(chan error, 2) wg.Add(2) go tailReader(bufio.NewReader(stdout), lines, errCh, &wg) go tailReader(bufio.NewReader(stderr), lines, errCh, &wg) wg.Wait() select { case err := <-errCh: return nil, err default: } return cmd.Wait(), nil }