From 99ab87e1b72c687f8d43219e91e38d0fa35cb020 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 20:27:32 +0000 Subject: [PATCH 01/12] fix: Add reaper to coder agent - The coder agent runs as PID 1 in some of our Docker workspaces. In such cases it is the responsibility of the init process to reap dead processes. Failing to do so can result in an inability to create new processes by running out of PIDs. This PR adds a reaper to our agent that is only spawned if it detects that it is PID1. --- agent/reaper/reaper.go | 68 +++++++++++++++++++++++++++++++++++++ agent/reaper/reaper_test.go | 51 ++++++++++++++++++++++++++++ cli/agent.go | 11 ++++++ go.mod | 5 ++- go.sum | 2 ++ 5 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 agent/reaper/reaper.go create mode 100644 agent/reaper/reaper_test.go diff --git a/agent/reaper/reaper.go b/agent/reaper/reaper.go new file mode 100644 index 0000000000000..78933bed4ddc1 --- /dev/null +++ b/agent/reaper/reaper.go @@ -0,0 +1,68 @@ +package reaper + +import ( + "fmt" + "os" + "syscall" + + "github.com/hashicorp/go-reap" + "golang.org/x/xerrors" +) + +// agentEnvMark is a simple environment variable that we use as a marker +// to indicated that the process is a child as opposed to the reaper. +// Since we are forkexec'ing we need to be able to differentiate between +// the two to avoid fork bombing ourselves. +const agentEnvMark = "CODER_AGENT" + +// IsChild returns true if we're the forked process. +func IsChild() bool { + return os.Getenv(agentEnvMark) != "" +} + +// ForkReap spawns a goroutine that reaps children. In order to avoid +// complications with spawning `exec.Commands` in the same process that +// is reaping, we forkexec a child process. This prevents a race between +// the reaper and an exec.Command waiting for its process to complete. +func ForkReap(pids reap.PidCh) error { + // Check if the process is the parent or the child. + // If it's the child we want to skip attempting to reap. + if !IsChild() { + go reap.ReapChildren(pids, nil, nil, nil) + + args := os.Args + // This is simply done to help identify the real agent process + // when viewing in something like 'ps'. + args = append(args, "#Agent") + + pwd, err := os.Getwd() + if err != nil { + return xerrors.Errorf("get wd: %w", err) + } + + pattrs := &syscall.ProcAttr{ + Dir: pwd, + // Add our marker for identifying the child process. + Env: append(os.Environ(), fmt.Sprintf("%s=true", agentEnvMark)), + Sys: &syscall.SysProcAttr{ + Setsid: true, + }, + Files: []uintptr{ + uintptr(syscall.Stdin), + uintptr(syscall.Stdout), + uintptr(syscall.Stderr), + }, + } + + pid, _ := syscall.ForkExec(args[0], args, pattrs) + + var wstatus syscall.WaitStatus + _, err = syscall.Wait4(pid, &wstatus, 0, nil) + for xerrors.Is(err, syscall.EINTR) { + _, err = syscall.Wait4(pid, &wstatus, 0, nil) + } + return nil + } + + return nil +} diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go new file mode 100644 index 0000000000000..0805d9152246a --- /dev/null +++ b/agent/reaper/reaper_test.go @@ -0,0 +1,51 @@ +package reaper_test + +import ( + "os/exec" + "testing" + "time" + + "github.com/hashicorp/go-reap" + "github.com/stretchr/testify/require" + + "github.com/coder/coder/agent/reaper" +) + +func TestReap(t *testing.T) { + t.Parallel() + + // Because we're forkexecing these tests will try to run twice... + if reaper.IsChild() { + t.Skip("I'm a child!") + } + + t.Run("OK", func(t *testing.T) { + pids := make(reap.PidCh, 1) + err := reaper.ForkReap(pids) + require.NoError(t, err) + + cmd := exec.Command("sleep", "5") + err = cmd.Start() + require.NoError(t, err) + + cmd2 := exec.Command("sleep", "5") + err = cmd2.Start() + require.NoError(t, err) + + err = cmd.Process.Kill() + require.NoError(t, err) + + err = cmd2.Process.Kill() + require.NoError(t, err) + + expectedPIDs := []int{cmd.Process.Pid, cmd2.Process.Pid} + + deadline := time.NewTimer(time.Second * 5) + select { + case <-deadline.C: + t.Fatalf("Timed out waiting for process") + case pid := <-pids: + require.Contains(t, expectedPIDs, pid) + } + }) +} diff --git a/cli/agent.go b/cli/agent.go index 287f18f7fbefa..b5827883c39a6 100644 --- a/cli/agent.go +++ b/cli/agent.go @@ -17,6 +17,7 @@ import ( "cdr.dev/slog/sloggers/sloghuman" "github.com/coder/coder/agent" + "github.com/coder/coder/agent/reaper" "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/codersdk" "github.com/coder/retry" @@ -35,6 +36,16 @@ func workspaceAgent() *cobra.Command { // This command isn't useful to manually execute. Hidden: true, RunE: func(cmd *cobra.Command, args []string) error { + // Spawn a reaper so that we don't accumulate a ton + // of zombie processes. + if !reaper.IsChild() { + err := reaper.ForkReap(nil) + if err != nil { + return xerrors.Errorf("fork reap: %w", err) + } + return nil + } + rawURL, err := cmd.Flags().GetString(varAgentURL) if err != nil { return xerrors.Errorf("CODER_AGENT_URL must be set: %w", err) diff --git a/go.mod b/go.mod index a7029e2df5d73..07137062eae3b 100644 --- a/go.mod +++ b/go.mod @@ -134,7 +134,10 @@ require ( storj.io/drpc v0.0.30 ) -require github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect +require ( + github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect +) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect diff --git a/go.sum b/go.sum index 26d6733bc3776..9cf0052fdcf9a 100644 --- a/go.sum +++ b/go.sum @@ -899,6 +899,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b h1:3GrpnZQBxcMj1gCXQLelfjCT1D5MPGTuGMKHVzSIH6A= +github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b/go.mod h1:qIFzeFcJU3OIFk/7JreWXcUjFmcCaeHTH9KoNyHYVCs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= From 5330e8c59e35a0a4b195bb29cdc5dc62b37a366f Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 21:17:22 +0000 Subject: [PATCH 02/12] add some comments --- agent/reaper/reaper.go | 5 +++++ cli/agent.go | 28 ++++++++++++++++++---------- go.mod | 7 ++----- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/agent/reaper/reaper.go b/agent/reaper/reaper.go index 78933bed4ddc1..9423deed8e2bb 100644 --- a/agent/reaper/reaper.go +++ b/agent/reaper/reaper.go @@ -20,6 +20,11 @@ func IsChild() bool { return os.Getenv(agentEnvMark) != "" } +// IsInitProcess returns true if the current process's PID is 1. +func IsInitProcess() bool { + return os.Getpid() == 1 +} + // ForkReap spawns a goroutine that reaps children. In order to avoid // complications with spawning `exec.Commands` in the same process that // is reaping, we forkexec a child process. This prevents a race between diff --git a/cli/agent.go b/cli/agent.go index b5827883c39a6..4e0e87209846e 100644 --- a/cli/agent.go +++ b/cli/agent.go @@ -7,6 +7,7 @@ import ( "net/url" "os" "path/filepath" + "runtime" "time" "cloud.google.com/go/compute/metadata" @@ -36,16 +37,6 @@ func workspaceAgent() *cobra.Command { // This command isn't useful to manually execute. Hidden: true, RunE: func(cmd *cobra.Command, args []string) error { - // Spawn a reaper so that we don't accumulate a ton - // of zombie processes. - if !reaper.IsChild() { - err := reaper.ForkReap(nil) - if err != nil { - return xerrors.Errorf("fork reap: %w", err) - } - return nil - } - rawURL, err := cmd.Flags().GetString(varAgentURL) if err != nil { return xerrors.Errorf("CODER_AGENT_URL must be set: %w", err) @@ -61,6 +52,23 @@ func workspaceAgent() *cobra.Command { } defer logWriter.Close() logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr()), sloghuman.Sink(logWriter)).Leveled(slog.LevelDebug) + + isLinux := runtime.GOOS == "linux" + + // Spawn a reaper so that we don't accumulate a ton + // of zombie processes. + if reaper.IsInitProcess() && !reaper.IsChild() && isLinux { + logger.Info(cmd.Context(), "spawning reaper process") + err := reaper.ForkReap(nil) + if err != nil { + logger.Error(cmd.Context(), "failed to reap", slog.Error(err)) + return xerrors.Errorf("fork reap: %w", err) + } + + logger.Info(cmd.Context(), "reaper process exiting") + return nil + } + client := codersdk.New(coderURL) if pprofEnabled { diff --git a/go.mod b/go.mod index 07137062eae3b..760acc82d0a39 100644 --- a/go.mod +++ b/go.mod @@ -73,6 +73,7 @@ require ( github.com/golang-migrate/migrate/v4 v4.15.2 github.com/google/go-github/v43 v43.0.1-0.20220414155304-00e42332e405 github.com/google/uuid v1.3.0 + github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b github.com/hashicorp/go-version v1.5.0 github.com/hashicorp/hc-install v0.3.2 github.com/hashicorp/hcl/v2 v2.12.0 @@ -134,11 +135,6 @@ require ( storj.io/drpc v0.0.30 ) -require ( - github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b // indirect - github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect -) - require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect @@ -239,6 +235,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/yashtewari/glob-intersection v0.1.0 // indirect github.com/yuin/goldmark v1.4.12 // indirect github.com/zclconf/go-cty v1.10.0 // indirect From b1cc536fc3e86230bb17ad3769703391e252b253 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 21:19:17 +0000 Subject: [PATCH 03/12] add doc.go --- agent/reaper/doc.go | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 agent/reaper/doc.go diff --git a/agent/reaper/doc.go b/agent/reaper/doc.go new file mode 100644 index 0000000000000..b4a8a42910a4c --- /dev/null +++ b/agent/reaper/doc.go @@ -0,0 +1,4 @@ +// Package reaper contains logic for reaping subprocesses. It is +// specifically used in the agent to avoid the accumulation of +// zombie processes. +package reaper From 1703e6d6c40625f03798387157dd1a50ec7f50ea Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 21:29:28 +0000 Subject: [PATCH 04/12] fix test --- agent/reaper/reaper.go | 4 +++- agent/reaper/reaper_test.go | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/agent/reaper/reaper.go b/agent/reaper/reaper.go index 9423deed8e2bb..88cabc5847adc 100644 --- a/agent/reaper/reaper.go +++ b/agent/reaper/reaper.go @@ -13,7 +13,7 @@ import ( // to indicated that the process is a child as opposed to the reaper. // Since we are forkexec'ing we need to be able to differentiate between // the two to avoid fork bombing ourselves. -const agentEnvMark = "CODER_AGENT" +const agentEnvMark = "CODER_REAPER_AGENT" // IsChild returns true if we're the forked process. func IsChild() bool { @@ -29,6 +29,8 @@ func IsInitProcess() bool { // complications with spawning `exec.Commands` in the same process that // is reaping, we forkexec a child process. This prevents a race between // the reaper and an exec.Command waiting for its process to complete. +// The provided 'pids' channel may be nil if the caller does not care about the +// reaped children PIDs. func ForkReap(pids reap.PidCh) error { // Check if the process is the parent or the child. // If it's the child we want to skip attempting to reap. diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index 0805d9152246a..5a2b53f8f058c 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -1,6 +1,7 @@ package reaper_test import ( + "fmt" "os/exec" "testing" "time" @@ -19,6 +20,9 @@ func TestReap(t *testing.T) { t.Skip("I'm a child!") } + // OK checks that's the reaper is successfully reaping + // exited processes and passing the PIDs through the shared + // channel. t.Run("OK", func(t *testing.T) { pids := make(reap.PidCh, 1) err := reaper.ForkReap(pids) @@ -41,11 +45,14 @@ func TestReap(t *testing.T) { expectedPIDs := []int{cmd.Process.Pid, cmd2.Process.Pid} deadline := time.NewTimer(time.Second * 5) - select { - case <-deadline.C: - t.Fatalf("Timed out waiting for process") - case pid := <-pids: - require.Contains(t, expectedPIDs, pid) + for i := 0; i < len(expectedPIDs); i++ { + select { + case <-deadline.C: + t.Fatalf("Timed out waiting for process") + case pid := <-pids: + fmt.Println("pid: ", pid) + require.Contains(t, expectedPIDs, pid) + } } }) } From 2806ab95b62e1ee8faaac740d022bf5d1c2c6d95 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 21:39:22 +0000 Subject: [PATCH 05/12] try again --- agent/reaper/reaper_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index 5a2b53f8f058c..82be6be04ca03 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -1,7 +1,6 @@ package reaper_test import ( - "fmt" "os/exec" "testing" "time" @@ -28,11 +27,11 @@ func TestReap(t *testing.T) { err := reaper.ForkReap(pids) require.NoError(t, err) - cmd := exec.Command("sleep", "5") + cmd := exec.Command("tail", "-f", "/dev/null") err = cmd.Start() require.NoError(t, err) - cmd2 := exec.Command("sleep", "5") + cmd2 := exec.Command("tail", "-f", "/dev/null") err = cmd2.Start() require.NoError(t, err) @@ -50,7 +49,6 @@ func TestReap(t *testing.T) { case <-deadline.C: t.Fatalf("Timed out waiting for process") case pid := <-pids: - fmt.Println("pid: ", pid) require.Contains(t, expectedPIDs, pid) } } From 8f2fa52908b45ec0f024d676e7ada17fd151b0f2 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 21:47:06 +0000 Subject: [PATCH 06/12] skip non-linux OS --- agent/reaper/reaper_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index 82be6be04ca03..cc0b196931493 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -2,6 +2,7 @@ package reaper_test import ( "os/exec" + "runtime" "testing" "time" @@ -14,6 +15,10 @@ import ( func TestReap(t *testing.T) { t.Parallel() + if runtime.GOOS != "linux" { + t.Skipf("Skipping non-Linux OS %q", runtime.GOOS) + } + // Because we're forkexecing these tests will try to run twice... if reaper.IsChild() { t.Skip("I'm a child!") From 85d0635f469f0d12f5ff2c79cbacdc72f05729d5 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 22:03:13 +0000 Subject: [PATCH 07/12] Improve env marker and code conventions --- agent/reaper/reaper.go | 62 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/agent/reaper/reaper.go b/agent/reaper/reaper.go index 88cabc5847adc..bd491e821dc4b 100644 --- a/agent/reaper/reaper.go +++ b/agent/reaper/reaper.go @@ -13,7 +13,7 @@ import ( // to indicated that the process is a child as opposed to the reaper. // Since we are forkexec'ing we need to be able to differentiate between // the two to avoid fork bombing ourselves. -const agentEnvMark = "CODER_REAPER_AGENT" +const agentEnvMark = "CODER_DO_NOT_REAP" // IsChild returns true if we're the forked process. func IsChild() bool { @@ -34,41 +34,43 @@ func IsInitProcess() bool { func ForkReap(pids reap.PidCh) error { // Check if the process is the parent or the child. // If it's the child we want to skip attempting to reap. - if !IsChild() { - go reap.ReapChildren(pids, nil, nil, nil) + if IsChild() { + return nil + } + + go reap.ReapChildren(pids, nil, nil, nil) - args := os.Args - // This is simply done to help identify the real agent process - // when viewing in something like 'ps'. - args = append(args, "#Agent") + args := os.Args + // This is simply done to help identify the real agent process + // when viewing in something like 'ps'. + args = append(args, "#Agent") - pwd, err := os.Getwd() - if err != nil { - return xerrors.Errorf("get wd: %w", err) - } + pwd, err := os.Getwd() + if err != nil { + return xerrors.Errorf("get wd: %w", err) + } - pattrs := &syscall.ProcAttr{ - Dir: pwd, - // Add our marker for identifying the child process. - Env: append(os.Environ(), fmt.Sprintf("%s=true", agentEnvMark)), - Sys: &syscall.SysProcAttr{ - Setsid: true, - }, - Files: []uintptr{ - uintptr(syscall.Stdin), - uintptr(syscall.Stdout), - uintptr(syscall.Stderr), - }, - } + pattrs := &syscall.ProcAttr{ + Dir: pwd, + // Add our marker for identifying the child process. + Env: append(os.Environ(), fmt.Sprintf("%s=true", agentEnvMark)), + Sys: &syscall.SysProcAttr{ + Setsid: true, + }, + Files: []uintptr{ + uintptr(syscall.Stdin), + uintptr(syscall.Stdout), + uintptr(syscall.Stderr), + }, + } - pid, _ := syscall.ForkExec(args[0], args, pattrs) + //#nosec G204 + pid, _ := syscall.ForkExec(args[0], args, pattrs) - var wstatus syscall.WaitStatus + var wstatus syscall.WaitStatus + _, err = syscall.Wait4(pid, &wstatus, 0, nil) + for xerrors.Is(err, syscall.EINTR) { _, err = syscall.Wait4(pid, &wstatus, 0, nil) - for xerrors.Is(err, syscall.EINTR) { - _, err = syscall.Wait4(pid, &wstatus, 0, nil) - } - return nil } return nil From 41e0165f3f6707a8f979412f8bf8c18d208f4b58 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 22:52:04 +0000 Subject: [PATCH 08/12] make windows-specific stubs --- agent/reaper/reaper_stub.go | 19 +++++++++++++++++++ agent/reaper/reaper_test.go | 7 ++----- agent/reaper/{reaper.go => reaper_unix.go} | 2 ++ 3 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 agent/reaper/reaper_stub.go rename agent/reaper/{reaper.go => reaper_unix.go} (99%) diff --git a/agent/reaper/reaper_stub.go b/agent/reaper/reaper_stub.go new file mode 100644 index 0000000000000..f9c6eab5d4862 --- /dev/null +++ b/agent/reaper/reaper_stub.go @@ -0,0 +1,19 @@ +//go:build windows + +package reaper + +import "github.com/hashicorp/go-reap" + +// IsChild returns true if we're the forked process. +func IsChild() bool { + return false +} + +// IsInitProcess returns true if the current process's PID is 1. +func IsInitProcess() bool { + return false +} + +func ForkReap(pids reap.PidCh) error { + return nil +} diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index cc0b196931493..52e366d388949 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -1,8 +1,9 @@ +//go:build !windows + package reaper_test import ( "os/exec" - "runtime" "testing" "time" @@ -15,10 +16,6 @@ import ( func TestReap(t *testing.T) { t.Parallel() - if runtime.GOOS != "linux" { - t.Skipf("Skipping non-Linux OS %q", runtime.GOOS) - } - // Because we're forkexecing these tests will try to run twice... if reaper.IsChild() { t.Skip("I'm a child!") diff --git a/agent/reaper/reaper.go b/agent/reaper/reaper_unix.go similarity index 99% rename from agent/reaper/reaper.go rename to agent/reaper/reaper_unix.go index bd491e821dc4b..8127e1e7900db 100644 --- a/agent/reaper/reaper.go +++ b/agent/reaper/reaper_unix.go @@ -1,3 +1,5 @@ +//go:build !windows + package reaper import ( From 757257c751f6c7660d08394f4412d28cff4bebaa Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 23:10:26 +0000 Subject: [PATCH 09/12] linux only --- agent/reaper/reaper_test.go | 2 +- agent/reaper/reaper_unix.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index 52e366d388949..250f685cfd654 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build linux package reaper_test diff --git a/agent/reaper/reaper_unix.go b/agent/reaper/reaper_unix.go index 8127e1e7900db..5655b1a188724 100644 --- a/agent/reaper/reaper_unix.go +++ b/agent/reaper/reaper_unix.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build windows package reaper From 282b583fad0a8221bab61c1e1c193f611af5a873 Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 23:19:22 +0000 Subject: [PATCH 10/12] typo --- agent/reaper/reaper_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/reaper/reaper_unix.go b/agent/reaper/reaper_unix.go index 5655b1a188724..8a2a8656857a4 100644 --- a/agent/reaper/reaper_unix.go +++ b/agent/reaper/reaper_unix.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build linux package reaper From fb11dafacc958a494f0968b0efc192d01ec6372a Mon Sep 17 00:00:00 2001 From: sreya Date: Thu, 16 Jun 2022 23:21:51 +0000 Subject: [PATCH 11/12] whoops --- agent/reaper/reaper_stub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/reaper/reaper_stub.go b/agent/reaper/reaper_stub.go index f9c6eab5d4862..9021165c975d8 100644 --- a/agent/reaper/reaper_stub.go +++ b/agent/reaper/reaper_stub.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build !linux package reaper From c66d7be8a424aa60535d12d568ffb86cbb0fe975 Mon Sep 17 00:00:00 2001 From: sreya Date: Fri, 17 Jun 2022 16:28:19 +0000 Subject: [PATCH 12/12] skip reaper tests in CI --- agent/reaper/reaper_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/agent/reaper/reaper_test.go b/agent/reaper/reaper_test.go index 250f685cfd654..8e9ca9143d3e3 100644 --- a/agent/reaper/reaper_test.go +++ b/agent/reaper/reaper_test.go @@ -3,6 +3,7 @@ package reaper_test import ( + "os" "os/exec" "testing" "time" @@ -16,6 +17,13 @@ import ( func TestReap(t *testing.T) { t.Parallel() + // Don't run the reaper test in CI. It does weird + // things like forkexecing which may have unintended + // consequences in CI. + if _, ok := os.LookupEnv("CI"); ok { + t.Skip("Detected CI, skipping reaper tests") + } + // Because we're forkexecing these tests will try to run twice... if reaper.IsChild() { t.Skip("I'm a child!")