From b554b577b05b1663931fcc3c792d60fb1a157020 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Tue, 5 Oct 2021 10:01:41 -0700 Subject: [PATCH] Move shim restore to a separate file Signed-off-by: Maksym Pavlenko --- runtime/v2/shim_load.go | 151 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 runtime/v2/shim_load.go diff --git a/runtime/v2/shim_load.go b/runtime/v2/shim_load.go new file mode 100644 index 000000000..9dcfccf09 --- /dev/null +++ b/runtime/v2/shim_load.go @@ -0,0 +1,151 @@ +/* + 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 v2 + +import ( + "context" + "os" + "path/filepath" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/events/exchange" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/runtime" +) + +func loadExistingTasks(ic *plugin.InitContext, list *runtime.TaskList, events *exchange.Exchange, containers containers.Store) error { + var ( + ctx = ic.Context + state = ic.State + root = ic.Root + containerdAddress = ic.Address + containerdTTRPCAddress = ic.TTRPCAddress + ) + + nsDirs, err := os.ReadDir(state) + if err != nil { + return err + } + for _, nsd := range nsDirs { + if !nsd.IsDir() { + continue + } + ns := nsd.Name() + // skip hidden directories + if len(ns) > 0 && ns[0] == '.' { + continue + } + log.G(ctx).WithField("namespace", ns).Debug("loading tasks in namespace") + if err := loadShims(namespaces.WithNamespace(ctx, ns), state, list, events, containers, containerdAddress, containerdTTRPCAddress); err != nil { + log.G(ctx).WithField("namespace", ns).WithError(err).Error("loading tasks in namespace") + continue + } + if err := cleanupWorkDirs(namespaces.WithNamespace(ctx, ns), root, list); err != nil { + log.G(ctx).WithField("namespace", ns).WithError(err).Error("cleanup working directory in namespace") + continue + } + } + + return nil +} + +func loadShims(ctx context.Context, state string, list *runtime.TaskList, events *exchange.Exchange, containers containers.Store, containerdAddress string, containerdTTRPCAddress string) error { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + shimDirs, err := os.ReadDir(filepath.Join(state, ns)) + if err != nil { + return err + } + for _, sd := range shimDirs { + if !sd.IsDir() { + continue + } + id := sd.Name() + // skip hidden directories + if len(id) > 0 && id[0] == '.' { + continue + } + bundle, err := LoadBundle(ctx, state, id) + if err != nil { + // fine to return error here, it is a programmer error if the context + // does not have a namespace + return err + } + // fast path + bf, err := os.ReadDir(bundle.Path) + if err != nil { + bundle.Delete() + log.G(ctx).WithError(err).Errorf("fast path read bundle path for %s", bundle.Path) + continue + } + if len(bf) == 0 { + bundle.Delete() + continue + } + container, err := containers.Get(ctx, id) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading container %s", id) + if err := mount.UnmountAll(filepath.Join(bundle.Path, "rootfs"), 0); err != nil { + log.G(ctx).WithError(err).Errorf("forceful unmount of rootfs %s", id) + } + bundle.Delete() + continue + } + binaryCall := shimBinary(bundle, container.Runtime.Name, containerdAddress, containerdTTRPCAddress) + shim, err := loadShim(ctx, bundle, func() { + log.G(ctx).WithField("id", id).Info("shim disconnected") + + cleanupAfterDeadShim(context.Background(), id, ns, list, events, binaryCall) + // Remove self from the runtime task list. + list.Delete(ctx, id) + }) + if err != nil { + cleanupAfterDeadShim(ctx, id, ns, list, events, binaryCall) + continue + } + list.Add(ctx, shim) + } + return nil +} + +func cleanupWorkDirs(ctx context.Context, root string, list *runtime.TaskList) error { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + dirs, err := os.ReadDir(filepath.Join(root, ns)) + if err != nil { + return err + } + for _, d := range dirs { + // if the task was not loaded, cleanup and empty working directory + // this can happen on a reboot where /run for the bundle state is cleaned up + // but that persistent working dir is left + if _, err := list.Get(ctx, d.Name()); err != nil { + path := filepath.Join(root, ns, d.Name()) + if err := os.RemoveAll(path); err != nil { + log.G(ctx).WithError(err).Errorf("cleanup working dir %s", path) + } + } + } + return nil +}