summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml147
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md6
-rw-r--r--README.md12
-rw-r--r--cmd/podman/common/completion.go62
-rw-r--r--cmd/podman/common/create_opts.go477
-rw-r--r--cmd/podman/system/reset.go14
-rw-r--r--contrib/cirrus/CIModes.md129
-rw-r--r--contrib/podmanimage/README.md10
-rw-r--r--contrib/podmanimage/stable/Containerfile3
-rw-r--r--contrib/podmanimage/stable/storage.conf6
-rw-r--r--contrib/podmanimage/testing/Containerfile3
-rw-r--r--contrib/podmanimage/upstream/Containerfile3
-rw-r--r--docs/source/markdown/podman-build.1.md2
-rw-r--r--docs/source/markdown/podman-create.1.md4
-rw-r--r--docs/source/markdown/podman-play-kube.1.md4
-rw-r--r--docs/source/markdown/podman-pod-create.1.md4
-rw-r--r--docs/source/markdown/podman-run.1.md4
-rw-r--r--docs/tutorials/basic_networking.md16
-rw-r--r--go.mod9
-rw-r--r--go.sum16
-rw-r--r--libpod/container_config.go3
-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/networking_linux.go30
-rw-r--r--libpod/oci_conmon_linux.go4
-rw-r--r--libpod/options.go29
-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.go21
-rw-r--r--pkg/resolvconf/dns/resolvconf.go28
-rw-r--r--pkg/specgen/generate/config_linux.go139
-rw-r--r--pkg/specgen/generate/container_create.go14
-rw-r--r--pkg/specgen/generate/oci.go10
-rw-r--r--pkg/specgen/volumes.go14
-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-apiv282
-rwxr-xr-xtest/buildah-bud/apply-podman-deltas13
-rw-r--r--test/e2e/build_test.go2
-rw-r--r--test/e2e/logs_test.go21
-rw-r--r--test/e2e/network_connect_disconnect_test.go9
-rw-r--r--test/e2e/play_kube_test.go8
-rw-r--r--test/e2e/pod_create_test.go22
-rw-r--r--test/e2e/run_privileged_test.go24
-rw-r--r--test/e2e/run_volume_test.go45
-rw-r--r--test/system/170-run-userns.bats35
-rw-r--r--test/system/500-networking.bats4
-rw-r--r--test/system/520-checkpoint.bats30
-rw-r--r--test/system/600-completion.bats18
-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/modules.txt12
82 files changed, 1773 insertions, 1596 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/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 5eef5f982..07dcc4e6a 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -284,7 +284,16 @@ func getNetworks(cmd *cobra.Command, toComplete string, cType completeType) ([]s
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
-func getPathCompletion(root string, toComplete string) []string {
+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 = "/"
}
@@ -292,41 +301,61 @@ func getPathCompletion(root string, toComplete string) []string {
userpath, err := securejoin.SecureJoin(root, toComplete)
if err != nil {
cobra.CompErrorln(err.Error())
- return nil
+ return nil, cobra.ShellCompDirectiveDefault
}
var base string
f, err := os.Open(userpath)
- if err != nil {
+ // 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
+ return nil, cobra.ShellCompDirectiveDefault
}
}
- stat, err := f.Stat()
- if err != nil {
- cobra.CompErrorln(err.Error())
- return nil
- }
- if !stat.IsDir() {
+
+ if fdIsNotDir(f) {
// nothing to complete since it is no dir
- return nil
+ return nil, cobra.ShellCompDirectiveDefault
}
+
entries, err := f.ReadDir(-1)
if err != nil {
cobra.CompErrorln(err.Error())
- return nil
+ 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) {
- completions = append(completions, simplePathJoinUnix(toComplete, e.Name()))
+ 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++
}
}
- return completions
+ 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.
@@ -605,7 +634,7 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string)
// 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), cobra.ShellCompDirectiveDefault | cobra.ShellCompDirectiveNoSpace
+ return getPathCompletion(resp[0].Path, toComplete)
}
// AutocompleteRegistries - Autocomplete registries.
@@ -676,7 +705,8 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
if len(resp) != 1 {
return nil, cobra.ShellCompDirectiveDefault
}
- return prefixSlice(toComplete[:i+1], getPathCompletion(resp[0].Path, toComplete[i+1:])), cobra.ShellCompDirectiveDefault | cobra.ShellCompDirectiveNoSpace
+ 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)
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/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/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/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
index 40a2cb5f3..9121c5cde 100644
--- a/contrib/podmanimage/stable/Containerfile
+++ b/contrib/podmanimage/stable/Containerfile
@@ -23,7 +23,6 @@ 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/storage.conf /etc/containers/storage.conf
ADD $_REPO_URL/containers.conf /etc/containers/containers.conf
ADD $_REPO_URL/podman-containers.conf /home/podman/.config/containers/containers.conf
@@ -33,7 +32,7 @@ RUN mkdir -p /home/podman/.local/share/containers && \
# 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 -i -e 's|^#mount_program|mount_program|g' \
+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 \
diff --git a/contrib/podmanimage/stable/storage.conf b/contrib/podmanimage/stable/storage.conf
deleted file mode 100644
index bc8d8c111..000000000
--- a/contrib/podmanimage/stable/storage.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-[storage.options]
-additionalimagestores = ["/var/lib/shared"]
-
-[storage.options.overlay]
-mountopt = "nodev,fsync=0"
-mount_program = "/usr/bin/fuse-overlayfs"
diff --git a/contrib/podmanimage/testing/Containerfile b/contrib/podmanimage/testing/Containerfile
index 5fa794baf..16314a633 100644
--- a/contrib/podmanimage/testing/Containerfile
+++ b/contrib/podmanimage/testing/Containerfile
@@ -23,7 +23,6 @@ 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/storage.conf /etc/containers/storage.conf
ADD $_REPO_URL/containers.conf /etc/containers/containers.conf
ADD $_REPO_URL/podman-containers.conf /home/podman/.config/containers/containers.conf
@@ -32,7 +31,7 @@ RUN mkdir -p /home/podman/.local/share/containers && \
# 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 -i -e 's|^#mount_program|mount_program|g' \
+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 \
diff --git a/contrib/podmanimage/upstream/Containerfile b/contrib/podmanimage/upstream/Containerfile
index b338a33ae..c3a07a8d6 100644
--- a/contrib/podmanimage/upstream/Containerfile
+++ b/contrib/podmanimage/upstream/Containerfile
@@ -29,7 +29,6 @@ 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/storage.conf /etc/containers/storage.conf
ADD $_REPO_URL/containers.conf /etc/containers/containers.conf
ADD $_REPO_URL/podman-containers.conf /home/podman/.config/containers/containers.conf
@@ -39,7 +38,7 @@ RUN mkdir -p /home/podman/.local/share/containers && \
# 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 -i -e 's|^#mount_program|mount_program|g' \
+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 \
diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md
index a59dcea89..4d6a74a1f 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://)
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 913183869..d5e96168d 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -1261,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-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 1a98528bb..d5b8232cf 100644
--- a/docs/source/markdown/podman-pod-create.1.md
+++ b/docs/source/markdown/podman-pod-create.1.md
@@ -360,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 b9d87b5bd..6acbec7d5 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -1329,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/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 fc0bbcc73..0d223aeca 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
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
@@ -72,5 +72,4 @@ require (
google.golang.org/protobuf v1.28.0
gopkg.in/inf.v0 v0.9.1
gopkg.in/yaml.v2 v2.4.0
- gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index aa2e07376..6a10a4c7b 100644
--- a/go.sum
+++ b/go.sum
@@ -339,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=
@@ -429,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=
@@ -1053,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=
@@ -1186,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=
@@ -1262,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=
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 30b84adcf..6558f3c89 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -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/networking_linux.go b/libpod/networking_linux.go
index 37fa9b5f5..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)
@@ -1089,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_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/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/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 daa6f0cbf..03e7ffb5d 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -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())
}
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/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/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/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/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..6151b7672 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,22 +430,33 @@ 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=
+ if [[ "$auth" = "htpasswd" ]]; then
+ REGISTRY_USERNAME=u$(random_string 7)
+ REGISTRY_PASSWORD=p$(random_string 7)
+
+ htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \
+ > $AUTHDIR/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=$auth" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \
@@ -462,13 +470,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..0b766dcc8 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"))
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 0d24a7e17..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"
@@ -370,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 019bb4617..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,7 @@ 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"})
@@ -211,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"
@@ -240,7 +239,7 @@ 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"})
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/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/system/170-run-userns.bats b/test/system/170-run-userns.bats
index 46cb37b9d..84788a7f4 100644
--- a/test/system/170-run-userns.bats
+++ b/test/system/170-run-userns.bats
@@ -111,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 2de9b1ae1..cb4a2c5f8 100644
--- a/test/system/600-completion.bats
+++ b/test/system/600-completion.bats
@@ -341,7 +341,9 @@ function _check_no_suggestions() {
skip_if_remote "mounting via remote does not work"
for cmd in create run; do
run_completion $cmd $IMAGE ""
- assert "$output" =~ ".*^/etc\$.*^/home\$.*^/root\$.*" "root directories suggested (cmd: podman $cmd)"
+ 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"
@@ -354,23 +356,31 @@ function _check_no_suggestions() {
# 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\$.*^../../home\$.*" "relative root directories suggested (cmd: podman $cmd ../../)"
+ 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 touch /tmp/$random_file
+ 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"
+ 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/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/modules.txt b/vendor/modules.txt
index e5de2d8d4..de76aad91 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -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
@@ -865,7 +866,6 @@ gopkg.in/tomb.v1
## explicit
gopkg.in/yaml.v2
# gopkg.in/yaml.v3 v3.0.1
-## explicit
gopkg.in/yaml.v3
# sigs.k8s.io/yaml v1.3.0
sigs.k8s.io/yaml