From 756373aa5594ae6ead15128763e28cf46a6cac0f Mon Sep 17 00:00:00 2001 From: Josh Powers Date: Mon, 18 Sep 2023 11:45:05 -0600 Subject: [PATCH 1/3] fix(inputs.exec): Clean up grandchildren processes fixes: #13935 --- internal/exec_unix.go | 12 ++++++++++-- plugins/inputs/exec/exec.go | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) 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..7fdb659e11ecf 100644 --- a/plugins/inputs/exec/exec.go +++ b/plugins/inputs/exec/exec.go @@ -13,6 +13,7 @@ import ( "runtime" "strings" "sync" + "syscall" "time" "github.com/kballard/go-shellquote" @@ -72,6 +73,7 @@ func (c CommandRunner) Run( } cmd := osExec.Command(splitCmd[0], splitCmd[1:]...) + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} if len(environments) > 0 { cmd.Env = append(os.Environ(), environments...) From 6e9f62ab6e446a8db0cb9e5982c471cfaf38a998 Mon Sep 17 00:00:00 2001 From: Josh Powers Date: Mon, 18 Sep 2023 12:13:39 -0600 Subject: [PATCH 2/3] Split out windows and non-windows --- plugins/inputs/exec/exec.go | 41 -------------------- plugins/inputs/exec/run_notwinodws.go | 54 +++++++++++++++++++++++++++ plugins/inputs/exec/run_windows.go | 53 ++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 41 deletions(-) create mode 100644 plugins/inputs/exec/run_notwinodws.go create mode 100644 plugins/inputs/exec/run_windows.go diff --git a/plugins/inputs/exec/exec.go b/plugins/inputs/exec/exec.go index 7fdb659e11ecf..17bbfbfd2d4d3 100644 --- a/plugins/inputs/exec/exec.go +++ b/plugins/inputs/exec/exec.go @@ -7,20 +7,14 @@ import ( "errors" "fmt" "io" - "os" - osExec "os/exec" "path/filepath" "runtime" "strings" "sync" - "syscall" "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" @@ -62,41 +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:]...) - 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 -} - 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..ae38e5347ca4e --- /dev/null +++ b/plugins/inputs/exec/run_notwinodws.go @@ -0,0 +1,54 @@ +//go:build !windows + +package exec + +import ( + "bytes" + "fmt" + "os" + osExec "os/exec" + "runtime" + "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:]...) + if runtime.GOOS != "windows" { + 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 +} From 33ed2e86b2b0047b6780ea440a52c848a5a9b540 Mon Sep 17 00:00:00 2001 From: Josh Powers Date: Thu, 21 Sep 2023 08:51:50 -0600 Subject: [PATCH 3/3] remove goos check --- plugins/inputs/exec/run_notwinodws.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/inputs/exec/run_notwinodws.go b/plugins/inputs/exec/run_notwinodws.go index ae38e5347ca4e..cac96dad463cb 100644 --- a/plugins/inputs/exec/run_notwinodws.go +++ b/plugins/inputs/exec/run_notwinodws.go @@ -7,7 +7,6 @@ import ( "fmt" "os" osExec "os/exec" - "runtime" "syscall" "time" @@ -27,9 +26,7 @@ func (c CommandRunner) Run( } cmd := osExec.Command(splitCmd[0], splitCmd[1:]...) - if runtime.GOOS != "windows" { - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - } + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} if len(environments) > 0 { cmd.Env = append(os.Environ(), environments...)