mirror of
https://github.com/containers/podman.git
synced 2025-10-17 11:14:40 +08:00
Merge pull request #25397 from Luap99/artifact-mount
add artifact mount support
This commit is contained in:
223
test/e2e/artifact_mount_test.go
Normal file
223
test/e2e/artifact_mount_test.go
Normal file
@ -0,0 +1,223 @@
|
||||
//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() {
|
||||
BeforeEach(func() {
|
||||
SkipIfRemote("artifacts are not supported on the remote client yet due to being in development still")
|
||||
})
|
||||
|
||||
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/testfile",
|
||||
},
|
||||
{
|
||||
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/sha256-e9510923578af3632946ecf5ae479c1b5f08b47464e707b5cbab9819272a9752",
|
||||
},
|
||||
}
|
||||
|
||||
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",
|
||||
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/test,title=test2",
|
||||
containerFiles: []expectedFiles{
|
||||
{
|
||||
file: "/test/test2",
|
||||
content: artifactContent2,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multi blob filter by digest",
|
||||
mountOpts: "src=" + ARTIFACT_MULTI + ",dst=/test,digest=sha256:8257bba28b9d19ac353c4b713b470860278857767935ef7e139afd596cb1bb2d",
|
||||
containerFiles: []expectedFiles{
|
||||
{
|
||||
file: "/test/sha256-8257bba28b9d19ac353c4b713b470860278857767935ef7e139afd596cb1bb2d",
|
||||
content: artifactContent1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
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=/test", ALPINE, "sleep", "100")
|
||||
|
||||
podmanTest.PodmanExitCleanly("artifact", "rm", artifactName)
|
||||
|
||||
// file must sill be readable after artifact removal
|
||||
session := podmanTest.PodmanExitCleanly("exec", ctrName, "cat", "/test/"+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", "/test/"+artifactFileName, "/test/"+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"))
|
||||
}
|
||||
})
|
||||
})
|
@ -475,7 +475,7 @@ var _ = Describe("Podman artifact", func() {
|
||||
a := podmanTest.InspectArtifact(artifact1Name)
|
||||
|
||||
Expect(a.Manifest.Layers).To(HaveLen(1))
|
||||
Expect(a.TotalSizeBytes()).To(Equal(int64(524288)))
|
||||
Expect(a.TotalSizeBytes()).To(Equal(int64(1024)))
|
||||
})
|
||||
|
||||
It("podman artifact add file already exists in artifact", func() {
|
||||
@ -506,7 +506,7 @@ var _ = Describe("Podman artifact", func() {
|
||||
a := podmanTest.InspectArtifact(artifact1Name)
|
||||
|
||||
Expect(a.Manifest.Layers).To(HaveLen(1))
|
||||
Expect(a.TotalSizeBytes()).To(Equal(int64(1048576)))
|
||||
Expect(a.TotalSizeBytes()).To(Equal(int64(2048)))
|
||||
})
|
||||
|
||||
It("podman artifact add with --append and --type", func() {
|
||||
|
@ -5,6 +5,7 @@ package integration
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -1390,6 +1391,7 @@ func writeYaml(content string, fileName string) error {
|
||||
func GetPort() int {
|
||||
portMin := 5000
|
||||
portMax := 5999
|
||||
|
||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
// Avoid dup-allocation races between parallel ginkgo processes
|
||||
@ -1617,16 +1619,22 @@ func setupRegistry(portOverride *int) (*lockfile.LockFile, string, error) {
|
||||
}
|
||||
|
||||
func createArtifactFile(numBytes int64) (string, error) {
|
||||
GinkgoHelper()
|
||||
artifactDir := filepath.Join(podmanTest.TempDir, "artifacts")
|
||||
if err := os.MkdirAll(artifactDir, 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
filename := RandomString(8)
|
||||
outFile := filepath.Join(artifactDir, filename)
|
||||
session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/artifacts:z", artifactDir), ALPINE, "dd", "if=/dev/urandom", fmt.Sprintf("of=%s", filepath.Join("/artifacts", filename)), "bs=1b", fmt.Sprintf("count=%d", numBytes)})
|
||||
session.WaitWithDefaultTimeout()
|
||||
if session.ExitCode() != 0 {
|
||||
return "", errors.New("unable to generate artifact file")
|
||||
|
||||
f, err := os.Create(filepath.Join(artifactDir, filename))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.CopyN(f, crand.Reader, numBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return outFile, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user