diff --git a/internal/exec_unix.go b/internal/exec_unix.go index 4d1b03d7fca17..9a012f72629ee 100644 --- a/internal/exec_unix.go +++ b/internal/exec_unix.go @@ -19,14 +19,22 @@ const KillGrace = 5 * time.Second func WaitTimeout(c *exec.Cmd, timeout time.Duration) error { var kill *time.Timer term := time.AfterFunc(timeout, func() { - err := c.Process.Signal(syscall.SIGTERM) + err := syscall.Kill(-c.Process.Pid, syscall.SIGTERM) + if err != nil { + log.Printf("E! [agent] Error terminating process children: %s", err) + } + err = c.Process.Signal(syscall.SIGTERM) if err != nil { log.Printf("E! [agent] Error terminating process: %s", err) return } kill = time.AfterFunc(KillGrace, func() { - err := c.Process.Kill() + err := syscall.Kill(-c.Process.Pid, syscall.SIGKILL) + if err != nil { + log.Printf("E! [agent] Error terminating process children: %s", err) + } + err = c.Process.Kill() if err != nil { log.Printf("E! [agent] Error killing process: %s", err) return diff --git a/plugins/inputs/exec/exec.go b/plugins/inputs/exec/exec.go index 18e6724e6dd7e..17bbfbfd2d4d3 100644 --- a/plugins/inputs/exec/exec.go +++ b/plugins/inputs/exec/exec.go @@ -7,19 +7,14 @@ import ( "errors" "fmt" "io" - "os" - osExec "os/exec" "path/filepath" "runtime" "strings" "sync" "time" - "github.com/kballard/go-shellquote" - "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/config" - "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/models" "github.com/influxdata/telegraf/plugins/inputs" "github.com/influxdata/telegraf/plugins/parsers/nagios" @@ -61,40 +56,6 @@ type Runner interface { type CommandRunner struct{} -func (c CommandRunner) Run( - command string, - environments []string, - timeout time.Duration, -) ([]byte, []byte, error) { - splitCmd, err := shellquote.Split(command) - if err != nil || len(splitCmd) == 0 { - return nil, nil, fmt.Errorf("exec: unable to parse command: %w", err) - } - - cmd := osExec.Command(splitCmd[0], splitCmd[1:]...) - - if len(environments) > 0 { - cmd.Env = append(os.Environ(), environments...) - } - - var ( - out bytes.Buffer - stderr bytes.Buffer - ) - cmd.Stdout = &out - cmd.Stderr = &stderr - - runErr := internal.RunTimeout(cmd, timeout) - - out = removeWindowsCarriageReturns(out) - if stderr.Len() > 0 && !telegraf.Debug { - stderr = removeWindowsCarriageReturns(stderr) - stderr = c.truncate(stderr) - } - - return out.Bytes(), stderr.Bytes(), runErr -} - func (c CommandRunner) truncate(buf bytes.Buffer) bytes.Buffer { // Limit the number of bytes. didTruncate := false diff --git a/plugins/inputs/exec/run_notwinodws.go b/plugins/inputs/exec/run_notwinodws.go new file mode 100644 index 0000000000000..cac96dad463cb --- /dev/null +++ b/plugins/inputs/exec/run_notwinodws.go @@ -0,0 +1,51 @@ +//go:build !windows + +package exec + +import ( + "bytes" + "fmt" + "os" + osExec "os/exec" + "syscall" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" + "github.com/kballard/go-shellquote" +) + +func (c CommandRunner) Run( + command string, + environments []string, + timeout time.Duration, +) ([]byte, []byte, error) { + splitCmd, err := shellquote.Split(command) + if err != nil || len(splitCmd) == 0 { + return nil, nil, fmt.Errorf("exec: unable to parse command: %w", err) + } + + cmd := osExec.Command(splitCmd[0], splitCmd[1:]...) + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + + if len(environments) > 0 { + cmd.Env = append(os.Environ(), environments...) + } + + var ( + out bytes.Buffer + stderr bytes.Buffer + ) + cmd.Stdout = &out + cmd.Stderr = &stderr + + runErr := internal.RunTimeout(cmd, timeout) + + out = removeWindowsCarriageReturns(out) + if stderr.Len() > 0 && !telegraf.Debug { + stderr = removeWindowsCarriageReturns(stderr) + stderr = c.truncate(stderr) + } + + return out.Bytes(), stderr.Bytes(), runErr +} diff --git a/plugins/inputs/exec/run_windows.go b/plugins/inputs/exec/run_windows.go new file mode 100644 index 0000000000000..8a69b8ccdca2a --- /dev/null +++ b/plugins/inputs/exec/run_windows.go @@ -0,0 +1,53 @@ +//go:build windows + +package exec + +import ( + "bytes" + "fmt" + "os" + osExec "os/exec" + "syscall" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" + "github.com/kballard/go-shellquote" +) + +func (c CommandRunner) Run( + command string, + environments []string, + timeout time.Duration, +) ([]byte, []byte, error) { + splitCmd, err := shellquote.Split(command) + if err != nil || len(splitCmd) == 0 { + return nil, nil, fmt.Errorf("exec: unable to parse command: %w", err) + } + + cmd := osExec.Command(splitCmd[0], splitCmd[1:]...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP, + } + + if len(environments) > 0 { + cmd.Env = append(os.Environ(), environments...) + } + + var ( + out bytes.Buffer + stderr bytes.Buffer + ) + cmd.Stdout = &out + cmd.Stderr = &stderr + + runErr := internal.RunTimeout(cmd, timeout) + + out = removeWindowsCarriageReturns(out) + if stderr.Len() > 0 && !telegraf.Debug { + stderr = removeWindowsCarriageReturns(stderr) + stderr = c.truncate(stderr) + } + + return out.Bytes(), stderr.Bytes(), runErr +}