github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/plugin/builtin/shell/subtree_darwin.go (about)

     1  package shell
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/evergreen-ci/evergreen/plugin"
    11  	"github.com/mongodb/grip/slogger"
    12  )
    13  
    14  func trackProcess(key string, pid int, log plugin.Logger) {
    15  	// trackProcess is a noop on OSX, because we detect all the processes to be killed in
    16  	// cleanup() and we don't need to do any special bookkeeping up-front.
    17  }
    18  
    19  func cleanup(key string, log plugin.Logger) error {
    20  	/*
    21  		Usage of ps on OSX for extracting environment variables:
    22  		-E: print the environment of the process (VAR1=FOO VAR2=BAR ...)
    23  		-e: list *all* processes, not just ones that we own
    24  		-o: print output according to the given format. We supply 'pid,command' so that
    25  		only those two columns are printed, and then we extract their values using the regexes.
    26  
    27  		Each line of output has a format with the pid, command, and environment, e.g.:
    28  		1084 foo.sh PATH=/usr/bin/sbin TMPDIR=/tmp LOGNAME=xxx
    29  	*/
    30  
    31  	out, err := exec.Command("ps", "-E", "-e", "-o", "pid,command").CombinedOutput()
    32  	if err != nil {
    33  		log.LogSystem(slogger.ERROR, "cleanup failed to get output of 'ps': %v", err)
    34  		return err
    35  	}
    36  	myPid := fmt.Sprintf("%v", os.Getpid())
    37  
    38  	pidsToKill := []int{}
    39  	lines := strings.Split(string(out), "\n")
    40  
    41  	// Look through the output of the "ps" command and find the processes we need to kill.
    42  	for _, line := range lines {
    43  		if len(line) == 0 {
    44  			continue
    45  		}
    46  		splitLine := strings.Fields(line)
    47  		pid := splitLine[0]
    48  		env := splitLine[2:]
    49  		pidMarker := fmt.Sprintf("EVR_AGENT_PID=%v", os.Getpid())
    50  		taskMarker := fmt.Sprintf("EVR_TASK_ID=%v", key)
    51  
    52  		if pid != myPid && envHasMarkers(env, pidMarker, taskMarker) {
    53  			// add it to the list of processes to clean up
    54  			pidAsInt, err := strconv.Atoi(pid)
    55  			if err != nil {
    56  				log.LogSystem(slogger.ERROR, "Cleaup failed to convert from string to int: %v", err)
    57  				continue
    58  			}
    59  			pidsToKill = append(pidsToKill, pidAsInt)
    60  		}
    61  	}
    62  
    63  	// Iterate through the list of processes to kill that we just built, and actually kill them.
    64  	for _, pid := range pidsToKill {
    65  		p := os.Process{}
    66  		p.Pid = pid
    67  		err := p.Kill()
    68  		if err != nil {
    69  			log.LogSystem(slogger.ERROR, "Cleanup got error killing pid %v: %v", pid, err)
    70  		} else {
    71  			log.LogSystem(slogger.INFO, "Cleanup killed pid %v", pid)
    72  		}
    73  	}
    74  	return nil
    75  
    76  }