diff options
-rw-r--r-- | docs/source/markdown/podman-unshare.1.md | 5 | ||||
-rw-r--r-- | libpod/networking_linux.go | 26 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 7 | ||||
-rw-r--r-- | test/e2e/common_test.go | 61 | ||||
-rw-r--r-- | test/e2e/libpod_suite_remote_test.go | 21 | ||||
-rw-r--r-- | test/e2e/libpod_suite_test.go | 12 | ||||
-rw-r--r-- | test/utils/utils.go | 1 |
7 files changed, 70 insertions, 63 deletions
diff --git a/docs/source/markdown/podman-unshare.1.md b/docs/source/markdown/podman-unshare.1.md index 5676b1be7..01393a862 100644 --- a/docs/source/markdown/podman-unshare.1.md +++ b/docs/source/markdown/podman-unshare.1.md @@ -35,7 +35,6 @@ Print usage statement Join the rootless network namespace used for CNI and netavark networking. It can be used to connect to a rootless container via IP address (bridge networking). This is otherwise not possible from the host network namespace. -_Note: Using this option with more than one unshare session can have unexpected results._ ## Exit Codes @@ -57,13 +56,13 @@ the exit codes follow the `chroot` standard, see below: **127** Executing a _contained command_ and the _command_ cannot be found - $ podman run busybox foo; echo $? + $ podman unshare foo; echo $? Error: fork/exec /usr/bin/bogus: no such file or directory 127 **Exit code** _contained command_ exit code - $ podman run busybox /bin/sh -c 'exit 3'; echo $? + $ podman unshare /bin/sh -c 'exit 3'; echo $? 3 ## EXAMPLE diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 7d1214183..b734b9c95 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -322,17 +322,14 @@ func (r *RootlessNetNS) Do(toRun func() error) error { // Cleanup the rootless network namespace if needed. // It checks if we have running containers with the bridge network mode. -// Cleanup() will try to lock RootlessNetNS, therefore you have to call -// it with an unlocked lock. +// Cleanup() expects that r.Lock is locked func (r *RootlessNetNS) Cleanup(runtime *Runtime) error { _, err := os.Stat(r.dir) if os.IsNotExist(err) { // the directory does not exists no need for cleanup return nil } - r.Lock.Lock() - defer r.Lock.Unlock() - running := func(c *Container) bool { + activeNetns := func(c *Container) bool { // no bridge => no need to check if !c.config.NetMode.IsBridge() { return false @@ -352,15 +349,18 @@ func (r *RootlessNetNS) Cleanup(runtime *Runtime) error { return false } - state := c.state.State - return state == define.ContainerStateRunning + // only check for an active netns, we cannot use the container state + // because not running does not mean that the netns does not need cleanup + // only if the netns is empty we know that we do not need cleanup + return c.state.NetNS != nil } - ctrs, err := runtime.GetContainersWithoutLock(running) + ctrs, err := runtime.GetContainersWithoutLock(activeNetns) if err != nil { return err } - // no cleanup if we found containers - if len(ctrs) > 0 { + // no cleanup if we found no other containers with a netns + // we will always find one container (the container cleanup that is currently calling us) + if len(ctrs) > 1 { return nil } logrus.Debug("Cleaning up rootless network namespace") @@ -809,10 +809,10 @@ func (r *Runtime) teardownNetwork(ns string, opts types.NetworkOptions) error { if rootlessNetNS != nil { // execute the cni setup in the rootless net ns err = rootlessNetNS.Do(tearDownPod) - rootlessNetNS.Lock.Unlock() - if err == nil { - err = rootlessNetNS.Cleanup(r) + if cerr := rootlessNetNS.Cleanup(r); cerr != nil { + logrus.WithError(err).Error("failed to cleanup rootless netns") } + rootlessNetNS.Lock.Unlock() } else { err = tearDownPod() } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 7da7754f2..e6c9d850b 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -365,9 +365,12 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options e if err != nil { return err } - // make sure to unlock, unshare can run for a long time + // Make sure to unlock, unshare can run for a long time. rootlessNetNS.Lock.Unlock() - defer rootlessNetNS.Cleanup(ic.Libpod) + // We do not want to cleanup the netns after unshare. + // The problem is that we cannot know if we need to cleanup and + // secondly unshare should allow user to setup the namespace with + // special things, e.g. potentially macvlan or something like that. return rootlessNetNS.Do(unshare) } return unshare() diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 63cb4f091..a411a860b 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -36,7 +36,6 @@ var ( PODMAN_BINARY string //nolint:golint,stylecheck INTEGRATION_ROOT string //nolint:golint,stylecheck CGROUP_MANAGER = "systemd" //nolint:golint,stylecheck - ARTIFACT_DIR = "/tmp/.artifacts" //nolint:golint,stylecheck RESTORE_IMAGES = []string{ALPINE, BB, nginx} //nolint:golint,stylecheck defaultWaitTimeout = 90 CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode() //nolint:golint,stylecheck @@ -46,7 +45,7 @@ var ( type PodmanTestIntegration struct { PodmanTest ConmonBinary string - CrioRoot string + Root string CNIConfigDir string OCIRuntime string RunRoot string @@ -111,13 +110,6 @@ var _ = SynchronizedBeforeSuite(func() []byte { cwd, _ := os.Getwd() INTEGRATION_ROOT = filepath.Join(cwd, "../../") podman := PodmanTestSetup("/tmp") - podman.ArtifactPath = ARTIFACT_DIR - if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) { - if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil { - fmt.Printf("%q\n", err) - os.Exit(1) - } - } // Pull cirros but don't put it into the cache pullImages := []string{cirros, fedoraToolbox, volumeTest} @@ -130,7 +122,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { fmt.Printf("%q\n", err) os.Exit(1) } - podman.CrioRoot = ImageCacheDir + podman.Root = ImageCacheDir // If running localized tests, the cache dir is created and populated. if the // tests are remote, this is a no-op populateCache(podman) @@ -170,7 +162,6 @@ var _ = SynchronizedBeforeSuite(func() []byte { func (p *PodmanTestIntegration) Setup() { cwd, _ := os.Getwd() INTEGRATION_ROOT = filepath.Join(cwd, "../../") - p.ArtifactPath = ARTIFACT_DIR } var _ = SynchronizedAfterSuite(func() {}, @@ -181,14 +172,14 @@ var _ = SynchronizedAfterSuite(func() {}, fmt.Printf("%s\t\t%f\n", result.name, result.length) } - // previous crio-run + // previous runroot tempdir, err := CreateTempDirInTempDir() if err != nil { os.Exit(1) } podmanTest := PodmanTestCreate(tempdir) - if err := os.RemoveAll(podmanTest.CrioRoot); err != nil { + if err := os.RemoveAll(podmanTest.Root); err != nil { fmt.Printf("%q\n", err) } @@ -265,18 +256,17 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { PodmanTest: PodmanTest{ PodmanBinary: podmanBinary, RemotePodmanBinary: podmanRemoteBinary, - ArtifactPath: ARTIFACT_DIR, TempDir: tempDir, RemoteTest: remote, ImageCacheFS: storageFs, ImageCacheDir: ImageCacheDir, }, ConmonBinary: conmonBinary, - CrioRoot: filepath.Join(tempDir, "crio"), + Root: filepath.Join(tempDir, "root"), TmpDir: tempDir, CNIConfigDir: CNIConfigDir, OCIRuntime: ociRuntime, - RunRoot: filepath.Join(tempDir, "crio-run"), + RunRoot: filepath.Join(tempDir, "runroot"), StorageOptions: storageOptions, SignaturePolicyPath: filepath.Join(INTEGRATION_ROOT, "test/policy.json"), CgroupManager: cgroupManager, @@ -308,15 +298,29 @@ func (p PodmanTestIntegration) AddImageToRWStore(image string) { } } -// createArtifact creates a cached image in the artifact dir +func imageTarPath(image string) string { + cacheDir := os.Getenv("PODMAN_TEST_IMAGE_CACHE_DIR") + if cacheDir == "" { + cacheDir = os.Getenv("TMPDIR") + if cacheDir == "" { + cacheDir = "/tmp" + } + } + + // e.g., registry.com/fubar:latest -> registry.com-fubar-latest.tar + imageCacheName := strings.Replace(strings.Replace(image, ":", "-", -1), "/", "-", -1) + ".tar" + + return filepath.Join(cacheDir, imageCacheName) +} + +// createArtifact creates a cached image tarball in a local directory func (p *PodmanTestIntegration) createArtifact(image string) { if os.Getenv("NO_TEST_CACHE") != "" { return } - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - fmt.Printf("Caching %s at %s...\n", image, destName) + destName := imageTarPath(image) if _, err := os.Stat(destName); os.IsNotExist(err) { + fmt.Printf("Caching %s at %s...\n", image, destName) pull := p.PodmanNoCache([]string{"pull", image}) pull.Wait(440) Expect(pull).Should(Exit(0)) @@ -326,7 +330,7 @@ func (p *PodmanTestIntegration) createArtifact(image string) { Expect(save).Should(Exit(0)) fmt.Printf("\n") } else { - fmt.Printf(" already exists.\n") + fmt.Printf("[image already cached: %s]\n", destName) } } @@ -738,12 +742,13 @@ func (p *PodmanTestIntegration) RestartRemoteService() { // RestoreArtifactToCache populates the imagecache from tarballs that were cached earlier func (p *PodmanTestIntegration) RestoreArtifactToCache(image string) error { - fmt.Printf("Restoring %s...\n", image) - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - p.CrioRoot = p.ImageCacheDir - restore := p.PodmanNoEvents([]string{"load", "-q", "-i", destName}) - restore.WaitWithDefaultTimeout() + tarball := imageTarPath(image) + if _, err := os.Stat(tarball); err == nil { + fmt.Printf("Restoring %s...\n", image) + p.Root = p.ImageCacheDir + restore := p.PodmanNoEvents([]string{"load", "-q", "-i", tarball}) + restore.WaitWithDefaultTimeout() + } return nil } @@ -795,7 +800,7 @@ func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache boo } podmanOptions := strings.Split(fmt.Sprintf("%s--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s --tmpdir %s --events-backend %s", - debug, p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager, p.TmpDir, eventsType), " ") + debug, p.Root, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager, p.TmpDir, eventsType), " ") if os.Getenv("HOOK_OPTION") != "" { podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) } diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index 2ecbd0eab..d60383029 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -148,7 +148,7 @@ func (p *PodmanTestIntegration) StopRemoteService() { //MakeOptions assembles all the podman main options func getRemoteOptions(p *PodmanTestIntegration, args []string) []string { podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s", - p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ") + p.Root, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ") if os.Getenv("HOOK_OPTION") != "" { podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) } @@ -164,15 +164,16 @@ func (p *PodmanTestIntegration) SeedImages() error { // RestoreArtifact puts the cached image into our test store func (p *PodmanTestIntegration) RestoreArtifact(image string) error { - fmt.Printf("Restoring %s...\n", image) - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - args := []string{"load", "-q", "-i", destName} - podmanOptions := getRemoteOptions(p, args) - command := exec.Command(p.PodmanBinary, podmanOptions...) - fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) - command.Start() - command.Wait() + tarball := imageTarPath(image) + if _, err := os.Stat(tarball); err == nil { + fmt.Printf("Restoring %s...\n", image) + args := []string{"load", "-q", "-i", tarball} + podmanOptions := getRemoteOptions(p, args) + command := exec.Command(p.PodmanBinary, podmanOptions...) + fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) + command.Start() + command.Wait() + } return nil } diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 001a869b1..4147ba2c3 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -7,7 +7,6 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "github.com/containers/podman/v3/pkg/rootless" ) @@ -59,11 +58,12 @@ func PodmanTestCreate(tempDir string) *PodmanTestIntegration { // RestoreArtifact puts the cached image into our test store func (p *PodmanTestIntegration) RestoreArtifact(image string) error { - fmt.Printf("Restoring %s...\n", image) - dest := strings.Split(image, "/") - destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - restore := p.PodmanNoEvents([]string{"load", "-q", "-i", destName}) - restore.Wait(90) + tarball := imageTarPath(image) + if _, err := os.Stat(tarball); err == nil { + fmt.Printf("Restoring %s...\n", image) + restore := p.PodmanNoEvents([]string{"load", "-q", "-i", tarball}) + restore.Wait(90) + } return nil } diff --git a/test/utils/utils.go b/test/utils/utils.go index 944c1ac3c..f41024072 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -36,7 +36,6 @@ type PodmanTestCommon interface { type PodmanTest struct { PodmanMakeOptions func(args []string, noEvents, noCache bool) []string PodmanBinary string - ArtifactPath string TempDir string RemoteTest bool RemotePodmanBinary string |