Add support for 'image' volume driver

We added the concept of image volumes in 2.2.0, to support
inspecting an image from within a container. However, this is a
strictly read-only mount, with no modification allowed.

By contrast, the new `image` volume driver creates a c/storage
container as its underlying storage, so we have a read/write
layer. This, in and of itself, is not especially interesting, but
what it will enable in the future is. If we add a new command to
allow these image volumes to be committed, we can now distribute
volumes - and changes to them - via a standard OCI image registry
(which is rather new and quite exciting).

Future work in this area:
- Add support for `podman volume push` (commit volume changes and
  push resulting image to OCI registry).
- Add support for `podman volume pull` (currently, we require
  that the image a volume is created from be already pulled; it
  would be simpler if we had a dedicated command that did the
  pull and made a volume from it)
- Add support for scratch images (make an empty image on demand
  to use as the base of the volume)
- Add UOR support to `podman volume push` and
  `podman volume pull` to enable both with non-image volume
  drivers

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
Matthew Heon
2022-09-16 15:00:37 -04:00
committed by Matthew Heon
parent 08993516a9
commit fc6dcd12b3
18 changed files with 289 additions and 9 deletions

View File

@@ -76,3 +76,4 @@ testvol6 = "/run/docker/plugins/testvol6.sock"
testvol7 = "/run/docker/plugins/testvol7.sock"
testvol8 = "/run/docker/plugins/testvol8.sock"
testvol9 = "/run/docker/plugins/testvol9.sock"
image = "/run/docker/plugins/image.sock"

View File

@@ -162,4 +162,58 @@ var _ = Describe("Podman volume create", func() {
Expect(inspectOpts).Should(Exit(0))
Expect(inspectOpts.OutputToString()).To(Equal(optionStrFormatExpect))
})
It("image-backed volume basic functionality", func() {
podmanTest.AddImageToRWStore(fedoraMinimal)
volName := "testvol"
volCreate := podmanTest.Podman([]string{"volume", "create", "--driver", "image", "--opt", fmt.Sprintf("image=%s", fedoraMinimal), volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(Exit(0))
runCmd := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "cat", "/test/etc/redhat-release"})
runCmd.WaitWithDefaultTimeout()
Expect(runCmd).Should(Exit(0))
Expect(runCmd.OutputToString()).To(ContainSubstring("Fedora"))
rmCmd := podmanTest.Podman([]string{"rmi", "--force", fedoraMinimal})
rmCmd.WaitWithDefaultTimeout()
Expect(rmCmd).Should(Exit(0))
psCmd := podmanTest.Podman([]string{"ps", "-aq"})
psCmd.WaitWithDefaultTimeout()
Expect(psCmd).Should(Exit(0))
Expect(psCmd.OutputToString()).To(BeEmpty())
volumesCmd := podmanTest.Podman([]string{"volume", "ls", "-q"})
volumesCmd.WaitWithDefaultTimeout()
Expect(volumesCmd).Should(Exit(0))
Expect(volumesCmd.OutputToString()).To(Not(ContainSubstring(volName)))
})
It("image-backed volume force removal", func() {
podmanTest.AddImageToRWStore(fedoraMinimal)
volName := "testvol"
volCreate := podmanTest.Podman([]string{"volume", "create", "--driver", "image", "--opt", fmt.Sprintf("image=%s", fedoraMinimal), volName})
volCreate.WaitWithDefaultTimeout()
Expect(volCreate).Should(Exit(0))
runCmd := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/test", volName), ALPINE, "cat", "/test/etc/redhat-release"})
runCmd.WaitWithDefaultTimeout()
Expect(runCmd).Should(Exit(0))
Expect(runCmd.OutputToString()).To(ContainSubstring("Fedora"))
rmCmd := podmanTest.Podman([]string{"volume", "rm", "--force", volName})
rmCmd.WaitWithDefaultTimeout()
Expect(rmCmd).Should(Exit(0))
psCmd := podmanTest.Podman([]string{"ps", "-aq"})
psCmd.WaitWithDefaultTimeout()
Expect(psCmd).Should(Exit(0))
Expect(psCmd.OutputToString()).To(BeEmpty())
volumesCmd := podmanTest.Podman([]string{"volume", "ls", "-q"})
volumesCmd.WaitWithDefaultTimeout()
Expect(volumesCmd).Should(Exit(0))
Expect(volumesCmd.OutputToString()).To(Not(ContainSubstring(volName)))
})
})

View File

@@ -60,7 +60,8 @@ var _ = Describe("Podman volume plugins", func() {
Expect(err).ToNot(HaveOccurred())
// Keep this distinct within tests to avoid multiple tests using the same plugin.
pluginName := "testvol1"
// This one verifies that the "image" plugin uses a volume plugin, not the "image" driver.
pluginName := "image"
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))
@@ -77,6 +78,12 @@ var _ = Describe("Podman volume plugins", func() {
Expect(arrOutput).To(HaveLen(1))
Expect(arrOutput[0]).To(ContainSubstring(volName))
// Verify this is not an image volume.
inspect := podmanTest.Podman([]string{"volume", "inspect", volName, "--format", "{{.StorageID}}"})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))
Expect(inspect.OutputToString()).To(BeEmpty())
remove := podmanTest.Podman([]string{"volume", "rm", volName})
remove.WaitWithDefaultTimeout()
Expect(remove).Should(Exit(0))