Skip to content

Commit 3f58719

Browse files
committed
Add Signal Forwarding to Entrypoint Runner
The Entrypoint process should be notified and signals received should be propogated as necessary. This signal forwarding mimics the one in https://github.com/pablo-ruth/go-init which is an golang implementation of https://github.com/Yelp/dumb-init . The cmd.Run() has also been replaced with a cmd.Start() and cmd.Wait() to systematically start the command and Wait for it's completion without prematurely exiting.
1 parent 6b1579c commit 3f58719

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

cmd/entrypoint/runner.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package main
33
import (
44
"os"
55
"os/exec"
6+
"os/signal"
7+
"syscall"
68

79
"github.com/tektoncd/pipeline/pkg/entrypoint"
810
)
@@ -11,22 +13,52 @@ import (
1113
// stdout/stderr are collected -- needs e2e tests.
1214

1315
// realRunner actually runs commands.
14-
type realRunner struct{}
16+
type realRunner struct {
17+
signals chan os.Signal
18+
}
1519

1620
var _ entrypoint.Runner = (*realRunner)(nil)
1721

18-
func (*realRunner) Run(args ...string) error {
22+
func (rr *realRunner) Run(args ...string) error {
1923
if len(args) == 0 {
2024
return nil
2125
}
2226
name, args := args[0], args[1:]
2327

28+
// Receive system signals on "rr.signals"
29+
if rr.signals == nil {
30+
rr.signals = make(chan os.Signal, 1)
31+
}
32+
defer close(rr.signals)
33+
signal.Notify(rr.signals)
34+
defer signal.Reset()
35+
2436
cmd := exec.Command(name, args...)
2537
cmd.Stdout = os.Stdout
2638
cmd.Stderr = os.Stderr
39+
// dedicated PID group used to forward signals to
40+
// main process and all children
41+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
42+
43+
// Start defined command
44+
if err := cmd.Start(); err != nil {
45+
return err
46+
}
2747

28-
if err := cmd.Run(); err != nil {
48+
// Goroutine for signals forwarding
49+
go func() {
50+
for s := range rr.signals {
51+
// Forward signal to main process and all children
52+
if s != syscall.SIGCHLD {
53+
_ = syscall.Kill(-cmd.Process.Pid, s.(syscall.Signal))
54+
}
55+
}
56+
}()
57+
58+
// Wait for command to exit
59+
if err := cmd.Wait(); err != nil {
2960
return err
3061
}
62+
3163
return nil
3264
}

cmd/entrypoint/runner_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"syscall"
6+
"testing"
7+
)
8+
9+
func TestRealRunnerSignalForwarding(t *testing.T) {
10+
rr := realRunner{}
11+
rr.signals = make(chan os.Signal, 1)
12+
rr.signals <- syscall.SIGINT
13+
if err := rr.Run("sleep", "3600"); err.Error() == "signal: interrupt" {
14+
t.Logf("SIGINT forwarded to Entrypoint")
15+
}
16+
}

0 commit comments

Comments
 (0)