mirror of
https://github.com/containers/podman.git
synced 2025-12-02 11:08:36 +08:00
Merge pull request #16035 from alexlarsson/quadlet
Initial quadlet version integrated in golang
This commit is contained in:
@@ -47,6 +47,7 @@ var (
|
||||
type PodmanTestIntegration struct {
|
||||
PodmanTest
|
||||
ConmonBinary string
|
||||
QuadletBinary string
|
||||
Root string
|
||||
NetworkConfigDir string
|
||||
OCIRuntime string
|
||||
@@ -212,6 +213,11 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
|
||||
podmanRemoteBinary = os.Getenv("PODMAN_REMOTE_BINARY")
|
||||
}
|
||||
|
||||
quadletBinary := filepath.Join(cwd, "../../bin/quadlet")
|
||||
if os.Getenv("QUADLET_BINARY") != "" {
|
||||
quadletBinary = os.Getenv("QUADLET_BINARY")
|
||||
}
|
||||
|
||||
conmonBinary := "/usr/libexec/podman/conmon"
|
||||
altConmonBinary := "/usr/bin/conmon"
|
||||
if _, err := os.Stat(conmonBinary); os.IsNotExist(err) {
|
||||
@@ -280,6 +286,7 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
|
||||
NetworkBackend: networkBackend,
|
||||
},
|
||||
ConmonBinary: conmonBinary,
|
||||
QuadletBinary: quadletBinary,
|
||||
Root: root,
|
||||
TmpDir: tempDir,
|
||||
NetworkConfigDir: networkConfigDir,
|
||||
@@ -513,6 +520,19 @@ func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegrat
|
||||
return &PodmanSessionIntegration{podmanSession}, command.Process.Pid
|
||||
}
|
||||
|
||||
func (p *PodmanTestIntegration) Quadlet(args []string, sourceDir string) *PodmanSessionIntegration {
|
||||
fmt.Printf("Running: %s %s with QUADLET_UNIT_DIRS=%s\n", p.QuadletBinary, strings.Join(args, " "), sourceDir)
|
||||
|
||||
command := exec.Command(p.QuadletBinary, args...)
|
||||
command.Env = []string{fmt.Sprintf("QUADLET_UNIT_DIRS=%s", sourceDir)}
|
||||
session, err := Start(command, GinkgoWriter, GinkgoWriter)
|
||||
if err != nil {
|
||||
Fail("unable to run quadlet command: " + strings.Join(args, " "))
|
||||
}
|
||||
quadletSession := &PodmanSession{Session: session}
|
||||
return &PodmanSessionIntegration{quadletSession}
|
||||
}
|
||||
|
||||
// Cleanup cleans up the temporary store
|
||||
func (p *PodmanTestIntegration) Cleanup() {
|
||||
// Remove all pods...
|
||||
|
||||
12
test/e2e/quadlet/annotation.container
Normal file
12
test/e2e/quadlet/annotation.container
Normal file
@@ -0,0 +1,12 @@
|
||||
## assert-podman-final-args imagename
|
||||
## assert-podman-args "--annotation" "org.foo.Arg0=arg0"
|
||||
## assert-podman-args "--annotation" "org.foo.Arg1=arg1"
|
||||
## assert-podman-args "--annotation" "org.foo.Arg2=arg 2"
|
||||
## assert-podman-args "--annotation" "org.foo.Arg3=arg3"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Annotation=org.foo.Arg1=arg1 "org.foo.Arg2=arg 2" \
|
||||
org.foo.Arg3=arg3
|
||||
|
||||
Annotation=org.foo.Arg0=arg0
|
||||
12
test/e2e/quadlet/basepodman.container
Normal file
12
test/e2e/quadlet/basepodman.container
Normal file
@@ -0,0 +1,12 @@
|
||||
## assert-podman-final-args run --name=systemd-%N --cidfile=%t/%N.cid --replace --rm -d --log-driver journald --pull=never --runtime /usr/bin/crun --cgroups=split --sdnotify=conmon imagename
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
|
||||
# Disable all default features to get as empty podman run command as we can
|
||||
RemapUsers=no
|
||||
NoNewPrivileges=no
|
||||
DropCapability=
|
||||
RunInit=no
|
||||
VolatileTmp=no
|
||||
Timezone=
|
||||
27
test/e2e/quadlet/basic.container
Normal file
27
test/e2e/quadlet/basic.container
Normal file
@@ -0,0 +1,27 @@
|
||||
## assert-podman-final-args imagename
|
||||
## assert-podman-args "--name=systemd-%N"
|
||||
## assert-podman-args "--cidfile=%t/%N.cid"
|
||||
## assert-podman-args "--rm"
|
||||
## assert-podman-args "--replace"
|
||||
## assert-podman-args "-d"
|
||||
## assert-podman-args "--log-driver" "journald"
|
||||
## assert-podman-args "--pull=never"
|
||||
## assert-podman-args "--init"
|
||||
## assert-podman-args "--runtime" "/usr/bin/crun"
|
||||
## assert-podman-args "--cgroups=split"
|
||||
## assert-podman-args "--sdnotify=conmon"
|
||||
## assert-podman-args "--security-opt=no-new-privileges"
|
||||
## assert-podman-args "--cap-drop=all"
|
||||
## assert-podman-args "--tmpfs" "/tmp:rw,size=512M,mode=1777"
|
||||
## assert-key-is "Unit" "RequiresMountsFor" "%t/containers"
|
||||
## assert-key-is "Service" "KillMode" "mixed"
|
||||
## assert-key-is "Service" "Delegate" "yes"
|
||||
## assert-key-is "Service" "Type" "notify"
|
||||
## assert-key-is "Service" "NotifyAccess" "all"
|
||||
## assert-key-is "Service" "SyslogIdentifier" "%N"
|
||||
## assert-key-is "Service" "ExecStartPre" "-rm -f %t/%N.cid"
|
||||
## assert-key-is "Service" "ExecStopPost" "-/usr/bin/podman rm -f -i --cidfile=%t/%N.cid" "-rm -f %t/%N.cid"
|
||||
## assert-key-is "Service" "Environment" "PODMAN_SYSTEMD_UNIT=%n"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
8
test/e2e/quadlet/basic.volume
Normal file
8
test/e2e/quadlet/basic.volume
Normal file
@@ -0,0 +1,8 @@
|
||||
## assert-key-is Unit RequiresMountsFor "%t/containers"
|
||||
## assert-key-is Service Type oneshot
|
||||
## assert-key-is Service RemainAfterExit yes
|
||||
## assert-key-is Service ExecCondition '/usr/bin/bash -c "! /usr/bin/podman volume exists systemd-basic"'
|
||||
## assert-key-is Service ExecStart "/usr/bin/podman volume create systemd-basic"
|
||||
## assert-key-is Service SyslogIdentifier "%N"
|
||||
|
||||
[Volume]
|
||||
8
test/e2e/quadlet/capabilities.container
Normal file
8
test/e2e/quadlet/capabilities.container
Normal file
@@ -0,0 +1,8 @@
|
||||
## assert-podman-args "--cap-drop=all"
|
||||
## assert-podman-args "--cap-add=cap_dac_override"
|
||||
## assert-podman-args "--cap-add=cap_ipc_owner"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
AddCapability=CAP_DAC_OVERRIDE
|
||||
AddCapability=CAP_IPC_OWNER
|
||||
12
test/e2e/quadlet/env.container
Normal file
12
test/e2e/quadlet/env.container
Normal file
@@ -0,0 +1,12 @@
|
||||
## assert-podman-final-args imagename
|
||||
## assert-podman-args --env "FOO1=foo1"
|
||||
## assert-podman-args --env "FOO2=foo2 "
|
||||
## assert-podman-args --env "FOO3=foo3"
|
||||
## assert-podman-args --env "REPLACE=replaced"
|
||||
## assert-podman-args --env "FOO4=foo\\nfoo"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Environment=FOO1=foo1 "FOO2=foo2 " \
|
||||
FOO3=foo3 REPLACE=replace
|
||||
Environment=REPLACE=replaced 'FOO4=foo\nfoo'
|
||||
5
test/e2e/quadlet/escapes.container
Normal file
5
test/e2e/quadlet/escapes.container
Normal file
@@ -0,0 +1,5 @@
|
||||
## assert-podman-final-args "/some/path" "an arg" "a;b\\nc\\td'e" "a;b\\nc\\td" "a\"b"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Exec=/some/path "an arg" "a;b\nc\td'e" a;b\nc\td 'a"b'
|
||||
6
test/e2e/quadlet/exec.container
Normal file
6
test/e2e/quadlet/exec.container
Normal file
@@ -0,0 +1,6 @@
|
||||
## assert-podman-final-args imagename "/some/binary file" "--arg1" "arg 2"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Exec="/some/binary file" --arg1 \
|
||||
"arg 2"
|
||||
4
test/e2e/quadlet/image.container
Normal file
4
test/e2e/quadlet/image.container
Normal file
@@ -0,0 +1,4 @@
|
||||
## assert-podman-final-args imagename
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
21
test/e2e/quadlet/install.container
Normal file
21
test/e2e/quadlet/install.container
Normal file
@@ -0,0 +1,21 @@
|
||||
## assert-symlink alias.service install.service
|
||||
## assert-symlink another-alias.service install.service
|
||||
## assert-symlink in/a/dir/alias3.service ../../../install.service
|
||||
## assert-symlink want1.service.wants/install.service ../install.service
|
||||
## assert-symlink want2.service.wants/install.service ../install.service
|
||||
## assert-symlink want3.service.wants/install.service ../install.service
|
||||
## assert-symlink req1.service.requires/install.service ../install.service
|
||||
## assert-symlink req2.service.requires/install.service ../install.service
|
||||
## assert-symlink req3.service.requires/install.service ../install.service
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
|
||||
[Install]
|
||||
Alias=alias.service \
|
||||
"another-alias.service"
|
||||
Alias=in/a/dir/alias3.service
|
||||
WantedBy=want1.service want2.service
|
||||
WantedBy=want3.service
|
||||
RequiredBy=req1.service req2.service
|
||||
RequiredBy=req3.service
|
||||
12
test/e2e/quadlet/label.container
Normal file
12
test/e2e/quadlet/label.container
Normal file
@@ -0,0 +1,12 @@
|
||||
## assert-podman-final-args imagename
|
||||
## assert-podman-args "--label" "org.foo.Arg0=arg0"
|
||||
## assert-podman-args "--label" "org.foo.Arg1=arg1"
|
||||
## assert-podman-args "--label" "org.foo.Arg2=arg 2"
|
||||
## assert-podman-args "--label" "org.foo.Arg3=arg3"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Label=org.foo.Arg1=arg1 "org.foo.Arg2=arg 2" \
|
||||
org.foo.Arg3=arg3
|
||||
|
||||
Label=org.foo.Arg0=arg0
|
||||
8
test/e2e/quadlet/label.volume
Normal file
8
test/e2e/quadlet/label.volume
Normal file
@@ -0,0 +1,8 @@
|
||||
## assert-key-contains Service ExecStart " --label org.foo.Arg1=arg1 "
|
||||
## assert-key-contains Service ExecStart " --label org.foo.Arg2=arg2 "
|
||||
## assert-key-contains Service ExecStart " --label org.foo.Arg3=arg3 "
|
||||
|
||||
[Volume]
|
||||
Label=org.foo.Arg1=arg1
|
||||
Label=org.foo.Arg2=arg2 \
|
||||
org.foo.Arg3=arg3
|
||||
5
test/e2e/quadlet/name.container
Normal file
5
test/e2e/quadlet/name.container
Normal file
@@ -0,0 +1,5 @@
|
||||
## assert-podman-args "--name=foobar"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
ContainerName=foobar
|
||||
4
test/e2e/quadlet/noimage.container
Normal file
4
test/e2e/quadlet/noimage.container
Normal file
@@ -0,0 +1,4 @@
|
||||
## assert-failed
|
||||
## assert-stderr-contains "No Image key specified"
|
||||
|
||||
[Container]
|
||||
6
test/e2e/quadlet/noremapuser.container
Normal file
6
test/e2e/quadlet/noremapuser.container
Normal file
@@ -0,0 +1,6 @@
|
||||
## !assert-podman-args --uidmap
|
||||
## !assert-podman-args --gidmap
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
RemapUsers=no
|
||||
28
test/e2e/quadlet/noremapuser2.container
Normal file
28
test/e2e/quadlet/noremapuser2.container
Normal file
@@ -0,0 +1,28 @@
|
||||
# This is an non-user-remapped container, but the user is mapped (uid
|
||||
# 1000 in container is uid 90 on host). This means the result should
|
||||
# map those particular ids to each other, but map all other container
|
||||
# ids to the same as the host.
|
||||
|
||||
# There is some additional complexity, as the host uid (90) that the
|
||||
# container uid is mapped to can't also be mapped to itself, as ids
|
||||
# can only be mapped once, so it has to be unmapped.
|
||||
|
||||
## assert-podman-args --user 1000:1001
|
||||
|
||||
## assert-podman-args --uidmap 0:0:90
|
||||
## assert-podman-args --uidmap 91:91:909
|
||||
## assert-podman-args --uidmap 1000:90:1
|
||||
## assert-podman-args --uidmap 1001:1001:4294966294
|
||||
|
||||
## assert-podman-args --gidmap 0:0:91
|
||||
## assert-podman-args --gidmap 92:92:909
|
||||
## assert-podman-args --gidmap 1001:91:1
|
||||
## assert-podman-args --gidmap 1002:1002:4294966293
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
RemapUsers=no
|
||||
User=1000
|
||||
Group=1001
|
||||
HostUser=90
|
||||
HostGroup=91
|
||||
5
test/e2e/quadlet/notify.container
Normal file
5
test/e2e/quadlet/notify.container
Normal file
@@ -0,0 +1,5 @@
|
||||
## assert-podman-args "--sdnotify=container"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Notify=yes
|
||||
10
test/e2e/quadlet/other-sections.container
Normal file
10
test/e2e/quadlet/other-sections.container
Normal file
@@ -0,0 +1,10 @@
|
||||
## assert-podman-final-args imagename
|
||||
## assert-key-is "Unit" "Foo" "bar1" "bar2"
|
||||
## assert-key-is "X-Container" "Image" "imagename"
|
||||
|
||||
[Unit]
|
||||
Foo=bar1
|
||||
Foo=bar2
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
9
test/e2e/quadlet/podmanargs.container
Normal file
9
test/e2e/quadlet/podmanargs.container
Normal file
@@ -0,0 +1,9 @@
|
||||
## assert-podman-args "--foo"
|
||||
## assert-podman-args "--bar"
|
||||
## assert-podman-args "--also"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
PodmanArgs="--foo" \
|
||||
--bar
|
||||
PodmanArgs=--also
|
||||
54
test/e2e/quadlet/ports.container
Normal file
54
test/e2e/quadlet/ports.container
Normal file
@@ -0,0 +1,54 @@
|
||||
[Container]
|
||||
Image=imagename
|
||||
## assert-podman-args --expose=1000
|
||||
ExposeHostPort=1000
|
||||
## assert-podman-args --expose=2000-3000
|
||||
ExposeHostPort=2000-3000
|
||||
|
||||
## assert-podman-args -p=127.0.0.1:80:90
|
||||
PublishPort=127.0.0.1:80:90
|
||||
|
||||
## assert-podman-args -p=80:91
|
||||
PublishPort=0.0.0.0:80:91
|
||||
|
||||
## assert-podman-args -p=80:92
|
||||
PublishPort=:80:92
|
||||
|
||||
## assert-podman-args -p=127.0.0.1::93
|
||||
PublishPort=127.0.0.1::93
|
||||
|
||||
## assert-podman-args -p=94
|
||||
PublishPort=0.0.0.0::94
|
||||
|
||||
## assert-podman-args -p=95
|
||||
PublishPort=::95
|
||||
|
||||
## assert-podman-args -p=80:96
|
||||
PublishPort=80:96
|
||||
|
||||
## assert-podman-args -p=97
|
||||
PublishPort=97
|
||||
|
||||
## assert-podman-args -p=1234/udp
|
||||
PublishPort=1234/udp
|
||||
|
||||
## assert-podman-args -p=1234:1234/udp
|
||||
PublishPort=1234:1234/udp
|
||||
|
||||
## assert-podman-args -p=127.0.0.1:1234:1234/udp
|
||||
PublishPort=127.0.0.1:1234:1234/udp
|
||||
|
||||
## assert-podman-args -p=1234/tcp
|
||||
PublishPort=1234/tcp
|
||||
|
||||
## assert-podman-args -p=1234:1234/tcp
|
||||
PublishPort=1234:1234/tcp
|
||||
|
||||
## assert-podman-args -p=127.0.0.1:1234:1234/tcp
|
||||
PublishPort=127.0.0.1:1234:1234/tcp
|
||||
|
||||
## assert-podman-args --expose=2000-3000/udp
|
||||
ExposeHostPort=2000-3000/udp
|
||||
|
||||
## assert-podman-args --expose=2000-3000/tcp
|
||||
ExposeHostPort=2000-3000/tcp
|
||||
28
test/e2e/quadlet/ports_ipv6.container
Normal file
28
test/e2e/quadlet/ports_ipv6.container
Normal file
@@ -0,0 +1,28 @@
|
||||
[Container]
|
||||
Image=imagename
|
||||
## assert-podman-args -p=[::1]:80:90
|
||||
PublishPort=[::1]:80:90
|
||||
|
||||
## assert-podman-args -p=[::]:80:91
|
||||
PublishPort=[::]:80:91
|
||||
|
||||
## assert-podman-args -p=[2001:DB8::23]:80:91
|
||||
PublishPort=[2001:DB8::23]:80:91
|
||||
|
||||
## assert-podman-args -p=[::1]::93
|
||||
PublishPort=[::1]::93
|
||||
|
||||
## assert-podman-args -p=[::]::94
|
||||
PublishPort=[::]::94
|
||||
|
||||
## assert-podman-args -p=[2001:db8::42]::94
|
||||
PublishPort=[2001:db8::42]::94
|
||||
|
||||
## assert-podman-args -p=[::1]:1234:1234/udp
|
||||
PublishPort=[::1]:1234:1234/udp
|
||||
|
||||
## assert-podman-args -p=[::1]:1234:1234/tcp
|
||||
PublishPort=[::1]:1234:1234/tcp
|
||||
|
||||
## assert-podman-args -p=[2001:db8:c0:ff:ee::1]:1234:1234/udp
|
||||
PublishPort=[2001:db8:c0:ff:ee::1]:1234:1234/udp
|
||||
9
test/e2e/quadlet/socketactivated.container
Normal file
9
test/e2e/quadlet/socketactivated.container
Normal file
@@ -0,0 +1,9 @@
|
||||
## assert-podman-args --preserve-fds=1
|
||||
## assert-podman-args --env LISTEN_FDS=1
|
||||
## assert-podman-args --env LISTEN_PID=2
|
||||
## assert-key-is "Service" "Type" "notify"
|
||||
## assert-key-is "Service" "NotifyAccess" "all"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
SocketActivated=yes
|
||||
5
test/e2e/quadlet/timezone.container
Normal file
5
test/e2e/quadlet/timezone.container
Normal file
@@ -0,0 +1,5 @@
|
||||
## assert-podman-args --tz=foo
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Timezone=foo
|
||||
6
test/e2e/quadlet/uid.volume
Normal file
6
test/e2e/quadlet/uid.volume
Normal file
@@ -0,0 +1,6 @@
|
||||
## assert-key-contains Service ExecStart " --opt o=uid=0,gid=11 "
|
||||
|
||||
[Volume]
|
||||
# Test usernames too
|
||||
User=root
|
||||
Group=11
|
||||
24
test/e2e/quadlet/user-host.container
Normal file
24
test/e2e/quadlet/user-host.container
Normal file
@@ -0,0 +1,24 @@
|
||||
## assert-podman-args --user 1000:1001
|
||||
|
||||
## assert-podman-args --uidmap 0:0:1
|
||||
## assert-podman-args --uidmap 1:100000:999
|
||||
## assert-podman-args --uidmap 1000:900:1
|
||||
## assert-podman-args --uidmap 1001:100999:99001
|
||||
|
||||
## assert-podman-args --gidmap 0:0:1
|
||||
## assert-podman-args --gidmap 1:100000:1000
|
||||
## assert-podman-args --gidmap 1001:901:1
|
||||
## assert-podman-args --gidmap 1002:101000:99000
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
User=1000
|
||||
HostUser=900
|
||||
Group=1001
|
||||
HostGroup=901
|
||||
|
||||
RemapUsers=yes
|
||||
|
||||
# Set this to get well-known valuse for the checks
|
||||
RemapUidRanges=100000-199999
|
||||
RemapGidRanges=100000-199999
|
||||
26
test/e2e/quadlet/user-root1.container
Normal file
26
test/e2e/quadlet/user-root1.container
Normal file
@@ -0,0 +1,26 @@
|
||||
## assert-podman-args --user 1000:1001
|
||||
|
||||
## assert-podman-args --uidmap 0:100000:1000
|
||||
## assert-podman-args --uidmap 1000:0:1
|
||||
## assert-podman-args --uidmap 1001:101000:99000
|
||||
## !assert-podman-args --uidmap 0:0:1
|
||||
|
||||
## assert-podman-args --gidmap 0:100000:1001
|
||||
## assert-podman-args --gidmap 1001:0:1
|
||||
## assert-podman-args --gidmap 1002:101001:98999
|
||||
## !assert-podman-args --gidmap 0:0:1
|
||||
|
||||
# Map container uid 1000 to host root
|
||||
# This means container root must map to something else
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
User=1000
|
||||
# Also test name parsing
|
||||
HostUser=root
|
||||
Group=1001
|
||||
HostGroup=0
|
||||
RemapUsers=yes
|
||||
# Set this to get well-known valuse for the checks
|
||||
RemapUidRanges=100000-199999
|
||||
RemapGidRanges=100000-199999
|
||||
22
test/e2e/quadlet/user-root2.container
Normal file
22
test/e2e/quadlet/user-root2.container
Normal file
@@ -0,0 +1,22 @@
|
||||
# No need for --user 0:0, it is the default
|
||||
## !assert-podman-args --user
|
||||
|
||||
## assert-podman-args --uidmap 0:0:1
|
||||
## assert-podman-args --gidmap 0:0:1
|
||||
|
||||
## assert-podman-args --uidmap 1:100000:100000
|
||||
## assert-podman-args --gidmap 1:100000:100000
|
||||
|
||||
# Map container uid root to host root
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
User=0
|
||||
# Also test name parsing
|
||||
HostUser=root
|
||||
Group=0
|
||||
HostGroup=0
|
||||
RemapUsers=yes
|
||||
# Set this to get well-known valuse for the checks
|
||||
RemapUidRanges=100000-199999
|
||||
RemapGidRanges=100000-199999
|
||||
7
test/e2e/quadlet/user.container
Normal file
7
test/e2e/quadlet/user.container
Normal file
@@ -0,0 +1,7 @@
|
||||
## assert-podman-final-args imagename
|
||||
## assert-podman-args "--user" "998:999"
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
User=998
|
||||
Group=999
|
||||
12
test/e2e/quadlet/volume.container
Normal file
12
test/e2e/quadlet/volume.container
Normal file
@@ -0,0 +1,12 @@
|
||||
## assert-podman-args -v /host/dir:/container/volume
|
||||
## assert-podman-args -v /host/dir2:/container/volume2:Z
|
||||
## assert-podman-args -v named:/container/named
|
||||
## assert-podman-args -v systemd-quadlet:/container/quadlet imagename
|
||||
|
||||
[Container]
|
||||
Image=imagename
|
||||
Volume=/host/dir:/container/volume
|
||||
Volume=/host/dir2:/container/volume2:Z
|
||||
Volume=/container/empty
|
||||
Volume=named:/container/named
|
||||
Volume=quadlet.volume:/container/quadlet
|
||||
291
test/e2e/quadlet_test.go
Normal file
291
test/e2e/quadlet_test.go
Normal file
@@ -0,0 +1,291 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman/v4/pkg/systemdparser"
|
||||
"github.com/mattn/go-shellwords"
|
||||
|
||||
. "github.com/containers/podman/v4/test/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/extensions/table"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
type quadletTestcase struct {
|
||||
data []byte
|
||||
serviceName string
|
||||
checks [][]string
|
||||
}
|
||||
|
||||
func loadQuadletTestcase(path string) *quadletTestcase {
|
||||
data, err := os.ReadFile(path)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
base := filepath.Base(path)
|
||||
ext := filepath.Ext(base)
|
||||
service := base[:len(base)-len(ext)]
|
||||
if ext == ".volume" {
|
||||
service += "-volume"
|
||||
}
|
||||
service += ".service"
|
||||
|
||||
checks := make([][]string, 0)
|
||||
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if strings.HasPrefix(line, "##") {
|
||||
words, err := shellwords.Parse(line[2:])
|
||||
Expect(err).To(BeNil())
|
||||
checks = append(checks, words)
|
||||
}
|
||||
}
|
||||
|
||||
return &quadletTestcase{
|
||||
data,
|
||||
service,
|
||||
checks,
|
||||
}
|
||||
}
|
||||
|
||||
func matchSublistAt(full []string, pos int, sublist []string) bool {
|
||||
if len(sublist) > len(full)-pos {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range sublist {
|
||||
if sublist[i] != full[pos+i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findSublist(full []string, sublist []string) int {
|
||||
if len(sublist) > len(full) {
|
||||
return -1
|
||||
}
|
||||
if len(sublist) == 0 {
|
||||
return -1
|
||||
}
|
||||
for i := 0; i < len(full)-len(sublist)+1; i++ {
|
||||
if matchSublistAt(full, i, sublist) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertStdErrContains(args []string, session *PodmanSessionIntegration) bool {
|
||||
return strings.Contains(session.OutputToString(), args[0])
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertKeyIs(args []string, unit *systemdparser.UnitFile) bool {
|
||||
group := args[0]
|
||||
key := args[1]
|
||||
values := args[2:]
|
||||
|
||||
realValues := unit.LookupAll(group, key)
|
||||
if len(realValues) != len(values) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := range realValues {
|
||||
if realValues[i] != values[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertKeyContains(args []string, unit *systemdparser.UnitFile) bool {
|
||||
group := args[0]
|
||||
key := args[1]
|
||||
value := args[2]
|
||||
|
||||
realValue, ok := unit.LookupLast(group, key)
|
||||
return ok && strings.Contains(realValue, value)
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertPodmanArgs(args []string, unit *systemdparser.UnitFile) bool {
|
||||
podmanArgs, _ := unit.LookupLastArgs("Service", "ExecStart")
|
||||
return findSublist(podmanArgs, args) != -1
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertFinalArgs(args []string, unit *systemdparser.UnitFile) bool {
|
||||
podmanArgs, _ := unit.LookupLastArgs("Service", "ExecStart")
|
||||
if len(podmanArgs) < len(args) {
|
||||
return false
|
||||
}
|
||||
return matchSublistAt(podmanArgs, len(podmanArgs)-len(args), args)
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertSymlink(args []string, unit *systemdparser.UnitFile) bool {
|
||||
symlink := args[0]
|
||||
expectedTarget := args[1]
|
||||
|
||||
dir := filepath.Dir(unit.Path)
|
||||
|
||||
target, err := os.Readlink(filepath.Join(dir, symlink))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
return expectedTarget == target
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) doAssert(check []string, unit *systemdparser.UnitFile, session *PodmanSessionIntegration) error {
|
||||
op := check[0]
|
||||
args := make([]string, 0)
|
||||
for _, a := range check[1:] {
|
||||
// Apply \n and \t as they are used in the testcases
|
||||
a = strings.ReplaceAll(a, "\\n", "\n")
|
||||
a = strings.ReplaceAll(a, "\\t", "\t")
|
||||
args = append(args, a)
|
||||
}
|
||||
invert := false
|
||||
if op[0] == '!' {
|
||||
invert = true
|
||||
op = op[1:]
|
||||
}
|
||||
|
||||
var ok bool
|
||||
switch op {
|
||||
case "assert-failed":
|
||||
ok = true /* Handled separately */
|
||||
case "assert-stderr-contains":
|
||||
ok = t.assertStdErrContains(args, session)
|
||||
case "assert-key-is":
|
||||
ok = t.assertKeyIs(args, unit)
|
||||
case "assert-key-contains":
|
||||
ok = t.assertKeyContains(args, unit)
|
||||
case "assert-podman-args":
|
||||
ok = t.assertPodmanArgs(args, unit)
|
||||
case "assert-podman-final-args":
|
||||
ok = t.assertFinalArgs(args, unit)
|
||||
case "assert-symlink":
|
||||
ok = t.assertSymlink(args, unit)
|
||||
default:
|
||||
return fmt.Errorf("Unsupported assertion %s", op)
|
||||
}
|
||||
if invert {
|
||||
ok = !ok
|
||||
}
|
||||
|
||||
if !ok {
|
||||
s, _ := unit.ToString()
|
||||
return fmt.Errorf("Failed assertion for %s: %s\n\n%s", t.serviceName, strings.Join(check, " "), s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) check(generateDir string, session *PodmanSessionIntegration) {
|
||||
expectFail := false
|
||||
for _, c := range t.checks {
|
||||
if c[0] == "assert-failed" {
|
||||
expectFail = true
|
||||
}
|
||||
}
|
||||
|
||||
file := filepath.Join(generateDir, t.serviceName)
|
||||
if _, err := os.Stat(file); os.IsNotExist(err) && expectFail {
|
||||
return // Successful fail
|
||||
}
|
||||
|
||||
unit, err := systemdparser.ParseUnitFile(file)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
for _, check := range t.checks {
|
||||
err := t.doAssert(check, unit, session)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
}
|
||||
|
||||
var _ = Describe("quadlet system generator", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
generatedDir string
|
||||
quadletDir string
|
||||
podmanTest *PodmanTestIntegration
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanTestCreate(tempdir)
|
||||
podmanTest.Setup()
|
||||
|
||||
generatedDir = filepath.Join(podmanTest.TempDir, "generated")
|
||||
err = os.Mkdir(generatedDir, os.ModePerm)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
quadletDir = filepath.Join(podmanTest.TempDir, "quadlet")
|
||||
err = os.Mkdir(quadletDir, os.ModePerm)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.Cleanup()
|
||||
f := CurrentGinkgoTestDescription()
|
||||
processTestResult(f)
|
||||
|
||||
})
|
||||
|
||||
DescribeTable("Running quadlet test case",
|
||||
func(fileName string) {
|
||||
testcase := loadQuadletTestcase(filepath.Join("quadlet", fileName))
|
||||
|
||||
// Write the tested file to the quadlet dir
|
||||
err = os.WriteFile(filepath.Join(quadletDir, fileName), testcase.data, 0644)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
// Run quadlet to convert the file
|
||||
session := podmanTest.Quadlet([]string{generatedDir}, quadletDir)
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
// Print any stderr output
|
||||
errs := session.ErrorToString()
|
||||
if errs != "" {
|
||||
fmt.Println("error:", session.ErrorToString())
|
||||
}
|
||||
|
||||
testcase.check(generatedDir, session)
|
||||
},
|
||||
Entry("Basic container", "basic.container"),
|
||||
Entry("annotation.container", "annotation.container"),
|
||||
Entry("basepodman.container", "basepodman.container"),
|
||||
Entry("capabilities.container", "capabilities.container"),
|
||||
Entry("env.container", "env.container"),
|
||||
Entry("escapes.container", "escapes.container"),
|
||||
Entry("exec.container", "exec.container"),
|
||||
Entry("image.container", "image.container"),
|
||||
Entry("install.container", "install.container"),
|
||||
Entry("label.container", "label.container"),
|
||||
Entry("name.container", "name.container"),
|
||||
Entry("noimage.container", "noimage.container"),
|
||||
Entry("noremapuser2.container", "noremapuser2.container"),
|
||||
Entry("noremapuser.container", "noremapuser.container"),
|
||||
Entry("notify.container", "notify.container"),
|
||||
Entry("other-sections.container", "other-sections.container"),
|
||||
Entry("podmanargs.container", "podmanargs.container"),
|
||||
Entry("ports.container", "ports.container"),
|
||||
Entry("ports_ipv6.container", "ports_ipv6.container"),
|
||||
Entry("socketactivated.container", "socketactivated.container"),
|
||||
Entry("timezone.container", "timezone.container"),
|
||||
Entry("user.container", "user.container"),
|
||||
Entry("user-host.container", "user-host.container"),
|
||||
Entry("user-root1.container", "user-root1.container"),
|
||||
Entry("user-root2.container", "user-root2.container"),
|
||||
Entry("volume.container", "volume.container"),
|
||||
|
||||
Entry("basic.volume", "basic.volume"),
|
||||
Entry("label.volume", "label.volume"),
|
||||
Entry("uid.volume", "uid.volume"),
|
||||
)
|
||||
|
||||
})
|
||||
Reference in New Issue
Block a user