DockerCLI/cli/command/container/signals.go

62 lines
1.2 KiB
Go
Raw Normal View History

package container
import (
"context"
"os"
gosignal "os/signal"
"github.com/docker/docker/client"
"github.com/moby/sys/signal"
"github.com/sirupsen/logrus"
)
// ForwardAllSignals forwards signals to the container
//
// The channel you pass in must already be setup to receive any signals you want to forward.
func ForwardAllSignals(ctx context.Context, apiClient client.ContainerAPIClient, cid string, sigc <-chan os.Signal) {
ForwardAllSignals: check if channel is closed, and remove warning Commit fff164c22e8dc904291fecb62307312fd4ca153e modified ForwardAllSignals to take `SIGURG` signals into account, which can be generated by the Go runtime on Go 1.14 and up as an interrupt to support pre-emptable system calls on Linux. With the updated code, the signal (`s`) would sometimes be `nil`, causing spurious (but otherwise harmless) warnings to be printed; Unsupported signal: <nil>. Discarding. To debug this issue, I patched v20.10.4 to handle `nil`, and added a debug line to print the signal in all cases; ```patch diff --git a/cli/command/container/signals.go b/cli/command/container/signals.go index 06e4d9eb6..0cb53ef06 100644 --- a/cli/command/container/signals.go +++ b/cli/command/container/signals.go @@ -22,8 +22,9 @@ func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <- case <-ctx.Done(): return } + fmt.Fprintf(cli.Err(), "Signal: %v\n", s) if s == signal.SIGCHLD || s == signal.SIGPIPE { ``` When running a cross-compiled macOS binary with Go 1.13 (`make -f docker.Makefile binary-osx`): # regular "docker run" (note that the `<nil>` signal only happens "sometimes"): ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git Cloning into 'getting-started'... Signal: <nil> # when cancelling with CTRL-C: ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git ^CSignal: interrupt Cloning into 'getting-started'... error: could not lock config file /git/getting-started/.git/config: No such file or directory fatal: could not set 'core.repositoryformatversion' to '0' Signal: <nil> Signal: <nil> When running a macOS binary built with Go 1.15 (`DISABLE_WARN_OUTSIDE_CONTAINER=1 make binary`): # regular "docker run" (note that the `<nil>` signal only happens "sometimes"): # this is the same as on Go 1.13 ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git Cloning into 'getting-started'... Signal: <nil> # when cancelling with CTRL-C: ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git Cloning into 'getting-started'... ^CSignal: interrupt Signal: urgent I/O condition Signal: urgent I/O condition fatal: --stdin requires a git repository fatal: index-pack failed Signal: <nil> Signal: <nil> This patch checks if the channel is closed, and removes the warning (to prevent warnings if new signals are added that are not in our known list of signals) We should also consider updating `notfiyAllSignals()`, which currently forwards _all_ signals (`signal.Notify(sigc)` without passing a list of signals), and instead pass it "all signals _minus_ the signals we don't want forwarded": https://github.com/docker/cli/blob/35f023a7c22a51867fb099d29006ef27379bc7fe/cli/command/container/signals.go#L55 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-03-01 08:06:19 -05:00
var (
s os.Signal
ok bool
)
for {
select {
ForwardAllSignals: check if channel is closed, and remove warning Commit fff164c22e8dc904291fecb62307312fd4ca153e modified ForwardAllSignals to take `SIGURG` signals into account, which can be generated by the Go runtime on Go 1.14 and up as an interrupt to support pre-emptable system calls on Linux. With the updated code, the signal (`s`) would sometimes be `nil`, causing spurious (but otherwise harmless) warnings to be printed; Unsupported signal: <nil>. Discarding. To debug this issue, I patched v20.10.4 to handle `nil`, and added a debug line to print the signal in all cases; ```patch diff --git a/cli/command/container/signals.go b/cli/command/container/signals.go index 06e4d9eb6..0cb53ef06 100644 --- a/cli/command/container/signals.go +++ b/cli/command/container/signals.go @@ -22,8 +22,9 @@ func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <- case <-ctx.Done(): return } + fmt.Fprintf(cli.Err(), "Signal: %v\n", s) if s == signal.SIGCHLD || s == signal.SIGPIPE { ``` When running a cross-compiled macOS binary with Go 1.13 (`make -f docker.Makefile binary-osx`): # regular "docker run" (note that the `<nil>` signal only happens "sometimes"): ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git Cloning into 'getting-started'... Signal: <nil> # when cancelling with CTRL-C: ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git ^CSignal: interrupt Cloning into 'getting-started'... error: could not lock config file /git/getting-started/.git/config: No such file or directory fatal: could not set 'core.repositoryformatversion' to '0' Signal: <nil> Signal: <nil> When running a macOS binary built with Go 1.15 (`DISABLE_WARN_OUTSIDE_CONTAINER=1 make binary`): # regular "docker run" (note that the `<nil>` signal only happens "sometimes"): # this is the same as on Go 1.13 ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git Cloning into 'getting-started'... Signal: <nil> # when cancelling with CTRL-C: ./build/docker run --rm alpine/git clone https://github.com/docker/getting-started.git Cloning into 'getting-started'... ^CSignal: interrupt Signal: urgent I/O condition Signal: urgent I/O condition fatal: --stdin requires a git repository fatal: index-pack failed Signal: <nil> Signal: <nil> This patch checks if the channel is closed, and removes the warning (to prevent warnings if new signals are added that are not in our known list of signals) We should also consider updating `notfiyAllSignals()`, which currently forwards _all_ signals (`signal.Notify(sigc)` without passing a list of signals), and instead pass it "all signals _minus_ the signals we don't want forwarded": https://github.com/docker/cli/blob/35f023a7c22a51867fb099d29006ef27379bc7fe/cli/command/container/signals.go#L55 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-03-01 08:06:19 -05:00
case s, ok = <-sigc:
if !ok {
return
}
case <-ctx.Done():
return
}
if s == signal.SIGCHLD || s == signal.SIGPIPE {
continue
}
// In go1.14+, the go runtime issues SIGURG as an interrupt to support pre-emptable system calls on Linux.
// Since we can't forward that along we'll check that here.
if isRuntimeSig(s) {
continue
}
var sig string
for sigStr, sigN := range signal.SignalMap {
if sigN == s {
sig = sigStr
break
}
}
if sig == "" {
continue
}
if err := apiClient.ContainerKill(ctx, cid, sig); err != nil {
logrus.Debugf("Error sending signal: %s", err)
}
}
}
func notifyAllSignals() chan os.Signal {
sigc := make(chan os.Signal, 128)
gosignal.Notify(sigc)
return sigc
}