summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml49
-rw-r--r--README.md2
-rw-r--r--contrib/cirrus/lib.sh11
-rwxr-xr-xcontrib/cirrus/setup_environment.sh7
-rw-r--r--docs/source/markdown/podman-mount.1.md6
-rw-r--r--docs/source/markdown/podman-system-service.1.md4
-rw-r--r--docs/source/markdown/podman-unmount.1.md4
-rw-r--r--go.mod4
-rw-r--r--go.sum12
-rwxr-xr-xhack/btrfs_installed_tag.sh2
-rwxr-xr-xhack/btrfs_tag.sh2
-rwxr-xr-xhack/libdm_tag.sh2
-rwxr-xr-xhack/systemd_tag.sh2
-rw-r--r--libpod/boltdb_state.go468
-rw-r--r--libpod/boltdb_state_internal.go220
-rw-r--r--libpod/container_config.go9
-rw-r--r--libpod/container_validate.go11
-rw-r--r--libpod/define/errors.go10
-rw-r--r--libpod/filters/pods.go7
-rw-r--r--libpod/in_memory_state.go393
-rw-r--r--libpod/oci_conmon_exec_linux.go5
-rw-r--r--libpod/oci_conmon_linux.go17
-rw-r--r--libpod/options.go14
-rw-r--r--libpod/runtime_ctr.go50
-rw-r--r--libpod/runtime_volume_linux.go2
-rw-r--r--libpod/state.go15
-rw-r--r--libpod/state_test.go244
-rw-r--r--nix/nixpkgs.json6
-rw-r--r--pkg/domain/infra/abi/containers.go73
-rw-r--r--test/e2e/pod_infra_container_test.go6
-rw-r--r--test/e2e/pod_ps_test.go22
-rw-r--r--test/system/060-mount.bats31
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/pkg/homedir/homedir_linux.go96
-rw-r--r--vendor/github.com/containers/storage/pkg/homedir/homedir_others.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go100
-rw-r--r--vendor/github.com/containers/storage/userns.go125
-rw-r--r--vendor/github.com/containers/storage/utils.go6
-rw-r--r--vendor/modules.txt4
39 files changed, 1761 insertions, 284 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index b75e99184..1a109f5ba 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -21,13 +21,13 @@ env:
####
#### Cache-image names to test with (double-quotes around names are critical)
####
- FEDORA_NAME: "fedora-32"
- PRIOR_FEDORA_NAME: "fedora-31"
+ FEDORA_NAME: "fedora-33"
+ PRIOR_FEDORA_NAME: "fedora-32"
UBUNTU_NAME: "ubuntu-20"
PRIOR_UBUNTU_NAME: "ubuntu-19"
# Google-cloud VM Images
- IMAGE_SUFFIX: "c4948709391728640"
+ IMAGE_SUFFIX: "c6323493627232256"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}"
@@ -74,12 +74,8 @@ ext_svc_check_task:
env:
TEST_FLAVOR: ext_svc
CTR_FQIN: ${FEDORA_CONTAINER_FQIN}
- setup_script: &setup
- - 'cd $GOSRC/$SCRIPT_BASE || exit 1'
- - './setup_environment.sh'
- main_script: &main
- - 'cd $GOSRC/$SCRIPT_BASE || exit 1'
- - './runner.sh'
+ setup_script: &setup '$GOSRC/$SCRIPT_BASE/setup_environment.sh'
+ main_script: &main '$GOSRC/$SCRIPT_BASE/runner.sh'
# Execute some quick checks to confirm this YAML file and all
@@ -189,17 +185,13 @@ build_task:
clone_script: &noop mkdir -p $CIRRUS_WORKING_DIR
setup_script: *setup
main_script: *main
- always: &artifacts
+ always: &binary_artifacts
gosrc_artifacts:
path: ./* # Grab everything in top-level $GOSRC
type: application/octet-stream
binary_artifacts:
path: ./bin/*
type: application/octet-stream
- # Required for `contrib/cirrus/logformatter` to work properly
- html_artifacts:
- path: ./*.html
- type: text/html
# Confirm the result of building on at least one platform appears sane.
@@ -228,7 +220,6 @@ validate_task:
clone_script: *noop
setup_script: *setup
main_script: *main
- always: *artifacts
# Exercise the "libpod" API with a small set of common
@@ -248,7 +239,6 @@ bindings_task:
clone_script: *noop # Comes from cache
setup_script: *setup
main_script: *main
- always: *artifacts
# Build the "libpod" API documentation `swagger.yaml` for eventual
@@ -267,7 +257,7 @@ swagger_task:
clone_script: *full_clone # build-cache not available to container tasks
setup_script: *setup
main_script: *main
- always: *artifacts
+ always: *binary_artifacts
endpoint_task:
@@ -285,7 +275,6 @@ endpoint_task:
clone_script: *full_clone # build-cache not available to container tasks
setup_script: *setup
main_script: *main
- always: *artifacts
# Check that all included go modules from other sources match
@@ -304,7 +293,6 @@ vendor_task:
clone_script: *full_clone # build-cache not available to container tasks
setup_script: *setup
main_script: *main
- always: *artifacts
# There are several other important variations of podman which
@@ -335,7 +323,8 @@ alt_build_task:
ALT_NAME: 'Build varlink-binaries'
setup_script: *setup
main_script: *main
- always: *artifacts
+ always: *binary_artifacts
+
# Confirm building a statically-linked binary is successful
static_alt_build_task:
@@ -346,7 +335,7 @@ static_alt_build_task:
- build
# Community-maintained task, may fail on occasion. If so, uncomment
# the next line and file an issue with details about the failure.
- # allow_failures: $CI == $CI
+ allow_failures: $CI == $CI
gce_instance: *bigvm
env:
<<: *stdenvars
@@ -364,7 +353,7 @@ static_alt_build_task:
fingerprint_script: cat nix/*
setup_script: *setup
main_script: *main
- always: *artifacts
+ always: *binary_artifacts
# Confirm building the remote client, natively on a Mac OS-X VM.
@@ -385,7 +374,7 @@ osx_alt_build_task:
- brew install go-md2man
- make podman-remote-darwin
- make install-podman-remote-darwin-docs
- always: *artifacts
+ always: *binary_artifacts
# This task is a stub: In the future it will be used to verify
@@ -405,7 +394,6 @@ docker-py_test_task:
clone_script: *noop # Comes from cache
setup_script: *setup
main_script: *main
- always: *artifacts
# Does exactly what it says, execute the podman unit-tests on all primary
@@ -424,7 +412,6 @@ unit_test_task:
gopath_cache: *ro_gopath_cache
setup_script: *setup
main_script: *main
- always: *artifacts
apiv2_test_task:
@@ -441,7 +428,10 @@ apiv2_test_task:
setup_script: *setup
main_script: *main
always: &logs_artifacts
- <<: *artifacts
+ # Required for `contrib/cirrus/logformatter` to work properly
+ html_artifacts:
+ path: ./*.html
+ type: text/html
package_versions_script: '$SCRIPT_BASE/logcollector.sh packages'
ginkgo_node_logs_script: '$SCRIPT_BASE/logcollector.sh ginkgo'
df_script: '$SCRIPT_BASE/logcollector.sh df'
@@ -515,6 +505,7 @@ container_integration_test_task:
main_script: *main
always: *logs_artifacts
+
# Execute most integration tests as a regular (non-root) user.
rootless_integration_test_task:
name: *std_name_fmt
@@ -584,6 +575,7 @@ rootless_system_test_task:
main_script: *main
always: *logs_artifacts
+
# This task is critical. It updates the "last-used by" timestamp stored
# in metadata for all VM images. This mechanism functions in tandem with
# an out-of-band pruning operation to remove disused VM images.
@@ -665,7 +657,8 @@ release_task:
clone_script: *noop # Comes from cache
setup_script: *setup
main_script: *main
- always: *artifacts
+ always: *binary_artifacts
+
# When preparing to release a new version, this task may be manually
# activated at the PR stage to verify the code is in a proper state.
@@ -686,4 +679,4 @@ release_test_task:
clone_script: *noop # Comes from cache
setup_script: *setup
main_script: *main
- always: *artifacts
+ always: *binary_artifacts
diff --git a/README.md b/README.md
index 18da18465..139af6983 100644
--- a/README.md
+++ b/README.md
@@ -136,7 +136,7 @@ Release notes for recent Podman versions.
**[Contributing](CONTRIBUTING.md)**
Information about contributing to this project.
-[spec-hooks]: https://github.com/opencontainers/runtime-spec/blob/v2.0.1/config.md#posix-platform-hooks
+[spec-hooks]: https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md#posix-platform-hooks
## Buildah and Podman relationship
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 050fb16f3..04e8a3c1c 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -10,6 +10,9 @@ set -a
# handling of the (otherwise) default shell setup is non-uniform. Rather
# than attempt to workaround differences, simply force-load/set required
# items every time this library is utilized.
+_waserrexit=0
+if [[ "$SHELLOPTS" =~ errexit ]]; then _waserrexit=1; fi
+set +e # Assumed in F33 for setting global vars
source /etc/profile
source /etc/environment
if [[ -r "/etc/ci_environment" ]]; then source /etc/ci_environment; fi
@@ -18,6 +21,7 @@ HOME="$(getent passwd $USER | cut -d : -f 6)"
# Some platforms set and make this read-only
[[ -n "$UID" ]] || \
UID=$(getent passwd $USER | cut -d : -f 3)
+if ((_waserrexit)); then set -e; fi
# During VM Image build, the 'containers/automation' installation
# was performed. The final step of installation sets the library
@@ -25,11 +29,8 @@ HOME="$(getent passwd $USER | cut -d : -f 6)"
# default shell profile depending on distribution.
# shellcheck disable=SC2154
if [[ -n "$AUTOMATION_LIB_PATH" ]]; then
- for libname in defaults anchors console_output utils; do
- # There's no way shellcheck can process this location
- # shellcheck disable=SC1090
- source $AUTOMATION_LIB_PATH/${libname}.sh
- done
+ # shellcheck source=/usr/share/automation/lib/common_lib.sh
+ source $AUTOMATION_LIB_PATH/common_lib.sh
else
(
echo "WARNING: It does not appear that containers/automation was installed."
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 8ccbd95d9..da175cc05 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -99,11 +99,12 @@ fi
case "$OS_RELEASE_ID" in
ubuntu*) ;;
fedora*)
- if ((CONTAINER==0)); then # Not yet running inside a container
+ if ((CONTAINER==0)); then
msg "Configuring / Expanding host storage."
# VM is setup to allow flexibility in testing alternate storage.
# For general use, simply make use of all available space.
- ooe.sh bash "$SCRIPT_BASE/add_second_partition.sh"
+ bash "$SCRIPT_BASE/add_second_partition.sh"
+ $SCRIPT_BASE/logcollector.sh df
# All SELinux distros need this for systemd-in-a-container
msg "Enabling container_manage_cgroup"
@@ -215,4 +216,4 @@ echo -e "\n# End of global variable definitions" \
>> /etc/ci_environment
msg "Global CI Environment vars.:"
-cat /etc/ci_environment | sort | indent
+grep -Ev '^#' /etc/ci_environment | sort | indent
diff --git a/docs/source/markdown/podman-mount.1.md b/docs/source/markdown/podman-mount.1.md
index 33c5aece8..a6ed3f10d 100644
--- a/docs/source/markdown/podman-mount.1.md
+++ b/docs/source/markdown/podman-mount.1.md
@@ -13,7 +13,9 @@ Mounts the specified containers' root file system in a location which can be
accessed from the host, and returns its location.
If you execute the command without any arguments, Podman will list all of the
-currently mounted containers.
+currently mounted containers, including external containers. External containers are
+containers in container/storage by tools other then Podman. For example Buildah and
+CRI-O.
Rootless mode only supports mounting VFS driver, unless you enter the user namespace
via the `podman unshare` command. All other storage drivers will fail to mount.
@@ -26,7 +28,7 @@ returned.
**--all**, **-a**
-Mount all containers.
+Mount all podman containers. (External containers will not be mounted)
**--format**=*format*
diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md
index 7d18a6832..580630cdc 100644
--- a/docs/source/markdown/podman-system-service.1.md
+++ b/docs/source/markdown/podman-system-service.1.md
@@ -21,8 +21,8 @@ Both APIs are versioned, but the server will not reject requests with an unsuppo
**--time**, **-t**
-The time until the session expires in _milliseconds_. The default is 1
-second. A value of `0` means no timeout and the session will not expire.
+The time until the session expires in _seconds_. The default is 5
+seconds. A value of `0` means no timeout and the session will not expire.
**--help**, **-h**
diff --git a/docs/source/markdown/podman-unmount.1.md b/docs/source/markdown/podman-unmount.1.md
index 47c55cc0b..08d1286ab 100644
--- a/docs/source/markdown/podman-unmount.1.md
+++ b/docs/source/markdown/podman-unmount.1.md
@@ -22,6 +22,10 @@ container's root filesystem is physically unmounted only when the mount
counter reaches zero indicating no other processes are using the mount.
An unmount can be forced with the --force flag.
+Note: Podman can be used to unmount Podman containers as well as external containers.
+External containers are containers created in container/storage by other tools like
+Buildah and CRI-O.
+
## OPTIONS
**--all**, **-a**
diff --git a/go.mod b/go.mod
index bd9effa19..06ac75047 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.7.0
github.com/containers/psgo v1.5.1
- github.com/containers/storage v1.23.8
+ github.com/containers/storage v1.23.9
github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.0
github.com/cyphar/filepath-securejoin v0.2.2
@@ -48,7 +48,7 @@ require (
github.com/opentracing/opentracing-go v1.2.0
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
- github.com/rootless-containers/rootlesskit v0.10.1
+ github.com/rootless-containers/rootlesskit v0.11.0
github.com/sirupsen/logrus v1.7.0
github.com/spf13/cobra v1.1.1
github.com/spf13/pflag v1.0.5
diff --git a/go.sum b/go.sum
index ad40d8f83..842473111 100644
--- a/go.sum
+++ b/go.sum
@@ -101,8 +101,8 @@ github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzP
github.com/containers/storage v1.23.6/go.mod h1:haFs0HRowKwyzvWEx9EgI3WsL8XCSnBDb5f8P5CAxJY=
github.com/containers/storage v1.23.7 h1:43ImvG/npvQSZXRjaudVvKISIuZSfI6qvtSNQQSGO/A=
github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI=
-github.com/containers/storage v1.23.8 h1:Z3KKE9BkbW6CGOjIeTtvX+Dl9pFX8QgvSD2j/tS+r5E=
-github.com/containers/storage v1.23.8/go.mod h1:3b2ktpB6pw53SEeIoFfO0sQfP9+IoJJKPq5iJk74gxE=
+github.com/containers/storage v1.23.9 h1:qbgnTp76pLSyW3vYwY5GH4vk5cHYVXFJ+CsUEBp9TMw=
+github.com/containers/storage v1.23.9/go.mod h1:3b2ktpB6pw53SEeIoFfO0sQfP9+IoJJKPq5iJk74gxE=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
@@ -347,7 +347,6 @@ github.com/moby/sys/mount v0.1.1 h1:mdhBytJ1SMmMat0gtzWWjFX/87K5j6E/7Q5z7rR0cZY=
github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
github.com/moby/sys/mountinfo v0.1.0/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
-github.com/moby/sys/mountinfo v0.2.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.3.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.4.0 h1:1KInV3Huv18akCu58V7lzNlt+jFmqlu1EaErnEHE/VM=
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
@@ -460,8 +459,8 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rootless-containers/rootlesskit v0.10.1 h1:WkkDeXAFR+meR9k+h5gPhnrDia4U781QqdGvV5BZ0E4=
-github.com/rootless-containers/rootlesskit v0.10.1/go.mod h1:m3LmCklz+LfrwgABaRYi/Yjym/DAG0z/Wc6Oa05WlVM=
+github.com/rootless-containers/rootlesskit v0.11.0 h1:Yn51y7RU6vE3oKrMv54qBCWDM3K6c5cmEtqc9j332D4=
+github.com/rootless-containers/rootlesskit v0.11.0/go.mod h1:pCUqFJBGOIonbjQBaxSVnk3w3KnK2drqjllgpgvNnO8=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U=
@@ -522,7 +521,7 @@ github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
+github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b h1:hdDRrn9OP/roL8a/e/5Zu85ldrcdndu9IeBj2OEvQm0=
github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b/go.mod h1:YHaw8N660ESgMgLOZfLQqT1htFItynAUxMesFBho52s=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
@@ -768,6 +767,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
diff --git a/hack/btrfs_installed_tag.sh b/hack/btrfs_installed_tag.sh
index c4d99f377..f2f2b33c8 100755
--- a/hack/btrfs_installed_tag.sh
+++ b/hack/btrfs_installed_tag.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-cc -E - > /dev/null 2> /dev/null << EOF
+${CPP:-${CC:-cc} -E} ${CPPFLAGS} - > /dev/null 2> /dev/null << EOF
#include <btrfs/ioctl.h>
EOF
if test $? -ne 0 ; then
diff --git a/hack/btrfs_tag.sh b/hack/btrfs_tag.sh
index 59cb969ad..ea753d4d0 100755
--- a/hack/btrfs_tag.sh
+++ b/hack/btrfs_tag.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-cc -E - > /dev/null 2> /dev/null << EOF
+${CPP:-${CC:-cc} -E} ${CPPFLAGS} - > /dev/null 2> /dev/null << EOF
#include <btrfs/version.h>
EOF
if test $? -ne 0 ; then
diff --git a/hack/libdm_tag.sh b/hack/libdm_tag.sh
index d3668aab1..815b5d914 100755
--- a/hack/libdm_tag.sh
+++ b/hack/libdm_tag.sh
@@ -2,7 +2,7 @@
tmpdir="$PWD/tmp.$RANDOM"
mkdir -p "$tmpdir"
trap 'rm -fr "$tmpdir"' EXIT
-cc -o "$tmpdir"/libdm_tag -ldevmapper -x c - > /dev/null 2> /dev/null << EOF
+${CC:-cc} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} -o "$tmpdir"/libdm_tag -x c - -ldevmapper > /dev/null 2> /dev/null << EOF
#include <libdevmapper.h>
int main() {
struct dm_task *task;
diff --git a/hack/systemd_tag.sh b/hack/systemd_tag.sh
index 19a7bf6a6..5af322881 100755
--- a/hack/systemd_tag.sh
+++ b/hack/systemd_tag.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-cc -E - > /dev/null 2> /dev/null << EOF
+${CPP:-${CC:-cc} -E} ${CPPFLAGS} - > /dev/null 2> /dev/null << EOF
#include <systemd/sd-daemon.h>
EOF
if test $? -eq 0 ; then
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 9dd5ca465..0b9b353c7 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -50,10 +50,12 @@ type BoltState struct {
// containers in the pod.
// - allPodsBkt: Map of ID to name containing only pods. Used for pod lookup
// operations.
-// - execBkt: Map of exec session ID to exec session - contains a sub-bucket for
-// each exec session in the DB.
-// - execRegistryBkt: Map of exec session ID to nothing. Contains one entry for
-// each exec session. Used for iterating through all exec sessions.
+// - execBkt: Map of exec session ID to container ID - used for resolving
+// exec session IDs to the containers that hold the exec session.
+// - aliasesBkt - Contains a bucket for each CNI network, which contain a map of
+// network alias (an extra name for containers in DNS) to the ID of the
+// container holding the alias. Aliases must be unique per-network, and cannot
+// conflict with names registered in nameRegistryBkt.
// - runtimeConfigBkt: Contains configuration of the libpod instance that
// initially created the database. This must match for any further instances
// that access the database, to ensure that state mismatches with
@@ -92,6 +94,7 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
volBkt,
allVolsBkt,
execBkt,
+ aliasesBkt,
runtimeConfigBkt,
}
@@ -969,6 +972,463 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
return ctrs, nil
}
+// GetNetworkAliases retrieves the network aliases for the given container in
+// the given CNI network.
+func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
+ if !s.valid {
+ return nil, define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return nil, define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return nil, errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ aliases := []string{}
+
+ err = db.View(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrNetworkBkt := dbCtr.Bucket(networksBkt)
+ if ctrNetworkBkt == nil {
+ // No networks joined, so no aliases
+ return nil
+ }
+
+ inNetwork := ctrNetworkBkt.Get([]byte(network))
+ if inNetwork == nil {
+ return errors.Wrapf(define.ErrNoAliases, "container %s is not part of network %s, no aliases found", ctr.ID(), network)
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ // No aliases
+ return nil
+ }
+
+ netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
+ if netAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliasesForNetwork, "container %s has no aliases for network %q", ctr.ID(), network)
+ }
+
+ return netAliasesBkt.ForEach(func(alias, v []byte) error {
+ aliases = append(aliases, string(alias))
+ return nil
+ })
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return aliases, nil
+}
+
+// GetAllNetworkAliases retrieves the network aliases for the given container in
+// all CNI networks.
+func (s *BoltState) GetAllNetworkAliases(ctr *Container) (map[string][]string, error) {
+ if !s.valid {
+ return nil, define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return nil, define.ErrCtrRemoved
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return nil, errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ aliases := make(map[string][]string)
+
+ err = db.View(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ // No aliases present
+ return nil
+ }
+
+ ctrNetworkBkt := dbCtr.Bucket(networksBkt)
+ if ctrNetworkBkt == nil {
+ // No networks joined, so no aliases
+ return nil
+ }
+
+ return ctrNetworkBkt.ForEach(func(network, v []byte) error {
+ netAliasesBkt := ctrAliasesBkt.Bucket(network)
+ if netAliasesBkt == nil {
+ return nil
+ }
+
+ netAliases := []string{}
+
+ _ = netAliasesBkt.ForEach(func(alias, v []byte) error {
+ netAliases = append(netAliases, string(alias))
+ return nil
+ })
+
+ aliases[string(network)] = netAliases
+ return nil
+ })
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return aliases, nil
+}
+
+// SetNetworkAliases sets network aliases for the given container in the given
+// network. All existing aliases for that network (if any exist) will be removed,
+// to be replaced by the new aliases given.
+func (s *BoltState) SetNetworkAliases(ctr *Container, network string, aliases []string) error {
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ return db.Update(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ allAliasesBucket, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ netAllAliasesBucket, err := allAliasesBucket.CreateBucketIfNotExists([]byte(network))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %s", network)
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID())
+ }
+
+ ctrNetworksBkt := dbCtr.Bucket(networksBkt)
+ if ctrNetworksBkt == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID())
+ }
+ netConnected := ctrNetworksBkt.Get([]byte(network))
+ if netConnected == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to CNI network %q, so cannot add aliases for this network", ctr.ID(), network)
+ }
+
+ namesBucket, err := getNamesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ // Check if the container already has network aliases for this network.
+ netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
+ if netAliasesBkt != nil {
+ // We have aliases. Have to remove them.
+ forEachErr := netAliasesBkt.ForEach(func(alias, v []byte) error {
+ // Relies on errors.Wrapf(nil, ...) returning
+ // nil.
+ return errors.Wrapf(netAllAliasesBucket.Delete(alias), "error removing alias %q from network %q when changing aliases for container %s", string(alias), network, ctr.ID())
+ })
+ if forEachErr != nil {
+ return forEachErr
+ }
+ }
+
+ if netAliasesBkt == nil {
+ newBkt, err := ctrAliasesBkt.CreateBucket([]byte(network))
+ if err != nil {
+ return errors.Wrapf(err, "could not create bucket for network aliases for network %q", network)
+ }
+ netAliasesBkt = newBkt
+ }
+
+ for _, alias := range aliases {
+ // Check if safe to use
+ aliasExists := netAllAliasesBucket.Get([]byte(alias))
+ if aliasExists != nil {
+ return errors.Wrapf(define.ErrAliasExists, "network alias %q already exists in network %q (used by container %s)", alias, network, string(aliasExists))
+ }
+ nameExists := namesBucket.Get([]byte(alias))
+ if nameExists != nil {
+ return errors.Wrapf(define.ErrCtrExists, "a container or pod already uses the name %q, cannot add network alias for container %s", alias, ctr.ID())
+ }
+
+ // Add alias
+ if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding container %s network %q alias %q to DB", ctr.ID(), network, alias)
+ }
+ if err := netAllAliasesBucket.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding container %s network %q alias %q to all aliases in DB", ctr.ID(), network, alias)
+ }
+ }
+
+ return nil
+ })
+}
+
+// RemoveNetworkAliases removes network aliases of the given container in the
+// given network.
+func (s *BoltState) RemoveNetworkAliases(ctr *Container, network string) error {
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ return db.Update(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ allAliasesBucket, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ netAllAliasesBucket, err := allAliasesBucket.CreateBucketIfNotExists([]byte(network))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %s", network)
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID())
+ }
+
+ ctrNetworksBkt := dbCtr.Bucket(networksBkt)
+ if ctrNetworksBkt == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID())
+ }
+ netConnected := ctrNetworksBkt.Get([]byte(network))
+ if netConnected == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to CNI network %q, so cannot add aliases for this network", ctr.ID(), network)
+ }
+
+ // Check if the container already has network aliases for this network.
+ netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
+ if netAliasesBkt != nil {
+ // We have aliases. Remove them.
+ forEachErr := netAliasesBkt.ForEach(func(alias, v []byte) error {
+ // Relies on errors.Wrapf(nil, ...) returning
+ // nil.
+ return errors.Wrapf(netAllAliasesBucket.Delete(alias), "error removing alias %q from network %q when changing aliases for container %s", string(alias), network, ctr.ID())
+ })
+ if forEachErr != nil {
+ return forEachErr
+ }
+ }
+
+ return nil
+ })
+}
+
+// Get all network aliases for a single CNI network. Returns a map of alias to
+// container ID.
+func (s *BoltState) GetAllAliasesForNetwork(network string) (map[string]string, error) {
+ if !s.valid {
+ return nil, define.ErrDBClosed
+ }
+
+ if network == "" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "network name must not be empty")
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ aliases := make(map[string]string)
+
+ err = db.View(func(tx *bolt.Tx) error {
+ aliasBucket, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ dbAlias := aliasBucket.Bucket([]byte(network))
+ if dbAlias == nil {
+ // We can't tell if the network exists, or doesn't exist
+ // So... Assume it exists, but has no aliases.
+ return nil
+ }
+
+ return dbAlias.ForEach(func(alias, ctrId []byte) error {
+ aliases[string(alias)] = string(ctrId)
+ return nil
+ })
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return aliases, nil
+}
+
+// RemoveAllAliasesForNetwork removes all the aliases in a given CNI network, as
+// part of that network being removed.
+func (s *BoltState) RemoveAllAliasesForNetwork(network string) error {
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ return db.Update(func(tx *bolt.Tx) error {
+ allCtrsBucket, err := getAllCtrsBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ allAliasesBucket, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ checkAliasesBucketExists := allAliasesBucket.Bucket([]byte(network))
+ if checkAliasesBucketExists != nil {
+ if err := allAliasesBucket.DeleteBucket([]byte(network)); err != nil {
+ return errors.Wrapf(err, "error removing network %s aliases bucket from DB", network)
+ }
+ }
+
+ // Iterate through all containers and remove their aliases
+ // bucket for the network.
+ return allCtrsBucket.ForEach(func(ctrID, ctrName []byte) error {
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ // DB State is inconsistent... but we can't do
+ // anything about it.
+ // Log and move on.
+ logrus.Errorf("Container %s listed in all containers, but has no bucket!", string(ctrID))
+ return nil
+ }
+
+ dbCtrAliases := dbCtr.Bucket(aliasesBkt)
+ if dbCtrAliases == nil {
+ // Container has no aliases, this is OK.
+ return nil
+ }
+
+ ctrNetAliases := dbCtrAliases.Bucket([]byte(network))
+ if ctrNetAliases != nil {
+ if err := dbCtrAliases.DeleteBucket([]byte(network)); err != nil {
+ return errors.Wrapf(err, "error removing bucket for network aliases for network %s from container %s", network, string(ctrID))
+ }
+ }
+ return nil
+ })
+ })
+}
+
// GetContainerConfig returns a container config from the database by full ID
func (s *BoltState) GetContainerConfig(id string) (*ContainerConfig, error) {
if len(id) == 0 {
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 2f485318c..a48de3092 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -26,6 +26,7 @@ const (
volName = "vol"
allVolsName = "allVolumes"
execName = "exec"
+ aliasesName = "aliases"
runtimeConfigName = "runtime-config"
configName = "config"
@@ -36,6 +37,7 @@ const (
containersName = "containers"
podIDName = "pod-id"
namespaceName = "namespace"
+ networksName = "networks"
staticDirName = "static-dir"
tmpDirName = "tmp-dir"
@@ -47,26 +49,28 @@ const (
)
var (
- idRegistryBkt = []byte(idRegistryName)
- nameRegistryBkt = []byte(nameRegistryName)
- nsRegistryBkt = []byte(nsRegistryName)
- ctrBkt = []byte(ctrName)
- allCtrsBkt = []byte(allCtrsName)
- podBkt = []byte(podName)
- allPodsBkt = []byte(allPodsName)
- volBkt = []byte(volName)
- allVolsBkt = []byte(allVolsName)
- execBkt = []byte(execName)
- runtimeConfigBkt = []byte(runtimeConfigName)
-
- configKey = []byte(configName)
- stateKey = []byte(stateName)
+ idRegistryBkt = []byte(idRegistryName)
+ nameRegistryBkt = []byte(nameRegistryName)
+ nsRegistryBkt = []byte(nsRegistryName)
+ ctrBkt = []byte(ctrName)
+ allCtrsBkt = []byte(allCtrsName)
+ podBkt = []byte(podName)
+ allPodsBkt = []byte(allPodsName)
+ volBkt = []byte(volName)
+ allVolsBkt = []byte(allVolsName)
+ execBkt = []byte(execName)
+ aliasesBkt = []byte(aliasesName)
+ runtimeConfigBkt = []byte(runtimeConfigName)
dependenciesBkt = []byte(dependenciesName)
volDependenciesBkt = []byte(volCtrDependencies)
- netNSKey = []byte(netNSName)
- containersBkt = []byte(containersName)
- podIDKey = []byte(podIDName)
- namespaceKey = []byte(namespaceName)
+ networksBkt = []byte(networksName)
+
+ configKey = []byte(configName)
+ stateKey = []byte(stateName)
+ netNSKey = []byte(netNSName)
+ containersBkt = []byte(containersName)
+ podIDKey = []byte(podIDName)
+ namespaceKey = []byte(namespaceName)
staticDirKey = []byte(staticDirName)
tmpDirKey = []byte(tmpDirName)
@@ -350,6 +354,14 @@ func getExecBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
return bkt, nil
}
+func getAliasesBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
+ bkt := tx.Bucket(aliasesBkt)
+ if bkt == nil {
+ return nil, errors.Wrapf(define.ErrDBBadConfig, "aliases bucket not found in DB")
+ }
+ return bkt, nil
+}
+
func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
bkt := tx.Bucket(runtimeConfigBkt)
if bkt == nil {
@@ -572,6 +584,11 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return err
}
+ allAliasesBkt, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
// If a pod was given, check if it exists
var podDB *bolt.Bucket
var podCtrs *bolt.Bucket
@@ -618,6 +635,44 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "name \"%s\" is in use", ctr.Name())
}
+ // Check that we don't have any empty network names
+ for _, net := range ctr.config.Networks {
+ if net == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string")
+ }
+ }
+
+ // If we have network aliases, check if they are already in use.
+ for net, aliases := range ctr.config.NetworkAliases {
+ // Aliases cannot conflict with container names.
+ for _, alias := range aliases {
+ aliasExist := namesBucket.Get([]byte(alias))
+ if aliasExist != nil {
+ return errors.Wrapf(define.ErrCtrExists, "alias %q conflicts with existing container/pod name", alias)
+ }
+ }
+
+ netAliasesBkt := allAliasesBkt.Bucket([]byte(net))
+ if netAliasesBkt != nil {
+ for _, alias := range aliases {
+ aliasExist := netAliasesBkt.Get([]byte(alias))
+ if aliasExist != nil {
+ return errors.Wrapf(define.ErrAliasExists, "network alias %q already exists for network %q", net, alias)
+ }
+ }
+ }
+ hasNet := false
+ for _, testNet := range ctr.config.Networks {
+ if testNet == net {
+ hasNet = true
+ break
+ }
+ }
+ if !hasNet {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not part of that network", ctr.ID(), net)
+ }
+ }
+
// No overlapping containers
// Add the new container to the DB
if err := idsBucket.Put(ctrID, ctrName); err != nil {
@@ -635,6 +690,63 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "error adding container %s to all containers bucket in DB", ctr.ID())
}
+ // Check aliases for all networks, remove conflicts with the
+ // container name.
+ for _, net := range ctr.config.Networks {
+ netAliasesBkt := allAliasesBkt.Bucket([]byte(net))
+ if netAliasesBkt == nil {
+ continue
+ }
+
+ otherCtrID := netAliasesBkt.Get(ctrName)
+ if otherCtrID == nil {
+ continue
+ }
+
+ if err := netAliasesBkt.Delete(ctrName); err != nil {
+ return errors.Wrapf(err, "error removing container %s name from network aliases for network %s", ctr.ID(), net)
+ }
+
+ // We now need to remove from the other container.
+ // To do this, we work through the container bucket,
+ // then its aliases bucket, then its aliases for this
+ // specific network, then we remove the alias.
+ // Just slightly ridiculous. Just slightly.
+ otherCtr := ctrBucket.Bucket(otherCtrID)
+ if otherCtr == nil {
+ // The state is inconsistent, but we can't do
+ // much...
+ logrus.Errorf("Container %s referred to by network alias but not present in state", string(otherCtrID))
+ continue
+ }
+ otherCtrAliases := otherCtr.Bucket(aliasesBkt)
+ if otherCtrAliases == nil {
+ logrus.Errorf("Container %s is missing aliases but but has an alias", string(otherCtrID))
+ continue
+ }
+ otherCtrNetworkAliases := otherCtrAliases.Bucket([]byte(net))
+ if otherCtrNetworkAliases == nil {
+ logrus.Errorf("Container %s is missing network aliases bucket for network %s but has alias in that network", string(otherCtrID), net)
+ }
+ if otherCtrNetworkAliases.Get(ctrName) != nil {
+ if err := otherCtrNetworkAliases.Delete(ctrName); err != nil {
+ return errors.Wrapf(err, "error removing container %s name from network %s aliases of container %s", ctr.Name(), net, string(otherCtrID))
+ }
+ }
+ }
+
+ for net, aliases := range ctr.config.NetworkAliases {
+ netAliasesBkt, err := allAliasesBkt.CreateBucketIfNotExists([]byte(net))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %q", net)
+ }
+ for _, alias := range aliases {
+ if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding container %s network alias %q to network %q", ctr.ID(), alias, net)
+ }
+ }
+ }
+
newCtrBkt, err := ctrBucket.CreateBucket(ctrID)
if err != nil {
return errors.Wrapf(err, "error adding container %s bucket to DB", ctr.ID())
@@ -661,6 +773,35 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "error adding container %s netns path to DB", ctr.ID())
}
}
+ if ctr.config.Networks != nil {
+ ctrNetworksBkt, err := newCtrBkt.CreateBucket(networksBkt)
+ if err != nil {
+ return errors.Wrapf(err, "error creating networks bucket for container %s", ctr.ID())
+ }
+ for _, network := range ctr.config.Networks {
+ if err := ctrNetworksBkt.Put([]byte(network), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding network %q to networks bucket for container %s", network, ctr.ID())
+ }
+ }
+ }
+ if ctr.config.NetworkAliases != nil {
+ ctrAliasesBkt, err := newCtrBkt.CreateBucket(aliasesBkt)
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for container %s", ctr.ID())
+ }
+ for net, aliases := range ctr.config.NetworkAliases {
+ netAliasesBkt, err := ctrAliasesBkt.CreateBucket([]byte(net))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %q in container %s", net, ctr.ID())
+ }
+ for _, alias := range aliases {
+ if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error creating network alias %q in network %q for container %s", alias, net, ctr.ID())
+ }
+ }
+ }
+ }
+
if _, err := newCtrBkt.CreateBucket(dependenciesBkt); err != nil {
return errors.Wrapf(err, "error creating dependencies bucket for container %s", ctr.ID())
}
@@ -857,6 +998,49 @@ func (s *BoltState) removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error
return errors.Wrapf(define.ErrCtrExists, "container %s is a dependency of the following containers: %s", ctr.ID(), strings.Join(deps, ", "))
}
+ // Does the container have any network aliases?
+ ctrNetAliasesBkt := ctrExists.Bucket(aliasesBkt)
+ if ctrNetAliasesBkt != nil {
+ allAliasesBkt, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+ ctrNetworksBkt := ctrExists.Bucket(networksBkt)
+ // Internal state mismatch if this doesn't exist - we'll just
+ // assume there are no aliases in that case.
+ if ctrNetworksBkt != nil {
+ // This is a little gross. Iterate through all networks
+ // the container is joined to. Check if we have aliases
+ // for them. If we do have such aliases, remove all of
+ // then from the global aliases table for that network.
+ err = ctrNetworksBkt.ForEach(func(network, v []byte) error {
+ netAliasesBkt := ctrNetAliasesBkt.Bucket(network)
+ if netAliasesBkt == nil {
+ return nil
+ }
+ netAllAliasesBkt := allAliasesBkt.Bucket(network)
+ if netAllAliasesBkt == nil {
+ // Again the state is inconsistent here,
+ // but the best we can do is try and
+ // recover by ignoring it.
+ return nil
+ }
+ return netAliasesBkt.ForEach(func(alias, v []byte) error {
+ // We don't want to hard-fail on a
+ // missing alias, so continue if we hit
+ // errors.
+ if err := netAllAliasesBkt.Delete(alias); err != nil {
+ logrus.Errorf("Error removing alias %q from network %q when removing container %s", string(alias), string(network), ctr.ID())
+ }
+ return nil
+ })
+ })
+ if err != nil {
+ return err
+ }
+ }
+ }
+
if err := ctrBucket.DeleteBucket(ctrID); err != nil {
return errors.Wrapf(define.ErrInternal, "error deleting container %s from DB", ctr.ID())
}
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 0006613bc..d73fbb42f 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -241,6 +241,15 @@ type ContainerNetworkConfig struct {
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
// NetworkOptions are additional options for each network
NetworkOptions map[string][]string `json:"network_options,omitempty"`
+ // NetworkAliases are aliases that will be added to each network.
+ // These are additional names that this container can be accessed as via
+ // DNS when the CNI dnsname plugin is in use.
+ // Please note that these can be altered at runtime. As such, the actual
+ // list is stored in the database and should be retrieved from there;
+ // this is only the set of aliases the container was *created with*.
+ // Formatted as map of network name to aliases. All network names must
+ // be present in the Networks list above.
+ NetworkAliases map[string][]string `json:"network_alises,omitempty"`
}
// ContainerImageConfig is an embedded sub-config providing image configuration
diff --git a/libpod/container_validate.go b/libpod/container_validate.go
index 68cc095b7..fa809436e 100644
--- a/libpod/container_validate.go
+++ b/libpod/container_validate.go
@@ -115,5 +115,16 @@ func (c *Container) validate() error {
destinations[vol.Dest] = true
}
+ // Check that networks and network aliases match up.
+ ctrNets := make(map[string]bool)
+ for _, net := range c.config.Networks {
+ ctrNets[net] = true
+ }
+ for net := range c.config.NetworkAliases {
+ if _, ok := ctrNets[net]; !ok {
+ return errors.Wrapf(define.ErrNoSuchNetwork, "container tried to set network aliases for network %s but is not connected to the network", net)
+ }
+ }
+
return nil
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 1b21cd1ce..27c5febf4 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -30,6 +30,13 @@ var (
// not exist.
ErrNoSuchExecSession = errors.New("no such exec session")
+ // ErrNoAliases indicates that the container does not have any network
+ // aliases.
+ ErrNoAliases = errors.New("no aliases for container")
+ // ErrNoAliasesForNetwork indicates that the container has no aliases
+ // for a specific network.
+ ErrNoAliasesForNetwork = errors.New("no aliases for network")
+
// ErrCtrExists indicates a container with the same name or ID already
// exists
ErrCtrExists = errors.New("container already exists")
@@ -42,6 +49,9 @@ var (
// ErrExecSessionExists indicates an exec session with the same ID
// already exists.
ErrExecSessionExists = errors.New("exec session already exists")
+ // ErrAliasExists indicates that a network alias with the same name
+ // already exists in the network.
+ ErrAliasExists = errors.New("alias already exists")
// ErrCtrStateInvalid indicates a container is in an improper state for
// the requested operation
diff --git a/libpod/filters/pods.go b/libpod/filters/pods.go
index adce9784c..0caa941dd 100644
--- a/libpod/filters/pods.go
+++ b/libpod/filters/pods.go
@@ -1,6 +1,7 @@
package lpfilters
import (
+ "regexp"
"strconv"
"strings"
@@ -78,7 +79,11 @@ func GeneratePodFilterFunc(filter, filterValue string) (
}, nil
case "name":
return func(p *libpod.Pod) bool {
- return strings.Contains(p.Name(), filterValue)
+ match, err := regexp.MatchString(filterValue, p.Name())
+ if err != nil {
+ return false
+ }
+ return match
}, nil
case "status":
if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) {
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 0de25a6ef..ba4c70c6b 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -31,6 +31,10 @@ type InMemoryState struct {
ctrExecSessions map[string][]string
// Maps pod ID to a map of container ID to container struct.
podContainers map[string]map[string]*Container
+ // Maps network name to alias to container ID
+ networkAliases map[string]map[string]string
+ // Maps container ID to network name to list of aliases.
+ ctrNetworkAliases map[string]map[string][]string
// Global name registry - ensures name uniqueness and performs lookups.
nameIndex *registrar.Registrar
// Global ID registry - ensures ID uniqueness and performs lookups.
@@ -65,6 +69,9 @@ func NewInMemoryState() (State, error) {
state.podContainers = make(map[string]map[string]*Container)
+ state.networkAliases = make(map[string]map[string]string)
+ state.ctrNetworkAliases = make(map[string]map[string][]string)
+
state.nameIndex = registrar.NewRegistrar()
state.idIndex = truncindex.NewTruncIndex([]string{})
@@ -278,6 +285,40 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
return err
}
+ // Check networks
+ for _, net := range ctr.config.Networks {
+ if net == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names cannot be empty")
+ }
+ }
+
+ // Check network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ break
+ }
+ }
+ if !inNet {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network)
+ }
+
+ allNetAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ // Check if alias is a name
+ if _, err := s.nameIndex.Get(alias); err == nil {
+ return define.ErrInvalidArg
+ }
+ if _, ok := allNetAliases[alias]; ok {
+ return define.ErrAliasExists
+ }
+ }
+ }
+ }
+
// There are potential race conditions with this
// But in-memory state is intended purely for testing and not production
// use, so this should be fine.
@@ -334,6 +375,48 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
}
+ for _, network := range ctr.config.Networks {
+ allNetAliases, ok := s.networkAliases[network]
+ if !ok {
+ continue
+ }
+ otherCtrID, ok := allNetAliases[ctr.Name()]
+ if !ok {
+ continue
+ }
+ delete(allNetAliases, ctr.Name())
+
+ otherCtrAliases, ok := s.ctrNetworkAliases[otherCtrID]
+ if !ok {
+ continue
+ }
+ otherCtrNetAliases, ok := otherCtrAliases[network]
+ if !ok {
+ continue
+ }
+ newAliases := []string{}
+ for _, alias := range otherCtrNetAliases {
+ if alias != ctr.Name() {
+ newAliases = append(newAliases, alias)
+ }
+ }
+ otherCtrAliases[network] = newAliases
+ }
+
+ // Add network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ allNetAliases, ok := s.networkAliases[network]
+ if !ok {
+ allNetAliases = make(map[string]string)
+ s.networkAliases[network] = allNetAliases
+ }
+
+ for _, alias := range aliases {
+ allNetAliases[alias] = ctr.ID()
+ }
+ }
+ s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases
+
return nil
}
@@ -396,6 +479,20 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
s.removeCtrFromVolDependsMap(ctr.ID(), vol.Name)
}
+ // Remove our network aliases
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if ok {
+ for network, aliases := range ctrAliases {
+ netAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ delete(netAliases, alias)
+ }
+ }
+ }
+ delete(s.ctrNetworkAliases, ctr.ID())
+ }
+
return nil
}
@@ -472,6 +569,207 @@ func (s *InMemoryState) AllContainers() ([]*Container, error) {
return ctrs, nil
}
+// GetNetworkAliases returns network aliases for the given container in the
+// given network.
+func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
+ if !ctr.valid {
+ return nil, define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return nil, define.ErrNoSuchCtr
+ }
+
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ }
+ }
+ if !inNet {
+ return nil, define.ErrInvalidArg
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ return []string{}, nil
+ }
+ netAliases, ok := ctrAliases[network]
+ if !ok {
+ return []string{}, nil
+ }
+
+ return netAliases, nil
+}
+
+// GetAllNetworkAliases gets all network aliases for the given container.
+func (s *InMemoryState) GetAllNetworkAliases(ctr *Container) (map[string][]string, error) {
+ if !ctr.valid {
+ return nil, define.ErrCtrRemoved
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return nil, define.ErrNoSuchCtr
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ return map[string][]string{}, nil
+ }
+
+ return ctrAliases, nil
+}
+
+// SetNetworkAliases sets network aliases for the given container in the given
+// network.
+func (s *InMemoryState) SetNetworkAliases(ctr *Container, network string, aliases []string) error {
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return define.ErrNoSuchCtr
+ }
+
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ }
+ }
+ if !inNet {
+ return define.ErrInvalidArg
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ ctrAliases = make(map[string][]string)
+ s.ctrNetworkAliases[ctr.ID()] = ctrAliases
+ }
+ netAliases, ok := ctrAliases[network]
+ if !ok {
+ netAliases = []string{}
+ ctrAliases[network] = netAliases
+ }
+
+ allAliases, ok := s.networkAliases[network]
+ if !ok {
+ allAliases = make(map[string]string)
+ s.networkAliases[network] = allAliases
+ }
+
+ for _, alias := range netAliases {
+ delete(allAliases, alias)
+ }
+
+ for _, newAlias := range aliases {
+ if _, ok := allAliases[newAlias]; ok {
+ return define.ErrAliasExists
+ }
+ allAliases[newAlias] = ctr.ID()
+ }
+
+ ctrAliases[network] = aliases
+
+ return nil
+}
+
+// RemoveNetworkAliases removes network aliases from the given container in the
+// given network.
+func (s *InMemoryState) RemoveNetworkAliases(ctr *Container, network string) error {
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return define.ErrNoSuchCtr
+ }
+
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ }
+ }
+ if !inNet {
+ return define.ErrInvalidArg
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ ctrAliases = make(map[string][]string)
+ s.ctrNetworkAliases[ctr.ID()] = ctrAliases
+ }
+ netAliases, ok := ctrAliases[network]
+ if !ok {
+ netAliases = []string{}
+ ctrAliases[network] = netAliases
+ }
+
+ allAliases, ok := s.networkAliases[network]
+ if !ok {
+ allAliases = make(map[string]string)
+ s.networkAliases[network] = allAliases
+ }
+
+ for _, alias := range netAliases {
+ delete(allAliases, alias)
+ }
+
+ return nil
+}
+
+// GetAllAliasesForNetwork gets all the aliases for a single network.
+func (s *InMemoryState) GetAllAliasesForNetwork(network string) (map[string]string, error) {
+ if network == "" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ allAliases, ok := s.networkAliases[network]
+ if !ok {
+ // Can't tell if the network exists.
+ // Assume it does.
+ return map[string]string{}, nil
+ }
+
+ return allAliases, nil
+}
+
+// RemoveAllAliasesForNetwork removes all the aliases for a given network.
+func (s *InMemoryState) RemoveAllAliasesForNetwork(network string) error {
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if _, ok := s.networkAliases[network]; ok {
+ delete(s.networkAliases, network)
+ }
+
+ for _, ctrAliases := range s.ctrNetworkAliases {
+ if _, ok := ctrAliases[network]; ok {
+ delete(ctrAliases, network)
+ }
+ }
+
+ return nil
+}
+
// GetContainerConfig returns a container config from the database by full ID
func (s *InMemoryState) GetContainerConfig(id string) (*ContainerConfig, error) {
ctr, err := s.LookupContainer(id)
@@ -1116,6 +1414,40 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
return err
}
+ // Check networks
+ for _, net := range ctr.config.Networks {
+ if net == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names cannot be empty")
+ }
+ }
+
+ // Check network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ break
+ }
+ }
+ if !inNet {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network)
+ }
+
+ allNetAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ // Check if alias is a name
+ if _, err := s.nameIndex.Get(alias); err == nil {
+ return define.ErrInvalidArg
+ }
+ if _, ok := allNetAliases[alias]; ok {
+ return define.ErrAliasExists
+ }
+ }
+ }
+ }
+
// Retrieve pod containers list
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
@@ -1188,6 +1520,53 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
s.addCtrToDependsMap(ctr.ID(), depCtr)
}
+ // Add container to volume dependencies
+ for _, vol := range ctr.config.NamedVolumes {
+ s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
+ }
+
+ for _, network := range ctr.config.Networks {
+ allNetAliases, ok := s.networkAliases[network]
+ if !ok {
+ continue
+ }
+ otherCtrID, ok := allNetAliases[ctr.Name()]
+ if !ok {
+ continue
+ }
+ delete(allNetAliases, ctr.Name())
+
+ otherCtrAliases, ok := s.ctrNetworkAliases[otherCtrID]
+ if !ok {
+ continue
+ }
+ otherCtrNetAliases, ok := otherCtrAliases[network]
+ if !ok {
+ continue
+ }
+ newAliases := []string{}
+ for _, alias := range otherCtrNetAliases {
+ if alias != ctr.Name() {
+ newAliases = append(newAliases, alias)
+ }
+ }
+ otherCtrAliases[network] = newAliases
+ }
+
+ // Add network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ allNetAliases, ok := s.networkAliases[network]
+ if !ok {
+ allNetAliases = make(map[string]string)
+ s.networkAliases[network] = allNetAliases
+ }
+
+ for _, alias := range aliases {
+ allNetAliases[alias] = ctr.ID()
+ }
+ }
+ s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases
+
return nil
}
@@ -1268,6 +1647,20 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
s.removeCtrFromDependsMap(ctr.ID(), depCtr)
}
+ // Remove our network aliases
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if ok {
+ for network, aliases := range ctrAliases {
+ netAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ delete(netAliases, alias)
+ }
+ }
+ }
+ delete(s.ctrNetworkAliases, ctr.ID())
+ }
+
return nil
}
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index 8651c1dc5..7068bf87a 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -444,10 +444,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
// }
// }
- conmonEnv, extraFiles, err := r.configureConmonEnv(c, runtimeDir)
- if err != nil {
- return nil, nil, err
- }
+ conmonEnv, extraFiles := r.configureConmonEnv(c, runtimeDir)
var filesToClose []*os.File
if options.PreserveFDs > 0 {
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 89d64537d..bd58610a2 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -32,6 +32,7 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
+ "github.com/containers/storage/pkg/homedir"
pmount "github.com/containers/storage/pkg/mount"
"github.com/coreos/go-systemd/v22/activation"
"github.com/coreos/go-systemd/v22/daemon"
@@ -1065,10 +1066,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
}
// 0, 1 and 2 are stdin, stdout and stderr
- conmonEnv, envFiles, err := r.configureConmonEnv(ctr, runtimeDir)
- if err != nil {
- return err
- }
+ conmonEnv, envFiles := r.configureConmonEnv(ctr, runtimeDir)
var filesToClose []*os.File
if ctr.config.PreserveFDs > 0 {
@@ -1268,16 +1266,15 @@ func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, se
// configureConmonEnv gets the environment values to add to conmon's exec struct
// TODO this may want to be less hardcoded/more configurable in the future
-func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) ([]string, []*os.File, error) {
+func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) ([]string, []*os.File) {
env := make([]string, 0, 6)
env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED")))
env = append(env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%s", os.Getenv("_CONTAINERS_ROOTLESS_UID")))
- home, err := util.HomeDir()
- if err != nil {
- return nil, nil, err
+ home := homedir.Get()
+ if home != "" {
+ env = append(env, fmt.Sprintf("HOME=%s", home))
}
- env = append(env, fmt.Sprintf("HOME=%s", home))
extraFiles := make([]*os.File, 0)
if ctr.config.SdNotifyMode == define.SdNotifyModeContainer {
@@ -1294,7 +1291,7 @@ func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string)
} else {
logrus.Debug("disabling SD notify")
}
- return env, extraFiles, nil
+ return env, extraFiles
}
// sharedConmonArgs takes common arguments for exec and create/restore and formats them for the conmon CLI
diff --git a/libpod/options.go b/libpod/options.go
index 060887b7e..0f55f34a3 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1506,6 +1506,20 @@ func WithCreateWorkingDir() CtrCreateOption {
}
}
+// WithNetworkAliases sets network aliases for the container.
+// Accepts a map of network name to aliases.
+func WithNetworkAliases(aliases map[string][]string) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ ctr.config.NetworkAliases = aliases
+
+ return nil
+ }
+}
+
// Volume Creation Options
// WithVolumeName sets the name of the volume.
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index de73a9ff3..c84268889 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -918,6 +918,56 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
return prunedContainers, pruneErrors, nil
}
+// MountStorageContainer mounts the storage container's root filesystem
+func (r *Runtime) MountStorageContainer(id string) (string, error) {
+ if _, err := r.GetContainer(id); err == nil {
+ return "", errors.Wrapf(define.ErrCtrExists, "ctr %s is a libpod container", id)
+ }
+ container, err := r.store.Container(id)
+ if err != nil {
+ return "", err
+ }
+ mountPoint, err := r.store.Mount(container.ID, "")
+ if err != nil {
+ return "", errors.Wrapf(err, "error mounting storage for container %s", id)
+ }
+ return mountPoint, nil
+}
+
+// UnmountStorageContainer unmounts the storage container's root filesystem
+func (r *Runtime) UnmountStorageContainer(id string, force bool) (bool, error) {
+ if _, err := r.GetContainer(id); err == nil {
+ return false, errors.Wrapf(define.ErrCtrExists, "ctr %s is a libpod container", id)
+ }
+ container, err := r.store.Container(id)
+ if err != nil {
+ return false, err
+ }
+ return r.store.Unmount(container.ID, force)
+}
+
+// MountedStorageContainer returns whether a storage container is mounted
+// along with the mount path
+func (r *Runtime) IsStorageContainerMounted(id string) (bool, string, error) {
+ var path string
+ if _, err := r.GetContainer(id); err == nil {
+ return false, "", errors.Wrapf(define.ErrCtrExists, "ctr %s is a libpod container", id)
+ }
+
+ mountCnt, err := r.storageService.MountedContainerImage(id)
+ if err != nil {
+ return false, "", err
+ }
+ mounted := mountCnt > 0
+ if mounted {
+ path, err = r.storageService.GetMountpoint(id)
+ if err != nil {
+ return false, "", err
+ }
+ }
+ return mounted, path, nil
+}
+
// StorageContainers returns a list of containers from containers/storage that
// are not currently known to Podman.
func (r *Runtime) StorageContainers() ([]storage.Container, error) {
diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go
index 32fb1ef44..e1877b17d 100644
--- a/libpod/runtime_volume_linux.go
+++ b/libpod/runtime_volume_linux.go
@@ -75,7 +75,7 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption)
return nil, errors.Wrapf(err, "error chowning volume directory %q to %d:%d", volPathRoot, volume.config.UID, volume.config.GID)
}
fullVolPath := filepath.Join(volPathRoot, "_data")
- if err := os.Mkdir(fullVolPath, 0755); err != nil {
+ if err := os.MkdirAll(fullVolPath, 0755); err != nil {
return nil, errors.Wrapf(err, "error creating volume directory %q", fullVolPath)
}
if err := os.Chown(fullVolPath, volume.config.UID, volume.config.GID); err != nil {
diff --git a/libpod/state.go b/libpod/state.go
index 44632b02f..183f773b5 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -98,6 +98,21 @@ type State interface {
// returned.
AllContainers() ([]*Container, error)
+ // Get network aliases for the given container in the given network.
+ GetNetworkAliases(ctr *Container, network string) ([]string, error)
+ // Get all network aliases for the given container.
+ GetAllNetworkAliases(ctr *Container) (map[string][]string, error)
+ // Set network aliases for the given container in the given network.
+ SetNetworkAliases(ctr *Container, network string, aliases []string) error
+ // Remove network aliases for the given container in the given network.
+ RemoveNetworkAliases(ctr *Container, network string) error
+ // GetAllAliasesForNetwork returns all the aliases for a given
+ // network. Returns a map of alias to container ID.
+ GetAllAliasesForNetwork(network string) (map[string]string, error)
+ // RemoveAllAliasesForNetwork removes all the aliases for a given
+ // network.
+ RemoveAllAliasesForNetwork(network string) error
+
// Return a container config from the database by full ID
GetContainerConfig(id string) (*ContainerConfig, error)
diff --git a/libpod/state_test.go b/libpod/state_test.go
index 373feb6e0..cf41270bf 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -1319,6 +1319,250 @@ func TestCannotUsePodAsDependency(t *testing.T) {
})
}
+func TestAddContainerEmptyNetworkNameErrors(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ testCtr.config.Networks = []string{""}
+
+ err = state.AddContainer(testCtr)
+ assert.Error(t, err)
+ })
+}
+
+func TestAddContainerNetworkAliasesButNoMatchingNetwork(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ testCtr.config.Networks = []string{"test1"}
+ testCtr.config.NetworkAliases = make(map[string][]string)
+ testCtr.config.NetworkAliases["test2"] = []string{"alias1"}
+
+ err = state.AddContainer(testCtr)
+ assert.Error(t, err)
+ })
+}
+
+func TestAddContainerNetworkAliasConflictWithName(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr1, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ netName := "testnet"
+ testCtr1.config.Networks = []string{netName}
+ testCtr1.config.NetworkAliases = make(map[string][]string)
+ testCtr1.config.NetworkAliases[netName] = []string{"alias1"}
+
+ testCtr2, err := getTestCtr2(manager)
+ assert.NoError(t, err)
+
+ testCtr2.config.Networks = []string{netName}
+ testCtr2.config.NetworkAliases = make(map[string][]string)
+ testCtr2.config.NetworkAliases[netName] = []string{testCtr1.Name()}
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainer(testCtr2)
+ assert.Error(t, err)
+ })
+}
+
+func TestAddContainerNetworkAliasConflictWithAlias(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr1, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ netName := "testnet"
+ aliasName := "alias1"
+ testCtr1.config.Networks = []string{netName}
+ testCtr1.config.NetworkAliases = make(map[string][]string)
+ testCtr1.config.NetworkAliases[netName] = []string{aliasName}
+
+ testCtr2, err := getTestCtr2(manager)
+ assert.NoError(t, err)
+
+ testCtr2.config.Networks = []string{netName}
+ testCtr2.config.NetworkAliases = make(map[string][]string)
+ testCtr2.config.NetworkAliases[netName] = []string{aliasName}
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainer(testCtr2)
+ assert.Error(t, err)
+ })
+}
+
+func TestAddContainerNetworkAliasConflictWithAliasButDifferentNets(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr1, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ netName := "testnet"
+ aliasName := "alias1"
+ testCtr1.config.Networks = []string{netName}
+ testCtr1.config.NetworkAliases = make(map[string][]string)
+ testCtr1.config.NetworkAliases[netName] = []string{aliasName}
+
+ testCtr2, err := getTestCtr2(manager)
+ assert.NoError(t, err)
+
+ netName2 := "testnet2"
+ testCtr2.config.Networks = []string{netName2}
+ testCtr2.config.NetworkAliases = make(map[string][]string)
+ testCtr2.config.NetworkAliases[netName2] = []string{aliasName}
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainer(testCtr2)
+ assert.NoError(t, err)
+ })
+}
+
+func TestAddContainerNameConflictsWithAliasRemovesAlias(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr1, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ testCtr2, err := getTestCtr2(manager)
+ assert.NoError(t, err)
+
+ netName := "testnet"
+ aliasName := testCtr2.Name()
+ testCtr1.config.Networks = []string{netName}
+ testCtr1.config.NetworkAliases = make(map[string][]string)
+ testCtr1.config.NetworkAliases[netName] = []string{aliasName}
+
+ testCtr2.config.Networks = []string{netName}
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ err = state.AddContainer(testCtr2)
+ assert.NoError(t, err)
+
+ aliases, err := state.GetNetworkAliases(testCtr1, netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(aliases))
+ })
+}
+
+func TestNetworkAliasAddAndRemoveSingleContainer(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ netName := "testnet"
+ testCtr.config.Networks = []string{netName}
+ testCtr.config.NetworkAliases = make(map[string][]string)
+ testCtr.config.NetworkAliases[netName] = []string{"alias1"}
+
+ startAliases, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(startAliases))
+
+ err = state.AddContainer(testCtr)
+ assert.NoError(t, err)
+
+ oneAlias, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(oneAlias))
+ assert.Equal(t, testCtr.ID(), oneAlias["alias1"])
+
+ allAliases, err := state.GetAllNetworkAliases(testCtr)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(allAliases))
+ netAliases, ok := allAliases[netName]
+ assert.True(t, ok)
+ assert.Equal(t, 1, len(netAliases))
+ assert.Equal(t, "alias1", netAliases[0])
+
+ ctrNetAliases, err := state.GetNetworkAliases(testCtr, netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(ctrNetAliases))
+ assert.Equal(t, "alias1", ctrNetAliases[0])
+
+ err = state.RemoveContainer(testCtr)
+ assert.NoError(t, err)
+
+ noAliases, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(noAliases))
+ })
+}
+
+func TestNetworkAliasAddAndRemoveTwoContainers(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testCtr1, err := getTestCtr1(manager)
+ assert.NoError(t, err)
+
+ netName := "testnet"
+ testCtr1.config.Networks = []string{netName}
+ testCtr1.config.NetworkAliases = make(map[string][]string)
+ testCtr1.config.NetworkAliases[netName] = []string{"alias1"}
+
+ testCtr2, err := getTestCtr2(manager)
+ assert.NoError(t, err)
+
+ testCtr2.config.Networks = []string{netName}
+ testCtr2.config.NetworkAliases = make(map[string][]string)
+ testCtr2.config.NetworkAliases[netName] = []string{"alias2"}
+
+ startAliases, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(startAliases))
+
+ err = state.AddContainer(testCtr1)
+ assert.NoError(t, err)
+
+ oneAlias, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(oneAlias))
+ assert.Equal(t, testCtr1.ID(), oneAlias["alias1"])
+
+ err = state.AddContainer(testCtr2)
+ assert.NoError(t, err)
+
+ twoAliases, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 2, len(twoAliases))
+ assert.Equal(t, testCtr1.ID(), twoAliases["alias1"])
+ assert.Equal(t, testCtr2.ID(), twoAliases["alias2"])
+
+ allAliases, err := state.GetAllNetworkAliases(testCtr1)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(allAliases))
+ netAliases, ok := allAliases[netName]
+ assert.True(t, ok)
+ assert.Equal(t, 1, len(netAliases))
+ assert.Equal(t, "alias1", netAliases[0])
+
+ ctrNetAliases, err := state.GetNetworkAliases(testCtr1, netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(ctrNetAliases))
+ assert.Equal(t, "alias1", ctrNetAliases[0])
+
+ err = state.RemoveContainer(testCtr2)
+ assert.NoError(t, err)
+
+ oneAlias, err = state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 1, len(oneAlias))
+ assert.Equal(t, testCtr1.ID(), oneAlias["alias1"])
+
+ err = state.RemoveContainer(testCtr1)
+ assert.NoError(t, err)
+
+ noAliases, err := state.GetAllAliasesForNetwork(netName)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(noAliases))
+ })
+}
+
func TestCannotUseBadIDAsDependency(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
testCtr, err := getTestCtr1(manager)
diff --git a/nix/nixpkgs.json b/nix/nixpkgs.json
index 31795516c..81a2f974c 100644
--- a/nix/nixpkgs.json
+++ b/nix/nixpkgs.json
@@ -1,7 +1,7 @@
{
"url": "https://github.com/nixos/nixpkgs",
- "rev": "c095d986c73b4e3d82af299b4175b9b475ebbf3a",
- "date": "2020-10-07T23:58:44-03:00",
- "sha256": "0ygv3wq26mxvy6kahs95ivl6n80bac3pbh6xmgw9ijcnnr03lm01",
+ "rev": "6e089d30148953df7abb3a1167169afc7848499c",
+ "date": "2020-11-05T09:56:30+01:00",
+ "sha256": "0ydqjkz7payl16psx445jwh6dc6lgbvj2w11xin1dqvbpcp03jcy",
"fetchSubmodules": false
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 98b886845..855f9ece8 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1058,11 +1058,23 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
os.Exit(ret)
}
}
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
+ reports := []*entities.ContainerMountReport{}
+ // Attempt to mount named containers directly from storage,
+ // this will fail and code will fall through to removing the container from libpod.`
+ names := []string{}
+ for _, ctr := range nameOrIDs {
+ report := entities.ContainerMountReport{Id: ctr}
+ if report.Path, report.Err = ic.Libpod.MountStorageContainer(ctr); report.Err != nil {
+ names = append(names, ctr)
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil {
return nil, err
}
- reports := make([]*entities.ContainerMountReport, 0, len(ctrs))
for _, ctr := range ctrs {
report := entities.ContainerMountReport{Id: ctr.ID()}
report.Path, report.Err = ctr.Mount()
@@ -1072,6 +1084,30 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
return reports, nil
}
+ storageCtrs, err := ic.Libpod.StorageContainers()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, sctr := range storageCtrs {
+ mounted, path, err := ic.Libpod.IsStorageContainerMounted(sctr.ID)
+ if err != nil {
+ return nil, err
+ }
+
+ var name string
+ if len(sctr.Names) > 0 {
+ name = sctr.Names[0]
+ }
+ if mounted {
+ reports = append(reports, &entities.ContainerMountReport{
+ Id: sctr.ID,
+ Name: name,
+ Path: path,
+ })
+ }
+ }
+
// No containers were passed, so we send back what is mounted
ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
if err != nil {
@@ -1091,15 +1127,44 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
})
}
}
+
return reports, nil
}
func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
+ reports := []*entities.ContainerUnmountReport{}
+ names := []string{}
+ if options.All {
+ storageCtrs, err := ic.Libpod.StorageContainers()
+ if err != nil {
+ return nil, err
+ }
+ for _, sctr := range storageCtrs {
+ mounted, _, _ := ic.Libpod.IsStorageContainerMounted(sctr.ID)
+ if mounted {
+ report := entities.ContainerUnmountReport{Id: sctr.ID}
+ if _, report.Err = ic.Libpod.UnmountStorageContainer(sctr.ID, options.Force); report.Err != nil {
+ if errors.Cause(report.Err) != define.ErrCtrExists {
+ reports = append(reports, &report)
+ }
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+ }
+ }
+ for _, ctr := range nameOrIDs {
+ report := entities.ContainerUnmountReport{Id: ctr}
+ if _, report.Err = ic.Libpod.UnmountStorageContainer(ctr, options.Force); report.Err != nil {
+ names = append(names, ctr)
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil {
return nil, err
}
- reports := []*entities.ContainerUnmountReport{}
for _, ctr := range ctrs {
state, err := ctr.State()
if err != nil {
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index 797d51c33..7ec36b2f8 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -383,12 +383,14 @@ var _ = Describe("Podman pod create", func() {
podID := session.OutputToString()
// verify we can add a host to the infra's /etc/hosts
- session = podmanTest.Podman([]string{"run", "--pod", podID, "--add-host", "foobar:127.0.0.1", BB, "ping", "-c", "1", "foobar"})
+ // N/B: Using alpine for ping, since BB ping throws
+ // permission denied error as of Fedora 33.
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--add-host", "foobar:127.0.0.1", ALPINE, "ping", "-c", "1", "foobar"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
// verify we can see the other hosts of infra's /etc/hosts
- session = podmanTest.Podman([]string{"run", "--pod", podID, BB, "ping", "-c", "1", "foobar"})
+ session = podmanTest.Podman([]string{"run", "--pod", podID, ALPINE, "ping", "-c", "1", "foobar"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go
index a299d3cf2..5d63d5985 100644
--- a/test/e2e/pod_ps_test.go
+++ b/test/e2e/pod_ps_test.go
@@ -107,6 +107,28 @@ var _ = Describe("Podman ps", func() {
Expect(result.ExitCode()).To(Equal(0))
})
+ It("podman pod ps filter name regexp", func() {
+ _, ec, podid := podmanTest.CreatePod("mypod")
+ Expect(ec).To(Equal(0))
+ _, ec2, _ := podmanTest.CreatePod("mypod1")
+ Expect(ec2).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "name=mypod"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ output := result.OutputToStringArray()
+ Expect(len(output)).To(Equal(2))
+
+ result = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "name=mypod$"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ output = result.OutputToStringArray()
+ Expect(len(output)).To(Equal(1))
+ Expect(output[0]).To(Equal(podid))
+ })
+
It("podman pod ps mutually exclusive flags", func() {
session := podmanTest.Podman([]string{"pod", "ps", "-q", "--format", "{{.ID}}"})
session.WaitWithDefaultTimeout()
diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats
index 73d210084..f04f34bf6 100644
--- a/test/system/060-mount.bats
+++ b/test/system/060-mount.bats
@@ -2,7 +2,6 @@
load helpers
-
@test "podman mount - basic test" {
# Only works with root (FIXME: does it work with rootless + vfs?)
skip_if_rootless "mount does not work rootless"
@@ -151,4 +150,34 @@ load helpers
run_podman rm -f $cid
}
+@test "podman mount external container - basic test" {
+ # Only works with root (FIXME: does it work with rootless + vfs?)
+ skip_if_rootless "mount does not work rootless"
+ skip_if_remote "mounting remote is meaningless"
+
+ # Create a container that podman does not know about
+ external_cid=$(buildah from $IMAGE)
+
+ run_podman mount $external_cid
+ mount_path=$output
+
+ # Test image will always have this file, and will always have the tag
+ test -d $mount_path
+ is $(< "$mount_path/home/podman/testimage-id") "$PODMAN_TEST_IMAGE_TAG" \
+ "Contents of well-known file in image"
+
+ # Make sure that 'podman mount' (no args) returns the expected path
+ run_podman mount --notruncate
+
+ reported_mountpoint=$(echo "$output" | awk '{print $2}')
+ is $reported_mountpoint $mount_path "mountpoint reported by 'podman mount'"
+
+ # umount, and make sure files are gone
+ run_podman umount $external_cid
+ if [ -d "$mount_path" ]; then
+ die "'podman umount' did not umount"
+ fi
+ buildah rm $external_cid
+}
+
# vim: filetype=sh
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 82bfa5ce3..63f23d2af 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.23.8
+1.23.9
diff --git a/vendor/github.com/containers/storage/pkg/homedir/homedir_linux.go b/vendor/github.com/containers/storage/pkg/homedir/homedir_linux.go
deleted file mode 100644
index d28ba9d69..000000000
--- a/vendor/github.com/containers/storage/pkg/homedir/homedir_linux.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package homedir
-
-// Copyright 2013-2018 Docker, Inc.
-// NOTE: this package has originally been copied from github.com/docker/docker.
-
-import (
- "errors"
- "os"
- "path/filepath"
- "strings"
-)
-
-// GetRuntimeDir returns XDG_RUNTIME_DIR.
-// XDG_RUNTIME_DIR is typically configured via pam_systemd.
-// GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
-//
-// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
-func GetRuntimeDir() (string, error) {
- if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" {
- return xdgRuntimeDir, nil
- }
- return "", errors.New("could not get XDG_RUNTIME_DIR")
-}
-
-// StickRuntimeDirContents sets the sticky bit on files that are under
-// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system.
-//
-// StickyRuntimeDir returns slice of sticked files.
-// StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set.
-//
-// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
-func StickRuntimeDirContents(files []string) ([]string, error) {
- runtimeDir, err := GetRuntimeDir()
- if err != nil {
- // ignore error if runtimeDir is empty
- return nil, nil
- }
- runtimeDir, err = filepath.Abs(runtimeDir)
- if err != nil {
- return nil, err
- }
- var sticked []string
- for _, f := range files {
- f, err = filepath.Abs(f)
- if err != nil {
- return sticked, err
- }
- if strings.HasPrefix(f, runtimeDir+"/") {
- if err = stick(f); err != nil {
- return sticked, err
- }
- sticked = append(sticked, f)
- }
- }
- return sticked, nil
-}
-
-func stick(f string) error {
- st, err := os.Stat(f)
- if err != nil {
- return err
- }
- m := st.Mode()
- m |= os.ModeSticky
- return os.Chmod(f, m)
-}
-
-// GetDataHome returns XDG_DATA_HOME.
-// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set.
-//
-// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
-func GetDataHome() (string, error) {
- if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
- return xdgDataHome, nil
- }
- home := os.Getenv("HOME")
- if home == "" {
- return "", errors.New("could not get either XDG_DATA_HOME or HOME")
- }
- return filepath.Join(home, ".local", "share"), nil
-}
-
-// GetConfigHome returns XDG_CONFIG_HOME.
-// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
-//
-// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
-func GetConfigHome() (string, error) {
- if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
- return xdgConfigHome, nil
- }
- home := os.Getenv("HOME")
- if home == "" {
- return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
- }
- return filepath.Join(home, ".config"), nil
-}
diff --git a/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go b/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
index f7bcfb878..4f778c858 100644
--- a/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
+++ b/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
@@ -1,4 +1,4 @@
-// +build !linux
+// +build !linux,!darwin
package homedir
diff --git a/vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go b/vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go
index dcadb7e8d..0274d037f 100644
--- a/vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go
+++ b/vendor/github.com/containers/storage/pkg/homedir/homedir_unix.go
@@ -6,8 +6,12 @@ package homedir
// NOTE: this package has originally been copied from github.com/docker/docker.
import (
+ "errors"
"os"
- "os/user"
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/storage/pkg/unshare"
)
// Key returns the env var name for the user's home dir based on
@@ -25,13 +29,8 @@ func Key() string {
//
// If needing to do nss lookups, do not disable cgo or set osusergo.
func Get() string {
- home := os.Getenv(Key())
- if home == "" {
- if u, err := user.Current(); err == nil {
- return u.HomeDir
- }
- }
- return home
+ homedir, _ := unshare.HomeDir()
+ return homedir
}
// GetShortcutString returns the string that is shortcut to user's home directory
@@ -39,3 +38,88 @@ func Get() string {
func GetShortcutString() string {
return "~"
}
+
+// GetRuntimeDir returns XDG_RUNTIME_DIR.
+// XDG_RUNTIME_DIR is typically configured via pam_systemd.
+// GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
+//
+// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
+func GetRuntimeDir() (string, error) {
+ if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" {
+ return xdgRuntimeDir, nil
+ }
+ return "", errors.New("could not get XDG_RUNTIME_DIR")
+}
+
+// StickRuntimeDirContents sets the sticky bit on files that are under
+// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system.
+//
+// StickyRuntimeDir returns slice of sticked files.
+// StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set.
+//
+// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
+func StickRuntimeDirContents(files []string) ([]string, error) {
+ runtimeDir, err := GetRuntimeDir()
+ if err != nil {
+ // ignore error if runtimeDir is empty
+ return nil, nil
+ }
+ runtimeDir, err = filepath.Abs(runtimeDir)
+ if err != nil {
+ return nil, err
+ }
+ var sticked []string
+ for _, f := range files {
+ f, err = filepath.Abs(f)
+ if err != nil {
+ return sticked, err
+ }
+ if strings.HasPrefix(f, runtimeDir+"/") {
+ if err = stick(f); err != nil {
+ return sticked, err
+ }
+ sticked = append(sticked, f)
+ }
+ }
+ return sticked, nil
+}
+
+func stick(f string) error {
+ st, err := os.Stat(f)
+ if err != nil {
+ return err
+ }
+ m := st.Mode()
+ m |= os.ModeSticky
+ return os.Chmod(f, m)
+}
+
+// GetDataHome returns XDG_DATA_HOME.
+// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set.
+//
+// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
+func GetDataHome() (string, error) {
+ if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
+ return xdgDataHome, nil
+ }
+ home := Get()
+ if home == "" {
+ return "", errors.New("could not get either XDG_DATA_HOME or HOME")
+ }
+ return filepath.Join(home, ".local", "share"), nil
+}
+
+// GetConfigHome returns XDG_CONFIG_HOME.
+// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
+//
+// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
+func GetConfigHome() (string, error) {
+ if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
+ return xdgConfigHome, nil
+ }
+ home := Get()
+ if home == "" {
+ return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
+ }
+ return filepath.Join(home, ".config"), nil
+}
diff --git a/vendor/github.com/containers/storage/userns.go b/vendor/github.com/containers/storage/userns.go
index 5ba8cc418..49ec544a3 100644
--- a/vendor/github.com/containers/storage/userns.go
+++ b/vendor/github.com/containers/storage/userns.go
@@ -221,94 +221,71 @@ outer:
return size, nil
}
+func minInt(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func maxInt(a, b int) int {
+ if a < b {
+ return b
+ }
+ return a
+}
+
// subtractHostIDs return the subtraction of the range USED from AVAIL. The range is specified
// by [HostID, HostID+Size).
// ContainerID is ignored.
func subtractHostIDs(avail idtools.IDMap, used idtools.IDMap) []idtools.IDMap {
- switch {
- case used.HostID <= avail.HostID && used.HostID+used.Size >= avail.HostID+avail.Size:
- return nil
- case used.HostID <= avail.HostID && used.HostID+used.Size > avail.HostID && used.HostID+used.Size < avail.HostID+avail.Size:
- newContainerID := avail.ContainerID + used.Size
- newHostID := used.HostID + used.Size
- r := idtools.IDMap{
- ContainerID: newContainerID,
- HostID: newHostID,
- Size: avail.Size + avail.HostID - newHostID,
- }
- return []idtools.IDMap{r}
- case used.HostID > avail.HostID && used.HostID < avail.HostID+avail.Size && used.HostID+used.Size >= avail.HostID+avail.Size:
- r := idtools.IDMap{
+ var out []idtools.IDMap
+ availEnd := avail.HostID + avail.Size
+ usedEnd := used.HostID + used.Size
+ // Intersection of [avail.HostID, availEnd) and (-inf, used.HostID) is [avail.HostID, newEnd).
+ if newEnd := minInt(availEnd, used.HostID); newEnd > avail.HostID {
+ out = append(out, idtools.IDMap{
ContainerID: avail.ContainerID,
HostID: avail.HostID,
- Size: used.HostID - avail.HostID,
- }
- return []idtools.IDMap{r}
- case used.HostID > avail.HostID && used.HostID < avail.HostID+avail.Size && used.HostID+used.Size < avail.HostID+avail.Size:
- r1 := idtools.IDMap{
- ContainerID: avail.ContainerID,
- HostID: avail.HostID,
- Size: used.HostID - avail.HostID,
- }
- r2 := idtools.IDMap{
- ContainerID: used.ContainerID + used.Size,
- HostID: avail.HostID + (used.HostID - avail.HostID),
- Size: avail.HostID + avail.Size - used.HostID - used.Size,
- }
- return []idtools.IDMap{r1, r2}
- default:
- r := idtools.IDMap{
- ContainerID: 0,
- HostID: avail.HostID,
- Size: avail.Size,
- }
- return []idtools.IDMap{r}
- }
+ Size: newEnd - avail.HostID,
+ })
+ }
+ // Intersection of [avail.HostID, availEnd) and [usedEnd, +inf) is [newStart, availEnd).
+ if newStart := maxInt(avail.HostID, usedEnd); newStart < availEnd {
+ out = append(out, idtools.IDMap{
+ ContainerID: newStart + avail.ContainerID - avail.HostID,
+ HostID: newStart,
+ Size: availEnd - newStart,
+ })
+ }
+ return out
}
// subtractContainerIDs return the subtraction of the range USED from AVAIL. The range is specified
// by [ContainerID, ContainerID+Size).
// HostID is ignored.
func subtractContainerIDs(avail idtools.IDMap, used idtools.IDMap) []idtools.IDMap {
- switch {
- case used.ContainerID <= avail.ContainerID && used.ContainerID+used.Size >= avail.ContainerID+avail.Size:
- return nil
- case used.ContainerID <= avail.ContainerID && used.ContainerID+used.Size > avail.ContainerID && used.ContainerID+used.Size < avail.ContainerID+avail.Size:
- newContainerID := used.ContainerID + used.Size
- newHostID := avail.HostID + used.Size
- r := idtools.IDMap{
- ContainerID: newContainerID,
- HostID: newHostID,
- Size: avail.Size + avail.ContainerID - newContainerID,
- }
- return []idtools.IDMap{r}
- case used.ContainerID > avail.ContainerID && used.ContainerID < avail.ContainerID+avail.Size && used.ContainerID+used.Size >= avail.ContainerID+avail.Size:
- r := idtools.IDMap{
- ContainerID: avail.ContainerID,
- HostID: avail.HostID,
- Size: used.ContainerID - avail.ContainerID,
- }
- return []idtools.IDMap{r}
- case used.ContainerID > avail.ContainerID && used.ContainerID < avail.ContainerID+avail.Size && used.ContainerID+used.Size < avail.ContainerID+avail.Size:
- r1 := idtools.IDMap{
+ var out []idtools.IDMap
+ availEnd := avail.ContainerID + avail.Size
+ usedEnd := used.ContainerID + used.Size
+ // Intersection of [avail.ContainerID, availEnd) and (-inf, used.ContainerID) is
+ // [avail.ContainerID, newEnd).
+ if newEnd := minInt(availEnd, used.ContainerID); newEnd > avail.ContainerID {
+ out = append(out, idtools.IDMap{
ContainerID: avail.ContainerID,
HostID: avail.HostID,
- Size: used.ContainerID - avail.ContainerID,
- }
- r2 := idtools.IDMap{
- ContainerID: used.ContainerID + used.Size,
- HostID: avail.HostID + (used.ContainerID - avail.ContainerID),
- Size: avail.ContainerID + avail.Size - used.ContainerID - used.Size,
- }
- return []idtools.IDMap{r1, r2}
- default:
- r := idtools.IDMap{
- ContainerID: avail.ContainerID,
- HostID: avail.HostID,
- Size: avail.Size,
- }
- return []idtools.IDMap{r}
- }
+ Size: newEnd - avail.ContainerID,
+ })
+ }
+ // Intersection of [avail.ContainerID, availEnd) and [usedEnd, +inf) is [newStart, availEnd).
+ if newStart := maxInt(avail.ContainerID, usedEnd); newStart < availEnd {
+ out = append(out, idtools.IDMap{
+ ContainerID: newStart,
+ HostID: newStart + avail.HostID - avail.ContainerID,
+ Size: availEnd - newStart,
+ })
+ }
+ return out
}
// subtractAll subtracts all usedIDs from the available IDs.
diff --git a/vendor/github.com/containers/storage/utils.go b/vendor/github.com/containers/storage/utils.go
index 762c3a00d..bd6c4feb1 100644
--- a/vendor/github.com/containers/storage/utils.go
+++ b/vendor/github.com/containers/storage/utils.go
@@ -273,7 +273,11 @@ func defaultStoreOptionsIsolated(rootless bool, rootlessUID int, storageConf str
storageOpts.RunRoot = defaultRootlessRunRoot
}
if storageOpts.GraphRoot == "" {
- storageOpts.GraphRoot = defaultRootlessGraphRoot
+ if storageOpts.RootlessStoragePath != "" {
+ storageOpts.GraphRoot = storageOpts.RootlessStoragePath
+ } else {
+ storageOpts.GraphRoot = defaultRootlessGraphRoot
+ }
}
}
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a7b35a318..79db4807e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -166,7 +166,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
-# github.com/containers/storage v1.23.8
+# github.com/containers/storage v1.23.9
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -478,7 +478,7 @@ github.com/prometheus/common/model
# github.com/prometheus/procfs v0.0.3
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
-# github.com/rootless-containers/rootlesskit v0.10.1
+# github.com/rootless-containers/rootlesskit v0.11.0
github.com/rootless-containers/rootlesskit/pkg/msgutil
github.com/rootless-containers/rootlesskit/pkg/port
github.com/rootless-containers/rootlesskit/pkg/port/builtin