Skip to content

Commit b10b858

Browse files
committed
envtest: improve process cleanup
When envtest creates new processes, it wasn't setting the process group to the parent, when the main process is killed or it panics, all the other processes are orphaned, and need to be killed separately. In addition, if for some reason we can't shutdown a process cleanly, we should try to SIGKILL before returning from Stop. Signed-off-by: Vince Prignano <[email protected]>
1 parent 15d7928 commit b10b858

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

pkg/internal/testing/controlplane/kubectl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ func (k *KubeCtl) Run(args ...string) (stdout, stderr io.Reader, err error) {
112112
cmd := exec.Command(k.Path, allArgs...)
113113
cmd.Stdout = stdoutBuffer
114114
cmd.Stderr = stderrBuffer
115+
cmd.SysProcAttr = process.GetSysProcAttr()
115116

116117
err = cmd.Run()
117118

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
2+
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
3+
4+
/*
5+
Copyright 2016 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package process
21+
22+
import "syscall"
23+
24+
// GetSysProcAttr returns the SysProcAttr to use for the process,
25+
// for non-unix systems this returns nil.
26+
func GetSysProcAttr() *syscall.SysProcAttr {
27+
return nil
28+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
2+
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
3+
4+
/*
5+
Copyright 2023 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package process
21+
22+
import (
23+
"golang.org/x/sys/unix"
24+
)
25+
26+
// GetSysProcAttr returns the SysProcAttr to use for the process,
27+
// for unix systems this returns a SysProcAttr with Setpgid set to true,
28+
// which inherits the parent's process group id.
29+
func GetSysProcAttr() *unix.SysProcAttr {
30+
return &unix.SysProcAttr{
31+
Setpgid: true,
32+
}
33+
}

pkg/internal/testing/process/process.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ func (ps *State) Start(stdout, stderr io.Writer) (err error) {
155155
ps.Cmd = exec.Command(ps.Path, ps.Args...)
156156
ps.Cmd.Stdout = stdout
157157
ps.Cmd.Stderr = stderr
158+
ps.Cmd.SysProcAttr = GetSysProcAttr()
158159

159160
ready := make(chan bool)
160161
timedOut := time.After(ps.StartTimeout)
@@ -265,6 +266,9 @@ func (ps *State) Stop() error {
265266
case <-ps.waitDone:
266267
break
267268
case <-timedOut:
269+
if err := ps.Cmd.Process.Signal(syscall.SIGKILL); err != nil {
270+
return fmt.Errorf("unable to kill process %s: %w", ps.Path, err)
271+
}
268272
return fmt.Errorf("timeout waiting for process %s to stop", path.Base(ps.Path))
269273
}
270274
ps.ready = false

pkg/internal/testing/process/process_test.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -352,16 +352,7 @@ var _ = Describe("Init", func() {
352352
})
353353

354354
var simpleBashScript = []string{
355-
"-c",
356-
`
357-
i=0
358-
while true
359-
do
360-
echo "loop $i" >&2
361-
let 'i += 1'
362-
sleep 0.2
363-
done
364-
`,
355+
"-c", "tail -f /dev/null",
365356
}
366357

367358
func getServerURL(server *ghttp.Server) url.URL {

0 commit comments

Comments
 (0)