github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/command/remote_command.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "io" 6 "os/exec" 7 "strings" 8 9 "github.com/mongodb/grip" 10 "github.com/pkg/errors" 11 ) 12 13 type RemoteCommand struct { 14 Id string 15 CmdString string 16 17 Stdout io.Writer 18 Stderr io.Writer 19 20 // info necessary for sshing into the remote host 21 RemoteHostName string 22 User string 23 Options []string 24 Background bool 25 26 // optional flag for hiding sensitive commands from log output 27 LoggingDisabled bool 28 29 // set after the command is started 30 Cmd *exec.Cmd 31 } 32 33 func (rc *RemoteCommand) Run() error { 34 grip.Debugf("RemoteCommand(%s) beginning Run()", rc.Id) 35 err := rc.Start() 36 if err != nil { 37 return err 38 } 39 if rc.Cmd != nil && rc.Cmd.Process != nil { 40 grip.Debugf("RemoteCommand(%s) started process %d", rc.Id, rc.Cmd.Process.Pid) 41 } else { 42 grip.Debugf("RemoteCommand(%s) has nil Cmd or Cmd.Process in Run()", rc.Id) 43 } 44 return rc.Cmd.Wait() 45 } 46 47 func (rc *RemoteCommand) Wait() error { 48 return rc.Cmd.Wait() 49 } 50 51 func (rc *RemoteCommand) Start() error { 52 53 // build the remote connection, in user@host format 54 remote := rc.RemoteHostName 55 if rc.User != "" { 56 remote = fmt.Sprintf("%v@%v", rc.User, remote) 57 } 58 59 // build the command 60 cmdArray := append(rc.Options, remote) 61 62 // set to the background, if necessary 63 cmdString := rc.CmdString 64 if rc.Background { 65 cmdString = fmt.Sprintf("nohup %v > /tmp/start 2>&1 &", cmdString) 66 } 67 cmdArray = append(cmdArray, cmdString) 68 69 grip.InfoWhenf(!rc.LoggingDisabled, "Remote command executing: '%s'", 70 strings.Join(cmdArray, " ")) 71 72 // set up execution 73 cmd := exec.Command("ssh", cmdArray...) 74 cmd.Stdout = rc.Stdout 75 cmd.Stderr = rc.Stderr 76 77 // cache the command running 78 rc.Cmd = cmd 79 return cmd.Start() 80 } 81 82 func (rc *RemoteCommand) Stop() error { 83 if rc.Cmd != nil && rc.Cmd.Process != nil { 84 grip.Debugf("RemoteCommand(%s) killing process %d", rc.Id, rc.Cmd.Process.Pid) 85 err := rc.Cmd.Process.Kill() 86 if strings.Contains(err.Error(), "process already finished") { 87 return nil 88 } 89 return errors.WithStack(err) 90 } 91 grip.Warningf("RemoteCommand(%s) Trying to stop command but Cmd / Process was nil", rc.Id) 92 return nil 93 }