Skip to content

Commit

Permalink
Add support to sig-proxy for podman-remote
Browse files Browse the repository at this point in the history
Signed-off-by: Boaz Shuster <boaz.shuster.github@gmail.com>
  • Loading branch information
boaz0 committed Sep 20, 2022
1 parent 30231d0 commit 3c962a3
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 5 deletions.
6 changes: 1 addition & 5 deletions pkg/domain/infra/abi/terminal/sigproxy_commn.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,13 @@ 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")
Expand Down
7 changes: 7 additions & 0 deletions pkg/domain/infra/tunnel/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions pkg/domain/infra/tunnel/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,3 +24,24 @@ 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 {
signalName, err := signal.ParseSysSignalToName(s.(syscall.Signal))
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)
}
}
}
}()
}
15 changes: 15 additions & 0 deletions pkg/signal/signal_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}
49 changes: 49 additions & 0 deletions pkg/signal/signal_common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}
43 changes: 43 additions & 0 deletions test/system/032-sig-proxy.bats
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3c962a3

Please sign in to comment.