mirror of
https://github.com/containers/podman.git
synced 2025-10-16 02:32:55 +08:00

Add the Go bindings implementation necessary to support Artifacts. Implement the tunnel interface that consumes the Artifacts Go bindings. With this patch, users of the Podman remote clients will now be able to manage OCI artifacts via the Podman CLI and Podman machine. Jira: https://issues.redhat.com/browse/RUN-2714# Signed-off-by: Lewis Roy <lewis@redhat.com>
249 lines
7.5 KiB
Go
249 lines
7.5 KiB
Go
//go:build linux || freebsd
|
|
|
|
package integration
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
. "github.com/containers/podman/v5/test/utils"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Podman artifact mount", func() {
|
|
It("podman artifact mount single blob", func() {
|
|
podmanTest.PodmanExitCleanly("artifact", "pull", ARTIFACT_SINGLE)
|
|
|
|
const artifactContent = "mRuO9ykak1Q2j"
|
|
|
|
tests := []struct {
|
|
name string
|
|
mountOpts string
|
|
containerFile string
|
|
}{
|
|
{
|
|
name: "single artifact mount",
|
|
mountOpts: "dst=/test",
|
|
containerFile: "/test",
|
|
},
|
|
{
|
|
name: "single artifact mount on existing file",
|
|
mountOpts: "dst=/etc/os-release",
|
|
containerFile: "/etc/os-release",
|
|
},
|
|
{
|
|
name: "single artifact mount with title",
|
|
mountOpts: "dst=/tmp,title=testfile",
|
|
containerFile: "/tmp/testfile",
|
|
},
|
|
{
|
|
name: "single artifact mount with digest",
|
|
mountOpts: "dst=/data,digest=sha256:e9510923578af3632946ecf5ae479c1b5f08b47464e707b5cbab9819272a9752",
|
|
containerFile: "/data",
|
|
},
|
|
{
|
|
name: "single artifact mount with name",
|
|
mountOpts: "dst=/tmp,name=abcd",
|
|
containerFile: "/tmp/abcd",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
By(tt.name)
|
|
// FIXME: we need https://github.com/containers/container-selinux/pull/360 to fix the selinux access problem, until then disable it.
|
|
session := podmanTest.PodmanExitCleanly("run", "--security-opt=label=disable", "--rm", "--mount", "type=artifact,src="+ARTIFACT_SINGLE+","+tt.mountOpts, ALPINE, "cat", tt.containerFile)
|
|
Expect(session.OutputToString()).To(Equal(artifactContent))
|
|
}
|
|
})
|
|
|
|
It("podman artifact mount multi blob", func() {
|
|
podmanTest.PodmanExitCleanly("artifact", "pull", ARTIFACT_MULTI)
|
|
podmanTest.PodmanExitCleanly("artifact", "pull", ARTIFACT_MULTI_NO_TITLE)
|
|
|
|
const (
|
|
artifactContent1 = "xuHWedtC0ADST"
|
|
artifactContent2 = "tAyZczFlgFsi4"
|
|
)
|
|
|
|
type expectedFiles struct {
|
|
file string
|
|
content string
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
mountOpts string
|
|
containerFiles []expectedFiles
|
|
}{
|
|
{
|
|
name: "multi blob with title",
|
|
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/test",
|
|
containerFiles: []expectedFiles{
|
|
{
|
|
file: "/test/test1",
|
|
content: artifactContent1,
|
|
},
|
|
{
|
|
file: "/test/test2",
|
|
content: artifactContent2,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multi blob without title",
|
|
mountOpts: "src=" + ARTIFACT_MULTI_NO_TITLE + ",dst=/test",
|
|
containerFiles: []expectedFiles{
|
|
{
|
|
file: "/test/sha256-8257bba28b9d19ac353c4b713b470860278857767935ef7e139afd596cb1bb2d",
|
|
content: artifactContent1,
|
|
},
|
|
{
|
|
file: "/test/sha256-63700c54129c6daaafe3a20850079f82d6d658d69de73d6158d81f920c6fbdd7",
|
|
content: artifactContent2,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multi blob filter by title on non existing file",
|
|
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/test,title=test2",
|
|
containerFiles: []expectedFiles{
|
|
{
|
|
file: "/test",
|
|
content: artifactContent2,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multi blob filter by title on existing file",
|
|
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/tmp,title=test2",
|
|
containerFiles: []expectedFiles{
|
|
{
|
|
file: "/tmp/test2",
|
|
content: artifactContent2,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multi blob filter by digest",
|
|
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/tmp,digest=sha256:8257bba28b9d19ac353c4b713b470860278857767935ef7e139afd596cb1bb2d",
|
|
containerFiles: []expectedFiles{
|
|
{
|
|
file: "/tmp/sha256-8257bba28b9d19ac353c4b713b470860278857767935ef7e139afd596cb1bb2d",
|
|
content: artifactContent1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "multi blob with name",
|
|
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/test,name=myname",
|
|
containerFiles: []expectedFiles{
|
|
{
|
|
file: "/test/myname-0",
|
|
content: artifactContent1,
|
|
},
|
|
{
|
|
file: "/test/myname-1",
|
|
content: artifactContent2,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
By(tt.name)
|
|
// FIXME: we need https://github.com/containers/container-selinux/pull/360 to fix the selinux access problem, until then disable it.
|
|
args := []string{"run", "--security-opt=label=disable", "--rm", "--mount", "type=artifact," + tt.mountOpts, ALPINE, "cat"}
|
|
for _, f := range tt.containerFiles {
|
|
args = append(args, f.file)
|
|
}
|
|
session := podmanTest.PodmanExitCleanly(args...)
|
|
outs := session.OutputToStringArray()
|
|
Expect(outs).To(HaveLen(len(tt.containerFiles)))
|
|
for i, f := range tt.containerFiles {
|
|
Expect(outs[i]).To(Equal(f.content))
|
|
}
|
|
}
|
|
})
|
|
|
|
It("podman artifact mount remove while in use", func() {
|
|
ctrName := "ctr1"
|
|
artifactName := "localhost/test"
|
|
artifactFileName := "somefile"
|
|
|
|
artifactFile := filepath.Join(podmanTest.TempDir, artifactFileName)
|
|
err := os.WriteFile(artifactFile, []byte("hello world\n"), 0o644)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
podmanTest.PodmanExitCleanly("artifact", "add", artifactName, artifactFile)
|
|
|
|
// FIXME: we need https://github.com/containers/container-selinux/pull/360 to fix the selinux access problem, until then disable it.
|
|
podmanTest.PodmanExitCleanly("run", "--security-opt=label=disable", "--name", ctrName, "-d", "--mount", "type=artifact,src="+artifactName+",dst=/tmp", ALPINE, "sleep", "100")
|
|
|
|
podmanTest.PodmanExitCleanly("artifact", "rm", artifactName)
|
|
|
|
// file must sill be readable after artifact removal
|
|
session := podmanTest.PodmanExitCleanly("exec", ctrName, "cat", "/tmp/"+artifactFileName)
|
|
Expect(session.OutputToString()).To(Equal("hello world"))
|
|
|
|
// restart will fail if artifact does not exist
|
|
session = podmanTest.Podman([]string{"restart", "-t0", ctrName})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError(125, artifactName+": artifact does not exist"))
|
|
|
|
// create a artifact with the same name again and add another file to ensure it picks up the changes
|
|
artifactFile2Name := "otherfile"
|
|
artifactFile2 := filepath.Join(podmanTest.TempDir, artifactFile2Name)
|
|
err = os.WriteFile(artifactFile2, []byte("second file"), 0o644)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
podmanTest.PodmanExitCleanly("artifact", "add", artifactName, artifactFile, artifactFile2)
|
|
podmanTest.PodmanExitCleanly("start", ctrName)
|
|
|
|
session = podmanTest.PodmanExitCleanly("exec", ctrName, "cat", "/tmp/"+artifactFileName, "/tmp/"+artifactFile2Name)
|
|
Expect(session.OutputToString()).To(Equal("hello world second file"))
|
|
})
|
|
|
|
It("podman artifact mount dest conflict", func() {
|
|
tests := []struct {
|
|
name string
|
|
mount string
|
|
}{
|
|
{
|
|
name: "bind mount --volume",
|
|
mount: "--volume=/tmp:/test",
|
|
},
|
|
{
|
|
name: "overlay mount",
|
|
mount: "--volume=/tmp:/test:O",
|
|
},
|
|
{
|
|
name: "named volume",
|
|
mount: "--volume=abc:/test:O",
|
|
},
|
|
{
|
|
name: "bind mount --mount type=bind",
|
|
mount: "--mount=type=bind,src=/tmp,dst=/test",
|
|
},
|
|
{
|
|
name: "image mount",
|
|
mount: "--mount=type=bind,src=someimage,dst=/test",
|
|
},
|
|
{
|
|
name: "tmpfs mount",
|
|
mount: "--tmpfs=/test",
|
|
},
|
|
{
|
|
name: "artifact mount",
|
|
mount: "--mount=type=artifact,src=abc,dst=/test",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
By(tt.name)
|
|
session := podmanTest.Podman([]string{"run", "--rm", "--mount", "type=artifact,src=someartifact,dst=/test", tt.mount, ALPINE})
|
|
session.WaitWithDefaultTimeout()
|
|
Expect(session).To(ExitWithError(125, "/test: duplicate mount destination"))
|
|
}
|
|
})
|
|
})
|