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  }