diff options
106 files changed, 2283 insertions, 236 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 8389c638d..5a9dbcb54 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -28,11 +28,13 @@ env: TIMESTAMP: "awk --file ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/timestamp.awk" #### - #### Cache-image names to test with + #### Cache-image names to test with (double-quotes around names are critical) ### - FEDORA_CACHE_IMAGE_NAME: "fedora-30-libpod-5479475851034624" - PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-5479475851034624" - UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-5479475851034624" + _BUILT_IMAGE_SUFFIX: "libpod-5751722641719296" + 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}" + UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-${_BUILT_IMAGE_SUFFIX}" #### #### Variables for composing new cache-images (used in PR testing) from @@ -47,6 +49,7 @@ env: #### SPECIALMODE: "none" # don't do anything special TEST_REMOTE_CLIENT: false # don't test remote client by default + ADD_SECOND_PARTITION: false # will certainly fail inside containers #### #### Credentials and other secret-sauces, decrypted at runtime when authorized. @@ -90,8 +93,8 @@ gating_task: timeout_in: 20m - networking_script: # Don't bother going further if something is down - - 'while read host port; do nc -zv -w 13 $host $port || exit 1; done < ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/required_host_ports.txt' + # Don't bother going further if something is down + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' gate_script: # N/B: entrypoint.sh resets $GOSRC (same as make clean) @@ -261,6 +264,7 @@ meta_task: IMGNAMES: >- ${FEDORA_CACHE_IMAGE_NAME} ${PRIOR_FEDORA_CACHE_IMAGE_NAME} + ${SPECIAL_FEDORA_CACHE_IMAGE_NAME} ${UBUNTU_CACHE_IMAGE_NAME} ${IMAGE_BUILDER_CACHE_IMAGE_NAME} BUILDID: "${CIRRUS_BUILD_ID}" @@ -285,7 +289,7 @@ image_prune_task: - "meta" container: - image: "quay.io/cevich/imgprune:latest" # see contrib/imgprune + image: "quay.io/libpod/imgprune:latest" # see contrib/imgprune cpu: 1 memory: 1 @@ -322,10 +326,12 @@ testing_task: timeout_in: 120m env: + ADD_SECOND_PARTITION: true matrix: TEST_REMOTE_CLIENT: true TEST_REMOTE_CLIENT: false + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}' integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' @@ -343,6 +349,41 @@ testing_task: 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}' + cache_release_archive_script: >- + [[ "$TEST_REMOTE_CLIENT" == "false" ]] || \ + $SCRIPT_BASE/cache_release_archive.sh |& ${TIMESTAMP} + + on_failure: + failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh' + + always: + <<: *standardlogs + # This task executes tests under unique environments/conditions special_testing_rootless_task: @@ -357,14 +398,15 @@ special_testing_rootless_task: only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*' env: + ADD_SECOND_PARTITION: true SPECIALMODE: 'rootless' # See docs - matrix: TEST_REMOTE_CLIENT: true TEST_REMOTE_CLIENT: false timeout_in: 60m + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}' @@ -388,10 +430,12 @@ special_testing_in_podman_task: only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*' env: + ADD_SECOND_PARTITION: true SPECIALMODE: 'in_podman' # See docs timeout_in: 60m + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' @@ -418,6 +462,7 @@ special_testing_cross_task: timeout_in: 20m + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' cache_release_archive_script: '$SCRIPT_BASE/cache_release_archive.sh |& ${TIMESTAMP}' @@ -425,6 +470,37 @@ special_testing_cross_task: failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh' +special_testing_cgroupv2_task: + + depends_on: + - "gating" + - "varlink_api" + - "vendor" + + only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\*\*\*\s*CIRRUS:\s*TEST\s*IMAGES\s*\*\*\*.*' + + gce_instance: + image_name: "${SPECIAL_FEDORA_CACHE_IMAGE_NAME}" + + env: + SPECIALMODE: 'cgroupv2' # See docs + matrix: + TEST_REMOTE_CLIENT: true + TEST_REMOTE_CLIENT: false + + timeout_in: 20m + + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' + setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' + integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' + + on_failure: + failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh' + + always: + <<: *standardlogs + + # Test building of new cache-images for future PR testing, in this PR. test_build_cache_images_task: @@ -450,7 +526,8 @@ test_build_cache_images_task: - compute - devstorage.full_control - environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' + setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' build_vm_images_script: '$SCRIPT_BASE/build_vm_images.sh |& ${TIMESTAMP}' df_script: '${DFCMD}' journalctl_b_script: 'journalctl -b' @@ -474,24 +551,36 @@ verify_test_built_images_task: - "test_build_cache_images" gce_instance: - matrix: - # Images are generated separately, from build_images_task (below) - image_name: "fedora-29${BUILT_IMAGE_SUFFIX}" - image_name: "fedora-30${BUILT_IMAGE_SUFFIX}" - image_name: "ubuntu-18${BUILT_IMAGE_SUFFIX}" + # Images generated by test_build_cache_images_task (above) + image_name: "${PACKER_BUILDER_NAME}${BUILT_IMAGE_SUFFIX}" env: + ADD_SECOND_PARTITION: true matrix: TEST_REMOTE_CLIENT: true TEST_REMOTE_CLIENT: false + matrix: + # Required env. var. by check_image_script + PACKER_BUILDER_NAME: "fedora-29" + PACKER_BUILDER_NAME: "fedora-30" + PACKER_BUILDER_NAME: "xfedora-30" + PACKER_BUILDER_NAME: "ubuntu-18" + networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' + environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' + # Verify expectations once per image + check_image_script: >- + [[ "$TEST_REMOTE_CLIENT" == "false" ]] || \ + $SCRIPT_BASE/check_image.sh |& ${TIMESTAMP} # Note: A truncated form of normal testing. It only needs to confirm new images # "probably" work. A full round of testing will happen again after $*_CACHE_IMAGE_NAME # are updated in this or another PR (w/o '***CIRRUS: TEST IMAGES***'). - environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' - check_image_script: '$SCRIPT_BASE/check_image.sh' - integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' - system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}' + integration_test_script: >- + [[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \ + $SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} + system_test_script: >- + [[ "$PACKER_BUILDER_NAME" == "xfedora-30" ]] || \ + $SCRIPT_BASE/system_test.sh |& ${TIMESTAMP} always: <<: *standardlogs @@ -513,8 +602,10 @@ success_task: - "meta" - "image_prune" - "testing" + - "testing_crun" - "special_testing_rootless" - "special_testing_in_podman" + - "special_testing_cgroupv2" - "special_testing_cross" - "test_build_cache_images" - "verify_test_built_images" @@ -551,8 +642,10 @@ release_task: - "meta" - "image_prune" - "testing" + - "testing_crun" - "special_testing_rootless" - "special_testing_in_podman" + - "special_testing_cgroupv2" - "special_testing_cross" - "test_build_cache_images" - "verify_test_built_images" @@ -265,6 +265,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [error ErrCtrStopped](#ErrCtrStopped) +[error ErrRequiresCgroupsV2ForRootless](#ErrRequiresCgroupsV2ForRootless) + [error ErrorOccurred](#ErrorOccurred) [error ImageNotFound](#ImageNotFound) @@ -2008,6 +2010,9 @@ ContainerNotFound means the container could not be found by the provided name or ### <a name="ErrCtrStopped"></a>type ErrCtrStopped Container is already stopped +### <a name="ErrRequiresCgroupsV2ForRootless"></a>type ErrRequiresCgroupsV2ForRootless + +This function requires CGroupsV2 to run in rootless mode. ### <a name="ErrorOccurred"></a>type ErrorOccurred ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message @@ -2,7 +2,7 @@ export GO111MODULE=off GO ?= go DESTDIR ?= -EPOCH_TEST_COMMIT ?= 55e028a12ee003e057c65e376fe4b723d28ae52e +EPOCH_TEST_COMMIT ?= b9a176bea94b8e3a97a70dd7cd599f1a057777b0 HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD @@ -20,6 +20,7 @@ SHAREDIR_CONTAINERS ?= ${PREFIX}/share/containers ETCDIR ?= /etc TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system +USERSYSTEMDDIR ?= ${PREFIX}/lib/systemd/user BUILDFLAGS ?= BUILDTAGS ?= \ $(shell hack/apparmor_tag.sh) \ @@ -253,10 +254,34 @@ remoteintegration: varlink_generate test-binaries ginkgo-remote localsystem: # Wipe existing config, database, and cache: start with clean slate. $(RM) -rf ${HOME}/.local/share/containers ${HOME}/.config/containers - if timeout -v 1 true; then PODMAN=./bin/podman bats test/system/; else echo "Skipping localsystem: 'timeout -v' unavailable'"; fi + if timeout -v 1 true; then PODMAN=./bin/podman bats test/system/; else echo "Skipping $@: 'timeout -v' unavailable'"; fi remotesystem: - @echo "remotesystem - unimplemented" + # Wipe existing config, database, and cache: start with clean slate. + $(RM) -rf ${HOME}/.local/share/containers ${HOME}/.config/containers + # Start varlink server using tmp socket; loop-wait for it; + # test podman-remote; kill server, clean up tmp socket file. + # varlink server spews copious unhelpful output; ignore it. + rc=0;\ + 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 & \ + retry=5;\ + while [[ $$retry -ge 0 ]]; do\ + echo Waiting for varlink server...;\ + sleep 1;\ + ./bin/podman-remote info &>/dev/null && break;\ + retry=$$(expr $$retry - 1);\ + done;\ + env PODMAN=./bin/podman-remote bats test/system/ ;\ + rc=$$?;\ + kill %1;\ + rm -f $$SOCK_FILE;\ + else \ + echo "Skipping $@: 'timeout -v' unavailable'";\ + fi;\ + exit $$rc system.test-binary: .install.ginkgo $(GO) test -c ./test/system @@ -311,6 +336,7 @@ brew-pkg: install-podman-remote-docs podman-remote-darwin @cp ./bin/podman-remote-darwin ./brew/podman @cp -r ./docs/remote ./brew/docs/ @cp docs/podman-remote.1 ./brew/docs/podman.1 + @cp docs/podman-remote.conf.5 ./brew/docs/podman-remote.conf.5 @sed -i 's/podman\\*-remote/podman/g' ./brew/docs/podman.1 @sed -i 's/Podman\\*-remote/Podman\ for\ Mac/g' ./brew/docs/podman.1 @sed -i 's/podman\.conf/podman\-remote\.conf/g' ./brew/docs/podman.1 @@ -371,9 +397,11 @@ install.docker: docker-docs install ${SELINUXOPT} -m 644 docs/docker*.1 -t $(DESTDIR)$(MANDIR)/man1 install.systemd: - install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${TMPFILESDIR} + install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR} ${DESTDIR}${TMPFILESDIR} install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.socket ${DESTDIR}${SYSTEMDDIR}/io.podman.socket + install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.socket ${DESTDIR}${USERSYSTEMDDIR}/io.podman.socket install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.service ${DESTDIR}${SYSTEMDDIR}/io.podman.service + install ${SELINUXOPT} -m 644 contrib/varlink/io.podman.service ${DESTDIR}${USERSYSTEMDDIR}/io.podman.service install ${SELINUXOPT} -m 644 contrib/varlink/podman.conf ${DESTDIR}${TMPFILESDIR}/podman.conf uninstall: diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f55fd9b18..3cfd8ed86 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,23 @@ # Release Notes +## 1.5.1 +### Features +- The hostname of pods is now set to the pod's name + +### Bugfixes +- Fixed a bug where `podman run` and `podman create` did not honor the `--authfile` option ([#3730](https://github.com/containers/libpod/issues/3730)) +- Fixed a bug where containers restored with `podman container restore --import` would incorrectly duplicate the Conmon PID file of the original container +- Fixed a bug where `podman build` ignored the default OCI runtime configured in `libpod.conf` +- Fixed a bug where `podman run --rm` (or force-removing any running container with `podman rm --force`) were not retrieving the correct exit code ([#3795](https://github.com/containers/libpod/issues/3795)) +- Fixed a bug where Podman would exit with an error if any configured hooks directory was not present +- Fixed a bug where `podman inspect` and `podman commit` would not use the correct `CMD` for containers run with `podman play kube` +- Fixed a bug created pods when using rootless Podman and CGroups V2 ([#3801](https://github.com/containers/libpod/issues/3801)) +- Fixed a bug where the `podman events` command with the `--since` or `--until` options could take a very long time to complete + +### Misc +- Rootless Podman will now inherit OCI runtime configuration from the root configuration ([#3781](https://github.com/containers/libpod/issues/3781)) +- Podman now properly sets a user agent while contacting registries ([#3788](https://github.com/containers/libpod/issues/3788)) + ## 1.5.0 ### Features - Podman containers can now join the user namespaces of other containers with `--userns=container:$ID`, or a user namespace at an arbitary path with `--userns=ns:$PATH` diff --git a/changelog.txt b/changelog.txt index 51ac92979..b0a847aee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,299 @@ +- Changelog for v1.5.1 (2019-08-15) + * Add release notes for v1.5.1 + * Set Pod hostname as Pod name + * tests for exit status on podman run --rm + * performance fix for podman events with large journalds + * pkg/cgroups: use DBUS session when rootless + * Fix play kube command in pod yaml + * removMergeDir from inspect result if not mounted + * Running Podman with a nonexistent hooks dir is nonfatal + * Cirrus: Install varlink on Ubuntu + * Cirrus: Install varlink on Fedora + * Add missing stage-packages in snapcraft.yaml. + * Add RHEL and SUSE to snap doc + * start groundwork for adding snap + * Add user systemd service and socket + * Small optimization - only store exit code when nonzero + * Fix container exit code with Journald backend + * Revert "Cirrus: Temp. workaround missing imgprune image" + * Homebrew installation in install.md + * varlink endpoint for containerstats requires root + * Adjust get_ci_vm.sh for substitution + * Cirrus: Add verification for cgroupv2 image + * Cirrus: Add experimental fedora VM image & test + * image: add user agent to Docker registry options + * Cirrus: Minor, use newer Ubuntu base image + * tests: disable some tests currently failing when not using runc + * containers: look also for 'file not found' in the error message + * cirrus: add tests with crun on Fedora 30 + * rootless: cherry-pick runtime from the system configuration + * cirrus: install crun + * cmd: drop check for euid==0 + * storage: drop unused geteuid check + * cmd, stats: fix check for rootless mode + * oci: drop check for euid==0 + * build: use the configured runtime + * Adjust read count so that a newline can be added afterwards + * Fix incorrect use of realloc() + * Bump gitvalidation epoch + * Bump to v1.5.1-dev + * Fix a couple of errors descovered by coverity + * Test that restored container does not depend on the original container + * Fix up ConmonPidFile after restore + * Cirrus: Enable updates-testing repo for Fedora + * enable windows remote client + * implement 'make remotesystem' + * Squish a few tpyo nits in container.go doc + * Cirrus: Add Second partition for storage testing + +- Changelog for v1.5.0 (2019-08-09) + * vendor github.com/containers/storage@v1.13.2 + * Improve dns-search validation, empty domains now return an error + * fix create&run getting --authfile from cli + * Add release notes for v1.5.0 + * Touch up build man page + * podman-container-runlabel(1): drop note + * make rmi messages more compatible with docker + * Add conmon probe to runtime construction + * fix copy change file owner if cp from container + * Vendor Buildah 1.10.1 + * Allow the passing of '.' to --dns-search + * add make to make installs + * namespaces: fix Container() call + * Add a test for verifying ENTRYPOINT and CMD + * fix port early return + * Allow --ro=[true|false] with mount flag + * refer to container whose namespace we share + * add test to verify hostname is shared in a pod + * Properly share UTS namespaces in a pod + * When populating CMD, do not include Entrypoint + * systemd library conflict with seektail and addmatch + * pod top test: reenable + * cgroup: fix regression when running systemd + * Add invalid credentials fix to docs + * Revert "rootless: Rearrange setup of rootless containers" + * restore: correctly set StartedTime + * container stop: kill conmon + * honor libpod.conf in /usr/share/containers + * fix system df crashes on unnamed images + * Don't log errors to the screen when XDG_RUNTIME_DIR is not set + * various fixes for varlink endpoints + * add eventlogger to info + * Add handling for empty LogDriver + * Add rootless NFS and OverlayFS warnings to docs + * podman events format json + * add godoc link to readme + * restore: added --ignore-static-ip option + * System tests: resolve hang in rawhide rootless + * fix search output limit + * Add capability functionality to play kube + * Use "none" instead of "null" for the null eventer + * Deduplicate capabilities in generate kube + * Fix typo + * Pass on events-backend config to cleanup processes + * Print Pod ID in `podman inspect` output + * go build: use `-mod=vendor` for go >= 1.11.x + * Use buildah/pkg/parse volume parsing rather then internal version + * github.com/containers/storage v1.12.13 + * Add new exit codes to rm & rmi for running containers & dependencies + * Add runtime and conmon path discovery + * systemd, cgroupsv2: not bind mount /sys/fs/cgroup/systemd + * Ensure we generate a 'stopped' event on force-remove + * Fix Dockerfile - a dependency's name was changed + * System events are valid, don't error on them + * Do not use an events backend when restoring images + * Expose Null eventer and allow its use in the Podman CLI + * Force tests to use file backend for events + * Add a flag to set events logger type + * Fix test suite + * Retrieve exit codes for containers via events + * podman: fix memleak caused by renaming and not deleting the exit file + * Cirrus: Fix release dependencies + * Cirrus: Fix re-run of release task into no-op. + * e2e test: check exit codes for pull, save, inspect + * rootless: Rearrange setup of rootless containers + * Add comment to describe postConfigureNetNS + * Vendor in buildah 1.9.2 + * Build fix for 32-bit systems. + * Set -env variables as appropriate + * Touch up input argument error on create + * Update libpod.conf to be NixOS friendly + * Allow info test to work with usernames w/dash + * Touch up XDG, add rootless links + * Fix the syntax in the podman export documentation example + * fix `podman -v` regression + * Move random IP code for tests from checkpoint to common + * Fix commit --changes env=X=Y + * Update pause/unpause video links and demo + * Cirrus: Remove fixed clone depth + * podman: support --userns=ns|container + * pods: do not to join a userns if there is not any + * Documenation & build automation for remote darwin + * Cirrus: Bypass release during image-building + * Use systemd cgroups for Ubuntu + * Cirrus: Ubuntu: Set + Test for $RUNC_BINARY + * Cirrus: Simplify evil-unit check in image + * Cirrus: Silence systemd-banish noise + * Cirrus: Fix image build metadata update + * Cirrus: Fix missing -n on CentOS + * Cirrus: Remove disused COMMIT variables + * Improved hooks monitoring + * Fix possible runtime panic if image history len is zero + * When retrieving volumes, only use exact names + * fix import not ignoring url path + * Document SELinux label requirements for the rootfs argument + * Fixes issue #3577. + * refactor to reduce duplicated error parsing + * remove debug prints + * Re-add int64 casts for ctime + * fix build --network=container + * Fix a segfault on Podman no-store commands with refresh + * always send generic error in case io fails + * only use stdin if specified + * buffer errChan + * move handleTerminalAttach to generic build + * remove unnecessary conversions + * add detach keys support for remote + * move editing of exitCode to runtime + * Update e2e tests for remote exec + * Finish up remote exec implementation + * golangci-lint cleanup + * install.md: mention all build tags + * golangci-lint phase 4 + * Change wait to sleep in podmanimage readme + * bump cirrus images to get new conmon + * Implement conmon exec + * bump conmon to 1.0.0-rc2 + * Cirrus: Temp. workaround missing imgprune image + * vendor github.com/containers/image@v2.0.1 + * golangci-lint round #3 + * Remove debug message + * Cleanup Pull Message + * Cirrus: Fix post-merge env. var. not set. + * mkdir -p /etc/cni/net.d requires sudo + * Add support for listing read/only and read/write images + * support podman ps filter regular expressions + * rootless: add rw devices with --privileged + * Cirrus: Minor scripting typo fix + * fix --dns* and --network not set to host conflict + * podman-remote make --size optional in ps + * Remove exec PID files after use to prevent memory leaks + * Add DefaultContent API to retrieve apparmor profile content + * libpod: support for cgroup namespace + * Make GOPATH-related symlinking more precise + * Populate inspect with security-opt settings + * Properly retrieve Conmon PID + * Move the HostConfig portion of Inspect inside libpod + * Fix play kube command + * spec: rework --ulimit host + * Cirrus: Add image-test for locked dpkg + * Cirrus: Use images w/o periodic svcs + * Cirrus: Disable most periodic services/timers + * dependency/analyses: simplify scripts + * dependency-tree analysis: direct and transitive + * analyses: README: consistent code examples + * analyses: README: fix typos + * analyses: add dependency-tree.sh + * analyses: add README.md + * hack/analyses -> dependencies/analyses + * hack/analyses/go-archive-analysis.sh: fix sorting + * add hack/analyses/nm-symbols-analysis.sh + * analyse package sizes + * Completion: complete "--health-start-period" in bash + * Make the healthcheck flags compatible with Docker CLI + * healthcheck: reject empty commands + * create: ignore check if image has HEALTHCHECK NONE + * create: apply defaults on image healthcheck options + * healthcheck: improve command list parser + * Completion: --no-healthcheck is not an option + * Cirrus: Abstract destination branch refs. + * Cirrus: Print images that should be pruned + * create: improve parser for --healthcheck-command + * Improves STD output/readability in combination with debug output. + * Fix the double replySendFile() + * Cirrus: Update to freshly built cache-images + * Cirrus: Execute system-tests during image-validation + * Cirrus: Fix missing removal of packaged podman + * cgroupsv2: do not enable controllers for the last component + * spec: fix userns with less than 5 gids + * Fix spelling mistakes in man pages and other docs + * Add glob parsing for --env flag + * Add support for -env-host + * cgroups: fix a leak when using cgroupfs + * cgroups: attempt a recursive rmdir + * Fix a bug where ctrs could not be removed from pods + * golangci-lint pass number 2 + * Add tests for --ignore-rootfs checkpoint/restore option + * Add --ignore-rootfs option for checkpoint/restore + * Fix typo in checkpoint/restore related texts + * Include root file-system changes in container migration + * Add function to get a filtered tarstream diff + * Correctly set FinishedTime for checkpointed container + * first pass of corrections for golangci-lint + * Cirrus: Fix #3543: Failure in 'release' task + * fix bug convert volume host path to absolute + * Cirrus: Fix 473d06045 / enable build_without_cgo + * account for varlink calls that dont use more + * runtime: drop spurious message log + * Ensure we have a valid store when we refresh + * cgroups: skip not existing cpuacct files + * cgroups: support creating cgroupsv2 paths + * make localsystem: wipe all user config state + * podman: create and run honors auth file location + * healthcheck: support rootless mode + * Use random IP addresses during checkpoint/restore tests + * Fix podman-remote usage message to display `podman-remote` instead of `podman` + * rootless.md: Include GPFS as a parallel filesystem + * speed up rootless tests + * podman: add --ulimit host + * docs: fix --healthcheck-command option + * code cleanup + * fix integration flake tests + * CONTRIBUTING.md: fix project paths + * get last container event + * Do not hardcode podman binary location in generate systemd. + * Move skipping systemd tests to early setup. + * Reload systemd daemon on creation of units location dir in tests. + * Add debug information to "generate systemd" test. + * Use default conmon pidfile location for root containers. + * Use conmon pidfile in generated systemd unit as PIDFile. + * Cirrus: Automate releasing of tested binaries + * trivial cleanups from golang + * ps should use nostore when possible + * libpod: discerne partial IDs between containers and pods + * Added instruction to enable the user namespaces permanenty in Manjaro + * Addressed code review comments + * Updated install.md for Manjaro Linux + * Vendor latest OCICNI version + * Bump current version in README + * Wipe PID and ConmonPID in state after container stops + * Store Conmon's PID in our state and display in inspect + * Restart failed containers in tests + * Improve parsing of mounts + * Add test for generate kube with volumes + * Bump gitvalidation epoch + * Bump to v1.4.5-dev + * Fix rootless detection error for pause & unpause + * Deduplicate volumes + * cirrus: add test for compiling without cgo + * lock: new lock type "file" + * runtime: allow to specify the lock mechanism + * lock: disable without cgo + * spec: move cgo stuff to their own file + * rootless: allow to build without cgo + * attach: move cgo bits to a different file + * vendor: update containers/psgo + * Update the testing documentation with system tests. + * Pass along volumes to pod yaml + * Configure container volumes for generate kube + * configure runtime without store + * Add RUN priv'd test for build + * Cirrus: Use packaged dependencies + * Add exec after checkpoint/restore test + * Provide correct SELinux mount-label for restored container + * Track if a container is restored from an exported checkpoint + * libpod/container_internal: Make all errors loading explicitly configured hook dirs fatal + - Changelog for v1.4.4 (2019-07-02) * Fix release notes * Ensure locks are freed when ctr/pod creation fails diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index d5098ee51..f7c78908f 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -258,6 +258,20 @@ type MountValues struct { Latest bool } +type NetworkListValues struct { + PodmanCommand + Filter []string + Quiet bool +} + +type NetworkRmValues struct { + PodmanCommand +} + +type NetworkInspectValues struct { + PodmanCommand +} + type PauseValues struct { PodmanCommand All bool diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go index 0f43e0b88..587c8260f 100644 --- a/cmd/podman/main_local.go +++ b/cmd/podman/main_local.go @@ -1,4 +1,5 @@ // +build !remoteclient +// +build linux package main diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go index d534f5bcb..a005e925c 100644 --- a/cmd/podman/main_remote.go +++ b/cmd/podman/main_remote.go @@ -3,14 +3,8 @@ package main import ( - "fmt" - "os" "os/user" - "path/filepath" - "github.com/containers/libpod/pkg/util" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -31,49 +25,6 @@ func init() { rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console") } -func setSyslog() error { - var err error - cfgHomeDir := os.Getenv("XDG_CONFIG_HOME") - if cfgHomeDir == "" { - if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil { - return err - } - if err = os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil { - return errors.Wrapf(err, "cannot set XDG_CONFIG_HOME") - } - } - path := filepath.Join(cfgHomeDir, "containers") - - // Log to file if not using syslog - - if _, err := os.Stat(path); os.IsNotExist(err) { - if err := os.MkdirAll(path, 0750); err != nil { - fmt.Fprintf(os.Stderr, "%v", err) - return err - } - } - - // Update path to include file name - path = filepath.Join(path, "podman.log") - - // Create the log file if doesn't exist. And append to it if it already exists. - file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640) - if err != nil { - // Cannot open log file. Logging to stderr - fmt.Fprintf(os.Stderr, "%v", err) - return err - } else { - formatter := new(logrus.TextFormatter) - formatter.FullTimestamp = true - logrus.SetFormatter(formatter) - logrus.SetOutput(file) - } - - // Note this message is only logged if --log-level >= Info! - logrus.Infof("Logging level set to %s", logrus.GetLevel().String()) - return nil -} - func profileOn(cmd *cobra.Command) error { return nil } diff --git a/cmd/podman/main_remote_supported.go b/cmd/podman/main_remote_supported.go new file mode 100644 index 000000000..bb567c273 --- /dev/null +++ b/cmd/podman/main_remote_supported.go @@ -0,0 +1,57 @@ +// +build remoteclient +// +build linux darwin + +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/containers/libpod/pkg/util" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +func setSyslog() error { + var err error + cfgHomeDir := os.Getenv("XDG_CONFIG_HOME") + if cfgHomeDir == "" { + if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil { + return err + } + if err = os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil { + return errors.Wrapf(err, "cannot set XDG_CONFIG_HOME") + } + } + path := filepath.Join(cfgHomeDir, "containers") + + // Log to file if not using syslog + + if _, err := os.Stat(path); os.IsNotExist(err) { + if err := os.MkdirAll(path, 0750); err != nil { + fmt.Fprintf(os.Stderr, "%v", err) + return err + } + } + + // Update path to include file name + path = filepath.Join(path, "podman.log") + + // Create the log file if doesn't exist. And append to it if it already exists. + file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640) + if err != nil { + // Cannot open log file. Logging to stderr + fmt.Fprintf(os.Stderr, "%v", err) + return err + } else { + formatter := new(logrus.TextFormatter) + formatter.FullTimestamp = true + logrus.SetFormatter(formatter) + logrus.SetOutput(file) + } + + // Note this message is only logged if --log-level >= Info! + logrus.Infof("Logging level set to %s", logrus.GetLevel().String()) + return nil +} diff --git a/cmd/podman/main_remote_windows.go b/cmd/podman/main_remote_windows.go new file mode 100644 index 000000000..0ef1370ce --- /dev/null +++ b/cmd/podman/main_remote_windows.go @@ -0,0 +1,7 @@ +// +build remoteclient,windows + +package main + +func setSyslog() error { + return nil +} diff --git a/cmd/podman/network.go b/cmd/podman/network.go new file mode 100644 index 000000000..83a5e71ab --- /dev/null +++ b/cmd/podman/network.go @@ -0,0 +1,31 @@ +//+build !remoteclient + +package main + +import ( + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/spf13/cobra" +) + +var networkcheckDescription = "Manage networks" +var networkcheckCommand = cliconfig.PodmanCommand{ + Command: &cobra.Command{ + Use: "network", + Short: "Manage Networks", + Long: networkcheckDescription, + RunE: commandRunE(), + }, +} + +// Commands that are universally implemented +var networkcheckCommands = []*cobra.Command{ + _networkinspectCommand, + _networklistCommand, + _networkrmCommand, +} + +func init() { + networkcheckCommand.AddCommand(networkcheckCommands...) + networkcheckCommand.SetUsageTemplate(UsageTemplate()) + rootCmd.AddCommand(networkcheckCommand.Command) +} diff --git a/cmd/podman/network_inspect.go b/cmd/podman/network_inspect.go new file mode 100644 index 000000000..38aaf6ba4 --- /dev/null +++ b/cmd/podman/network_inspect.go @@ -0,0 +1,48 @@ +// +build !remoteclient + +package main + +import ( + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + networkinspectCommand cliconfig.NetworkInspectValues + networkinspectDescription = `Inspect network` + _networkinspectCommand = &cobra.Command{ + Use: "inspect NETWORK [NETWORK...] [flags] ", + Short: "network inspect", + Long: networkinspectDescription, + RunE: func(cmd *cobra.Command, args []string) error { + networkinspectCommand.InputArgs = args + networkinspectCommand.GlobalFlags = MainGlobalOpts + networkinspectCommand.Remote = remoteclient + return networkinspectCmd(&networkinspectCommand) + }, + Example: `podman network inspect podman`, + } +) + +func init() { + networkinspectCommand.Command = _networkinspectCommand + networkinspectCommand.SetHelpTemplate(HelpTemplate()) + networkinspectCommand.SetUsageTemplate(UsageTemplate()) +} + +func networkinspectCmd(c *cliconfig.NetworkInspectValues) error { + if rootless.IsRootless() && !remoteclient { + return errors.New("network inspect is not supported for rootless mode") + } + if len(c.InputArgs) < 1 { + return errors.Errorf("at least one network name is required") + } + runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand) + if err != nil { + return err + } + return runtime.NetworkInspect(c) +} diff --git a/cmd/podman/network_list.go b/cmd/podman/network_list.go new file mode 100644 index 000000000..16edf743b --- /dev/null +++ b/cmd/podman/network_list.go @@ -0,0 +1,53 @@ +// +build !remoteclient + +package main + +import ( + "errors" + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" + "github.com/spf13/cobra" +) + +var ( + networklistCommand cliconfig.NetworkListValues + networklistDescription = `List networks` + _networklistCommand = &cobra.Command{ + Use: "ls", + Args: noSubArgs, + Short: "network list", + Long: networklistDescription, + RunE: func(cmd *cobra.Command, args []string) error { + networklistCommand.InputArgs = args + networklistCommand.GlobalFlags = MainGlobalOpts + networklistCommand.Remote = remoteclient + return networklistCmd(&networklistCommand) + }, + Example: `podman network list`, + } +) + +func init() { + networklistCommand.Command = _networklistCommand + networklistCommand.SetHelpTemplate(HelpTemplate()) + networklistCommand.SetUsageTemplate(UsageTemplate()) + flags := networklistCommand.Flags() + // TODO enable filters based on something + //flags.StringSliceVarP(&networklistCommand.Filter, "filter", "f", []string{}, "Pause all running containers") + flags.BoolVarP(&networklistCommand.Quiet, "quiet", "q", false, "display only names") +} + +func networklistCmd(c *cliconfig.NetworkListValues) error { + if rootless.IsRootless() && !remoteclient { + return errors.New("network list is not supported for rootless mode") + } + if len(c.InputArgs) > 0 { + return errors.New("network list takes no arguments") + } + runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand) + if err != nil { + return err + } + return runtime.NetworkList(c) +} diff --git a/cmd/podman/network_rm.go b/cmd/podman/network_rm.go new file mode 100644 index 000000000..50bd48cea --- /dev/null +++ b/cmd/podman/network_rm.go @@ -0,0 +1,48 @@ +// +build !remoteclient + +package main + +import ( + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + networkrmCommand cliconfig.NetworkRmValues + networkrmDescription = `Remove networks` + _networkrmCommand = &cobra.Command{ + Use: "rm [flags] NETWORK [NETWORK...]", + Short: "network rm", + Long: networkrmDescription, + RunE: func(cmd *cobra.Command, args []string) error { + networkrmCommand.InputArgs = args + networkrmCommand.GlobalFlags = MainGlobalOpts + networkrmCommand.Remote = remoteclient + return networkrmCmd(&networkrmCommand) + }, + Example: `podman network rm podman`, + } +) + +func init() { + networkrmCommand.Command = _networkrmCommand + networkrmCommand.SetHelpTemplate(HelpTemplate()) + networkrmCommand.SetUsageTemplate(UsageTemplate()) +} + +func networkrmCmd(c *cliconfig.NetworkRmValues) error { + if rootless.IsRootless() && !remoteclient { + return errors.New("network rm is not supported for rootless mode") + } + if len(c.InputArgs) < 1 { + return errors.Errorf("at least one network name is required") + } + runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand) + if err != nil { + return err + } + return runtime.NetworkRemove(c) +} diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index b6154b4db..d04c85dba 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -78,7 +78,7 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error { if !c.Infra && c.Flag("share").Changed && c.Share != "none" && c.Share != "" { return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container") } - if c.Flag("pod-id-file").Changed && os.Geteuid() == 0 { + if c.Flag("pod-id-file").Changed { podIdFile, err = util.OpenExclusiveFile(c.PodIDFile) if err != nil && os.IsExist(err) { return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", c.PodIDFile) diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go index 46cacc026..2f1ebd3ac 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -15,6 +15,8 @@ import ( "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -53,9 +55,14 @@ func init() { } func podStatsCmd(c *cliconfig.PodStatsValues) error { - - if os.Geteuid() != 0 { - return errors.New("stats is not supported in rootless mode") + if rootless.IsRootless() { + unified, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return err + } + if !unified { + return errors.New("stats is not supported in rootless mode without cgroups v2") + } } format := c.Format diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index dc372d79c..5122d37d1 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -660,7 +660,7 @@ func formatGroup(key string, start, last int32) string { } // portsToString converts the ports used to a string of the from "port1, port2" -// and also groups continuous list of ports in readable format. +// and also groups a continuous list of ports into a readable format. func portsToString(ports []ocicni.PortMapping) string { type portGroup struct { first int32 @@ -750,7 +750,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim return runLabel, imageName, err } -// GenerateRunlabelCommand generates the command that will eventually be execucted by podman. +// GenerateRunlabelCommand generates the command that will eventually be execucted by Podman. func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string, globalOpts string) ([]string, []string, error) { // If no name is provided, we use the image's basename instead. if name == "" { @@ -809,7 +809,7 @@ func envSliceToMap(env []string) map[string]string { return m } -// GenerateKube generates kubernetes yaml based on a pod or container +// GenerateKube generates kubernetes yaml based on a pod or container. func GenerateKube(name string, service bool, r *libpod.Runtime) (*v1.Pod, *v1.Service, error) { var ( pod *libpod.Pod diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 6e873aade..094330e24 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -55,7 +55,7 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. rootfs = c.InputArgs[0] } - if c.IsSet("cidfile") && os.Geteuid() == 0 { + if c.IsSet("cidfile") { cidFile, err = util.OpenExclusiveFile(c.String("cidfile")) if err != nil && os.IsExist(err) { return nil, nil, errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", c.String("cidfile")) @@ -70,8 +70,8 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. imageName := "" var data *inspect.ImageData = nil - // Set the storage if we are running as euid == 0 and there is no rootfs specified - if rootfs == "" && os.Geteuid() == 0 { + // Set the storage if there is no rootfs specified + if rootfs == "" { var writer io.Writer if !c.Bool("quiet") { writer = os.Stderr diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index 3accae1b6..2f696445e 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "os" "reflect" "strings" "time" @@ -13,6 +12,8 @@ import ( "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/rootless" "github.com/docker/go-units" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -66,8 +67,14 @@ func init() { } func statsCmd(c *cliconfig.StatsValues) error { - if os.Geteuid() != 0 { - return errors.New("stats is not supported for rootless containers") + if rootless.IsRootless() { + unified, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return err + } + if !unified { + return errors.New("stats is not supported in rootless mode without cgroups v2") + } } all := c.All diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 4444b5679..2e7dee94d 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -1278,3 +1278,6 @@ error WantsMoreRequired (reason: string) # Container is already stopped error ErrCtrStopped (id: string) + +# This function requires CGroupsV2 to run in rootless mode. +error ErrRequiresCgroupsV2ForRootless(reason: string)
\ No newline at end of file diff --git a/commands.md b/commands.md index 1b48d7862..4d3bea439 100644 --- a/commands.md +++ b/commands.md @@ -44,6 +44,10 @@ | [podman-logout(1)](/docs/podman-logout.1.md) | Logout of a container registry | | [podman-logs(1)](/docs/podman-logs.1.md) | Display the logs of a container | | [podman-mount(1)](/docs/podman-mount.1.md) | Mount a working container's root filesystem | +| [podman-network(1)](/docs/podman-network.1.md) | Manage Podman CNI networks | +| [podman-network-inspect(1)](/docs/podman-network-inspect.1.md) | Inspect one or more Podman networks | +| [podman-network-ls(1)](/docs/podman-network-ls.1.md) | Display a summary of Podman networks | +| [podman-network-rm(1)](/docs/podman-network-rm.1.md) | Remove one or more Podman networks | | [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers | [![...](/docs/play.png)](https://podman.io/asciinema/podman/pause_unpause/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_pause_unpause.sh) | | [podman-play(1)](/docs/podman-play.1.md) | Play pods and containers based on a structured input file | | [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods | diff --git a/completions/bash/podman b/completions/bash/podman index ad7df4b42..962c15a95 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -946,6 +946,78 @@ _podman_healthcheck() { esac } +_podman_network() { + local boolean_options=" + --help + -h + " + subcommands=" + inspect + ls + rm + " + __podman_subcommands "$subcommands $aliases" && return + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac +} + +_podman_network_inspect() { + local options_with_args=" + " + local boolean_options=" + --help + -h + " + _complete_ "$options_with_args" "$boolean_options" + + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + esac +} + +_podman_network_ls() { + local options_with_args=" + " + local boolean_options=" + --help + -h + --quiet + -q + " + _complete_ "$options_with_args" "$boolean_options" + + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + esac +} + +_podman_network_ls() { + local options_with_args=" + " + local boolean_options=" + --help + -h + " + _complete_ "$options_with_args" "$boolean_options" + + case "$cur" in + -*) + COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur")) + ;; + esac +} + _podman_generate() { local boolean_options=" --help diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md index 18ef3e7f7..ada362d95 100644 --- a/contrib/cirrus/README.md +++ b/contrib/cirrus/README.md @@ -69,6 +69,13 @@ Confirm that cross-compile of podman-remote functions for both `windows` and `darwin` targets. +### ``special_testing_cgroupv2`` Task + +Use the latest Fedora release with the required kernel options pre-set for +exercising cgroups v2 with podman integration tests. Also depends on +having `SPECIALMODE` set to 'cgroupv2` + + ### ``test_build_cache_images_task`` Task Modifying the contents of cache-images is tested by making changes to @@ -266,5 +273,6 @@ values follows: and utilized for testing. * `in_podman`: Causes testing to occur within a container executed by podman on the host. +* `cgroupv2`: The kernel on this VM was prepared with options to enable v2 cgroups * `windows`: See **darwin** * `darwin`: Signals the ``special_testing_cross`` task to cross-compile the remote client. diff --git a/contrib/cirrus/add_second_partition.sh b/contrib/cirrus/add_second_partition.sh new file mode 100644 index 000000000..73db192c5 --- /dev/null +++ b/contrib/cirrus/add_second_partition.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# N/B: This script could mega f*!@up your disks if run by mistake. +# it is left without the execute-bit on purpose! + +# $SLASH_DEVICE is the disk device to be f*xtuP +SLASH_DEVICE="/dev/sda" # Always the case on GCP + +# The unallocated space results from the difference in disk-size between VM Image +# and runtime request. The check_image.sh test includes a minimum-space check, +# with the Image size set initially lower by contrib/cirrus/packer/libpod_images.yml +NEW_PART_START="50%" +NEW_PART_END="100%" + +set -eo pipefail + +source $(dirname $0)/lib.sh + +if [[ ! -r "/root" ]] || [[ -r "/root/second_partition_ready" ]] +then + echo "Warning: Ignoring attempted execution of $(basename $0)" + exit 0 +fi + +[[ -n "type -P parted" ]] || \ + die 2 "The parted command is required." + +[[ ! -b ${SLASH_DEVICE}2 ]] || \ + die 5 "Found unexpected block device ${SLASH_DEVICE}2" + +PPRINTCMD="parted --script ${SLASH_DEVICE} print" +FINDMNTCMD="findmnt --source=${SLASH_DEVICE}1 --mountpoint=/ --canonicalize --evaluate --first-only --noheadings" +TMPF=$(mktemp -p '' $(basename $0)_XXXX) +trap "rm -f $TMPF" EXIT + +if $FINDMNTCMD | tee $TMPF | egrep -q "^/\s+${SLASH_DEVICE}1" +then + echo "Repartitioning original partition table:" + $PPRINTCMD +else + die 6 "Unexpected output from '$FINDMNTCMD': $(<$TMPF)" +fi + +echo "Adding partition offset within unpartitioned space." +parted --script --align optimal /dev/sda unit % mkpart primary "" "" "$NEW_PART_START" "$NEW_PART_END" + +echo "New partition table:" +$PPRINTCMD + +echo "Growing ${SLASH_DEVICE}1 meet start of ${SLASH_DEVICE}2" +growpart ${SLASH_DEVICE} 1 + +FSTYPE=$(findmnt --first-only --noheadings --output FSTYPE ${SLASH_DEVICE}1) +echo "Expanding $FSTYPE filesystem on ${SLASH_DEVICE}1" +case $FSTYPE in + ext*) resize2fs ${SLASH_DEVICE}1 ;; + *) die 11 "Script $(basename $0) doesn't know how to resize a $FSTYPE filesystem." ;; +esac + +# Must happen last - signals completion to other tooling +echo "Recording newly available disk partition device into /root/second_partition_ready" +echo "${SLASH_DEVICE}2" > /root/second_partition_ready diff --git a/contrib/cirrus/build_vm_images.sh b/contrib/cirrus/build_vm_images.sh index dd5182c37..6230610cb 100755 --- a/contrib/cirrus/build_vm_images.sh +++ b/contrib/cirrus/build_vm_images.sh @@ -62,6 +62,6 @@ URI="gs://packer-import${POST_MERGE_BUCKET_SUFFIX}/manifest${BUILT_IMAGE_SUFFIX} gsutil cp packer-manifest.json "$URI" # Ensure any background 'gcloud compute images update' processes finish -wait # CentOS has no -n option :( +wait # No -n option in CentOS, this is the best that can be done :( echo "Finished. A JSON manifest of produced images is available at $URI" diff --git a/contrib/cirrus/check_image.sh b/contrib/cirrus/check_image.sh index 22ed1ddc4..ad9a12f49 100755 --- a/contrib/cirrus/check_image.sh +++ b/contrib/cirrus/check_image.sh @@ -4,10 +4,12 @@ set -eo pipefail source $(dirname $0)/lib.sh +req_env_var PACKER_BUILDER_NAME TEST_REMOTE_CLIENT EVIL_UNITS OS_RELEASE_ID + NFAILS=0 echo "Validating VM image" -MIN_SLASH_GIGS=50 +MIN_SLASH_GIGS=30 read SLASH_DEVICE SLASH_FSTYPE SLASH_SIZE JUNK <<<$(findmnt --df --first-only --noheadings / | cut -d '.' -f 1) SLASH_SIZE_GIGS=$(echo "$SLASH_SIZE" | sed -r -e 's/G|g//') item_test "Minimum available disk space" $SLASH_SIZE_GIGS -gt $MIN_SLASH_GIGS || let "NFAILS+=1" @@ -20,6 +22,9 @@ item_test 'Minimum available memory' $MEM_FREE -ge $MIN_MEM_MB || let "NFAILS+=1 # binary anywhere; that could potentially taint our results. item_test "remove_packaged_podman_files() did it's job" -z "$(type -P podman)" || let "NFAILS+=1" +# Integration Tests require varlink in Fedora +item_test "The varlink executable is present" -x "$(type -P varlink)" || let "NFAILS+=1" + MIN_ZIP_VER='3.0' VER_RE='.+([[:digit:]]+\.[[:digit:]]+).+' ACTUAL_VER=$(zip --version 2>&1 | egrep -m 1 "Zip$VER_RE" | sed -r -e "s/$VER_RE/\\1/") @@ -49,5 +54,16 @@ then item_test "On ubuntu /usr/bin/runc is /usr/lib/cri-o-runc/sbin/runc" "$SAMESAME" -eq "0" || let "NFAILS+=1" fi +echo "Checking items specific to ${PACKER_BUILDER_NAME}${BUILT_IMAGE_SUFFIX}" +case "$PACKER_BUILDER_NAME" in + xfedora*) + echo "Kernel Command-line: $(cat /proc/cmdline)" + item_test \ + "On ${PACKER_BUILDER_NAME} images, the /sys/fs/cgroup/unified directory does NOT exist" \ + "!" "-d" "/sys/fs/cgroup/unified" || let "NFAILS+=1" + ;; + *) echo "No vm-image specific items to check" +esac + echo "Total failed tests: $NFAILS" exit $NFAILS diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh index cfaf33b85..e5de518fa 100755 --- a/contrib/cirrus/integration_test.sh +++ b/contrib/cirrus/integration_test.sh @@ -36,6 +36,18 @@ case "$SPECIALMODE" in -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \ -o CheckHostIP=no $GOSRC/$SCRIPT_BASE/rootless_test.sh ${TESTSUITE} ;; + cgroupv2) + # FIXME: use the package once all the fixes are in a release + # yum install -y crun + setenforce 0 + yum builddep -y crun + (git clone --depth=1 https://github.com/containers/crun && cd crun && ./autogen.sh && ./configure --prefix=/usr && make -j4 && make install) + export OCI_RUNTIME=/usr/bin/crun + make + make install PREFIX=/usr ETCDIR=/etc + make test-binaries + make local${TESTSUITE} + ;; none) make make install PREFIX=/usr ETCDIR=/etc @@ -52,5 +64,5 @@ case "$SPECIALMODE" in warn '' "No $SPECIALMODE remote client integration tests configured" ;; *) - die 110 "Unsupported \$SPECIAL_MODE: $SPECIALMODE" + die 110 "Unsupported \$SPECIALMODE: $SPECIALMODE" esac diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 737ca3c01..a20ee5a62 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -55,9 +55,9 @@ PACKER_VER="1.3.5" # CSV of cache-image names to build (see $PACKER_BASE/libpod_images.json) # Base-images rarely change, define them here so they're out of the way. -export PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,fedora-30,fedora-29}" +export PACKER_BUILDS="${PACKER_BUILDS:-ubuntu-18,fedora-30,xfedora-30,fedora-29}" # Google-maintained base-image names -export UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20181203a" +export UBUNTU_BASE_IMAGE="ubuntu-1804-bionic-v20190722a" # Manually produced base-image names (see $SCRIPT_BASE/README.md) export FEDORA_BASE_IMAGE="fedora-cloud-base-30-1-2-1559164849" export PRIOR_FEDORA_BASE_IMAGE="fedora-cloud-base-29-1-2-1559164849" @@ -100,6 +100,9 @@ OS_RELEASE_VER="$(source /etc/os-release; echo $VERSION_ID | cut -d '.' -f 1)" # Combined to ease soe usage OS_REL_VER="${OS_RELEASE_ID}-${OS_RELEASE_VER}" +# Installed into cache-images, supports overrides +# by user-data in case of breakage or for debugging. +CUSTOM_CLOUD_CONFIG_DEFAULTS="$GOSRC/$PACKER_BASE/cloud-init/$OS_RELEASE_ID/cloud.cfg.d" # Pass in a list of one or more envariable names; exit non-zero with # helpful error message if any value is empty req_env_var() { @@ -354,7 +357,7 @@ remove_packaged_podman_files(){ } systemd_banish(){ - echo "Disabling periodic services that could destabilize testing:" + echo "Disabling periodic services that could destabilize testing (ignoring errors):" set +e # Not all of these exist on every platform for unit in $EVIL_UNITS do @@ -372,11 +375,20 @@ systemd_banish(){ _finalize(){ set +e # Don't fail at the very end - set +e # make errors non-fatal - echo "Removing leftover giblets from cloud-init" + if [[ -d "$CUSTOM_CLOUD_CONFIG_DEFAULTS" ]] + then + echo "Installing custom cloud-init defaults" + sudo cp -v "$CUSTOM_CLOUD_CONFIG_DEFAULTS"/* /etc/cloud/cloud.cfg.d/ + else + echo "Could not find any files in $CUSTOM_CLOUD_CONFIG_DEFAULTS" + fi + echo "Re-initializing so next boot does 'first-boot' setup again." + sudo history -c cd / sudo rm -rf /var/lib/cloud/instanc* sudo rm -rf /root/.ssh/* + sudo rm -rf /etc/ssh/*key* + sudo rm -rf /etc/ssh/moduli sudo rm -rf /home/* sudo rm -rf /tmp/* sudo rm -rf /tmp/.??* @@ -386,11 +398,6 @@ _finalize(){ rh_finalize(){ set +e # Don't fail at the very end - # Allow root ssh-logins - if [[ -r /etc/cloud/cloud.cfg ]] - then - sudo sed -re 's/^disable_root:.*/disable_root: 0/g' -i /etc/cloud/cloud.cfg - fi echo "Resetting to fresh-state for usage as cloud-image." PKG=$(type -P dnf || type -P yum || echo "") sudo $PKG clean all diff --git a/contrib/cirrus/networking.sh b/contrib/cirrus/networking.sh new file mode 100755 index 000000000..aeaf74035 --- /dev/null +++ b/contrib/cirrus/networking.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# This script attempts basic confirmation of functional networking +# by connecting to a set of essential external servers and failing +# if any cannot be reached. + +source $(dirname $0)/lib.sh + +while read host port +do + if [[ "$port" -eq "443" ]] + then + item_test "SSL/TLS to $host:$port" "$(echo -n '' | openssl s_client -quiet -no_ign_eof -connect $host:$port &> /dev/null; echo $?)" -eq "0" + else + item_test "Connect to $host:$port" "$(nc -zv -w 13 $host $port &> /dev/null; echo $?)" -eq 0 + fi +done < ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/required_host_ports.txt diff --git a/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg new file mode 100644 index 000000000..672d1907b --- /dev/null +++ b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/40_enable_root.cfg @@ -0,0 +1 @@ +disable_root: 0 diff --git a/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg new file mode 100644 index 000000000..c0fdf0e23 --- /dev/null +++ b/contrib/cirrus/packer/cloud-init/fedora/cloud.cfg.d/50_custom_disk_setup.cfg @@ -0,0 +1,4 @@ +#cloud-config +growpart: + mode: false +resize_rootfs: false diff --git a/contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg b/contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg new file mode 120000 index 000000000..98a0e3918 --- /dev/null +++ b/contrib/cirrus/packer/cloud-init/ubuntu/cloud.cfg.d/40_enable_root.cfg @@ -0,0 +1 @@ +../../fedora/cloud.cfg.d/40_enable_root.cfg
\ No newline at end of file diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh index 1e25a1a3c..0e1a82cc0 100644 --- a/contrib/cirrus/packer/fedora_setup.sh +++ b/contrib/cirrus/packer/fedora_setup.sh @@ -8,7 +8,7 @@ set -e # Load in library (copied by packer, before this script was run) source /tmp/libpod/$SCRIPT_BASE/lib.sh -req_env_var SCRIPT_BASE +req_env_var SCRIPT_BASE PACKER_BUILDER_NAME GOSRC install_ooe @@ -17,6 +17,10 @@ trap "sudo rm -rf $GOPATH" EXIT ooe.sh sudo dnf update -y +echo "Enabling updates-testing repository" +ooe.sh sudo dnf install -y 'dnf-command(config-manager)' +ooe.sh sudo dnf config-manager --set-enabled updates-testing + echo "Installing general build/test dependencies" ooe.sh sudo dnf install -y \ atomic-registries \ @@ -49,6 +53,7 @@ ooe.sh sudo dnf install -y \ libseccomp \ libseccomp-devel \ libselinux-devel \ + libvarlink-util \ lsof \ make \ nmap-ncat \ @@ -81,6 +86,17 @@ systemd_banish sudo /tmp/libpod/hack/install_catatonit.sh +# Same script is used for several related contexts +case "$PACKER_BUILDER_NAME" in + xfedora*) + echo "Configuring CGroups v2 enabled on next boot" + sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1" + ;& # continue to next matching item + *) + echo "Finalizing $PACKER_BUILDER_NAME VM image" + ;; +esac + rh_finalize echo "SUCCESS!" diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml index 91ed3b474..cae5d4138 100644 --- a/contrib/cirrus/packer/libpod_images.yml +++ b/contrib/cirrus/packer/libpod_images.yml @@ -33,7 +33,7 @@ builders: image_name: '{{build_name}}{{user `BUILT_IMAGE_SUFFIX`}}' image_family: '{{build_name}}-libpod' source_image: '{{user `UBUNTU_BASE_IMAGE`}}' - disk_size: 20 + disk_size: 20 # REQUIRED: Runtime allocation > this value project_id: '{{user `GCP_PROJECT_ID`}}' service_account_email: '{{user `SERVICE_ACCOUNT`}}' communicator: 'ssh' @@ -48,6 +48,10 @@ builders: source_image: '{{user `FEDORA_BASE_IMAGE`}}' - <<: *gce_hosted_image + name: 'xfedora-30' + source_image: '{{user `FEDORA_BASE_IMAGE`}}' + + - <<: *gce_hosted_image name: 'fedora-29' source_image: '{{user `PRIOR_FEDORA_BASE_IMAGE`}}' @@ -60,6 +64,7 @@ provisioners: - type: 'shell' script: '{{user `GOSRC`}}/{{user `PACKER_BASE`}}/{{split build_name "-" 0}}_setup.sh' environment_vars: + - 'PACKER_BUILDER_NAME={{build_name}}' - 'GOSRC=/tmp/libpod' - 'SCRIPT_BASE={{user `SCRIPT_BASE`}}' diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh index dba191ad2..00d92570f 100644 --- a/contrib/cirrus/packer/ubuntu_setup.sh +++ b/contrib/cirrus/packer/ubuntu_setup.sh @@ -15,6 +15,9 @@ install_ooe export GOPATH="$(mktemp -d)" trap "sudo rm -rf $GOPATH" EXIT +# Ensure there are no disruptive periodic services enabled by default in image +systemd_banish + echo "Updating/configuring package repositories." $LILTO $SUDOAPTGET update $LILTO $SUDOAPTGET install software-properties-common @@ -62,6 +65,7 @@ $BIGTO $SUDOAPTGET install \ libnet1-dev \ libnl-3-dev \ libostree-dev \ + libvarlink \ libprotobuf-c0-dev \ libprotobuf-dev \ libseccomp-dev \ @@ -100,9 +104,6 @@ ooe.sh sudo update-grub sudo /tmp/libpod/hack/install_catatonit.sh ooe.sh sudo make -C /tmp/libpod install.libseccomp.sudo -# Ensure there are no disruptive periodic services enabled by default in image -systemd_banish - ubuntu_finalize echo "SUCCESS!" diff --git a/contrib/cirrus/packer/xfedora_setup.sh b/contrib/cirrus/packer/xfedora_setup.sh new file mode 120000 index 000000000..5e9f1ec77 --- /dev/null +++ b/contrib/cirrus/packer/xfedora_setup.sh @@ -0,0 +1 @@ +fedora_setup.sh
\ No newline at end of file diff --git a/contrib/cirrus/required_host_ports.txt b/contrib/cirrus/required_host_ports.txt index 9248e497a..85a6c26be 100644 --- a/contrib/cirrus/required_host_ports.txt +++ b/contrib/cirrus/required_host_ports.txt @@ -2,3 +2,14 @@ github.com 22 docker.io 443 quay.io 443 registry.fedoraproject.org 443 +mirrors.fedoraproject.org 443 +dl.fedoraproject.org 443 +ewr.edge.kernel.org 443 +mirror.chpc.utah.edu 443 +mirror.clarkson.edu 443 +mirror.umd.edu 443 +mirror.vcu.edu 443 +mirrors.cat.pdx.edu 443 +pubmirror1.math.uh.edu 443 +pubmirror2.math.uh.edu 443 +sjc.edge.kernel.org 443 diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 2230684ac..7b6765f8a 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -42,8 +42,11 @@ case "${OS_REL_VER}" in ln -f "$CRIO_RUNC_PATH" "/usr/bin/runc" fi ;; - fedora-30) ;; - fedora-29) ;; + fedora-30) ;& # continue to next item + fedora-29) + if [[ "$ADD_SECOND_PARTITION" == "true" ]]; then + bash "$SCRIPT_BASE/add_second_partition.sh"; fi + ;; centos-7) # Current VM is an image-builder-image no local podman/testing echo "No further setup required for VM image building" exit 0 @@ -59,9 +62,12 @@ install_test_configs make install.tools case "$SPECIALMODE" in - none) + cgroupv2) remove_packaged_podman_files # we're building from source ;; + none) + remove_packaged_podman_files + ;; rootless) # Only do this once, even if ROOTLESS_USER (somehow) changes if ! grep -q 'ROOTLESS_USER' /etc/environment @@ -82,5 +88,5 @@ case "$SPECIALMODE" in windows) ;& # for podman-remote building only darwin) ;; *) - die 111 "Unsupported \$SPECIAL_MODE: $SPECIALMODE" + die 111 "Unsupported \$SPECIALMODE: $SPECIALMODE" esac diff --git a/contrib/imgprune/Dockerfile b/contrib/imgprune/Dockerfile index 26329e828..b0dc77da5 100644 --- a/contrib/imgprune/Dockerfile +++ b/contrib/imgprune/Dockerfile @@ -1,4 +1,4 @@ -FROM libpod/imgts:latest +FROM quay.io/libpod/imgts:latest RUN yum -y update && \ yum clean all diff --git a/contrib/snapcraft/.editorconfig b/contrib/snapcraft/.editorconfig new file mode 100644 index 000000000..1749b2d4c --- /dev/null +++ b/contrib/snapcraft/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false + +[*.yaml] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true
\ No newline at end of file diff --git a/contrib/snapcraft/.gitignore b/contrib/snapcraft/.gitignore new file mode 100644 index 000000000..59894f50f --- /dev/null +++ b/contrib/snapcraft/.gitignore @@ -0,0 +1,12 @@ +#snapcraft specifics +/parts/ +/stage/ +/prime/ + +*.snap + +.snapcraft +__pycache__ +*.pyc +*_source.tar.bz2 +snap/.snapcraft diff --git a/contrib/snapcraft/LICENSE b/contrib/snapcraft/LICENSE new file mode 100644 index 000000000..81802d619 --- /dev/null +++ b/contrib/snapcraft/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Snapcrafters + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/snapcraft/README.md b/contrib/snapcraft/README.md new file mode 100644 index 000000000..f543c61a7 --- /dev/null +++ b/contrib/snapcraft/README.md @@ -0,0 +1,82 @@ +<h1 align="center"> + <img src="https://raw.githubusercontent.com/containers/podman.io/master/images/podman.svg?sanitize=true" alt="podman"> + <br /> +</h1> + +<p align="center"><b>This is the snap for <a href="https://podman.io/">podman</a></b>, <i>“Managing Pods, Containers, and Container Images in Multiple Formats (Docker, OCI, ...).”</i>. It works on Ubuntu, Fedora, Debian, RHEL, SUSE, and other major Linux +distributions.</p> + +<!-- Uncomment and modify this when you are provided a build status badge +<p align="center"> +<a href="https://build.snapcraft.io/user/snapcrafters/fork-and-rename-me"><img src="https://build.snapcraft.io/badge/snapcrafters/fork-and-rename-me.svg" alt="Snap Status"></a> +</p> +--> + +<!-- Uncomment and modify this when you have a screenshot +![podman](screenshot.png?raw=true "podman") +--> + +<p align="center">Published for <img src="https://raw.githubusercontent.com/anythingcodes/slack-emoji-for-techies/gh-pages/emoji/tux.png" align="top" width="24" /> with 💝 by Snapcrafters</p> + +## Install + + sudo snap install podman + +([Don't have snapd installed?](https://snapcraft.io/docs/core/install)) + +## Remaining tasks +<!-- Uncomment and modify this when you have a screenshot +![podman](screenshot.png?raw=true "podman") +--> + +Snapcrafters ([join us](https://forum.snapcraft.io/t/join-snapcrafters/1325)) +are working to land snap install documentation and +the [snapcraft.yaml](https://github.com/snapcrafters/podman/blob/master/snap/snapcraft.yaml) +upstream so `podman` can authoritatively publish future releases. + + - [x] Fork the [Snapcrafters template](https://github.com/snapcrafters/fork-and-rename-me) repository to your own GitHub account. + - If you have already forked the Snapcrafter template to your account and want to create another snap, you'll need to use GitHub's [Import repository](https://github.com/new/import) feature because you can only fork a repository once. + - [x] Rename the forked Snapcrafters template repository + - [x] Update the description of the repository + - [x] Update logos and references to `podman` and `[podman]` + - [ ] Create a snap that runs in `devmode` + - [x] Register the snap in the store, **using the preferred upstream name** + - [ ] Add a screenshot to this `README.md` + - [ ] Publish the `devmode` snap in the Snap store edge channel + - [ ] Add install instructions to this `README.md` + - [ ] Update snap store metadata, icons and screenshots + - [ ] Convert the snap to `strict` confinement, or `classic` confinement if it qualifies + - [ ] Publish the confined snap in the Snap store beta channel + - [ ] Update the install instructions in this `README.md` + - [ ] Post a call for testing on the [Snapcraft Forum](https://forum.snapcraft.io) - [link]() + - [ ] Make a post in the [Snapcraft Forum](https://forum.snapcraft.io) asking for a transfer of the snap name from you to snapcrafters - [link]() + - [ ] Ask a [Snapcrafters admin](https://github.com/orgs/snapcrafters/people?query=%20role%3Aowner) to fork your repo into github.com/snapcrafters, and configure the repo for automatic publishing into edge on commit + - [ ] Add the provided Snapcraft build badge to this `README.md` + - [ ] Publish the snap in the Snap store stable channel + - [ ] Update the install instructions in this `README.md` + - [ ] Post an announcement in the [Snapcraft Forum](https://forum.snapcraft.io) - [link]() + - [ ] Submit a pull request or patch upstream that adds snap install documentation - [link]() + - [ ] Submit a pull request or patch upstream that adds the `snapcraft.yaml` and any required assets/launchers - [link]() + - [ ] Add upstream contact information to the `README.md` + - If upstream accept the PR: + - [ ] Request upstream create a Snap store account + - [ ] Contact the Snap Advocacy team to request the snap be transferred to upstream + - [ ] Ask the Snap Advocacy team to celebrate the snap - [link]() + +If you have any questions, [post in the Snapcraft forum](https://forum.snapcraft.io). + +<!-- +## The Snapcrafters + +| [![Your Name](https://gravatar.com/avatar/bc0bced65e963eb5c3a16cab8b004431/?s=128)](https://github.com/yourname/) | +| :---: | +| [Your Name](https://github.com/yourname/) | +--> + +<!-- Uncomment and modify this when you have upstream contacts +## Upstream + +| [![Upstream Name](https://gravatar.com/avatar/bc0bced65e963eb5c3a16cab8b004431?s=128)](https://github.com/upstreamname) | +| :---: | +| [Upstream Name](https://github.com/upstreamname) | +--> diff --git a/contrib/snapcraft/snap/snapcraft.yaml b/contrib/snapcraft/snap/snapcraft.yaml new file mode 100644 index 000000000..7ff0df03b --- /dev/null +++ b/contrib/snapcraft/snap/snapcraft.yaml @@ -0,0 +1,45 @@ +name: podman # you probably want to 'snapcraft register <name>' +version: '0.11.1.1' # just for humans, typically '1.2+git' or '1.3.2' +summary: Manage pods, containers and container images +description: | + `podman` is a tool for managing Pods, Containers, and Container Images + in multiple formats including Docker/OSI images. It exposes the same + command line interface as Docker, but runs containers unprivileged by + default. + +confinement: devmode # use 'strict' once you have the right plugs and slots + +base: core18 + +parts: + podman: + plugin: go + source: https://github.com/containers/libpod/archive/v0.11.1.1.tar.gz + go-importpath: github.com/containers/libpod + build-packages: + # https://github.com/containers/libpod/blob/master/install.md#build-and-run-dependencies + - btrfs-tools + - git + - golang-go + - go-md2man + - iptables + - libassuan-dev + - libdevmapper-dev + - libglib2.0-dev + - libc6-dev + - libgpgme11-dev + - libgpg-error-dev + - libostree-dev + - libprotobuf-dev + - libprotobuf-c0-dev + - libseccomp-dev + - libselinux1-dev + - pkg-config + stage-packages: + - libarchive13 + - libassuan0 + - libgpgme11 + - libicu60 + - libostree-1-1 + - libsoup2.4-1 + - libxml2 diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 7e361d757..934f785db 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -39,7 +39,7 @@ %global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7}) Name: podman -Version: 1.4.5 +Version: 1.5.2 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 @@ -389,6 +389,7 @@ popd %install install -dp %{buildroot}%{_unitdir} +install -dp %{buildroot}%{_usr}/lib/systemd/user PODMAN_VERSION=%{version} %{__make} PREFIX=%{buildroot}%{_prefix} ETCDIR=%{buildroot}%{_sysconfdir} \ install.bin \ install.remote \ @@ -487,6 +488,8 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath} %{_datadir}/containers/%{repo}.conf %{_unitdir}/io.podman.service %{_unitdir}/io.podman.socket +%{_usr}/lib/systemd/user/io.podman.service +%{_usr}/lib/systemd/user/io.podman.socket %{_usr}/lib/tmpfiles.d/%{name}.conf %if 0%{?with_devel} diff --git a/contrib/varlink/io.podman.service b/contrib/varlink/io.podman.service index c524ce815..725198e79 100644 --- a/contrib/varlink/io.podman.service +++ b/contrib/varlink/io.podman.service @@ -6,7 +6,8 @@ Documentation=man:podman-varlink(1) [Service] Type=simple -ExecStart=/usr/bin/podman varlink unix:/run/podman/io.podman +ExecStart=/usr/bin/podman varlink unix:%t/podman/io.podman +KillMode=none [Install] WantedBy=multi-user.target diff --git a/contrib/varlink/io.podman.socket b/contrib/varlink/io.podman.socket index 0f09fe3ef..f6a3ddc49 100644 --- a/contrib/varlink/io.podman.socket +++ b/contrib/varlink/io.podman.socket @@ -3,7 +3,7 @@ Description=Podman Remote API Socket Documentation=man:podman-varlink(1) [Socket] -ListenStream=/run/podman/io.podman +ListenStream=%t/podman/io.podman SocketMode=0600 [Install] diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index df6faa780..1377f2a03 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -724,7 +724,7 @@ $ podman run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image This command mounts a `tmpfs` at `/tmp` within the container. The supported mount options are the same as the Linux default `mount` flags. If you do not specify any options, the systems uses the following options: -`rw,noexec,nosuid,nodev,size=65536k`. +`rw,noexec,nosuid,nodev`. **--tty**, **-t**=*true|false* diff --git a/docs/podman-network-inspect.1.md b/docs/podman-network-inspect.1.md new file mode 100644 index 000000000..576e61c79 --- /dev/null +++ b/docs/podman-network-inspect.1.md @@ -0,0 +1,50 @@ +% podman-network-inspect(1) + +## NAME +podman\-network-inspect- Inspect one or more Podman networks + +## SYNOPSIS +**podman network inspect** [*network* ...] + +## DESCRIPTION +Display the raw (JSON format) network configuration. This command is not available for rootless users. + +## EXAMPLE + +Inspect the default podman network + +``` +# podman network inspect podman +[{ + "cniVersion": "0.3.0", + "name": "podman", + "plugins": [ + { + "type": "bridge", + "bridge": "cni0", + "isGateway": true, + "ipMasq": true, + "ipam": { + "type": "host-local", + "subnet": "10.88.1.0/24", + "routes": [ + { "dst": "0.0.0.0/0" } + ] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] +} +] +``` + +## SEE ALSO +podman(1), podman-network(1), podman-network-ls(1) + +## HISTORY +August 2019, Originally compiled by Brent Baude <bbaude@redhat.com> diff --git a/docs/podman-network-ls.1.md b/docs/podman-network-ls.1.md new file mode 100644 index 000000000..725e07dbb --- /dev/null +++ b/docs/podman-network-ls.1.md @@ -0,0 +1,43 @@ +% podman-network-ls(1) + +## NAME +podman\-network-ls- Display a summary of CNI networks + +## SYNOPSIS +**podman network ls** [*options*] + +## DESCRIPTION +Displays a list of existing podman networks. This command is not available for rootless users. + +## OPTIONS +**--quiet**, **-q** + +The `quiet` options will restrict the output to only the network names + +## EXAMPLE + +Display networks + +``` +# podman network ls +NAME VERSION PLUGINS +podman 0.3.0 bridge,portmap +podman2 0.3.0 bridge,portmap +outside 0.3.0 bridge +podman9 0.3.0 bridge,portmap +``` + +Display only network names +``` +# podman network ls -q +podman +podman2 +outside +podman9 +``` + +## SEE ALSO +podman(1), podman-network(1), podman-network-inspect(1) + +## HISTORY +August 2019, Originally compiled by Brent Baude <bbaude@redhat.com> diff --git a/docs/podman-network-rm.1.md b/docs/podman-network-rm.1.md new file mode 100644 index 000000000..f72d6a694 --- /dev/null +++ b/docs/podman-network-rm.1.md @@ -0,0 +1,25 @@ +% podman-network-rm(1) + +## NAME +podman\-network-rm- Delete a Podman CNI network + +## SYNOPSIS +**podman network rm** [*network...*] + +## DESCRIPTION +Delete one or more Podman networks. + +## EXAMPLE + +Delete the `podman9` network + +``` +# podman network rm podman +Deleted: podman9 +``` + +## SEE ALSO +podman(1), podman-network(1), podman-network-inspect(1) + +## HISTORY +August 2019, Originally compiled by Brent Baude <bbaude@redhat.com> diff --git a/docs/podman-network.1.md b/docs/podman-network.1.md new file mode 100644 index 000000000..c01adc23e --- /dev/null +++ b/docs/podman-network.1.md @@ -0,0 +1,21 @@ +% podman-network(1) + +## NAME +podman\-network- Manage podman CNI networks + +## SYNOPSIS +**podman network** *subcommand* + +## DESCRIPTION +The network command manages CNI networks for Podman. It is not supported for rootless users. + +## COMMANDS + +| Command | Man Page | Description | +| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- | +| inspect | [podman-network-inspect(1)](podman-network-inspect.1.md)| Displays the raw CNI network configuration for one or more networks| +| ls | [podman-network-ls(1)](podman-network-ls.1.md)| Display a summary of CNI networks | +| rm | [podman-network-rm(1)](podman-network-rm.1.md)| Remove one or more CNI networks | + +## SEE ALSO +podman(1) diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index f8e61c84a..2445df566 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -761,7 +761,7 @@ $ podman run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image This command mounts a `tmpfs` at `/tmp` within the container. The supported mount options are the same as the Linux default `mount` flags. If you do not specify any options, the systems uses the following options: -`rw,noexec,nosuid,nodev,size=65536k`. +`rw,noexec,nosuid,nodev`. **--tty**, **-t**=*true|false* diff --git a/docs/podman.1.md b/docs/podman.1.md index 12b7866ca..33ea81ef6 100644 --- a/docs/podman.1.md +++ b/docs/podman.1.md @@ -161,6 +161,7 @@ the exit codes follow the `chroot` standard, see below: | [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. | | [podman-logs(1)](podman-logs.1.md) | Display the logs of a container. | | [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. | +| [podman-network(1)](podman-network.1.md) | Manage Podman CNI networks. | | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. | | [podman-play(1)](podman-play.1.md) | Play pods and containers based on a structured input file. | | [podman-pod(1)](podman-pod.1.md) | Management tool for groups of containers, called pods. | @@ -17,7 +17,7 @@ require ( github.com/containers/conmon v0.3.0 // indirect github.com/containers/image v3.0.2+incompatible github.com/containers/psgo v1.3.1 - github.com/containers/storage v1.13.1 + github.com/containers/storage v1.13.2 github.com/coreos/bbolt v1.3.3 // indirect github.com/coreos/etcd v3.3.13+incompatible // indirect github.com/coreos/go-iptables v0.4.1 @@ -99,6 +99,8 @@ github.com/containers/storage v1.12.16 h1:zePYS1GiG8CuRqLCeA0ufx4X27K06HcJLV50Dd github.com/containers/storage v1.12.16/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c= github.com/containers/storage v1.13.1 h1:rjVirLS9fCGkUFlLDZEoGDDUugtIf46DufWvJu08wxQ= github.com/containers/storage v1.13.1/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA= +github.com/containers/storage v1.13.2 h1:UXZ0Ckmk6+6+4vj2M2ywruVtH97pnRoAhTG8ctd+yQI= +github.com/containers/storage v1.13.2/go.mod h1:6D8nK2sU9V7nEmAraINRs88ZEscM5C5DK+8Npp27GeA= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh index 90e3aea8e..e1588d570 100755 --- a/hack/get_ci_vm.sh +++ b/hack/get_ci_vm.sh @@ -68,9 +68,10 @@ delvm() { } image_hints() { + _BIS=$(egrep -m 1 '_BUILT_IMAGE_SUFFIX:[[:space:]+"[[:print:]]+"' "$LIBPODROOT/.cirrus.yml" | cut -d: -f 2 | tr -d '"[:blank:]') egrep '[[:space:]]+[[:alnum:]].+_CACHE_IMAGE_NAME:[[:space:]+"[[:print:]]+"' \ "$LIBPODROOT/.cirrus.yml" | cut -d: -f 2 | tr -d '"[:blank:]' | \ - grep -v 'notready' | sort -u + sed -r -e "s/\\\$[{]_BUILT_IMAGE_SUFFIX[}]/$_BIS/" | sort -u } show_usage() { diff --git a/install.md b/install.md index 49a67f984..d8d70a7b6 100644 --- a/install.md +++ b/install.md @@ -26,6 +26,14 @@ Built-in, no need to install sudo emerge app-emulation/libpod ``` +#### [MacOS](https://www.apple.com/macos) + +Using [Homebrew](https://brew.sh/): + +```bash +brew cask install podman +``` + #### [openSUSE](https://www.opensuse.org) ```bash diff --git a/libpod/driver/driver.go b/libpod/driver/driver.go index f9442fa21..85eda5a21 100644 --- a/libpod/driver/driver.go +++ b/libpod/driver/driver.go @@ -38,6 +38,10 @@ func GetDriverData(store cstorage.Store, layerID string) (*Data, error) { if err != nil { return nil, err } + if mountTimes, err := store.Mounted(layerID); mountTimes == 0 || err != nil { + delete(metaData, "MergedDir") + } + return &Data{ Name: name, Data: metaData, diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index 7d195dc79..470c76959 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -4,6 +4,7 @@ package events import ( "fmt" + "strconv" "time" "github.com/coreos/go-systemd/journal" @@ -42,6 +43,9 @@ func (e EventJournalD) Write(ee Event) error { m["PODMAN_IMAGE"] = ee.Image m["PODMAN_NAME"] = ee.Name m["PODMAN_ID"] = ee.ID + if ee.ContainerExitCode != 0 { + m["PODMAN_EXIT_CODE"] = strconv.Itoa(ee.ContainerExitCode) + } case Volume: m["PODMAN_NAME"] = ee.Name } @@ -69,6 +73,11 @@ func (e EventJournalD) Read(options ReadOptions) error { if err := j.SeekTail(); err != nil { return errors.Wrap(err, "failed to seek end of journal") } + } else { + podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"} //nolint + if err := j.AddMatch(podmanJournal.String()); err != nil { + return errors.Wrap(err, "failed to add filter for event log") + } } // the api requires a next|prev before getting a cursor if _, err := j.Next(); err != nil { @@ -150,6 +159,14 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { / case Container, Pod: newEvent.ID = entry.Fields["PODMAN_ID"] newEvent.Image = entry.Fields["PODMAN_IMAGE"] + if code, ok := entry.Fields["PODMAN_EXIT_CODE"]; ok { + intCode, err := strconv.Atoi(code) + if err != nil { + logrus.Errorf("Error parsing event exit code %s", code) + } else { + newEvent.ContainerExitCode = intCode + } + } case Image: newEvent.ID = entry.Fields["PODMAN_ID"] } diff --git a/libpod/image/docker_registry_options.go b/libpod/image/docker_registry_options.go index c191a3ca2..60bb3c33f 100644 --- a/libpod/image/docker_registry_options.go +++ b/libpod/image/docker_registry_options.go @@ -1,8 +1,12 @@ package image import ( + "fmt" + "github.com/containers/image/docker/reference" "github.com/containers/image/types" + + podmanVersion "github.com/containers/libpod/version" ) // DockerRegistryOptions encapsulates settings that affect how we connect or @@ -36,6 +40,7 @@ func (o DockerRegistryOptions) GetSystemContext(parent *types.SystemContext, add sc.SignaturePolicyPath = parent.SignaturePolicyPath sc.AuthFilePath = parent.AuthFilePath sc.DirForceCompress = parent.DirForceCompress + sc.DockerRegistryUserAgent = parent.DockerRegistryUserAgent } return sc } @@ -48,5 +53,7 @@ func GetSystemContext(signaturePolicyPath, authFilePath string, forceCompress bo } sc.AuthFilePath = authFilePath sc.DirForceCompress = forceCompress + sc.DockerRegistryUserAgent = fmt.Sprintf("libpod/%s", podmanVersion.Version) + return sc } diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go index 52cebefab..e2c73f5ed 100644 --- a/libpod/oci_internal_linux.go +++ b/libpod/oci_internal_linux.go @@ -352,31 +352,29 @@ func startCommandGivenSelinux(cmd *exec.Cmd) error { // it then signals for conmon to start by sending nonse data down the start fd func (r *OCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File, uuid string) error { cgroupParent := ctr.CgroupParent() - if os.Geteuid() == 0 { - if r.cgroupManager == SystemdCgroupsManager { - unitName := createUnitName("libpod-conmon", ctr.ID()) - - realCgroupParent := cgroupParent - splitParent := strings.Split(cgroupParent, "/") - if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 { - realCgroupParent = splitParent[len(splitParent)-1] - } + if r.cgroupManager == SystemdCgroupsManager { + unitName := createUnitName("libpod-conmon", ctr.ID()) - logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName) - if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil { - logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err) - } + realCgroupParent := cgroupParent + splitParent := strings.Split(cgroupParent, "/") + if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 { + realCgroupParent = splitParent[len(splitParent)-1] + } + + logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName) + if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil { + logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err) + } + } else { + cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon") + control, err := cgroups.New(cgroupPath, &spec.LinuxResources{}) + if err != nil { + logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err) } else { - cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon") - control, err := cgroups.New(cgroupPath, &spec.LinuxResources{}) - if err != nil { + // we need to remove this defer and delete the cgroup once conmon exits + // maybe need a conmon monitor? + if err := control.AddPid(cmd.Process.Pid); err != nil { logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err) - } else { - // we need to remove this defer and delete the cgroup once conmon exits - // maybe need a conmon monitor? - if err := control.AddPid(cmd.Process.Pid); err != nil { - logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err) - } } } } diff --git a/libpod/runtime.go b/libpod/runtime.go index 83799a52b..8a4eee081 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -274,6 +274,8 @@ type runtimeConfiguredFrom struct { runtimePath bool cniPluginDir bool noPivotRoot bool + runtimeSupportsJSON bool + ociRuntime bool } func defaultRuntimeConfig() (RuntimeConfig, error) { @@ -593,6 +595,12 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options .. if tmpConfig.NoPivotRoot { runtime.configuredFrom.noPivotRoot = true } + if tmpConfig.RuntimeSupportsJSON != nil { + runtime.configuredFrom.runtimeSupportsJSON = true + } + if tmpConfig.OCIRuntime != "" { + runtime.configuredFrom.ociRuntime = true + } if _, err := toml.Decode(string(contents), runtime.config); err != nil { return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath) @@ -633,6 +641,13 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options .. if !runtime.configuredFrom.noPivotRoot { runtime.config.NoPivotRoot = tmpConfig.NoPivotRoot } + if !runtime.configuredFrom.runtimeSupportsJSON { + runtime.config.RuntimeSupportsJSON = tmpConfig.RuntimeSupportsJSON + } + if !runtime.configuredFrom.ociRuntime { + runtime.config.OCIRuntime = tmpConfig.OCIRuntime + } + break } } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 61a871b28..92b2faefb 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -54,6 +54,14 @@ func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config } // For an imported checkpoint no one has ever set the StartedTime. Set it now. ctr.state.StartedTime = time.Now() + + // If the path to ConmonPidFile starts with the default value (RunRoot), then + // the user has not specified '--conmon-pidfile' during run or create (probably). + // In that case reset ConmonPidFile to be set to the default value later. + if strings.HasPrefix(ctr.config.ConmonPidFile, r.config.StorageConfig.RunRoot) { + ctr.config.ConmonPidFile = "" + } + return r.setupContainer(ctx, ctr) } diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 4b77721d0..5387eb587 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -31,6 +31,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID return nil, err } + // Set Pod hostname as Pod name + g.Config.Hostname = p.config.Name + isRootless := rootless.IsRootless() entryCmd := []string{r.config.InfraCommand} diff --git a/libpod/util_linux.go b/libpod/util_linux.go index 78cbc75a7..d5c113daf 100644 --- a/libpod/util_linux.go +++ b/libpod/util_linux.go @@ -48,6 +48,9 @@ func makeSystemdCgroup(path string) error { return err } + if rootless.IsRootless() { + return controller.CreateSystemdUserUnit(path, rootless.GetRootlessUID()) + } return controller.CreateSystemdUnit(path) } @@ -57,6 +60,14 @@ func deleteSystemdCgroup(path string) error { if err != nil { return err } + if rootless.IsRootless() { + conn, err := cgroups.GetUserConnection(rootless.GetRootlessUID()) + if err != nil { + return err + } + defer conn.Close() + return controller.DeleteByPathConn(path, conn) + } return controller.DeleteByPath(path) } diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index b712bd9aa..45a9a54a3 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -342,7 +342,7 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode if err := ctr.Start(ctx, c.IsSet("pod")); err != nil { // This means the command did not exist exitCode = 127 - if strings.Contains(err.Error(), "permission denied") { + if strings.Contains(err.Error(), "permission denied") || strings.Contains(err.Error(), "file not found") { exitCode = 126 } return exitCode, err diff --git a/pkg/adapter/network.go b/pkg/adapter/network.go new file mode 100644 index 000000000..cf3a1dfdd --- /dev/null +++ b/pkg/adapter/network.go @@ -0,0 +1,147 @@ +// +build !remoteclient + +package adapter + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "strings" + "text/tabwriter" + + "github.com/containernetworking/cni/libcni" + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/network" + "github.com/pkg/errors" +) + +func getCNIConfDir(r *LocalRuntime) (string, error) { + config, err := r.GetConfig() + if err != nil { + return "", err + } + configPath := config.CNIConfigDir + + if len(config.CNIConfigDir) < 1 { + configPath = network.CNIConfigDir + } + return configPath, nil +} + +// NetworkList displays summary information about CNI networks +func (r *LocalRuntime) NetworkList(cli *cliconfig.NetworkListValues) error { + cniConfigPath, err := getCNIConfDir(r) + if err != nil { + return err + } + networks, err := network.LoadCNIConfsFromDir(cniConfigPath) + if err != nil { + return err + } + // quiet means we only print the network names + if cli.Quiet { + for _, cniNetwork := range networks { + fmt.Println(cniNetwork.Name) + } + return nil + } + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + if _, err := fmt.Fprintln(w, "NAME\tVERSION\tPLUGINS"); err != nil { + return err + } + for _, cniNetwork := range networks { + if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", cniNetwork.Name, cniNetwork.CNIVersion, getCNIPlugins(cniNetwork)); err != nil { + return err + } + } + return w.Flush() +} + +// NetworkInspect displays the raw CNI configuration for one +// or more CNI networks +func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error { + var ( + rawCNINetworks []map[string]interface{} + ) + cniConfigPath, err := getCNIConfDir(r) + if err != nil { + return err + } + for _, name := range cli.InputArgs { + b, err := readRawCNIConfByName(name, cniConfigPath) + if err != nil { + return err + } + rawList := make(map[string]interface{}) + if err := json.Unmarshal(b, &rawList); err != nil { + return fmt.Errorf("error parsing configuration list: %s", err) + } + rawCNINetworks = append(rawCNINetworks, rawList) + } + out, err := json.MarshalIndent(rawCNINetworks, "", "\t") + if err != nil { + return err + } + fmt.Printf("%s\n", out) + return nil +} + +// NetworkRemove deletes one or more CNI networks +func (r *LocalRuntime) NetworkRemove(cli *cliconfig.NetworkRmValues) error { + cniConfigPath, err := getCNIConfDir(r) + if err != nil { + return err + } + for _, name := range cli.InputArgs { + cniPath, err := getCNIConfigPathByName(name, cniConfigPath) + if err != nil { + return err + } + if err := os.Remove(cniPath); err != nil { + return err + } + fmt.Printf("Deleted: %s\n", name) + } + return nil +} + +// getCNIConfigPathByName finds a CNI network by name and +// returns its configuration file path +func getCNIConfigPathByName(name, cniConfigPath string) (string, error) { + files, err := libcni.ConfFiles(cniConfigPath, []string{".conflist"}) + if err != nil { + return "", err + } + for _, confFile := range files { + conf, err := libcni.ConfListFromFile(confFile) + if err != nil { + return "", err + } + if conf.Name == name { + return confFile, nil + } + } + return "", errors.Errorf("unable to find network configuration for %s", name) +} + +// readRawCNIConfByName reads the raw CNI configuration for a CNI +// network by name +func readRawCNIConfByName(name, cniConfigPath string) ([]byte, error) { + confFile, err := getCNIConfigPathByName(name, cniConfigPath) + if err != nil { + return nil, err + } + b, err := ioutil.ReadFile(confFile) + return b, err +} + +// getCNIPlugins returns a list of plugins that a given network +// has in the form of a string +func getCNIPlugins(list *libcni.NetworkConfigList) string { + var plugins []string + for _, plug := range list.Plugins { + plugins = append(plugins, plug.Network.Type) + } + return strings.Join(plugins, ",") +} diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 66588ce26..1dd72babf 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -708,6 +708,8 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name) } + containerConfig.UserCommand = containerConfig.Command + containerConfig.StopSignal = 15 // If the user does not pass in ID mappings, just set to basics diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 61db65a9d..ba988aaf7 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -289,9 +289,12 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti options.CommonBuildOpts = commonOpts options.SystemContext = systemContext - if c.Flag("runtime").Changed { + if c.GlobalFlags.Runtime != "" { + options.Runtime = c.GlobalFlags.Runtime + } else { options.Runtime = r.GetOCIRuntimePath() } + if c.Quiet { options.ReportWriter = ioutil.Discard } diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 39ea88131..420c9d0bb 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -10,6 +10,7 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "strings" "text/template" "time" @@ -69,6 +70,12 @@ func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, cmd: c.GlobalFlags, } configPath := remoteclientconfig.GetConfigFilePath() + // Check if the basedir for configPath exists and if not, create it. + if _, err := os.Stat(filepath.Dir(configPath)); os.IsNotExist(err) { + if mkdirErr := os.MkdirAll(filepath.Dir(configPath), 0750); mkdirErr != nil { + return nil, mkdirErr + } + } if len(c.GlobalFlags.RemoteConfigFilePath) > 0 { configPath = c.GlobalFlags.RemoteConfigFilePath customConfig = true diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index f2c6b548e..085718855 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -10,6 +10,8 @@ import ( "strconv" "strings" + systemdDbus "github.com/coreos/go-systemd/dbus" + "github.com/godbus/dbus" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -352,7 +354,56 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error { if !c.systemd { return fmt.Errorf("the cgroup controller is not using systemd") } - return systemdCreate(path) + + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + + return systemdCreate(path, conn) +} + +// GetUserConnection returns an user connection to D-BUS +func GetUserConnection(uid int) (*systemdDbus.Conn, error) { + return systemdDbus.NewConnection(func() (*dbus.Conn, error) { + return dbusAuthConnection(uid, dbus.SessionBusPrivate) + }) +} + +// CreateSystemdUserUnit creates the systemd cgroup for the specified user +func (c *CgroupControl) CreateSystemdUserUnit(path string, uid int) error { + if !c.systemd { + return fmt.Errorf("the cgroup controller is not using systemd") + } + + conn, err := GetUserConnection(uid) + if err != nil { + return err + } + defer conn.Close() + + return systemdCreate(path, conn) +} + +func dbusAuthConnection(uid int, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := createBus() + if err != nil { + return nil, err + } + + methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))} + + err = conn.Auth(methods) + if err != nil { + conn.Close() + return nil, err + } + if err := conn.Hello(); err != nil { + return nil, err + } + + return conn, nil } // Delete cleans a cgroup @@ -386,10 +437,11 @@ func rmDirRecursively(path string) error { return nil } -// DeleteByPath deletes the specified cgroup path -func (c *CgroupControl) DeleteByPath(path string) error { +// DeleteByPathConn deletes the specified cgroup path using the specified +// dbus connection if needed. +func (c *CgroupControl) DeleteByPathConn(path string, conn *systemdDbus.Conn) error { if c.systemd { - return systemdDestroy(path) + return systemdDestroyConn(path, conn) } if c.cgroup2 { return rmDirRecursively(filepath.Join(cgroupRoot, c.path)) @@ -413,6 +465,19 @@ func (c *CgroupControl) DeleteByPath(path string) error { return lastError } +// DeleteByPath deletes the specified cgroup path +func (c *CgroupControl) DeleteByPath(path string) error { + if c.systemd { + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + return c.DeleteByPathConn(path, conn) + } + return c.DeleteByPathConn(path, nil) +} + // Update updates the cgroups func (c *CgroupControl) Update(resources *spec.LinuxResources) error { for _, h := range handlers { diff --git a/pkg/cgroups/systemd.go b/pkg/cgroups/systemd.go index e72e456bc..b8e6db156 100644 --- a/pkg/cgroups/systemd.go +++ b/pkg/cgroups/systemd.go @@ -9,13 +9,7 @@ import ( "github.com/godbus/dbus" ) -func systemdCreate(path string) error { - c, err := systemdDbus.New() - if err != nil { - return err - } - defer c.Close() - +func systemdCreate(path string, c *systemdDbus.Conn) error { slice, name := filepath.Split(path) slice = strings.TrimSuffix(slice, "/") @@ -43,7 +37,7 @@ func systemdCreate(path string) error { } ch := make(chan string) - _, err = c.StartTransientUnit(name, "replace", properties, ch) + _, err := c.StartTransientUnit(name, "replace", properties, ch) if err != nil { lastError = err continue @@ -55,7 +49,7 @@ func systemdCreate(path string) error { } /* - systemdDestroy is copied from containerd/cgroups/systemd.go file, that + systemdDestroyConn is copied from containerd/cgroups/systemd.go file, that has the following license: Copyright The containerd Authors. @@ -72,18 +66,11 @@ func systemdCreate(path string) error { See the License for the specific language governing permissions and limitations under the License. */ - -func systemdDestroy(path string) error { - c, err := systemdDbus.New() - if err != nil { - return err - } - defer c.Close() - +func systemdDestroyConn(path string, c *systemdDbus.Conn) error { name := filepath.Base(path) ch := make(chan string) - _, err = c.StopUnit(name, "replace", ch) + _, err := c.StopUnit(name, "replace", ch) if err != nil { return err } diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go index b962ffa5c..0d26bf4af 100644 --- a/pkg/hooks/hooks.go +++ b/pkg/hooks/hooks.go @@ -4,6 +4,7 @@ package hooks import ( "context" "fmt" + "os" "sort" "strings" "sync" @@ -56,7 +57,7 @@ func New(ctx context.Context, directories []string, extensionStages []string) (m for _, dir := range directories { err = ReadDir(dir, manager.extensionStages, manager.hooks) - if err != nil { + if err != nil && !os.IsNotExist(err) { return nil, err } } diff --git a/pkg/network/config.go b/pkg/network/config.go new file mode 100644 index 000000000..d282f66b6 --- /dev/null +++ b/pkg/network/config.go @@ -0,0 +1,4 @@ +package network + +// CNIConfigDir is the path where CNI config files exist +const CNIConfigDir = "/etc/cni/net.d" diff --git a/pkg/network/network.go b/pkg/network/network.go new file mode 100644 index 000000000..9d04340a3 --- /dev/null +++ b/pkg/network/network.go @@ -0,0 +1,26 @@ +package network + +import ( + "sort" + + "github.com/containernetworking/cni/libcni" +) + +// LoadCNIConfsFromDir loads all the CNI configurations from a dir +func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) { + var configs []*libcni.NetworkConfigList + files, err := libcni.ConfFiles(dir, []string{".conflist"}) + if err != nil { + return nil, err + } + sort.Strings(files) + + for _, confFile := range files { + conf, err := libcni.ConfListFromFile(confFile) + if err != nil { + return nil, err + } + configs = append(configs, conf) + } + return configs, nil +} diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 19b76f387..94933ddd0 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -137,7 +137,7 @@ get_cmd_line_args (pid_t pid) { allocated += 512; char *tmp = realloc (buffer, allocated); - if (buffer == NULL) + if (tmp == NULL) { free (buffer); return NULL; @@ -276,7 +276,7 @@ static void __attribute__((constructor)) init() return; } - r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf))); + r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1)); close (fd); if (r < 0) { @@ -457,6 +457,11 @@ create_pause_process (const char *pause_pid_file_path, char **argv) } r = TEMP_FAILURE_RETRY (write (p[1], "0", 1)); + if (r < 0) + { + fprintf (stderr, "cannot write to pipe: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } close (p[1]); _exit (EXIT_SUCCESS); @@ -811,6 +816,11 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re } ret = TEMP_FAILURE_RETRY (write (ready, "0", 1)); + if (ret < 0) + { + fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } close (ready); if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go index e0bb48a9c..b634f4cac 100644 --- a/pkg/spec/storage.go +++ b/pkg/spec/storage.go @@ -168,14 +168,14 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount, "/run": false, } if config.ReadOnlyRootfs && config.ReadOnlyTmpfs { - options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup", "size=65536k"} + options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"} for dest := range readonlyTmpfs { if _, ok := baseMounts[dest]; ok { continue } localOpts := options if dest == "/run" { - localOpts = append(localOpts, "noexec") + localOpts = append(localOpts, "noexec", "size=65536k") } baseMounts[dest] = spec.Mount{ Destination: dest, @@ -238,11 +238,6 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount, // Conflicts are resolved simply - the last container specified wins. // Container names may be suffixed by mount options after a colon. func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { - // TODO: This can probably be disabled now - if os.Geteuid() != 0 { - return nil, nil, nil - } - // Both of these are maps of mount destination to mount type. // We ensure that each destination is only mounted to once in this way. finalMounts := make(map[string]spec.Mount) diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go index 40c99384d..9b2c734c0 100644 --- a/pkg/util/mountOpts.go +++ b/pkg/util/mountOpts.go @@ -92,9 +92,6 @@ func ProcessTmpfsOptions(options []string) ([]string, error) { if !foundWrite { baseOpts = append(baseOpts, "rw") } - if !foundSize { - baseOpts = append(baseOpts, "size=65536k") - } if !foundProp { baseOpts = append(baseOpts, "rprivate") } diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go index e7b2a272e..e781e6717 100644 --- a/pkg/util/utils_windows.go +++ b/pkg/util/utils_windows.go @@ -6,29 +6,31 @@ import ( "github.com/pkg/errors" ) +var errNotImplemented = errors.New("not yet implemented") + // IsCgroup2UnifiedMode returns whether we are running in cgroup 2 unified mode. func IsCgroup2UnifiedMode() (bool, error) { - return false, errors.New("this function is not implemented for windows") + return false, errors.Wrap(errNotImplemented, "IsCgroup2Unified") } // GetContainerPidInformationDescriptors returns a string slice of all supported // format descriptors of GetContainerPidInformation. func GetContainerPidInformationDescriptors() ([]string, error) { - return nil, errors.New("this function is not implemented for windows") + return nil, errors.Wrap(errNotImplemented, "GetContainerPidInformationDescriptors") } // GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for // the pause process func GetRootlessPauseProcessPidPath() (string, error) { - return "", errors.New("this function is not implemented for windows") + return "", errors.Wrap(errNotImplemented, "GetRootlessPauseProcessPidPath") } // GetRootlessRuntimeDir returns the runtime directory when running as non root func GetRootlessRuntimeDir() (string, error) { - return "", errors.New("this function is not implemented for windows") + return "", errors.Wrap(errNotImplemented, "GetRootlessRuntimeDir") } // GetRootlessConfigHomeDir returns the config home directory when running as non root func GetRootlessConfigHomeDir() (string, error) { - return "", errors.New("this function is not implemented for windows") + return "", errors.Wrap(errNotImplemented, "GetRootlessConfigHomeDir") } diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index bb66ff962..c7aa5233f 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -19,6 +19,8 @@ import ( "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/logs" "github.com/containers/libpod/pkg/adapter/shortcuts" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/varlinkapi/virtwriter" "github.com/containers/storage/pkg/archive" "github.com/pkg/errors" @@ -317,6 +319,13 @@ func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath str // GetContainerStats ... func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error { + cgroupv2, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + if rootless.IsRootless() && !cgroupv2 { + return call.ReplyErrRequiresCgroupsV2ForRootless("rootless containers cannot report container stats") + } ctr, err := i.Runtime.LookupContainer(name) if err != nil { return call.ReplyContainerNotFound(name, err.Error()) diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index d37d7c7cc..1caefd299 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -375,23 +375,28 @@ var _ = Describe("Podman checkpoint", func() { result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName}) result.WaitWithDefaultTimeout() + // As the container has been started with '--rm' it will be completely + // cleaned up after checkpointing. Expect(result.ExitCode()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) - result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) + // Restore container the first time with different name. + // Using '--ignore-static-ip' as for parallel test runs + // each containers gets a random IP address via '--ip'. + // '--ignore-static-ip' tells the restore to use the next + // available IP address. + // First restore the container with a new name/ID to make + // sure nothing in the restored container depends on the + // original container. + result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again", "--ignore-static-ip"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) - // Restore container a second time with different name. - // Using '--ignore-static-ip' as for parallel test runs - // each containers gets a random IP address via '--ip'. - // '--ignore-static-ip' tells the restore to use the next - // available IP address. - result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again", "--ignore-static-ip"}) + result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index b6dd1ecd1..4e9881d59 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -538,7 +538,7 @@ func (p *PodmanTestIntegration) RunHealthCheck(cid string) error { return nil } // Restart container if it's not running - ps := p.Podman([]string{"ps", "--no-trunc", "--q", "--filter", fmt.Sprintf("id=%s", cid)}) + ps := p.Podman([]string{"ps", "--no-trunc", "--quiet", "--filter", fmt.Sprintf("id=%s", cid)}) ps.WaitWithDefaultTimeout() if ps.ExitCode() == 0 { if !strings.Contains(ps.OutputToString(), cid) { diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go index 6cf78a25c..3f9639fda 100644 --- a/test/e2e/exec_test.go +++ b/test/e2e/exec_test.go @@ -179,6 +179,8 @@ var _ = Describe("Podman exec", func() { }) It("podman exec cannot be invoked", func() { + SkipIfNotRunc() + setup := podmanTest.RunTopContainer("test1") setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) @@ -189,6 +191,8 @@ var _ = Describe("Podman exec", func() { }) It("podman exec command not found", func() { + SkipIfNotRunc() + setup := podmanTest.RunTopContainer("test1") setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go index 7f33fec87..a6cedfc58 100644 --- a/test/e2e/libpod_suite_remoteclient_test.go +++ b/test/e2e/libpod_suite_remoteclient_test.go @@ -28,6 +28,13 @@ func SkipIfRootless() { } } +func SkipIfNotRunc() { + runtime := os.Getenv("OCI_RUNTIME") + if runtime != "" && filepath.Base(runtime) != "runc" { + ginkgo.Skip("Not using runc as runtime") + } +} + // Podman is the exec call to podman on the filesystem func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { podmanSession := p.PodmanBase(args, false, false) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 1df59dbe3..22cc14d6b 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -21,6 +21,13 @@ func SkipIfRootless() { } } +func SkipIfNotRunc() { + runtime := os.Getenv("OCI_RUNTIME") + if runtime != "" && filepath.Base(runtime) != "runc" { + ginkgo.Skip("Not using runc as runtime") + } +} + // Podman is the exec call to podman on the filesystem func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { podmanSession := p.PodmanBase(args, false, false) diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go new file mode 100644 index 000000000..9aed5351a --- /dev/null +++ b/test/e2e/network_test.go @@ -0,0 +1,158 @@ +// +build !remoteclient + +package integration + +import ( + "fmt" + . "github.com/containers/libpod/test/utils" + "github.com/containers/storage/pkg/stringid" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "io/ioutil" + "os" + "path/filepath" +) + +func writeConf(conf []byte, confPath string) { + if err := ioutil.WriteFile(confPath, conf, 777); err != nil { + fmt.Println(err) + } +} +func removeConf(confPath string) { + if err := os.Remove(confPath); err != nil { + fmt.Println(err) + } +} + +var _ = Describe("Podman network", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + var ( + secondConf = `{ + "cniVersion": "0.3.0", + "name": "podman-integrationtest", + "plugins": [ + { + "type": "bridge", + "bridge": "cni1", + "isGateway": true, + "ipMasq": true, + "ipam": { + "type": "host-local", + "subnet": "10.99.0.0/16", + "routes": [ + { "dst": "0.0.0.0/0" } + ] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] +}` + cniPath = "/etc/cni/net.d" + ) + + It("podman network list", func() { + SkipIfRootless() + // Setup, use uuid to prevent conflict with other tests + uuid := stringid.GenerateNonCryptoID() + secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid)) + writeConf([]byte(secondConf), secondPath) + defer removeConf(secondPath) + + session := podmanTest.Podman([]string{"network", "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOutputContains("podman-integrationtest")).To(BeTrue()) + }) + + It("podman network list -q", func() { + SkipIfRootless() + // Setup, use uuid to prevent conflict with other tests + uuid := stringid.GenerateNonCryptoID() + secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid)) + writeConf([]byte(secondConf), secondPath) + defer removeConf(secondPath) + + session := podmanTest.Podman([]string{"network", "ls", "--quiet"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOutputContains("podman-integrationtest")).To(BeTrue()) + }) + + It("podman network rm no args", func() { + SkipIfRootless() + session := podmanTest.Podman([]string{"network", "rm"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(BeZero()) + }) + + It("podman network rm", func() { + SkipIfRootless() + // Setup, use uuid to prevent conflict with other tests + uuid := stringid.GenerateNonCryptoID() + secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid)) + writeConf([]byte(secondConf), secondPath) + defer removeConf(secondPath) + + session := podmanTest.Podman([]string{"network", "ls", "--quiet"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOutputContains("podman-integrationtest")).To(BeTrue()) + + rm := podmanTest.Podman([]string{"network", "rm", "podman-integrationtest"}) + rm.WaitWithDefaultTimeout() + Expect(rm.ExitCode()).To(BeZero()) + + results := podmanTest.Podman([]string{"network", "ls", "--quiet"}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(results.LineInOutputContains("podman-integrationtest")).To(BeFalse()) + }) + + It("podman network inspect no args", func() { + SkipIfRootless() + session := podmanTest.Podman([]string{"network", "inspect"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(BeZero()) + }) + + It("podman network inspect", func() { + SkipIfRootless() + // Setup, use uuid to prevent conflict with other tests + uuid := stringid.GenerateNonCryptoID() + secondPath := filepath.Join(cniPath, fmt.Sprintf("%s.conflist", uuid)) + writeConf([]byte(secondConf), secondPath) + defer removeConf(secondPath) + + session := podmanTest.Podman([]string{"network", "inspect", "podman-integrationtest", "podman"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.IsJSONOutputValid()).To(BeTrue()) + }) + +}) diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index 455f60937..c61131078 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/containers/libpod/pkg/cgroups" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -25,6 +26,17 @@ var _ = Describe("Podman pause", func() { if err != nil { os.Exit(1) } + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + _, err := os.Stat("/sys/fs/cgroup/cgroup.freeze") + if err != nil { + Skip("freezer controller not available on the current kernel") + } + } + podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() podmanTest.SeedImages() diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 331412a39..b0a9f2ead 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -140,6 +140,30 @@ var _ = Describe("Podman generate kube", func() { Expect(inspect.OutputToString()).To(ContainSubstring(ctrCmd[0])) }) + It("podman play kube test correct output", func() { + ctrName := "testCtr" + ctrCmd := []string{"echo", "hello"} + testContainer := Container{ctrCmd, ALPINE, ctrName, false, nil, nil} + tempFile := filepath.Join(podmanTest.TempDir, "kube.yaml") + + err := generateKubeYaml([]Container{testContainer}, tempFile) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", tempFile}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + logs := podmanTest.Podman([]string{"logs", ctrName}) + logs.WaitWithDefaultTimeout() + Expect(logs.ExitCode()).To(Equal(0)) + Expect(logs.OutputToString()).To(ContainSubstring("hello")) + + inspect := podmanTest.Podman([]string{"inspect", ctrName, "--format", "'{{ .Config.Cmd }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("hello")) + }) + It("podman play kube cap add", func() { ctrName := "testCtr" ctrCmd := []string{"cat", "/proc/self/status"} diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go index 87f89b1dd..4be9da3d2 100644 --- a/test/e2e/run_cpu_test.go +++ b/test/e2e/run_cpu_test.go @@ -3,8 +3,10 @@ package integration import ( + "io/ioutil" "os" + "github.com/containers/libpod/pkg/cgroups" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -22,6 +24,16 @@ var _ = Describe("Podman run cpu", func() { if err != nil { os.Exit(1) } + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + if err := ioutil.WriteFile("/sys/fs/cgroup/cgroup.subtree_control", []byte("+cpuset"), 0644); err != nil { + Skip("cpuset controller not available on the current kernel") + } + } + podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() podmanTest.SeedImages() @@ -36,44 +48,96 @@ var _ = Describe("Podman run cpu", func() { It("podman run cpu-period", func() { SkipIfRootless() - result := podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var result *PodmanSessionIntegration + if cgroupsv2 { + result = podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.max"}) + } else { + result = podmanTest.Podman([]string{"run", "--rm", "--cpu-period=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"}) + } result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) - Expect(result.OutputToString()).To(Equal("5000")) + Expect(result.LineInOutputContains("5000")) }) It("podman run cpu-quota", func() { SkipIfRootless() - result := podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var result *PodmanSessionIntegration + + if cgroupsv2 { + result = podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.max"}) + } else { + result = podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"}) + } result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) - Expect(result.OutputToString()).To(Equal("5000")) + Expect(result.LineInOutputContains("5000")) }) It("podman run cpus", func() { SkipIfRootless() - result := podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"}) - result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Equal(0)) - Expect(result.OutputToString()).To(Equal("100000")) - result = podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"}) - result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Equal(0)) - Expect(result.OutputToString()).To(Equal("50000")) + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + result := podmanTest.Podman([]string{"run", "--rm", "--cpu-quota=5000", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.max"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal("5000 100000")) + } else { + result := podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_period_us"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal("100000")) + + result = podmanTest.Podman([]string{"run", "--rm", "--cpus=0.5", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal("50000")) + } }) It("podman run cpu-shares", func() { SkipIfRootless() - result := podmanTest.Podman([]string{"run", "--rm", "--cpu-shares=2", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.shares"}) - result.WaitWithDefaultTimeout() - Expect(result.ExitCode()).To(Equal(0)) - Expect(result.OutputToString()).To(Equal("2")) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + // [2-262144] is mapped to [1-10000] + result := podmanTest.Podman([]string{"run", "--rm", "--cpu-shares=262144", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpu.weight"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal("10000")) + } else { + result := podmanTest.Podman([]string{"run", "--rm", "--cpu-shares=2", ALPINE, "cat", "/sys/fs/cgroup/cpu/cpu.shares"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(Equal("2")) + } }) It("podman run cpuset-cpus", func() { SkipIfRootless() - result := podmanTest.Podman([]string{"run", "--rm", "--cpuset-cpus=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.cpus"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var result *PodmanSessionIntegration + + if cgroupsv2 { + result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-cpus=0", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpuset.cpus.effective"}) + } else { + result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-cpus=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.cpus"}) + } result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(result.OutputToString()).To(Equal("0")) @@ -81,7 +145,17 @@ var _ = Describe("Podman run cpu", func() { It("podman run cpuset-mems", func() { SkipIfRootless() - result := podmanTest.Podman([]string{"run", "--rm", "--cpuset-mems=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.mems"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var result *PodmanSessionIntegration + + if cgroupsv2 { + result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-mems=0", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/cpuset.mems.effective"}) + } else { + result = podmanTest.Podman([]string{"run", "--rm", "--cpuset-mems=0", ALPINE, "cat", "/sys/fs/cgroup/cpuset/cpuset.mems"}) + } result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(result.OutputToString()).To(Equal("0")) diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go index 861d6b3b7..b05849ddb 100644 --- a/test/e2e/run_exit_test.go +++ b/test/e2e/run_exit_test.go @@ -41,12 +41,16 @@ var _ = Describe("Podman run exit", func() { }) It("podman run exit 126", func() { + SkipIfNotRunc() + result := podmanTest.Podman([]string{"run", ALPINE, "/etc"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(126)) }) It("podman run exit 127", func() { + SkipIfNotRunc() + result := podmanTest.Podman([]string{"run", ALPINE, "foobar"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(127)) diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index 8fe90c8d8..a45735a8a 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -5,6 +5,7 @@ package integration import ( "os" + "github.com/containers/libpod/pkg/cgroups" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -36,7 +37,16 @@ var _ = Describe("Podman run memory", func() { }) It("podman run memory test", func() { - session := podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"}) + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var session *PodmanSessionIntegration + + if cgroupsv2 { + session = podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.max"}) + } else { + session = podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"}) + } session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(Equal("41943040")) @@ -46,13 +56,31 @@ var _ = Describe("Podman run memory", func() { if podmanTest.Host.Distribution == "ubuntu" { Skip("Unable to perform test on Ubuntu distributions due to memory management") } - session := podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var session *PodmanSessionIntegration + + if cgroupsv2 { + session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.high"}) + } else { + session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"}) + } + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(Equal("41943040")) }) It("podman run memory-swappiness test", func() { + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + Skip("Memory swappiness not supported on cgroups v2") + } + session := podmanTest.Podman([]string{"run", "--memory-swappiness=15", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.swappiness"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -60,6 +88,12 @@ var _ = Describe("Podman run memory", func() { }) It("podman run kernel-memory test", func() { + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + Skip("Kernel memory not supported on cgroups v2") + } session := podmanTest.Podman([]string{"run", "--kernel-memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index f66d1d2fa..ce2044a72 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -13,6 +13,7 @@ import ( "syscall" "time" + "github.com/containers/libpod/pkg/cgroups" . "github.com/containers/libpod/test/utils" "github.com/containers/storage/pkg/stringid" "github.com/mrunalp/fileutils" @@ -263,9 +264,15 @@ var _ = Describe("Podman run", func() { Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("1024")) - session = podmanTest.Podman([]string{"run", "--rm", "--oom-kill-disable=true", fedoraMinimal, "echo", "memory-hog"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if !cgroupsv2 { + // --oom-kill-disable not supported on cgroups v2. + session = podmanTest.Podman([]string{"run", "--rm", "--oom-kill-disable=true", fedoraMinimal, "echo", "memory-hog"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + } session = podmanTest.Podman([]string{"run", "--rm", "--oom-score-adj=100", fedoraMinimal, "cat", "/proc/self/oom_score_adj"}) session.WaitWithDefaultTimeout() @@ -310,18 +317,43 @@ var _ = Describe("Podman run", func() { It("podman run blkio-weight test", func() { SkipIfRootless() - if _, err := os.Stat("/sys/fs/cgroup/blkio/blkio.weight"); os.IsNotExist(err) { - Skip("Kernel does not support blkio.weight") + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if !cgroupsv2 { + if _, err := os.Stat("/sys/fs/cgroup/blkio/blkio.weight"); os.IsNotExist(err) { + Skip("Kernel does not support blkio.weight") + } + } + + if cgroupsv2 { + // convert linearly from [10-1000] to [1-10000] + session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.bfq.weight"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("51")) + } else { + session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.weight"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("15")) } - session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.weight"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(ContainSubstring("15")) }) It("podman run device-read-bps test", func() { SkipIfRootless() - session := podmanTest.Podman([]string{"run", "--rm", "--device-read-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var session *PodmanSessionIntegration + + if cgroupsv2 { + session = podmanTest.Podman([]string{"run", "--rm", "--device-read-bps=/dev/zero:1mb", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"}) + } else { + session = podmanTest.Podman([]string{"run", "--rm", "--device-read-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"}) + } + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("1048576")) @@ -329,7 +361,17 @@ var _ = Describe("Podman run", func() { It("podman run device-write-bps test", func() { SkipIfRootless() - session := podmanTest.Podman([]string{"run", "--rm", "--device-write-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_bps_device"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var session *PodmanSessionIntegration + + if cgroupsv2 { + session = podmanTest.Podman([]string{"run", "--rm", "--device-write-bps=/dev/zero:1mb", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"}) + } else { + session = podmanTest.Podman([]string{"run", "--rm", "--device-write-bps=/dev/zero:1mb", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_bps_device"}) + } session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("1048576")) @@ -337,7 +379,18 @@ var _ = Describe("Podman run", func() { It("podman run device-read-iops test", func() { SkipIfRootless() - session := podmanTest.Podman([]string{"run", "--rm", "--device-read-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var session *PodmanSessionIntegration + + if cgroupsv2 { + session = podmanTest.Podman([]string{"run", "--rm", "--device-read-iops=/dev/zero:100", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"}) + } else { + session = podmanTest.Podman([]string{"run", "--rm", "--device-read-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device"}) + } + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("100")) @@ -345,7 +398,18 @@ var _ = Describe("Podman run", func() { It("podman run device-write-iops test", func() { SkipIfRootless() - session := podmanTest.Podman([]string{"run", "--rm", "--device-write-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_iops_device"}) + + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + var session *PodmanSessionIntegration + + if cgroupsv2 { + session = podmanTest.Podman([]string{"run", "--rm", "--device-write-iops=/dev/zero:100", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"}) + } else { + session = podmanTest.Podman([]string{"run", "--rm", "--device-write-iops=/dev/zero:100", ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.write_iops_device"}) + } + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("100")) @@ -353,6 +417,8 @@ var _ = Describe("Podman run", func() { It("podman run notify_socket", func() { SkipIfRemote() + SkipIfNotRunc() + host := GetHostDistributionInfo() if host.Distribution != "rhel" && host.Distribution != "centos" && host.Distribution != "fedora" { Skip("this test requires a working runc") @@ -563,6 +629,7 @@ var _ = Describe("Podman run", func() { }) It("podman run exit code on failure to exec", func() { + SkipIfNotRunc() session := podmanTest.Podman([]string{"run", ALPINE, "/etc"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(126)) diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go index fc1203ed1..2dbb9545b 100644 --- a/test/e2e/start_test.go +++ b/test/e2e/start_test.go @@ -101,6 +101,8 @@ var _ = Describe("Podman start", func() { }) It("podman failed to start with --rm should delete the container", func() { + SkipIfNotRunc() + session := podmanTest.Podman([]string{"create", "-it", "--rm", ALPINE, "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -114,6 +116,8 @@ var _ = Describe("Podman start", func() { }) It("podman failed to start without --rm should NOT delete the container", func() { + SkipIfNotRunc() + session := podmanTest.Podman([]string{"create", "-it", ALPINE, "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats index 85b9bc1ca..5fc07acfb 100644 --- a/test/system/001-basic.bats +++ b/test/system/001-basic.bats @@ -13,6 +13,14 @@ function setup() { @test "podman version emits reasonable output" { run_podman version + # First line of podman-remote is "Client:<blank>". + # Just delete it (i.e. remove the first entry from the 'lines' array) + if is_remote; then + if expr "${lines[0]}" : "Client:" >/dev/null; then + lines=("${lines[@]:1}") + fi + fi + is "${lines[0]}" "Version:[ ]\+[1-9][0-9.]\+" "Version line 1" is "$output" ".*Go Version: \+" "'Go Version' in output" is "$output" ".*RemoteAPI Version: \+" "API version in output" diff --git a/test/system/030-run.bats b/test/system/030-run.bats index cefff0e2c..9e609b434 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -43,4 +43,17 @@ echo $rand | 0 | $rand is "$output" "" "unwanted /sys/kernel in 'mount' output (with --net=host)" } +# 'run --rm' goes through different code paths and may lose exit status. +# See https://github.com/containers/libpod/issues/3795 +@test "podman run --rm" { + skip_if_remote "podman-remote does not handle exit codes" + + run_podman 0 run --rm $IMAGE /bin/true + run_podman 1 run --rm $IMAGE /bin/false + + # Believe it or not, 'sh -c' resulted in different behavior + run_podman 0 run --rm $IMAGE sh -c /bin/true + run_podman 1 run --rm $IMAGE sh -c /bin/false +} + # vim: filetype=sh diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats new file mode 100644 index 000000000..c13c8c52e --- /dev/null +++ b/test/system/055-rm.bats @@ -0,0 +1,42 @@ +#!/usr/bin/env bats -*- bats -*- +# +# tests for podman rm +# + +load helpers + +@test "podman rm" { + rand=$(random_string 30) + run_podman run --name $rand $IMAGE /bin/true + + # Don't care about output, just check exit status (it should exist) + run_podman 0 inspect $rand + + # container should be in output of 'ps -a' + run_podman ps -a + is "$output" ".* $IMAGE .*/true .* $rand" "Container present in 'ps -a'" + + # Remove container; now 'inspect' should fail + run_podman rm $rand + run_podman 125 inspect $rand +} + +# I'm sorry! This test takes 13 seconds. There's not much I can do about it, +# please know that I think it's justified: podman 1.5.0 had a strange bug +# in with exit status was not preserved on some code paths with 'rm -f' +# or 'podman run --rm' (see also 030-run.bats). The test below is a bit +# kludgy: what we care about is the exit status of the killed container, +# not 'podman rm', but BATS has no provision (that I know of) for forking, +# so what we do is start the 'rm' beforehand and monitor the exit status +# of the 'sleep' container. +# +# See https://github.com/containers/libpod/issues/3795 +@test "podman rm -f" { + skip_if_remote "podman-remote does not handle exit codes" + + rand=$(random_string 30) + ( sleep 3; run_podman rm -f $rand ) & + run_podman 137 run --name $rand $IMAGE sleep 30 +} + +# vim: filetype=sh diff --git a/test/system/070-build.bats b/test/system/070-build.bats index c1e7c7ec4..5ef84e9b8 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -6,10 +6,8 @@ load helpers @test "podman build - basic test" { - if [[ "$PODMAN" =~ -remote ]]; then - if [ "$(id -u)" -ne 0 ]; then - skip "unreliable with podman-remote and rootless; #2972" - fi + if is_remote && is_rootless; then + skip "unreliable with podman-remote and rootless; #2972" fi rand_filename=$(random_string 20) diff --git a/test/system/200-pod-top.bats b/test/system/200-pod-top.bats index 10808ddb2..bba1e8d14 100644 --- a/test/system/200-pod-top.bats +++ b/test/system/200-pod-top.bats @@ -3,6 +3,8 @@ load helpers @test "podman pod top - containers in different PID namespaces" { + skip_if_remote "podman-pod does not work with podman-remote" + # With infra=false, we don't get a /pause container (we also # don't pull k8s.gcr.io/pause ) no_infra='--infra=false' diff --git a/test/system/README.md b/test/system/README.md index d98b1c0fe..fe6d1ed52 100644 --- a/test/system/README.md +++ b/test/system/README.md @@ -28,6 +28,8 @@ on failure. * `skip_if_rootless` - if rootless, skip this test with a helpful message. +* `skip_if_remote` - like the above, but skip if testing `podman-remote` + * `random_string` - returns a pseudorandom alphanumeric string Test files are of the form `NNN-name.bats` where NNN is a three-digit diff --git a/test/system/helpers.bash b/test/system/helpers.bash index fe0a25b37..3d607f4bd 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -216,26 +216,31 @@ function wait_for_ready { ############################################################################### # BEGIN miscellaneous tools +# Shortcuts for common needs: +function is_rootless() { + [ "$(id -u)" -ne 0 ] +} + +function is_remote() { + [[ "$PODMAN" =~ -remote ]] +} + ###################### # skip_if_rootless # ...with an optional message ###################### function skip_if_rootless() { - if [ "$(id -u)" -eq 0 ]; then - return + if is_rootless; then + skip "${1:-not applicable under rootless podman}" fi - - skip "${1:-not applicable under rootless podman}" } #################### # skip_if_remote # ...with an optional message #################### function skip_if_remote() { - if [[ ! "$PODMAN" =~ -remote ]]; then - return + if is_remote; then + skip "${1:-test does not work with podman-remote}" fi - - skip "${1:-test does not work with podman-remote}" } ######################### diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION index b50dd27dd..065f9ec4c 100644 --- a/vendor/github.com/containers/storage/VERSION +++ b/vendor/github.com/containers/storage/VERSION @@ -1 +1 @@ -1.13.1 +1.13.3-dev diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go index 30264ef4a..1f719fa85 100644 --- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go +++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go @@ -645,7 +645,15 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { if err != nil { return "", err } - if len(options.Options) > 0 { + switch len(options.Options) { + case 0: + case 1: + if options.Options[0] == "ro" { + // ignore "ro" option + break + } + fallthrough + default: return "", fmt.Errorf("btrfs driver does not support mount options") } diff --git a/vendor/github.com/containers/storage/drivers/windows/windows.go b/vendor/github.com/containers/storage/drivers/windows/windows.go index 11f1c98b1..c1ab93e1d 100644 --- a/vendor/github.com/containers/storage/drivers/windows/windows.go +++ b/vendor/github.com/containers/storage/drivers/windows/windows.go @@ -372,7 +372,15 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, options.MountLabel) var dir string - if len(options.Options) > 0 { + switch len(options.Options) { + case 0: + case 1: + if options.Options[0] == "ro" { + // ignore "ro" option + break + } + fallthrough + default: return "", fmt.Errorf("windows driver does not support mount options") } rID, err := d.resolveID(id) diff --git a/vendor/modules.txt b/vendor/modules.txt index 2726a53a9..efb7d99da 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -103,7 +103,7 @@ github.com/containers/psgo/internal/dev github.com/containers/psgo/internal/proc github.com/containers/psgo/internal/process github.com/containers/psgo/internal/host -# github.com/containers/storage v1.13.1 +# github.com/containers/storage v1.13.2 github.com/containers/storage github.com/containers/storage/pkg/archive github.com/containers/storage/pkg/chrootarchive diff --git a/version/version.go b/version/version.go index 286f66093..f0823f260 100644 --- a/version/version.go +++ b/version/version.go @@ -4,7 +4,7 @@ package version // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -const Version = "1.4.5-dev" +const Version = "1.5.2-dev" // RemoteAPIVersion is the version for the remote // client API. It is used to determine compatibility |