Skip to content

Commit

Permalink
Add Signal Forwarding to Entrypoint Runner
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
waveywaves committed Apr 17, 2020
1 parent 6b1579c commit 430f729
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
38 changes: 35 additions & 3 deletions cmd/entrypoint/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"os"
"os/exec"
"os/signal"
"syscall"

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

// realRunner actually runs commands.
type realRunner struct{}
type realRunner struct {
signals chan os.Signal
}

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

func (*realRunner) Run(args ...string) error {
func (rr *realRunner) Run(args ...string) error {
if len(args) == 0 {
return nil
}
name, args := args[0], args[1:]

// Receive system signals on "rr.signals"
if rr.signals == nil {
rr.signals = make(chan os.Signal, 1)
}
defer close(rr.signals)
signal.Notify(rr.signals)
defer signal.Reset()

cmd := exec.Command(name, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// dedicated PID group used to forward signals to
// main process and all children
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

// Start defined command
if err := cmd.Start(); err != nil {
return err
}

if err := cmd.Run(); err != nil {
// Goroutine for signals forwarding
go func() {
for s := range rr.signals {
// Forward signal to main process and all children
if s != syscall.SIGCHLD {
_ = syscall.Kill(-cmd.Process.Pid, s.(syscall.Signal))
}
}
}()

// Wait for command to exit
if err := cmd.Wait(); err != nil {
return err
}

return nil
}
18 changes: 18 additions & 0 deletions cmd/entrypoint/runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"os"
"syscall"
"testing"
)

func TestRealRunnerSignalForwarding(t *testing.T) {
rr := realRunner{}
rr.signals = make(chan os.Signal, 1)
rr.signals <- syscall.SIGINT
if err := rr.Run("sleep", "3600"); err.Error() == "signal: interrupt" {
t.Logf("SIGINT forwarded to Entrypoint")
} else {
t.Fatalf("Unexpected error received: %v", err)
}
}

0 comments on commit 430f729

Please sign in to comment.