summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml147
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md6
-rw-r--r--Makefile36
-rw-r--r--README.md12
-rw-r--r--cmd/podman/common/completion.go146
-rw-r--r--cmd/podman/common/create.go7
-rw-r--r--cmd/podman/common/create_opts.go477
-rw-r--r--cmd/podman/common/default.go3
-rw-r--r--cmd/podman/containers/create.go19
-rw-r--r--cmd/podman/containers/run.go12
-rw-r--r--cmd/podman/images/load.go2
-rw-r--r--cmd/podman/machine/list.go9
-rw-r--r--cmd/podman/machine/ssh.go4
-rw-r--r--cmd/podman/machine/start.go2
-rw-r--r--cmd/podman/system/reset.go14
-rw-r--r--cmd/podman/system/unshare.go21
-rw-r--r--cmd/podman/utils/error.go32
-rw-r--r--cmd/podman/utils/signals_linux.go15
-rw-r--r--cmd/podman/utils/signals_windows.go15
-rw-r--r--cmd/podman/volumes/export.go6
-rw-r--r--cmd/podman/volumes/import.go7
-rw-r--r--contrib/cirrus/CIModes.md129
-rwxr-xr-xcontrib/cirrus/runner.sh5
-rw-r--r--contrib/podmanimage/README.md10
-rw-r--r--contrib/podmanimage/stable/Containerfile55
-rw-r--r--contrib/podmanimage/stable/Dockerfile36
-rw-r--r--contrib/podmanimage/testing/Containerfile60
-rw-r--r--contrib/podmanimage/testing/Dockerfile36
-rw-r--r--contrib/podmanimage/upstream/Containerfile61
-rw-r--r--contrib/podmanimage/upstream/Dockerfile85
-rw-r--r--contrib/systemd/system/podman-restart.service.in3
-rw-r--r--docs/source/markdown/podman-build.1.md12
-rw-r--r--docs/source/markdown/podman-container-clone.1.md6
-rw-r--r--docs/source/markdown/podman-create.1.md35
-rw-r--r--docs/source/markdown/podman-image-scp.1.md12
-rw-r--r--docs/source/markdown/podman-machine-ssh.1.md30
-rw-r--r--docs/source/markdown/podman-play-kube.1.md4
-rw-r--r--docs/source/markdown/podman-pod-create.1.md30
-rw-r--r--docs/source/markdown/podman-run.1.md27
-rw-r--r--docs/source/markdown/podman-volume-import.1.md6
-rw-r--r--docs/source/markdown/podman-volume.1.md2
-rw-r--r--docs/tutorials/basic_networking.md16
-rw-r--r--go.mod10
-rw-r--r--go.sum22
-rw-r--r--libpod/container_api.go25
-rw-r--r--libpod/container_config.go7
-rw-r--r--libpod/container_internal.go26
-rw-r--r--libpod/container_internal_linux.go239
-rw-r--r--libpod/container_log.go8
-rw-r--r--libpod/healthcheck_linux.go70
-rw-r--r--libpod/networking_linux.go64
-rw-r--r--libpod/oci.go30
-rw-r--r--libpod/oci_conmon_attach_linux.go (renamed from libpod/oci_attach_linux.go)40
-rw-r--r--libpod/oci_conmon_linux.go4
-rw-r--r--libpod/oci_missing.go5
-rw-r--r--libpod/options.go29
-rw-r--r--libpod/pod.go27
-rw-r--r--libpod/pod_api.go5
-rw-r--r--libpod/reset.go72
-rw-r--r--libpod/runtime.go62
-rw-r--r--pkg/api/handlers/compat/containers_create.go12
-rw-r--r--pkg/api/handlers/compat/images_build.go146
-rw-r--r--pkg/api/handlers/libpod/manifests.go1
-rw-r--r--pkg/api/handlers/libpod/play.go4
-rw-r--r--pkg/bindings/images/build.go7
-rw-r--r--pkg/domain/infra/abi/containers.go1
-rw-r--r--pkg/domain/infra/abi/system.go2
-rw-r--r--pkg/domain/infra/runtime_abi.go2
-rw-r--r--pkg/domain/infra/runtime_libpod.go25
-rw-r--r--pkg/machine/config.go34
-rw-r--r--pkg/machine/e2e/config.go8
-rw-r--r--pkg/machine/e2e/inspect_test.go2
-rw-r--r--pkg/machine/e2e/ssh_test.go7
-rw-r--r--pkg/machine/fcos.go7
-rw-r--r--pkg/machine/qemu/machine.go46
-rw-r--r--pkg/machine/wsl/machine.go1
-rw-r--r--pkg/resolvconf/dns/resolvconf.go28
-rw-r--r--pkg/specgen/container_validate.go6
-rw-r--r--pkg/specgen/generate/config_linux.go139
-rw-r--r--pkg/specgen/generate/container_create.go14
-rw-r--r--pkg/specgen/generate/namespaces.go41
-rw-r--r--pkg/specgen/generate/oci.go10
-rw-r--r--pkg/specgen/generate/pod_create.go9
-rw-r--r--pkg/specgen/namespaces.go65
-rw-r--r--pkg/specgen/namespaces_test.go25
-rw-r--r--pkg/specgen/podspecgen.go5
-rw-r--r--pkg/specgen/volumes.go14
-rw-r--r--pkg/specgenutil/createparse.go17
-rw-r--r--pkg/specgenutil/specgen.go37
-rw-r--r--pkg/util/utils_linux.go142
-rw-r--r--test/apiv2/10-images.at2
-rw-r--r--test/apiv2/12-imagesMore.at56
-rw-r--r--test/apiv2/15-manifest.at24
-rw-r--r--test/apiv2/20-containers.at10
-rw-r--r--test/apiv2/60-auth.at4
-rw-r--r--test/apiv2/70-short-names.at2
-rwxr-xr-xtest/apiv2/test-apiv290
-rwxr-xr-xtest/buildah-bud/apply-podman-deltas13
-rw-r--r--test/e2e/build_test.go4
-rw-r--r--test/e2e/checkpoint_test.go4
-rw-r--r--test/e2e/logs_test.go33
-rw-r--r--test/e2e/network_connect_disconnect_test.go19
-rw-r--r--test/e2e/play_kube_test.go8
-rw-r--r--test/e2e/pod_create_test.go22
-rw-r--r--test/e2e/pod_infra_container_test.go23
-rw-r--r--test/e2e/run_privileged_test.go24
-rw-r--r--test/e2e/run_volume_test.go45
-rw-r--r--test/e2e/save_test.go8
-rw-r--r--test/e2e/volume_create_test.go17
-rw-r--r--test/system/030-run.bats11
-rw-r--r--test/system/120-load.bats2
-rw-r--r--test/system/160-volumes.bats39
-rw-r--r--test/system/170-run-userns.bats39
-rw-r--r--test/system/500-networking.bats4
-rw-r--r--test/system/520-checkpoint.bats30
-rw-r--r--test/system/600-completion.bats102
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/invoke/exec.go45
-rw-r--r--vendor/github.com/containers/common/libimage/inspect.go2
-rw-r--r--vendor/github.com/containers/common/libimage/pull.go3
-rw-r--r--vendor/github.com/containers/common/libnetwork/resolvconf/resolv.go182
-rw-r--r--vendor/github.com/containers/common/libnetwork/resolvconf/resolvconf.go (renamed from pkg/resolvconf/resolvconf.go)158
-rw-r--r--vendor/github.com/docker/docker/api/swagger.yaml2
-rw-r--r--vendor/github.com/docker/docker/pkg/system/mknod.go6
-rw-r--r--vendor/github.com/docker/docker/pkg/system/mknod_freebsd.go14
-rw-r--r--vendor/github.com/docker/docker/pkg/system/mknod_unix.go14
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/.golangci.yml4
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/.travis.yml57
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md26
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/Makefile7
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/README.md24
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/SECURITY.md47
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/go.sum23
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/seccomp.go253
-rw-r--r--vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go175
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go2
-rw-r--r--vendor/gopkg.in/yaml.v3/decode.go78
-rw-r--r--vendor/gopkg.in/yaml.v3/parserc.go11
-rw-r--r--vendor/modules.txt15
138 files changed, 2886 insertions, 2151 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index fe00974b3..21100388f 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -59,6 +59,7 @@ env:
curl --fail --location -O
--url https://api.cirrus-ci.com/v1/artifact/build/${CIRRUS_BUILD_ID}
+
# Default timeout for each task
timeout_in: 60m
@@ -71,7 +72,9 @@ gcp_credentials: ENCRYPTED[a28959877b2c9c36f151781b0a05407218cda646c7d047fc556e4
ext_svc_check_task:
alias: 'ext_svc_check' # int. ref. name - required for depends_on reference
name: "Ext. services" # Displayed Title - has no other significance
- skip: &tags "$CIRRUS_TAG != ''" # Don't run on tags
+ # Don't create this task for new tags so release process is more reliable
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: $CIRRUS_TAG == ''
# Default/small container image to execute tasks with
container: &smallcontainer
image: ${CTR_FQIN}
@@ -117,7 +120,9 @@ ext_svc_check_task:
automation_task:
alias: 'automation'
name: "Check Automation"
- skip: &branches_and_tags "$CIRRUS_PR == '' || $CIRRUS_TAG != ''" # Don't run on branches/tags
+ # This task is not needed for branches, tags, or cron runs.
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: &is_pr "$CIRRUS_PR != ''"
container: *smallcontainer
env:
TEST_FLAVOR: automation
@@ -138,6 +143,9 @@ automation_task:
build_task:
alias: 'build'
name: 'Build for $DISTRO_NV'
+ # Multiarch doesn't depend on buildability in this automation context
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: "$CIRRUS_CRON != 'multiarch'"
gce_instance: &standardvm
image_project: libpod-218412
zone: "us-central1-a"
@@ -189,7 +197,8 @@ validate_task:
# automation reliability/speed in those contexts. Any missed errors due
# to nonsequential PR merging practices, will be caught on a future PR,
# build or test task failures.
- skip: *branches_and_tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *is_pr
depends_on:
- ext_svc_check
- automation
@@ -218,9 +227,12 @@ validate_task:
bindings_task:
name: "Test Bindings"
alias: bindings
- # Don't run for [CI:DOCS] or [CI:BUILD]
- only_if: &not_build $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' && $CIRRUS_CHANGE_TITLE !=~ '.*CI:BUILD.*'
- skip: *branches_and_tags
+ # Don't create task for PRs using [CI:DOCS] or [CI:BUILD]
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: >-
+ $CIRRUS_PR != '' &&
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' &&
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:BUILD.*'
depends_on:
- build
gce_instance: *standardvm
@@ -249,6 +261,11 @@ bindings_task:
swagger_task:
name: "Test Swagger"
alias: swagger
+ # Don't create task for [CI:BUILD] or multiarch builds
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: >-
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:BUILD.*' &&
+ $CIRRUS_CRON != 'multiarch'
depends_on:
- build
gce_instance: *standardvm
@@ -276,7 +293,8 @@ swagger_task:
consistency_task:
name: "Test Code Consistency"
alias: consistency
- skip: *tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *is_pr
depends_on:
- build
container: *smallcontainer
@@ -297,8 +315,11 @@ consistency_task:
alt_build_task:
name: "$ALT_NAME"
alias: alt_build
- # Don't run for [CI:DOCS]; DO run for [CI:BUILD]
- only_if: &not_docs $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*'
+ # Don't create task for [CI:DOCS] or multiarch builds
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: &not_docs_multiarch >-
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' &&
+ $CIRRUS_CRON != 'multiarch'
depends_on:
- build
env:
@@ -330,7 +351,8 @@ alt_build_task:
osx_alt_build_task:
name: "OSX Cross"
alias: osx_alt_build
- only_if: *not_docs
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_docs_multiarch
depends_on:
- build
env:
@@ -359,8 +381,14 @@ osx_alt_build_task:
docker-py_test_task:
name: Docker-py Compat.
alias: docker-py_test
- skip: *tags
- only_if: *not_build
+ # Don't create task for tags, branches, or PRs w/ [CI:DOCS] or [CI:BUILD]
+ # N/B: for PRs $CIRRUS_BRANCH == 'pull/<number>'
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: &not_tag_branch_build_docs >-
+ $CIRRUS_PR != '' &&
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' &&
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:BUILD.*'
+
depends_on:
- build
gce_instance: *standardvm
@@ -379,8 +407,8 @@ docker-py_test_task:
unit_test_task:
name: "Unit tests on $DISTRO_NV"
alias: unit_test
- skip: *tags
- only_if: *not_build
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- validate
matrix:
@@ -404,8 +432,8 @@ unit_test_task:
apiv2_test_task:
name: "APIv2 test on $DISTRO_NV"
alias: apiv2_test
- only_if: *not_build
- skip: *tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- validate
gce_instance: *standardvm
@@ -424,8 +452,8 @@ apiv2_test_task:
compose_test_task:
name: "$TEST_FLAVOR test on $DISTRO_NV ($PRIV_NAME)"
alias: compose_test
- only_if: *not_build
- skip: *tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- validate
gce_instance: *standardvm
@@ -457,8 +485,8 @@ local_integration_test_task: &local_integration_test_task
# <int.|sys.> <podman|remote> <Distro NV> <root|rootless>
name: &std_name_fmt "$TEST_FLAVOR $PODBIN_NAME $DISTRO_NV $PRIV_NAME $TEST_ENVIRON"
alias: local_integration_test
- only_if: *not_build
- skip: *branches_and_tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- unit_test
matrix: *platform_axis
@@ -492,8 +520,8 @@ remote_integration_test_task:
container_integration_test_task:
name: *std_name_fmt
alias: container_integration_test
- only_if: *not_build
- skip: *branches_and_tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- unit_test
matrix: &fedora_vm_axis
@@ -522,8 +550,8 @@ container_integration_test_task:
rootless_integration_test_task:
name: *std_name_fmt
alias: rootless_integration_test
- only_if: *not_build
- skip: *branches_and_tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- unit_test
matrix: *platform_axis
@@ -545,8 +573,13 @@ rootless_integration_test_task:
local_system_test_task: &local_system_test_task
name: *std_name_fmt
alias: local_system_test
- skip: *tags
- only_if: *not_build
+ # Don't create task for tags, or if using [CI:DOCS], [CI:BUILD], multiarch
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: &not_tag_build_docs_multiarch >-
+ $CIRRUS_TAG == '' &&
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' &&
+ $CIRRUS_CHANGE_TITLE !=~ '.*CI:BUILD.*' &&
+ $CIRRUS_CRON != 'multiarch'
depends_on:
- local_integration_test
matrix: *platform_axis
@@ -590,11 +623,29 @@ rootless_remote_system_test_task:
PRIV_NAME: rootless
+rootless_system_test_task:
+ name: *std_name_fmt
+ alias: rootless_system_test
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_build_docs_multiarch
+ depends_on:
+ - rootless_integration_test
+ matrix: *platform_axis
+ gce_instance: *standardvm
+ env:
+ TEST_FLAVOR: sys
+ PRIV_NAME: rootless
+ clone_script: *get_gosrc
+ setup_script: *setup
+ main_script: *main
+ always: *logs_artifacts
+
+
buildah_bud_test_task:
name: *std_name_fmt
alias: buildah_bud_test
- skip: *tags
- only_if: *not_build
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- local_integration_test
env:
@@ -618,29 +669,11 @@ buildah_bud_test_task:
always: *int_logs_artifacts
-rootless_system_test_task:
- name: *std_name_fmt
- alias: rootless_system_test
- skip: *tags
- only_if: *not_build
- depends_on:
- - rootless_integration_test
- matrix: *platform_axis
- gce_instance: *standardvm
- env:
- TEST_FLAVOR: sys
- PRIV_NAME: rootless
- clone_script: *get_gosrc
- setup_script: *setup
- main_script: *main
- always: *logs_artifacts
-
-
rootless_gitlab_test_task:
name: *std_name_fmt
alias: rootless_gitlab_test
- skip: *tags
- only_if: *not_build
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
# Community-maintained downstream test may fail unexpectedly.
# Ref. repository: https://gitlab.com/gitlab-org/gitlab-runner
# If necessary, uncomment the next line and file issue(s) with details.
@@ -666,8 +699,8 @@ rootless_gitlab_test_task:
upgrade_test_task:
name: "Upgrade test: from $PODMAN_UPGRADE_FROM"
alias: upgrade_test
- skip: *tags
- only_if: *not_build
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_tag_branch_build_docs
depends_on:
- local_system_test
matrix:
@@ -695,9 +728,10 @@ image_build_task: &image-build
alias: image_build
# Some of these container images take > 1h to build, limit
# this task to a specific Cirrus-Cron entry with this name.
+ # Docs: ./contrib/cirrus/CIModes.md
only_if: $CIRRUS_CRON == 'multiarch'
depends_on:
- - build
+ - ext_svc_check
timeout_in: 120m # emulation is sssllllooooowwww
gce_instance:
<<: *standardvm
@@ -728,6 +762,7 @@ test_image_build_task:
<<: *image-build
alias: test_image_build
# Allow this to run inside a PR w/ [CI:BUILD] only.
+ # Docs: ./contrib/cirrus/CIModes.md
only_if: $CIRRUS_PR != '' && $CIRRUS_CHANGE_TITLE =~ '.*CI:BUILD.*'
# This takes a LONG time, only run when requested. N/B: Any task
# made to depend on this one will block FOREVER unless triggered.
@@ -793,9 +828,9 @@ success_task:
- remote_system_test
- rootless_system_test
- rootless_remote_system_test
+ - buildah_bud_test
- rootless_gitlab_test
- upgrade_test
- - buildah_bud_test
- image_build
- meta
container: *smallcontainer
@@ -809,7 +844,8 @@ success_task:
artifacts_task:
name: "Artifacts"
alias: artifacts
- only_if: *not_docs
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: *not_docs_multiarch
depends_on:
- success
# This task is a secondary/convenience for downstream consumers, don't
@@ -862,7 +898,9 @@ artifacts_task:
release_task:
name: "Verify Release"
alias: release
- only_if: *tags
+ # This should _only_ run for new tags
+ # Docs: ./contrib/cirrus/CIModes.md
+ only_if: $CIRRUS_TAG != ''
depends_on:
- success
gce_instance: *standardvm
@@ -884,6 +922,7 @@ release_test_task:
name: "Optional Release Test"
alias: release_test
# Release-PRs always include "release" or "Bump" in the title
+ # Docs: ./contrib/cirrus/CIModes.md
only_if: $CIRRUS_CHANGE_TITLE =~ '.*((release)|(bump)).*'
# Allow running manually only as part of release-related builds
# see RELEASE_PROCESS.md
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 9a4563308..cc8b618f4 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -3,9 +3,9 @@ Thanks for sending a pull request!
Please make sure you've read our contributing guidelines and how to submit a pull request (https://github.com/containers/podman/blob/main/CONTRIBUTING.md#submitting-pull-requests).
-In case you're only changing docs, make sure to prefix the pull-request title with "[CI:DOCS]". That will prevent functional tests from running and save time and energy.
+In case you're only changing docs, make sure to prefix the pull-request title with "[CI:DOCS]". That will prevent functional tests from running and save time and energy.
-Finally, be sure to sign commits with your real name. Since by opening
+Finally, be sure to sign commits with your real name. Since by opening
a PR you already have commits, you can add signatures if needed with
something like `git commit -s --amend`.
-->
@@ -18,7 +18,7 @@ is required: Enter your extended release note in the block below. If the PR
requires additional action from users switching to the new release, include the
string "action required".
-For more information on release notes please follow the kubernetes model:
+For more information on release notes, please follow the Kubernetes model:
https://git.k8s.io/community/contributors/guide/release-notes.md
-->
diff --git a/Makefile b/Makefile
index fb9eb057d..3810459b0 100644
--- a/Makefile
+++ b/Makefile
@@ -29,8 +29,6 @@ EPOCH_TEST_COMMIT ?= $(shell git merge-base $${DEST_BRANCH:-main} HEAD)
HEAD ?= HEAD
PROJECT := github.com/containers/podman
GIT_BASE_BRANCH ?= origin/main
-GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
-GIT_BRANCH_CLEAN ?= $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
LIBPOD_INSTANCE := libpod_dev
PREFIX ?= /usr/local
BINDIR ?= ${PREFIX}/bin
@@ -80,18 +78,18 @@ FISHINSTALLDIR=${PREFIX}/share/fish/vendor_completions.d
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
COMMIT_NO ?= $(shell git rev-parse HEAD 2> /dev/null || true)
-GIT_COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO})
+GIT_COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),$(call err_if_empty,COMMIT_NO)-dirty,$(COMMIT_NO))
DATE_FMT = %s
ifdef SOURCE_DATE_EPOCH
- BUILD_INFO ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u "+$(DATE_FMT)")
+ BUILD_INFO ?= $(shell date -u -d "@$(call err_if_empty,SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+$(DATE_FMT)" 2>/dev/null || date -u "+$(DATE_FMT)")
else
BUILD_INFO ?= $(shell date "+$(DATE_FMT)")
endif
LIBPOD := ${PROJECT}/v4/libpod
GOFLAGS ?= -trimpath
LDFLAGS_PODMAN ?= \
- -X $(LIBPOD)/define.gitCommit=$(GIT_COMMIT) \
- -X $(LIBPOD)/define.buildInfo=$(BUILD_INFO) \
+ $(if $(GIT_COMMIT),-X $(LIBPOD)/define.gitCommit=$(GIT_COMMIT),) \
+ $(if $(BUILD_INFO),-X $(LIBPOD)/define.buildInfo=$(BUILD_INFO),) \
-X $(LIBPOD)/config._installPrefix=$(PREFIX) \
-X $(LIBPOD)/config._etcDir=$(ETCDIR) \
-X github.com/containers/common/pkg/config.additionalHelperBinariesDir=$(HELPER_BINARIES_DIR)\
@@ -107,7 +105,7 @@ GINKGOTIMEOUT ?= -timeout=90m
# Conditional required to produce empty-output if binary not built yet.
RELEASE_VERSION = $(shell if test -x test/version/version; then test/version/version; fi)
-RELEASE_NUMBER = $(shell echo "$(RELEASE_VERSION)" | sed -e 's/^v\(.*\)/\1/')
+RELEASE_NUMBER = $(shell echo "$(call err_if_empty,RELEASE_VERSION)" | sed -e 's/^v\(.*\)/\1/')
# If non-empty, logs all output from server during remote system testing
PODMAN_SERVER_LOG ?=
@@ -138,7 +136,7 @@ err_if_empty = $(if $(strip $($(1))),$(strip $($(1))),$(error Required variable
CGO_ENABLED ?= 1
# Default to the native OS type and architecture unless otherwise specified
NATIVE_GOOS := $(shell env -u GOOS $(GO) env GOOS)
-GOOS ?= $(NATIVE_GOOS)
+GOOS ?= $(call err_if_empty,NATIVE_GOOS)
# Default to the native architecture type
NATIVE_GOARCH := $(shell env -u GOARCH $(GO) env GOARCH)
GOARCH ?= $(NATIVE_GOARCH)
@@ -158,7 +156,7 @@ export GOOS GOARCH CGO_ENABLED BINSFX SRCBINDIR
# Need to use CGO for mDNS resolution, but cross builds need CGO disabled
# See https://github.com/golang/go/issues/12524 for details
DARWIN_GCO := 0
-ifeq ($(NATIVE_GOOS),darwin)
+ifeq ($(call err_if_empty,NATIVE_GOOS),darwin)
ifdef HOMEBREW_PREFIX
DARWIN_GCO := 1
endif
@@ -189,8 +187,8 @@ binaries: podman podman-remote rootlessport ## Build podman, podman-remote and r
# at reference-time (due to `=` and not `=:`).
_HLP_TGTS_RX = '^[[:print:]]+:.*?\#\# .*$$'
_HLP_TGTS_CMD = grep -E $(_HLP_TGTS_RX) $(MAKEFILE_LIST)
-_HLP_TGTS_LEN = $(shell $(_HLP_TGTS_CMD) | cut -d : -f 1 | wc -L)
-_HLPFMT = "%-$(_HLP_TGTS_LEN)s %s\n"
+_HLP_TGTS_LEN = $(shell $(call err_if_empty,_HLP_TGTS_CMD) | cut -d : -f 1 | wc -L)
+_HLPFMT = "%-$(call err_if_empty,_HLP_TGTS_LEN)s %s\n"
.PHONY: help
help: ## (Default) Print listing of key targets with their descriptions
@printf $(_HLPFMT) "Target:" "Description:"
@@ -250,7 +248,7 @@ validate: lint .gitvalidation validate.completions man-page-check swagger-check
.PHONY: build-all-new-commits
build-all-new-commits:
# Validate that all the commits build on top of $(GIT_BASE_BRANCH)
- git rebase $(GIT_BASE_BRANCH) -x "$(MAKE)"
+ git rebase $(call err_if_empty,GIT_BASE_BRANCH) -x "$(MAKE)"
.PHONY: vendor
vendor:
@@ -295,7 +293,7 @@ $(SRCBINDIR)/podman$(BINSFX): $(SRCBINDIR) $(SOURCES) go.mod go.sum
$(SRCBINDIR)/podman-remote-static: $(SRCBINDIR) $(SOURCES) go.mod go.sum
CGO_ENABLED=0 \
- GOOS=$(GOOS) \
+ GOOS=linux \
GOARCH=$(GOARCH) \
$(GO) build \
$(BUILDFLAGS) \
@@ -441,7 +439,7 @@ docs: $(MANPAGES) ## Generate documentation
# docs/remote-docs.sh requires a locally executable 'podman-remote' binary
# in addition to the target-archetecture binary (if any).
-podman-remote-%-docs: podman-remote-$(NATIVE_GOOS)
+podman-remote-%-docs: podman-remote-$(call err_if_empty,NATIVE_GOOS)
$(eval GOOS := $*)
$(MAKE) docs $(MANPAGES)
rm -rf docs/build/remote
@@ -639,7 +637,7 @@ podman-release-%.tar.gz: test/version/version
$(eval SUBDIR := podman-v$(call err_if_empty,RELEASE_NUMBER))
$(eval _DSTARGS := "DESTDIR=$(TMPDIR)/$(SUBDIR)" "PREFIX=/usr")
$(eval GOARCH := $*)
- mkdir -p "$(TMPDIR)/$(SUBDIR)"
+ mkdir -p "$(call err_if_empty,TMPDIR)/$(SUBDIR)"
$(MAKE) GOOS=$(GOOS) GOARCH=$(NATIVE_GOARCH) \
clean-binaries docs podman-remote-$(GOOS)-docs
if [[ "$(GOARCH)" != "$(NATIVE_GOARCH)" ]]; then \
@@ -660,7 +658,7 @@ podman-remote-release-%.zip: test/version/version ## Build podman-remote for %=$
$(eval GOOS := $(firstword $(subst _, ,$*)))
$(eval GOARCH := $(lastword $(subst _, ,$*)))
$(eval _GOPLAT := GOOS=$(call err_if_empty,GOOS) GOARCH=$(call err_if_empty,GOARCH))
- mkdir -p "$(TMPDIR)/$(SUBDIR)"
+ mkdir -p "$(call err_if_empty,TMPDIR)/$(SUBDIR)"
$(MAKE) GOOS=$(GOOS) GOARCH=$(NATIVE_GOARCH) \
clean-binaries podman-remote-$(GOOS)-docs
if [[ "$(GOARCH)" != "$(NATIVE_GOARCH)" ]]; then \
@@ -679,8 +677,8 @@ podman-remote-release-%.zip: test/version/version ## Build podman-remote for %=$
.PHONY: podman.msi
podman.msi: test/version/version ## Build podman-remote, package for installation on Windows
- $(MAKE) podman-v$(RELEASE_NUMBER).msi
-podman-v$(RELEASE_NUMBER).msi: podman-remote-windows podman-remote-windows-docs podman-winpath win-sshproxy
+ $(MAKE) podman-v$(call err_if_empty,RELEASE_NUMBER).msi
+podman-v%.msi: test/version/version podman-remote-windows podman-remote-windows-docs podman-winpath win-sshproxy
$(eval DOCFILE := docs/build/remote/windows)
find $(DOCFILE) -print | \
wixl-heat --var var.ManSourceDir --component-group ManFiles \
@@ -715,7 +713,7 @@ package: ## Build rpm packages
# a full path to test installed podman or you risk to call another executable.
.PHONY: package-install
package-install: package ## Install rpm packages
- sudo ${PKG_MANAGER} -y install ${HOME}/rpmbuild/RPMS/*/*.rpm
+ sudo $(call err_if_empty,PKG_MANAGER) -y install ${HOME}/rpmbuild/RPMS/*/*.rpm
/usr/bin/podman version
/usr/bin/podman info # will catch a broken conmon
diff --git a/README.md b/README.md
index 1a1e21fe3..5e86b336e 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
# Podman: A tool for managing OCI containers and pods
Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers.
+Podman runs containers on Linux, but can also be used on Mac and Windows systems using a Podman-managed virtual machine.
Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes.
* [Latest Version: 4.1.0](https://github.com/containers/podman/releases/tag/v4.1.0)
@@ -24,16 +25,15 @@ At a high level, the scope of Podman and libpod is the following:
* Support for pods, groups of containers that share resources and are managed together.
* Support for running containers and pods without root or other elevated privileges.
* Resource isolation of containers and pods.
-* Support for a Docker-compatible CLI interface.
+* Support for a Docker-compatible CLI interface, which can both run containers locally and on remote systems.
* No manager daemon, for improved security and lower resource utilization at idle.
* Support for a REST API providing both a Docker-compatible interface and an improved interface exposing advanced Podman functionality.
-
-Podman presently only supports running containers on Linux. However, we are building a remote client which can run on Windows and macOS and manage Podman containers on a Linux system via the REST API using SSH tunneling.
+* Support for running on Windows and Mac via virtual machines run by `podman machine`.
## Roadmap
-1. Further improvements to the REST API, with a focus on bugfixes and implementing missing functionality
-1. Improvements on rootless containers, with a focus on improving the user experience and exposing presently-unavailable features when possible
+1. A fully-featured GUI frontend for `podman machine`
+1. Further improvements to `podman generate kube` and `podman play kube`
1. Improvements to Pods, including the addition of pod-level resource limits
## Communications
@@ -111,7 +111,7 @@ includes tables showing Docker commands and their Podman equivalent commands.
Tutorials on using Podman.
**[Remote Client](https://github.com/containers/podman/blob/main/docs/tutorials/remote_client.md)**
-A brief how-to on using the Podman remote-client.
+A brief how-to on using the Podman remote client.
**[Basic Setup and Use of Podman in a Rootless environment](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md)**
A tutorial showing the setup and configuration necessary to run Rootless Podman.
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 3720e9608..07dcc4e6a 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -4,6 +4,7 @@ import (
"bufio"
"fmt"
"os"
+ "path"
"reflect"
"strconv"
"strings"
@@ -21,6 +22,7 @@ import (
"github.com/containers/podman/v4/pkg/signal"
systemdDefine "github.com/containers/podman/v4/pkg/systemd/define"
"github.com/containers/podman/v4/pkg/util"
+ securejoin "github.com/cyphar/filepath-securejoin"
"github.com/spf13/cobra"
)
@@ -282,6 +284,90 @@ func getNetworks(cmd *cobra.Command, toComplete string, cType completeType) ([]s
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
+func fdIsNotDir(f *os.File) bool {
+ stat, err := f.Stat()
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return true
+ }
+ return !stat.IsDir()
+}
+
+func getPathCompletion(root string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if toComplete == "" {
+ toComplete = "/"
+ }
+ // Important: securejoin is required to make sure we never leave the root mount point
+ userpath, err := securejoin.SecureJoin(root, toComplete)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ var base string
+ f, err := os.Open(userpath)
+ // when error or file is not dir get the parent path to stat
+ if err != nil || fdIsNotDir(f) {
+ // Do not use path.Dir() since this cleans the paths which
+ // then no longer matches the user input.
+ userpath, base = path.Split(userpath)
+ toComplete, _ = path.Split(toComplete)
+ f, err = os.Open(userpath)
+ if err != nil {
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ }
+
+ if fdIsNotDir(f) {
+ // nothing to complete since it is no dir
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ entries, err := f.ReadDir(-1)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ if len(entries) == 0 {
+ // path is empty dir, just add the trailing slash and no space
+ if !strings.HasSuffix(toComplete, "/") {
+ toComplete += "/"
+ }
+ return []string{toComplete}, cobra.ShellCompDirectiveDefault | cobra.ShellCompDirectiveNoSpace
+ }
+ completions := make([]string, 0, len(entries))
+ count := 0
+ for _, e := range entries {
+ if strings.HasPrefix(e.Name(), base) {
+ suf := ""
+ // When the entry is an directory we add the "/" as suffix and do not want to add space
+ // to match normal shell completion behavior.
+ // Just inc counter again to fake more than one entry in this case and thus get no space.
+ if e.IsDir() {
+ suf = "/"
+ count++
+ }
+ completions = append(completions, simplePathJoinUnix(toComplete, e.Name()+suf))
+ count++
+ }
+ }
+ directive := cobra.ShellCompDirectiveDefault
+ if count > 1 {
+ // when we have more than one match we do not want to add a space after the completion
+ directive |= cobra.ShellCompDirectiveNoSpace
+ }
+ return completions, directive
+}
+
+// simplePathJoinUnix joins to path components by adding a slash only if p1 doesn't end with one.
+// We cannot use path.Join() for the completions logic because this one always calls Clean() on
+// the path which changes it from the input.
+func simplePathJoinUnix(p1, p2 string) string {
+ if p1[len(p1)-1] == '/' {
+ return p1 + p2
+ }
+ return p1 + "/" + p2
+}
+
// validCurrentCmdLine validates the current cmd line
// It utilizes the Args function from the cmd struct
// In most cases the Args function validates the args length but it
@@ -523,8 +609,32 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string)
}
return getImages(cmd, toComplete)
}
- // TODO: add path completion for files in the image
- return nil, cobra.ShellCompDirectiveDefault
+ // Mount the image and provide path completion
+ engine, err := setupImageEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ resp, err := engine.Mount(registry.Context(), []string{args[0]}, entities.ImageMountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ defer func() {
+ _, err := engine.Unmount(registry.Context(), []string{args[0]}, entities.ImageUnmountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ }
+ }()
+ if len(resp) != 1 {
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ // So this uses ShellCompDirectiveDefault to also still provide normal shell
+ // completion in case no path matches. This is useful if someone tries to get
+ // completion for paths that are not available in the image, e.g. /proc/...
+ return getPathCompletion(resp[0].Path, toComplete)
}
// AutocompleteRegistries - Autocomplete registries.
@@ -572,14 +682,40 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) < 2 {
+ if i := strings.IndexByte(toComplete, ':'); i > -1 {
+ // Looks like the user already set the container.
+ // Lets mount it and provide path completion for files in the container.
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ resp, err := engine.ContainerMount(registry.Context(), []string{toComplete[:i]}, entities.ContainerMountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ defer func() {
+ _, err := engine.ContainerUnmount(registry.Context(), []string{toComplete[:i]}, entities.ContainerUnmountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ }
+ }()
+ if len(resp) != 1 {
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ comps, directive := getPathCompletion(resp[0].Path, toComplete[i+1:])
+ return prefixSlice(toComplete[:i+1], comps), directive
+ }
+ // Suggest containers when they match the input otherwise normal shell completion is used
containers, _ := getContainers(cmd, toComplete, completeDefault)
for _, container := range containers {
- // TODO: Add path completion for inside the container if possible
if strings.HasPrefix(container, toComplete) {
- return containers, cobra.ShellCompDirectiveNoSpace
+ return suffixCompSlice(":", containers), cobra.ShellCompDirectiveNoSpace
}
}
- // else complete paths
+ // else complete paths on the host
return nil, cobra.ShellCompDirectiveDefault
}
// don't complete more than 2 args
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index d28becc8a..f89035be3 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra"
)
-const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))"
+const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))"
var containerConfig = registry.PodmanConfig()
@@ -255,9 +255,8 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
_ = cmd.RegisterFlagCompletionFunc(hostUserFlagName, completion.AutocompleteNone)
imageVolumeFlagName := "image-volume"
- createFlags.StringVar(
- &cf.ImageVolume,
- imageVolumeFlagName, DefaultImageVolume,
+ createFlags.String(
+ imageVolumeFlagName, containerConfig.Engine.ImageVolumeMode,
`Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`,
)
_ = cmd.RegisterFlagCompletionFunc(imageVolumeFlagName, AutocompleteImageVolume)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index c40d1ea51..ad535ff59 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -1,472 +1,9 @@
package common
import (
- "fmt"
- "net"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/containers/common/libnetwork/types"
- "github.com/containers/common/pkg/cgroups"
- "github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/cmd/podman/registry"
- "github.com/containers/podman/v4/libpod/define"
- "github.com/containers/podman/v4/pkg/api/handlers"
- "github.com/containers/podman/v4/pkg/domain/entities"
- "github.com/containers/podman/v4/pkg/rootless"
- "github.com/containers/podman/v4/pkg/specgen"
- "github.com/docker/docker/api/types/mount"
- "github.com/pkg/errors"
)
-func stringMaptoArray(m map[string]string) []string {
- a := make([]string, 0, len(m))
- for k, v := range m {
- a = append(a, fmt.Sprintf("%s=%s", k, v))
- }
- return a
-}
-
-// ContainerCreateToContainerCLIOpts converts a compat input struct to cliopts so it can be converted to
-// a specgen spec.
-func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.ContainerCreateOptions, []string, error) {
- var (
- capAdd []string
- cappDrop []string
- entrypoint *string
- init bool
- specPorts []types.PortMapping
- )
-
- if cc.HostConfig.Init != nil {
- init = *cc.HostConfig.Init
- }
-
- // Iterate devices and convert back to string
- devices := make([]string, 0, len(cc.HostConfig.Devices))
- for _, dev := range cc.HostConfig.Devices {
- devices = append(devices, fmt.Sprintf("%s:%s:%s", dev.PathOnHost, dev.PathInContainer, dev.CgroupPermissions))
- }
-
- // iterate blkreaddevicebps
- readBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadBps))
- for _, dev := range cc.HostConfig.BlkioDeviceReadBps {
- readBps = append(readBps, dev.String())
- }
-
- // iterate blkreaddeviceiops
- readIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceReadIOps))
- for _, dev := range cc.HostConfig.BlkioDeviceReadIOps {
- readIops = append(readIops, dev.String())
- }
-
- // iterate blkwritedevicebps
- writeBps := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteBps))
- for _, dev := range cc.HostConfig.BlkioDeviceWriteBps {
- writeBps = append(writeBps, dev.String())
- }
-
- // iterate blkwritedeviceiops
- writeIops := make([]string, 0, len(cc.HostConfig.BlkioDeviceWriteIOps))
- for _, dev := range cc.HostConfig.BlkioDeviceWriteIOps {
- writeIops = append(writeIops, dev.String())
- }
-
- // entrypoint
- // can be a string or slice. if it is a slice, we need to
- // marshall it to json; otherwise it should just be the string
- // value
- if len(cc.Config.Entrypoint) > 0 {
- entrypoint = &cc.Config.Entrypoint[0]
- if len(cc.Config.Entrypoint) > 1 {
- b, err := json.Marshal(cc.Config.Entrypoint)
- if err != nil {
- return nil, nil, err
- }
- var jsonString = string(b)
- entrypoint = &jsonString
- }
- }
-
- // expose ports
- expose := make([]string, 0, len(cc.Config.ExposedPorts))
- for p := range cc.Config.ExposedPorts {
- expose = append(expose, fmt.Sprintf("%s/%s", p.Port(), p.Proto()))
- }
-
- // mounts type=tmpfs/bind,source=...,target=...=,opt=val
- volSources := make(map[string]bool)
- volDestinations := make(map[string]bool)
- mounts := make([]string, 0, len(cc.HostConfig.Mounts))
- var builder strings.Builder
- for _, m := range cc.HostConfig.Mounts {
- addField(&builder, "type", string(m.Type))
- addField(&builder, "source", m.Source)
- addField(&builder, "target", m.Target)
-
- // Store source/dest so we don't add duplicates if a volume is
- // also mentioned in cc.Volumes.
- // Which Docker Compose v2.0 does, for unclear reasons...
- volSources[m.Source] = true
- volDestinations[m.Target] = true
-
- if m.ReadOnly {
- addField(&builder, "ro", "true")
- }
- addField(&builder, "consistency", string(m.Consistency))
- // Map any specialized mount options that intersect between *Options and cli options
- switch m.Type {
- case mount.TypeBind:
- if m.BindOptions != nil {
- addField(&builder, "bind-propagation", string(m.BindOptions.Propagation))
- addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive))
- }
- case mount.TypeTmpfs:
- if m.TmpfsOptions != nil {
- addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10))
- addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 8))
- }
- case mount.TypeVolume:
- // All current VolumeOpts are handled above
- // See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts()
- }
- mounts = append(mounts, builder.String())
- builder.Reset()
- }
-
- // dns
- dns := make([]net.IP, 0, len(cc.HostConfig.DNS))
- for _, d := range cc.HostConfig.DNS {
- dns = append(dns, net.ParseIP(d))
- }
-
- // publish
- for port, pbs := range cc.HostConfig.PortBindings {
- for _, pb := range pbs {
- var hostport int
- var err error
- if pb.HostPort != "" {
- hostport, err = strconv.Atoi(pb.HostPort)
- }
- if err != nil {
- return nil, nil, err
- }
- tmpPort := types.PortMapping{
- HostIP: pb.HostIP,
- ContainerPort: uint16(port.Int()),
- HostPort: uint16(hostport),
- Range: 0,
- Protocol: port.Proto(),
- }
- specPorts = append(specPorts, tmpPort)
- }
- }
-
- // special case for NetworkMode, the podman default is slirp4netns for
- // rootless but for better docker compat we want bridge.
- netmode := string(cc.HostConfig.NetworkMode)
- if netmode == "" || netmode == "default" {
- netmode = "bridge"
- }
- nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{netmode})
- if err != nil {
- return nil, nil, err
- }
-
- // network
- // Note: we cannot emulate compat exactly here. we only allow specifics of networks to be
- // defined when there is only one network.
- netInfo := entities.NetOptions{
- AddHosts: cc.HostConfig.ExtraHosts,
- DNSOptions: cc.HostConfig.DNSOptions,
- DNSSearch: cc.HostConfig.DNSSearch,
- DNSServers: dns,
- Network: nsmode,
- PublishPorts: specPorts,
- NetworkOptions: netOpts,
- NoHosts: rtc.Containers.NoHosts,
- }
-
- // network names
- switch {
- case len(cc.NetworkingConfig.EndpointsConfig) > 0:
- endpointsConfig := cc.NetworkingConfig.EndpointsConfig
- networks := make(map[string]types.PerNetworkOptions, len(endpointsConfig))
- for netName, endpoint := range endpointsConfig {
- netOpts := types.PerNetworkOptions{}
- if endpoint != nil {
- netOpts.Aliases = endpoint.Aliases
-
- // if IP address is provided
- if len(endpoint.IPAddress) > 0 {
- staticIP := net.ParseIP(endpoint.IPAddress)
- if staticIP == nil {
- return nil, nil, errors.Errorf("failed to parse the ip address %q", endpoint.IPAddress)
- }
- netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
- }
-
- if endpoint.IPAMConfig != nil {
- // if IPAMConfig.IPv4Address is provided
- if len(endpoint.IPAMConfig.IPv4Address) > 0 {
- staticIP := net.ParseIP(endpoint.IPAMConfig.IPv4Address)
- if staticIP == nil {
- return nil, nil, errors.Errorf("failed to parse the ipv4 address %q", endpoint.IPAMConfig.IPv4Address)
- }
- netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
- }
- // if IPAMConfig.IPv6Address is provided
- if len(endpoint.IPAMConfig.IPv6Address) > 0 {
- staticIP := net.ParseIP(endpoint.IPAMConfig.IPv6Address)
- if staticIP == nil {
- return nil, nil, errors.Errorf("failed to parse the ipv6 address %q", endpoint.IPAMConfig.IPv6Address)
- }
- netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
- }
- }
- // If MAC address is provided
- if len(endpoint.MacAddress) > 0 {
- staticMac, err := net.ParseMAC(endpoint.MacAddress)
- if err != nil {
- return nil, nil, errors.Errorf("failed to parse the mac address %q", endpoint.MacAddress)
- }
- netOpts.StaticMAC = types.HardwareAddr(staticMac)
- }
- }
-
- networks[netName] = netOpts
- }
-
- netInfo.Networks = networks
- case len(cc.HostConfig.NetworkMode) > 0:
- netInfo.Networks = networks
- }
-
- parsedTmp := make([]string, 0, len(cc.HostConfig.Tmpfs))
- for path, options := range cc.HostConfig.Tmpfs {
- finalString := path
- if options != "" {
- finalString += ":" + options
- }
- parsedTmp = append(parsedTmp, finalString)
- }
-
- // Note: several options here are marked as "don't need". this is based
- // on speculation by Matt and I. We think that these come into play later
- // like with start. We believe this is just a difference in podman/compat
- cliOpts := entities.ContainerCreateOptions{
- // Attach: nil, // don't need?
- Authfile: "",
- CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
- CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
- CgroupParent: cc.HostConfig.CgroupParent,
- CIDFile: cc.HostConfig.ContainerIDFile,
- CPUPeriod: uint64(cc.HostConfig.CPUPeriod),
- CPUQuota: cc.HostConfig.CPUQuota,
- CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
- CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
- CPUShares: uint64(cc.HostConfig.CPUShares),
- // CPUS: 0, // don't need?
- CPUSetCPUs: cc.HostConfig.CpusetCpus,
- CPUSetMems: cc.HostConfig.CpusetMems,
- // Detach: false, // don't need
- // DetachKeys: "", // don't need
- Devices: devices,
- DeviceCgroupRule: nil,
- DeviceReadBPs: readBps,
- DeviceReadIOPs: readIops,
- DeviceWriteBPs: writeBps,
- DeviceWriteIOPs: writeIops,
- Entrypoint: entrypoint,
- Env: cc.Config.Env,
- Expose: expose,
- GroupAdd: cc.HostConfig.GroupAdd,
- Hostname: cc.Config.Hostname,
- ImageVolume: "bind",
- Init: init,
- Interactive: cc.Config.OpenStdin,
- IPC: string(cc.HostConfig.IpcMode),
- Label: stringMaptoArray(cc.Config.Labels),
- LogDriver: cc.HostConfig.LogConfig.Type,
- LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config),
- Name: cc.Name,
- OOMScoreAdj: &cc.HostConfig.OomScoreAdj,
- Arch: "",
- OS: "",
- Variant: "",
- PID: string(cc.HostConfig.PidMode),
- PIDsLimit: cc.HostConfig.PidsLimit,
- Privileged: cc.HostConfig.Privileged,
- PublishAll: cc.HostConfig.PublishAllPorts,
- Quiet: false,
- ReadOnly: cc.HostConfig.ReadonlyRootfs,
- ReadOnlyTmpFS: true, // podman default
- Rm: cc.HostConfig.AutoRemove,
- SecurityOpt: cc.HostConfig.SecurityOpt,
- StopSignal: cc.Config.StopSignal,
- StorageOpts: stringMaptoArray(cc.HostConfig.StorageOpt),
- Sysctl: stringMaptoArray(cc.HostConfig.Sysctls),
- Systemd: "true", // podman default
- TmpFS: parsedTmp,
- TTY: cc.Config.Tty,
- UnsetEnv: cc.UnsetEnv,
- UnsetEnvAll: cc.UnsetEnvAll,
- User: cc.Config.User,
- UserNS: string(cc.HostConfig.UsernsMode),
- UTS: string(cc.HostConfig.UTSMode),
- Mount: mounts,
- VolumesFrom: cc.HostConfig.VolumesFrom,
- Workdir: cc.Config.WorkingDir,
- Net: &netInfo,
- HealthInterval: define.DefaultHealthCheckInterval,
- HealthRetries: define.DefaultHealthCheckRetries,
- HealthTimeout: define.DefaultHealthCheckTimeout,
- HealthStartPeriod: define.DefaultHealthCheckStartPeriod,
- }
- if !rootless.IsRootless() {
- var ulimits []string
- if len(cc.HostConfig.Ulimits) > 0 {
- for _, ul := range cc.HostConfig.Ulimits {
- ulimits = append(ulimits, ul.String())
- }
- cliOpts.Ulimit = ulimits
- }
- }
- if cc.HostConfig.Resources.NanoCPUs > 0 {
- if cliOpts.CPUPeriod != 0 || cliOpts.CPUQuota != 0 {
- return nil, nil, errors.Errorf("NanoCpus conflicts with CpuPeriod and CpuQuota")
- }
- cliOpts.CPUPeriod = 100000
- cliOpts.CPUQuota = cc.HostConfig.Resources.NanoCPUs / 10000
- }
-
- // volumes
- for _, vol := range cc.HostConfig.Binds {
- cliOpts.Volume = append(cliOpts.Volume, vol)
- // Extract the destination so we don't add duplicate mounts in
- // the volumes phase.
- splitVol := specgen.SplitVolumeString(vol)
- switch len(splitVol) {
- case 1:
- volDestinations[vol] = true
- default:
- volSources[splitVol[0]] = true
- volDestinations[splitVol[1]] = true
- }
- }
- // Anonymous volumes are added differently from other volumes, in their
- // own special field, for reasons known only to Docker. Still use the
- // format of `-v` so we can just append them in there.
- // Unfortunately, these may be duplicates of existing mounts in Binds.
- // So... We need to catch that.
- // This also handles volumes duplicated between cc.HostConfig.Mounts and
- // cc.Volumes, as seen in compose v2.0.
- for vol := range cc.Volumes {
- if _, ok := volDestinations[filepath.Clean(vol)]; ok {
- continue
- }
- cliOpts.Volume = append(cliOpts.Volume, vol)
- }
- // Make mount points for compat volumes
- for vol := range volSources {
- // This might be a named volume.
- // Assume it is if it's not an absolute path.
- if !filepath.IsAbs(vol) {
- continue
- }
- // If volume already exists, there is nothing to do
- if _, err := os.Stat(vol); err == nil {
- continue
- }
- if err := os.MkdirAll(vol, 0755); err != nil {
- if !os.IsExist(err) {
- return nil, nil, errors.Wrapf(err, "error making volume mountpoint for volume %s", vol)
- }
- }
- }
- if len(cc.HostConfig.BlkioWeightDevice) > 0 {
- devices := make([]string, 0, len(cc.HostConfig.BlkioWeightDevice))
- for _, d := range cc.HostConfig.BlkioWeightDevice {
- devices = append(devices, d.String())
- }
- cliOpts.BlkIOWeightDevice = devices
- }
- if cc.HostConfig.BlkioWeight > 0 {
- cliOpts.BlkIOWeight = strconv.Itoa(int(cc.HostConfig.BlkioWeight))
- }
-
- if cc.HostConfig.Memory > 0 {
- cliOpts.Memory = strconv.Itoa(int(cc.HostConfig.Memory))
- }
-
- if cc.HostConfig.MemoryReservation > 0 {
- cliOpts.MemoryReservation = strconv.Itoa(int(cc.HostConfig.MemoryReservation))
- }
-
- cgroupsv2, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return nil, nil, err
- }
- if cc.HostConfig.MemorySwap > 0 && (!rootless.IsRootless() || (rootless.IsRootless() && cgroupsv2)) {
- cliOpts.MemorySwap = strconv.Itoa(int(cc.HostConfig.MemorySwap))
- }
-
- if cc.Config.StopTimeout != nil {
- cliOpts.StopTimeout = uint(*cc.Config.StopTimeout)
- }
-
- if cc.HostConfig.ShmSize > 0 {
- cliOpts.ShmSize = strconv.Itoa(int(cc.HostConfig.ShmSize))
- }
-
- if len(cc.HostConfig.RestartPolicy.Name) > 0 {
- policy := cc.HostConfig.RestartPolicy.Name
- // only add restart count on failure
- if cc.HostConfig.RestartPolicy.IsOnFailure() {
- policy += fmt.Sprintf(":%d", cc.HostConfig.RestartPolicy.MaximumRetryCount)
- }
- cliOpts.Restart = policy
- }
-
- if cc.HostConfig.MemorySwappiness != nil && (!rootless.IsRootless() || rootless.IsRootless() && cgroupsv2 && rtc.Engine.CgroupManager == "systemd") {
- cliOpts.MemorySwappiness = *cc.HostConfig.MemorySwappiness
- } else {
- cliOpts.MemorySwappiness = -1
- }
- if cc.HostConfig.OomKillDisable != nil {
- cliOpts.OOMKillDisable = *cc.HostConfig.OomKillDisable
- }
- if cc.Config.Healthcheck != nil {
- finCmd := ""
- for _, str := range cc.Config.Healthcheck.Test {
- finCmd = finCmd + str + " "
- }
- if len(finCmd) > 1 {
- finCmd = finCmd[:len(finCmd)-1]
- }
- cliOpts.HealthCmd = finCmd
- if cc.Config.Healthcheck.Interval > 0 {
- cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String()
- }
- if cc.Config.Healthcheck.Retries > 0 {
- cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries)
- }
- if cc.Config.Healthcheck.StartPeriod > 0 {
- cliOpts.HealthStartPeriod = cc.Config.Healthcheck.StartPeriod.String()
- }
- if cc.Config.Healthcheck.Timeout > 0 {
- cliOpts.HealthTimeout = cc.Config.Healthcheck.Timeout.String()
- }
- }
-
- // specgen assumes the image name is arg[0]
- cmd := []string{cc.Config.Image}
- cmd = append(cmd, cc.Config.Cmd...)
- return &cliOpts, cmd, nil
-}
-
func ulimits() []string {
if !registry.IsRemote() {
return containerConfig.Ulimits()
@@ -536,17 +73,3 @@ func LogDriver() string {
}
return ""
}
-
-// addField is a helper function to populate mount options
-func addField(b *strings.Builder, name string, value string) {
- if value == "" {
- return
- }
-
- if b.Len() > 0 {
- b.WriteRune(',')
- }
- b.WriteString(name)
- b.WriteRune('=')
- b.WriteString(value)
-}
diff --git a/cmd/podman/common/default.go b/cmd/podman/common/default.go
index 7caec50ff..6f78d3d29 100644
--- a/cmd/podman/common/default.go
+++ b/cmd/podman/common/default.go
@@ -5,9 +5,6 @@ import (
)
var (
-
- // DefaultImageVolume default value
- DefaultImageVolume = "bind"
// Pull in configured json library
json = registry.JSONLibrary()
)
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index c62ddd6eb..0a513c606 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -102,16 +102,25 @@ func init() {
createFlags(containerCreateCommand)
}
-func create(cmd *cobra.Command, args []string) error {
- var (
- err error
- )
+func commonFlags(cmd *cobra.Command) error {
+ var err error
flags := cmd.Flags()
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags)
if err != nil {
return err
}
+ if cmd.Flags().Changed("image-volume") {
+ cliVals.ImageVolume = cmd.Flag("image-volume").Value.String()
+ }
+ return nil
+}
+
+func create(cmd *cobra.Command, args []string) error {
+ if err := commonFlags(cmd); err != nil {
+ return err
+ }
+
// Check if initctr is used with --pod and the value is correct
if initctr := InitContainerType; cmd.Flags().Changed("init-ctr") {
if !cmd.Flags().Changed("pod") {
@@ -123,7 +132,7 @@ func create(cmd *cobra.Command, args []string) error {
cliVals.InitContainerType = initctr
}
- cliVals, err = CreateInit(cmd, cliVals, false)
+ cliVals, err := CreateInit(cmd, cliVals, false)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 951981293..a6c500afa 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -109,7 +109,9 @@ func init() {
}
func run(cmd *cobra.Command, args []string) error {
- var err error
+ if err := commonFlags(cmd); err != nil {
+ return err
+ }
// TODO: Breaking change should be made fatal in next major Release
if cliVals.TTY && cliVals.Interactive && !term.IsTerminal(int(os.Stdin.Fd())) {
@@ -122,14 +124,10 @@ func run(cmd *cobra.Command, args []string) error {
}
}
- flags := cmd.Flags()
- cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags)
- if err != nil {
- return err
- }
runOpts.CIDFile = cliVals.CIDFile
runOpts.Rm = cliVals.Rm
- if cliVals, err = CreateInit(cmd, cliVals, false); err != nil {
+ cliVals, err := CreateInit(cmd, cliVals, false)
+ if err != nil {
return err
}
diff --git a/cmd/podman/images/load.go b/cmd/podman/images/load.go
index dbb7c32fa..c18c32387 100644
--- a/cmd/podman/images/load.go
+++ b/cmd/podman/images/load.go
@@ -110,6 +110,6 @@ func load(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- fmt.Println("Loaded image(s): " + strings.Join(response.Names, ","))
+ fmt.Println("Loaded image: " + strings.Join(response.Names, "\nLoaded image: "))
return nil
}
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index 5254d50cf..bb14d4a67 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -48,6 +48,7 @@ type ListReporter struct {
Default bool
Created string
Running bool
+ Starting bool
LastUp string
Stream string
VMType string
@@ -224,10 +225,14 @@ func toHumanFormat(vms []*machine.ListResponse) ([]*ListReporter, error) {
} else {
response.Name = vm.Name
}
- if vm.Running {
+ switch {
+ case vm.Running:
response.LastUp = "Currently running"
response.Running = true
- } else {
+ case vm.Starting:
+ response.LastUp = "Currently starting"
+ response.Starting = true
+ default:
response.LastUp = units.HumanDuration(time.Since(vm.LastUp)) + " ago"
}
response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago"
diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go
index 4a86da67a..8261f3607 100644
--- a/cmd/podman/machine/ssh.go
+++ b/cmd/podman/machine/ssh.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/machine"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -89,7 +90,8 @@ func ssh(cmd *cobra.Command, args []string) error {
if err != nil {
return errors.Wrapf(err, "vm %s not found", vmName)
}
- return vm.SSH(vmName, sshOpts)
+ err = vm.SSH(vmName, sshOpts)
+ return utils.HandleOSExecError(err)
}
func remoteConnectionUsername() (string, error) {
diff --git a/cmd/podman/machine/start.go b/cmd/podman/machine/start.go
index c9b99e63b..3bd7f4a25 100644
--- a/cmd/podman/machine/start.go
+++ b/cmd/podman/machine/start.go
@@ -56,7 +56,7 @@ func start(_ *cobra.Command, args []string) error {
if vmName == activeName {
return errors.Wrapf(machine.ErrVMAlreadyRunning, "cannot start VM %s", vmName)
}
- return errors.Wrapf(machine.ErrMultipleActiveVM, "cannot start VM %s. VM %s is currently running", vmName, activeName)
+ return errors.Wrapf(machine.ErrMultipleActiveVM, "cannot start VM %s. VM %s is currently running or starting", vmName, activeName)
}
fmt.Printf("Starting machine %q\n", vmName)
if err := vm.Start(vmName, machine.StartOptions{}); err != nil {
diff --git a/cmd/podman/system/reset.go b/cmd/podman/system/reset.go
index 176573bf6..20f15a34f 100644
--- a/cmd/podman/system/reset.go
+++ b/cmd/podman/system/reset.go
@@ -91,18 +91,10 @@ func reset(cmd *cobra.Command, args []string) {
registry.ContainerEngine().Shutdown(registry.Context())
registry.ImageEngine().Shutdown(registry.Context())
- engine, err := infra.NewSystemEngine(entities.ResetMode, registry.PodmanConfig())
- if err != nil {
- logrus.Error(err)
- os.Exit(define.ExecErrorCodeGeneric)
- }
- defer engine.Shutdown(registry.Context())
-
- if err := engine.Reset(registry.Context()); err != nil {
+ // Do not try to shut the engine down, as a Reset engine is not valid
+ // after its creation.
+ if _, err := infra.NewSystemEngine(entities.ResetMode, registry.PodmanConfig()); err != nil {
logrus.Error(err)
- // FIXME change this to return the error like other commands
- // defer will never run on os.Exit()
- //nolint:gocritic
os.Exit(define.ExecErrorCodeGeneric)
}
diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go
index 0ae5b81ad..1ed08eac3 100644
--- a/cmd/podman/system/unshare.go
+++ b/cmd/podman/system/unshare.go
@@ -2,10 +2,10 @@ package system
import (
"os"
- "os/exec"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/pkg/errors"
@@ -60,22 +60,5 @@ func unshare(cmd *cobra.Command, args []string) error {
}
err := registry.ContainerEngine().Unshare(registry.Context(), args, unshareOptions)
- if err != nil {
- if exitError, ok := err.(*exec.ExitError); ok {
- // the user command inside the unshare env has failed
- // we set the exit code, do not return the error to the user
- // otherwise "exit status X" will be printed
- registry.SetExitCode(exitError.ExitCode())
- return nil
- }
- // cmd.Run() can return fs.ErrNotExist, fs.ErrPermission or exec.ErrNotFound
- // follow podman run/exec standard with the exit codes
- if errors.Is(err, os.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
- registry.SetExitCode(127)
- } else if errors.Is(err, os.ErrPermission) {
- registry.SetExitCode(126)
- }
- return err
- }
- return nil
+ return utils.HandleOSExecError(err)
}
diff --git a/cmd/podman/utils/error.go b/cmd/podman/utils/error.go
index 2aaa71373..3efff0301 100644
--- a/cmd/podman/utils/error.go
+++ b/cmd/podman/utils/error.go
@@ -4,10 +4,12 @@ import (
"errors"
"fmt"
"os"
+ "os/exec"
"strconv"
"strings"
buildahCLI "github.com/containers/buildah/pkg/cli"
+ "github.com/containers/podman/v4/cmd/podman/registry"
)
type OutputErrors []error
@@ -43,3 +45,33 @@ func ExitCodeFromBuildError(errorMsg string) (int, error) {
}
return buildahCLI.ExecErrorCodeGeneric, errors.New("message does not contains a valid exit code")
}
+
+// HandleOSExecError checks the given error for an exec.ExitError error and
+// sets the same podman exit code as the error.
+// No error will be returned in this case to make sure things like podman
+// unshare false work correctly without extra output.
+// When the exec file does not exists we set the exit code to 127, for
+// permission errors 126 is used as exit code. In this case we still return
+// the error so the user gets an error message.
+// If the error is nil it returns nil.
+func HandleOSExecError(err error) error {
+ if err == nil {
+ return nil
+ }
+ var exitError *exec.ExitError
+ if errors.As(err, &exitError) {
+ // the user command inside the unshare/ssh env has failed
+ // we set the exit code, do not return the error to the user
+ // otherwise "exit status X" will be printed
+ registry.SetExitCode(exitError.ExitCode())
+ return nil
+ }
+ // cmd.Run() can return fs.ErrNotExist, fs.ErrPermission or exec.ErrNotFound
+ // follow podman run/exec standard with the exit codes
+ if errors.Is(err, os.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
+ registry.SetExitCode(127)
+ } else if errors.Is(err, os.ErrPermission) {
+ registry.SetExitCode(126)
+ }
+ return err
+}
diff --git a/cmd/podman/utils/signals_linux.go b/cmd/podman/utils/signals_linux.go
deleted file mode 100644
index dd0507c0e..000000000
--- a/cmd/podman/utils/signals_linux.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package utils
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-// Platform specific signal synonyms
-var (
- SIGHUP os.Signal = unix.SIGHUP
-)
diff --git a/cmd/podman/utils/signals_windows.go b/cmd/podman/utils/signals_windows.go
deleted file mode 100644
index e6fcc1b32..000000000
--- a/cmd/podman/utils/signals_windows.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build windows
-// +build windows
-
-package utils
-
-import (
- "os"
-
- "golang.org/x/sys/windows"
-)
-
-// Platform specific signal synonyms
-var (
- SIGHUP os.Signal = windows.SIGHUP
-)
diff --git a/cmd/podman/volumes/export.go b/cmd/podman/volumes/export.go
index 5086323f9..113f79a0b 100644
--- a/cmd/podman/volumes/export.go
+++ b/cmd/podman/volumes/export.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/utils"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -58,10 +59,13 @@ func export(cmd *cobra.Command, args []string) error {
return errors.New("expects output path, use --output=[path]")
}
inspectOpts.Type = common.VolumeType
- volumeData, _, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
+ volumeData, errs, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
if err != nil {
return err
}
+ if len(errs) > 0 {
+ return errorhandling.JoinErrors(errs)
+ }
if len(volumeData) < 1 {
return errors.New("no volume data found")
}
diff --git a/cmd/podman/volumes/import.go b/cmd/podman/volumes/import.go
index 988c5536d..76a311643 100644
--- a/cmd/podman/volumes/import.go
+++ b/cmd/podman/volumes/import.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/utils"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -60,10 +61,14 @@ func importVol(cmd *cobra.Command, args []string) error {
}
inspectOpts.Type = common.VolumeType
- volumeData, _, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
+ inspectOpts.Type = common.VolumeType
+ volumeData, errs, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
if err != nil {
return err
}
+ if len(errs) > 0 {
+ return errorhandling.JoinErrors(errs)
+ }
if len(volumeData) < 1 {
return errors.New("no volume data found")
}
diff --git a/contrib/cirrus/CIModes.md b/contrib/cirrus/CIModes.md
new file mode 100644
index 000000000..8b1e33bb1
--- /dev/null
+++ b/contrib/cirrus/CIModes.md
@@ -0,0 +1,129 @@
+The following is a list (incomplete) of the primary contexts and runtime
+"modes" supported by podman CI. Note that there may be additional checks
+done regarding "skipping work" in the `runner.sh` script. This document
+only details the controls at the `.cirrus.yml` level.
+
+## Visualization
+
+The relationship between tasks can be incredibly hard to understand by
+staring at the YAML.
+[A tool exists](https://github.com/containers/automation/tree/main/cirrus-task-map)
+for producing a graph (flow-chart) of the `.cirrus.yml` file. A (possibly
+outdated) example of it's output can be seen below:
+
+![cirrus-task-map output](https://github.com/containers/podman/wiki/cirrus-map.svg)
+
+## Implementation notes
+
++ The `skip` conditional should never be used for tasks.
+ While it's arguably easier to read that `only_if`, it leads to a cluttered
+ status output that's harder to page through when reviewing PRs. As opposed
+ to `only_if` which will bypass creation of the task (at runtime) completely.
+ Also, by sticking to one conditional style, it's easer to re-use the YAML
+ statements across multiple tasks.
+
++ The only variables which can be used as part of conditions are defined by
+ Cirrus-CI.
+ [The list is documented](https://cirrus-ci.org/guide/writing-tasks/#environment-variables). Reference to any variables defined in YAML will **not** behave how
+ you expect, don't use them!
+
+* Somme Cirrus-CI defined variables contain non-empty values outside their
+ obvious context. For example, when running for a PR a task will have
+ `$CIRRUS_BRANCH` set to `pull/<number>`.
+
+* Conditions which use positive or negative regular-expressions have several
+ "flags" set: "Multi-line" and "Case-insensitive".
+
+## Testing
+
+Executing most of the modes can be mocked by forcing values for (otherwise)
+Cirrus-CI defined variables. For example `$CIRRUS_TAG`. As of the publishing
+of this document, it's not possible to override the behavior of `$CIRRUS_PR`.
+
+## Cirrus Task contexts and runtime modes
+
+### Intended general PR Tasks (*italic*: matrix)
++ ext_svc_check
++ automation
++ *build*
++ validate
++ bindings
++ swagger
++ consistency
++ *alt_build*
++ osx_alt_build
++ docker-py_test
++ *unit_test*
++ apiv2_test
++ *compose_test*
++ *local_integration_test*
++ *remote_integration_test*
++ *container_integration_test*
++ *rootless_integration_test*
++ *local_system_test*
++ *remote_system_test*
++ *rootless_remote_system_test*
++ *buildah_bud_test*
++ *rootless_system_test*
++ rootless_gitlab_test
++ *upgrade_test*
++ meta
++ success
++ artifacts
+
+### Intended for PR w/ "release" or "bump" in title:
++ (All the general PR tasks above)
++ release_test
+
+### Intended `[CI:DOCS]` PR Tasks:
++ ext_svc_check
++ automation
++ *build*
++ validate
++ swagger
++ consistency
++ meta
++ success
+
+### Intend `[CI:BUILD]` PR Tasks:
++ ext_svc_check
++ automation
++ *build*
++ validate
++ consistency
++ *alt_build*
++ osx_alt_build
++ test_image_build
++ meta
++ success
++ artifacts
+
+### Intended Branch tasks (and Cirrus-cron jobs, except "multiarch"):
++ ext_svc_check
++ *build*
++ swagger
++ *alt_build*
++ osx_alt_build
++ *local_system_test*
++ *remote_system_test*
++ *rootless_remote_system_test*
++ *rootless_system_test*
++ meta
++ success
++ artifacts
+
+### Intended for "multiarch" Cirrus-Cron (always a branch):
++ ext_svc_check
++ image_build
++ meta
++ success
+
+### Intended for new Tag tasks:
++ *build*
++ swagger
++ *alt_build*
++ osx_alt_build
++ meta
++ success
++ artifacts
++ release
diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh
index c871f1f54..b9f43f395 100755
--- a/contrib/cirrus/runner.sh
+++ b/contrib/cirrus/runner.sh
@@ -312,6 +312,11 @@ function _run_release() {
if [[ -n "$dev" ]]; then
die "Releases must never contain '-dev' in output of 'podman info' ($dev)"
fi
+
+ commit=$(bin/podman info --format='{{.Version.GitCommit}}' | tr -d '[:space:]')
+ if [[ -z "$commit" ]]; then
+ die "Releases must contain a non-empty Version.GitCommit in 'podman info'"
+ fi
msg "All OK"
}
diff --git a/contrib/podmanimage/README.md b/contrib/podmanimage/README.md
index 4f184ca28..b4ef81d84 100644
--- a/contrib/podmanimage/README.md
+++ b/contrib/podmanimage/README.md
@@ -4,7 +4,7 @@
## Overview
-This directory contains the Dockerfiles necessary to create the podmanimage container
+This directory contains the Containerfiles necessary to create the podmanimage container
images that are housed on quay.io under the Podman account. All repositories where
the images live are public and can be pulled without credentials. These container images are secured and the
resulting containers can run safely with privileges within the container.
@@ -21,18 +21,18 @@ The container images are:
and stable version of podman. For the most recent `<version>` tags (`vX`,
`vX.Y`, and `vX.Y.Z`) the image contents will be updated daily to incorporate
(especially) security upgrades. For build details, please [see the
- configuration file](stable/Dockerfile).
+ configuration file](stable/Containerfile).
* `quay.io/containers/podman:latest` and `quay.io/podman/stable:latest` -
- Built daily using the same Dockerfile as above. The Podman version
+ Built daily using the same Containerfile as above. The Podman version
will remain the "latest" available in Fedora, however the other image
contents may vary compared to the version-tagged images.
* `quay.io/podman/testing:latest` - This image is built daily, using the
latest version of Podman that was in the Fedora `updates-testing` repository.
- The image is Built with [the testing Dockerfile](testing/Dockerfile).
+ The image is Built with [the testing Containerfile](testing/Containerfile).
* `quay.io/podman/upstream:latest` - This image is built daily using the latest
code found in this GitHub repository. Due to the image changing frequently,
it's not guaranteed to be stable or even executable. The image is built with
- [the upstream Dockerfile](upstream/Dockerfile).
+ [the upstream Containerfile](upstream/Containerfile).
## Sample Usage
diff --git a/contrib/podmanimage/stable/Containerfile b/contrib/podmanimage/stable/Containerfile
new file mode 100644
index 000000000..9121c5cde
--- /dev/null
+++ b/contrib/podmanimage/stable/Containerfile
@@ -0,0 +1,55 @@
+# stable/Containerfile
+#
+# Build a Podman container image from the latest
+# stable version of Podman on the Fedoras Updates System.
+# https://bodhi.fedoraproject.org/updates/?search=podman
+# This image can be used to create a secured container
+# that runs safely with privileges within the container.
+#
+FROM registry.fedoraproject.org/fedora:latest
+
+# Don't include container-selinux and remove
+# directories used by dnf that are just taking
+# up space.
+RUN dnf -y update && \
+ rpm --setcaps shadow-utils 2>/dev/null && \
+ dnf -y install podman fuse-overlayfs \
+ --exclude container-selinux && \
+ dnf clean all && \
+ rm -rf /var/cache /var/log/dnf* /var/log/yum.*
+
+RUN useradd podman; \
+echo -e "podman:1:999\npodman:1001:64535" > /etc/subuid; \
+echo -e "podman:1:999\npodman:1001:64535" > /etc/subgid;
+
+ARG _REPO_URL="https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable"
+ADD $_REPO_URL/containers.conf /etc/containers/containers.conf
+ADD $_REPO_URL/podman-containers.conf /home/podman/.config/containers/containers.conf
+
+RUN mkdir -p /home/podman/.local/share/containers && \
+ chown podman:podman -R /home/podman && \
+ chmod 644 /etc/containers/containers.conf
+
+# Copy & modify the defaults to provide reference if runtime changes needed.
+# Changes here are required for running with fuse-overlay storage inside container.
+RUN sed -e 's|^#mount_program|mount_program|g' \
+ -e '/additionalimage.*/a "/var/lib/shared",' \
+ -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
+ /usr/share/containers/storage.conf \
+ > /etc/containers/storage.conf
+
+# Note VOLUME options must always happen after the chown call above
+# RUN commands can not modify existing volumes
+VOLUME /var/lib/containers
+VOLUME /home/podman/.local/share/containers
+
+RUN mkdir -p /var/lib/shared/overlay-images \
+ /var/lib/shared/overlay-layers \
+ /var/lib/shared/vfs-images \
+ /var/lib/shared/vfs-layers && \
+ touch /var/lib/shared/overlay-images/images.lock && \
+ touch /var/lib/shared/overlay-layers/layers.lock && \
+ touch /var/lib/shared/vfs-images/images.lock && \
+ touch /var/lib/shared/vfs-layers/layers.lock
+
+ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/stable/Dockerfile b/contrib/podmanimage/stable/Dockerfile
deleted file mode 100644
index 78d820458..000000000
--- a/contrib/podmanimage/stable/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-# stable/Dockerfile
-#
-# Build a Podman container image from the latest
-# stable version of Podman on the Fedoras Updates System.
-# https://bodhi.fedoraproject.org/updates/?search=podman
-# This image can be used to create a secured container
-# that runs safely with privileges within the container.
-#
-FROM registry.fedoraproject.org/fedora:latest
-
-# Don't include container-selinux and remove
-# directories used by yum that are just taking
-# up space.
-RUN dnf -y update; rpm --restore shadow-utils 2>/dev/null; \
-yum -y install podman fuse-overlayfs --exclude container-selinux; \
-rm -rf /var/cache /var/log/dnf* /var/log/yum.*
-
-RUN useradd podman; \
-echo -e "podman:1:999\npodman:1001:64535" > /etc/subuid; \
-echo -e "podman:1:999\npodman:1001:64535" > /etc/subgid;
-
-ADD https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
-ADD https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
-
-RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman
-
-# Note VOLUME options must always happen after the chown call above
-# RUN commands can not modify existing volumes
-VOLUME /var/lib/containers
-VOLUME /home/podman/.local/share/containers
-
-# chmod containers.conf and adjust storage.conf to enable Fuse storage.
-RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
-RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers /var/lib/shared/vfs-images /var/lib/shared/vfs-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock; touch /var/lib/shared/vfs-images/images.lock; touch /var/lib/shared/vfs-layers/layers.lock
-
-ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/testing/Containerfile b/contrib/podmanimage/testing/Containerfile
new file mode 100644
index 000000000..16314a633
--- /dev/null
+++ b/contrib/podmanimage/testing/Containerfile
@@ -0,0 +1,60 @@
+# testing/Containerfile
+#
+# Build a Podman container image from the latest
+# stable version of Podman on the Fedoras Updates System.
+# https://bodhi.fedoraproject.org/updates/?search=podman
+# This image can be used to create a secured container
+# that runs safely with privileges within the container.
+#
+FROM registry.fedoraproject.org/fedora:latest
+
+# Don't include container-selinux and remove
+# directories used by dnf that are just taking
+# up space.
+RUN dnf -y update && \
+ rpm --setcaps shadow-utils 2>/dev/null && \
+ dnf -y install podman fuse-overlayfs \
+ --exclude container-selinux --enablerepo updates-testing && \
+ dnf clean all && \
+ rm -rf /var/cache /var/log/dnf* /var/log/yum.*
+
+RUN useradd podman; \
+echo -e "podman:1:999\npodman:1001:64535" > /etc/subuid; \
+echo -e "podman:1:999\npodman:1001:64535" > /etc/subgid;
+
+ARG _REPO_URL="https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable"
+ADD $_REPO_URL/containers.conf /etc/containers/containers.conf
+ADD $_REPO_URL/podman-containers.conf /home/podman/.config/containers/containers.conf
+
+RUN mkdir -p /home/podman/.local/share/containers && \
+ chown podman:podman -R /home/podman
+
+# Copy & modify the defaults to provide reference if runtime changes needed.
+# Changes here are required for running with fuse-overlay storage inside container.
+RUN sed -e 's|^#mount_program|mount_program|g' \
+ -e '/additionalimage.*/a "/var/lib/shared",' \
+ -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
+ /usr/share/containers/storage.conf \
+ > /etc/containers/storage.conf
+
+# Note VOLUME options must always happen after the chown call above
+# RUN commands can not modify existing volumes
+VOLUME /var/lib/containers
+VOLUME /home/podman/.local/share/containers
+
+# chmod containers.conf and adjust storage.conf to enable Fuse storage.
+RUN chmod 644 /etc/containers/containers.conf && \
+ sed -i -e 's|^#mount_program|mount_program|g' \
+ -e '/additionalimage.*/a "/var/lib/shared",' \
+ -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
+ /etc/containers/storage.conf
+RUN mkdir -p /var/lib/shared/overlay-images \
+ /var/lib/shared/overlay-layers \
+ /var/lib/shared/vfs-images \
+ /var/lib/shared/vfs-layers && \
+ touch /var/lib/shared/overlay-images/images.lock && \
+ touch /var/lib/shared/overlay-layers/layers.lock && \
+ touch /var/lib/shared/vfs-images/images.lock && \
+ touch /var/lib/shared/vfs-layers/layers.lock
+
+ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/testing/Dockerfile b/contrib/podmanimage/testing/Dockerfile
deleted file mode 100644
index 41af1c849..000000000
--- a/contrib/podmanimage/testing/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-# testing/Dockerfile
-#
-# Build a Podman image using the latest
-# version of Podman that is in updates-testing
-# on the Fedoras Updates System. At times this
-# may be the same the latest stable version.
-# https://bodhi.fedoraproject.org/updates/?search=podman
-# This image can be used to create a secured container
-# that runs safely with privileges within the container.
-#
-FROM registry.fedoraproject.org/fedora:latest
-
-# Don't include container-selinux and remove
-# directories used by yum that are just taking
-# up space.
-RUN yum -y update; rpm --restore shadow-utils 2>/dev/null; yum -y install podman fuse-overlayfs --exclude container-selinux --enablerepo updates-testing; rm -rf /var/cache /var/log/dnf* /var/log/yum.*
-
-RUN useradd podman; \
-echo -e "podman:1:999\npodman:1001:64535" > /etc/subuid; \
-echo -e "podman:1:999\npodman:1001:64535" > /etc/subgid;
-
-ADD https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
-ADD https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
-
-RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman
-
-# Note VOLUME options must always happen after the chown call above
-# RUN commands can not modify existing volumes
-VOLUME /var/lib/containers
-VOLUME /home/podman/.local/share/containers
-
-# chmod containers.conf and adjust storage.conf to enable Fuse storage.
-RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
-RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers /var/lib/shared/vfs-images /var/lib/shared/vfs-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock; touch /var/lib/shared/vfs-images/images.lock; touch /var/lib/shared/vfs-layers/layers.lock
-
-ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/upstream/Containerfile b/contrib/podmanimage/upstream/Containerfile
new file mode 100644
index 000000000..c3a07a8d6
--- /dev/null
+++ b/contrib/podmanimage/upstream/Containerfile
@@ -0,0 +1,61 @@
+# upstream/Containerfile
+#
+# Build a Podman container image from the latest
+# upstream version of Podman on GitHub.
+# https://github.com/containers/podman
+# This image can be used to create a secured container
+# that runs safely with privileges within the container.
+# The containers created by this image also come with a
+# Podman development environment in /root/podman.
+#
+FROM registry.fedoraproject.org/fedora:latest
+
+# Don't include container-selinux and remove
+# directories used by dnf that are just taking
+# up space. The latest podman + deps. come from
+# https://copr.fedorainfracloud.org/coprs/rhcontainerbot/podman-next/
+RUN dnf -y update && \
+ rpm --setcaps shadow-utils 2>/dev/null && \
+ dnf -y install 'dnf-command(copr)' --enablerepo=updates-testing && \
+ dnf -y copr enable rhcontainerbot/podman-next && \
+ dnf -y install podman fuse-overlayfs \
+ --exclude container-selinux \
+ --enablerepo=updates-testing && \
+ dnf clean all && \
+ rm -rf /var/cache /var/log/dnf* /var/log/yum.*
+
+RUN useradd podman; \
+echo -e "podman:1:999\npodman:1001:64535" > /etc/subuid; \
+echo -e "podman:1:999\npodman:1001:64535" > /etc/subgid;
+
+ARG _REPO_URL="https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable"
+ADD $_REPO_URL/containers.conf /etc/containers/containers.conf
+ADD $_REPO_URL/podman-containers.conf /home/podman/.config/containers/containers.conf
+
+RUN mkdir -p /home/podman/.local/share/containers && \
+ chown podman:podman -R /home/podman && \
+ chmod 644 /etc/containers/containers.conf
+
+# Copy & modify the defaults to provide reference if runtime changes needed.
+# Changes here are required for running with fuse-overlay storage inside container.
+RUN sed -e 's|^#mount_program|mount_program|g' \
+ -e '/additionalimage.*/a "/var/lib/shared",' \
+ -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
+ /usr/share/containers/storage.conf \
+ > /etc/containers/storage.conf
+
+# Note VOLUME options must always happen after the chown call above
+# RUN commands can not modify existing volumes
+VOLUME /var/lib/containers
+VOLUME /home/podman/.local/share/containers
+
+RUN mkdir -p /var/lib/shared/overlay-images \
+ /var/lib/shared/overlay-layers \
+ /var/lib/shared/vfs-images \
+ /var/lib/shared/vfs-layers && \
+ touch /var/lib/shared/overlay-images/images.lock && \
+ touch /var/lib/shared/overlay-layers/layers.lock && \
+ touch /var/lib/shared/vfs-images/images.lock && \
+ touch /var/lib/shared/vfs-layers/layers.lock
+
+ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile
deleted file mode 100644
index 0769a7612..000000000
--- a/contrib/podmanimage/upstream/Dockerfile
+++ /dev/null
@@ -1,85 +0,0 @@
-# git/Dockerfile
-#
-# Build a Podman container image from the latest
-# upstream version of Podman on GitHub.
-# https://github.com/containers/podman
-# This image can be used to create a secured container
-# that runs safely with privileges within the container.
-# The containers created by this image also come with a
-# Podman development environment in /root/podman.
-#
-FROM registry.fedoraproject.org/fedora:latest
-ENV GOPATH=/root/podman
-
-# Install the software required to build Podman.
-# Then create a directory and clone from the Podman
-# GitHub repository, make and install Podman
-# to the container.
-# Finally remove the podman directory and a few other packages
-# that are needed for building but not running Podman
-RUN yum -y update; rpm --restore shadow-utils 2>/dev/null; yum -y install --exclude container-selinux \
- --enablerepo=updates-testing \
- btrfs-progs-devel \
- containernetworking-cni \
- conmon \
- device-mapper-devel \
- git \
- glib2-devel \
- glibc-devel \
- glibc-static \
- go \
- golang-github-cpuguy83-md2man \
- gpgme-devel \
- iptables \
- libassuan-devel \
- libgpg-error-devel \
- libseccomp-devel \
- libselinux-devel \
- make \
- pkgconfig \
- crun \
- fuse-overlayfs \
- fuse3 \
- containers-common \
- podman-plugins; \
- mkdir /root/podman; \
- git clone https://github.com/containers/podman /root/podman/src/github.com/containers/podman; \
- cd /root/podman/src/github.com/containers/podman; \
- make BUILDTAGS="selinux seccomp"; \
- make install PREFIX=/usr; \
- cd /root/podman; \
- git clone https://github.com/containers/conmon /root/podman/conmon; \
- cd conmon; \
- make; \
- install -D -m 755 bin/conmon /usr/libexec/podman/conmon; \
- git clone https://github.com/containernetworking/plugins.git $GOPATH/src/github.com/containernetworking/plugins; \
- cd $GOPATH/src/github.com/containernetworking/plugins; \
- ./build_linux.sh; \
- mkdir -p /usr/libexec/cni; \
- \cp -fR bin/* /usr/libexec/cni; \
- mkdir -p /etc/cni/net.d; \
- curl -qsSL https://raw.githubusercontent.com/containers/podman/main/cni/87-podman-bridge.conflist | tee /etc/cni/net.d/99-loopback.conf; \
- mkdir -p /usr/share/containers; \
- rm -rf /root/podman/*; \
- yum -y remove git golang go-md2man make; \
- yum clean all;
-
-RUN useradd podman; \
-echo -e "podman:1:999\npodman:1001:64535" > /etc/subuid; \
-echo -e "podman:1:999\npodman:1001:64535" > /etc/subgid;
-
-ADD https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf
-ADD https://raw.githubusercontent.com/containers/podman/main/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf
-
-RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman
-
-# Note VOLUME options must always happen after the chown call above
-# RUN commands can not modify existing volumes
-VOLUME /var/lib/containers
-VOLUME /home/podman/.local/share/containers
-
-# chmod containers.conf and adjust storage.conf to enable Fuse storage.
-RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf
-RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers /var/lib/shared/vfs-images /var/lib/shared/vfs-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock; touch /var/lib/shared/vfs-images/images.lock; touch /var/lib/shared/vfs-layers/layers.lock
-
-ENV _CONTAINERS_USERNS_CONFIGURED=""
diff --git a/contrib/systemd/system/podman-restart.service.in b/contrib/systemd/system/podman-restart.service.in
index 1f13e57e1..de0249381 100644
--- a/contrib/systemd/system/podman-restart.service.in
+++ b/contrib/systemd/system/podman-restart.service.in
@@ -2,12 +2,15 @@
Description=Podman Start All Containers With Restart Policy Set To Always
Documentation=man:podman-start(1)
StartLimitIntervalSec=0
+Wants=network-online.target
+After=network-online.target
[Service]
Type=oneshot
RemainAfterExit=true
Environment=LOGGING="--log-level=info"
ExecStart=@@PODMAN@@ $LOGGING start --all --filter restart-policy=always
+ExecStop=/bin/sh -c '@@PODMAN@@ $LOGGING stop $(@@PODMAN@@ container ls --filter restart-policy=always -q)'
[Install]
WantedBy=default.target
diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md
index 358441add..25c0121f8 100644
--- a/docs/source/markdown/podman-build.1.md
+++ b/docs/source/markdown/podman-build.1.md
@@ -99,7 +99,7 @@ different stages in COPY instruction.
Valid values could be:
-* Local directory – e.g. --build-context project2=../path/to/project2/src
+* Local directory – e.g. --build-context project2=../path/to/project2/src (This option is not available with the remote Podman client. On Podman machine setup (i.e macOS and Winows) path must exists on the machine VM)
* HTTP URL to a tarball – e.g. --build-context src=https://example.org/releases/src.tar
* Container image – specified with a container-image:// prefix, e.g. --build-context alpine=container-image://alpine:3.15, (also accepts docker://, docker-image://)
@@ -435,8 +435,8 @@ if it does not exist. This option is useful for building multi architecture imag
#### **--memory**, **-m**=*LIMIT*
-Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes),
-m (megabytes), or g (gigabytes))
+Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes),
+m (mebibytes), or g (gibibytes))
Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
@@ -453,7 +453,7 @@ A limit value equal to memory plus swap. Must be used with the **-m**
the value of --memory.
The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
-`k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a
+`k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
#### **--network**=*mode*, **--net**
@@ -631,8 +631,8 @@ as a seccomp filter
Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater
than `0`.
-Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or
-`g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the
+Unit is optional and can be `b` (bytes), `k` (kibibytes), `m`(mebibytes), or
+`g` (gibibytes). If you omit the unit, the system uses bytes. If you omit the
size entirely, the system uses `64m`.
#### **--sign-by**=*fingerprint*
diff --git a/docs/source/markdown/podman-container-clone.1.md b/docs/source/markdown/podman-container-clone.1.md
index 69423113d..6d552db75 100644
--- a/docs/source/markdown/podman-container-clone.1.md
+++ b/docs/source/markdown/podman-container-clone.1.md
@@ -131,7 +131,7 @@ Force removal of the original container that we are cloning. Can only be used in
#### **--memory**, **-m**=*limit*
-Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))
+Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
Allows the memory available to a container to be constrained. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
@@ -143,7 +143,7 @@ If no memory limits are specified, the original container's will be used.
#### **--memory-reservation**=*limit*
-Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))
+Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
@@ -159,7 +159,7 @@ A limit value equal to memory plus swap. Must be used with the **-m**
the value of --memory if specified. Otherwise, the container being cloned will be used to derive the swap value.
The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
-`k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a
+`k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
#### **--memory-swappiness**=*number*
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 2da902844..f464acde0 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -573,7 +573,7 @@ To specify multiple static MAC addresses per container, set multiple networks us
#### **--memory**, **-m**=*limit*
-Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))
+Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
@@ -583,7 +583,7 @@ system's page size (the value would be very large, that's millions of trillions)
#### **--memory-reservation**=*limit*
-Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))
+Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
@@ -599,7 +599,7 @@ A limit value equal to memory plus swap. Must be used with the **-m**
the value of --memory.
The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
-`k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a
+`k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
#### **--memory-swappiness**=*number*
@@ -826,22 +826,27 @@ container.
Rootless containers cannot have more privileges than the account that launched them.
-#### **--publish**, **-p**=*port*
+#### **--publish**, **-p**=[[_ip_:][_hostPort_]:]_containerPort_[/_protocol_]
-Publish a container's port, or range of ports, to the host
+Publish a container's port, or range of ports, to the host.
-Format: `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort`
Both hostPort and containerPort can be specified as a range of ports.
-When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range.
-(e.g., `podman run -p 1234-1236:1222-1224 --name thisWorks -t busybox`
-but not `podman run -p 1230-1236:1230-1240 --name RangeContainerPortsBiggerThanRangeHostPorts -t busybox`)
-With host IP: `podman run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage`
+When specifying ranges for both, the number of container ports in the
+range must match the number of host ports in the range.
+
If host IP is set to 0.0.0.0 or not set at all, the port will be bound on all IPs on the host.
+
+By default, Podman will publish TCP ports. To publish a UDP port instead, give
+`udp` as protocol. To publish both TCP and UDP ports, set `--publish` twice,
+with `tcp`, and `udp` as protocols respectively. Rootful containers can also
+publish ports using the `sctp` protocol.
+
Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
If it is not, the container port will be randomly assigned a port on the host.
-Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPORT`
-**Note:** if a container will be run within a pod, it is not necessary to publish the port for
+Use **podman port** to see the actual mapping: `podman port $CONTAINER $CONTAINERPORT`.
+
+**Note:** If a container will be run within a pod, it is not necessary to publish the port for
the containers in the pod. The port must only be published by the pod itself. Pod network
stacks act like the network stack on the host - you have a variety of containers in the pod,
and programs in the container, all sharing a single interface and IP address, and
@@ -1008,7 +1013,7 @@ Note: Labeling can be disabled for all containers by setting label=false in the
#### **--shm-size**=*size*
-Size of `/dev/shm` (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))
+Size of `/dev/shm` (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
When size is `0`, there is no limit on the amount of memory used for IPC by the container.
@@ -1256,9 +1261,9 @@ Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinat
**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).
-**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is ignored for containers created by the root user.
+**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
-**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is ignored for containers created by the root user.
+**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
**ns:**_namespace_: run the container in the given existing user namespace.
diff --git a/docs/source/markdown/podman-image-scp.1.md b/docs/source/markdown/podman-image-scp.1.md
index 1d902da91..b6b610a7d 100644
--- a/docs/source/markdown/podman-image-scp.1.md
+++ b/docs/source/markdown/podman-image-scp.1.md
@@ -33,7 +33,7 @@ Suppress the output
```
$ podman image scp alpine
-Loaded image(s): docker.io/library/alpine:latest
+Loaded image: docker.io/library/alpine:latest
```
```
@@ -43,12 +43,12 @@ Copying blob 72e830a4dff5 done
Copying config 85f9dc67c7 done
Writing manifest to image destination
Storing signatures
-Loaded image(s): docker.io/library/alpine:latest
+Loaded image: docker.io/library/alpine:latest
```
```
$ podman image scp Fedora::alpine RHEL::
-Loaded image(s): docker.io/library/alpine:latest
+Loaded image: docker.io/library/alpine:latest
```
```
@@ -59,7 +59,7 @@ Copying blob 9450ef9feb15 [--------------------------------------] 0.0b / 0.0b
Copying config 1f97f0559c done
Writing manifest to image destination
Storing signatures
-Loaded image(s): docker.io/library/alpine:latest
+Loaded image: docker.io/library/alpine:latest
```
```
@@ -73,7 +73,7 @@ Copying blob 5eb901baf107 skipped: already exists
Copying config 696d33ca15 done
Writing manifest to image destination
Storing signatures
-Loaded image(s): docker.io/library/alpine:latest
+Loaded image: docker.io/library/alpine:latest
```
```
@@ -87,7 +87,7 @@ Copying blob 5eb901baf107
Copying config 696d33ca15 done
Writing manifest to image destination
Storing signatures
-Loaded image(s): docker.io/library/alpine:latest
+Loaded image: docker.io/library/alpine:latest
```
## SEE ALSO
diff --git a/docs/source/markdown/podman-machine-ssh.1.md b/docs/source/markdown/podman-machine-ssh.1.md
index db0350961..6a1455df1 100644
--- a/docs/source/markdown/podman-machine-ssh.1.md
+++ b/docs/source/markdown/podman-machine-ssh.1.md
@@ -14,6 +14,7 @@ first argument must be the virtual machine name. The optional command to
execute can then follow. If no command is provided, an interactive session
with the virtual machine is established.
+The exit code from ssh command will be forwarded to the podman machine ssh caller, see [Exit Codes](#Exit-Codes).
## OPTIONS
@@ -25,6 +26,35 @@ Print usage statement.
Username to use when SSH-ing into the VM.
+## Exit Codes
+
+The exit code from `podman machine ssh` gives information about why the command failed.
+When `podman machine ssh` commands exit with a non-zero code,
+the exit codes follow the `chroot` standard, see below:
+
+ **125** The error is with podman **_itself_**
+
+ $ podman machine ssh --foo; echo $?
+ Error: unknown flag: --foo
+ 125
+
+ **126** Executing a _contained command_ and the _command_ cannot be invoked
+
+ $ podman machine ssh /etc; echo $?
+ Error: fork/exec /etc: permission denied
+ 126
+
+ **127** Executing a _contained command_ and the _command_ cannot be found
+
+ $ podman machine ssh foo; echo $?
+ Error: fork/exec /usr/bin/bogus: no such file or directory
+ 127
+
+ **Exit code** _contained command_ exit code
+
+ $ podman machine ssh /bin/sh -c 'exit 3'; echo $?
+ 3
+
## EXAMPLES
To get an interactive session with the default virtual machine:
diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md
index 08bb2a5bc..1c7fc99a2 100644
--- a/docs/source/markdown/podman-play-kube.1.md
+++ b/docs/source/markdown/podman-play-kube.1.md
@@ -276,9 +276,9 @@ Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinat
**host**: create a new namespace for the container.
-**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is ignored for containers created by the root user.
+**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
-**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is ignored for containers created by the root user.
+**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
**ns:**_namespace_: run the pod in the given existing user namespace.
diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md
index 3dafeace5..8d8bded37 100644
--- a/docs/source/markdown/podman-pod-create.1.md
+++ b/docs/source/markdown/podman-pod-create.1.md
@@ -227,16 +227,30 @@ Set the PID mode for the pod. The default is to create a private PID namespace f
Write the pod ID to the file.
-#### **--publish**=*port*, **-p**
+#### **--publish**, **-p**=[[_ip_:][_hostPort_]:]_containerPort_[/_protocol_]
-Publish a port or range of ports from the pod to the host.
+Publish a container's port, or range of ports, within this pod to the host.
-Format: `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort`
Both hostPort and containerPort can be specified as a range of ports.
-When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range.
-Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPORT`.
+When specifying ranges for both, the number of container ports in the
+range must match the number of host ports in the range.
-NOTE: This cannot be modified once the pod is created.
+If host IP is set to 0.0.0.0 or not set at all, the port will be bound on all IPs on the host.
+
+By default, Podman will publish TCP ports. To publish a UDP port instead, give
+`udp` as protocol. To publish both TCP and UDP ports, set `--publish` twice,
+with `tcp`, and `udp` as protocols respectively. Rootful containers can also
+publish ports using the `sctp` protocol.
+
+Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
+If it is not, the container port will be randomly assigned a port on the host.
+
+Use **podman port** to see the actual mapping: `podman port $CONTAINER $CONTAINERPORT`.
+
+**Note:** You must not publish ports of containers in the pod individually,
+but only by the pod itself.
+
+**Note:** This cannot be modified once the pod is created.
#### **--replace**
@@ -346,9 +360,9 @@ Valid _mode_ values are:
- *host*: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).
- - *keep-id*: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is ignored for containers created by the root user.
+ - *keep-id*: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
- - *nomap*: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is ignored for containers created by the root user.
+ - *nomap*: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
#### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*]
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 9041a6778..4535de3de 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -597,7 +597,7 @@ To specify multiple static MAC addresses per container, set multiple networks us
#### **--memory**, **-m**=_number_[_unit_]
-Memory limit. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes).
+Memory limit. A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes).
Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
@@ -607,7 +607,7 @@ system's page size (the value would be very large, that's millions of trillions)
#### **--memory-reservation**=_number_[_unit_]
-Memory soft limit. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes).
+Memory soft limit. A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes).
After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
@@ -618,7 +618,7 @@ as memory limit.
#### **--memory-swap**=_number_[_unit_]
A limit value equal to memory plus swap.
-A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes).
+A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes).
Must be used with the **-m** (**--memory**) flag.
The argument value should always be larger than that of
@@ -864,22 +864,27 @@ points, Apparmor/SELinux separation, and Seccomp filters are all disabled.
Rootless containers cannot have more privileges than the account that launched them.
-#### **--publish**, **-p**=_ip_:_hostPort_:_containerPort_ | _ip_::_containerPort_ | _hostPort_:_containerPort_ | _containerPort_
+#### **--publish**, **-p**=[[_ip_:][_hostPort_]:]_containerPort_[/_protocol_]
Publish a container's port, or range of ports, to the host.
Both hostPort and containerPort can be specified as a range of ports.
-
-When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range.
+When specifying ranges for both, the number of container ports in the
+range must match the number of host ports in the range.
If host IP is set to 0.0.0.0 or not set at all, the port will be bound on all IPs on the host.
+By default, Podman will publish TCP ports. To publish a UDP port instead, give
+`udp` as protocol. To publish both TCP and UDP ports, set `--publish` twice,
+with `tcp`, and `udp` as protocols respectively. Rootful containers can also
+publish ports using the `sctp` protocol.
+
Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
If it is not, the container port will be randomly assigned a port on the host.
-Use **podman port** to see the actual mapping: **podman port $CONTAINER $CONTAINERPORT**.
+Use **podman port** to see the actual mapping: `podman port $CONTAINER $CONTAINERPORT`.
-**Note:** if a container will be run within a pod, it is not necessary to publish the port for
+**Note:** If a container will be run within a pod, it is not necessary to publish the port for
the containers in the pod. The port must only be published by the pod itself. Pod network
stacks act like the network stack on the host - you have a variety of containers in the pod,
and programs in the container, all sharing a single interface and IP address, and
@@ -1053,7 +1058,7 @@ Note: Labeling can be disabled for all containers by setting **label=false** in
#### **--shm-size**=_number_[_unit_]
-Size of _/dev/shm_. A _unit_ can be **b** (bytes), **k** (kilobytes), **m** (megabytes), or **g** (gigabytes).
+Size of _/dev/shm_. A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes).
If you omit the unit, the system uses bytes. If you omit the size entirely, the default is **64m**.
When _size_ is **0**, there is no limit on the amount of memory used for IPC by the container.
@@ -1324,9 +1329,9 @@ The rootless option `--userns=keep-id` uses all the subuids and subgids of the u
**host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default).
-**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is ignored for containers created by the root user.
+**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user.
-**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is ignored for containers created by the root user.
+**nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user.
**ns:**_namespace_: run the container in the given existing user namespace.
diff --git a/docs/source/markdown/podman-volume-import.1.md b/docs/source/markdown/podman-volume-import.1.md
index 71956f43a..4ae9ae1e2 100644
--- a/docs/source/markdown/podman-volume-import.1.md
+++ b/docs/source/markdown/podman-volume-import.1.md
@@ -1,7 +1,7 @@
% podman-volume-import(1)
## NAME
-podman\-volume\-import - Import tarball contents into a podman volume
+podman\-volume\-import - Import tarball contents into an existing podman volume
## SYNOPSIS
**podman volume import** *volume* [*source*]
@@ -11,9 +11,9 @@ podman\-volume\-import - Import tarball contents into a podman volume
**podman volume import** imports the contents of a tarball into the podman volume's mount point.
**podman volume import** can consume piped input when using `-` as source path.
-Note: Following command is not supported by podman-remote.
+The given volume must already exist and will not be created by podman volume import.
-**podman volume import VOLUME [SOURCE]**
+Note: Following command is not supported by podman-remote.
#### **--help**
diff --git a/docs/source/markdown/podman-volume.1.md b/docs/source/markdown/podman-volume.1.md
index d05f007c8..476d58591 100644
--- a/docs/source/markdown/podman-volume.1.md
+++ b/docs/source/markdown/podman-volume.1.md
@@ -16,7 +16,7 @@ podman volume is a set of subcommands that manage volumes.
| create | [podman-volume-create(1)](podman-volume-create.1.md) | Create a new volume. |
| exists | [podman-volume-exists(1)](podman-volume-exists.1.md) | Check if the given volume exists. |
| export | [podman-volume-export(1)](podman-volume-export.1.md) | Exports volume to external tar. |
-| import | [podman-volume-import(1)](podman-volume-import.1.md) | Import tarball contents into a podman volume. |
+| import | [podman-volume-import(1)](podman-volume-import.1.md) | Import tarball contents into an existing podman volume. |
| inspect | [podman-volume-inspect(1)](podman-volume-inspect.1.md) | Get detailed information on one or more volumes. |
| ls | [podman-volume-ls(1)](podman-volume-ls.1.md) | List all the available volumes. |
| mount | [podman-volume-mount(1)](podman-volume-mount.1.md) | Mount a volume filesystem. |
diff --git a/docs/tutorials/basic_networking.md b/docs/tutorials/basic_networking.md
index 396994596..b6f53175b 100644
--- a/docs/tutorials/basic_networking.md
+++ b/docs/tutorials/basic_networking.md
@@ -93,6 +93,22 @@ When rootless containers are run, network operations
will be executed inside an extra network namespace. To join this namespace, use
`podman unshare --rootless-netns`.
+#### Default Network
+
+The default network `podman` with netavark is memory-only. It does not support dns resolution because of backwards compatibility with Docker. To change settings, export the in-memory network and change the file.
+
+For the default rootful network use
+```
+podman network inspect podman | jq .[] > /etc/containers/networks/podman.json
+```
+
+And for the rootless network use
+
+```
+podman network inspect podman | jq .[] > ~/.local/share/containers/storage/networks/podman.json
+```
+
+
#### Example
By default, rootful containers use the netavark for its default network if
diff --git a/go.mod b/go.mod
index 1880134e9..0d223aeca 100644
--- a/go.mod
+++ b/go.mod
@@ -9,10 +9,10 @@ require (
github.com/checkpoint-restore/checkpointctl v0.0.0-20220321135231-33f4a66335f0
github.com/checkpoint-restore/go-criu/v5 v5.3.0
github.com/container-orchestrated-devices/container-device-interface v0.4.0
- github.com/containernetworking/cni v1.1.0
+ github.com/containernetworking/cni v1.1.1
github.com/containernetworking/plugins v1.1.1
github.com/containers/buildah v1.26.1-0.20220524184833-5500333c2e06
- github.com/containers/common v0.48.1-0.20220523155016-2fd37da97824
+ github.com/containers/common v0.48.1-0.20220528105338-54c8092c69a1
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.21.2-0.20220520105616-e594853d6471
github.com/containers/ocicrypt v1.1.4-0.20220428134531-566b808bdf6f
@@ -24,7 +24,7 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001
github.com/docker/distribution v2.8.1+incompatible
- github.com/docker/docker v20.10.16+incompatible
+ github.com/docker/docker v20.10.17+incompatible
github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11
github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651
github.com/docker/go-units v0.4.0
@@ -47,7 +47,7 @@ require (
github.com/onsi/gomega v1.19.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198
- github.com/opencontainers/runc v1.1.2
+ github.com/opencontainers/runc v1.1.3
github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab
github.com/opencontainers/runtime-tools v0.9.1-0.20220110225228-7e2d60f1e41f
github.com/opencontainers/selinux v1.10.1
@@ -57,7 +57,7 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
- github.com/stretchr/testify v1.7.1
+ github.com/stretchr/testify v1.7.2
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/ulikunitz/xz v0.5.10
diff --git a/go.sum b/go.sum
index 47c842744..6a10a4c7b 100644
--- a/go.sum
+++ b/go.sum
@@ -328,8 +328,9 @@ github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
-github.com/containernetworking/cni v1.1.0 h1:T00oIz4hef+/p9gpRZa57SnIN+QnbmAHBjbxaOSFo9U=
github.com/containernetworking/cni v1.1.0/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
+github.com/containernetworking/cni v1.1.1 h1:ky20T7c0MvKvbMOwS/FrlbNwjEoqJEUUYfsL4b0mc4k=
+github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE=
@@ -338,8 +339,8 @@ github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19
github.com/containers/buildah v1.26.1-0.20220524184833-5500333c2e06 h1:Tx1IfKch/SnsCk1YrdyR4B2AcS1TKLYxbSMXzmQXafU=
github.com/containers/buildah v1.26.1-0.20220524184833-5500333c2e06/go.mod h1:oB0PwsW+rhePNsBimCnEz4YMLx8QxZBjHi/DPnXhUCg=
github.com/containers/common v0.48.1-0.20220519181648-280c6f69fa82/go.mod h1:Ru/JjL1CTHzlxghVMhchzcFUwHLvlIeR5/SUMw8VUOI=
-github.com/containers/common v0.48.1-0.20220523155016-2fd37da97824 h1:5gMIUUpIK9DvHrrlj1Tik8GfCh5DEuVqm0JnYHWYUDw=
-github.com/containers/common v0.48.1-0.20220523155016-2fd37da97824/go.mod h1:Ru/JjL1CTHzlxghVMhchzcFUwHLvlIeR5/SUMw8VUOI=
+github.com/containers/common v0.48.1-0.20220528105338-54c8092c69a1 h1:oq9ol4U/HEJfDYCp9aKBFDBaE16Y1RZN0GJ4eIkrJoo=
+github.com/containers/common v0.48.1-0.20220528105338-54c8092c69a1/go.mod h1:Ru/JjL1CTHzlxghVMhchzcFUwHLvlIeR5/SUMw8VUOI=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.21.2-0.20220511203756-fe4fd4ed8be4/go.mod h1:OsX9sFexyGF0FCNAjfcVFv3IwMqDyLyV/WQY/roLPcE=
@@ -428,8 +429,9 @@ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r
github.com/docker/docker v20.10.3-0.20220208084023-a5c757555091+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.15+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v20.10.16+incompatible h1:2Db6ZR/+FUR3hqPMwnogOPHFn405crbpxvWzKovETOQ=
github.com/docker/docker v20.10.16+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
+github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o=
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
@@ -1052,8 +1054,9 @@ github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04s
github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
-github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw=
github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
+github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
+github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@@ -1185,8 +1188,9 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
-github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921 h1:58EBmR2dMNL2n/FnbQewK3D14nXr0V9CObDSvMJLq+Y=
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
+github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646 h1:RpforrEYXWkmGwJHIGnLZ3tTWStkjVVstwzNGqxX2Ds=
+github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@@ -1261,8 +1265,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/sylabs/sif/v2 v2.7.0 h1:VFzN8alnJ/3n1JA0K9DyUtfSzezWgWrzLDcYGhgBskk=
github.com/sylabs/sif/v2 v2.7.0/go.mod h1:TiyBWsgWeh5yBeQFNuQnvROwswqK7YJT8JA1L53bsXQ=
@@ -2047,8 +2052,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
diff --git a/libpod/container_api.go b/libpod/container_api.go
index d87deb71a..b064d3528 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -123,7 +123,18 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachSt
// Attach to the container before starting it
go func() {
- if err := c.attach(streams, keys, resize, true, startedChan, nil); err != nil {
+ // Start resizing
+ if c.LogDriver() != define.PassthroughLogging {
+ registerResizeFunc(resize, c.bundlePath())
+ }
+
+ opts := new(AttachOptions)
+ opts.Streams = streams
+ opts.DetachKeys = &keys
+ opts.Start = true
+ opts.Started = startedChan
+
+ if err := c.ociRuntime.Attach(c, opts); err != nil {
attachChan <- err
}
close(attachChan)
@@ -260,8 +271,18 @@ func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-
}()
}
+ // Start resizing
+ if c.LogDriver() != define.PassthroughLogging {
+ registerResizeFunc(resize, c.bundlePath())
+ }
+
+ opts := new(AttachOptions)
+ opts.Streams = streams
+ opts.DetachKeys = &keys
+ opts.AttachReady = attachRdy
+
c.newContainerEvent(events.Attach)
- return c.attach(streams, keys, resize, false, nil, attachRdy)
+ return c.ociRuntime.Attach(c, opts)
}
// HTTPAttach forwards an attach session over a hijacked HTTP session.
diff --git a/libpod/container_config.go b/libpod/container_config.go
index ae3bc5865..6558f3c89 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -243,12 +243,12 @@ type ContainerNetworkConfig struct {
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned an IP by CNI.
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
- StaticIP net.IP `json:"staticIP"`
+ StaticIP net.IP `json:"staticIP,omitempty"`
// StaticMAC is a static MAC to request for the container.
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned a MAC by CNI.
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
- StaticMAC types.HardwareAddr `json:"staticMAC"`
+ StaticMAC types.HardwareAddr `json:"staticMAC,omitempty"`
// PortMappings are the ports forwarded to the container's network
// namespace
// These are not used unless CreateNetNS is true
@@ -412,6 +412,9 @@ type ContainerMiscConfig struct {
InitContainerType string `json:"init_container_type,omitempty"`
// PasswdEntry specifies arbitrary data to append to a file.
PasswdEntry string `json:"passwd_entry,omitempty"`
+ // MountAllDevices is an option to indicate whether a privileged container
+ // will mount all the host's devices
+ MountAllDevices bool `json:"mountAllDevices"`
}
// InfraInherit contains the compatible options inheritable from the infra container
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 7494eb3ec..fd451f9ef 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/buildah/pkg/overlay"
butil "github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/etchosts"
+ "github.com/containers/common/libnetwork/resolvconf"
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/chown"
"github.com/containers/common/pkg/config"
@@ -986,7 +987,7 @@ func (c *Container) checkDependenciesRunning() ([]string, error) {
}
func (c *Container) completeNetworkSetup() error {
- var outResolvConf []string
+ var nameservers []string
netDisabled, err := c.NetworkDisabled()
if err != nil {
return err
@@ -1000,11 +1001,14 @@ func (c *Container) completeNetworkSetup() error {
if err := c.runtime.setupNetNS(c); err != nil {
return err
}
+ if err := c.save(); err != nil {
+ return err
+ }
state := c.state
// collect any dns servers that cni tells us to use (dnsname)
for _, status := range c.getNetworkStatus() {
for _, server := range status.DNSServerIPs {
- outResolvConf = append(outResolvConf, fmt.Sprintf("nameserver %s", server))
+ nameservers = append(nameservers, server.String())
}
}
// check if we have a bindmount for /etc/hosts
@@ -1020,24 +1024,12 @@ func (c *Container) completeNetworkSetup() error {
}
// check if we have a bindmount for resolv.conf
- resolvBindMount := state.BindMounts["/etc/resolv.conf"]
- if len(outResolvConf) < 1 || resolvBindMount == "" || len(c.config.NetNsCtr) > 0 {
+ resolvBindMount := state.BindMounts[resolvconf.DefaultResolvConf]
+ if len(nameservers) < 1 || resolvBindMount == "" || len(c.config.NetNsCtr) > 0 {
return nil
}
- // read the existing resolv.conf
- b, err := ioutil.ReadFile(resolvBindMount)
- if err != nil {
- return err
- }
- for _, line := range strings.Split(string(b), "\n") {
- // only keep things that don't start with nameserver from the old
- // resolv.conf file
- if !strings.HasPrefix(line, "nameserver") {
- outResolvConf = append([]string{line}, outResolvConf...)
- }
- }
// write and return
- return ioutil.WriteFile(resolvBindMount, []byte(strings.Join(outResolvConf, "\n")), 0644)
+ return resolvconf.Add(resolvBindMount, nameservers)
}
// Initialize a container, creating it in the runtime
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index e19d75deb..41c0ac595 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -9,7 +9,6 @@ import (
"io"
"io/ioutil"
"math"
- "net"
"os"
"os/user"
"path"
@@ -29,6 +28,7 @@ import (
"github.com/containers/buildah/pkg/overlay"
butil "github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/etchosts"
+ "github.com/containers/common/libnetwork/resolvconf"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/apparmor"
"github.com/containers/common/pkg/cgroups"
@@ -44,7 +44,6 @@ import (
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
"github.com/containers/podman/v4/pkg/criu"
"github.com/containers/podman/v4/pkg/lookup"
- "github.com/containers/podman/v4/pkg/resolvconf"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils"
@@ -388,6 +387,37 @@ func lookupHostUser(name string) (*runcuser.ExecUser, error) {
return &execUser, nil
}
+// Internal only function which returns upper and work dir from
+// overlay options.
+func getOverlayUpperAndWorkDir(options []string) (string, string, error) {
+ upperDir := ""
+ workDir := ""
+ for _, o := range options {
+ if strings.HasPrefix(o, "upperdir") {
+ splitOpt := strings.SplitN(o, "=", 2)
+ if len(splitOpt) > 1 {
+ upperDir = splitOpt[1]
+ if upperDir == "" {
+ return "", "", errors.New("cannot accept empty value for upperdir")
+ }
+ }
+ }
+ if strings.HasPrefix(o, "workdir") {
+ splitOpt := strings.SplitN(o, "=", 2)
+ if len(splitOpt) > 1 {
+ workDir = splitOpt[1]
+ if workDir == "" {
+ return "", "", errors.New("cannot accept empty value for workdir")
+ }
+ }
+ }
+ }
+ if (upperDir != "" && workDir == "") || (upperDir == "" && workDir != "") {
+ return "", "", errors.New("must specify both upperdir and workdir")
+ }
+ return upperDir, workDir, nil
+}
+
// Generate spec for a container
// Accepts a map of the container's dependencies
func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
@@ -407,6 +437,14 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
//nolint:staticcheck
g := generate.NewFromSpec(c.config.Spec)
+ // If the flag to mount all devices is set for a privileged container, add
+ // all the devices from the host's machine into the container
+ if c.config.MountAllDevices {
+ if err := util.AddPrivilegedDevices(&g); err != nil {
+ return nil, err
+ }
+ }
+
// If network namespace was requested, add it now
if c.config.CreateNetNS {
if c.config.PostConfigureNetNS {
@@ -460,23 +498,9 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
for _, o := range namedVol.Options {
if o == "O" {
overlayFlag = true
- }
- if overlayFlag && strings.Contains(o, "upperdir") {
- splitOpt := strings.SplitN(o, "=", 2)
- if len(splitOpt) > 1 {
- upperDir = splitOpt[1]
- if upperDir == "" {
- return nil, errors.New("cannot accept empty value for upperdir")
- }
- }
- }
- if overlayFlag && strings.Contains(o, "workdir") {
- splitOpt := strings.SplitN(o, "=", 2)
- if len(splitOpt) > 1 {
- workDir = splitOpt[1]
- if workDir == "" {
- return nil, errors.New("cannot accept empty value for workdir")
- }
+ upperDir, workDir, err = getOverlayUpperAndWorkDir(namedVol.Options)
+ if err != nil {
+ return nil, err
}
}
}
@@ -489,10 +513,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
return nil, err
}
- if (upperDir != "" && workDir == "") || (upperDir == "" && workDir != "") {
- return nil, errors.Wrapf(err, "must specify both upperdir and workdir")
- }
-
overlayOpts = &overlay.Options{RootUID: c.RootUID(),
RootGID: c.RootGID(),
UpperDirOptionFragment: upperDir,
@@ -585,11 +605,22 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Add overlay volumes
for _, overlayVol := range c.config.OverlayVolumes {
+ upperDir, workDir, err := getOverlayUpperAndWorkDir(overlayVol.Options)
+ if err != nil {
+ return nil, err
+ }
contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID())
if err != nil {
return nil, err
}
- overlayMount, err := overlay.Mount(contentDir, overlayVol.Source, overlayVol.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions())
+ overlayOpts := &overlay.Options{RootUID: c.RootUID(),
+ RootGID: c.RootGID(),
+ UpperDirOptionFragment: upperDir,
+ WorkDirOptionFragment: workDir,
+ GraphOpts: c.runtime.store.GraphOptions(),
+ }
+
+ overlayMount, err := overlay.MountWithOptions(contentDir, overlayVol.Source, overlayVol.Dest, overlayOpts)
if err != nil {
return nil, errors.Wrapf(err, "mounting overlay failed %q", overlayVol.Source)
}
@@ -2284,49 +2315,10 @@ rootless=%d
// generateResolvConf generates a containers resolv.conf
func (c *Container) generateResolvConf() error {
var (
- nameservers []string
networkNameServers []string
networkSearchDomains []string
)
- hostns := true
- resolvConf := "/etc/resolv.conf"
- for _, namespace := range c.config.Spec.Linux.Namespaces {
- if namespace.Type == spec.NetworkNamespace {
- hostns = false
- if namespace.Path != "" && !strings.HasPrefix(namespace.Path, "/proc/") {
- definedPath := filepath.Join("/etc/netns", filepath.Base(namespace.Path), "resolv.conf")
- _, err := os.Stat(definedPath)
- if err == nil {
- resolvConf = definedPath
- } else if !os.IsNotExist(err) {
- return err
- }
- }
- break
- }
- }
-
- contents, err := ioutil.ReadFile(resolvConf)
- // resolv.conf doesn't have to exists
- if err != nil && !os.IsNotExist(err) {
- return err
- }
-
- ns := resolvconf.GetNameservers(contents)
- // check if systemd-resolved is used, assume it is used when 127.0.0.53 is the only nameserver
- if !hostns && len(ns) == 1 && ns[0] == "127.0.0.53" {
- // read the actual resolv.conf file for systemd-resolved
- resolvedContents, err := ioutil.ReadFile("/run/systemd/resolve/resolv.conf")
- if err != nil {
- if !os.IsNotExist(err) {
- return errors.Wrapf(err, "detected that systemd-resolved is in use, but could not locate real resolv.conf")
- }
- } else {
- contents = resolvedContents
- }
- }
-
netStatus := c.getNetworkStatus()
for _, status := range netStatus {
if status.DNSServerIPs != nil {
@@ -2346,34 +2338,18 @@ func (c *Container) generateResolvConf() error {
return err
}
- // Ensure that the container's /etc/resolv.conf is compatible with its
- // network configuration.
- resolv, err := resolvconf.FilterResolvDNS(contents, ipv6, !hostns)
- if err != nil {
- return errors.Wrapf(err, "error parsing host resolv.conf")
+ nameservers := make([]string, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer))
+ nameservers = append(nameservers, c.runtime.config.Containers.DNSServers...)
+ for _, ip := range c.config.DNSServer {
+ nameservers = append(nameservers, ip.String())
}
-
- dns := make([]net.IP, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer))
- for _, i := range c.runtime.config.Containers.DNSServers {
- result := net.ParseIP(i)
- if result == nil {
- return errors.Wrapf(define.ErrInvalidArg, "invalid IP address %s", i)
- }
- dns = append(dns, result)
- }
- dns = append(dns, c.config.DNSServer...)
// If the user provided dns, it trumps all; then dns masq; then resolv.conf
var search []string
- switch {
- case len(dns) > 0:
- // We store DNS servers as net.IP, so need to convert to string
- for _, server := range dns {
- nameservers = append(nameservers, server.String())
- }
- default:
- // Make a new resolv.conf
+ keepHostServers := false
+ if len(nameservers) == 0 {
+ keepHostServers = true
// first add the nameservers from the networks status
- nameservers = append(nameservers, networkNameServers...)
+ nameservers = networkNameServers
// when we add network dns server we also have to add the search domains
search = networkSearchDomains
// slirp4netns has a built in DNS forwarder.
@@ -2385,38 +2361,34 @@ func (c *Container) generateResolvConf() error {
nameservers = append(nameservers, slirp4netnsDNS.String())
}
}
- nameservers = append(nameservers, resolvconf.GetNameservers(resolv.Content)...)
}
if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 {
- if !cutil.StringInSlice(".", c.config.DNSSearch) {
- search = append(search, c.runtime.config.Containers.DNSSearches...)
- search = append(search, c.config.DNSSearch...)
- }
- } else {
- search = append(search, resolvconf.GetSearchDomains(resolv.Content)...)
+ customSearch := make([]string, 0, len(c.config.DNSSearch)+len(c.runtime.config.Containers.DNSSearches))
+ customSearch = append(customSearch, c.runtime.config.Containers.DNSSearches...)
+ customSearch = append(customSearch, c.config.DNSSearch...)
+ search = customSearch
}
- var options []string
- if len(c.config.DNSOption) > 0 || len(c.runtime.config.Containers.DNSOptions) > 0 {
- options = c.runtime.config.Containers.DNSOptions
- options = append(options, c.config.DNSOption...)
- } else {
- options = resolvconf.GetOptions(resolv.Content)
- }
+ options := make([]string, 0, len(c.config.DNSOption)+len(c.runtime.config.Containers.DNSOptions))
+ options = append(options, c.runtime.config.Containers.DNSOptions...)
+ options = append(options, c.config.DNSOption...)
destPath := filepath.Join(c.state.RunDir, "resolv.conf")
- if err := os.Remove(destPath); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "container %s", c.ID())
- }
-
- // Build resolv.conf
- if _, err = resolvconf.Build(destPath, nameservers, search, options); err != nil {
+ if err := resolvconf.New(&resolvconf.Params{
+ IPv6Enabled: ipv6,
+ KeepHostServers: keepHostServers,
+ Nameservers: nameservers,
+ Namespaces: c.config.Spec.Linux.Namespaces,
+ Options: options,
+ Path: destPath,
+ Searches: search,
+ }); err != nil {
return errors.Wrapf(err, "error building resolv.conf for container %s", c.ID())
}
- return c.bindMountRootFile(destPath, "/etc/resolv.conf")
+ return c.bindMountRootFile(destPath, resolvconf.DefaultResolvConf)
}
// Check if a container uses IPv6.
@@ -2457,31 +2429,13 @@ func (c *Container) addNameserver(ips []string) error {
}
// Do we have a resolv.conf at all?
- path, ok := c.state.BindMounts["/etc/resolv.conf"]
+ path, ok := c.state.BindMounts[resolvconf.DefaultResolvConf]
if !ok {
return nil
}
- // Read in full contents, parse out existing nameservers
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- ns := resolvconf.GetNameservers(contents)
- options := resolvconf.GetOptions(contents)
- search := resolvconf.GetSearchDomains(contents)
-
- // We could verify that it doesn't already exist
- // but extra nameservers shouldn't harm anything.
- // Ensure we are the first entry in resolv.conf though, otherwise we
- // might be after user-added servers.
- ns = append(ips, ns...)
-
- // We're rewriting the container's resolv.conf as part of this, but we
- // hold the container lock, so there should be no risk of parallel
- // modification.
- if _, err := resolvconf.Build(path, ns, search, options); err != nil {
- return errors.Wrapf(err, "error adding new nameserver to container %s resolv.conf", c.ID())
+ if err := resolvconf.Add(path, ips); err != nil {
+ return fmt.Errorf("adding new nameserver to container %s resolv.conf: %w", c.ID(), err)
}
return nil
@@ -2496,34 +2450,13 @@ func (c *Container) removeNameserver(ips []string) error {
}
// Do we have a resolv.conf at all?
- path, ok := c.state.BindMounts["/etc/resolv.conf"]
+ path, ok := c.state.BindMounts[resolvconf.DefaultResolvConf]
if !ok {
return nil
}
- // Read in full contents, parse out existing nameservers
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- ns := resolvconf.GetNameservers(contents)
- options := resolvconf.GetOptions(contents)
- search := resolvconf.GetSearchDomains(contents)
-
- toRemove := make(map[string]bool)
- for _, ip := range ips {
- toRemove[ip] = true
- }
-
- newNS := make([]string, 0, len(ns))
- for _, server := range ns {
- if !toRemove[server] {
- newNS = append(newNS, server)
- }
- }
-
- if _, err := resolvconf.Build(path, newNS, search, options); err != nil {
- return errors.Wrapf(err, "error removing nameservers from container %s resolv.conf", c.ID())
+ if err := resolvconf.Remove(path, ips); err != nil {
+ return fmt.Errorf("removing nameservers from container %s resolv.conf: %w", c.ID(), err)
}
return nil
diff --git a/libpod/container_log.go b/libpod/container_log.go
index 7a9eb2dbf..da6d51670 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -75,7 +75,6 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption
go func() {
defer options.WaitGroup.Done()
- var partial string
for line := range t.Lines {
select {
case <-ctx.Done():
@@ -89,13 +88,6 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption
logrus.Errorf("Getting new log line: %v", err)
continue
}
- if nll.Partial() {
- partial += nll.Msg
- continue
- } else if !nll.Partial() && len(partial) > 0 {
- nll.Msg = partial + nll.Msg
- partial = ""
- }
nll.CID = c.ID()
nll.CName = c.Name()
nll.ColorID = colorID
diff --git a/libpod/healthcheck_linux.go b/libpod/healthcheck_linux.go
index 45b3a0e41..1e03db542 100644
--- a/libpod/healthcheck_linux.go
+++ b/libpod/healthcheck_linux.go
@@ -7,6 +7,7 @@ import (
"os/exec"
"strings"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/systemd"
"github.com/pkg/errors"
@@ -46,6 +47,17 @@ func (c *Container) createTimer() error {
return nil
}
+// Wait for a message on the channel. Throw an error if the message is not "done".
+func systemdOpSuccessful(c chan string) error {
+ msg := <-c
+ switch msg {
+ case "done":
+ return nil
+ default:
+ return fmt.Errorf("expected %q but received %q", "done", msg)
+ }
+}
+
// startTimer starts a systemd timer for the healthchecks
func (c *Container) startTimer() error {
if c.disableHealthCheckSystemd() {
@@ -56,8 +68,17 @@ func (c *Container) startTimer() error {
return errors.Wrapf(err, "unable to get systemd connection to start healthchecks")
}
defer conn.Close()
- _, err = conn.StartUnitContext(context.Background(), fmt.Sprintf("%s.service", c.ID()), "fail", nil)
- return err
+
+ startFile := fmt.Sprintf("%s.service", c.ID())
+ startChan := make(chan string)
+ if _, err := conn.StartUnitContext(context.Background(), startFile, "fail", startChan); err != nil {
+ return err
+ }
+ if err := systemdOpSuccessful(startChan); err != nil {
+ return fmt.Errorf("starting systemd health-check timer %q: %w", startFile, err)
+ }
+
+ return nil
}
// removeTransientFiles removes the systemd timer and unit files
@@ -71,30 +92,37 @@ func (c *Container) removeTransientFiles(ctx context.Context) error {
return errors.Wrapf(err, "unable to get systemd connection to remove healthchecks")
}
defer conn.Close()
+
+ // Errors are returned at the very end. Let's make sure to stop and
+ // clean up as much as possible.
+ stopErrors := []error{}
+
+ // Stop the timer before the service to make sure the timer does not
+ // fire after the service is stopped.
+ timerChan := make(chan string)
timerFile := fmt.Sprintf("%s.timer", c.ID())
- serviceFile := fmt.Sprintf("%s.service", c.ID())
+ if _, err := conn.StopUnitContext(ctx, timerFile, "fail", timerChan); err != nil {
+ if !strings.HasSuffix(err.Error(), ".timer not loaded.") {
+ stopErrors = append(stopErrors, fmt.Errorf("removing health-check timer %q: %w", timerFile, err))
+ }
+ } else if err := systemdOpSuccessful(timerChan); err != nil {
+ stopErrors = append(stopErrors, fmt.Errorf("stopping systemd health-check timer %q: %w", timerFile, err))
+ }
- // If the service has failed (the healthcheck has failed), then
- // the .service file is not removed on stopping the unit file. If
- // we check the properties of the service, it will automatically
- // reset the state. But checking the state takes msecs vs usecs to
- // blindly call reset.
+ // Reset the service before stopping it to make sure it's being removed
+ // on stop.
+ serviceChan := make(chan string)
+ serviceFile := fmt.Sprintf("%s.service", c.ID())
if err := conn.ResetFailedUnitContext(ctx, serviceFile); err != nil {
- logrus.Debugf("failed to reset unit file: %q", err)
+ logrus.Debugf("Failed to reset unit file: %q", err)
}
-
- // We want to ignore errors where the timer unit and/or service unit has already
- // been removed. The error return is generic so we have to check against the
- // string in the error
- if _, err = conn.StopUnitContext(ctx, serviceFile, "fail", nil); err != nil {
+ if _, err := conn.StopUnitContext(ctx, serviceFile, "fail", serviceChan); err != nil {
if !strings.HasSuffix(err.Error(), ".service not loaded.") {
- return errors.Wrapf(err, "unable to remove service file")
- }
- }
- if _, err = conn.StopUnitContext(ctx, timerFile, "fail", nil); err != nil {
- if strings.HasSuffix(err.Error(), ".timer not loaded.") {
- return nil
+ stopErrors = append(stopErrors, fmt.Errorf("removing health-check service %q: %w", serviceFile, err))
}
+ } else if err := systemdOpSuccessful(serviceChan); err != nil {
+ stopErrors = append(stopErrors, fmt.Errorf("stopping systemd health-check service %q: %w", serviceFile, err))
}
- return err
+
+ return errorhandling.JoinErrors(stopErrors)
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 73e64530e..ee80b00fe 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -21,6 +21,7 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containers/common/libnetwork/etchosts"
+ "github.com/containers/common/libnetwork/resolvconf"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/machine"
@@ -30,11 +31,10 @@ import (
"github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/pkg/namespaces"
- "github.com/containers/podman/v4/pkg/resolvconf"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/lockfile"
- spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -526,23 +526,19 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return nil, errors.Wrapf(err, "failed to determine slirp4netns DNS address from cidr: %s", cidr.String())
}
}
- conf, err := resolvconf.Get()
- if err != nil {
- return nil, err
- }
- conf, err = resolvconf.FilterResolvDNS(conf.Content, netOptions.enableIPv6, true)
- if err != nil {
- return nil, err
- }
- searchDomains := resolvconf.GetSearchDomains(conf.Content)
- dnsOptions := resolvconf.GetOptions(conf.Content)
- nameServers := resolvconf.GetNameservers(conf.Content)
- _, err = resolvconf.Build(filepath.Join(rootlessNetNsDir, "resolv.conf"), append([]string{resolveIP.String()}, nameServers...), searchDomains, dnsOptions)
- if err != nil {
+ if err := resolvconf.New(&resolvconf.Params{
+ Path: filepath.Join(rootlessNetNsDir, "resolv.conf"),
+ // fake the netns since we want to filter localhost
+ Namespaces: []specs.LinuxNamespace{
+ {Type: specs.NetworkNamespace},
+ },
+ IPv6Enabled: netOptions.enableIPv6,
+ KeepHostServers: true,
+ Nameservers: []string{resolveIP.String()},
+ }); err != nil {
return nil, errors.Wrap(err, "failed to create rootless netns resolv.conf")
}
-
// create cni directories to store files
// they will be bind mounted to the correct location in a extra mount ns
err = os.MkdirAll(filepath.Join(rootlessNetNsDir, persistentCNIDir), 0700)
@@ -930,6 +926,8 @@ func (r *Runtime) reloadContainerNetwork(ctr *Container) (map[string]types.Statu
return r.configureNetNS(ctr, ctr.state.NetNS)
}
+// TODO (5.0): return the statistics per network interface
+// This would allow better compat with docker.
func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
var netStats *netlink.LinkStatistics
@@ -943,21 +941,39 @@ func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
return nil, nil
}
- // FIXME get the interface from the container netstatus
- dev := "eth0"
netMode := ctr.config.NetMode
+ netStatus := ctr.getNetworkStatus()
if otherCtr != nil {
netMode = otherCtr.config.NetMode
+ netStatus = otherCtr.getNetworkStatus()
}
if netMode.IsSlirp4netns() {
- dev = "tap0"
+ // create a fake status with correct interface name for the logic below
+ netStatus = map[string]types.StatusBlock{
+ "slirp4netns": {
+ Interfaces: map[string]types.NetInterface{"tap0": {}},
+ },
+ }
}
err := ns.WithNetNSPath(netNSPath, func(_ ns.NetNS) error {
- link, err := netlink.LinkByName(dev)
- if err != nil {
- return err
+ for _, status := range netStatus {
+ for dev := range status.Interfaces {
+ link, err := netlink.LinkByName(dev)
+ if err != nil {
+ return err
+ }
+ if netStats == nil {
+ netStats = link.Attrs().Statistics
+ continue
+ }
+ // Currently only Tx/RxBytes are used.
+ // In the future we should return all stats per interface so that
+ // api users have a better options.
+ stats := link.Attrs().Statistics
+ netStats.TxBytes += stats.TxBytes
+ netStats.RxBytes += stats.RxBytes
+ }
}
- netStats = link.Attrs().Statistics
return nil
})
return netStats, err
@@ -1069,7 +1085,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
func (c *Container) joinedNetworkNSPath() string {
for _, namespace := range c.config.Spec.Linux.Namespaces {
- if namespace.Type == spec.NetworkNamespace {
+ if namespace.Type == specs.NetworkNamespace {
return namespace.Path
}
}
diff --git a/libpod/oci.go b/libpod/oci.go
index 09f856ac7..90862969c 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -12,9 +12,7 @@ import (
// management logic - e.g., we do not expect it to determine on its own that
// calling 'UnpauseContainer()' on a container that is not paused is an error.
// The code calling the OCIRuntime will manage this.
-// TODO: May want to move the Attach() code under this umbrella. It's highly OCI
-// runtime dependent.
-// TODO: May want to move the conmon cleanup code here too - it depends on
+// TODO: May want to move the conmon cleanup code here - it depends on
// Conmon being in use.
type OCIRuntime interface {
// Name returns the name of the runtime.
@@ -52,6 +50,8 @@ type OCIRuntime interface {
// UnpauseContainer unpauses the given container.
UnpauseContainer(ctr *Container) error
+ // Attach to a container.
+ Attach(ctr *Container, params *AttachOptions) error
// HTTPAttach performs an attach intended to be transported over HTTP.
// For terminal attach, the container's output will be directly streamed
// to output; otherwise, STDOUT and STDERR will be multiplexed, with
@@ -149,6 +149,30 @@ type OCIRuntime interface {
RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error)
}
+// AttachOptions are options used when attached to a container or an exec
+// session.
+type AttachOptions struct {
+ // Streams are the streams to attach to.
+ Streams *define.AttachStreams
+ // DetachKeys containers the key combination that will detach from the
+ // attach session. Empty string is assumed as no detach keys - user
+ // detach is impossible. If unset, defaults from containers.conf will be
+ // used.
+ DetachKeys *string
+ // InitialSize is the initial size of the terminal. Set before the
+ // attach begins.
+ InitialSize *define.TerminalSize
+ // AttachReady signals when the attach has successfully completed and
+ // streaming has begun.
+ AttachReady chan<- bool
+ // Start indicates that the container should be started if it is not
+ // already running.
+ Start bool
+ // Started signals when the container has been successfully started.
+ // Required if Start is true, unused otherwise.
+ Started chan<- bool
+}
+
// ExecOptions are options passed into ExecContainer. They control the command
// that will be executed and how the exec will proceed.
type ExecOptions struct {
diff --git a/libpod/oci_attach_linux.go b/libpod/oci_conmon_attach_linux.go
index 06f8f8719..155a8fbc3 100644
--- a/libpod/oci_attach_linux.go
+++ b/libpod/oci_conmon_attach_linux.go
@@ -38,19 +38,28 @@ func openUnixSocket(path string) (*net.UnixConn, error) {
return net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: fmt.Sprintf("/proc/self/fd/%d", fd), Net: "unixpacket"})
}
-// Attach to the given container
-// Does not check if state is appropriate
-// started is only required if startContainer is true
-func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan define.TerminalSize, startContainer bool, started chan bool, attachRdy chan<- bool) error {
+// Attach to the given container.
+// Does not check if state is appropriate.
+// started is only required if startContainer is true.
+func (r *ConmonOCIRuntime) Attach(c *Container, params *AttachOptions) error {
passthrough := c.LogDriver() == define.PassthroughLogging
- if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput && !passthrough {
+ if params == nil || params.Streams == nil {
+ return errors.Wrapf(define.ErrInternal, "must provide parameters to Attach")
+ }
+
+ if !params.Streams.AttachOutput && !params.Streams.AttachError && !params.Streams.AttachInput && !passthrough {
return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
}
- if startContainer && started == nil {
+ if params.Start && params.Started == nil {
return errors.Wrapf(define.ErrInternal, "started chan not passed when startContainer set")
}
+ keys := config.DefaultDetachKeys
+ if params.DetachKeys != nil {
+ keys = *params.DetachKeys
+ }
+
detachKeys, err := processDetachKeys(keys)
if err != nil {
return err
@@ -60,7 +69,12 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
if !passthrough {
logrus.Debugf("Attaching to container %s", c.ID())
- registerResizeFunc(resize, c.bundlePath())
+ // If we have a resize, do it.
+ if params.InitialSize != nil {
+ if err := r.AttachResize(c, *params.InitialSize); err != nil {
+ return err
+ }
+ }
attachSock, err := c.AttachSocketPath()
if err != nil {
@@ -80,22 +94,22 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
// If starting was requested, start the container and notify when that's
// done.
- if startContainer {
+ if params.Start {
if err := c.start(); err != nil {
return err
}
- started <- true
+ params.Started <- true
}
if passthrough {
return nil
}
- receiveStdoutError, stdinDone := setupStdioChannels(streams, conn, detachKeys)
- if attachRdy != nil {
- attachRdy <- true
+ receiveStdoutError, stdinDone := setupStdioChannels(params.Streams, conn, detachKeys)
+ if params.AttachReady != nil {
+ params.AttachReady <- true
}
- return readStdio(conn, streams, receiveStdoutError, stdinDone)
+ return readStdio(conn, params.Streams, receiveStdoutError, stdinDone)
}
// Attach to the given container's exec session
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 6aa7ce6dc..0c1ee61d3 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -411,8 +411,8 @@ func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool)
if err2 := r.UpdateContainerStatus(ctr); err2 != nil {
logrus.Infof("Error updating status for container %s: %v", ctr.ID(), err2)
}
- if ctr.state.State == define.ContainerStateExited {
- return nil
+ if ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) {
+ return define.ErrCtrStateInvalid
}
return errors.Wrapf(err, "error sending signal to container %s", ctr.ID())
}
diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go
index 86f54c02e..fd8160830 100644
--- a/libpod/oci_missing.go
+++ b/libpod/oci_missing.go
@@ -108,6 +108,11 @@ func (r *MissingRuntime) UnpauseContainer(ctr *Container) error {
return r.printError()
}
+// Attach is not available as the runtime is missing
+func (r *MissingRuntime) Attach(ctr *Container, params *AttachOptions) error {
+ return r.printError()
+}
+
// HTTPAttach is not available as the runtime is missing
func (r *MissingRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, detachKeys *string, cancel <-chan bool, hijackDone chan<- bool, streamAttach, streamLogs bool) error {
return r.printError()
diff --git a/libpod/options.go b/libpod/options.go
index a02c05537..8b3b07efa 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -435,6 +435,21 @@ func WithDefaultInfraCommand(cmd string) RuntimeOption {
}
}
+// WithReset instructs libpod to reset all storage to factory defaults.
+// All containers, pods, volumes, images, and networks will be removed.
+// All directories created by Libpod will be removed.
+func WithReset() RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return define.ErrRuntimeFinalized
+ }
+
+ rt.doReset = true
+
+ return nil
+ }
+}
+
// WithRenumber instructs libpod to perform a lock renumbering while
// initializing. This will handle migrations from early versions of libpod with
// file locks to newer versions with SHM locking, as well as changes in the
@@ -2159,3 +2174,17 @@ func WithPasswdEntry(passwdEntry string) CtrCreateOption {
return nil
}
}
+
+// WithMountAllDevices sets the option to mount all of a privileged container's
+// host devices
+func WithMountAllDevices() CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ ctr.config.MountAllDevices = true
+
+ return nil
+ }
+}
diff --git a/libpod/pod.go b/libpod/pod.go
index 3c8dc43d4..108317637 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -178,8 +178,8 @@ func (p *Pod) NetworkMode() string {
return infra.NetworkMode()
}
-// PidMode returns the PID mode given by the user ex: pod, private...
-func (p *Pod) PidMode() string {
+// Namespace Mode returns the given NS mode provided by the user ex: host, private...
+func (p *Pod) NamespaceMode(kind specs.LinuxNamespaceType) string {
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
if err != nil {
return ""
@@ -187,28 +187,7 @@ func (p *Pod) PidMode() string {
ctrSpec := infra.config.Spec
if ctrSpec != nil && ctrSpec.Linux != nil {
for _, ns := range ctrSpec.Linux.Namespaces {
- if ns.Type == specs.PIDNamespace {
- if ns.Path != "" {
- return fmt.Sprintf("ns:%s", ns.Path)
- }
- return "private"
- }
- }
- return "host"
- }
- return ""
-}
-
-// PidMode returns the PID mode given by the user ex: pod, private...
-func (p *Pod) UserNSMode() string {
- infra, err := p.infraContainer()
- if err != nil {
- return ""
- }
- ctrSpec := infra.config.Spec
- if ctrSpec != nil && ctrSpec.Linux != nil {
- for _, ns := range ctrSpec.Linux.Namespaces {
- if ns.Type == specs.UserNamespace {
+ if ns.Type == kind {
if ns.Path != "" {
return fmt.Sprintf("ns:%s", ns.Path)
}
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index 1c1e15984..fefe0e329 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/parallel"
"github.com/containers/podman/v4/pkg/rootless"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -673,8 +674,8 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
infraConfig.CPUPeriod = p.CPUPeriod()
infraConfig.CPUQuota = p.CPUQuota()
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
- infraConfig.PidNS = p.PidMode()
- infraConfig.UserNS = p.UserNSMode()
+ infraConfig.PidNS = p.NamespaceMode(specs.PIDNamespace)
+ infraConfig.UserNS = p.NamespaceMode(specs.UserNamespace)
namedVolumes, mounts := infra.SortUserVolumes(infra.config.Spec)
inspectMounts, err = infra.GetMounts(namedVolumes, infra.config.ImageVolumes, mounts)
infraSecurity = infra.GetSecurityOptions()
diff --git a/libpod/reset.go b/libpod/reset.go
index 28d0ee3f6..30eab50fb 100644
--- a/libpod/reset.go
+++ b/libpod/reset.go
@@ -17,8 +17,78 @@ import (
"github.com/sirupsen/logrus"
)
+// removeAllDirs removes all Podman storage directories. It is intended to be
+// used as a backup for reset() when that function cannot be used due to
+// failures in initializing libpod.
+// It does not expect that all the directories match what is in use by Podman,
+// as this is a common failure point for `system reset`. As such, our ability to
+// interface with containers and pods is somewhat limited.
+// This function assumes that we do not have a working c/storage store.
+func (r *Runtime) removeAllDirs() error {
+ var lastErr error
+
+ // Grab the runtime alive lock.
+ // This ensures that no other Podman process can run while we are doing
+ // a reset, so no race conditions with containers/pods/etc being created
+ // while we are resetting storage.
+ // TODO: maybe want a helper for getting the path? This is duped from
+ // runtime.go
+ runtimeAliveLock := filepath.Join(r.config.Engine.TmpDir, "alive.lck")
+ aliveLock, err := storage.GetLockfile(runtimeAliveLock)
+ if err != nil {
+ logrus.Errorf("Lock runtime alive lock %s: %v", runtimeAliveLock, err)
+ } else {
+ aliveLock.Lock()
+ defer aliveLock.Unlock()
+ }
+
+ // We do not have a store - so we can't really try and remove containers
+ // or pods or volumes...
+ // Try and remove the directories, in hopes that they are unmounted.
+ // This is likely to fail but it's the best we can do.
+
+ // Volume path
+ if err := os.RemoveAll(r.config.Engine.VolumePath); err != nil {
+ lastErr = errors.Wrapf(err, "removing volume path")
+ }
+
+ // Tmpdir
+ if err := os.RemoveAll(r.config.Engine.TmpDir); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Reset: %v", lastErr)
+ }
+ lastErr = errors.Wrapf(err, "removing tmp dir")
+ }
+
+ // Runroot
+ if err := os.RemoveAll(r.storageConfig.RunRoot); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Reset: %v", lastErr)
+ }
+ lastErr = errors.Wrapf(err, "removing run root")
+ }
+
+ // Static dir
+ if err := os.RemoveAll(r.config.Engine.StaticDir); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Reset: %v", lastErr)
+ }
+ lastErr = errors.Wrapf(err, "removing static dir")
+ }
+
+ // Graph root
+ if err := os.RemoveAll(r.storageConfig.GraphRoot); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Reset: %v", lastErr)
+ }
+ lastErr = errors.Wrapf(err, "removing graph root")
+ }
+
+ return lastErr
+}
+
// Reset removes all storage
-func (r *Runtime) Reset(ctx context.Context) error {
+func (r *Runtime) reset(ctx context.Context) error {
var timeout *uint
pods, err := r.GetAllPods()
if err != nil {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index e268c2d17..6c8a99846 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -96,6 +96,10 @@ type Runtime struct {
// This bool is just needed so that we can set it for netavark interface.
syslog bool
+ // doReset indicates that the runtime should perform a system reset.
+ // All Podman files will be removed.
+ doReset bool
+
// doRenumber indicates that the runtime should perform a lock renumber
// during initialization.
// Once the runtime has been initialized and returned, this variable is
@@ -235,6 +239,11 @@ func newRuntimeFromConfig(conf *config.Config, options ...RuntimeOption) (*Runti
runtime.config.CheckCgroupsAndAdjustConfig()
+ // If resetting storage, do *not* return a runtime.
+ if runtime.doReset {
+ return nil, nil
+ }
+
return runtime, nil
}
@@ -305,6 +314,13 @@ func makeRuntime(runtime *Runtime) (retErr error) {
}
runtime.conmonPath = cPath
+ if runtime.noStore && runtime.doReset {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot perform system reset if runtime is not creating a store")
+ }
+ if runtime.doReset && runtime.doRenumber {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot perform system reset while renumbering locks")
+ }
+
// Make the static files directory if it does not exist
if err := os.MkdirAll(runtime.config.Engine.StaticDir, 0700); err != nil {
// The directory is allowed to exist
@@ -339,6 +355,20 @@ func makeRuntime(runtime *Runtime) (retErr error) {
// Grab config from the database so we can reset some defaults
dbConfig, err := runtime.state.GetDBConfig()
if err != nil {
+ if runtime.doReset {
+ // We can at least delete the DB and the static files
+ // directory.
+ // Can't safely touch anything else because we aren't
+ // sure of other directories.
+ if err := runtime.state.Close(); err != nil {
+ logrus.Errorf("Closing database connection: %v", err)
+ } else {
+ if err := os.RemoveAll(runtime.config.Engine.StaticDir); err != nil {
+ logrus.Errorf("Removing static files directory %v: %v", runtime.config.Engine.StaticDir, err)
+ }
+ }
+ }
+
return errors.Wrapf(err, "error retrieving runtime configuration from database")
}
@@ -372,7 +402,13 @@ func makeRuntime(runtime *Runtime) (retErr error) {
// Validate our config against the database, now that we've set our
// final storage configuration
if err := runtime.state.ValidateDBConfig(runtime); err != nil {
- return err
+ // If we are performing a storage reset: continue on with a
+ // warning. Otherwise we can't `system reset` after a change to
+ // the core paths.
+ if !runtime.doReset {
+ return err
+ }
+ logrus.Errorf("Runtime paths differ from those stored in database, storage reset may not remove all files")
}
if err := runtime.state.SetNamespace(runtime.config.Engine.Namespace); err != nil {
@@ -394,6 +430,14 @@ func makeRuntime(runtime *Runtime) (retErr error) {
} else if runtime.noStore {
logrus.Debug("No store required. Not opening container store.")
} else if err := runtime.configureStore(); err != nil {
+ // Make a best-effort attempt to clean up if performing a
+ // storage reset.
+ if runtime.doReset {
+ if err := runtime.removeAllDirs(); err != nil {
+ logrus.Errorf("Removing libpod directories: %v", err)
+ }
+ }
+
return err
}
defer func() {
@@ -575,6 +619,18 @@ func makeRuntime(runtime *Runtime) (retErr error) {
return err
}
+ // If we're resetting storage, do it now.
+ // We will not return a valid runtime.
+ // TODO: Plumb this context out so it can be set.
+ if runtime.doReset {
+ // Mark the runtime as valid, so normal functionality "mostly"
+ // works and we can use regular functions to remove
+ // ctrs/pods/etc
+ runtime.valid = true
+
+ return runtime.reset(context.Background())
+ }
+
// If we're renumbering locks, do it now.
// It breaks out of normal runtime init, and will not return a valid
// runtime.
@@ -818,7 +874,7 @@ func (r *Runtime) DeferredShutdown(force bool) {
// still containers running or mounted
func (r *Runtime) Shutdown(force bool) error {
if !r.valid {
- return define.ErrRuntimeStopped
+ return nil
}
if r.workerChannel != nil {
@@ -1067,7 +1123,7 @@ func (r *Runtime) mergeDBConfig(dbConfig *DBConfig) {
if !r.storageSet.GraphDriverNameSet && dbConfig.GraphDriver != "" {
if r.storageConfig.GraphDriverName != dbConfig.GraphDriver &&
r.storageConfig.GraphDriverName != "" {
- logrus.Errorf("User-selected graph driver %q overwritten by graph driver %q from database - delete libpod local files to resolve",
+ logrus.Errorf("User-selected graph driver %q overwritten by graph driver %q from database - delete libpod local files to resolve. May prevent use of images created by other tools",
r.storageConfig.GraphDriverName, dbConfig.GraphDriver)
}
r.storageConfig.GraphDriverName = dbConfig.GraphDriver
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index b9b7f6708..67ec52047 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -261,8 +261,13 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C
}
}
- // netMode
- nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{string(cc.HostConfig.NetworkMode)})
+ // special case for NetworkMode, the podman default is slirp4netns for
+ // rootless but for better docker compat we want bridge.
+ netmode := string(cc.HostConfig.NetworkMode)
+ if netmode == "" || netmode == "default" {
+ netmode = "bridge"
+ }
+ nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{netmode})
if err != nil {
return nil, nil, err
}
@@ -278,6 +283,7 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C
Network: nsmode,
PublishPorts: specPorts,
NetworkOptions: netOpts,
+ NoHosts: rtc.Containers.NoHosts,
}
// network names
@@ -438,7 +444,7 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C
cliOpts.Volume = append(cliOpts.Volume, vol)
// Extract the destination so we don't add duplicate mounts in
// the volumes phase.
- splitVol := strings.SplitN(vol, ":", 3)
+ splitVol := specgen.SplitVolumeString(vol)
switch len(splitVol) {
case 1:
volDestinations[vol] = true
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index f47aa523e..fe17aa1d4 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -70,68 +70,69 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}()
query := struct {
- AddHosts string `schema:"extrahosts"`
- AdditionalCapabilities string `schema:"addcaps"`
- AllPlatforms bool `schema:"allplatforms"`
- Annotations string `schema:"annotations"`
- AppArmor string `schema:"apparmor"`
- BuildArgs string `schema:"buildargs"`
- CacheFrom string `schema:"cachefrom"`
- CgroupParent string `schema:"cgroupparent"` // nolint
- Compression uint64 `schema:"compression"`
- ConfigureNetwork string `schema:"networkmode"`
- CPPFlags string `schema:"cppflags"`
- CpuPeriod uint64 `schema:"cpuperiod"` // nolint
- CpuQuota int64 `schema:"cpuquota"` // nolint
- CpuSetCpus string `schema:"cpusetcpus"` // nolint
- CpuSetMems string `schema:"cpusetmems"` // nolint
- CpuShares uint64 `schema:"cpushares"` // nolint
- DNSOptions string `schema:"dnsoptions"`
- DNSSearch string `schema:"dnssearch"`
- DNSServers string `schema:"dnsservers"`
- Devices string `schema:"devices"`
- Dockerfile string `schema:"dockerfile"`
- DropCapabilities string `schema:"dropcaps"`
- Envs []string `schema:"setenv"`
- Excludes string `schema:"excludes"`
- ForceRm bool `schema:"forcerm"`
- From string `schema:"from"`
- HTTPProxy bool `schema:"httpproxy"`
- IdentityLabel bool `schema:"identitylabel"`
- Ignore bool `schema:"ignore"`
- Isolation string `schema:"isolation"`
- Jobs int `schema:"jobs"` // nolint
- LabelOpts string `schema:"labelopts"`
- Labels string `schema:"labels"`
- Layers bool `schema:"layers"`
- LogRusage bool `schema:"rusage"`
- Manifest string `schema:"manifest"`
- MemSwap int64 `schema:"memswap"`
- Memory int64 `schema:"memory"`
- NamespaceOptions string `schema:"nsoptions"`
- NoCache bool `schema:"nocache"`
- OSFeatures []string `schema:"osfeature"`
- OSVersion string `schema:"osversion"`
- OutputFormat string `schema:"outputformat"`
- Platform []string `schema:"platform"`
- Pull bool `schema:"pull"`
- PullPolicy string `schema:"pullpolicy"`
- Quiet bool `schema:"q"`
- Registry string `schema:"registry"`
- Rm bool `schema:"rm"`
- RusageLogFile string `schema:"rusagelogfile"`
- Remote string `schema:"remote"`
- Seccomp string `schema:"seccomp"`
- Secrets string `schema:"secrets"`
- SecurityOpt string `schema:"securityopt"`
- ShmSize int `schema:"shmsize"`
- Squash bool `schema:"squash"`
- TLSVerify bool `schema:"tlsVerify"`
- Tags []string `schema:"t"`
- Target string `schema:"target"`
- Timestamp int64 `schema:"timestamp"`
- Ulimits string `schema:"ulimits"`
- UnsetEnvs []string `schema:"unsetenv"`
+ AddHosts string `schema:"extrahosts"`
+ AdditionalCapabilities string `schema:"addcaps"`
+ AdditionalBuildContexts string `schema:"additionalbuildcontexts"`
+ AllPlatforms bool `schema:"allplatforms"`
+ Annotations string `schema:"annotations"`
+ AppArmor string `schema:"apparmor"`
+ BuildArgs string `schema:"buildargs"`
+ CacheFrom string `schema:"cachefrom"`
+ CgroupParent string `schema:"cgroupparent"` // nolint
+ Compression uint64 `schema:"compression"`
+ ConfigureNetwork string `schema:"networkmode"`
+ CPPFlags string `schema:"cppflags"`
+ CpuPeriod uint64 `schema:"cpuperiod"` // nolint
+ CpuQuota int64 `schema:"cpuquota"` // nolint
+ CpuSetCpus string `schema:"cpusetcpus"` // nolint
+ CpuSetMems string `schema:"cpusetmems"` // nolint
+ CpuShares uint64 `schema:"cpushares"` // nolint
+ DNSOptions string `schema:"dnsoptions"`
+ DNSSearch string `schema:"dnssearch"`
+ DNSServers string `schema:"dnsservers"`
+ Devices string `schema:"devices"`
+ Dockerfile string `schema:"dockerfile"`
+ DropCapabilities string `schema:"dropcaps"`
+ Envs []string `schema:"setenv"`
+ Excludes string `schema:"excludes"`
+ ForceRm bool `schema:"forcerm"`
+ From string `schema:"from"`
+ HTTPProxy bool `schema:"httpproxy"`
+ IdentityLabel bool `schema:"identitylabel"`
+ Ignore bool `schema:"ignore"`
+ Isolation string `schema:"isolation"`
+ Jobs int `schema:"jobs"` // nolint
+ LabelOpts string `schema:"labelopts"`
+ Labels string `schema:"labels"`
+ Layers bool `schema:"layers"`
+ LogRusage bool `schema:"rusage"`
+ Manifest string `schema:"manifest"`
+ MemSwap int64 `schema:"memswap"`
+ Memory int64 `schema:"memory"`
+ NamespaceOptions string `schema:"nsoptions"`
+ NoCache bool `schema:"nocache"`
+ OSFeatures []string `schema:"osfeature"`
+ OSVersion string `schema:"osversion"`
+ OutputFormat string `schema:"outputformat"`
+ Platform []string `schema:"platform"`
+ Pull bool `schema:"pull"`
+ PullPolicy string `schema:"pullpolicy"`
+ Quiet bool `schema:"q"`
+ Registry string `schema:"registry"`
+ Rm bool `schema:"rm"`
+ RusageLogFile string `schema:"rusagelogfile"`
+ Remote string `schema:"remote"`
+ Seccomp string `schema:"seccomp"`
+ Secrets string `schema:"secrets"`
+ SecurityOpt string `schema:"securityopt"`
+ ShmSize int `schema:"shmsize"`
+ Squash bool `schema:"squash"`
+ TLSVerify bool `schema:"tlsVerify"`
+ Tags []string `schema:"t"`
+ Target string `schema:"target"`
+ Timestamp int64 `schema:"timestamp"`
+ Ulimits string `schema:"ulimits"`
+ UnsetEnvs []string `schema:"unsetenv"`
}{
Dockerfile: "Dockerfile",
IdentityLabel: true,
@@ -375,6 +376,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
additionalTags = append(additionalTags, possiblyNormalizedTag)
}
+ var additionalBuildContexts = map[string]*buildahDefine.AdditionalBuildContext{}
+ if _, found := r.URL.Query()["additionalbuildcontexts"]; found {
+ if err := json.Unmarshal([]byte(query.AdditionalBuildContexts), &additionalBuildContexts); err != nil {
+ utils.BadRequest(w, "additionalbuildcontexts", query.AdditionalBuildContexts, err)
+ return
+ }
+ }
+
var buildArgs = map[string]string{}
if _, found := r.URL.Query()["buildargs"]; found {
if err := json.Unmarshal([]byte(query.BuildArgs), &buildArgs); err != nil {
@@ -562,12 +571,13 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
buildOptions := buildahDefine.BuildOptions{
- AddCapabilities: addCaps,
- AdditionalTags: additionalTags,
- Annotations: annotations,
- CPPFlags: cppflags,
- Args: buildArgs,
- AllPlatforms: query.AllPlatforms,
+ AddCapabilities: addCaps,
+ AdditionalBuildContexts: additionalBuildContexts,
+ AdditionalTags: additionalTags,
+ Annotations: annotations,
+ CPPFlags: cppflags,
+ Args: buildArgs,
+ AllPlatforms: query.AllPlatforms,
CommonBuildOpts: &buildah.CommonBuildOptions{
AddHost: addhosts,
ApparmorProfile: apparmor,
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index 65b9d6cb5..d9ed1c265 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -163,7 +163,6 @@ func ManifestAddV3(w http.ResponseWriter, r *http.Request) {
// Wrapper to support 3.x with 4.x libpod
query := struct {
entities.ManifestAddOptions
- Images []string
TLSVerify bool `schema:"tlsVerify"`
}{}
if err := json.NewDecoder(r.Body).Decode(&query); err != nil {
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index b71afc28c..36e61c986 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -77,7 +77,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
utils.Error(w, http.StatusInternalServerError, err)
return
}
- query.LogDriver = config.Containers.LogDriver
+ logDriver = config.Containers.LogDriver
}
containerEngine := abi.ContainerEngine{Libpod: runtime}
@@ -89,7 +89,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
Networks: query.Network,
NoHosts: query.NoHosts,
Quiet: true,
- LogDriver: query.LogDriver,
+ LogDriver: logDriver,
LogOptions: query.LogOptions,
StaticIPs: staticIPs,
StaticMACs: staticMACs,
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index b4b7c36f6..fe81dc662 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -81,6 +81,13 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
for _, tag := range options.AdditionalTags {
params.Add("t", tag)
}
+ if additionalBuildContexts := options.AdditionalBuildContexts; len(additionalBuildContexts) > 0 {
+ additionalBuildContextMap, err := jsoniter.Marshal(additionalBuildContexts)
+ if err != nil {
+ return nil, err
+ }
+ params.Set("additionalbuildcontexts", string(additionalBuildContextMap))
+ }
if buildArgs := options.Args; len(buildArgs) > 0 {
bArgs, err := jsoniter.MarshalToString(buildArgs)
if err != nil {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index d2fafccb1..8bd84a310 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -616,6 +616,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
ImportPrevious: options.ImportPrevious,
Pod: options.Pod,
PrintStats: options.PrintStats,
+ FileLocks: options.FileLocks,
}
filterFuncs := []libpod.ContainerFilter{
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 2ce190464..762f0d79a 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -328,7 +328,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
}
func (se *SystemEngine) Reset(ctx context.Context) error {
- return se.Libpod.Reset(ctx)
+ return nil
}
func (se *SystemEngine) Renumber(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig) error {
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index 39989c96b..7b5198d2f 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -53,7 +53,7 @@ func NewSystemEngine(setup entities.EngineSetup, facts *entities.PodmanConfig) (
case entities.RenumberMode:
r, err = GetRuntimeRenumber(context.Background(), facts.FlagSet, facts)
case entities.ResetMode:
- r, err = GetRuntimeRenumber(context.Background(), facts.FlagSet, facts)
+ r, err = GetRuntimeReset(context.Background(), facts.FlagSet, facts)
case entities.MigrateMode:
name, flagErr := facts.FlagSet.GetString("new-runtime")
if flagErr != nil {
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index ac557e9de..03e7ffb5d 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -9,9 +9,9 @@ import (
"os"
"os/signal"
"sync"
+ "syscall"
"github.com/containers/common/pkg/cgroups"
- "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/namespaces"
@@ -37,6 +37,7 @@ type engineOpts struct {
migrate bool
noStore bool
withFDS bool
+ reset bool
config *entities.PodmanConfig
}
@@ -48,6 +49,7 @@ func GetRuntimeMigrate(ctx context.Context, fs *flag.FlagSet, cfg *entities.Podm
migrate: true,
noStore: false,
withFDS: true,
+ reset: false,
config: cfg,
})
}
@@ -59,6 +61,7 @@ func GetRuntimeDisableFDs(ctx context.Context, fs *flag.FlagSet, cfg *entities.P
migrate: false,
noStore: false,
withFDS: false,
+ reset: false,
config: cfg,
})
}
@@ -70,6 +73,7 @@ func GetRuntimeRenumber(ctx context.Context, fs *flag.FlagSet, cfg *entities.Pod
migrate: false,
noStore: false,
withFDS: true,
+ reset: false,
config: cfg,
})
}
@@ -82,6 +86,7 @@ func GetRuntime(ctx context.Context, flags *flag.FlagSet, cfg *entities.PodmanCo
migrate: false,
noStore: false,
withFDS: true,
+ reset: false,
config: cfg,
})
})
@@ -95,6 +100,18 @@ func GetRuntimeNoStore(ctx context.Context, fs *flag.FlagSet, cfg *entities.Podm
migrate: false,
noStore: true,
withFDS: true,
+ reset: false,
+ config: cfg,
+ })
+}
+
+func GetRuntimeReset(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) {
+ return getRuntime(ctx, fs, &engineOpts{
+ renumber: false,
+ migrate: false,
+ noStore: false,
+ withFDS: true,
+ reset: true,
config: cfg,
})
}
@@ -161,6 +178,10 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
}
}
+ if opts.reset {
+ options = append(options, libpod.WithReset())
+ }
+
if opts.renumber {
options = append(options, libpod.WithRenumber())
}
@@ -375,7 +396,7 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
func StartWatcher(rt *libpod.Runtime) {
// Setup the signal notifier
ch := make(chan os.Signal, 1)
- signal.Notify(ch, utils.SIGHUP)
+ signal.Notify(ch, syscall.SIGHUP)
go func() {
for {
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index d34776714..fcc129338 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -42,7 +42,9 @@ const (
// Running indicates the qemu vm is running.
Running Status = "running"
// Stopped indicates the vm has stopped.
- Stopped Status = "stopped"
+ Stopped Status = "stopped"
+ // Starting indicated the vm is in the process of starting
+ Starting Status = "starting"
DefaultMachineName string = "podman-machine-default"
)
@@ -62,7 +64,7 @@ var (
DefaultIgnitionUserName = "core"
ErrNoSuchVM = errors.New("VM does not exist")
ErrVMAlreadyExists = errors.New("VM already exists")
- ErrVMAlreadyRunning = errors.New("VM already running")
+ ErrVMAlreadyRunning = errors.New("VM already running or starting")
ErrMultipleActiveVM = errors.New("only one VM can be active at a time")
ForwarderBinaryName = "gvproxy"
)
@@ -88,6 +90,7 @@ type ListResponse struct {
CreatedAt time.Time
LastUp time.Time
Running bool
+ Starting bool
Stream string
VMType string
CPUs uint64
@@ -138,14 +141,15 @@ type DistributionDownload interface {
Get() *Download
}
type InspectInfo struct {
- ConfigPath VMFile
- Created time.Time
- Image ImageConfig
- LastUp time.Time
- Name string
- Resources ResourceConfig
- SSHConfig SSHConfig
- State Status
+ ConfigPath VMFile
+ ConnectionInfo ConnectionConfig
+ Created time.Time
+ Image ImageConfig
+ LastUp time.Time
+ Name string
+ Resources ResourceConfig
+ SSHConfig SSHConfig
+ State Status
}
func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL {
@@ -286,11 +290,11 @@ func NewMachineFile(path string, symlink *string) (*VMFile, error) {
// makeSymlink for macOS creates a symlink in $HOME/.podman/
// for a machinefile like a socket
func (m *VMFile) makeSymlink(symlink *string) error {
- homedir, err := os.UserHomeDir()
+ homeDir, err := os.UserHomeDir()
if err != nil {
return err
}
- sl := filepath.Join(homedir, ".podman", *symlink)
+ sl := filepath.Join(homeDir, ".podman", *symlink)
// make the symlink dir and throw away if it already exists
if err := os.MkdirAll(filepath.Dir(sl), 0700); err != nil && !errors2.Is(err, os.ErrNotExist) {
return err
@@ -335,3 +339,9 @@ type SSHConfig struct {
// RemoteUsername of the vm user
RemoteUsername string
}
+
+// ConnectionConfig contains connections like sockets, etc.
+type ConnectionConfig struct {
+ // PodmanSocket is the exported podman service socket
+ PodmanSocket *VMFile `json:"PodmanSocket"`
+}
diff --git a/pkg/machine/e2e/config.go b/pkg/machine/e2e/config.go
index c17b840d3..248a2f0ad 100644
--- a/pkg/machine/e2e/config.go
+++ b/pkg/machine/e2e/config.go
@@ -85,6 +85,14 @@ func (ms *machineSession) outputToString() string {
return strings.Join(fields, " ")
}
+// errorToString returns the error output from a session in string form
+func (ms *machineSession) errorToString() string {
+ if ms == nil || ms.Err == nil || ms.Err.Contents() == nil {
+ return ""
+ }
+ return string(ms.Err.Contents())
+}
+
// newMB constructor for machine test builders
func newMB() (*machineTestBuilder, error) {
mb := machineTestBuilder{
diff --git a/pkg/machine/e2e/inspect_test.go b/pkg/machine/e2e/inspect_test.go
index 2c9de5664..cdf13bb1a 100644
--- a/pkg/machine/e2e/inspect_test.go
+++ b/pkg/machine/e2e/inspect_test.go
@@ -2,6 +2,7 @@ package e2e
import (
"encoding/json"
+ "strings"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/qemu"
@@ -86,6 +87,7 @@ var _ = Describe("podman machine stop", func() {
var inspectInfo []machine.InspectInfo
err = jsoniter.Unmarshal(inspectSession.Bytes(), &inspectInfo)
Expect(err).To(BeNil())
+ Expect(strings.HasSuffix(inspectInfo[0].ConnectionInfo.PodmanSocket.GetPath(), "podman.sock"))
inspect := new(inspectMachine)
inspect = inspect.withFormat("{{.Name}}")
diff --git a/pkg/machine/e2e/ssh_test.go b/pkg/machine/e2e/ssh_test.go
index 155d39a64..9ee31ac26 100644
--- a/pkg/machine/e2e/ssh_test.go
+++ b/pkg/machine/e2e/ssh_test.go
@@ -56,5 +56,12 @@ var _ = Describe("podman machine ssh", func() {
Expect(err).To(BeNil())
Expect(sshSession).To(Exit(0))
Expect(sshSession.outputToString()).To(ContainSubstring("Fedora CoreOS"))
+
+ // keep exit code
+ sshSession, err = mb.setName(name).setCmd(ssh.withSSHComand([]string{"false"})).run()
+ Expect(err).To(BeNil())
+ Expect(sshSession).To(Exit(1))
+ Expect(sshSession.outputToString()).To(Equal(""))
+ Expect(sshSession.errorToString()).To(Equal(""))
})
})
diff --git a/pkg/machine/fcos.go b/pkg/machine/fcos.go
index df58b8a1e..77427139a 100644
--- a/pkg/machine/fcos.go
+++ b/pkg/machine/fcos.go
@@ -146,13 +146,6 @@ func GetFCOSDownload(imageStream string) (*FcosDownloadInfo, error) { //nolint:s
streamType string
)
- // This is being hard set to testing. Once podman4 is in the
- // fcos trees, we should remove it and re-release at least on
- // macs.
- // TODO: remove when podman4.0 is in coreos
-
- imageStream = "podman-testing" //nolint:staticcheck
-
switch imageStream {
case "podman-testing":
streamType = "podman-testing"
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index e3fb3b970..1b0d63986 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -831,8 +831,14 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
if err != nil {
return "", nil, err
}
- if state == machine.Running && !opts.Force {
- return "", nil, errors.Errorf("running vm %q cannot be destroyed", v.Name)
+ if state == machine.Running {
+ if !opts.Force {
+ return "", nil, errors.Errorf("running vm %q cannot be destroyed", v.Name)
+ }
+ err := v.Stop(v.Name, machine.StopOptions{})
+ if err != nil {
+ return "", nil, err
+ }
}
// Collect all the files that need to be destroyed
@@ -904,7 +910,7 @@ func (v *MachineVM) State(bypass bool) (machine.Status, error) {
}
// Check if we can dial it
if v.Starting && !bypass {
- return "", nil
+ return machine.Starting, nil
}
monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
if err != nil {
@@ -952,7 +958,8 @@ func (v *MachineVM) SSH(_ string, opts machine.SSHOptions) error {
sshDestination := username + "@localhost"
port := strconv.Itoa(v.Port)
- args := []string{"-i", v.IdentityPath, "-p", port, sshDestination, "-o", "UserKnownHostsFile=/dev/null", "-o", "StrictHostKeyChecking=no"}
+ args := []string{"-i", v.IdentityPath, "-p", port, sshDestination, "-o", "UserKnownHostsFile=/dev/null",
+ "-o", "StrictHostKeyChecking=no", "-o", "LogLevel=ERROR"}
if len(opts.Args) > 0 {
args = append(args, opts.Args...)
} else {
@@ -1074,8 +1081,11 @@ func getVMInfos() ([]*machine.ListResponse, error) {
return err
}
}
- if state == machine.Running {
+ switch state {
+ case machine.Running:
listEntry.Running = true
+ case machine.Starting:
+ listEntry.Starting = true
}
listed = append(listed, listEntry)
@@ -1108,7 +1118,7 @@ func (p *Provider) CheckExclusiveActiveVM() (bool, string, error) {
return false, "", errors.Wrap(err, "error checking VM active")
}
for _, vm := range vms {
- if vm.Running {
+ if vm.Running || vm.Starting {
return true, vm.Name, nil
}
}
@@ -1471,16 +1481,22 @@ func (v *MachineVM) Inspect() (*machine.InspectInfo, error) {
if err != nil {
return nil, err
}
-
+ connInfo := new(machine.ConnectionConfig)
+ podmanSocket, err := v.forwardSocketPath()
+ if err != nil {
+ return nil, err
+ }
+ connInfo.PodmanSocket = podmanSocket
return &machine.InspectInfo{
- ConfigPath: v.ConfigPath,
- Created: v.Created,
- Image: v.ImageConfig,
- LastUp: v.LastUp,
- Name: v.Name,
- Resources: v.ResourceConfig,
- SSHConfig: v.SSHConfig,
- State: state,
+ ConfigPath: v.ConfigPath,
+ ConnectionInfo: *connInfo,
+ Created: v.Created,
+ Image: v.ImageConfig,
+ LastUp: v.LastUp,
+ Name: v.Name,
+ Resources: v.ResourceConfig,
+ SSHConfig: v.SSHConfig,
+ State: state,
}, nil
}
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 06020aded..075f42cb2 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -1312,6 +1312,7 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
listEntry.RemoteUsername = vm.RemoteUsername
listEntry.Port = vm.Port
listEntry.IdentityPath = vm.IdentityPath
+ listEntry.Starting = false
running := vm.isRunning()
listEntry.CreatedAt, listEntry.LastUp, _ = vm.updateTimeStamps(running)
diff --git a/pkg/resolvconf/dns/resolvconf.go b/pkg/resolvconf/dns/resolvconf.go
deleted file mode 100644
index cb4bd1033..000000000
--- a/pkg/resolvconf/dns/resolvconf.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Originally from github.com/docker/libnetwork/resolvconf/dns
-
-package dns
-
-import (
- "regexp"
-)
-
-// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
-const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
-
-// IPv4Localhost is a regex pattern for IPv4 localhost address range.
-const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})`
-
-var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
-var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
-
-// IsLocalhost returns true if ip matches the localhost IP regular expression.
-// Used for determining if nameserver settings are being passed which are
-// localhost addresses
-func IsLocalhost(ip string) bool {
- return localhostIPRegexp.MatchString(ip)
-}
-
-// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
-func IsIPv4Localhost(ip string) bool {
- return localhostIPv4Regexp.MatchString(ip)
-}
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index 532a2094f..5616a4511 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -183,10 +183,12 @@ func (s *SpecGenerator) Validate() error {
}
// Set defaults if network info is not provided
- if s.NetNS.NSMode == "" {
- s.NetNS.NSMode = Bridge
+ // when we are rootless we default to slirp4netns
+ if s.NetNS.IsPrivate() || s.NetNS.IsDefault() {
if rootless.IsRootless() {
s.NetNS.NSMode = Slirp
+ } else {
+ s.NetNS.NSMode = Bridge
}
}
if err := validateNetNS(&s.NetNS); err != nil {
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index ed2e5408d..4c3748e67 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -3,7 +3,6 @@ package generate
import (
"fmt"
"io/fs"
- "io/ioutil"
"os"
"path"
"path/filepath"
@@ -11,6 +10,7 @@ import (
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/rootless"
+ "github.com/containers/podman/v4/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
@@ -18,56 +18,6 @@ import (
"golang.org/x/sys/unix"
)
-var (
- errNotADevice = errors.New("not a device node")
-)
-
-func addPrivilegedDevices(g *generate.Generator) error {
- hostDevices, err := getDevices("/dev")
- if err != nil {
- return err
- }
- g.ClearLinuxDevices()
-
- if rootless.IsRootless() {
- mounts := make(map[string]interface{})
- for _, m := range g.Mounts() {
- mounts[m.Destination] = true
- }
- newMounts := []spec.Mount{}
- for _, d := range hostDevices {
- devMnt := spec.Mount{
- Destination: d.Path,
- Type: define.TypeBind,
- Source: d.Path,
- Options: []string{"slave", "nosuid", "noexec", "rw", "rbind"},
- }
- if d.Path == "/dev/ptmx" || strings.HasPrefix(d.Path, "/dev/tty") {
- continue
- }
- if _, found := mounts[d.Path]; found {
- continue
- }
- newMounts = append(newMounts, devMnt)
- }
- g.Config.Mounts = append(newMounts, g.Config.Mounts...)
- if g.Config.Linux.Resources != nil {
- g.Config.Linux.Resources.Devices = nil
- }
- } else {
- for _, d := range hostDevices {
- g.AddDevice(d)
- }
- // Add resources device - need to clear the existing one first.
- if g.Config.Linux.Resources != nil {
- g.Config.Linux.Resources.Devices = nil
- }
- g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
- }
-
- return nil
-}
-
// DevicesFromPath computes a list of devices
func DevicesFromPath(g *generate.Generator, devicePath string) error {
devs := strings.Split(devicePath, ":")
@@ -174,60 +124,12 @@ func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, mask, unmask
}
}
-// based on getDevices from runc (libcontainer/devices/devices.go)
-func getDevices(path string) ([]spec.LinuxDevice, error) {
- files, err := ioutil.ReadDir(path)
- if err != nil {
- if rootless.IsRootless() && os.IsPermission(err) {
- return nil, nil
- }
- return nil, err
- }
- out := []spec.LinuxDevice{}
- for _, f := range files {
- switch {
- case f.IsDir():
- switch f.Name() {
- // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
- case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
- continue
- default:
- sub, err := getDevices(filepath.Join(path, f.Name()))
- if err != nil {
- return nil, err
- }
- if sub != nil {
- out = append(out, sub...)
- }
- continue
- }
- case f.Name() == "console":
- continue
- case f.Mode()&os.ModeSymlink != 0:
- continue
- }
-
- device, err := deviceFromPath(filepath.Join(path, f.Name()))
- if err != nil {
- if err == errNotADevice {
- continue
- }
- if os.IsNotExist(err) {
- continue
- }
- return nil, err
- }
- out = append(out, *device)
- }
- return out, nil
-}
-
func addDevice(g *generate.Generator, device string) error {
src, dst, permissions, err := ParseDevice(device)
if err != nil {
return err
}
- dev, err := deviceFromPath(src)
+ dev, err := util.DeviceFromPath(src)
if err != nil {
return errors.Wrapf(err, "%s is not a valid device", src)
}
@@ -316,43 +218,6 @@ func IsValidDeviceMode(mode string) bool {
return true
}
-// Copied from github.com/opencontainers/runc/libcontainer/devices
-// Given the path to a device look up the information about a linux device
-func deviceFromPath(path string) (*spec.LinuxDevice, error) {
- var stat unix.Stat_t
- err := unix.Lstat(path, &stat)
- if err != nil {
- return nil, err
- }
- var (
- devType string
- mode = stat.Mode
- devNumber = uint64(stat.Rdev) // nolint: unconvert
- m = os.FileMode(mode)
- )
-
- switch {
- case mode&unix.S_IFBLK == unix.S_IFBLK:
- devType = "b"
- case mode&unix.S_IFCHR == unix.S_IFCHR:
- devType = "c"
- case mode&unix.S_IFIFO == unix.S_IFIFO:
- devType = "p"
- default:
- return nil, errNotADevice
- }
-
- return &spec.LinuxDevice{
- Type: devType,
- Path: path,
- FileMode: &m,
- UID: &stat.Uid,
- GID: &stat.Gid,
- Major: int64(unix.Major(devNumber)),
- Minor: int64(unix.Minor(devNumber)),
- }, nil
-}
-
func supportAmbientCapabilities() bool {
err := unix.Prctl(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, 0, 0, 0)
return err == nil
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 04e24d625..7faf13465 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -278,6 +278,10 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
options = append(options, libpod.WithPasswdEntry(s.PasswdEntry))
}
+ if s.Privileged {
+ options = append(options, libpod.WithMountAllDevices())
+ }
+
useSystemd := false
switch s.Systemd {
case "always":
@@ -542,6 +546,16 @@ func Inherit(infra libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtim
infraConf := infra.Config()
infraSpec := infraConf.Spec
+ // need to set compatOptions to the currently filled specgenOptions so we do not overwrite
+ compatibleOptions.CapAdd = append(compatibleOptions.CapAdd, s.CapAdd...)
+ compatibleOptions.CapDrop = append(compatibleOptions.CapDrop, s.CapDrop...)
+ compatibleOptions.HostDeviceList = append(compatibleOptions.HostDeviceList, s.HostDeviceList...)
+ compatibleOptions.ImageVolumes = append(compatibleOptions.ImageVolumes, s.ImageVolumes...)
+ compatibleOptions.Mounts = append(compatibleOptions.Mounts, s.Mounts...)
+ compatibleOptions.OverlayVolumes = append(compatibleOptions.OverlayVolumes, s.OverlayVolumes...)
+ compatibleOptions.SelinuxOpts = append(compatibleOptions.SelinuxOpts, s.SelinuxOpts...)
+ compatibleOptions.Volumes = append(compatibleOptions.Volumes, s.Volumes...)
+
compatByte, err := json.Marshal(compatibleOptions)
if err != nil {
return nil, nil, nil, err
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 37d561ec2..4224d16ce 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -19,6 +19,8 @@ import (
"github.com/sirupsen/logrus"
)
+const host = "host"
+
// Get the default namespace mode for any given namespace type.
func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod) (specgen.Namespace, error) {
// The default for most is private
@@ -33,16 +35,38 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
podMode := false
switch {
case nsType == "pid" && pod.SharesPID():
+ if pod.NamespaceMode(spec.PIDNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "ipc" && pod.SharesIPC():
+ if pod.NamespaceMode(spec.IPCNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "uts" && pod.SharesUTS():
+ if pod.NamespaceMode(spec.UTSNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "user" && pod.SharesUser():
+ // user does not need a special check for host, this is already validated on pod creation
+ // if --userns=host then pod.SharesUser == false
podMode = true
case nsType == "net" && pod.SharesNet():
+ if pod.NetworkMode() == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
case nsType == "cgroup" && pod.SharesCgroup():
+ if pod.NamespaceMode(spec.CgroupNamespace) == host {
+ toReturn.NSMode = specgen.Host
+ return toReturn, nil
+ }
podMode = true
}
if podMode {
@@ -236,10 +260,12 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.
toReturn = append(toReturn, libpod.WithCgroupsMode(s.CgroupsMode))
}
- // Net
- // TODO validate CNINetworks, StaticIP, StaticIPv6 are only set if we
- // are in bridge mode.
postConfigureNetNS := !s.UserNS.IsHost()
+ // when we are rootless we default to slirp4netns
+ if rootless.IsRootless() && (s.NetNS.IsPrivate() || s.NetNS.IsDefault()) {
+ s.NetNS.NSMode = specgen.Slirp
+ }
+
switch s.NetNS.NSMode {
case specgen.FromPod:
if pod == nil || infraCtr == nil {
@@ -262,9 +288,7 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.
val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value)
}
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil))
- case specgen.Private:
- fallthrough
- case specgen.Bridge:
+ case specgen.Bridge, specgen.Private, specgen.Default:
portMappings, expose, err := createPortMappings(s, imageData)
if err != nil {
return nil, err
@@ -488,10 +512,7 @@ func GetNamespaceOptions(ns []string, netnsIsHost bool) ([]libpod.PodCreateOptio
case "cgroup":
options = append(options, libpod.WithPodCgroup())
case "net":
- // share the netns setting with other containers in the pod only when it is not set to host
- if !netnsIsHost {
- options = append(options, libpod.WithPodNet())
- }
+ options = append(options, libpod.WithPodNet())
case "mnt":
return erroredOptions, errors.Errorf("Mount sharing functionality not supported on pod level")
case "pid":
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index dda2de6e4..716960024 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -337,14 +337,8 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
var userDevices []spec.LinuxDevice
- if s.Privileged {
- // If privileged, we need to add all the host devices to the
- // spec. We do not add the user provided ones because we are
- // already adding them all.
- if err := addPrivilegedDevices(&g); err != nil {
- return nil, err
- }
- } else {
+
+ if !s.Privileged {
// add default devices from containers.conf
for _, device := range rtc.Containers.Devices {
if err = DevicesFromPath(&g, device); err != nil {
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 5b7bb2b57..d4f281a11 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -141,6 +141,9 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
case specgen.Bridge:
p.InfraContainerSpec.NetNS.NSMode = specgen.Bridge
logrus.Debugf("Pod using bridge network mode")
+ case specgen.Private:
+ p.InfraContainerSpec.NetNS.NSMode = specgen.Private
+ logrus.Debugf("Pod will use default network mode")
case specgen.Host:
logrus.Debugf("Pod will use host networking")
if len(p.InfraContainerSpec.PortMappings) > 0 ||
@@ -151,15 +154,15 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
p.InfraContainerSpec.NetNS.NSMode = specgen.Host
case specgen.Slirp:
logrus.Debugf("Pod will use slirp4netns")
- if p.InfraContainerSpec.NetNS.NSMode != "host" {
+ if p.InfraContainerSpec.NetNS.NSMode != specgen.Host {
p.InfraContainerSpec.NetworkOptions = p.NetworkOptions
- p.InfraContainerSpec.NetNS.NSMode = specgen.NamespaceMode("slirp4netns")
+ p.InfraContainerSpec.NetNS.NSMode = specgen.Slirp
}
case specgen.NoNetwork:
logrus.Debugf("Pod will not use networking")
if len(p.InfraContainerSpec.PortMappings) > 0 ||
len(p.InfraContainerSpec.Networks) > 0 ||
- p.InfraContainerSpec.NetNS.NSMode == "host" {
+ p.InfraContainerSpec.NetNS.NSMode == specgen.Host {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot disable pod network if network-related configuration is specified")
}
p.InfraContainerSpec.NetNS.NSMode = specgen.NoNetwork
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index 5a3b94ca4..f1343f6e2 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -10,7 +10,6 @@ import (
"github.com/containers/common/pkg/cgroups"
cutil "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/libpod/define"
- "github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -319,62 +318,6 @@ func ParseUserNamespace(ns string) (Namespace, error) {
return ParseNamespace(ns)
}
-// ParseNetworkNamespace parses a network namespace specification in string
-// form.
-// Returns a namespace and (optionally) a list of CNI networks to join.
-func ParseNetworkNamespace(ns string, rootlessDefaultCNI bool) (Namespace, map[string]types.PerNetworkOptions, error) {
- toReturn := Namespace{}
- networks := make(map[string]types.PerNetworkOptions)
- // Net defaults to Slirp on rootless
- switch {
- case ns == string(Slirp), strings.HasPrefix(ns, string(Slirp)+":"):
- toReturn.NSMode = Slirp
- case ns == string(FromPod):
- toReturn.NSMode = FromPod
- case ns == "" || ns == string(Default) || ns == string(Private):
- if rootless.IsRootless() {
- if rootlessDefaultCNI {
- toReturn.NSMode = Bridge
- } else {
- toReturn.NSMode = Slirp
- }
- } else {
- toReturn.NSMode = Bridge
- }
- case ns == string(Bridge):
- toReturn.NSMode = Bridge
- case ns == string(NoNetwork):
- toReturn.NSMode = NoNetwork
- case ns == string(Host):
- toReturn.NSMode = Host
- case strings.HasPrefix(ns, "ns:"):
- split := strings.SplitN(ns, ":", 2)
- if len(split) != 2 {
- return toReturn, nil, errors.Errorf("must provide a path to a namespace when specifying \"ns:\"")
- }
- toReturn.NSMode = Path
- toReturn.Value = split[1]
- case strings.HasPrefix(ns, string(FromContainer)+":"):
- split := strings.SplitN(ns, ":", 2)
- if len(split) != 2 {
- return toReturn, nil, errors.Errorf("must provide name or ID or a container when specifying \"container:\"")
- }
- toReturn.NSMode = FromContainer
- toReturn.Value = split[1]
- default:
- // Assume we have been given a list of CNI networks.
- // Which only works in bridge mode, so set that.
- networkList := strings.Split(ns, ",")
- for _, net := range networkList {
- networks[net] = types.PerNetworkOptions{}
- }
-
- toReturn.NSMode = Bridge
- }
-
- return toReturn, networks, nil
-}
-
// ParseNetworkFlag parses a network string slice into the network options
// If the input is nil or empty it will use the default setting from containers.conf
func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetworkOptions, map[string][]string, error) {
@@ -400,13 +343,7 @@ func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetwork
case ns == string(FromPod):
toReturn.NSMode = FromPod
case ns == "" || ns == string(Default) || ns == string(Private):
- // Net defaults to Slirp on rootless
- if rootless.IsRootless() {
- toReturn.NSMode = Slirp
- break
- }
- // if root we use bridge
- fallthrough
+ toReturn.NSMode = Private
case ns == string(Bridge), strings.HasPrefix(ns, string(Bridge)+":"):
toReturn.NSMode = Bridge
parts := strings.SplitN(ns, ":", 2)
diff --git a/pkg/specgen/namespaces_test.go b/pkg/specgen/namespaces_test.go
index 368c92bd5..d03a6d032 100644
--- a/pkg/specgen/namespaces_test.go
+++ b/pkg/specgen/namespaces_test.go
@@ -5,7 +5,6 @@ import (
"testing"
"github.com/containers/common/libnetwork/types"
- "github.com/containers/podman/v4/pkg/rootless"
"github.com/stretchr/testify/assert"
)
@@ -17,14 +16,6 @@ func parsMacNoErr(mac string) types.HardwareAddr {
func TestParseNetworkFlag(t *testing.T) {
// root and rootless have different defaults
defaultNetName := "default"
- defaultNetworks := map[string]types.PerNetworkOptions{
- defaultNetName: {},
- }
- defaultNsMode := Namespace{NSMode: Bridge}
- if rootless.IsRootless() {
- defaultNsMode = Namespace{NSMode: Slirp}
- defaultNetworks = map[string]types.PerNetworkOptions{}
- }
tests := []struct {
name string
@@ -37,26 +28,26 @@ func TestParseNetworkFlag(t *testing.T) {
{
name: "empty input",
args: nil,
- nsmode: defaultNsMode,
- networks: defaultNetworks,
+ nsmode: Namespace{NSMode: Private},
+ networks: map[string]types.PerNetworkOptions{},
},
{
name: "empty string as input",
args: []string{},
- nsmode: defaultNsMode,
- networks: defaultNetworks,
+ nsmode: Namespace{NSMode: Private},
+ networks: map[string]types.PerNetworkOptions{},
},
{
name: "default mode",
args: []string{"default"},
- nsmode: defaultNsMode,
- networks: defaultNetworks,
+ nsmode: Namespace{NSMode: Private},
+ networks: map[string]types.PerNetworkOptions{},
},
{
name: "private mode",
args: []string{"private"},
- nsmode: defaultNsMode,
- networks: defaultNetworks,
+ nsmode: Namespace{NSMode: Private},
+ networks: map[string]types.PerNetworkOptions{},
},
{
name: "bridge mode",
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 603506241..777097ac5 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -4,6 +4,7 @@ import (
"net"
"github.com/containers/common/libnetwork/types"
+ storageTypes "github.com/containers/storage/types"
spec "github.com/opencontainers/runtime-spec/specs-go"
)
@@ -222,6 +223,10 @@ type PodResourceConfig struct {
type PodSecurityConfig struct {
SecurityOpt []string `json:"security_opt,omitempty"`
+ // IDMappings are UID and GID mappings that will be used by user
+ // namespaces.
+ // Required if UserNS is private.
+ IDMappings *storageTypes.IDMappingOptions `json:"idmappings,omitempty"`
}
// NewPodSpecGenerator creates a new pod spec
diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go
index b26666df3..a7a1022b0 100644
--- a/pkg/specgen/volumes.go
+++ b/pkg/specgen/volumes.go
@@ -97,6 +97,8 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na
// This is not a named volume
overlayFlag := false
chownFlag := false
+ upperDirFlag := false
+ workDirFlag := false
for _, o := range options {
if o == "O" {
overlayFlag = true
@@ -105,8 +107,16 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na
if strings.Contains(joinedOpts, "U") {
chownFlag = true
}
-
- if len(options) > 2 || (len(options) == 2 && !chownFlag) {
+ if strings.Contains(joinedOpts, "upperdir") {
+ upperDirFlag = true
+ }
+ if strings.Contains(joinedOpts, "workdir") {
+ workDirFlag = true
+ }
+ if (workDirFlag && !upperDirFlag) || (!workDirFlag && upperDirFlag) {
+ return nil, nil, nil, errors.New("must set both `upperdir` and `workdir`")
+ }
+ if len(options) > 2 && !(len(options) == 3 && upperDirFlag && workDirFlag) || (len(options) == 2 && !chownFlag) {
return nil, nil, nil, errors.New("can't use 'O' with other options")
}
}
diff --git a/pkg/specgenutil/createparse.go b/pkg/specgenutil/createparse.go
index fb5f9c351..132f93771 100644
--- a/pkg/specgenutil/createparse.go
+++ b/pkg/specgenutil/createparse.go
@@ -18,20 +18,5 @@ func validate(c *entities.ContainerCreateOptions) error {
return err
}
- var imageVolType = map[string]string{
- "bind": "",
- "tmpfs": "",
- "ignore": "",
- }
- if _, ok := imageVolType[c.ImageVolume]; !ok {
- switch {
- case c.IsInfra:
- c.ImageVolume = "bind"
- case c.IsClone: // the image volume type will be deduced later from the container we are cloning
- return nil
- default:
- return errors.Errorf("invalid image-volume type %q. Pick one of bind, tmpfs, or ignore", c.ImageVolume)
- }
- }
- return nil
+ return config.ValidateImageVolumeMode(c.ImageVolume)
}
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 9cb2f200b..6d70af106 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -229,9 +229,11 @@ func setNamespaces(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions)
}
func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions, args []string) error {
- var (
- err error
- )
+ rtc, err := config.Default()
+ if err != nil {
+ return err
+ }
+
// validate flags as needed
if err := validate(c); err != nil {
return err
@@ -479,8 +481,13 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
if len(s.HostUsers) == 0 || len(c.HostUsers) != 0 {
s.HostUsers = c.HostUsers
}
- if len(s.ImageVolumeMode) == 0 || len(c.ImageVolume) != 0 {
- s.ImageVolumeMode = c.ImageVolume
+ if len(c.ImageVolume) != 0 {
+ if len(s.ImageVolumeMode) == 0 {
+ s.ImageVolumeMode = c.ImageVolume
+ }
+ }
+ if len(s.ImageVolumeMode) == 0 {
+ s.ImageVolumeMode = rtc.Engine.ImageVolumeMode
}
if s.ImageVolumeMode == "bind" {
s.ImageVolumeMode = "anonymous"
@@ -550,11 +557,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.CgroupsMode = c.CgroupsMode
}
if s.CgroupsMode == "" {
- rtc, err := config.Default()
- if err != nil {
- return err
- }
-
s.CgroupsMode = rtc.Cgroups()
}
@@ -622,7 +624,14 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
if opt == "no-new-privileges" {
s.ContainerSecurityConfig.NoNewPrivileges = true
} else {
- con := strings.SplitN(opt, "=", 2)
+ // Docker deprecated the ":" syntax but still supports it,
+ // so we need to as well
+ var con []string
+ if strings.Contains(opt, "=") {
+ con = strings.SplitN(opt, "=", 2)
+ } else {
+ con = strings.SplitN(opt, ":", 2)
+ }
if len(con) != 2 {
return fmt.Errorf("invalid --security-opt 1: %q", opt)
}
@@ -650,6 +659,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
}
case "unmask":
s.ContainerSecurityConfig.Unmask = append(s.ContainerSecurityConfig.Unmask, con[1:]...)
+ case "no-new-privileges":
+ noNewPrivileges, err := strconv.ParseBool(con[1])
+ if err != nil {
+ return fmt.Errorf("invalid --security-opt 2: %q", opt)
+ }
+ s.ContainerSecurityConfig.NoNewPrivileges = noNewPrivileges
default:
return fmt.Errorf("invalid --security-opt 2: %q", opt)
}
diff --git a/pkg/util/utils_linux.go b/pkg/util/utils_linux.go
index 0b21bf3c5..871303f64 100644
--- a/pkg/util/utils_linux.go
+++ b/pkg/util/utils_linux.go
@@ -3,13 +3,24 @@ package util
import (
"fmt"
"io/fs"
+ "io/ioutil"
"os"
"path/filepath"
+ "strings"
"syscall"
+ "github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/psgo"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
+)
+
+var (
+ errNotADevice = errors.New("not a device node")
)
// GetContainerPidInformationDescriptors returns a string slice of all supported
@@ -59,3 +70,134 @@ func FindDeviceNodes() (map[string]string, error) {
return nodes, nil
}
+
+func AddPrivilegedDevices(g *generate.Generator) error {
+ hostDevices, err := getDevices("/dev")
+ if err != nil {
+ return err
+ }
+ g.ClearLinuxDevices()
+
+ if rootless.IsRootless() {
+ mounts := make(map[string]interface{})
+ for _, m := range g.Mounts() {
+ mounts[m.Destination] = true
+ }
+ newMounts := []spec.Mount{}
+ for _, d := range hostDevices {
+ devMnt := spec.Mount{
+ Destination: d.Path,
+ Type: define.TypeBind,
+ Source: d.Path,
+ Options: []string{"slave", "nosuid", "noexec", "rw", "rbind"},
+ }
+ if d.Path == "/dev/ptmx" || strings.HasPrefix(d.Path, "/dev/tty") {
+ continue
+ }
+ if _, found := mounts[d.Path]; found {
+ continue
+ }
+ newMounts = append(newMounts, devMnt)
+ }
+ g.Config.Mounts = append(newMounts, g.Config.Mounts...)
+ if g.Config.Linux.Resources != nil {
+ g.Config.Linux.Resources.Devices = nil
+ }
+ } else {
+ for _, d := range hostDevices {
+ g.AddDevice(d)
+ }
+ // Add resources device - need to clear the existing one first.
+ if g.Config.Linux.Resources != nil {
+ g.Config.Linux.Resources.Devices = nil
+ }
+ g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
+ }
+
+ return nil
+}
+
+// based on getDevices from runc (libcontainer/devices/devices.go)
+func getDevices(path string) ([]spec.LinuxDevice, error) {
+ files, err := ioutil.ReadDir(path)
+ if err != nil {
+ if rootless.IsRootless() && os.IsPermission(err) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ out := []spec.LinuxDevice{}
+ for _, f := range files {
+ switch {
+ case f.IsDir():
+ switch f.Name() {
+ // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
+ case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
+ continue
+ default:
+ sub, err := getDevices(filepath.Join(path, f.Name()))
+ if err != nil {
+ return nil, err
+ }
+ if sub != nil {
+ out = append(out, sub...)
+ }
+ continue
+ }
+ case f.Name() == "console":
+ continue
+ case f.Mode()&os.ModeSymlink != 0:
+ continue
+ }
+
+ device, err := DeviceFromPath(filepath.Join(path, f.Name()))
+ if err != nil {
+ if err == errNotADevice {
+ continue
+ }
+ if os.IsNotExist(err) {
+ continue
+ }
+ return nil, err
+ }
+ out = append(out, *device)
+ }
+ return out, nil
+}
+
+// Copied from github.com/opencontainers/runc/libcontainer/devices
+// Given the path to a device look up the information about a linux device
+func DeviceFromPath(path string) (*spec.LinuxDevice, error) {
+ var stat unix.Stat_t
+ err := unix.Lstat(path, &stat)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ devType string
+ mode = stat.Mode
+ devNumber = uint64(stat.Rdev) // nolint: unconvert
+ m = os.FileMode(mode)
+ )
+
+ switch {
+ case mode&unix.S_IFBLK == unix.S_IFBLK:
+ devType = "b"
+ case mode&unix.S_IFCHR == unix.S_IFCHR:
+ devType = "c"
+ case mode&unix.S_IFIFO == unix.S_IFIFO:
+ devType = "p"
+ default:
+ return nil, errNotADevice
+ }
+
+ return &spec.LinuxDevice{
+ Type: devType,
+ Path: path,
+ FileMode: &m,
+ UID: &stat.Uid,
+ GID: &stat.Gid,
+ Major: int64(unix.Major(devNumber)),
+ Minor: int64(unix.Minor(devNumber)),
+ }, nil
+}
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 13aaea317..f03b95786 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -53,7 +53,7 @@ t POST "images/create?fromImage=alpine" 200 .error~null .status~".*Download comp
t POST "images/create?fromImage=alpine&tag=latest" 200
# 10977 - handle platform parameter correctly
-t POST "images/create?fromImage=testimage:20210610&platform=linux/arm64" 200
+t POST "images/create?fromImage=quay.io/libpod/testimage:20210610&platform=linux/arm64" 200
t GET "images/testimage:20210610/json" 200 \
.Architecture=arm64
diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at
index 67b4f1c79..57d5e114d 100644
--- a/test/apiv2/12-imagesMore.at
+++ b/test/apiv2/12-imagesMore.at
@@ -6,6 +6,8 @@
red='\e[31m'
nc='\e[0m'
+start_registry
+
podman pull -q $IMAGE
t GET libpod/images/json 200 \
@@ -20,48 +22,38 @@ t GET libpod/images/$IMAGE/tree 200 \
t POST "libpod/images/nonesuch/tag?repo=myrepo&tag=mytag" 404
# Tag the image
-t POST "libpod/images/$IMAGE/tag?repo=localhost:5000/myrepo&tag=mytag" 201
+t POST "libpod/images/$IMAGE/tag?repo=localhost:$REGISTRY_PORT/myrepo&tag=mytag" 201
t GET libpod/images/$IMAGE/json 200 \
- .RepoTags[1]=localhost:5000/myrepo:mytag
-
-# Run registry container
-# FIXME this fails if python tests have been run first...
-podman run -d --name registry -p 5000:5000 quay.io/libpod/registry:2.7 /entrypoint.sh /etc/docker/registry/config.yml
-wait_for_port localhost 5000
-
-# Push to local registry and check output
-while read -r LINE
-do
- if echo "${LINE}" | jq --exit-status 'select( .status != null) | select ( .status | contains("digest: sha256:"))' &>/dev/null; then
- GOT_DIGEST="1"
- fi
-done < <(curl -sL "http://$HOST:$PORT/images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" -XPOST)
-if [ -z "${GOT_DIGEST}" ] ; then
- echo -e "${red}not ok: did not found digest in output${nc}" 1>&2;
-fi
-
-# Push to local registry
-t POST "images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" 200
+ .RepoTags[1]=localhost:$REGISTRY_PORT/myrepo:mytag
+
+# Push to local registry...
+t POST "images/localhost:$REGISTRY_PORT/myrepo/push?tlsVerify=false&tag=mytag" 200
+
+# ...and check output. We can't use our built-in checks because this output
+# is a sequence of JSON objects, i.e., individual ones, not in a JSON array.
+# The lines themselves are valid JSON, but taken together they are not.
+readarray lines <<<"$output"
+s0=$(jq -r .status <<<"${lines[0]}")
+is "$s0" "The push refers to repository [localhost:$REGISTRY_PORT/myrepo:mytag]" \
+ "Push to local registry: first status line"
+
+# FIXME: is there a way to test the actual digest?
+s1=$(jq -r .status <<<"${lines[1]}")
+like "$s1" "mytag: digest: sha256:[0-9a-f]\{64\} size: [0-9]\+" \
+ "Push to local registry: second status line"
# Untag the image
-t POST "libpod/images/$iid/untag?repo=localhost:5000/myrepo&tag=mytag" 201
+t POST "libpod/images/$iid/untag?repo=localhost:$REGISTRY_PORT/myrepo&tag=mytag" 201
# Try to push non-existing image
-t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" 404
+t POST "images/localhost:$REGISTRY_PORT/idonotexist/push?tlsVerify=false" 404
t GET libpod/images/$IMAGE/json 200 \
.RepoTags[-1]=$IMAGE
-# Remove the registry container
-t DELETE libpod/containers/registry?force=true 200
-
-# Remove images
+# Remove image
t DELETE libpod/images/$IMAGE 200 \
.ExitCode=0
-t DELETE libpod/images/quay.io/libpod/registry:2.7 200 \
- .ExitCode=0
-if [ -z "${GOT_DIGEST}" ] ; then
- exit 1;
-fi
+stop_registry
diff --git a/test/apiv2/15-manifest.at b/test/apiv2/15-manifest.at
index 0dd7026fa..970bed5a8 100644
--- a/test/apiv2/15-manifest.at
+++ b/test/apiv2/15-manifest.at
@@ -2,18 +2,40 @@
#
# Tests for manifest list endpoints
+start_registry
+
t POST /v3.4.0/libpod/manifests/create?name=abc 200 \
.Id~[0-9a-f]\\{64\\}
id_abc=$(jq -r '.Id' <<<"$output")
t POST /v4.0.0/libpod/manifests/xyz 201 \
.Id~[0-9a-f]\\{64\\}
-echo xyz $output
id_xyz=$(jq -r '.Id' <<<"$output")
t GET /v3.4.0/libpod/manifests/$id_abc/exists 204
t GET /v4.0.0/libpod/manifests/$id_xyz/exists 204
+id_abc_image=$($PODMAN_BIN --root $WORKDIR/server_root image build -q --format=docker -<<EOF
+FROM alpine
+RUN >file1
+EOF
+)
+
+id_xyz_image=$($PODMAN_BIN --root $WORKDIR/server_root image build -q --format=docker -<<EOF
+FROM alpine
+RUN >file2
+EOF
+)
+
+t POST /v3.4.0/libpod/manifests/$id_abc/add images="[\"containers-storage:$id_abc_image\"]" 200
+t PUT /v4.0.0/libpod/manifests/$id_xyz operation='update' images="[\"containers-storage:$id_xyz_image\"]" 200
+
+t POST "/v3.4.0/libpod/manifests/abc:latest/push?destination=localhost:$REGISTRY_PORT%2Fabc:latest&tlsVerify=false&all=true" 200
+t POST "/v4.0.0/libpod/manifests/xyz:latest/registry/localhost:$REGISTRY_PORT%2Fxyz:latest?tlsVerify=false&all=true" 200
+
# /v3.x cannot delete a manifest list
t DELETE /v4.0.0/libpod/manifests/$id_abc 200
t DELETE /v4.0.0/libpod/manifests/$id_xyz 200
+
+podman rmi -a
+stop_registry
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 4d32a1031..383c527b4 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -45,16 +45,16 @@ t GET libpod/containers/json?all=true 200 \
.[0].IsInfra=false
# Test compat API for Network Settings (.Network is N/A when rootless)
-network_expect=
+network_expect="Networks=null"
if root; then
- network_expect='.[0].NetworkSettings.Networks.podman.NetworkID=podman'
+ network_expect="Networks.podman.NetworkID=podman"
fi
t GET /containers/json?all=true 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Mounts~.*/tmp \
- $network_expect
+ .[0].NetworkSettings.$network_expect
# compat API imageid with sha256: prefix
t GET containers/json?limit=1 200 \
@@ -239,6 +239,7 @@ t GET containers/$cid/json 200 \
t POST containers/create Image=$IMAGE Entrypoint='["top"]' 201 \
.Id~[0-9a-f]\\{64\\}
cid_top=$(jq -r '.Id' <<<"$output")
+
t GET containers/${cid_top}/json 200 \
.Config.Entrypoint[0]="top" \
.Config.Cmd='[]' \
@@ -477,7 +478,8 @@ for endpoint in containers/create libpod/containers/create; do
t POST libpod/containers/$cid/init 204
- t GET libpod/containers/$cid/json 200
+ t GET libpod/containers/$cid/json 200 \
+ .HostsPath=""
t DELETE containers/$cid 204
done
diff --git a/test/apiv2/60-auth.at b/test/apiv2/60-auth.at
index 1e087d12b..465b0a96d 100644
--- a/test/apiv2/60-auth.at
+++ b/test/apiv2/60-auth.at
@@ -3,7 +3,7 @@
# registry-related tests
#
-start_registry
+start_registry htpasswd
# Test unreachable
t POST /v1.40/auth username=$REGISTRY_USERNAME password=WrOnGPassWord serveraddress=does.not.exist.io:1234/ \
@@ -26,3 +26,5 @@ t POST /v1.40/auth username=$REGISTRY_USERNAME password=$REGISTRY_PASSWORD serve
200 \
.Status="Login Succeeded" \
.IdentityToken=""
+
+stop_registry
diff --git a/test/apiv2/70-short-names.at b/test/apiv2/70-short-names.at
index dbf816f55..bd7f8e7bd 100644
--- a/test/apiv2/70-short-names.at
+++ b/test/apiv2/70-short-names.at
@@ -128,7 +128,7 @@ t DELETE "containers/$cid"
# disable the docker.io enforcement.
stop_service
-CONTAINERS_CONF=$(pwd)/test/apiv2/containers.conf start_service
+CONTAINERS_CONF=$TESTS_DIR/containers.conf start_service
t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .status~".*Download complete.*"
t POST "images/alpine/tag?repo=foo" 201
diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2
index c3545522e..8ecc2aa2d 100755
--- a/test/apiv2/test-apiv2
+++ b/test/apiv2/test-apiv2
@@ -62,7 +62,7 @@ clean_up_server() {
podman rm -a
podman rmi -af
- stop_registry
+ stop_registry --cleanup
stop_service
fi
}
@@ -87,6 +87,7 @@ trap err_handler ERR
#########
function die() {
echo "$ME: $*" >&2
+ clean_up_server
exit 1
}
@@ -219,19 +220,19 @@ function jsonify() {
function t() {
local method=$1; shift
local path=$1; shift
- local curl_args
+ local -a curl_args
local content_type="application/json"
local testname="$method $path"
- # POST requests may be followed by one or more key=value pairs.
+ # POST and PUT requests may be followed by one or more key=value pairs.
# Slurp the command line until we see a 3-digit status code.
- if [[ $method = "POST" ]]; then
+ if [[ $method = "POST" || $method == "PUT" ]]; then
local -a post_args
for arg; do
case "$arg" in
*=*) post_args+=("$arg");
shift;;
- *.tar) curl_args="--data-binary @$arg" ;
+ *.tar) curl_args+=(--data-binary @$arg);
content_type="application/x-tar";
shift;;
application/*) content_type="$arg";
@@ -241,8 +242,8 @@ function t() {
esac
done
if [[ -z "$curl_args" ]]; then
- curl_args="-d $(jsonify ${post_args[@]})"
- testname="$testname [$curl_args]"
+ curl_args=(-d $(jsonify ${post_args[@]}))
+ testname="$testname [${curl_args[@]}]"
fi
fi
@@ -269,7 +270,7 @@ function t() {
# curl -X HEAD but without --head seems to wait for output anyway
if [[ $method == "HEAD" ]]; then
- curl_args="--head"
+ curl_args+=("--head")
fi
local expected_code=$1; shift
@@ -281,7 +282,7 @@ function t() {
# -s = silent, but --write-out 'format' gives us important response data
# The hairy "{ ...;rc=$?; } || :" lets us capture curl's exit code and
# give a helpful diagnostic if it fails.
- { response=$(curl -s -X $method ${curl_args} \
+ { response=$(curl -s -X $method "${curl_args[@]}" \
-H "Content-type: $content_type" \
--dump-header $WORKDIR/curl.headers.out \
--write-out '%{http_code}^%{content_type}^%{time_total}' \
@@ -289,8 +290,7 @@ function t() {
# Any error from curl is instant bad news, from which we can't recover
if [[ $rc -ne 0 ]]; then
- echo "FATAL: curl failure ($rc) on $url - cannot continue" >&2
- exit 1
+ die "curl failure ($rc) on $url - cannot continue"
fi
# Show returned headers (without trailing ^M or empty lines) in log file.
@@ -380,11 +380,6 @@ function start_service() {
die "Cannot start service on non-localhost ($HOST)"
fi
- echo "rootdir: "$WORKDIR
- # Some tests use shortnames; force registry override to work around
- # docker.io throttling.
-# FIXME esm revisit pulling expected images re: shortnames caused tests to fail
-# env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf
$PODMAN_BIN \
--root $WORKDIR/server_root --syslog=true \
system service \
@@ -411,15 +406,17 @@ REGISTRY_PORT=
REGISTRY_USERNAME=
REGISTRY_PASSWORD=
function start_registry() {
- # We can be invoked multiple times, e.g. from different subtests, but
- # let's assume that once started we only kill it at the end of tests.
+ # We can be called multiple times, but each time should start a new
+ # registry container with (possibly) different configuration. That
+ # means that all callers must be responsible for invoking stop_registry.
if [[ -n "$REGISTRY_PORT" ]]; then
- return
+ die "start_registry invoked twice in succession, without stop_registry"
fi
+ # First arg is auth type (default: "none", but can also be "htpasswd")
+ local auth="${1:-none}"
+
REGISTRY_PORT=$(random_port)
- REGISTRY_USERNAME=u$(random_string 7)
- REGISTRY_PASSWORD=p$(random_string 7)
local REGDIR=$WORKDIR/registry
local AUTHDIR=$REGDIR/auth
@@ -433,24 +430,39 @@ function start_registry() {
podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE ||
podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE
- # Create a local cert and credentials
- # FIXME: is there a hidden "--quiet" flag? This is too noisy.
- openssl req -newkey rsa:4096 -nodes -sha256 \
- -keyout $AUTHDIR/domain.key -x509 -days 2 \
- -out $AUTHDIR/domain.crt \
- -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=registry host certificate" \
- -addext subjectAltName=DNS:localhost
- htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \
- > $AUTHDIR/htpasswd
+ # Create a local cert (no need to do this more than once)
+ if [[ ! -e $AUTHDIR/domain.key ]]; then
+ # FIXME: is there a hidden "--quiet" flag? This is too noisy.
+ openssl req -newkey rsa:4096 -nodes -sha256 \
+ -keyout $AUTHDIR/domain.key -x509 -days 2 \
+ -out $AUTHDIR/domain.crt \
+ -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=registry host certificate" \
+ -addext subjectAltName=DNS:localhost
+ fi
+
+ # If invoked with auth=htpasswd, create credentials
+ REGISTRY_USERNAME=
+ REGISTRY_PASSWORD=
+ declare -a registry_auth_params=(-e "REGISTRY_AUTH=$auth")
+ if [[ "$auth" = "htpasswd" ]]; then
+ REGISTRY_USERNAME=u$(random_string 7)
+ REGISTRY_PASSWORD=p$(random_string 7)
+
+ htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \
+ > $AUTHDIR/htpasswd
+
+ registry_auth_params+=(
+ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"
+ -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd"
+ )
+ fi
# Run the registry, and wait for it to come up
podman ${PODMAN_REGISTRY_ARGS} run -d \
-p ${REGISTRY_PORT}:5000 \
--name registry \
-v $AUTHDIR:/auth:Z \
- -e "REGISTRY_AUTH=htpasswd" \
- -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
- -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
+ "${registry_auth_params[@]}" \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/auth/domain.key \
${REGISTRY_IMAGE}
@@ -462,13 +474,19 @@ function stop_registry() {
local REGDIR=${WORKDIR}/registry
if [[ -d $REGDIR ]]; then
local OPTS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot"
- podman $OPTS stop -f -t 0 -a
+ podman $OPTS stop -i -t 0 registry
# rm/rmi are important when running rootless: without them we
# get EPERMS in tmpdir cleanup because files are owned by subuids.
- podman $OPTS rm -f -a
- podman $OPTS rmi -f -a
+ podman $OPTS rm -f -i registry
+ if [[ "$1" = "--cleanup" ]]; then
+ podman $OPTS rmi -f -a
+ fi
fi
+
+ REGISTRY_PORT=
+ REGISTRY_USERNAME=
+ REGISTRY_PASSWORD=
}
#################
diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas
index e2ca45728..6ff564aaa 100755
--- a/test/buildah-bud/apply-podman-deltas
+++ b/test/buildah-bud/apply-podman-deltas
@@ -193,21 +193,12 @@ skip_if_remote "volumes don't work with podman-remote" \
"buildah bud --volume" \
"buildah-bud-policy"
-# Most of this should work in podman remote after API implementation other than where context is host.
skip_if_remote "--build-context option not implemented in podman-remote" \
- "build-with-additional-build-context and COPY, test pinning image" \
- "build-with-additional-build-context and COPY, stagename and additional-context conflict" \
- "build-with-additional-build-context and COPY, additionalContext and numeric value of stage" \
- "build-with-additional-build-context and COPY, additionalContext and numeric value of stage" \
"build-with-additional-build-context and COPY, additional context from host" \
- "build-with-additional-build-context and COPY, additional context from external URL" \
- "build-with-additional-build-context and RUN --mount=from=, additional-context is URL and mounted from subdir" \
"build-with-additional-build-context and RUN --mount=from=, additional-context not image and also test conflict with stagename" \
- "build-with-additional-build-context and RUN --mount=from=, additional-context and also test conflict with stagename" \
- "bud-multiple-platform for --all-platform with additional-build-context" \
- "build-with-additional-build-context and FROM, stagename and additional-context conflict" \
+
+skip_if_remote "env-variable for Containerfile.in pre-processing is not propogated on remote" \
"bud with Containerfile.in, via envariable" \
- "build-with-additional-build-context and FROM, pin busybox to alpine"
# Requires a local file outside context dir
skip_if_remote "local keyfile not sent to podman-remote" \
diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go
index 86dc76116..9ecc2f8c6 100644
--- a/test/e2e/build_test.go
+++ b/test/e2e/build_test.go
@@ -85,7 +85,7 @@ var _ = Describe("Podman build", func() {
})
It("podman build with a secret from file and verify if secret file is not leaked into image", func() {
- session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/"})
+ session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/secret-verify-leak"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("somesecret"))
@@ -555,7 +555,7 @@ subdir**`
dd := exec.Command("dd", "if=/dev/random", "of="+randomFile, "bs=1G", "count=1")
ddSession, err := Start(dd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
- Eventually(ddSession).Should(Exit(0))
+ Eventually(ddSession, "10s", "1s").Should(Exit(0))
// make cwd as context root path
Expect(os.Chdir(contextDir)).ToNot(HaveOccurred())
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 787178cd3..1da199714 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -676,8 +676,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during restore", func() {
// Start the container
- localRunString := getRunString([]string{"--rm", ALPINE, "top"})
- session := podmanTest.Podman(localRunString)
+ // test that restore works without network namespace (https://github.com/containers/podman/issues/14389)
+ session := podmanTest.Podman([]string{"run", "--network=none", "-d", "--rm", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 4e6dcb8af..14dd6b6b8 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -8,6 +8,7 @@ import (
"time"
. "github.com/containers/podman/v4/test/utils"
+ "github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -102,12 +103,12 @@ var _ = Describe("Podman logs", func() {
It("tail 99 lines: "+log, func() {
skipIfJournaldInContainer()
- logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
+ name := "test1"
+ logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
- cid := logc.OutputToString()
- results := podmanTest.Podman([]string{"logs", "--tail", "99", cid})
+ results := podmanTest.Podman([]string{"logs", "--tail", "99", name})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
@@ -116,11 +117,17 @@ var _ = Describe("Podman logs", func() {
It("tail 800 lines: "+log, func() {
skipIfJournaldInContainer()
+ // this uses -d so that we do not have 1000 unnecessary lines printed in every test log
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
+ // make sure we wait for the container to finish writing its output
+ wait := podmanTest.Podman([]string{"wait", cid})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait).To(Exit(0))
+
results := podmanTest.Podman([]string{"logs", "--tail", "800", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
@@ -364,6 +371,26 @@ var _ = Describe("Podman logs", func() {
Expect(results.OutputToString()).To(Equal("stdout"))
Expect(results.ErrorToString()).To(Equal("stderr"))
})
+
+ It("podman logs partial log lines: "+log, func() {
+ skipIfJournaldInContainer()
+
+ cname := "log-test"
+ content := stringid.GenerateNonCryptoID()
+ // use printf to print no extra newline
+ logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "printf", content})
+ logc.WaitWithDefaultTimeout()
+ Expect(logc).To(Exit(0))
+ // Important: do not use OutputToString(), this will remove the trailing newline from the output.
+ // However this test must make sure that there is no such extra newline.
+ Expect(string(logc.Out.Contents())).To(Equal(content))
+
+ logs := podmanTest.Podman([]string{"logs", cname})
+ logs.WaitWithDefaultTimeout()
+ Expect(logs).To(Exit(0))
+ // see comment above
+ Expect(string(logs.Out.Contents())).To(Equal(content))
+ })
}
It("using journald for container with container tag", func() {
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index a0716c84d..c9ffe6a8d 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -2,7 +2,6 @@ package integration
import (
"os"
- "strings"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/storage/pkg/stringid"
@@ -94,7 +93,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec2 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec2.WaitWithDefaultTimeout()
Expect(exec2).Should(Exit(0))
- Expect(strings.Contains(exec2.OutputToString(), ns)).To(BeTrue())
+ Expect(exec2.OutputToString()).To(ContainSubstring(ns))
dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"})
dis.WaitWithDefaultTimeout()
@@ -113,7 +112,12 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec3 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec3.WaitWithDefaultTimeout()
Expect(exec3).Should(Exit(0))
- Expect(strings.Contains(exec3.OutputToString(), ns)).To(BeFalse())
+ Expect(exec3.OutputToString()).ToNot(ContainSubstring(ns))
+
+ // make sure stats still works https://github.com/containers/podman/issues/13824
+ stats := podmanTest.Podman([]string{"stats", "test", "--no-stream"})
+ stats.WaitWithDefaultTimeout()
+ Expect(stats).Should(Exit(0))
})
It("bad network name in connect should result in error", func() {
@@ -206,7 +210,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec2 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec2.WaitWithDefaultTimeout()
Expect(exec2).Should(Exit(0))
- Expect(strings.Contains(exec2.OutputToString(), ns)).To(BeFalse())
+ Expect(exec2.OutputToString()).ToNot(ContainSubstring(ns))
ip := "10.11.100.99"
mac := "44:11:44:11:44:11"
@@ -235,7 +239,12 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec3 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec3.WaitWithDefaultTimeout()
Expect(exec3).Should(Exit(0))
- Expect(strings.Contains(exec3.OutputToString(), ns)).To(BeTrue())
+ Expect(exec3.OutputToString()).To(ContainSubstring(ns))
+
+ // make sure stats works https://github.com/containers/podman/issues/13824
+ stats := podmanTest.Podman([]string{"stats", "test", "--no-stream"})
+ stats.WaitWithDefaultTimeout()
+ Expect(stats).Should(Exit(0))
// make sure no logrus errors are shown https://github.com/containers/podman/issues/9602
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 31044f68b..61f2b3a1c 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -3688,7 +3688,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
})
// Check the block devices are exposed inside container
- It("ddpodman play kube expose block device inside container", func() {
+ It("podman play kube expose block device inside container", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3727,7 +3727,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
})
// Check the char devices are exposed inside container
- It("ddpodman play kube expose character device inside container", func() {
+ It("podman play kube expose character device inside container", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3781,7 +3781,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
Expect(kube).Should(Exit(125))
})
- It("ddpodman play kube reports error when we try to expose char device as block device", func() {
+ It("podman play kube reports error when we try to expose char device as block device", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3807,7 +3807,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
Expect(kube).Should(Exit(125))
})
- It("ddpodman play kube reports error when we try to expose block device as char device", func() {
+ It("podman play kube reports error when we try to expose block device as char device", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index dedb1caeb..4919cc670 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -1112,4 +1112,26 @@ ENTRYPOINT ["sleep","99999"]
})
+ It("podman pod create infra inheritance test", func() {
+ volName := "testVol1"
+ volCreate := podmanTest.Podman([]string{"volume", "create", volName})
+ volCreate.WaitWithDefaultTimeout()
+ Expect(volCreate).Should(Exit(0))
+
+ session := podmanTest.Podman([]string{"pod", "create", "-v", volName + ":/vol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ volName2 := "testVol2"
+ volCreate = podmanTest.Podman([]string{"volume", "create", volName2})
+ volCreate.WaitWithDefaultTimeout()
+ Expect(volCreate).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", session.OutputToString(), "-v", volName2 + ":/vol2", ALPINE, "mount"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("/vol1"))
+ Expect(session.OutputToString()).Should(ContainSubstring("/vol2"))
+ })
+
})
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index ab204992c..20794a29c 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -125,6 +125,29 @@ var _ = Describe("Podman pod create", func() {
session = podmanTest.Podman([]string{"run", fedoraMinimal, "curl", "-f", "localhost"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
+
+ session = podmanTest.Podman([]string{"pod", "create", "--network", "host"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--name", "hostCtr", "--pod", session.OutputToString(), ALPINE, "readlink", "/proc/self/ns/net"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ ns := SystemExec("readlink", []string{"/proc/self/ns/net"})
+ ns.WaitWithDefaultTimeout()
+ Expect(ns).Should(Exit(0))
+ netns := ns.OutputToString()
+ Expect(netns).ToNot(BeEmpty())
+
+ Expect(session.OutputToString()).To(Equal(netns))
+
+ // Sanity Check for podman inspect
+ session = podmanTest.Podman([]string{"inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "hostCtr"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("''")) // no network path... host
+
})
It("podman pod correctly sets up IPCNS", func() {
diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go
index 4f0b512c6..dfaff7e67 100644
--- a/test/e2e/run_privileged_test.go
+++ b/test/e2e/run_privileged_test.go
@@ -131,6 +131,30 @@ var _ = Describe("Podman privileged container tests", func() {
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 20))
})
+ It("podman privileged should restart after host devices change", func() {
+ containerName := "privileged-restart-test"
+ SkipIfRootless("Cannot create devices in /dev in rootless mode")
+ Expect(os.MkdirAll("/dev/foodevdir", os.ModePerm)).To(BeNil())
+
+ mknod := SystemExec("mknod", []string{"/dev/foodevdir/null", "c", "1", "3"})
+ mknod.WaitWithDefaultTimeout()
+ Expect(mknod).Should(Exit(0))
+
+ session := podmanTest.Podman([]string{"run", "--name=" + containerName, "--privileged", "-it", fedoraMinimal, "ls", "/dev"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ deviceFiles := session.OutputToStringArray()
+
+ os.RemoveAll("/dev/foodevdir")
+ session = podmanTest.Podman([]string{"start", "--attach", containerName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ deviceFilesAfterRemoval := session.OutputToStringArray()
+ Expect(deviceFiles).To(Not(Equal(deviceFilesAfterRemoval)))
+ })
+
It("run no-new-privileges test", func() {
// Check if our kernel is new enough
k, err := IsKernelNewerThan("4.14")
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 3bef889b7..1c0480407 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -325,6 +325,51 @@ var _ = Describe("Podman run with volumes", func() {
})
+ It("podman support overlay volume with custom upperdir and workdir", func() {
+ SkipIfRemote("Overlay volumes only work locally")
+ if os.Getenv("container") != "" {
+ Skip("Overlay mounts not supported when running in a container")
+ }
+ if rootless.IsRootless() {
+ if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
+ Skip("Fuse-Overlayfs required for rootless overlay mount test")
+ }
+ }
+
+ // Use bindsource instead of named volume
+ bindSource := filepath.Join(tempdir, "bindsource")
+ err := os.Mkdir(bindSource, 0755)
+ Expect(err).To(BeNil(), "mkdir "+bindSource)
+
+ // create persistent upperdir on host
+ upperDir := filepath.Join(tempdir, "upper")
+ err = os.Mkdir(upperDir, 0755)
+ Expect(err).To(BeNil(), "mkdir "+upperDir)
+
+ // create persistent workdir on host
+ workDir := filepath.Join(tempdir, "work")
+ err = os.Mkdir(workDir, 0755)
+ Expect(err).To(BeNil(), "mkdir "+workDir)
+
+ overlayOpts := fmt.Sprintf("upperdir=%s,workdir=%s", upperDir, workDir)
+
+ // create file on overlay volume
+ session := podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "ls /data"})
+ session.WaitWithDefaultTimeout()
+ // must contain `overlay` file since it should be persistent on specified upper and workdir
+ Expect(session.OutputToString()).To(ContainSubstring("overlay"))
+
+ session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O", ALPINE, "sh", "-c", "ls /data"})
+ session.WaitWithDefaultTimeout()
+ // must not contain `overlay` file which was on custom upper and workdir since we have not specified any upper or workdir
+ Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
+
+ })
+
It("podman run with noexec can't exec", func() {
session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index 897e49ef7..7a1fb0fc2 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -226,13 +226,17 @@ default-docker:
})
It("podman save --multi-image-archive (untagged images)", func() {
- // Refer to images via ID instead of tag.
- session := podmanTest.Podman([]string{"images", "--format", "{{.ID}}"})
+ // #14468: to make execution time more predictable, save at
+ // most three images and sort them by size.
+ session := podmanTest.Podman([]string{"images", "--sort", "size", "--format", "{{.ID}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
ids := session.OutputToStringArray()
Expect(len(ids)).To(BeNumerically(">", 1), "We need to have *some* images to save")
+ if len(ids) > 3 {
+ ids = ids[:3]
+ }
multiImageSave(podmanTest, ids)
})
})
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 0bf5acbf1..499283cab 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -110,15 +110,24 @@ var _ = Describe("Podman volume create", func() {
Expect(session.OutputToString()).To(ContainSubstring("hello"))
})
- It("podman import volume should fail", func() {
+ It("podman import/export volume should fail", func() {
// try import on volume or source which does not exists
- if podmanTest.RemoteTest {
- Skip("Volume export check does not work with a remote client")
- }
+ SkipIfRemote("Volume export check does not work with a remote client")
session := podmanTest.Podman([]string{"volume", "import", "notfound", "notfound.tar"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("open notfound.tar: no such file or directory"))
+
+ session = podmanTest.Podman([]string{"volume", "import", "notfound", "-"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound"))
+
+ session = podmanTest.Podman([]string{"volume", "export", "notfound"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound"))
})
It("podman create volume with bad volume option", func() {
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 283c3aea9..241831257 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -855,4 +855,15 @@ EOF
run_podman rmi $test_image
}
+@test "podman create --security-opt" {
+ run_podman create --security-opt no-new-privileges=true $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges:true $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges=false $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges $IMAGE
+ run_podman rm $output
+}
+
# vim: filetype=sh
diff --git a/test/system/120-load.bats b/test/system/120-load.bats
index 45e0b3362..5a7f63b43 100644
--- a/test/system/120-load.bats
+++ b/test/system/120-load.bats
@@ -121,7 +121,7 @@ verify_iid_and_name() {
run_podman untag $IMAGE $newname
run_podman image scp -q ${notme}@localhost::$newname
- expect="Loaded image(s): $newname"
+ expect="Loaded image: $newname"
is "$output" "$expect" "-q silences output"
# Confirm that we have it, and that its digest matches our original
diff --git a/test/system/160-volumes.bats b/test/system/160-volumes.bats
index 5b0460723..797883ec6 100644
--- a/test/system/160-volumes.bats
+++ b/test/system/160-volumes.bats
@@ -411,4 +411,43 @@ NeedsChown | true
fi
}
+@test "podman --image-volume" {
+ tmpdir=$PODMAN_TMPDIR/volume-test
+ mkdir -p $tmpdir
+ containerfile=$tmpdir/Containerfile
+ cat >$containerfile <<EOF
+FROM $IMAGE
+VOLUME /data
+EOF
+ fs=$(stat -f -c %T .)
+ run_podman build -t volume_image $tmpdir
+
+ containersconf=$tmpdir/containers.conf
+ cat >$containersconf <<EOF
+[engine]
+image_volume_mode="tmpfs"
+EOF
+
+ run_podman run --image-volume tmpfs --rm volume_image stat -f -c %T /data
+ is "$output" "tmpfs" "Should be tmpfs"
+
+ run_podman 1 run --image-volume ignore --rm volume_image stat -f -c %T /data
+ is "$output" "stat: can't read file system information for '/data': No such file or directory" "Should fail with /data does not exists"
+
+ CONTAINERS_CONF="$containersconf" run_podman run --rm volume_image stat -f -c %T /data
+ is "$output" "tmpfs" "Should be tmpfs"
+
+ CONTAINERS_CONF="$containersconf" run_podman run --image-volume bind --rm volume_image stat -f -c %T /data
+ assert "$output" != "tmpfs" "Should match hosts $fs"
+
+ CONTAINERS_CONF="$containersconf" run_podman run --image-volume tmpfs --rm volume_image stat -f -c %T /data
+ is "$output" "tmpfs" "Should be tmpfs"
+
+ CONTAINERS_CONF="$containersconf" run_podman 1 run --image-volume ignore --rm volume_image stat -f -c %T /data
+ is "$output" "stat: can't read file system information for '/data': No such file or directory" "Should fail with /data does not exists"
+
+ run_podman rm --all --force -t 0
+ run_podman image rm --force localhost/volume_image
+}
+
# vim: filetype=sh
diff --git a/test/system/170-run-userns.bats b/test/system/170-run-userns.bats
index b80351902..84788a7f4 100644
--- a/test/system/170-run-userns.bats
+++ b/test/system/170-run-userns.bats
@@ -38,10 +38,12 @@ function _require_crun() {
@test "rootful pod with custom ID mapping" {
skip_if_rootless "does not work rootless - rootful feature"
- skip_if_remote "remote --uidmap is broken (see #14233)"
random_pod_name=$(random_string 30)
run_podman pod create --uidmap 0:200000:5000 --name=$random_pod_name
run_podman pod start $random_pod_name
+ run_podman pod inspect --format '{{.InfraContainerID}}' $random_pod_name
+ run podman inspect --format '{{.HostConfig.IDMappings.UIDMap}}' $output
+ is "$output" ".*0:200000:5000" "UID Map Successful"
# Remove the pod and the pause image
run_podman pod rm $random_pod_name
@@ -109,15 +111,30 @@ EOF
}
@test "podman userns=nomap" {
- skip_if_not_rootless "--userns=nomap only works in rootless mode"
- ns_user=$(id -un)
- baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:)
- test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}"
+ if is_rootless; then
+ ns_user=$(id -un)
+ baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:)
+ test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}"
+
+ test_name="test_$(random_string 12)"
+ run_podman run -d --userns=nomap $IMAGE sleep 100
+ cid=${output}
+ run_podman top ${cid} huser
+ is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID"
+ run_podman rm -t 0 --force ${cid}
+ else
+ run_podman 125 run -d --userns=nomap $IMAGE sleep 100
+ is "${output}" "Error: nomap is only supported in rootless mode" "Container should fail to start since nomap is not suppored in rootful mode"
+ fi
+}
- test_name="test_$(random_string 12)"
- run_podman run -d --userns=nomap $IMAGE sleep 100
- cid=${output}
- run_podman top ${cid} huser
- is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID"
- run_podman rm -t 0 --force ${cid}
+@test "podman userns=keep-id" {
+ if is_rootless; then
+ user=$(id -u)
+ run_podman run --rm --userns=keep-id $IMAGE id -u
+ is "${output}" "$user" "Container should run as the current user"
+ else
+ run_podman 125 run --rm --userns=keep-id $IMAGE id -u
+ is "${output}" "Error: keep-id is only supported in rootless mode" "Container should fail to start since keep-id is not suppored in rootful mode"
+ fi
}
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index 3db0804d1..92aabae32 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -111,6 +111,10 @@ load helpers
$IMAGE nc -l -n -v -p $myport
cid="$output"
+ # check that podman stores the network info correctly when a userns is used (#14465)
+ run_podman container inspect --format "{{.NetworkSettings.SandboxKey}}" $cid
+ assert "$output" =~ ".*/netns/netns-.*" "Netns path should be set"
+
wait_for_output "listening on .*:$myport .*" $cid
# emit random string, and check it
diff --git a/test/system/520-checkpoint.bats b/test/system/520-checkpoint.bats
index c16a8c35d..7f60f01b3 100644
--- a/test/system/520-checkpoint.bats
+++ b/test/system/520-checkpoint.bats
@@ -170,4 +170,34 @@ function teardown() {
# FIXME: test --leave-running
+@test "podman checkpoint --file-locks" {
+ action='flock test.lock sh -c "while [ -e /wait ];do sleep 0.5;done;for i in 1 2 3;do echo \$i;sleep 0.5;done"'
+ run_podman run -d $IMAGE sh -c "touch /wait; touch test.lock; echo READY; $action & $action & wait"
+ local cid="$output"
+
+ # Wait for container to start emitting output
+ wait_for_ready $cid
+
+ # Checkpoint, and confirm via inspect
+ run_podman container checkpoint --file-locks $cid
+ is "$output" "$cid" "podman container checkpoint"
+
+ run_podman container inspect \
+ --format '{{.State.Status}}:{{.State.Running}}:{{.State.Paused}}:{{.State.Checkpointed}}' $cid
+ is "$output" "exited:false:false:true" "State. Status:Running:Pause:Checkpointed"
+
+ # Restart immediately and confirm state
+ run_podman container restore --file-locks $cid
+ is "$output" "$cid" "podman container restore"
+
+ # Signal the container to continue; this is where the 1-2-3s will come from
+ run_podman exec $cid rm /wait
+
+ # Wait for the container to stop
+ run_podman wait $cid
+
+ run_podman logs $cid
+ trim=$(sed -z -e 's/[\r\n]\+//g' <<<"$output")
+ is "$trim" "READY123123" "File lock restored"
+}
# vim: filetype=sh
diff --git a/test/system/600-completion.bats b/test/system/600-completion.bats
index 018e95e78..cb4a2c5f8 100644
--- a/test/system/600-completion.bats
+++ b/test/system/600-completion.bats
@@ -8,6 +8,16 @@
load helpers
+function setup() {
+ # $PODMAN may be a space-separated string, e.g. if we include a --url.
+ local -a podman_as_array=($PODMAN)
+ # __completeNoDesc must be the first arg if we running the completion cmd
+ # set the var for the run_completion function
+ PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}"
+
+ basic_setup
+}
+
# Returns true if we are able to podman-pause
function _can_pause() {
# Even though we're just trying completion, not an actual unpause,
@@ -88,8 +98,14 @@ function check_shell_completion() {
continue 2
fi
+ name=$random_container_name
+ # special case podman cp suggest containers names with a colon
+ if [[ $cmd = "cp" ]]; then
+ name="$name:"
+ fi
+
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*-$random_container_name${nl}" \
+ is "$output" ".*-$name${nl}" \
"$* $cmd: actual container listed in suggestions"
match=true
@@ -175,7 +191,7 @@ function check_shell_completion() {
_check_completion_end NoSpace
else
_check_completion_end Default
- assert "${#lines[@]}" -eq 2 "$* $cmd: Suggestions are in the output"
+ _check_no_suggestions
fi
;;
@@ -205,16 +221,7 @@ function check_shell_completion() {
if [[ ! ${args##* } =~ "..." ]]; then
run_completion "$@" $cmd "${extra_args[@]}" ""
_check_completion_end NoFileComp
- if [ ${#lines[@]} -gt 2 ]; then
- # checking for line count is not enough since we may include additional debug output
- # lines starting with [Debug] are allowed
- i=0
- length=$(( ${#lines[@]} - 2 ))
- while [[ i -lt length ]]; do
- assert "${lines[$i]:0:7}" == "[Debug]" "Suggestions are in the output"
- i=$(( i + 1 ))
- done
- fi
+ _check_no_suggestions
fi
done
@@ -231,6 +238,24 @@ function _check_completion_end() {
is "${lines[-1]}" "Completion ended with directive: ShellCompDirective$1" "Completion has wrong ShellCompDirective set"
}
+# Check that there are no suggestions in the output.
+# We could only check stdout and not stderr but this is not possible with bats.
+# By default we always have two extra lines at the end for the ShellCompDirective.
+# Then we could also have other extra lines for debugging, they will always start
+# with [Debug], e.g. `[Debug] [Error] no container with name or ID "t12" found: no such container`.
+function _check_no_suggestions() {
+ if [ ${#lines[@]} -gt 2 ]; then
+ # Checking for line count is not enough since we may include additional debug output.
+ # Lines starting with [Debug] are allowed.
+ local i=0
+ length=$((${#lines[@]} - 2))
+ while [[ i -lt length ]]; do
+ assert "${lines[$i]:0:7}" == "[Debug]" "Unexpected non-Debug output line: ${lines[$i]}"
+ i=$((i + 1))
+ done
+ fi
+}
+
@test "podman shell completion test" {
@@ -280,11 +305,6 @@ function _check_completion_end() {
# create secret
run_podman secret create $random_secret_name $secret_file
- # $PODMAN may be a space-separated string, e.g. if we include a --url.
- local -a podman_as_array=($PODMAN)
- # __completeNoDesc must be the first arg if we running the completion cmd
- PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}"
-
# Called with no args -- start with 'podman --help'. check_shell_completion() will
# recurse for any subcommands.
check_shell_completion
@@ -316,3 +336,51 @@ function _check_completion_end() {
done <<<"$output"
}
+
+@test "podman shell completion for paths in container/image" {
+ skip_if_remote "mounting via remote does not work"
+ for cmd in create run; do
+ run_completion $cmd $IMAGE ""
+ assert "$output" =~ ".*^/etc/\$.*" "etc directory suggested (cmd: podman $cmd)"
+ assert "$output" =~ ".*^/home/\$.*" "home directory suggested (cmd: podman $cmd)"
+ assert "$output" =~ ".*^/root/\$.*" "root directory suggested (cmd: podman $cmd)"
+
+ # check completion for subdirectory
+ run_completion $cmd $IMAGE "/etc"
+ # It should be safe to assume the os-release file always exists in $IMAGE
+ assert "$output" =~ ".*^/etc/os-release\$.*" "/etc files suggested (cmd: podman $cmd /etc)"
+ # check completion for partial file name
+ run_completion $cmd $IMAGE "/etc/os-"
+ assert "$output" =~ ".*^/etc/os-release\$.*" "/etc files suggested (cmd: podman $cmd /etc/os-)"
+
+ # check completion with relative path components
+ # It is important the we will still use the image root and not escape to the host
+ run_completion $cmd $IMAGE "../../"
+ assert "$output" =~ ".*^../../etc/\$.*" "relative etc directory suggested (cmd: podman $cmd ../../)"
+ assert "$output" =~ ".*^../../home/\$.*" "relative home directory suggested (cmd: podman $cmd ../../)"
+ done
+
+ random_name=$(random_string 30)
+ random_file=$(random_string 30)
+ run_podman run --name $random_name $IMAGE sh -c "touch /tmp/$random_file && touch /tmp/${random_file}2 && mkdir /emptydir"
+
+ # check completion for podman cp
+ run_completion cp ""
+ assert "$output" =~ ".*^$random_name\:\$.*" "podman cp suggest container names"
+
+ run_completion cp "$random_name:"
+ assert "$output" =~ ".*^$random_name\:/etc/\$.*" "podman cp suggest paths in container"
+
+ run_completion cp "$random_name:/tmp"
+ assert "$output" =~ ".*^$random_name\:/tmp/$random_file\$.*" "podman cp suggest custom file in container"
+
+ run_completion cp "$random_name:/tmp/$random_file"
+ assert "$output" =~ ".*^$random_name\:/tmp/$random_file\$.*" "podman cp suggest /tmp/$random_file file in container"
+ assert "$output" =~ ".*^$random_name\:/tmp/${random_file}2\$.*" "podman cp suggest /tmp/${random_file}2 file in container"
+
+ run_completion cp "$random_name:/emptydir"
+ assert "$output" =~ ".*^$random_name\:/emptydir/\$.*ShellCompDirectiveNoSpace" "podman cp suggest empty dir with no space directive (:2)"
+
+ # cleanup container
+ run_podman rm $random_name
+}
diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
index e79bffe63..55ed392a0 100644
--- a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
+++ b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go
@@ -16,6 +16,7 @@ package invoke
import (
"context"
+ "encoding/json"
"fmt"
"os"
@@ -33,6 +34,43 @@ type Exec interface {
Decode(jsonBytes []byte) (version.PluginInfo, error)
}
+// Plugin must return result in same version as specified in netconf; but
+// for backwards compatibility reasons if the result version is empty use
+// config version (rather than technically correct 0.1.0).
+// https://github.com/containernetworking/cni/issues/895
+func fixupResultVersion(netconf, result []byte) (string, []byte, error) {
+ versionDecoder := &version.ConfigDecoder{}
+ confVersion, err := versionDecoder.Decode(netconf)
+ if err != nil {
+ return "", nil, err
+ }
+
+ var rawResult map[string]interface{}
+ if err := json.Unmarshal(result, &rawResult); err != nil {
+ return "", nil, fmt.Errorf("failed to unmarshal raw result: %w", err)
+ }
+
+ // Manually decode Result version; we need to know whether its cniVersion
+ // is empty, while built-in decoders (correctly) substitute 0.1.0 for an
+ // empty version per the CNI spec.
+ if resultVerRaw, ok := rawResult["cniVersion"]; ok {
+ resultVer, ok := resultVerRaw.(string)
+ if ok && resultVer != "" {
+ return resultVer, result, nil
+ }
+ }
+
+ // If the cniVersion is not present or empty, assume the result is
+ // the same CNI spec version as the config
+ rawResult["cniVersion"] = confVersion
+ newBytes, err := json.Marshal(rawResult)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to remarshal fixed result: %w", err)
+ }
+
+ return confVersion, newBytes, nil
+}
+
// For example, a testcase could pass an instance of the following fakeExec
// object to ExecPluginWithResult() to verify the incoming stdin and environment
// and provide a tailored response:
@@ -84,7 +122,12 @@ func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte
return nil, err
}
- return create.CreateFromBytes(stdoutBytes)
+ resultVersion, fixedBytes, err := fixupResultVersion(netconf, stdoutBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ return create.Create(resultVersion, fixedBytes)
}
func ExecPluginWithoutResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) error {
diff --git a/vendor/github.com/containers/common/libimage/inspect.go b/vendor/github.com/containers/common/libimage/inspect.go
index 05d60edfc..ae06acd2c 100644
--- a/vendor/github.com/containers/common/libimage/inspect.go
+++ b/vendor/github.com/containers/common/libimage/inspect.go
@@ -128,7 +128,7 @@ func (i *Image) Inspect(ctx context.Context, options *InspectOptions) (*ImageDat
Config: &ociImage.Config,
Version: info.DockerVersion,
Size: size,
- VirtualSize: size, // TODO: they should be different (inherited from Podman)
+ VirtualSize: size, // NOTE: same as size. Inherited from Docker where it's scheduled for deprecation.
Digest: i.Digest(),
Labels: info.Labels,
RootFS: &RootFS{
diff --git a/vendor/github.com/containers/common/libimage/pull.go b/vendor/github.com/containers/common/libimage/pull.go
index 771756160..d204ef1c4 100644
--- a/vendor/github.com/containers/common/libimage/pull.go
+++ b/vendor/github.com/containers/common/libimage/pull.go
@@ -533,9 +533,6 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
sys := r.systemContextCopy()
resolved, err := shortnames.Resolve(sys, imageName)
if err != nil {
- // TODO: that is a too big of a hammer since we should only
- // ignore errors that indicate that there's no alias and no
- // USRs. Must be addressed in c/image first.
if localImage != nil && pullPolicy == config.PullPolicyNewer {
return []string{resolvedImageName}, nil
}
diff --git a/vendor/github.com/containers/common/libnetwork/resolvconf/resolv.go b/vendor/github.com/containers/common/libnetwork/resolvconf/resolv.go
new file mode 100644
index 000000000..c451d3b49
--- /dev/null
+++ b/vendor/github.com/containers/common/libnetwork/resolvconf/resolv.go
@@ -0,0 +1,182 @@
+package resolvconf
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/common/pkg/util"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/sirupsen/logrus"
+)
+
+const (
+ localhost = "127.0.0.1"
+ systemdResolvedIP = "127.0.0.53"
+)
+
+// Params for the New() function.
+type Params struct {
+ // Path is the path to new resolv.conf file which should be created.
+ Path string
+ // Namespaces is the list of container namespaces.
+ // This is required to fist check for a resolv.conf under /etc/netns,
+ // created by "ip netns". Also used to check if the container has a
+ // netns in which case localhost nameserver must be filtered.
+ Namespaces []specs.LinuxNamespace
+ // IPv6Enabled will filter ipv6 nameservers when not set to true.
+ IPv6Enabled bool
+ // KeepHostServers can be set when it is required to still keep the
+ // original resolv.conf content even when custom Nameserver/Searches/Options
+ // are set. In this case they will be appended to the given values.
+ KeepHostServers bool
+ // Nameservers is a list of nameservers the container should use,
+ // instead of the default ones from the host.
+ Nameservers []string
+ // Searches is a list of dns search domains the container should use,
+ // instead of the default ones from the host.
+ Searches []string
+ // Options is a list of dns options the container should use,
+ // instead of the default ones from the host.
+ Options []string
+
+ // resolvConfPath is the path which should be used as base to get the dns
+ // options. This should only be used for testing purposes. For all other
+ // callers this defaults to /etc/resolv.conf.
+ resolvConfPath string
+}
+
+func getDefaultResolvConf(params *Params) ([]byte, bool, error) {
+ resolveConf := DefaultResolvConf
+ // this is only used by testing
+ if params.resolvConfPath != "" {
+ resolveConf = params.resolvConfPath
+ }
+ hostNS := true
+ for _, ns := range params.Namespaces {
+ if ns.Type == specs.NetworkNamespace {
+ hostNS = false
+ if ns.Path != "" && !strings.HasPrefix(ns.Path, "/proc/") {
+ // check for netns created by "ip netns"
+ path := filepath.Join("/etc/netns", filepath.Base(ns.Path), "resolv.conf")
+ _, err := os.Stat(path)
+ if err == nil {
+ resolveConf = path
+ }
+ }
+ break
+ }
+ }
+
+ contents, err := os.ReadFile(resolveConf)
+ if err != nil && !errors.Is(err, os.ErrNotExist) {
+ return nil, false, err
+ }
+ if hostNS {
+ return contents, hostNS, nil
+ }
+
+ ns := getNameservers(contents)
+ // Check for local only resolver, in this case we want to get the real nameservers
+ // since localhost is not reachable from the netns.
+ if len(ns) == 1 {
+ var path string
+ switch ns[0] {
+ case systemdResolvedIP:
+ // used by systemd-resolved
+ path = "/run/systemd/resolve/resolv.conf"
+ case localhost:
+ // used by NetworkManager https://github.com/containers/podman/issues/13599
+ path = "/run/NetworkManager/no-stub-resolv.conf"
+ }
+ if path != "" {
+ // read the actual resolv.conf file for
+ resolvedContents, err := os.ReadFile(path)
+ if err != nil {
+ // do not error when the file does not exists, the detection logic is not perfect
+ if !errors.Is(err, os.ErrNotExist) {
+ return nil, false, fmt.Errorf("local resolver detected, but could not read real resolv.conf at %q: %w", path, err)
+ }
+ } else {
+ logrus.Debugf("found local resolver, using %q to get the nameservers", path)
+ contents = resolvedContents
+ }
+ }
+ }
+
+ return contents, hostNS, nil
+}
+
+// unsetSearchDomainsIfNeeded removes the search domain when they contain a single dot as element.
+func unsetSearchDomainsIfNeeded(searches []string) []string {
+ if util.StringInSlice(".", searches) {
+ return nil
+ }
+ return searches
+}
+
+// New creates a new resolv.conf file with the given params.
+func New(params *Params) error {
+ // short path, if everything is given there is no need to actually read the hosts /etc/resolv.conf
+ if len(params.Nameservers) > 0 && len(params.Options) > 0 && len(params.Searches) > 0 && !params.KeepHostServers {
+ return build(params.Path, params.Nameservers, unsetSearchDomainsIfNeeded(params.Searches), params.Options)
+ }
+
+ content, hostNS, err := getDefaultResolvConf(params)
+ if err != nil {
+ return fmt.Errorf("failed to get the default /etc/resolv.conf content: %w", err)
+ }
+
+ content = filterResolvDNS(content, params.IPv6Enabled, !hostNS)
+
+ nameservers := params.Nameservers
+ if len(nameservers) == 0 || params.KeepHostServers {
+ nameservers = append(nameservers, getNameservers(content)...)
+ }
+
+ searches := unsetSearchDomainsIfNeeded(params.Searches)
+ // if no params.Searches then use host ones
+ // otherwise make sure that they were no explicitly unset before adding host ones
+ if len(params.Searches) == 0 || (params.KeepHostServers && len(searches) > 0) {
+ searches = append(searches, getSearchDomains(content)...)
+ }
+
+ options := params.Options
+ if len(options) == 0 || params.KeepHostServers {
+ options = append(options, getOptions(content)...)
+ }
+
+ return build(params.Path, nameservers, searches, options)
+}
+
+// Add will add the given nameservers to the given resolv.conf file.
+// It will add the nameserver in front of the existing ones.
+func Add(path string, nameservers []string) error {
+ contents, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+
+ nameservers = append(nameservers, getNameservers(contents)...)
+ return build(path, nameservers, getSearchDomains(contents), getOptions(contents))
+}
+
+// Remove the given nameserver from the given resolv.conf file.
+func Remove(path string, nameservers []string) error {
+ contents, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+
+ oldNameservers := getNameservers(contents)
+ newNameserver := make([]string, 0, len(oldNameservers))
+ for _, ns := range oldNameservers {
+ if !util.StringInSlice(ns, nameservers) {
+ newNameserver = append(newNameserver, ns)
+ }
+ }
+
+ return build(path, newNameserver, getSearchDomains(contents), getOptions(contents))
+}
diff --git a/pkg/resolvconf/resolvconf.go b/vendor/github.com/containers/common/libnetwork/resolvconf/resolvconf.go
index f23cd61b0..54b8c3227 100644
--- a/pkg/resolvconf/resolvconf.go
+++ b/vendor/github.com/containers/common/libnetwork/resolvconf/resolvconf.go
@@ -1,26 +1,23 @@
// Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf.
-// Originally from github.com/docker/libnetwork/resolvconf.
+// Originally from github.com/docker/libnetwork/resolvconf but heavily modified to better work with podman.
package resolvconf
import (
"bytes"
- "io/ioutil"
+ "os"
"regexp"
"strings"
- "sync"
- "github.com/containers/podman/v4/pkg/resolvconf/dns"
- "github.com/containers/storage/pkg/ioutils"
"github.com/sirupsen/logrus"
)
const (
- // DefaultResolvConf points to the default file used for dns configuration on a linux machine
+ // DefaultResolvConf points to the default file used for dns configuration on a linux machine.
DefaultResolvConf = "/etc/resolv.conf"
)
var (
- // Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS
+ // Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS.
defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"}
defaultIPv6Dns = []string{"nameserver 2001:4860:4860::8888", "nameserver 2001:4860:4860::8844"}
ipv4NumBlock = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)`
@@ -29,94 +26,30 @@ var (
// will *not match* IPv4-Embedded IPv6 Addresses (RFC6052), but that and other variants
// -- e.g. other link-local types -- either won't work in containers or are unnecessary.
// For readability and sufficiency for Docker purposes this seemed more reasonable than a
- // 1000+ character regexp with exact and complete IPv6 validation
+ // 1000+ character regexp with exact and complete IPv6 validation.
ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})(%\w+)?`
- localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`)
+ // ipLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
+ ipLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
+
+ localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipLocalhost + `\s*\n*`)
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
)
-var lastModified struct {
- sync.Mutex
- sha256 string
- contents []byte
-}
-
-// File contains the resolv.conf content and its hash
-type File struct {
- Content []byte
- Hash string
-}
-
-// Get returns the contents of /etc/resolv.conf and its hash
-func Get() (*File, error) {
- return GetSpecific(DefaultResolvConf)
-}
-
-// GetSpecific returns the contents of the user specified resolv.conf file and its hash
-func GetSpecific(path string) (*File, error) {
- resolv, err := ioutil.ReadFile(path)
- if err != nil {
- return nil, err
- }
- hash, err := ioutils.HashData(bytes.NewReader(resolv))
- if err != nil {
- return nil, err
- }
- return &File{Content: resolv, Hash: hash}, nil
-}
-
-// GetIfChanged retrieves the host /etc/resolv.conf file, checks against the last hash
-// and, if modified since last check, returns the bytes and new hash.
-// This feature is used by the resolv.conf updater for containers
-func GetIfChanged() (*File, error) {
- lastModified.Lock()
- defer lastModified.Unlock()
-
- resolv, err := ioutil.ReadFile("/etc/resolv.conf")
- if err != nil {
- return nil, err
- }
- newHash, err := ioutils.HashData(bytes.NewReader(resolv))
- if err != nil {
- return nil, err
- }
- if lastModified.sha256 != newHash {
- lastModified.sha256 = newHash
- lastModified.contents = resolv
- return &File{Content: resolv, Hash: newHash}, nil
- }
- // nothing changed, so return no data
- return nil, nil
-}
-
-// GetLastModified retrieves the last used contents and hash of the host resolv.conf.
-// Used by containers updating on restart
-func GetLastModified() *File {
- lastModified.Lock()
- defer lastModified.Unlock()
-
- return &File{Content: lastModified.contents, Hash: lastModified.sha256}
-}
-
-// FilterResolvDNS cleans up the config in resolvConf. It has two main jobs:
+// filterResolvDNS cleans up the config in resolvConf. It has two main jobs:
// 1. If a netns is enabled, it looks for localhost (127.*|::1) entries in the provided
// resolv.conf, removing local nameserver entries, and, if the resulting
// cleaned config has no defined nameservers left, adds default DNS entries
// 2. Given the caller provides the enable/disable state of IPv6, the filter
// code will remove all IPv6 nameservers if it is not enabled for containers
//
-func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) (*File, error) {
+func filterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) []byte {
// If we're using the host netns, we have nothing to do besides hash the file.
if !netnsEnabled {
- hash, err := ioutils.HashData(bytes.NewReader(resolvConf))
- if err != nil {
- return nil, err
- }
- return &File{Content: resolvConf, Hash: hash}, nil
+ return resolvConf
}
cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
// if IPv6 is not enabled, also clean out any IPv6 address nameserver
@@ -125,7 +58,7 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) (*F
}
// if the resulting resolvConf has no more nameservers defined, add appropriate
// default DNS servers for IPv4 and (optionally) IPv6
- if len(GetNameservers(cleanedResolvConf)) == 0 {
+ if len(getNameservers(cleanedResolvConf)) == 0 {
logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: %v", defaultIPv4Dns)
dns := defaultIPv4Dns
if ipv6Enabled {
@@ -134,19 +67,15 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) (*F
}
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
}
- hash, err := ioutils.HashData(bytes.NewReader(cleanedResolvConf))
- if err != nil {
- return nil, err
- }
- return &File{Content: cleanedResolvConf, Hash: hash}, nil
+ return cleanedResolvConf
}
// getLines parses input into lines and strips away comments.
-func getLines(input []byte, commentMarker []byte) [][]byte {
+func getLines(input []byte) [][]byte {
lines := bytes.Split(input, []byte("\n"))
var output [][]byte
for _, currentLine := range lines {
- var commentIndex = bytes.Index(currentLine, commentMarker)
+ commentIndex := bytes.Index(currentLine, []byte("#"))
if commentIndex == -1 {
output = append(output, currentLine)
} else {
@@ -156,10 +85,10 @@ func getLines(input []byte, commentMarker []byte) [][]byte {
return output
}
-// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf
-func GetNameservers(resolvConf []byte) []string {
+// getNameservers returns nameservers (if any) listed in /etc/resolv.conf.
+func getNameservers(resolvConf []byte) []string {
nameservers := []string{}
- for _, line := range getLines(resolvConf, []byte("#")) {
+ for _, line := range getLines(resolvConf) {
ns := nsRegexp.FindSubmatch(line)
if len(ns) > 0 {
nameservers = append(nameservers, string(ns[1]))
@@ -168,30 +97,12 @@ func GetNameservers(resolvConf []byte) []string {
return nameservers
}
-// GetNameserversAsCIDR returns nameservers (if any) listed in
-// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32")
-// This function's output is intended for net.ParseCIDR
-func GetNameserversAsCIDR(resolvConf []byte) []string {
- nameservers := []string{}
- for _, nameserver := range GetNameservers(resolvConf) {
- var address string
- // If IPv6, strip zone if present
- if strings.Contains(nameserver, ":") {
- address = strings.Split(nameserver, "%")[0] + "/128"
- } else {
- address = nameserver + "/32"
- }
- nameservers = append(nameservers, address)
- }
- return nameservers
-}
-
-// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf
+// getSearchDomains returns search domains (if any) listed in /etc/resolv.conf
// If more than one search line is encountered, only the contents of the last
// one is returned.
-func GetSearchDomains(resolvConf []byte) []string {
+func getSearchDomains(resolvConf []byte) []string {
domains := []string{}
- for _, line := range getLines(resolvConf, []byte("#")) {
+ for _, line := range getLines(resolvConf) {
match := searchRegexp.FindSubmatch(line)
if match == nil {
continue
@@ -201,12 +112,12 @@ func GetSearchDomains(resolvConf []byte) []string {
return domains
}
-// GetOptions returns options (if any) listed in /etc/resolv.conf
+// getOptions returns options (if any) listed in /etc/resolv.conf
// If more than one options line is encountered, only the contents of the last
// one is returned.
-func GetOptions(resolvConf []byte) []string {
+func getOptions(resolvConf []byte) []string {
options := []string{}
- for _, line := range getLines(resolvConf, []byte("#")) {
+ for _, line := range getLines(resolvConf) {
match := optionsRegexp.FindSubmatch(line)
if match == nil {
continue
@@ -216,35 +127,30 @@ func GetOptions(resolvConf []byte) []string {
return options
}
-// Build writes a configuration file to path containing a "nameserver" entry
+// build writes a configuration file to path containing a "nameserver" entry
// for every element in dns, a "search" entry for every element in
// dnsSearch, and an "options" entry for every element in dnsOptions.
-func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) {
- content := bytes.NewBuffer(nil)
+func build(path string, dns, dnsSearch, dnsOptions []string) error {
+ content := new(bytes.Buffer)
if len(dnsSearch) > 0 {
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
- return nil, err
+ return err
}
}
}
for _, dns := range dns {
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
- return nil, err
+ return err
}
}
if len(dnsOptions) > 0 {
if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
- return nil, err
+ return err
}
}
}
- hash, err := ioutils.HashData(bytes.NewReader(content.Bytes()))
- if err != nil {
- return nil, err
- }
-
- return &File{Content: content.Bytes(), Hash: hash}, ioutil.WriteFile(path, content.Bytes(), 0644)
+ return os.WriteFile(path, content.Bytes(), 0o644)
}
diff --git a/vendor/github.com/docker/docker/api/swagger.yaml b/vendor/github.com/docker/docker/api/swagger.yaml
index b6bca4cef..0bbe74700 100644
--- a/vendor/github.com/docker/docker/api/swagger.yaml
+++ b/vendor/github.com/docker/docker/api/swagger.yaml
@@ -3347,7 +3347,7 @@ definitions:
Limits:
description: "Define resources limits."
$ref: "#/definitions/Limit"
- Reservation:
+ Reservations:
description: "Define resources reservation."
$ref: "#/definitions/ResourceObject"
RestartPolicy:
diff --git a/vendor/github.com/docker/docker/pkg/system/mknod.go b/vendor/github.com/docker/docker/pkg/system/mknod.go
index 5734d47d4..d27152c0f 100644
--- a/vendor/github.com/docker/docker/pkg/system/mknod.go
+++ b/vendor/github.com/docker/docker/pkg/system/mknod.go
@@ -7,12 +7,6 @@ import (
"golang.org/x/sys/unix"
)
-// Mknod creates a filesystem node (file, device special file or named pipe) named path
-// with attributes specified by mode and dev.
-func Mknod(path string, mode uint32, dev int) error {
- return unix.Mknod(path, mode, dev)
-}
-
// Mkdev is used to build the value of linux devices (in /dev/) which specifies major
// and minor number of the newly created device special file.
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
diff --git a/vendor/github.com/docker/docker/pkg/system/mknod_freebsd.go b/vendor/github.com/docker/docker/pkg/system/mknod_freebsd.go
new file mode 100644
index 000000000..c890be116
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/system/mknod_freebsd.go
@@ -0,0 +1,14 @@
+//go:build freebsd
+// +build freebsd
+
+package system // import "github.com/docker/docker/pkg/system"
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// Mknod creates a filesystem node (file, device special file or named pipe) named path
+// with attributes specified by mode and dev.
+func Mknod(path string, mode uint32, dev int) error {
+ return unix.Mknod(path, mode, uint64(dev))
+}
diff --git a/vendor/github.com/docker/docker/pkg/system/mknod_unix.go b/vendor/github.com/docker/docker/pkg/system/mknod_unix.go
new file mode 100644
index 000000000..4586aad19
--- /dev/null
+++ b/vendor/github.com/docker/docker/pkg/system/mknod_unix.go
@@ -0,0 +1,14 @@
+//go:build !freebsd && !windows
+// +build !freebsd,!windows
+
+package system // import "github.com/docker/docker/pkg/system"
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+// Mknod creates a filesystem node (file, device special file or named pipe) named path
+// with attributes specified by mode and dev.
+func Mknod(path string, mode uint32, dev int) error {
+ return unix.Mknod(path, mode, dev)
+}
diff --git a/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml b/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml
new file mode 100644
index 000000000..7df8aa198
--- /dev/null
+++ b/vendor/github.com/seccomp/libseccomp-golang/.golangci.yml
@@ -0,0 +1,4 @@
+# For documentation, see https://golangci-lint.run/usage/configuration/
+linters:
+ enable:
+ - gofumpt
diff --git a/vendor/github.com/seccomp/libseccomp-golang/.travis.yml b/vendor/github.com/seccomp/libseccomp-golang/.travis.yml
deleted file mode 100644
index 5240d4622..000000000
--- a/vendor/github.com/seccomp/libseccomp-golang/.travis.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-# Travis CI configuration for libseccomp-golang
-
-# https://docs.travis-ci.com/user/reference/bionic
-# https://wiki.ubuntu.com/Releases
-
-dist: bionic
-sudo: false
-
-notifications:
- email:
- on_success: always
- on_failure: always
-
-arch:
- - amd64
-
-os:
- - linux
-
-language: go
-
-jobs:
- include:
- - name: "last libseccomp 2.5.0"
- env:
- - SECCOMP_VER=2.5.0
- - SECCOMP_SHA256SUM=1ffa7038d2720ad191919816db3479295a4bcca1ec14e02f672539f4983014f3
- - name: "compat libseccomp 2.4.4"
- env:
- - SECCOMP_VER=2.4.4
- - SECCOMP_SHA256SUM=4e79738d1ef3c9b7ca9769f1f8b8d84fc17143c2c1c432e53b9c64787e0ff3eb
- - name: "compat libseccomp 2.2.1"
- env:
- - SECCOMP_VER=2.2.1
- - SECCOMP_SHA256SUM=0ba1789f54786c644af54cdffc9fd0dd0a8bb2b2ee153933f658855d2851a740
-
-addons:
- apt:
- packages:
- - build-essential
- - astyle
- - golint
- - gperf
-
-install:
- - go get -u golang.org/x/lint/golint
-
-# run all of the tests independently, fail if any of the tests error
-script:
- - wget https://github.com/seccomp/libseccomp/releases/download/v$SECCOMP_VER/libseccomp-$SECCOMP_VER.tar.gz
- - echo $SECCOMP_SHA256SUM libseccomp-$SECCOMP_VER.tar.gz | sha256sum -c
- - tar xf libseccomp-$SECCOMP_VER.tar.gz
- - pushd libseccomp-$SECCOMP_VER && ./configure --prefix=/opt/libseccomp-$SECCOMP_VER && make && sudo make install && popd
- - make check-syntax
- - make lint
- - PKG_CONFIG_PATH=/opt/libseccomp-$SECCOMP_VER/lib/pkgconfig LD_LIBRARY_PATH=/opt/libseccomp-$SECCOMP_VER/lib make vet
- - PKG_CONFIG_PATH=/opt/libseccomp-$SECCOMP_VER/lib/pkgconfig LD_LIBRARY_PATH=/opt/libseccomp-$SECCOMP_VER/lib make test
diff --git a/vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md b/vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md
index d6862cbd5..c2fc80d5a 100644
--- a/vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md
+++ b/vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md
@@ -1,31 +1,23 @@
-How to Submit Patches to the libseccomp Project
+How to Submit Patches to the libseccomp-golang Project
===============================================================================
https://github.com/seccomp/libseccomp-golang
This document is intended to act as a guide to help you contribute to the
-libseccomp project. It is not perfect, and there will always be exceptions
-to the rules described here, but by following the instructions below you
-should have a much easier time getting your work merged with the upstream
+libseccomp-golang project. It is not perfect, and there will always be
+exceptions to the rules described here, but by following the instructions below
+you should have a much easier time getting your work merged with the upstream
project.
## Test Your Code Using Existing Tests
-There are two possible tests you can run to verify your code. The first
-test is used to check the formatting and coding style of your changes, you
-can run the test with the following command:
-
- # make check-syntax
-
-... if there are any problems with your changes a diff/patch will be shown
-which indicates the problems and how to fix them.
-
-The second possible test is used to ensure the sanity of your code changes
-and to test these changes against the included tests. You can run the test
-with the following command:
+A number of tests and lint related recipes are provided in the Makefile, if
+you want to run the standard regression tests, you can execute the following:
# make check
-... if there are any faults or errors they will be displayed.
+In order to use it, the 'golangci-lint' tool is needed, which can be found at:
+
+* https://github.com/golangci/golangci-lint
## Add New Tests for New Functionality
diff --git a/vendor/github.com/seccomp/libseccomp-golang/Makefile b/vendor/github.com/seccomp/libseccomp-golang/Makefile
index 38cfa852c..530f5b4ad 100644
--- a/vendor/github.com/seccomp/libseccomp-golang/Makefile
+++ b/vendor/github.com/seccomp/libseccomp-golang/Makefile
@@ -4,7 +4,7 @@
all: check-build
-check: vet test
+check: lint test
check-build:
go build
@@ -16,7 +16,7 @@ fix-syntax:
gofmt -w .
vet:
- go vet -v
+ go vet -v ./...
# Previous bugs have made the tests freeze until the timeout. Golang default
# timeout for tests is 10 minutes, which is too long, considering current tests
@@ -28,5 +28,4 @@ test:
go test -v -timeout $(TEST_TIMEOUT)
lint:
- @$(if $(shell which golint),true,$(error "install golint and include it in your PATH"))
- golint -set_exit_status
+ golangci-lint run .
diff --git a/vendor/github.com/seccomp/libseccomp-golang/README.md b/vendor/github.com/seccomp/libseccomp-golang/README.md
index 806a5ddf2..6430f1c9e 100644
--- a/vendor/github.com/seccomp/libseccomp-golang/README.md
+++ b/vendor/github.com/seccomp/libseccomp-golang/README.md
@@ -2,7 +2,9 @@
===============================================================================
https://github.com/seccomp/libseccomp-golang
-[![Build Status](https://img.shields.io/travis/seccomp/libseccomp-golang/main.svg)](https://travis-ci.org/seccomp/libseccomp-golang)
+[![Go Reference](https://pkg.go.dev/badge/github.com/seccomp/libseccomp-golang.svg)](https://pkg.go.dev/github.com/seccomp/libseccomp-golang)
+[![validate](https://github.com/seccomp/libseccomp-golang/actions/workflows/validate.yml/badge.svg)](https://github.com/seccomp/libseccomp-golang/actions/workflows/validate.yml)
+[![test](https://github.com/seccomp/libseccomp-golang/actions/workflows/test.yml/badge.svg)](https://github.com/seccomp/libseccomp-golang/actions/workflows/test.yml)
The libseccomp library provides an easy to use, platform independent, interface
to the Linux Kernel's syscall filtering mechanism. The libseccomp API is
@@ -26,26 +28,14 @@ list.
* https://groups.google.com/d/forum/libseccomp
-Documentation is also available at:
+Documentation for this package is also available at:
-* https://godoc.org/github.com/seccomp/libseccomp-golang
+* https://pkg.go.dev/github.com/seccomp/libseccomp-golang
## Installing the package
-The libseccomp-golang bindings require at least Go v1.2.1 and GCC v4.8.4;
-earlier versions may yield unpredictable results. If you meet these
-requirements you can install this package using the command below:
-
# go get github.com/seccomp/libseccomp-golang
-## Testing the Library
-
-A number of tests and lint related recipes are provided in the Makefile, if
-you want to run the standard regression tests, you can excute the following:
-
- # make check
-
-In order to execute the 'make lint' recipe the 'golint' tool is needed, it
-can be found at:
+## Contributing
-* https://github.com/golang/lint
+See [CONTRIBUTING.md](CONTRIBUTING.md).
diff --git a/vendor/github.com/seccomp/libseccomp-golang/SECURITY.md b/vendor/github.com/seccomp/libseccomp-golang/SECURITY.md
new file mode 100644
index 000000000..c448faa8e
--- /dev/null
+++ b/vendor/github.com/seccomp/libseccomp-golang/SECURITY.md
@@ -0,0 +1,47 @@
+The libseccomp-golang Security Vulnerability Handling Process
+===============================================================================
+https://github.com/seccomp/libseccomp-golang
+
+This document document attempts to describe the processes through which
+sensitive security relevant bugs can be responsibly disclosed to the
+libseccomp-golang project and how the project maintainers should handle these
+reports. Just like the other libseccomp-golang process documents, this
+document should be treated as a guiding document and not a hard, unyielding set
+of regulations; the bug reporters and project maintainers are encouraged to
+work together to address the issues as best they can, in a manner which works
+best for all parties involved.
+
+### Reporting Problems
+
+Problems with the libseccomp-golang library that are not suitable for immediate
+public disclosure should be emailed to the current libseccomp-golang
+maintainers, the list is below. We typically request at most a 90 day time
+period to address the issue before it is made public, but we will make every
+effort to address the issue as quickly as possible and shorten the disclosure
+window.
+
+* Paul Moore, paul@paul-moore.com
+* Tom Hromatka, tom.hromatka@oracle.com
+
+### Resolving Sensitive Security Issues
+
+Upon disclosure of a bug, the maintainers should work together to investigate
+the problem and decide on a solution. In order to prevent an early disclosure
+of the problem, those working on the solution should do so privately and
+outside of the traditional libseccomp-golang development practices. One
+possible solution to this is to leverage the GitHub "Security" functionality to
+create a private development fork that can be shared among the maintainers, and
+optionally the reporter. A placeholder GitHub issue may be created, but
+details should remain extremely limited until such time as the problem has been
+fixed and responsibly disclosed. If a CVE, or other tag, has been assigned to
+the problem, the GitHub issue title should include the vulnerability tag once
+the problem has been disclosed.
+
+### Public Disclosure
+
+Whenever possible, responsible reporting and patching practices should be
+followed, including notification to the linux-distros and oss-security mailing
+lists.
+
+* https://oss-security.openwall.org/wiki/mailing-lists/distros
+* https://oss-security.openwall.org/wiki/mailing-lists/oss-security
diff --git a/vendor/github.com/seccomp/libseccomp-golang/go.sum b/vendor/github.com/seccomp/libseccomp-golang/go.sum
index 72ae16111..e69de29bb 100644
--- a/vendor/github.com/seccomp/libseccomp-golang/go.sum
+++ b/vendor/github.com/seccomp/libseccomp-golang/go.sum
@@ -1,23 +0,0 @@
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200313205530-4303120df7d8 h1:gkI/wGGwpcG5W4hLCzZNGxA4wzWBGGDStRI1MrjDl2Q=
-golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/vendor/github.com/seccomp/libseccomp-golang/seccomp.go b/vendor/github.com/seccomp/libseccomp-golang/seccomp.go
index e9b92e221..8dad12fdb 100644
--- a/vendor/github.com/seccomp/libseccomp-golang/seccomp.go
+++ b/vendor/github.com/seccomp/libseccomp-golang/seccomp.go
@@ -1,5 +1,3 @@
-// +build linux
-
// Public API specification for libseccomp Go bindings
// Contains public API for the bindings
@@ -18,48 +16,36 @@ import (
"unsafe"
)
-// C wrapping code
-
-// To compile libseccomp-golang against a specific version of libseccomp:
-// cd ../libseccomp && mkdir -p prefix
-// ./configure --prefix=$PWD/prefix && make && make install
-// cd ../libseccomp-golang
-// PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make
-// LD_PRELOAD=$PWD/../libseccomp/prefix/lib/libseccomp.so.2.5.0 PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make test
-
-// #cgo pkg-config: libseccomp
// #include <stdlib.h>
// #include <seccomp.h>
import "C"
// Exported types
-// VersionError denotes that the system libseccomp version is incompatible
-// with this package.
+// VersionError represents an error when either the system libseccomp version
+// or the kernel version is too old to perform the operation requested.
type VersionError struct {
- message string
- minimum string
+ op string // operation that failed or would fail
+ major, minor, micro uint // minimally required libseccomp version
+ curAPI, minAPI uint // current and minimally required API versions
}
func init() {
// This forces the cgo libseccomp to initialize its internal API support state,
// which is necessary on older versions of libseccomp in order to work
// correctly.
- GetAPI()
+ _, _ = getAPI()
}
func (e VersionError) Error() string {
- messageStr := ""
- if e.message != "" {
- messageStr = e.message + ": "
+ if e.minAPI != 0 {
+ return fmt.Sprintf("%s requires libseccomp >= %d.%d.%d and API level >= %d "+
+ "(current version: %d.%d.%d, API level: %d)",
+ e.op, e.major, e.minor, e.micro, e.minAPI,
+ verMajor, verMinor, verMicro, e.curAPI)
}
- minimumStr := ""
- if e.minimum != "" {
- minimumStr = e.minimum
- } else {
- minimumStr = "2.2.0"
- }
- return fmt.Sprintf("Libseccomp version too low: %sminimum supported is %s: detected %d.%d.%d", messageStr, minimumStr, verMajor, verMinor, verMicro)
+ return fmt.Sprintf("%s requires libseccomp >= %d.%d.%d (current version: %d.%d.%d)",
+ e.op, e.major, e.minor, e.micro, verMajor, verMinor, verMicro)
}
// ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a
@@ -148,44 +134,46 @@ const (
// variables are invalid
ArchInvalid ScmpArch = iota
// ArchNative is the native architecture of the kernel
- ArchNative ScmpArch = iota
+ ArchNative
// ArchX86 represents 32-bit x86 syscalls
- ArchX86 ScmpArch = iota
+ ArchX86
// ArchAMD64 represents 64-bit x86-64 syscalls
- ArchAMD64 ScmpArch = iota
+ ArchAMD64
// ArchX32 represents 64-bit x86-64 syscalls (32-bit pointers)
- ArchX32 ScmpArch = iota
+ ArchX32
// ArchARM represents 32-bit ARM syscalls
- ArchARM ScmpArch = iota
+ ArchARM
// ArchARM64 represents 64-bit ARM syscalls
- ArchARM64 ScmpArch = iota
+ ArchARM64
// ArchMIPS represents 32-bit MIPS syscalls
- ArchMIPS ScmpArch = iota
+ ArchMIPS
// ArchMIPS64 represents 64-bit MIPS syscalls
- ArchMIPS64 ScmpArch = iota
+ ArchMIPS64
// ArchMIPS64N32 represents 64-bit MIPS syscalls (32-bit pointers)
- ArchMIPS64N32 ScmpArch = iota
+ ArchMIPS64N32
// ArchMIPSEL represents 32-bit MIPS syscalls (little endian)
- ArchMIPSEL ScmpArch = iota
+ ArchMIPSEL
// ArchMIPSEL64 represents 64-bit MIPS syscalls (little endian)
- ArchMIPSEL64 ScmpArch = iota
+ ArchMIPSEL64
// ArchMIPSEL64N32 represents 64-bit MIPS syscalls (little endian,
// 32-bit pointers)
- ArchMIPSEL64N32 ScmpArch = iota
+ ArchMIPSEL64N32
// ArchPPC represents 32-bit POWERPC syscalls
- ArchPPC ScmpArch = iota
+ ArchPPC
// ArchPPC64 represents 64-bit POWER syscalls (big endian)
- ArchPPC64 ScmpArch = iota
+ ArchPPC64
// ArchPPC64LE represents 64-bit POWER syscalls (little endian)
- ArchPPC64LE ScmpArch = iota
+ ArchPPC64LE
// ArchS390 represents 31-bit System z/390 syscalls
- ArchS390 ScmpArch = iota
+ ArchS390
// ArchS390X represents 64-bit System z/390 syscalls
- ArchS390X ScmpArch = iota
+ ArchS390X
// ArchPARISC represents 32-bit PA-RISC
- ArchPARISC ScmpArch = iota
+ ArchPARISC
// ArchPARISC64 represents 64-bit PA-RISC
- ArchPARISC64 ScmpArch = iota
+ ArchPARISC64
+ // ArchRISCV64 represents RISCV64
+ ArchRISCV64
)
const (
@@ -194,34 +182,36 @@ const (
// ActInvalid is a placeholder to ensure uninitialized ScmpAction
// variables are invalid
ActInvalid ScmpAction = iota
- // ActKill kills the thread that violated the rule. It is the same as ActKillThread.
+ // ActKillThread kills the thread that violated the rule.
// All other threads from the same thread group will continue to execute.
- ActKill ScmpAction = iota
+ ActKillThread
// ActTrap throws SIGSYS
- ActTrap ScmpAction = iota
+ ActTrap
// ActNotify triggers a userspace notification. This action is only usable when
// libseccomp API level 6 or higher is supported.
- ActNotify ScmpAction = iota
+ ActNotify
// ActErrno causes the syscall to return a negative error code. This
// code can be set with the SetReturnCode method
- ActErrno ScmpAction = iota
+ ActErrno
// ActTrace causes the syscall to notify tracing processes with the
// given error code. This code can be set with the SetReturnCode method
- ActTrace ScmpAction = iota
+ ActTrace
// ActAllow permits the syscall to continue execution
- ActAllow ScmpAction = iota
+ ActAllow
// ActLog permits the syscall to continue execution after logging it.
// This action is only usable when libseccomp API level 3 or higher is
// supported.
- ActLog ScmpAction = iota
- // ActKillThread kills the thread that violated the rule. It is the same as ActKill.
- // All other threads from the same thread group will continue to execute.
- ActKillThread ScmpAction = iota
+ ActLog
// ActKillProcess kills the process that violated the rule.
// All threads in the thread group are also terminated.
// This action is only usable when libseccomp API level 3 or higher is
// supported.
- ActKillProcess ScmpAction = iota
+ ActKillProcess
+ // ActKill kills the thread that violated the rule.
+ // All other threads from the same thread group will continue to execute.
+ //
+ // Deprecated: use ActKillThread
+ ActKill = ActKillThread
)
const (
@@ -234,36 +224,35 @@ const (
CompareInvalid ScmpCompareOp = iota
// CompareNotEqual returns true if the argument is not equal to the
// given value
- CompareNotEqual ScmpCompareOp = iota
+ CompareNotEqual
// CompareLess returns true if the argument is less than the given value
- CompareLess ScmpCompareOp = iota
+ CompareLess
// CompareLessOrEqual returns true if the argument is less than or equal
// to the given value
- CompareLessOrEqual ScmpCompareOp = iota
+ CompareLessOrEqual
// CompareEqual returns true if the argument is equal to the given value
- CompareEqual ScmpCompareOp = iota
+ CompareEqual
// CompareGreaterEqual returns true if the argument is greater than or
// equal to the given value
- CompareGreaterEqual ScmpCompareOp = iota
+ CompareGreaterEqual
// CompareGreater returns true if the argument is greater than the given
// value
- CompareGreater ScmpCompareOp = iota
- // CompareMaskedEqual returns true if the argument is equal to the given
- // value, when masked (bitwise &) against the second given value
- CompareMaskedEqual ScmpCompareOp = iota
+ CompareGreater
+ // CompareMaskedEqual returns true if the masked argument value is
+ // equal to the masked datum value. Mask is the first argument, and
+ // datum is the second one.
+ CompareMaskedEqual
)
-var (
- // ErrSyscallDoesNotExist represents an error condition where
- // libseccomp is unable to resolve the syscall
- ErrSyscallDoesNotExist = fmt.Errorf("could not resolve syscall name")
-)
+// ErrSyscallDoesNotExist represents an error condition where
+// libseccomp is unable to resolve the syscall
+var ErrSyscallDoesNotExist = fmt.Errorf("could not resolve syscall name")
const (
// Userspace notification response flags
// NotifRespFlagContinue tells the kernel to continue executing the system
- // call that triggered the notification. Must only be used when the notication
+ // call that triggered the notification. Must only be used when the notification
// response's error is 0.
NotifRespFlagContinue uint32 = 1
)
@@ -314,6 +303,8 @@ func GetArchFromString(arch string) (ScmpArch, error) {
return ArchPARISC, nil
case "parisc64":
return ArchPARISC64, nil
+ case "riscv64":
+ return ArchRISCV64, nil
default:
return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %q", arch)
}
@@ -358,6 +349,8 @@ func (a ScmpArch) String() string {
return "parisc"
case ArchPARISC64:
return "parisc64"
+ case ArchRISCV64:
+ return "riscv64"
case ArchNative:
return "native"
case ArchInvalid:
@@ -394,7 +387,7 @@ func (a ScmpCompareOp) String() string {
// String returns a string representation of a seccomp match action
func (a ScmpAction) String() string {
switch a & 0xFFFF {
- case ActKill, ActKillThread:
+ case ActKillThread:
return "Action: Kill thread"
case ActKillProcess:
return "Action: Kill process"
@@ -556,8 +549,8 @@ func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCo
return condStruct, err
}
- if comparison == CompareInvalid {
- return condStruct, fmt.Errorf("invalid comparison operator")
+ if err := sanitizeCompareOp(comparison); err != nil {
+ return condStruct, err
} else if arg > 5 {
return condStruct, fmt.Errorf("syscalls only have up to 6 arguments (%d given)", arg)
} else if len(values) > 2 {
@@ -874,10 +867,8 @@ func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) {
func (f *ScmpFilter) GetLogBit() (bool, error) {
log, err := f.getFilterAttr(filterAttrLog)
if err != nil {
- // Ignore error, if not supported returns apiLevel == 0
- apiLevel, _ := GetAPI()
- if apiLevel < 3 {
- return false, fmt.Errorf("getting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher")
+ if e := checkAPI("GetLogBit", 3, 2, 4, 0); e != nil {
+ err = e
}
return false, err
@@ -899,9 +890,8 @@ func (f *ScmpFilter) GetLogBit() (bool, error) {
func (f *ScmpFilter) GetSSB() (bool, error) {
ssb, err := f.getFilterAttr(filterAttrSSB)
if err != nil {
- api, apiErr := getAPI()
- if (apiErr != nil && api == 0) || (apiErr == nil && api < 4) {
- return false, fmt.Errorf("getting the SSB flag is only supported in libseccomp 2.5.0 and newer with API level 4 or higher")
+ if e := checkAPI("GetSSB", 4, 2, 5, 0); e != nil {
+ err = e
}
return false, err
@@ -914,6 +904,42 @@ func (f *ScmpFilter) GetSSB() (bool, error) {
return true, nil
}
+// GetOptimize returns the current optimization level of the filter,
+// or an error if an issue was encountered retrieving the value.
+// See SetOptimize for more details.
+func (f *ScmpFilter) GetOptimize() (int, error) {
+ level, err := f.getFilterAttr(filterAttrOptimize)
+ if err != nil {
+ if e := checkAPI("GetOptimize", 4, 2, 5, 0); e != nil {
+ err = e
+ }
+
+ return 0, err
+ }
+
+ return int(level), nil
+}
+
+// GetRawRC returns the current state of RawRC flag, or an error
+// if an issue was encountered retrieving the value.
+// See SetRawRC for more details.
+func (f *ScmpFilter) GetRawRC() (bool, error) {
+ rawrc, err := f.getFilterAttr(filterAttrRawRC)
+ if err != nil {
+ if e := checkAPI("GetRawRC", 4, 2, 5, 0); e != nil {
+ err = e
+ }
+
+ return false, err
+ }
+
+ if rawrc == 0 {
+ return false, nil
+ }
+
+ return true, nil
+}
+
// SetBadArchAction sets the default action taken on a syscall for an
// architecture not in the filter, or an error if an issue was encountered
// setting the value.
@@ -953,10 +979,8 @@ func (f *ScmpFilter) SetLogBit(state bool) error {
err := f.setFilterAttr(filterAttrLog, toSet)
if err != nil {
- // Ignore error, if not supported returns apiLevel == 0
- apiLevel, _ := GetAPI()
- if apiLevel < 3 {
- return fmt.Errorf("setting the log bit is only supported in libseccomp 2.4.0 and newer with API level 3 or higher")
+ if e := checkAPI("SetLogBit", 3, 2, 4, 0); e != nil {
+ err = e
}
}
@@ -976,9 +1000,52 @@ func (f *ScmpFilter) SetSSB(state bool) error {
err := f.setFilterAttr(filterAttrSSB, toSet)
if err != nil {
- api, apiErr := getAPI()
- if (apiErr != nil && api == 0) || (apiErr == nil && api < 4) {
- return fmt.Errorf("setting the SSB flag is only supported in libseccomp 2.5.0 and newer with API level 4 or higher")
+ if e := checkAPI("SetSSB", 4, 2, 5, 0); e != nil {
+ err = e
+ }
+ }
+
+ return err
+}
+
+// SetOptimize sets optimization level of the seccomp filter. By default
+// libseccomp generates a set of sequential "if" statements for each rule in
+// the filter. SetSyscallPriority can be used to prioritize the order for the
+// default cause. The binary tree optimization sorts by syscall numbers and
+// generates consistent O(log n) filter traversal for every rule in the filter.
+// The binary tree may be advantageous for large filters. Note that
+// SetSyscallPriority is ignored when level == 2.
+//
+// The different optimization levels are:
+// 0: Reserved value, not currently used.
+// 1: Rules sorted by priority and complexity (DEFAULT).
+// 2: Binary tree sorted by syscall number.
+func (f *ScmpFilter) SetOptimize(level int) error {
+ cLevel := C.uint32_t(level)
+
+ err := f.setFilterAttr(filterAttrOptimize, cLevel)
+ if err != nil {
+ if e := checkAPI("SetOptimize", 4, 2, 5, 0); e != nil {
+ err = e
+ }
+ }
+
+ return err
+}
+
+// SetRawRC sets whether libseccomp should pass system error codes back to the
+// caller, instead of the default ECANCELED. Defaults to false.
+func (f *ScmpFilter) SetRawRC(state bool) error {
+ var toSet C.uint32_t = 0x0
+
+ if state {
+ toSet = 0x1
+ }
+
+ err := f.setFilterAttr(filterAttrRawRC, toSet)
+ if err != nil {
+ if e := checkAPI("SetRawRC", 4, 2, 5, 0); e != nil {
+ err = e
}
}
@@ -1029,9 +1096,6 @@ func (f *ScmpFilter) AddRuleExact(call ScmpSyscall, action ScmpAction) error {
// AddRuleConditional adds a single rule for a conditional action on a syscall.
// Returns an error if an issue was encountered adding the rule.
// All conditions must match for the rule to match.
-// There is a bug in library versions below v2.2.1 which can, in some cases,
-// cause conditions to be lost when more than one are used. Consequently,
-// AddRuleConditional is disabled on library versions lower than v2.2.1
func (f *ScmpFilter) AddRuleConditional(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error {
return f.addRuleGeneric(call, action, false, conds)
}
@@ -1043,9 +1107,6 @@ func (f *ScmpFilter) AddRuleConditional(call ScmpSyscall, action ScmpAction, con
// The rule will function exactly as described, but it may not function identically
// (or be able to be applied to) all architectures.
// Returns an error if an issue was encountered adding the rule.
-// There is a bug in library versions below v2.2.1 which can, in some cases,
-// cause conditions to be lost when more than one are used. Consequently,
-// AddRuleConditionalExact is disabled on library versions lower than v2.2.1
func (f *ScmpFilter) AddRuleConditionalExact(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error {
return f.addRuleGeneric(call, action, true, conds)
}
diff --git a/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go b/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
index 8dc7b296f..df4dfb7eb 100644
--- a/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
+++ b/vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
@@ -1,11 +1,10 @@
-// +build linux
-
// Internal functions for libseccomp Go bindings
// No exported functions
package seccomp
import (
+ "errors"
"fmt"
"syscall"
)
@@ -27,10 +26,10 @@ import (
#include <stdlib.h>
#include <seccomp.h>
-#if SCMP_VER_MAJOR < 2
-#error Minimum supported version of Libseccomp is v2.2.0
-#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2
-#error Minimum supported version of Libseccomp is v2.2.0
+#if (SCMP_VER_MAJOR < 2) || \
+ (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 3) || \
+ (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 3 && SCMP_VER_MICRO < 1)
+#error This package requires libseccomp >= v2.3.1
#endif
#define ARCH_BAD ~0
@@ -65,6 +64,10 @@ const uint32_t C_ARCH_BAD = ARCH_BAD;
#define SCMP_ARCH_PARISC64 ARCH_BAD
#endif
+#ifndef SCMP_ARCH_RISCV64
+#define SCMP_ARCH_RISCV64 ARCH_BAD
+#endif
+
const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
@@ -84,6 +87,7 @@ const uint32_t C_ARCH_S390 = SCMP_ARCH_S390;
const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
const uint32_t C_ARCH_PARISC = SCMP_ARCH_PARISC;
const uint32_t C_ARCH_PARISC64 = SCMP_ARCH_PARISC64;
+const uint32_t C_ARCH_RISCV64 = SCMP_ARCH_RISCV64;
#ifndef SCMP_ACT_LOG
#define SCMP_ACT_LOG 0x7ffc0000U
@@ -113,20 +117,25 @@ const uint32_t C_ACT_NOTIFY = SCMP_ACT_NOTIFY;
// The libseccomp SCMP_FLTATR_CTL_LOG member of the scmp_filter_attr enum was
// added in v2.4.0
-#if (SCMP_VER_MAJOR < 2) || \
- (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4)
+#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4
#define SCMP_FLTATR_CTL_LOG _SCMP_FLTATR_MIN
#endif
+
+// The following SCMP_FLTATR_* were added in libseccomp v2.5.0.
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5
-#define SCMP_FLTATR_CTL_SSB _SCMP_FLTATR_MIN
+#define SCMP_FLTATR_CTL_SSB _SCMP_FLTATR_MIN
+#define SCMP_FLTATR_CTL_OPTIMIZE _SCMP_FLTATR_MIN
+#define SCMP_FLTATR_API_SYSRAWRC _SCMP_FLTATR_MIN
#endif
-const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
-const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
-const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
-const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
-const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
-const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB;
+const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
+const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
+const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
+const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
+const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
+const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB;
+const uint32_t C_ATTRIBUTE_OPTIMIZE = (uint32_t)SCMP_FLTATR_CTL_OPTIMIZE;
+const uint32_t C_ATTRIBUTE_SYSRAWRC = (uint32_t)SCMP_FLTATR_API_SYSRAWRC;
const int C_CMP_NE = (int)SCMP_CMP_NE;
const int C_CMP_LT = (int)SCMP_CMP_LT;
@@ -173,8 +182,7 @@ unsigned int get_micro_version()
#endif
// The libseccomp API level functions were added in v2.4.0
-#if (SCMP_VER_MAJOR < 2) || \
- (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4)
+#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4
const unsigned int seccomp_api_get(void)
{
// libseccomp-golang requires libseccomp v2.2.0, at a minimum, which
@@ -217,8 +225,7 @@ void add_struct_arg_cmp(
}
// The seccomp notify API functions were added in v2.5.0
-#if (SCMP_VER_MAJOR < 2) || \
- (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5)
+#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5
struct seccomp_data {
int nr;
@@ -270,11 +277,13 @@ type scmpFilterAttr uint32
const (
filterAttrActDefault scmpFilterAttr = iota
- filterAttrActBadArch scmpFilterAttr = iota
- filterAttrNNP scmpFilterAttr = iota
- filterAttrTsync scmpFilterAttr = iota
- filterAttrLog scmpFilterAttr = iota
- filterAttrSSB scmpFilterAttr = iota
+ filterAttrActBadArch
+ filterAttrNNP
+ filterAttrTsync
+ filterAttrLog
+ filterAttrSSB
+ filterAttrOptimize
+ filterAttrRawRC
)
const (
@@ -282,9 +291,9 @@ const (
scmpError C.int = -1
// Comparison boundaries to check for architecture validity
archStart ScmpArch = ArchNative
- archEnd ScmpArch = ArchPARISC64
+ archEnd ScmpArch = ArchRISCV64
// Comparison boundaries to check for action validity
- actionStart ScmpAction = ActKill
+ actionStart ScmpAction = ActKillThread
actionEnd ScmpAction = ActKillProcess
// Comparison boundaries to check for comparison operator validity
compareOpStart ScmpCompareOp = CompareNotEqual
@@ -292,8 +301,9 @@ const (
)
var (
- // Error thrown on bad filter context
- errBadFilter = fmt.Errorf("filter is invalid or uninitialized")
+ // errBadFilter is thrown on bad filter context.
+ errBadFilter = errors.New("filter is invalid or uninitialized")
+ errDefAction = errors.New("requested action matches default action of filter")
// Constants representing library major, minor, and micro versions
verMajor = uint(C.get_major_version())
verMinor = uint(C.get_minor_version())
@@ -302,19 +312,28 @@ var (
// Nonexported functions
-// Check if library version is greater than or equal to the given one
-func checkVersionAbove(major, minor, micro uint) bool {
- return (verMajor > major) ||
+// checkVersion returns an error if the libseccomp version being used
+// is less than the one specified by major, minor, and micro arguments.
+// Argument op is an arbitrary non-empty operation description, which
+// is used as a part of the error message returned.
+//
+// Most users should use checkAPI instead.
+func checkVersion(op string, major, minor, micro uint) error {
+ if (verMajor > major) ||
(verMajor == major && verMinor > minor) ||
- (verMajor == major && verMinor == minor && verMicro >= micro)
+ (verMajor == major && verMinor == minor && verMicro >= micro) {
+ return nil
+ }
+ return &VersionError{
+ op: op,
+ major: major,
+ minor: minor,
+ micro: micro,
+ }
}
-// Ensure that the library is supported, i.e. >= 2.2.0.
func ensureSupportedVersion() error {
- if !checkVersionAbove(2, 2, 0) {
- return VersionError{}
- }
- return nil
+ return checkVersion("seccomp", 2, 3, 1)
}
// Get the API level
@@ -406,8 +425,10 @@ func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact b
switch e := errRc(retCode); e {
case syscall.EFAULT:
return fmt.Errorf("unrecognized syscall %#x", int32(call))
- case syscall.EPERM:
- return fmt.Errorf("requested action matches default action of filter")
+ // libseccomp >= v2.5.0 returns EACCES, older versions return EPERM.
+ // TODO: remove EPERM once libseccomp < v2.5.0 is not supported.
+ case syscall.EPERM, syscall.EACCES:
+ return errDefAction
case syscall.EINVAL:
return fmt.Errorf("two checks on same syscall argument")
default:
@@ -432,14 +453,6 @@ func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact b
return err
}
} else {
- // We don't support conditional filtering in library version v2.1
- if !checkVersionAbove(2, 2, 1) {
- return VersionError{
- message: "conditional filtering is not supported",
- minimum: "2.2.1",
- }
- }
-
argsArr := C.make_arg_cmp_array(C.uint(len(conds)))
if argsArr == nil {
return fmt.Errorf("error allocating memory for conditions")
@@ -536,6 +549,8 @@ func archFromNative(a C.uint32_t) (ScmpArch, error) {
return ArchPARISC, nil
case C.C_ARCH_PARISC64:
return ArchPARISC64, nil
+ case C.C_ARCH_RISCV64:
+ return ArchRISCV64, nil
default:
return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a))
}
@@ -580,6 +595,8 @@ func (a ScmpArch) toNative() C.uint32_t {
return C.C_ARCH_PARISC
case ArchPARISC64:
return C.C_ARCH_PARISC64
+ case ArchRISCV64:
+ return C.C_ARCH_RISCV64
case ArchNative:
return C.C_ARCH_NATIVE
default:
@@ -612,8 +629,6 @@ func (a ScmpCompareOp) toNative() C.int {
func actionFromNative(a C.uint32_t) (ScmpAction, error) {
aTmp := a & 0xFFFF
switch a & 0xFFFF0000 {
- case C.C_ACT_KILL:
- return ActKill, nil
case C.C_ACT_KILL_PROCESS:
return ActKillProcess, nil
case C.C_ACT_KILL_THREAD:
@@ -638,8 +653,6 @@ func actionFromNative(a C.uint32_t) (ScmpAction, error) {
// Only use with sanitized actions, no error handling
func (a ScmpAction) toNative() C.uint32_t {
switch a & 0xFFFF {
- case ActKill:
- return C.C_ACT_KILL
case ActKillProcess:
return C.C_ACT_KILL_PROCESS
case ActKillThread:
@@ -676,15 +689,15 @@ func (a scmpFilterAttr) toNative() uint32 {
return uint32(C.C_ATTRIBUTE_LOG)
case filterAttrSSB:
return uint32(C.C_ATTRIBUTE_SSB)
+ case filterAttrOptimize:
+ return uint32(C.C_ATTRIBUTE_OPTIMIZE)
+ case filterAttrRawRC:
+ return uint32(C.C_ATTRIBUTE_SYSRAWRC)
default:
return 0x0
}
}
-func (a ScmpSyscall) toNative() C.uint32_t {
- return C.uint32_t(a)
-}
-
func syscallFromNative(a C.int) ScmpSyscall {
return ScmpSyscall(a)
}
@@ -724,9 +737,34 @@ func (scmpResp *ScmpNotifResp) toNative(resp *C.struct_seccomp_notif_resp) {
resp.flags = C.__u32(scmpResp.Flags)
}
+// checkAPI checks that both the API level and the seccomp version is equal to
+// or greater than the specified minLevel and major, minor, micro,
+// respectively, and returns an error otherwise. Argument op is an arbitrary
+// non-empty operation description, used as a part of the error message
+// returned.
+func checkAPI(op string, minLevel uint, major, minor, micro uint) error {
+ // Ignore error from getAPI, as it returns level == 0 in case of error.
+ level, _ := getAPI()
+ if level >= minLevel {
+ return checkVersion(op, major, minor, micro)
+ }
+ return &VersionError{
+ op: op,
+ curAPI: level,
+ minAPI: minLevel,
+ major: major,
+ minor: minor,
+ micro: micro,
+ }
+}
+
// Userspace Notification API
// Calls to C.seccomp_notify* hidden from seccomp.go
+func notifSupported() error {
+ return checkAPI("seccomp notification", 6, 2, 5, 0)
+}
+
func (f *ScmpFilter) getNotifFd() (ScmpFd, error) {
f.lock.Lock()
defer f.lock.Unlock()
@@ -734,11 +772,8 @@ func (f *ScmpFilter) getNotifFd() (ScmpFd, error) {
if !f.valid {
return -1, errBadFilter
}
-
- // Ignore error, if not supported returns apiLevel == 0
- apiLevel, _ := GetAPI()
- if apiLevel < 6 {
- return -1, fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel)
+ if err := notifSupported(); err != nil {
+ return -1, err
}
fd := C.seccomp_notify_fd(f.filterCtx)
@@ -750,10 +785,8 @@ func notifReceive(fd ScmpFd) (*ScmpNotifReq, error) {
var req *C.struct_seccomp_notif
var resp *C.struct_seccomp_notif_resp
- // Ignore error, if not supported returns apiLevel == 0
- apiLevel, _ := GetAPI()
- if apiLevel < 6 {
- return nil, fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel)
+ if err := notifSupported(); err != nil {
+ return nil, err
}
// we only use the request here; the response is unused
@@ -789,13 +822,11 @@ func notifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error {
var req *C.struct_seccomp_notif
var resp *C.struct_seccomp_notif_resp
- // Ignore error, if not supported returns apiLevel == 0
- apiLevel, _ := GetAPI()
- if apiLevel < 6 {
- return fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel)
+ if err := notifSupported(); err != nil {
+ return err
}
- // we only use the reponse here; the request is discarded
+ // we only use the response here; the request is discarded
if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 {
return errRc(retCode)
}
@@ -827,10 +858,8 @@ func notifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error {
}
func notifIDValid(fd ScmpFd, id uint64) error {
- // Ignore error, if not supported returns apiLevel == 0
- apiLevel, _ := GetAPI()
- if apiLevel < 6 {
- return fmt.Errorf("seccomp notification requires API level >= 6; current level = %d", apiLevel)
+ if err := notifSupported(); err != nil {
+ return err
}
for {
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
index df22c47fc..da867903e 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
@@ -9,7 +9,7 @@ package assert
import "reflect"
-// Wrapper around reflect.Value.CanConvert, for compatability
+// Wrapper around reflect.Value.CanConvert, for compatibility
// reasons.
func canConvert(value reflect.Value, to reflect.Type) bool {
return value.CanConvert(to)
diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go
index df36e3a30..0173b6982 100644
--- a/vendor/gopkg.in/yaml.v3/decode.go
+++ b/vendor/gopkg.in/yaml.v3/decode.go
@@ -100,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t {
if p.event.typ != yaml_NO_EVENT {
return p.event.typ
}
- if !yaml_parser_parse(&p.parser, &p.event) {
+ // It's curious choice from the underlying API to generally return a
+ // positive result on success, but on this case return true in an error
+ // scenario. This was the source of bugs in the past (issue #666).
+ if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
p.fail()
}
return p.event.typ
@@ -320,6 +323,8 @@ type decoder struct {
decodeCount int
aliasCount int
aliasDepth int
+
+ mergedFields map[interface{}]bool
}
var (
@@ -808,6 +813,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
}
+ mergedFields := d.mergedFields
+ d.mergedFields = nil
+
+ var mergeNode *Node
+
mapIsNew := false
if out.IsNil() {
out.Set(reflect.MakeMap(outt))
@@ -815,11 +825,18 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
for i := 0; i < l; i += 2 {
if isMerge(n.Content[i]) {
- d.merge(n.Content[i+1], out)
+ mergeNode = n.Content[i+1]
continue
}
k := reflect.New(kt).Elem()
if d.unmarshal(n.Content[i], k) {
+ if mergedFields != nil {
+ ki := k.Interface()
+ if mergedFields[ki] {
+ continue
+ }
+ mergedFields[ki] = true
+ }
kkind := k.Kind()
if kkind == reflect.Interface {
kkind = k.Elem().Kind()
@@ -833,6 +850,12 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
}
}
+
+ d.mergedFields = mergedFields
+ if mergeNode != nil {
+ d.merge(n, mergeNode, out)
+ }
+
d.stringMapType = stringMapType
d.generalMapType = generalMapType
return true
@@ -844,7 +867,8 @@ func isStringMap(n *Node) bool {
}
l := len(n.Content)
for i := 0; i < l; i += 2 {
- if n.Content[i].ShortTag() != strTag {
+ shortTag := n.Content[i].ShortTag()
+ if shortTag != strTag && shortTag != mergeTag {
return false
}
}
@@ -861,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
var elemType reflect.Type
if sinfo.InlineMap != -1 {
inlineMap = out.Field(sinfo.InlineMap)
- inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
elemType = inlineMap.Type().Elem()
}
@@ -870,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.prepare(n, field)
}
+ mergedFields := d.mergedFields
+ d.mergedFields = nil
+ var mergeNode *Node
var doneFields []bool
if d.uniqueKeys {
doneFields = make([]bool, len(sinfo.FieldsList))
@@ -879,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
for i := 0; i < l; i += 2 {
ni := n.Content[i]
if isMerge(ni) {
- d.merge(n.Content[i+1], out)
+ mergeNode = n.Content[i+1]
continue
}
if !d.unmarshal(ni, name) {
continue
}
- if info, ok := sinfo.FieldsMap[name.String()]; ok {
+ sname := name.String()
+ if mergedFields != nil {
+ if mergedFields[sname] {
+ continue
+ }
+ mergedFields[sname] = true
+ }
+ if info, ok := sinfo.FieldsMap[sname]; ok {
if d.uniqueKeys {
if doneFields[info.Id] {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
@@ -911,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
}
}
+
+ d.mergedFields = mergedFields
+ if mergeNode != nil {
+ d.merge(n, mergeNode, out)
+ }
return true
}
@@ -918,19 +956,29 @@ func failWantMap() {
failf("map merge requires map or sequence of maps as the value")
}
-func (d *decoder) merge(n *Node, out reflect.Value) {
- switch n.Kind {
+func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
+ mergedFields := d.mergedFields
+ if mergedFields == nil {
+ d.mergedFields = make(map[interface{}]bool)
+ for i := 0; i < len(parent.Content); i += 2 {
+ k := reflect.New(ifaceType).Elem()
+ if d.unmarshal(parent.Content[i], k) {
+ d.mergedFields[k.Interface()] = true
+ }
+ }
+ }
+
+ switch merge.Kind {
case MappingNode:
- d.unmarshal(n, out)
+ d.unmarshal(merge, out)
case AliasNode:
- if n.Alias != nil && n.Alias.Kind != MappingNode {
+ if merge.Alias != nil && merge.Alias.Kind != MappingNode {
failWantMap()
}
- d.unmarshal(n, out)
+ d.unmarshal(merge, out)
case SequenceNode:
- // Step backwards as earlier nodes take precedence.
- for i := len(n.Content) - 1; i >= 0; i-- {
- ni := n.Content[i]
+ for i := 0; i < len(merge.Content); i++ {
+ ni := merge.Content[i]
if ni.Kind == AliasNode {
if ni.Alias != nil && ni.Alias.Kind != MappingNode {
failWantMap()
@@ -943,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) {
default:
failWantMap()
}
+
+ d.mergedFields = mergedFields
}
func isMerge(n *Node) bool {
diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go
index ac66fccc0..268558a0d 100644
--- a/vendor/gopkg.in/yaml.v3/parserc.go
+++ b/vendor/gopkg.in/yaml.v3/parserc.go
@@ -687,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i
func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
+ if token == nil {
+ return false
+ }
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
@@ -786,7 +789,7 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
}
token := peek_token(parser)
- if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
+ if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
return
}
@@ -813,6 +816,9 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
+ if token == nil {
+ return false
+ }
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
@@ -922,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev
func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
+ if token == nil {
+ return false
+ }
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index e28d91bde..de76aad91 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -72,7 +72,7 @@ github.com/containerd/containerd/sys
# github.com/containerd/stargz-snapshotter/estargz v0.11.4
github.com/containerd/stargz-snapshotter/estargz
github.com/containerd/stargz-snapshotter/estargz/errorutil
-# github.com/containernetworking/cni v1.1.0
+# github.com/containernetworking/cni v1.1.1
## explicit
github.com/containernetworking/cni/libcni
github.com/containernetworking/cni/pkg/invoke
@@ -109,7 +109,7 @@ github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util
github.com/containers/buildah/util
-# github.com/containers/common v0.48.1-0.20220523155016-2fd37da97824
+# github.com/containers/common v0.48.1-0.20220528105338-54c8092c69a1
## explicit
github.com/containers/common/libimage
github.com/containers/common/libimage/define
@@ -119,6 +119,7 @@ github.com/containers/common/libnetwork/etchosts
github.com/containers/common/libnetwork/internal/util
github.com/containers/common/libnetwork/netavark
github.com/containers/common/libnetwork/network
+github.com/containers/common/libnetwork/resolvconf
github.com/containers/common/libnetwork/types
github.com/containers/common/libnetwork/util
github.com/containers/common/pkg/apparmor
@@ -329,7 +330,7 @@ github.com/docker/distribution/registry/client/auth/challenge
github.com/docker/distribution/registry/client/transport
github.com/docker/distribution/registry/storage/cache
github.com/docker/distribution/registry/storage/cache/memory
-# github.com/docker/docker v20.10.16+incompatible
+# github.com/docker/docker v20.10.17+incompatible
## explicit
github.com/docker/docker/api
github.com/docker/docker/api/types
@@ -554,7 +555,7 @@ github.com/opencontainers/go-digest
## explicit
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
-# github.com/opencontainers/runc v1.1.2
+# github.com/opencontainers/runc v1.1.3
## explicit
github.com/opencontainers/runc/libcontainer/apparmor
github.com/opencontainers/runc/libcontainer/cgroups
@@ -627,7 +628,7 @@ github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy
github.com/rootless-containers/rootlesskit/pkg/port/portutil
-# github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921
+# github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646
github.com/seccomp/libseccomp-golang
# github.com/sirupsen/logrus v1.8.1
## explicit
@@ -641,7 +642,7 @@ github.com/spf13/cobra
github.com/spf13/pflag
# github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980
github.com/stefanberger/go-pkcs11uri
-# github.com/stretchr/testify v1.7.1
+# github.com/stretchr/testify v1.7.2
## explicit
github.com/stretchr/testify/assert
github.com/stretchr/testify/require
@@ -864,7 +865,7 @@ gopkg.in/tomb.v1
# gopkg.in/yaml.v2 v2.4.0
## explicit
gopkg.in/yaml.v2
-# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+# gopkg.in/yaml.v3 v3.0.1
gopkg.in/yaml.v3
# sigs.k8s.io/yaml v1.3.0
sigs.k8s.io/yaml