containerd/pkg/cri/server/sandbox_remove.go
Wei Fu 337cc21719 pkg/cri: should ignore no sandbox bucket
The sandbox might be recovered from v1.x release. It doesn't have
metadata bucket. We should ignore the not-found error.

How to reproduce the issue:

```bash
➜  containerd git:(main) sudo ctr version
Client:
  Version:  1.6.22
  Revision: 8165feabfdfe38c65b599c4993d227328c231fca
  Go version: go1.19.11

Server:
  Version:  1.6.22
  Revision: 8165feabfdfe38c65b599c4993d227328c231fca
  UUID: be4216aa-8a2e-4305-9186-efeacd2d9a17

➜  containerd git:(main) cat /tmp/pod.json
{
    "metadata": {
        "name": "nginx-sandbox",
        "namespace": "default",
        "attempt": 1,
        "uid": "hdishd83djaidwnduwk28bcsb"
    },
    "log_directory": "/tmp",
    "linux": {
    }
}

➜  containerd git:(main) sudo crictl runp /tmp/pod.json
616ea1cc657c57e80abf74e707a8177878ac2ec1ab7c346b4adb7bc0fadf986e
➜  containerd git:(main) sudo crictl pods
POD ID              CREATED             STATE               NAME                NAMESPACE           ATTEMPT             RUNTIME
616ea1cc657c5       9 seconds ago       Ready               nginx-sandbox       default             1                   (default)

➜  containerd git:(main) make BUILDTAGS=no_btrfs
➜  containerd git:(main) sudo PREFIX=/usr make install
+ install bin/ctr bin/containerd bin/containerd-stress bin/containerd-shim-runc-v2

➜  containerd git:(main) sudo systemctl restart containerd
➜  containerd git:(main) sudo ctr version
Client:
  Version:  v1.7.0-943-g980767551
  Revision: 9807675518
  Go version: go1.20.10

Server:
  Version:  v1.7.0-943-g980767551
  Revision: 9807675518
  UUID: be4216aa-8a2e-4305-9186-efeacd2d9a17

➜  containerd git:(main) sudo crictl stopp  616ea1cc657c5
Stopped sandbox 616ea1cc657c5

➜  containerd git:(main) sudo crictl rmp 616ea1cc657c5
E1019 14:03:37.885162 2052643 remote_runtime.go:295] "RemovePodSandbox from runtime service failed" err="rpc error: code = Unknown desc = failed to remove sandbox metadata from store: failed to delete sandbox \"616ea1cc657c57e80abf74e707a8177878ac2ec1ab7c346b4adb7bc0fadf986e\": bucket not found" podSandboxID="616ea1cc657c5"
removing the pod sandbox "616ea1cc657c5": rpc error: code = Unknown desc = failed to remove sandbox metadata from store: failed to delete sandbox "616ea1cc657c57e80abf74e707a8177878ac2ec1ab7c346b4adb7bc0fadf986e": bucket not found
```

Signed-off-by: Wei Fu <fuweid89@gmail.com>
2023-10-20 15:20:18 +08:00

121 lines
4.4 KiB
Go

/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package server
import (
"context"
"fmt"
"time"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/log"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)
// RemovePodSandbox removes the sandbox. If there are running containers in the
// sandbox, they should be forcibly removed.
func (c *criService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodSandboxRequest) (*runtime.RemovePodSandboxResponse, error) {
start := time.Now()
sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId())
if err != nil {
if !errdefs.IsNotFound(err) {
return nil, fmt.Errorf("an error occurred when try to find sandbox %q: %w",
r.GetPodSandboxId(), err)
}
// Do not return error if the id doesn't exist.
log.G(ctx).Tracef("RemovePodSandbox called for sandbox %q that does not exist",
r.GetPodSandboxId())
return &runtime.RemovePodSandboxResponse{}, nil
}
// Use the full sandbox id.
id := sandbox.ID
// If the sandbox is still running, not ready, or in an unknown state, forcibly stop it.
// Even if it's in a NotReady state, this will close its network namespace, if open.
// This can happen if the task process associated with the Pod died or it was killed.
log.G(ctx).Infof("Forcibly stopping sandbox %q", id)
if err := c.stopPodSandbox(ctx, sandbox); err != nil {
return nil, fmt.Errorf("failed to forcibly stop sandbox %q: %w", id, err)
}
// Return error if sandbox network namespace is not closed yet.
if sandbox.NetNS != nil {
nsPath := sandbox.NetNS.GetPath()
if closed, err := sandbox.NetNS.Closed(); err != nil {
return nil, fmt.Errorf("failed to check sandbox network namespace %q closed: %w", nsPath, err)
} else if !closed {
return nil, fmt.Errorf("sandbox network namespace %q is not fully closed", nsPath)
}
}
// Remove all containers inside the sandbox.
// NOTE(random-liu): container could still be created after this point, Kubelet should
// not rely on this behavior.
// TODO(random-liu): Introduce an intermediate state to avoid container creation after
// this point.
cntrs := c.containerStore.List()
for _, cntr := range cntrs {
if cntr.SandboxID != id {
continue
}
_, err = c.RemoveContainer(ctx, &runtime.RemoveContainerRequest{ContainerId: cntr.ID})
if err != nil {
return nil, fmt.Errorf("failed to remove container %q: %w", cntr.ID, err)
}
}
// Use sandbox controller to delete sandbox
controller, err := c.getSandboxController(sandbox.Config, sandbox.RuntimeHandler)
if err != nil {
return nil, fmt.Errorf("failed to get sandbox controller: %w", err)
}
if err := controller.Shutdown(ctx, id); err != nil && !errdefs.IsNotFound(err) {
return nil, fmt.Errorf("failed to delete sandbox %q: %w", id, err)
}
// Send CONTAINER_DELETED event with ContainerId equal to SandboxId.
c.generateAndSendContainerEvent(ctx, id, id, runtime.ContainerEventType_CONTAINER_DELETED_EVENT)
err = c.nri.RemovePodSandbox(ctx, &sandbox)
if err != nil {
log.G(ctx).WithError(err).Errorf("NRI pod removal notification failed")
}
// Remove sandbox from sandbox store. Note that once the sandbox is successfully
// deleted:
// 1) ListPodSandbox will not include this sandbox.
// 2) PodSandboxStatus and StopPodSandbox will return error.
// 3) On-going operations which have held the reference will not be affected.
c.sandboxStore.Delete(id)
if err := c.client.SandboxStore().Delete(ctx, id); err != nil {
if !errdefs.IsNotFound(err) {
return nil, fmt.Errorf("failed to remove sandbox metadata from store: %w", err)
}
log.G(ctx).WithError(err).Warnf("failed to delete sandbox metadata from store: %q maybe recovered from v1.x release", id)
}
// Release the sandbox name reserved for the sandbox.
c.sandboxNameIndex.ReleaseByKey(id)
sandboxRemoveTimer.WithValues(sandbox.RuntimeHandler).UpdateSince(start)
return &runtime.RemovePodSandboxResponse{}, nil
}