From 759fc933438dead681a0c4f3d9e17826b0dc18cc Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Mon, 15 Feb 2021 11:58:24 -0500 Subject: [PATCH] Fix an issue where copyup could fail with ENOENT This one is rather bizarre because it triggers only on some systems. I've included a CI test, for example, but I'm 99% sure we use images in CI that have volumes over empty directories, and the earlier patch to change copy-up implementation passed CI without complaint. I can reproduce this on a stock F33 VM, but that's the only place I have been able to see it. Regardless, the issue: under certain as-yet-unidentified environmental conditions, the copier.Get method will return an ENOENT attempting to stream a directory that is empty. Work around this by avoiding the copy altogether in this case. Signed-off-by: Matthew Heon --- libpod/container_internal.go | 11 +++++++++++ test/e2e/run_volume_test.go | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index ced357096f..ca0e082ff0 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1617,6 +1617,17 @@ func (c *Container) mountNamedVolume(v *ContainerNamedVolume, mountpoint string) if !srcStat.IsDir() { return vol, nil } + // Read contents, do not bother continuing if it's empty. Fixes + // a bizarre issue where something copier.Get will ENOENT on + // empty directories and sometimes it will not. + // RHBZ#1928643 + srcContents, err := ioutil.ReadDir(srcDir) + if err != nil { + return nil, errors.Wrapf(err, "error reading contents of source directory for copy up into volume %s", vol.Name()) + } + if len(srcContents) == 0 { + return vol, nil + } // Buildah Copier accepts a reader, so we'll need a pipe. reader, writer := io.Pipe() diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 19d82c9749..91d8f15f4b 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -322,6 +322,18 @@ RUN sh -c "cd /etc/apk && ln -s ../../testfile"` Expect(outputSession.OutputToString()).To(Equal(baselineOutput)) }) + It("podman named volume copyup empty directory", func() { + baselineSession := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", ALPINE, "ls", "/srv"}) + baselineSession.WaitWithDefaultTimeout() + Expect(baselineSession.ExitCode()).To(Equal(0)) + baselineOutput := baselineSession.OutputToString() + + outputSession := podmanTest.Podman([]string{"run", "-t", "-i", "-v", "/srv", ALPINE, "ls", "/srv"}) + outputSession.WaitWithDefaultTimeout() + Expect(outputSession.ExitCode()).To(Equal(0)) + Expect(outputSession.OutputToString()).To(Equal(baselineOutput)) + }) + It("podman read-only tmpfs conflict with volume", func() { session := podmanTest.Podman([]string{"run", "--rm", "-t", "-i", "--read-only", "-v", "tmp_volume:" + dest, ALPINE, "touch", dest + "/a"}) session.WaitWithDefaultTimeout()