mirror of
https://github.com/containers/podman.git
synced 2025-09-17 06:47:10 +08:00

Also, do a general cleanup of all the timeout code. Changes include: - Convert from int to *uint where possible. Timeouts cannot be negative, hence the uint change; and a timeout of 0 is valid, so we need a new way to detect that the user set a timeout (hence, pointer). - Change name in the database to avoid conflicts between new data type and old one. This will cause timeouts set with 4.2.0 to be lost, but considering nobody is using the feature at present (and the lack of validation means we could have invalid, negative timeouts in the DB) this feels safe. - Ensure volume plugin timeouts can only be used with volumes created using a plugin. Timeouts on the local driver are nonsensical. - Remove the existing test, as it did not use a volume plugin. Write a new test that does. The actual plumbing of the containers.conf timeout in is one line in volume_api.go; the remainder are the above-described cleanups. Signed-off-by: Matthew Heon <mheon@redhat.com>
294 lines
12 KiB
Go
294 lines
12 KiB
Go
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
. "github.com/containers/podman/v4/test/utils"
|
|
"github.com/containers/storage/pkg/stringid"
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
. "github.com/onsi/gomega/gexec"
|
|
)
|
|
|
|
var _ = Describe("Podman volume plugins", func() {
|
|
var (
|
|
tempdir string
|
|
err error
|
|
podmanTest *PodmanTestIntegration
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
tempdir, err = CreateTempDirInTempDir()
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
podmanTest = PodmanTestCreate(tempdir)
|
|
podmanTest.Setup()
|
|
os.Setenv("CONTAINERS_CONF", "config/containers.conf")
|
|
SkipIfRemote("Volume plugins only supported as local")
|
|
SkipIfRootless("Root is required for volume plugin testing")
|
|
err = os.MkdirAll("/run/docker/plugins", 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
AfterEach(func() {
|
|
podmanTest.CleanupVolume()
|
|
f := CurrentGinkgoTestDescription()
|
|
processTestResult(f)
|
|
os.Unsetenv("CONTAINERS_CONF")
|
|
})
|
|
|
|
It("volume create with nonexistent plugin errors", func() {
|
|
session := podmanTest.Podman([]string{"volume", "create", "--driver", "notexist", "test_volume_name"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError())
|
|
})
|
|
|
|
It("volume create with not-running plugin does not error", func() {
|
|
session := podmanTest.Podman([]string{"volume", "create", "--driver", "testvol0", "test_volume_name"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError())
|
|
})
|
|
|
|
It("volume create and remove with running plugin succeeds", func() {
|
|
podmanTest.AddImageToRWStore(volumeTest)
|
|
|
|
pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
|
|
err := os.Mkdir(pluginStatePath, 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Keep this distinct within tests to avoid multiple tests using the same plugin.
|
|
pluginName := "testvol1"
|
|
plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
volName := "testVolume1"
|
|
create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName})
|
|
create.WaitWithDefaultTimeout()
|
|
Expect(create).Should(Exit(0))
|
|
|
|
ls1 := podmanTest.Podman([]string{"volume", "ls", "-q"})
|
|
ls1.WaitWithDefaultTimeout()
|
|
Expect(ls1).Should(Exit(0))
|
|
arrOutput := ls1.OutputToStringArray()
|
|
Expect(arrOutput).To(HaveLen(1))
|
|
Expect(arrOutput[0]).To(ContainSubstring(volName))
|
|
|
|
remove := podmanTest.Podman([]string{"volume", "rm", volName})
|
|
remove.WaitWithDefaultTimeout()
|
|
Expect(remove).Should(Exit(0))
|
|
|
|
ls2 := podmanTest.Podman([]string{"volume", "ls", "-q"})
|
|
ls2.WaitWithDefaultTimeout()
|
|
Expect(ls2).Should(Exit(0))
|
|
Expect(ls2.OutputToStringArray()).To(BeEmpty())
|
|
})
|
|
|
|
It("volume inspect with running plugin succeeds", func() {
|
|
podmanTest.AddImageToRWStore(volumeTest)
|
|
|
|
pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
|
|
err := os.Mkdir(pluginStatePath, 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Keep this distinct within tests to avoid multiple tests using the same plugin.
|
|
pluginName := "testvol2"
|
|
plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
volName := "testVolume1"
|
|
create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName})
|
|
create.WaitWithDefaultTimeout()
|
|
Expect(create).Should(Exit(0))
|
|
|
|
volInspect := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Driver }}", volName})
|
|
volInspect.WaitWithDefaultTimeout()
|
|
Expect(volInspect).Should(Exit(0))
|
|
Expect(volInspect.OutputToString()).To(ContainSubstring(pluginName))
|
|
})
|
|
|
|
It("remove plugin with stopped plugin succeeds", func() {
|
|
podmanTest.AddImageToRWStore(volumeTest)
|
|
|
|
pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
|
|
err := os.Mkdir(pluginStatePath, 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Keep this distinct within tests to avoid multiple tests using the same plugin.
|
|
pluginName := "testvol3"
|
|
ctrName := "pluginCtr"
|
|
plugin := podmanTest.Podman([]string{"run", "--name", ctrName, "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
volName := "testVolume1"
|
|
create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName})
|
|
create.WaitWithDefaultTimeout()
|
|
Expect(create).Should(Exit(0))
|
|
|
|
ls1 := podmanTest.Podman([]string{"volume", "ls", "-q"})
|
|
ls1.WaitWithDefaultTimeout()
|
|
Expect(ls1).Should(Exit(0))
|
|
arrOutput := ls1.OutputToStringArray()
|
|
Expect(arrOutput).To(HaveLen(1))
|
|
Expect(arrOutput[0]).To(ContainSubstring(volName))
|
|
|
|
stop := podmanTest.Podman([]string{"stop", "--timeout", "0", ctrName})
|
|
stop.WaitWithDefaultTimeout()
|
|
Expect(stop).Should(Exit(0))
|
|
|
|
// Remove should exit non-zero because missing plugin
|
|
remove := podmanTest.Podman([]string{"volume", "rm", volName})
|
|
remove.WaitWithDefaultTimeout()
|
|
Expect(remove).To(ExitWithError())
|
|
|
|
// But the volume should still be gone
|
|
ls2 := podmanTest.Podman([]string{"volume", "ls", "-q"})
|
|
ls2.WaitWithDefaultTimeout()
|
|
Expect(ls2).Should(Exit(0))
|
|
Expect(ls2.OutputToStringArray()).To(BeEmpty())
|
|
})
|
|
|
|
It("use plugin in containers", func() {
|
|
podmanTest.AddImageToRWStore(volumeTest)
|
|
|
|
pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
|
|
err := os.Mkdir(pluginStatePath, 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Keep this distinct within tests to avoid multiple tests using the same plugin.
|
|
pluginName := "testvol4"
|
|
plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
volName := "testVolume1"
|
|
create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName})
|
|
create.WaitWithDefaultTimeout()
|
|
Expect(create).Should(Exit(0))
|
|
|
|
ctr1Name := "ctr1"
|
|
ctr1 := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "--name", ctr1Name, "-v", fmt.Sprintf("%v:/test", volName), ALPINE, "sh", "-c", "touch /test/testfile && echo helloworld > /test/testfile"})
|
|
ctr1.WaitWithDefaultTimeout()
|
|
Expect(ctr1).Should(Exit(0))
|
|
|
|
ctr2Name := "ctr2"
|
|
ctr2 := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "--name", ctr2Name, "-v", fmt.Sprintf("%v:/test", volName), ALPINE, "cat", "/test/testfile"})
|
|
ctr2.WaitWithDefaultTimeout()
|
|
Expect(ctr2).Should(Exit(0))
|
|
Expect(ctr2.OutputToString()).To(ContainSubstring("helloworld"))
|
|
|
|
// HACK: `volume rm -f` is timing out trying to remove containers using the volume.
|
|
// Solution: remove them manually...
|
|
// TODO: fix this when I get back
|
|
rmAll := podmanTest.Podman([]string{"rm", "-f", ctr2Name, ctr1Name})
|
|
rmAll.WaitWithDefaultTimeout()
|
|
Expect(rmAll).Should(Exit(0))
|
|
})
|
|
|
|
It("podman volume reload", func() {
|
|
podmanTest.AddImageToRWStore(volumeTest)
|
|
|
|
confFile := filepath.Join(podmanTest.TempDir, "containers.conf")
|
|
err := os.WriteFile(confFile, []byte(`[engine]
|
|
[engine.volume_plugins]
|
|
testvol5 = "/run/docker/plugins/testvol5.sock"`), 0o644)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
os.Setenv("CONTAINERS_CONF", confFile)
|
|
|
|
pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
|
|
err = os.Mkdir(pluginStatePath, 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Keep this distinct within tests to avoid multiple tests using the same plugin.
|
|
pluginName := "testvol5"
|
|
ctrName := "pluginCtr"
|
|
plugin := podmanTest.Podman([]string{"run", "--name", ctrName, "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins",
|
|
"-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
localvol := "local-" + stringid.GenerateNonCryptoID()
|
|
// create local volume
|
|
session := podmanTest.Podman([]string{"volume", "create", localvol})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(Exit(0))
|
|
|
|
vol1 := "vol1-" + stringid.GenerateNonCryptoID()
|
|
session = podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, vol1})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(Exit(0))
|
|
|
|
// now create volume in plugin without podman
|
|
vol2 := "vol2-" + stringid.GenerateNonCryptoID()
|
|
plugin = podmanTest.Podman([]string{"exec", ctrName, "/usr/local/bin/testvol", "--sock-name", pluginName, "create", vol2})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
session = podmanTest.Podman([]string{"volume", "ls", "-q"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(Exit(0))
|
|
Expect(session.OutputToStringArray()).To(ContainElements(localvol, vol1))
|
|
Expect(session.ErrorToString()).To(Equal("")) // make sure no errors are shown
|
|
|
|
plugin = podmanTest.Podman([]string{"exec", ctrName, "/usr/local/bin/testvol", "--sock-name", pluginName, "remove", vol1})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
// now reload volumes from plugins
|
|
session = podmanTest.Podman([]string{"volume", "reload"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(Exit(0))
|
|
Expect(string(session.Out.Contents())).To(Equal(fmt.Sprintf(`Added:
|
|
%s
|
|
Removed:
|
|
%s
|
|
`, vol2, vol1)))
|
|
Expect(session.ErrorToString()).To(Equal("")) // make sure no errors are shown
|
|
|
|
session = podmanTest.Podman([]string{"volume", "ls", "-q"})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(Exit(0))
|
|
Expect(session.OutputToStringArray()).To(ContainElements(localvol, vol2))
|
|
Expect(session.ErrorToString()).To(Equal("")) // make no errors are shown
|
|
})
|
|
|
|
It("volume driver timeouts test", func() {
|
|
podmanTest.AddImageToRWStore(volumeTest)
|
|
|
|
pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
|
|
err := os.Mkdir(pluginStatePath, 0755)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Keep this distinct within tests to avoid multiple tests using the same plugin.
|
|
pluginName := "testvol6"
|
|
plugin := podmanTest.Podman([]string{"run", "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins", "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
|
|
plugin.WaitWithDefaultTimeout()
|
|
Expect(plugin).Should(Exit(0))
|
|
|
|
volName := "testVolume1"
|
|
create := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, volName})
|
|
create.WaitWithDefaultTimeout()
|
|
Expect(create).Should(Exit(0))
|
|
|
|
volInspect := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Timeout }}", volName})
|
|
volInspect.WaitWithDefaultTimeout()
|
|
Expect(volInspect).Should(Exit(0))
|
|
Expect(volInspect.OutputToString()).To(ContainSubstring("15"))
|
|
|
|
volName2 := "testVolume2"
|
|
create2 := podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, "--opt", "o=timeout=3", volName2})
|
|
create2.WaitWithDefaultTimeout()
|
|
Expect(create2).Should(Exit(0))
|
|
|
|
volInspect2 := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Timeout }}", volName2})
|
|
volInspect2.WaitWithDefaultTimeout()
|
|
Expect(volInspect2).Should(Exit(0))
|
|
Expect(volInspect2.OutputToString()).To(ContainSubstring("3"))
|
|
})
|
|
})
|