diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 5b35573cf5..2968d2d48c 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1773,6 +1773,15 @@ func (c *Container) mountStorage() (_ string, deferredErr error) { if err != nil { return "", fmt.Errorf("rootfs-overlay: failed to create TempDir in the %s directory: %w", overlayDest, err) } + + // Recreate the rootfs for infra container. It can be missing after system reboot if it's stored on tmpfs. + if c.IsDefaultInfra() || c.IsService() { + err := c.createInitRootfs() + if err != nil { + return "", err + } + } + overlayMount, err := overlay.Mount(contentDir, c.config.Rootfs, overlayDest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions()) if err != nil { return "", fmt.Errorf("rootfs-overlay: creating overlay failed %q: %w", c.config.Rootfs, err) diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index bc8ef31756..88ff2d9b2f 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -179,10 +179,26 @@ func getOverlayUpperAndWorkDir(options []string) (string, string, error) { } // Internal only function which creates the Rootfs for default internal -// pause image, configures the Rootfs in the Container and returns -// the mount-point for the /catatonit. This mount-point should be added -// to the Container spec. -func (c *Container) prepareInitRootfs() (spec.Mount, error) { +// pause image and configures the Rootfs in the Container. +func (c *Container) createInitRootfs() error { + tmpDir, err := c.runtime.TmpDir() + if err != nil { + return fmt.Errorf("getting runtime temporary directory: %w", err) + } + tmpDir = filepath.Join(tmpDir, "infra-container") + err = os.MkdirAll(tmpDir, 0755) + if err != nil { + return fmt.Errorf("creating infra container temporary directory: %w", err) + } + + c.config.Rootfs = tmpDir + c.config.RootfsOverlay = true + return nil +} + +// Internal only function which returns the mount-point for the /catatonit. +// This mount-point should be added to the Container spec. +func (c *Container) prepareCatatonitMount() (spec.Mount, error) { newMount := spec.Mount{ Type: define.TypeBind, Source: "", @@ -190,15 +206,6 @@ func (c *Container) prepareInitRootfs() (spec.Mount, error) { Options: append(bindOptions, "ro", "nosuid", "nodev"), } - tmpDir, err := c.runtime.TmpDir() - if err != nil { - return newMount, fmt.Errorf("getting runtime temporary directory: %w", err) - } - tmpDir = filepath.Join(tmpDir, "infra-container") - err = os.MkdirAll(tmpDir, 0755) - if err != nil { - return newMount, fmt.Errorf("creating infra container temporary directory: %w", err) - } // Also look into the path as some distributions install catatonit in // /usr/bin. catatonitPath, err := c.runtime.config.FindInitBinary() @@ -213,8 +220,6 @@ func (c *Container) prepareInitRootfs() (spec.Mount, error) { newMount.Source = catatonitPath newMount.Destination = "/" + filepath.Base(catatonitPath) - c.config.Rootfs = tmpDir - c.config.RootfsOverlay = true if len(c.config.Entrypoint) == 0 { c.config.Entrypoint = []string{"/" + filepath.Base(catatonitPath), "-P"} c.config.Spec.Process.Args = c.config.Entrypoint @@ -426,7 +431,7 @@ func (c *Container) generateSpec(ctx context.Context) (s *spec.Spec, cleanupFunc c.setMountLabel(&g) if c.IsDefaultInfra() || c.IsService() { - newMount, err := c.prepareInitRootfs() + newMount, err := c.prepareCatatonitMount() if err != nil { return nil, nil, err } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index a313621735..941d3e048c 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -250,7 +250,11 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Container, retErr error) { if ctr.IsDefaultInfra() || ctr.IsService() { - _, err := ctr.prepareInitRootfs() + err := ctr.createInitRootfs() + if err != nil { + return nil, err + } + _, err = ctr.prepareCatatonitMount() if err != nil { return nil, err } diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index aaa08e41f2..2cd38c5eba 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1475,6 +1475,27 @@ VOLUME %s`, ALPINE, volPath, volPath) Expect(numContainers).To(Equal(0)) }) + It("podman run after infra-container rootfs removed", func() { + // Regression test for #26190 + podmanTest.PodmanExitCleanly("run", "--name", "test", "--pod", "new:foobar", ALPINE, "ls") + + podInspect := podmanTest.PodmanExitCleanly("pod", "inspect", "foobar", "--format", "{{.InfraContainerID}}") + infraID := podInspect.OutputToString() + + infraInspect := podmanTest.PodmanExitCleanly("inspect", infraID, "--format", "{{.Rootfs}}") + rootfs := infraInspect.OutputToString() + + podmanTest.PodmanExitCleanly("pod", "stop", "foobar") + + _, statErr := os.Stat(rootfs) + Expect(statErr).ToNot(HaveOccurred()) + + err := os.RemoveAll(rootfs) + Expect(err).ToNot(HaveOccurred()) + + podmanTest.PodmanExitCleanly("run", "--replace", "--name", "test", "--pod", "foobar", ALPINE, "ls") + }) + It("podman run --rm failed container should delete itself", func() { session := podmanTest.Podman([]string{"run", "--name", "test", "--rm", ALPINE, "foo"}) session.WaitWithDefaultTimeout()