mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
Add support to sig-proxy for podman-remote
Signed-off-by: Boaz Shuster <boaz.shuster.github@gmail.com>
This commit is contained in:
@ -15,33 +15,25 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Make sure the signal buffer is sufficiently big.
|
||||
// runc is using the same value.
|
||||
const signalBufferSize = 2048
|
||||
|
||||
// ProxySignals ...
|
||||
func ProxySignals(ctr *libpod.Container) {
|
||||
// Stop catching the shutdown signals (SIGINT, SIGTERM) - they're going
|
||||
// to the container now.
|
||||
shutdown.Stop() //nolint: errcheck
|
||||
|
||||
sigBuffer := make(chan os.Signal, signalBufferSize)
|
||||
sigBuffer := make(chan os.Signal, signal.SignalBufferSize)
|
||||
signal.CatchAll(sigBuffer)
|
||||
|
||||
logrus.Debugf("Enabling signal proxying")
|
||||
|
||||
go func() {
|
||||
for s := range sigBuffer {
|
||||
// Ignore SIGCHLD and SIGPIPE - these are mostly likely
|
||||
// intended for the podman command itself.
|
||||
// SIGURG was added because of golang 1.14 and its preemptive changes
|
||||
// causing more signals to "show up".
|
||||
// https://github.com/containers/podman/issues/5483
|
||||
if s == syscall.SIGCHLD || s == syscall.SIGPIPE || s == syscall.SIGURG {
|
||||
syscallSignal := s.(syscall.Signal)
|
||||
if signal.IsSignalIgnoredBySigProxy(syscallSignal) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil {
|
||||
if err := ctr.Kill(uint(syscallSignal)); err != nil {
|
||||
if errors.Is(err, define.ErrCtrStateInvalid) {
|
||||
logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID())
|
||||
} else {
|
||||
|
@ -825,6 +825,13 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
||||
}
|
||||
|
||||
// Attach
|
||||
if opts.SigProxy {
|
||||
remoteProxySignals(con.ID, func(signal string) error {
|
||||
killOpts := entities.KillOptions{All: false, Latest: false, Signal: signal}
|
||||
_, err := ic.ContainerKill(ctx, []string{con.ID}, killOpts)
|
||||
return err
|
||||
})
|
||||
}
|
||||
if err := startAndAttach(ic, con.ID, &opts.DetachKeys, opts.InputStream, opts.OutputStream, opts.ErrorStream); err != nil {
|
||||
if err == define.ErrDetach {
|
||||
return &report, nil
|
||||
|
@ -2,6 +2,12 @@ package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/podman/v4/libpod/define"
|
||||
"github.com/containers/podman/v4/pkg/signal"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Image-related runtime using an ssh-tunnel to utilize Podman service
|
||||
@ -18,3 +24,28 @@ type ContainerEngine struct {
|
||||
type SystemEngine struct {
|
||||
ClientCtx context.Context
|
||||
}
|
||||
|
||||
func remoteProxySignals(ctrID string, killFunc func(string) error) {
|
||||
sigBuffer := make(chan os.Signal, signal.SignalBufferSize)
|
||||
signal.CatchAll(sigBuffer)
|
||||
|
||||
logrus.Debugf("Enabling signal proxying")
|
||||
|
||||
go func() {
|
||||
for s := range sigBuffer {
|
||||
syscallSignal := s.(syscall.Signal)
|
||||
if signal.IsSignalIgnoredBySigProxy(syscallSignal) {
|
||||
continue
|
||||
}
|
||||
signalName, err := signal.ParseSysSignalToName(syscallSignal)
|
||||
if err != nil {
|
||||
logrus.Infof("Ceasing signal %v forwarding to container %s as it has stopped: %s", s, ctrID, err)
|
||||
}
|
||||
if err := killFunc(signalName); err != nil {
|
||||
if err.Error() == define.ErrCtrStateInvalid.Error() {
|
||||
logrus.Debugf("Ceasing signal %q forwarding to container %s as it has stopped", signalName, ctrID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Make sure the signal buffer is sufficiently big.
|
||||
// runc is using the same value.
|
||||
const SignalBufferSize = 2048
|
||||
|
||||
// ParseSignal translates a string to a valid syscall signal.
|
||||
// It returns an error if the signal map doesn't include the given signal.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
@ -56,3 +60,14 @@ func StopCatch(sigc chan os.Signal) {
|
||||
signal.Stop(sigc)
|
||||
close(sigc)
|
||||
}
|
||||
|
||||
// ParseSysSignalToName translates syscall.Signal to its name in the operating system.
|
||||
// For example, syscall.Signal(9) will return "KILL" on Linux system.
|
||||
func ParseSysSignalToName(s syscall.Signal) (string, error) {
|
||||
for k, v := range SignalMap {
|
||||
if v == s {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("unknown syscall signal: %s", s)
|
||||
}
|
||||
|
@ -118,3 +118,52 @@ func TestParseSignalNameOrNumber(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSysSignalToName(t *testing.T) {
|
||||
type args struct {
|
||||
signal syscall.Signal
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Kill should work",
|
||||
args: args{
|
||||
signal: syscall.SIGKILL,
|
||||
},
|
||||
want: "KILL",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Non-defined signal number should not work",
|
||||
args: args{
|
||||
signal: 923,
|
||||
},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "garbage should fail",
|
||||
args: args{
|
||||
signal: -1,
|
||||
},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParseSysSignalToName(tt.args.signal)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParseSysSignalToName() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("ParseSysSignalToName() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -89,3 +89,11 @@ var SignalMap = map[string]syscall.Signal{
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
|
||||
// IsSignalIgnoredBySigProxy determines whether sig-proxy should ignore syscall signal
|
||||
func IsSignalIgnoredBySigProxy(s syscall.Signal) bool {
|
||||
// Ignore SIGCHLD and SIGPIPE - these are most likely intended for the podman command itself.
|
||||
// SIGURG was added because of golang 1.14 and its preemptive changes causing more signals to "show up".
|
||||
// https://github.com/containers/podman/issues/5483
|
||||
return s == syscall.SIGCHLD || s == syscall.SIGPIPE || s == syscall.SIGURG
|
||||
}
|
||||
|
@ -90,3 +90,11 @@ var SignalMap = map[string]syscall.Signal{
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
|
||||
// IsSignalIgnoredBySigProxy determines whether sig-proxy should ignore syscall signal
|
||||
func IsSignalIgnoredBySigProxy(s syscall.Signal) bool {
|
||||
// Ignore SIGCHLD and SIGPIPE - these are most likely intended for the podman command itself.
|
||||
// SIGURG was added because of golang 1.14 and its preemptive changes causing more signals to "show up".
|
||||
// https://github.com/containers/podman/issues/5483
|
||||
return s == syscall.SIGCHLD || s == syscall.SIGPIPE || s == syscall.SIGURG
|
||||
}
|
||||
|
@ -87,3 +87,11 @@ var SignalMap = map[string]syscall.Signal{
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
|
||||
// IsSignalIgnoredBySigProxy determines whether sig-proxy should ignore syscall signal
|
||||
func IsSignalIgnoredBySigProxy(s syscall.Signal) bool {
|
||||
// Ignore SIGCHLD and SIGPIPE - these are most likely intended for the podman command itself.
|
||||
// SIGURG was added because of golang 1.14 and its preemptive changes causing more signals to "show up".
|
||||
// https://github.com/containers/podman/issues/5483
|
||||
return s == syscall.SIGCHLD || s == syscall.SIGPIPE || s == syscall.SIGURG
|
||||
}
|
||||
|
@ -87,3 +87,9 @@ var SignalMap = map[string]syscall.Signal{
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
|
||||
// IsSignalIgnoredBySigProxy determines whether to sig-proxy should ignore syscall signal
|
||||
// keep the container running or not. In unsupported OS this should not ignore any syscall signal.
|
||||
func IsSignalIgnoredBySigProxy(s syscall.Signal) bool {
|
||||
return false
|
||||
}
|
||||
|
43
test/system/032-sig-proxy.bats
Normal file
43
test/system/032-sig-proxy.bats
Normal file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
@test "podman sigkill" {
|
||||
$PODMAN run -i --name foo $IMAGE sh -c 'trap "echo BYE;exit 0" INT;echo READY;while :;do sleep 0.1;done' &
|
||||
local kidpid=$!
|
||||
|
||||
# Wait for container to appear
|
||||
local timeout=5
|
||||
while :;do
|
||||
sleep 0.5
|
||||
run_podman '?' container exists foo
|
||||
if [[ $status -eq 0 ]]; then
|
||||
break
|
||||
fi
|
||||
timeout=$((timeout - 1))
|
||||
if [[ $timeout -eq 0 ]]; then
|
||||
die "Timed out waiting for container to start"
|
||||
fi
|
||||
done
|
||||
|
||||
wait_for_ready foo
|
||||
|
||||
# Signal, and wait for container to exit
|
||||
kill -INT $kidpid
|
||||
local timeout=5
|
||||
while :;do
|
||||
sleep 0.5
|
||||
run_podman logs foo
|
||||
if [[ "$output" =~ BYE ]]; then
|
||||
break
|
||||
fi
|
||||
timeout=$((timeout - 1))
|
||||
if [[ $timeout -eq 0 ]]; then
|
||||
die "Timed out waiting for BYE from container"
|
||||
fi
|
||||
done
|
||||
|
||||
run_podman rm -f -t0 foo
|
||||
}
|
||||
|
||||
# vim: filetype=sh
|
Reference in New Issue
Block a user