mirror of
https://github.com/containers/podman.git
synced 2025-06-19 16:33:24 +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"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make sure the signal buffer is sufficiently big.
|
|
||||||
// runc is using the same value.
|
|
||||||
const signalBufferSize = 2048
|
|
||||||
|
|
||||||
// ProxySignals ...
|
// ProxySignals ...
|
||||||
func ProxySignals(ctr *libpod.Container) {
|
func ProxySignals(ctr *libpod.Container) {
|
||||||
// Stop catching the shutdown signals (SIGINT, SIGTERM) - they're going
|
// Stop catching the shutdown signals (SIGINT, SIGTERM) - they're going
|
||||||
// to the container now.
|
// to the container now.
|
||||||
shutdown.Stop() //nolint: errcheck
|
shutdown.Stop() //nolint: errcheck
|
||||||
|
|
||||||
sigBuffer := make(chan os.Signal, signalBufferSize)
|
sigBuffer := make(chan os.Signal, signal.SignalBufferSize)
|
||||||
signal.CatchAll(sigBuffer)
|
signal.CatchAll(sigBuffer)
|
||||||
|
|
||||||
logrus.Debugf("Enabling signal proxying")
|
logrus.Debugf("Enabling signal proxying")
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for s := range sigBuffer {
|
for s := range sigBuffer {
|
||||||
// Ignore SIGCHLD and SIGPIPE - these are mostly likely
|
syscallSignal := s.(syscall.Signal)
|
||||||
// intended for the podman command itself.
|
if signal.IsSignalIgnoredBySigProxy(syscallSignal) {
|
||||||
// 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 {
|
|
||||||
continue
|
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) {
|
if errors.Is(err, define.ErrCtrStateInvalid) {
|
||||||
logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID())
|
logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID())
|
||||||
} else {
|
} else {
|
||||||
|
@ -825,6 +825,13 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attach
|
// 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 := startAndAttach(ic, con.ID, &opts.DetachKeys, opts.InputStream, opts.OutputStream, opts.ErrorStream); err != nil {
|
||||||
if err == define.ErrDetach {
|
if err == define.ErrDetach {
|
||||||
return &report, nil
|
return &report, nil
|
||||||
|
@ -2,6 +2,12 @@ package tunnel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"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
|
// Image-related runtime using an ssh-tunnel to utilize Podman service
|
||||||
@ -18,3 +24,28 @@ type ContainerEngine struct {
|
|||||||
type SystemEngine struct {
|
type SystemEngine struct {
|
||||||
ClientCtx context.Context
|
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"
|
"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.
|
// ParseSignal translates a string to a valid syscall signal.
|
||||||
// It returns an error if the signal map doesn't include the given signal.
|
// It returns an error if the signal map doesn't include the given signal.
|
||||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||||
@ -56,3 +60,14 @@ func StopCatch(sigc chan os.Signal) {
|
|||||||
signal.Stop(sigc)
|
signal.Stop(sigc)
|
||||||
close(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-1": sigrtmax - 1,
|
||||||
"RTMAX": sigrtmax,
|
"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-1": sigrtmax - 1,
|
||||||
"RTMAX": sigrtmax,
|
"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-1": sigrtmax - 1,
|
||||||
"RTMAX": sigrtmax,
|
"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-1": sigrtmax - 1,
|
||||||
"RTMAX": sigrtmax,
|
"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