diff --git a/internal/config/nsmgr/types.go b/internal/config/nsmgr/types.go index c7c7aaa08bd..72f665415b4 100644 --- a/internal/config/nsmgr/types.go +++ b/internal/config/nsmgr/types.go @@ -51,7 +51,10 @@ type Namespace interface { // Type returns the namespace type (net, ipc, user, pid or uts). Type() NSType - // Remove ensures this namespace is closed and removed. + // Close ensures this namespace is closed. + Close() error + + // Remove ensures this namespace is removed. Remove() error } @@ -84,13 +87,13 @@ func (n *namespace) Type() NSType { return n.nsType } -// Remove ensures this namespace is closed and removed. -func (n *namespace) Remove() error { +// Close ensures this namespace is closed. +func (n *namespace) Close() error { n.Lock() defer n.Unlock() if n.closed { - // Remove() can be called multiple + // Close() can be called multiple // times without returning an error. return nil } @@ -101,16 +104,29 @@ func (n *namespace) Remove() error { n.closed = true - fp := n.Path() - if fp == "" { + if n.nsPath == "" { return nil } // try to unmount, ignoring "not mounted" (EINVAL) error. - if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil && err != unix.EINVAL { - return errors.Wrapf(err, "unable to unmount %s", fp) + if err := unix.Unmount(n.nsPath, unix.MNT_DETACH); err != nil && err != unix.EINVAL { + return errors.Wrapf(err, "unable to unmount %s", n.nsPath) + } + return nil +} + +// Remove ensures this namespace is closed and removed. +func (n *namespace) Remove() error { + n.Lock() + defer n.Unlock() + if !n.closed { + return errors.New("Namespace must be closed before it can be removed") + } + + if n.nsPath == "" { + return nil } - return os.RemoveAll(fp) + return os.Remove(n.nsPath) } // GetNamespace takes a path and type, checks if it is a namespace, and if so @@ -118,6 +134,10 @@ func (n *namespace) Remove() error { func GetNamespace(nsPath string, nsType NSType) (Namespace, error) { ns, err := nspkg.GetNS(nsPath) if err != nil { + // path exists but is not an NS, the namespace must have been closed + if _, ok := err.(nspkg.NSPathNotNSErr); ok { + return &namespace{nsType: nsType, nsPath: nsPath, closed: true}, nil + } return nil, err } diff --git a/internal/lib/container_server.go b/internal/lib/container_server.go index 2f5f6ef27ef..656fe3385c6 100644 --- a/internal/lib/container_server.go +++ b/internal/lib/container_server.go @@ -209,26 +209,6 @@ func (c *ContainerServer) LoadSandbox(ctx context.Context, id string) (sb *sandb } } }() - // We add an NS only if we can load a permanent one. - // Otherwise, the sandbox will live in the host namespace. - namespacesToJoin := []struct { - rspecNS rspec.LinuxNamespaceType - joinFunc func(string) error - }{ - {rspecNS: rspec.NetworkNamespace, joinFunc: sb.NetNsJoin}, - {rspecNS: rspec.IPCNamespace, joinFunc: sb.IpcNsJoin}, - {rspecNS: rspec.UTSNamespace, joinFunc: sb.UtsNsJoin}, - {rspecNS: rspec.UserNamespace, joinFunc: sb.UserNsJoin}, - } - for _, namespaceToJoin := range namespacesToJoin { - path, err := configNsPath(&m, namespaceToJoin.rspecNS) - if err == nil { - if nsErr := namespaceToJoin.joinFunc(path); nsErr != nil { - return sb, nsErr - } - } - } - if err := c.AddSandbox(sb); err != nil { return sb, err } @@ -293,6 +273,31 @@ func (c *ContainerServer) LoadSandbox(ctx context.Context, id string) (sb *sandb scontainer = oci.NewSpoofedContainer(cID, cname, labels, id, created, sandboxPath) } + if err := sb.SetInfraContainer(scontainer); err != nil { + return sb, err + } + + sb.RestoreStopped() + // We add an NS only if we can load a permanent one. + // Otherwise, the sandbox will live in the host namespace. + namespacesToJoin := []struct { + rspecNS rspec.LinuxNamespaceType + joinFunc func(string) error + }{ + {rspecNS: rspec.NetworkNamespace, joinFunc: sb.NetNsJoin}, + {rspecNS: rspec.IPCNamespace, joinFunc: sb.IpcNsJoin}, + {rspecNS: rspec.UTSNamespace, joinFunc: sb.UtsNsJoin}, + {rspecNS: rspec.UserNamespace, joinFunc: sb.UserNsJoin}, + } + for _, namespaceToJoin := range namespacesToJoin { + path, err := configNsPath(&m, namespaceToJoin.rspecNS) + if err == nil { + if nsErr := namespaceToJoin.joinFunc(path); nsErr != nil { + return sb, nsErr + } + } + } + if err := c.ContainerStateFromDisk(ctx, scontainer); err != nil { return sb, fmt.Errorf("error reading sandbox state from disk %q: %v", scontainer.ID(), err) } @@ -303,17 +308,11 @@ func (c *ContainerServer) LoadSandbox(ctx context.Context, id string) (sb *sandb return sb, fmt.Errorf("failed to write container %q state to disk: %v", scontainer.ID(), err) } - if err := sb.SetInfraContainer(scontainer); err != nil { - return sb, err - } - sb.SetCreated() if err := label.ReserveLabel(processLabel); err != nil { return sb, err } - sb.RestoreStopped() - if err := c.ctrIDIndex.Add(scontainer.ID()); err != nil { return sb, err } diff --git a/internal/lib/sandbox/namespaces.go b/internal/lib/sandbox/namespaces.go index 1c2f18e237f..0bd9befbb7f 100644 --- a/internal/lib/sandbox/namespaces.go +++ b/internal/lib/sandbox/namespaces.go @@ -91,29 +91,34 @@ func (s *Sandbox) NamespacePaths() []*ManagedNamespace { return typesAndPaths } -// RemoveManagedNamespaces cleans up after managing the namespaces. It removes all of the namespaces -// and the parent directory in which they lived. +// CloseManagedNamespaces cleans up after managing the namespaces. +// It unmounts all of the namespaces, but does not remove their parent directory. +func (s *Sandbox) CloseManagedNamespaces() error { + return s.runFunctionOnNamespaces(func(ns nsmgr.Namespace) error { + return ns.Close() + }) +} + +// RemoveManagedNamespaces removes the formerly mounted namespace. +// Must be stopped first or this will fail. func (s *Sandbox) RemoveManagedNamespaces() error { + return s.runFunctionOnNamespaces(func(ns nsmgr.Namespace) error { + if err := ns.Close(); err != nil { + return err + } + return ns.Remove() + }) +} + +func (s *Sandbox) runFunctionOnNamespaces(toRun func(nsmgr.Namespace) error) error { errs := make([]error, 0) - // use a map as a set to delete each parent directory just once - if s.utsns != nil { - if err := s.utsns.Remove(); err != nil { - errs = append(errs, err) - } - } - if s.ipcns != nil { - if err := s.ipcns.Remove(); err != nil { - errs = append(errs, err) - } - } - if s.netns != nil { - if err := s.netns.Remove(); err != nil { - errs = append(errs, err) + allNamespaces := []nsmgr.Namespace{s.utsns, s.ipcns, s.netns, s.userns} + for _, ns := range allNamespaces { + if ns == nil { + continue } - } - if s.userns != nil { - if err := s.userns.Remove(); err != nil { + if err := toRun(ns); err != nil { errs = append(errs, err) } } diff --git a/internal/lib/sandbox/namespaces_test.go b/internal/lib/sandbox/namespaces_test.go index 1434ee9d43b..f997eb29a23 100644 --- a/internal/lib/sandbox/namespaces_test.go +++ b/internal/lib/sandbox/namespaces_test.go @@ -23,6 +23,10 @@ func (s *spoofedIface) Type() nsmgr.NSType { return s.nsType } +func (s *spoofedIface) Close() error { + return nil +} + func (s *spoofedIface) Remove() error { s.removed = true return nil @@ -211,39 +215,6 @@ var _ = t.Describe("SandboxManagedNamespaces", func() { // When err := testSandbox.UserNsJoin("/proc/self/ns/user") - // Then - Expect(err).NotTo(BeNil()) - }) - It("should fail when asked to join a non-namespace", func() { - // Given - // When - err := testSandbox.NetNsJoin("/tmp") - - // Then - Expect(err).NotTo(BeNil()) - }) - It("should fail when asked to join a non-namespace", func() { - // Given - - // When - err := testSandbox.IpcNsJoin("/tmp") - - // Then - Expect(err).NotTo(BeNil()) - }) - It("should fail when asked to join a non-namespace", func() { - // Given - // When - err := testSandbox.UtsNsJoin("/tmp") - - // Then - Expect(err).NotTo(BeNil()) - }) - It("should fail when asked to join a non-namespace", func() { - // Given - // When - err := testSandbox.UserNsJoin("/tmp") - // Then Expect(err).NotTo(BeNil()) }) diff --git a/server/sandbox_stop_linux.go b/server/sandbox_stop_linux.go index ce2674f2af0..5e2f53f15ac 100644 --- a/server/sandbox_stop_linux.go +++ b/server/sandbox_stop_linux.go @@ -88,6 +88,10 @@ func (s *Server) stopPodSandbox(ctx context.Context, sb *sandbox.Sandbox) error } } + if err := sb.CloseManagedNamespaces(); err != nil { + return errors.Wrap(err, "unable to close managed namespaces") + } + if err := sb.UnmountShm(); err != nil { return err }