mirror of
https://github.com/moby/moby.git
synced 2026-08-08 17:11:38 +00:00
Drop cancellation at the kill boundary because killing starts irreversible task and cleanup work that must finish after request cancellation. Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
108 lines
2.6 KiB
Go
108 lines
2.6 KiB
Go
package daemon
|
|
|
|
import (
|
|
"context"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
containerd "github.com/containerd/containerd/v2/client"
|
|
cerrdefs "github.com/containerd/errdefs"
|
|
containertypes "github.com/moby/moby/api/types/container"
|
|
"github.com/moby/moby/v2/daemon/container"
|
|
"github.com/moby/moby/v2/daemon/events"
|
|
libcontainerdtypes "github.com/moby/moby/v2/daemon/internal/libcontainerd/types"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
type notFoundKillTask struct {
|
|
libcontainerdtypes.Task
|
|
deleteCalled chan struct{}
|
|
}
|
|
|
|
type killContextKey struct{}
|
|
|
|
type contextKillTask struct {
|
|
libcontainerdtypes.Task
|
|
killContext chan context.Context
|
|
}
|
|
|
|
func (t *contextKillTask) Pid() uint32 {
|
|
return 1
|
|
}
|
|
|
|
func (t *contextKillTask) Kill(ctx context.Context, _ syscall.Signal) error {
|
|
t.killContext <- ctx
|
|
return nil
|
|
}
|
|
|
|
func (t *notFoundKillTask) Pid() uint32 {
|
|
return 1
|
|
}
|
|
|
|
func (t *notFoundKillTask) Kill(context.Context, syscall.Signal) error {
|
|
return cerrdefs.ErrNotFound
|
|
}
|
|
|
|
func (t *notFoundKillTask) Delete(ctx context.Context) (*containerd.ExitStatus, error) {
|
|
close(t.deleteCalled)
|
|
<-ctx.Done()
|
|
return nil, ctx.Err()
|
|
}
|
|
|
|
func TestKillWithSignalWaitsIndefinitelyForDelayedExit(t *testing.T) {
|
|
task := ¬FoundKillTask{deleteCalled: make(chan struct{})}
|
|
ctr := container.NewBaseContainer(t.Name(), t.TempDir())
|
|
stopTimeout := -1
|
|
ctr.Config = &containertypes.Config{StopTimeout: &stopTimeout}
|
|
ctr.HostConfig = &containertypes.HostConfig{}
|
|
ctr.Lock()
|
|
ctr.State.SetRunning(nil, task, time.Now())
|
|
ctr.Unlock()
|
|
|
|
daemon := &Daemon{
|
|
EventsService: events.New(),
|
|
shutdown: true,
|
|
}
|
|
|
|
err := daemon.killWithSignal(t.Context(), ctr, syscall.SIGKILL)
|
|
assert.NilError(t, err)
|
|
|
|
select {
|
|
case <-task.deleteCalled:
|
|
t.Fatal("fallback exit handling ran before the delayed exit event")
|
|
case <-time.After(100 * time.Millisecond):
|
|
}
|
|
|
|
ctr.Lock()
|
|
ctr.State.SetStopped(&container.ExitStatus{})
|
|
ctr.Unlock()
|
|
}
|
|
|
|
func TestKillWithSignalDetachesContext(t *testing.T) {
|
|
task := &contextKillTask{killContext: make(chan context.Context, 1)}
|
|
ctr := container.NewBaseContainer(t.Name(), t.TempDir())
|
|
ctr.Config = &containertypes.Config{}
|
|
ctr.HostConfig = &containertypes.HostConfig{}
|
|
ctr.Lock()
|
|
ctr.State.SetRunning(nil, task, time.Now())
|
|
ctr.Unlock()
|
|
|
|
daemon := &Daemon{
|
|
EventsService: events.New(),
|
|
shutdown: true,
|
|
}
|
|
|
|
const contextValue = "value"
|
|
ctx := context.WithValue(t.Context(), killContextKey{}, contextValue)
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
cancel()
|
|
|
|
err := daemon.killWithSignal(ctx, ctr, syscall.SIGKILL)
|
|
assert.NilError(t, err)
|
|
|
|
killCtx := <-task.killContext
|
|
assert.NilError(t, killCtx.Err())
|
|
assert.Equal(t, killCtx.Value(killContextKey{}), contextValue)
|
|
}
|