Forcibly stop running containers before removal
Signed-off-by: Abhishek Kulkarni <abd.kulkarni@gmail.com>
This commit is contained in:
parent
aa0f4fd37b
commit
287c52d1c6
@ -34,48 +34,6 @@ import (
|
|||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSandboxCleanRemove(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
t.Logf("Create a sandbox")
|
|
||||||
sbConfig := PodSandboxConfig("sandbox", "clean-remove")
|
|
||||||
sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer func() {
|
|
||||||
// Make sure the sandbox is cleaned up in any case.
|
|
||||||
runtimeService.StopPodSandbox(sb)
|
|
||||||
runtimeService.RemovePodSandbox(sb)
|
|
||||||
}()
|
|
||||||
|
|
||||||
t.Logf("Should not be able to remove the sandbox when it's still running")
|
|
||||||
assert.Error(t, runtimeService.RemovePodSandbox(sb))
|
|
||||||
|
|
||||||
t.Logf("Delete sandbox task from containerd")
|
|
||||||
cntr, err := containerdClient.LoadContainer(ctx, sb)
|
|
||||||
require.NoError(t, err)
|
|
||||||
task, err := cntr.Task(ctx, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
// Kill the task with signal SIGKILL, once the task exited,
|
|
||||||
// the TaskExit event will trigger the task.Delete().
|
|
||||||
err = task.Kill(ctx, syscall.SIGKILL, containerd.WithKillAll)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
t.Logf("Sandbox state should be NOTREADY")
|
|
||||||
assert.NoError(t, Eventually(func() (bool, error) {
|
|
||||||
status, err := runtimeService.PodSandboxStatus(sb)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return status.GetState() == runtime.PodSandboxState_SANDBOX_NOTREADY, nil
|
|
||||||
}, time.Second, 30*time.Second), "sandbox state should become NOTREADY")
|
|
||||||
|
|
||||||
t.Logf("Should not be able to remove the sandbox when netns is not closed")
|
|
||||||
assert.Error(t, runtimeService.RemovePodSandbox(sb))
|
|
||||||
|
|
||||||
t.Logf("Should be able to remove the sandbox after properly stopped")
|
|
||||||
assert.NoError(t, runtimeService.StopPodSandbox(sb))
|
|
||||||
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSandboxRemoveWithoutIPLeakage(t *testing.T) {
|
func TestSandboxRemoveWithoutIPLeakage(t *testing.T) {
|
||||||
const hostLocalCheckpointDir = "/var/lib/cni"
|
const hostLocalCheckpointDir = "/var/lib/cni"
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
|
|
||||||
@ -29,7 +30,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// RemoveContainer removes the container.
|
// RemoveContainer removes the container.
|
||||||
// TODO(random-liu): Forcibly stop container if it's running.
|
|
||||||
func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveContainerRequest) (_ *runtime.RemoveContainerResponse, retErr error) {
|
func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveContainerRequest) (_ *runtime.RemoveContainerResponse, retErr error) {
|
||||||
container, err := c.containerStore.Get(r.GetContainerId())
|
container, err := c.containerStore.Get(r.GetContainerId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -42,6 +42,17 @@ func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveConta
|
|||||||
}
|
}
|
||||||
id := container.ID
|
id := container.ID
|
||||||
|
|
||||||
|
// Forcibly stop the containers if they are in running or unknown state
|
||||||
|
state := container.Status.Get().State()
|
||||||
|
if state == runtime.ContainerState_CONTAINER_RUNNING ||
|
||||||
|
state == runtime.ContainerState_CONTAINER_UNKNOWN {
|
||||||
|
logrus.Infof("Forcibly stopping container %q", id)
|
||||||
|
if err := c.stopContainer(ctx, container, 0); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to forcibly stop container %q", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Set removing state to prevent other start/remove operations against this container
|
// Set removing state to prevent other start/remove operations against this container
|
||||||
// while it's being removed.
|
// while it's being removed.
|
||||||
if err := setContainerRemoving(container); err != nil {
|
if err := setContainerRemoving(container); err != nil {
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
|
|
||||||
@ -48,7 +49,10 @@ func (c *criService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodS
|
|||||||
// Return error if sandbox container is still running or unknown.
|
// Return error if sandbox container is still running or unknown.
|
||||||
state := sandbox.Status.Get().State
|
state := sandbox.Status.Get().State
|
||||||
if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown {
|
if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown {
|
||||||
return nil, errors.Errorf("sandbox container %q is not fully stopped", id)
|
logrus.Infof("Forcibly stopping sandbox %q", id)
|
||||||
|
if err := c.stopPodSandbox(ctx, sandbox); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to forcibly stop sandbox %q", id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return error if sandbox network namespace is not closed yet.
|
// Return error if sandbox network namespace is not closed yet.
|
||||||
|
@ -39,6 +39,15 @@ func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandb
|
|||||||
return nil, errors.Wrapf(err, "an error occurred when try to find sandbox %q",
|
return nil, errors.Wrapf(err, "an error occurred when try to find sandbox %q",
|
||||||
r.GetPodSandboxId())
|
r.GetPodSandboxId())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.stopPodSandbox(ctx, sandbox); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &runtime.StopPodSandboxResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *criService) stopPodSandbox(ctx context.Context, sandbox sandboxstore.Sandbox) error {
|
||||||
// Use the full sandbox id.
|
// Use the full sandbox id.
|
||||||
id := sandbox.ID
|
id := sandbox.ID
|
||||||
|
|
||||||
@ -52,20 +61,20 @@ func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandb
|
|||||||
}
|
}
|
||||||
// Forcibly stop the container. Do not use `StopContainer`, because it introduces a race
|
// Forcibly stop the container. Do not use `StopContainer`, because it introduces a race
|
||||||
// if a container is removed after list.
|
// if a container is removed after list.
|
||||||
if err = c.stopContainer(ctx, container, 0); err != nil {
|
if err := c.stopContainer(ctx, container, 0); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to stop container %q", container.ID)
|
return errors.Wrapf(err, "failed to stop container %q", container.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.cleanupSandboxFiles(id, sandbox.Config); err != nil {
|
if err := c.cleanupSandboxFiles(id, sandbox.Config); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to cleanup sandbox files")
|
return errors.Wrap(err, "failed to cleanup sandbox files")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only stop sandbox container when it's running or unknown.
|
// Only stop sandbox container when it's running or unknown.
|
||||||
state := sandbox.Status.Get().State
|
state := sandbox.Status.Get().State
|
||||||
if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown {
|
if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown {
|
||||||
if err := c.stopSandboxContainer(ctx, sandbox); err != nil {
|
if err := c.stopSandboxContainer(ctx, sandbox); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to stop sandbox container %q in %q state", id, state)
|
return errors.Wrapf(err, "failed to stop sandbox container %q in %q state", id, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,21 +83,21 @@ func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandb
|
|||||||
// Use empty netns path if netns is not available. This is defined in:
|
// Use empty netns path if netns is not available. This is defined in:
|
||||||
// https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md
|
// https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md
|
||||||
if closed, err := sandbox.NetNS.Closed(); err != nil {
|
if closed, err := sandbox.NetNS.Closed(); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to check network namespace closed")
|
return errors.Wrap(err, "failed to check network namespace closed")
|
||||||
} else if closed {
|
} else if closed {
|
||||||
sandbox.NetNSPath = ""
|
sandbox.NetNSPath = ""
|
||||||
}
|
}
|
||||||
if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
|
if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to destroy network for sandbox %q", id)
|
return errors.Wrapf(err, "failed to destroy network for sandbox %q", id)
|
||||||
}
|
}
|
||||||
if err = sandbox.NetNS.Remove(); err != nil {
|
if err := sandbox.NetNS.Remove(); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove network namespace for sandbox %q", id)
|
return errors.Wrapf(err, "failed to remove network namespace for sandbox %q", id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.G(ctx).Infof("TearDown network for sandbox %q successfully", id)
|
log.G(ctx).Infof("TearDown network for sandbox %q successfully", id)
|
||||||
|
|
||||||
return &runtime.StopPodSandboxResponse{}, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopSandboxContainer kills the sandbox container.
|
// stopSandboxContainer kills the sandbox container.
|
||||||
|
Loading…
Reference in New Issue
Block a user