From 055fdb235f40aad28932516e3cb6829a27a97183 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 1 Sep 2023 12:19:54 -0700 Subject: [PATCH] cmd/tailscaled, tstest/integration: make tailscaled die when parent dies I noticed that failed tests were leaving aroudn stray tailscaled processes on macOS at least. To repro, add this to tstest/integration: func TestFailInFewSeconds(t *testing.T) { t.Parallel() time.Sleep(3 * time.Second) os.Exit(1) t.Fatal("boom") } Those three seconds let the other parallel tests (with all their tailscaled child processes) start up and start running their tests, but then we violently os.Exit(1) the test driver and all the children were kept alive (and were spinning away, using all available CPU in gvisor scheduler code, which is a separate scary issue) Updates #cleanup Change-Id: I9c891ed1a1ec639fb2afec2808c04dbb8a460e0e Co-authored-by: Maisem Ali Signed-off-by: Brad Fitzpatrick --- cmd/tailscaled/tailscaled.go | 15 +++++++++++++++ tstest/integration/integration_test.go | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/cmd/tailscaled/tailscaled.go b/cmd/tailscaled/tailscaled.go index 45f583300..ce0f46b52 100644 --- a/cmd/tailscaled/tailscaled.go +++ b/cmd/tailscaled/tailscaled.go @@ -202,6 +202,10 @@ func main() { } } + if fd, ok := envknob.LookupInt("TS_PARENT_DEATH_FD"); ok && fd > 2 { + go dieOnPipeReadErrorOfFD(fd) + } + if printVersion { fmt.Println(version.String()) os.Exit(0) @@ -769,3 +773,14 @@ func beChild(args []string) error { } return f(args[1:]) } + +// dieOnPipeReadErrorOfFD reads from the pipe named by fd and exit the process +// when the pipe becomes readable. We use this in tests as a somewhat more +// portable mechanism for the Linux PR_SET_PDEATHSIG, which we wish existed on +// macOS. This helps us clean up straggler tailscaled processes when the parent +// test driver dies unexpectedly. +func dieOnPipeReadErrorOfFD(fd int) { + f := os.NewFile(uintptr(fd), "TS_PARENT_DEATH_FD") + f.Read(make([]byte, 1)) + os.Exit(1) +} diff --git a/tstest/integration/integration_test.go b/tstest/integration/integration_test.go index f7bde738f..5fc17302c 100644 --- a/tstest/integration/integration_test.go +++ b/tstest/integration/integration_test.go @@ -934,6 +934,15 @@ func (n *testNode) StartDaemonAsIPNGOOS(ipnGOOS string) *Daemon { cmd.Stdout = os.Stdout cmd.Stderr = io.MultiWriter(cmd.Stderr, os.Stderr) } + if runtime.GOOS != "windows" { + pr, pw, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { pw.Close() }) + cmd.ExtraFiles = append(cmd.ExtraFiles, pr) + cmd.Env = append(cmd.Env, "TS_PARENT_DEATH_FD=3") + } if err := cmd.Start(); err != nil { t.Fatalf("starting tailscaled: %v", err) }