test: run --cgroups=split in new cgroup

the --cgroups=split test changes the current cgroup as it creates a
sub-cgroup.  This can cause a race condition in tests that are reading
the current cgroup.

Closes: https://github.com/containers/podman/issues/11191

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano
2021-11-02 12:51:10 +01:00
parent 0686f0bb2f
commit 0234b153cc
6 changed files with 42 additions and 12 deletions

View File

@ -685,7 +685,7 @@ func SkipIfContainerized(reason string) {
// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment // PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment
func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration {
podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil, nil)
return &PodmanSessionIntegration{podmanSession} return &PodmanSessionIntegration{podmanSession}
} }

View File

@ -38,11 +38,25 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
return &PodmanSessionIntegration{podmanSession} return &PodmanSessionIntegration{podmanSession}
} }
// PodmanSystemdScope runs the podman command in a new systemd scope
func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration {
var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
remoteArgs = append(remoteArgs, args...)
wrapper := []string{"systemd-run", "--scope"}
if rootless.IsRootless() {
wrapper = []string{"systemd-run", "--scope", "--user"}
}
podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, wrapper, nil)
return &PodmanSessionIntegration{podmanSession}
}
// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files // PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files
func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration {
var remoteArgs = []string{"--remote", "--url", p.RemoteSocket} var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
remoteArgs = append(remoteArgs, args...) remoteArgs = append(remoteArgs, args...)
podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, extraFiles) podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, nil, extraFiles)
return &PodmanSessionIntegration{podmanSession} return &PodmanSessionIntegration{podmanSession}
} }

View File

@ -8,6 +8,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/containers/podman/v3/pkg/rootless"
) )
func IsRemote() bool { func IsRemote() bool {
@ -23,9 +25,19 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration
return &PodmanSessionIntegration{podmanSession} return &PodmanSessionIntegration{podmanSession}
} }
// PodmanSystemdScope runs the podman command in a new systemd scope
func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration {
wrapper := []string{"systemd-run", "--scope"}
if rootless.IsRootless() {
wrapper = []string{"systemd-run", "--scope", "--user"}
}
podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, wrapper, nil)
return &PodmanSessionIntegration{podmanSession}
}
// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files // PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files
func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration {
podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, extraFiles) podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, nil, extraFiles)
return &PodmanSessionIntegration{podmanSession} return &PodmanSessionIntegration{podmanSession}
} }

View File

@ -1381,13 +1381,13 @@ USER mail`, BB)
} }
} }
container := podmanTest.Podman([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) container := podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"})
container.WaitWithDefaultTimeout() container.WaitWithDefaultTimeout()
Expect(container).Should(Exit(0)) Expect(container).Should(Exit(0))
checkLines(container.OutputToStringArray()) checkLines(container.OutputToStringArray())
// check that --cgroups=split is honored also when a container runs in a pod // check that --cgroups=split is honored also when a container runs in a pod
container = podmanTest.Podman([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) container = podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"})
container.WaitWithDefaultTimeout() container.WaitWithDefaultTimeout()
Expect(container).Should(Exit(0)) Expect(container).Should(Exit(0))
checkLines(container.OutputToStringArray()) checkLines(container.OutputToStringArray())

View File

@ -23,7 +23,7 @@ var _ = Describe("PodmanTest test", func() {
FakeOutputs["check"] = []string{"check"} FakeOutputs["check"] = []string{"check"}
os.Setenv("HOOK_OPTION", "hook_option") os.Setenv("HOOK_OPTION", "hook_option")
env := os.Environ() env := os.Environ()
session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil) session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil, nil)
os.Unsetenv("HOOK_OPTION") os.Unsetenv("HOOK_OPTION")
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session.Command.Process).ShouldNot(BeNil()) Expect(session.Command.Process).ShouldNot(BeNil())

View File

@ -66,27 +66,31 @@ func (p *PodmanTest) MakeOptions(args []string, noEvents, noCache bool) []string
// PodmanAsUserBase exec podman as user. uid and gid is set for credentials usage. env is used // PodmanAsUserBase exec podman as user. uid and gid is set for credentials usage. env is used
// to record the env for debugging // to record the env for debugging
func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, extraFiles []*os.File) *PodmanSession { func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, wrapper []string, extraFiles []*os.File) *PodmanSession {
var command *exec.Cmd var command *exec.Cmd
podmanOptions := p.MakeOptions(args, noEvents, noCache) podmanOptions := p.MakeOptions(args, noEvents, noCache)
podmanBinary := p.PodmanBinary podmanBinary := p.PodmanBinary
if p.RemoteTest { if p.RemoteTest {
podmanBinary = p.RemotePodmanBinary podmanBinary = p.RemotePodmanBinary
} }
runCmd := append(wrapper, podmanBinary)
if p.RemoteTest { if p.RemoteTest {
podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...) podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...)
} }
if env == nil { if env == nil {
fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " ")) fmt.Printf("Running: %s %s\n", strings.Join(runCmd, " "), strings.Join(podmanOptions, " "))
} else { } else {
fmt.Printf("Running: (env: %v) %s %s\n", env, podmanBinary, strings.Join(podmanOptions, " ")) fmt.Printf("Running: (env: %v) %s %s\n", env, strings.Join(runCmd, " "), strings.Join(podmanOptions, " "))
} }
if uid != 0 || gid != 0 { if uid != 0 || gid != 0 {
pythonCmd := fmt.Sprintf("import os; import sys; uid = %d; gid = %d; cwd = '%s'; os.setgid(gid); os.setuid(uid); os.chdir(cwd) if len(cwd)>0 else True; os.execv(sys.argv[1], sys.argv[1:])", gid, uid, cwd) pythonCmd := fmt.Sprintf("import os; import sys; uid = %d; gid = %d; cwd = '%s'; os.setgid(gid); os.setuid(uid); os.chdir(cwd) if len(cwd)>0 else True; os.execv(sys.argv[1], sys.argv[1:])", gid, uid, cwd)
nsEnterOpts := append([]string{"-c", pythonCmd, podmanBinary}, podmanOptions...) runCmd = append(runCmd, podmanOptions...)
nsEnterOpts := append([]string{"-c", pythonCmd}, runCmd...)
command = exec.Command("python", nsEnterOpts...) command = exec.Command("python", nsEnterOpts...)
} else { } else {
command = exec.Command(podmanBinary, podmanOptions...) runCmd = append(runCmd, podmanOptions...)
command = exec.Command(runCmd[0], runCmd[1:]...)
} }
if env != nil { if env != nil {
command.Env = env command.Env = env
@ -106,7 +110,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
// PodmanBase exec podman with default env. // PodmanBase exec podman with default env.
func (p *PodmanTest) PodmanBase(args []string, noEvents, noCache bool) *PodmanSession { func (p *PodmanTest) PodmanBase(args []string, noEvents, noCache bool) *PodmanSession {
return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil) return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil, nil)
} }
// WaitForContainer waits on a started container // WaitForContainer waits on a started container