in agent/util/process/process.go [152:253]
func (p *ProcessCmd) SyncRun(
workingDir string,
commandName string,
commandArguments []string,
stdoutWriter io.Writer,
stderrWriter io.Writer,
stdinReader io.Reader,
callbackFunc ReadCallbackFunc,
timeOut int) (exitCode int, status int, err error) {
status = Success
exitCode = 0
p.command = executil.Command(commandName, commandArguments...)
p.command.Stdout = stdoutWriter
p.command.Stderr = stderrWriter
p.command.Stdin = stdinReader
p.command.Dir = workingDir
p.command.Env = p.env
if err := p.prepareProcess(); err != nil {
return 0, Fail, err
}
if p.user_name != "" {
if err := p.addCredential(); err != nil {
return 0, Fail, err
}
}
if err = p.command.Start(); err != nil {
log.GetLogger().Errorln("error occurred starting the command", err)
exitCode = 1
return exitCode, Fail, err
}
if p.collection != nil {
if err := p.collection.AddProcess(p.command.Process); err != nil {
log.GetLogger().WithError(err).Error("add process into collection failed")
p.command.Process.Kill()
return 1, Fail, fmt.Errorf("add process into collection failed: %v", err)
} else {
log.GetLogger().Infof("add process %d into collection %s success", p.command.Process.Pid, p.collection.Name())
}
}
finished := make(chan WaitProcessResult, 1)
go func() {
processState, err := p.command.Process.Wait()
finished <- WaitProcessResult{
processState: processState,
err: err,
}
}()
var timeoutChannel <-chan time.Time = nil
if timeOut > 0 {
timer := time.NewTimer(time.Duration(timeOut) * time.Second)
defer timer.Stop()
timeoutChannel = timer.C
}
select {
case waitProcessResult := <-finished:
log.GetLogger().Println("Command completed.", commandName)
if waitProcessResult.processState != nil {
if waitProcessResult.err != nil {
log.GetLogger().WithFields(logrus.Fields{
"processState": waitProcessResult.processState,
}).WithError(waitProcessResult.err).Error("os.Process.Wait() returns error with valid process state")
}
exitCode = waitProcessResult.processState.ExitCode()
// Sleep 200ms to allow remaining data to be copied back
time.Sleep(time.Duration(200) * time.Millisecond)
// Explicitly break select statement in case timer also times out
break
} else {
exitCode = 1
return exitCode, Fail, waitProcessResult.err
}
case <-timeoutChannel:
log.GetLogger().Errorln("Timeout in run command.", commandName)
exitCode = 1
status = Timeout
err = errors.New("timeout")
if p.collection != nil {
if err := p.collection.KillAll(); err != nil {
log.GetLogger().WithError(err).Error("kill all process in collection failed")
}
} else {
p.command.Process.Kill()
}
}
if p.user_name != "" {
p.removeCredential()
}
if p.collection != nil {
p.collection.Dispose()
}
return exitCode, status, err
}