diff options
-rw-r--r-- | .cirrus.yml | 36 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | cmd/podman/common.go | 5 | ||||
-rw-r--r-- | cmd/podman/main_local.go | 19 | ||||
-rw-r--r-- | cmd/podman/shared/create.go | 7 | ||||
-rw-r--r-- | cmd/podman/start.go | 3 | ||||
-rwxr-xr-x | contrib/cirrus/integration_test.sh | 4 | ||||
-rw-r--r-- | contrib/cirrus/lib.sh | 7 | ||||
-rwxr-xr-x | contrib/cirrus/logcollector.sh | 11 | ||||
-rw-r--r-- | contrib/cirrus/packer/fedora_setup.sh | 1 | ||||
-rw-r--r-- | contrib/varlink/io.podman.socket | 1 | ||||
-rw-r--r-- | docs/podman-create.1.md | 2 | ||||
-rw-r--r-- | docs/podman-run.1.md | 2 | ||||
-rw-r--r-- | libpod/boltdb_state.go | 11 | ||||
-rw-r--r-- | libpod/container_internal.go | 3 | ||||
-rw-r--r-- | pkg/rootless/rootless.go | 45 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 3 | ||||
-rw-r--r-- | pkg/spec/spec.go | 23 | ||||
-rw-r--r-- | pkg/sysinfo/sysinfo.go | 9 | ||||
-rw-r--r-- | pkg/sysinfo/sysinfo_linux.go | 15 |
20 files changed, 142 insertions, 70 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 7f295e22e..71fa68d45 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -30,7 +30,7 @@ env: #### #### Cache-image names to test with (double-quotes around names are critical) ### - _BUILT_IMAGE_SUFFIX: "libpod-5816955207942144" + _BUILT_IMAGE_SUFFIX: "libpod-6296905679634432" FEDORA_CACHE_IMAGE_NAME: "fedora-30-${_BUILT_IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-${_BUILT_IMAGE_SUFFIX}" SPECIAL_FEDORA_CACHE_IMAGE_NAME: "xfedora-30-${_BUILT_IMAGE_SUFFIX}" @@ -368,38 +368,7 @@ testing_task: df_script: '$SCRIPT_BASE/logcollector.sh df' audit_log_script: '$SCRIPT_BASE/logcollector.sh audit' journal_script: '$SCRIPT_BASE/logcollector.sh journal' - -# Test crun only on latest Fedora -testing_crun_task: - - depends_on: - - "gating" - - "vendor" - - "varlink_api" - - "build_each_commit" - - "build_without_cgo" - - # Only test build cache-images, if that's what's requested - only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*' - - timeout_in: 120m - - env: - ADD_SECOND_PARTITION: true - OCI_RUNTIME: "/usr/bin/crun" - - networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' - setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' - install_crun_script: 'dnf install -y crun' - unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}' - integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' - system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}' - - on_failure: - failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh' - - always: - <<: *standardlogs + varlink_script: '$SCRIPT_BASE/logcollector.sh varlink' # This task executes tests under unique environments/conditions @@ -686,7 +655,6 @@ success_task: - "meta" - "image_prune" - "testing" - - "testing_crun" - "special_testing_rootless" - "special_testing_in_podman" - "special_testing_cgroupv2" @@ -89,6 +89,9 @@ RELEASE_DIST_VER ?= $(shell hack/get_release_info.sh DIST_VER) RELEASE_ARCH ?= $(shell hack/get_release_info.sh ARCH) RELEASE_BASENAME := $(shell hack/get_release_info.sh BASENAME) +# If non-empty, logs all output from varlink during remote system testing +VARLINK_LOG ?= + # If GOPATH not specified, use one in the local directory ifeq ($(GOPATH),) export GOPATH := $(CURDIR)/_output @@ -274,7 +277,7 @@ remotesystem: if timeout -v 1 true; then \ SOCK_FILE=$(shell mktemp --dry-run --tmpdir io.podman.XXXXXX);\ export PODMAN_VARLINK_ADDRESS=unix:$$SOCK_FILE; \ - ./bin/podman varlink --timeout=0 $$PODMAN_VARLINK_ADDRESS &>/dev/null & \ + ./bin/podman varlink --timeout=0 $$PODMAN_VARLINK_ADDRESS &> $(if $(VARLINK_LOG),$(VARLINK_LOG),/dev/null) & \ retry=5;\ while [[ $$retry -ge 0 ]]; do\ echo Waiting for varlink server...;\ diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 0115e6ef1..2a3f8f3ad 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -11,6 +11,7 @@ import ( "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/sysinfo" "github.com/fatih/camelcase" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" @@ -374,8 +375,8 @@ func getCreateFlags(c *cliconfig.PodmanCommand) { "PID namespace to use", ) createFlags.Int64( - "pids-limit", 0, - "Tune container pids limit (set -1 for unlimited)", + "pids-limit", sysinfo.GetDefaultPidsLimit(), + "Tune container pids limit (set 0 for unlimited)", ) createFlags.String( "pod", "", diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go index 917096e17..bdffb6b1e 100644 --- a/cmd/podman/main_local.go +++ b/cmd/podman/main_local.go @@ -200,17 +200,12 @@ func setupRootless(cmd *cobra.Command, args []string) error { return errors.Wrapf(err, "could not get pause process pid file path") } - if _, err := os.Stat(pausePidPath); err == nil { - became, ret, err := rootless.TryJoinFromFilePaths("", false, []string{pausePidPath}) - if err != nil { - logrus.Errorf("cannot join pause process. You may need to remove %s and stop all containers", pausePidPath) - logrus.Errorf("you can use `%s system migrate` to recreate the pause process and restart the containers", os.Args[0]) - logrus.Errorf(err.Error()) - os.Exit(1) - } - if became { - os.Exit(ret) - } + became, ret, err := rootless.TryJoinPauseProcess(pausePidPath) + if err != nil { + return err + } + if became { + os.Exit(ret) } // if there is no pid file, try to join existing containers, and create a pause process. @@ -225,7 +220,7 @@ func setupRootless(cmd *cobra.Command, args []string) error { paths = append(paths, ctr.Config().ConmonPidFile) } - became, ret, err := rootless.TryJoinFromFilePaths(pausePidPath, true, paths) + became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths) if err := movePauseProcessToScope(); err != nil { conf, err := runtime.GetConfig() if err != nil { diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index c9b05d2c4..9020613c5 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -686,6 +686,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. logDriver = c.String("log-driver") } + pidsLimit := c.Int64("pids-limit") + if c.String("cgroups") == "disabled" && !c.Changed("pids-limit") { + pidsLimit = 0 + } + config := &cc.CreateConfig{ Annotations: annotations, BuiltinImgVolumes: ImageVolumes, @@ -764,7 +769,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. MemorySwappiness: int(memorySwappiness), KernelMemory: memoryKernel, OomScoreAdj: c.Int("oom-score-adj"), - PidsLimit: c.Int64("pids-limit"), + PidsLimit: pidsLimit, Ulimit: c.StringSlice("ulimit"), }, RestartPolicy: c.String("restart"), diff --git a/cmd/podman/start.go b/cmd/podman/start.go index 737a6d9f1..2d2cf74d2 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -60,6 +60,9 @@ func startCmd(c *cliconfig.StartValues) error { } sigProxy := c.SigProxy || attach + if c.Flag("sig-proxy").Changed { + sigProxy = c.SigProxy + } if sigProxy && !attach { return errors.Wrapf(define.ErrInvalidArg, "you cannot use sig-proxy without --attach") diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh index 110066ea7..e8f6c50d9 100755 --- a/contrib/cirrus/integration_test.sh +++ b/contrib/cirrus/integration_test.sh @@ -4,7 +4,7 @@ set -e source $(dirname $0)/lib.sh -req_env_var GOSRC SCRIPT_BASE OS_RELEASE_ID OS_RELEASE_VER CONTAINER_RUNTIME +req_env_var GOSRC SCRIPT_BASE OS_RELEASE_ID OS_RELEASE_VER CONTAINER_RUNTIME VARLINK_LOG # Our name must be of the form xxxx_test or xxxx_test.sh, where xxxx is # the test suite to run; currently (2019-05) the only option is 'integration' @@ -59,7 +59,7 @@ case "$SPECIALMODE" in make test-binaries if [[ "$TEST_REMOTE_CLIENT" == "true" ]] then - make remote${TESTSUITE} + make remote${TESTSUITE} VARLINK_LOG=$VARLINK_LOG else make local${TESTSUITE} fi diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index fe4c25e73..8a7d3c1a3 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -35,6 +35,9 @@ PACKER_BASE=${PACKER_BASE:-./contrib/cirrus/packer} SETUP_MARKER_FILEPATH="${SETUP_MARKER_FILEPATH:-/var/tmp/.setup_environment_sh_complete}" AUTHOR_NICKS_FILEPATH="${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/git_authors_to_irc_nicks.csv" +# Log remote-client system test varlink output here +export VARLINK_LOG=/var/tmp/varlink.log + cd $GOSRC if type -P git &> /dev/null && [[ -d "$GOSRC/.git" ]] then @@ -370,8 +373,8 @@ remove_packaged_podman_files() { # yum/dnf/dpkg may list system directories, only remove files $LISTING_CMD | while read fullpath do - # TODO: This can go away when conmon gets it's own package - if [[ -d "$fullpath" ]] || [[ $(basename "$fullpath") == "conmon" ]] ; then continue; fi + # Sub-directories may contain unrelated/valuable stuff + if [[ -d "$fullpath" ]]; then continue; fi ooe.sh sudo rm -vf "$fullpath" done diff --git a/contrib/cirrus/logcollector.sh b/contrib/cirrus/logcollector.sh index b0a644f8c..17f5eb099 100755 --- a/contrib/cirrus/logcollector.sh +++ b/contrib/cirrus/logcollector.sh @@ -4,7 +4,7 @@ set -e source $(dirname $0)/lib.sh -req_env_var CIRRUS_WORKING_DIR OS_RELEASE_ID +req_env_var CIRRUS_WORKING_DIR OS_RELEASE_ID TEST_REMOTE_CLIENT # Assume there are other log collection commands to follow - Don't # let one break another that may be useful, but also keep any @@ -32,6 +32,15 @@ case $1 in df) showrun df -lhTx tmpfs ;; ginkgo) showrun cat $CIRRUS_WORKING_DIR/test/e2e/ginkgo-node-*.log ;; journal) showrun journalctl -b ;; + varlink) + if [[ "$TEST_REMOTE_CLIENT" == "true" ]] + then + echo "(Trailing 100 lines of $VARLINK_LOG)" + showrun tail -100 $VARLINK_LOG + else + die 0 "\$TEST_REMOTE_CLIENT is not 'true': $TEST_REMOTE_CLIENT" + fi + ;; packages) # These names are common to Fedora and Ubuntu PKG_NAMES=(\ diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh index 679ad3b8d..38b9e6860 100644 --- a/contrib/cirrus/packer/fedora_setup.sh +++ b/contrib/cirrus/packer/fedora_setup.sh @@ -31,6 +31,7 @@ ooe.sh sudo dnf install -y \ bridge-utils \ btrfs-progs-devel \ bzip2 \ + conmon \ container-selinux \ containernetworking-plugins \ containers-common \ diff --git a/contrib/varlink/io.podman.socket b/contrib/varlink/io.podman.socket index 629a5dd20..f6a3ddc49 100644 --- a/contrib/varlink/io.podman.socket +++ b/contrib/varlink/io.podman.socket @@ -8,4 +8,3 @@ SocketMode=0600 [Install] WantedBy=sockets.target -Also=multi-user.target diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index c088f3e94..46fa4fcd4 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -552,7 +552,7 @@ Default is to create a private PID namespace for the container **--pids-limit**=*limit* -Tune the container's pids limit. Set `-1` to have unlimited pids for the container. +Tune the container's pids limit. Set `0` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups). **--pod**=*name* diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index d677f8262..dfc634288 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -565,7 +565,7 @@ Default is to create a private PID namespace for the container **--pids-limit**=*limit* -Tune the container's pids limit. Set `-1` to have unlimited pids for the container. +Tune the container's pids limit. Set `0` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups). **--pod**=*name* diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go index e43d54eee..0bb1df7b8 100644 --- a/libpod/boltdb_state.go +++ b/libpod/boltdb_state.go @@ -2,6 +2,7 @@ package libpod import ( "bytes" + "os" "strings" "sync" @@ -658,9 +659,13 @@ func (s *BoltState) UpdateContainer(ctr *Container) error { return err } - // Handle network namespace - if err := replaceNetNS(netNSPath, ctr, newState); err != nil { - return err + // Handle network namespace. + if os.Geteuid() == 0 { + // Do it only when root, either on the host or as root in the + // user namespace. + if err := replaceNetNS(netNSPath, ctr, newState); err != nil { + return err + } } // New state compiled successfully, swap it into the current state diff --git a/libpod/container_internal.go b/libpod/container_internal.go index a4dcd23be..ac921d737 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -939,6 +939,9 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error { // With the spec complete, do an OCI create if err := c.ociRuntime.createContainer(c, nil); err != nil { + if strings.Contains(err.Error(), "this version of runc doesn't work on cgroups v2") { + logrus.Errorf("oci runtime %q does not support CGroups V2: use system migrate to mitigate", c.ociRuntime.name) + } return err } diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go new file mode 100644 index 000000000..7e9fe9db6 --- /dev/null +++ b/pkg/rootless/rootless.go @@ -0,0 +1,45 @@ +package rootless + +import ( + "os" + + "github.com/containers/storage" + "github.com/pkg/errors" +) + +func TryJoinPauseProcess(pausePidPath string) (bool, int, error) { + if _, err := os.Stat(pausePidPath); err != nil { + return false, -1, nil + } + + became, ret, err := TryJoinFromFilePaths("", false, []string{pausePidPath}) + if err == nil { + return became, ret, err + } + + // It could not join the pause process, let's lock the file before trying to delete it. + pidFileLock, err := storage.GetLockfile(pausePidPath) + if err != nil { + // The file was deleted by another process. + if os.IsNotExist(err) { + return false, -1, nil + } + return false, -1, errors.Wrapf(err, "error acquiring lock on %s", pausePidPath) + } + + pidFileLock.Lock() + defer func() { + if pidFileLock.Locked() { + pidFileLock.Unlock() + } + }() + + // Now the pause PID file is locked. Try to join once again in case it changed while it was not locked. + became, ret, err = TryJoinFromFilePaths("", false, []string{pausePidPath}) + if err != nil { + // It is still failing. We can safely remove it. + os.Remove(pausePidPath) + return false, -1, nil + } + return became, ret, err +} diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 6f6239e5f..05d641383 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -566,10 +566,10 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st r, w := os.NewFile(uintptr(fds[0]), "read file"), os.NewFile(uintptr(fds[1]), "write file") - defer errorhandling.CloseQuiet(w) defer errorhandling.CloseQuiet(r) if _, _, err := becomeRootInUserNS("", path, w); err != nil { + w.Close() lastErr = err continue } @@ -578,7 +578,6 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st return false, 0, err } defer func() { - errorhandling.CloseQuiet(r) C.reexec_in_user_namespace_wait(-1, 0) }() diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index c7aa003e8..57c6e8da7 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -7,6 +7,7 @@ import ( "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/sysinfo" "github.com/docker/docker/oci/caps" "github.com/docker/go-units" "github.com/opencontainers/runc/libcontainer/user" @@ -300,9 +301,25 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM blockAccessToKernelFilesystems(config, &g) // RESOURCES - PIDS - if config.Resources.PidsLimit != 0 { - g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit) - addedResources = true + if config.Resources.PidsLimit > 0 { + // if running on rootless on a cgroupv1 machine, pids limit is + // not supported. If the value is still the default + // then ignore the settings. If the caller asked for a + // non-default, then try to use it. + setPidLimit := true + if rootless.IsRootless() { + cgroup2, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return nil, err + } + if !cgroup2 && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() { + setPidLimit = false + } + } + if setPidLimit { + g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit) + addedResources = true + } } for name, val := range config.Env { diff --git a/pkg/sysinfo/sysinfo.go b/pkg/sysinfo/sysinfo.go index f046de4b1..686f66ce5 100644 --- a/pkg/sysinfo/sysinfo.go +++ b/pkg/sysinfo/sysinfo.go @@ -142,3 +142,12 @@ func popcnt(x uint64) (n byte) { x *= 0x0101010101010101 return byte(x >> 56) } + +// GetDefaultPidsLimit returns the default pids limit to run containers with +func GetDefaultPidsLimit() int64 { + sysInfo := New(true) + if !sysInfo.PidsLimit { + return 0 + } + return 4096 +} diff --git a/pkg/sysinfo/sysinfo_linux.go b/pkg/sysinfo/sysinfo_linux.go index 9e675c655..76bda23c6 100644 --- a/pkg/sysinfo/sysinfo_linux.go +++ b/pkg/sysinfo/sysinfo_linux.go @@ -7,6 +7,7 @@ import ( "path" "strings" + cg "github.com/containers/libpod/pkg/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -227,12 +228,18 @@ func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetI // checkCgroupPids reads the pids information from the pids cgroup mount point. func checkCgroupPids(quiet bool) cgroupPids { - _, err := cgroups.FindCgroupMountpoint("", "pids") + cgroup2, err := cg.IsCgroup2UnifiedMode() if err != nil { - if !quiet { - logrus.Warn(err) + logrus.Errorf("Failed to check cgroups version: %v", err) + } + if !cgroup2 { + _, err := cgroups.FindCgroupMountpoint("", "pids") + if err != nil { + if !quiet { + logrus.Warn(err) + } + return cgroupPids{} } - return cgroupPids{} } return cgroupPids{ |