summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--OWNERS2
-rw-r--r--cmd/podman/common/specgen.go5
-rw-r--r--cmd/podman/common/volumes.go2
-rw-r--r--cmd/podman/images/build.go10
-rw-r--r--docs/source/markdown/containers-mounts.conf.5.md2
-rw-r--r--docs/source/markdown/podman-build.1.md15
-rw-r--r--docs/source/markdown/podman-create.1.md19
-rw-r--r--docs/source/markdown/podman-run.1.md17
-rw-r--r--docs/tutorials/README.md2
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/container_inspect.go2
-rw-r--r--libpod/container_internal_linux.go2
-rw-r--r--libpod/kube.go2
-rw-r--r--libpod/runtime_volume.go12
-rw-r--r--nix/default.nix2
-rw-r--r--pkg/domain/infra/abi/play.go9
-rw-r--r--pkg/spec/storage.go2
-rw-r--r--pkg/specgen/generate/config_linux.go5
-rw-r--r--pkg/specgen/generate/security.go10
-rw-r--r--pkg/util/mountOpts.go2
-rw-r--r--pkg/util/utils.go23
-rw-r--r--pkg/util/utils_test.go20
-rw-r--r--test/apiv2/30-volumes.at2
-rw-r--r--test/apiv2/rest_api/__init__.py132
-rw-r--r--test/apiv2/rest_api/test_rest_v2_0_0.py82
-rw-r--r--test/apiv2/rest_api/v1_test_rest_v1_0_0.py (renamed from test/apiv2/rest_api/test_rest_v1_0_0.py)52
-rw-r--r--test/e2e/common_test.go8
-rw-r--r--test/e2e/play_kube_test.go2
-rw-r--r--test/e2e/run_test.go33
-rw-r--r--test/e2e/toolbox_test.go15
-rw-r--r--test/e2e/volume_ls_test.go23
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/chown_unix.go12
-rw-r--r--vendor/github.com/containers/storage/drivers/copy/copy_linux.go5
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go27
-rw-r--r--vendor/github.com/containers/storage/go.mod2
-rw-r--r--vendor/github.com/containers/storage/go.sum4
-rw-r--r--vendor/github.com/containers/storage/layers.go1
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go23
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_linux.go13
-rw-r--r--vendor/github.com/containers/storage/pkg/system/chmod.go17
-rw-r--r--vendor/github.com/containers/storage/pkg/system/lchown.go20
-rw-r--r--vendor/github.com/containers/storage/pkg/system/xattrs_linux.go15
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md4
-rw-r--r--vendor/modules.txt4
47 files changed, 496 insertions, 174 deletions
diff --git a/Makefile b/Makefile
index 89bf8707e..5cfed666a 100644
--- a/Makefile
+++ b/Makefile
@@ -357,6 +357,7 @@ remotesystem:
.PHONY: localapiv2
localapiv2:
env PODMAN=./bin/podman ./test/apiv2/test-apiv2
+ env PODMAN=./bin/podman ${PYTHON} -m unittest discover -v ./test/apiv2/rest_api/
.PHONY: remoteapiv2
remoteapiv2:
diff --git a/OWNERS b/OWNERS
index 6d0cb3e25..7cbef7f37 100644
--- a/OWNERS
+++ b/OWNERS
@@ -7,6 +7,7 @@ approvers:
- rhatdan
- TomSweeneyRedHat
- vrothberg
+ - umohnani8
reviewers:
- baude
- edsantiago
@@ -18,3 +19,4 @@ reviewers:
- vrothberg
- ashley-cui
- QiWang19
+ - umohnani8
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index bd3e5fafd..ca1e25be1 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -25,11 +25,8 @@ func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
cpu := &specs.LinuxCPU{}
hasLimits := false
- const cpuPeriod = 100000
-
if c.CPUS > 0 {
- quota := int64(c.CPUS * cpuPeriod)
- period := uint64(cpuPeriod)
+ period, quota := util.CoresToPeriodAndQuota(c.CPUS)
cpu.Period = &period
cpu.Quota = &quota
diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go
index 8ab20ccae..b3c160ddf 100644
--- a/cmd/podman/common/volumes.go
+++ b/cmd/podman/common/volumes.go
@@ -313,7 +313,7 @@ func getBindMount(args []string) (spec.Mount, error) {
}
setExec = true
newMount.Options = append(newMount.Options, kv[0])
- case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z":
+ case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z":
newMount.Options = append(newMount.Options, kv[0])
case "bind-propagation":
if len(kv) == 1 {
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index 0ff482cd9..f48d1cd94 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -240,13 +240,9 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
}
}
- pullPolicy := imagebuildah.PullIfNewer
- if c.Flags().Changed("pull") {
- if flags.Pull {
- pullPolicy = imagebuildah.PullAlways
- } else {
- pullPolicy = imagebuildah.PullNever
- }
+ pullPolicy := imagebuildah.PullIfMissing
+ if c.Flags().Changed("pull") && flags.Pull {
+ pullPolicy = imagebuildah.PullAlways
}
if flags.PullAlways {
pullPolicy = imagebuildah.PullAlways
diff --git a/docs/source/markdown/containers-mounts.conf.5.md b/docs/source/markdown/containers-mounts.conf.5.md
index 130c1c523..74492c831 100644
--- a/docs/source/markdown/containers-mounts.conf.5.md
+++ b/docs/source/markdown/containers-mounts.conf.5.md
@@ -10,7 +10,7 @@ The mounts.conf file specifies volume mount directories that are automatically m
The format of the mounts.conf is the volume format `/SRC:/DEST`, one mount per line. For example, a mounts.conf with the line `/usr/share/secrets:/run/secrets` would cause the contents of the `/usr/share/secrets` directory on the host to be mounted on the `/run/secrets` directory inside the container. Setting mountpoints allows containers to use the files of the host, for instance, to use the host's subscription to some enterprise Linux distribution.
## FILES
-Some distributions may provide a `/usr/share/containers/mounts.conf` file to provide default mounts, but users can create a `/etc/containers/mounts.conf`, to specify their own special volumes to mount in the container.
+Some distributions may provide a `/usr/share/containers/mounts.conf` file to provide default mounts, but users can create a `/etc/containers/mounts.conf`, to specify their own special volumes to mount in the container. When Podman runs in rootless mode, the file `$HOME/.config/containers/mounts.conf` will override the default if it exists.
## HISTORY
Aug 2018, Originally compiled by Valentin Rothberg <vrothberg@suse.com>
diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md
index f1fddb2fc..1e1e1d27e 100644
--- a/docs/source/markdown/podman-build.1.md
+++ b/docs/source/markdown/podman-build.1.md
@@ -384,16 +384,13 @@ not required for Buildah as it supports only Linux.
**--pull**
-When the flag is enabled, attempt to pull the latest image from the registries
-listed in registries.conf if a local image does not exist or the image is newer
-than the one in storage. Raise an error if the image is not in any listed
-registry and is not present locally.
+When the option is specified or set to "true", pull the image from the first registry
+it is found in as listed in registries.conf. Raise an error if not found in the
+registries, even if the image is present locally.
-If the flag is disabled (with *--pull=false*), do not pull the image from the
-registry, unless there is no local image. Raise an error if the image is not
-in any registry and is not present locally.
-
-Defaults to *true*.
+If the option is disabled (with *--pull=false*), or not specified, pull the image
+from the registry only if the image is not present locally. Raise an error if the image
+is not found in the registries.
**--pull-always**
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index f823ac565..e243a5842 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -541,7 +541,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
· ro, readonly: true or false (default).
- · bind-propagation: shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2).
+ · bind-propagation: shared, slave, private, unbindable, rshared, rslave, runbindable, or rprivate(default). See also mount(2).
. bind-nonrecursive: do not setup a recursive bind mount. By default it is recursive.
@@ -962,7 +962,7 @@ The _options_ is a comma delimited list and can be:
* **rw**|**ro**
* **z**|**Z**
-* [**r**]**shared**|[**r**]**slave**|[**r**]**private**
+* [**r**]**shared**|[**r**]**slave**|[**r**]**private**[**r**]**unbindable**
* [**r**]**bind**
* [**no**]**exec**
* [**no**]**dev**
@@ -1048,13 +1048,14 @@ visible on host and vice versa. Making a volume `slave` enables only one
way mount propagation and that is mounts done on host under that volume
will be visible inside container but not the other way around. <sup>[[1]](#Footnote1)</sup>
-To control mount propagation property of volume one can use `:[r]shared`,
-`:[r]slave` or `:[r]private` propagation flag. Propagation property can
-be specified only for bind mounted volumes and not for internal volumes or
-named volumes. For mount propagation to work source mount point (mount point
-where source dir is mounted on) has to have right propagation properties. For
-shared volumes, source mount point has to be shared. And for slave volumes,
-source mount has to be either shared or slave. <sup>[[1]](#Footnote1)</sup>
+To control mount propagation property of a volume one can use the [**r**]**shared**,
+[**r**]**slave**, [**r**]**private** or the [**r**]**unbindable** propagation flag.
+Propagation property can be specified only for bind mounted volumes and not for
+internal volumes or named volumes. For mount propagation to work the source mount
+point (the mount point where source dir is mounted on) has to have the right propagation
+properties. For shared volumes, the source mount point has to be shared. And for
+slave volumes, the source mount point has to be either shared or slave.
+<sup>[[1]](#Footnote1)</sup>
If you want to recursively mount a volume and all of its submounts into a
container, then you can use the `rbind` option. By default the bind option is
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 71f77d307..0166a344a 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -567,7 +567,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
· ro, readonly: true or false (default).
- · bind-propagation: shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2).
+ · bind-propagation: shared, slave, private, unbindable, rshared, rslave, runbindable, or rprivate(default). See also mount(2).
. bind-nonrecursive: do not setup a recursive bind mount. By default it is recursive.
@@ -1015,7 +1015,7 @@ The _options_ is a comma delimited list and can be: <sup>[[1]](#Footnote1)</sup>
* **rw**|**ro**
* **z**|**Z**
-* [**r**]**shared**|[**r**]**slave**|[**r**]**private**
+* [**r**]**shared**|[**r**]**slave**|[**r**]**private**[**r**]**unbindable**
* [**r**]**bind**
* [**no**]**exec**
* [**no**]**dev**
@@ -1099,12 +1099,13 @@ way mount propagation and that is mounts done on host under that volume
will be visible inside container but not the other way around. <sup>[[1]](#Footnote1)</sup>
To control mount propagation property of volume one can use [**r**]**shared**,
-[**r**]**slave** or [**r**]**private** propagation flag. Propagation property can
-be specified only for bind mounted volumes and not for internal volumes or
-named volumes. For mount propagation to work source mount point (mount point
-where source dir is mounted on) has to have right propagation properties. For
-shared volumes, source mount point has to be shared. And for slave volumes,
-source mount has to be either shared or slave. <sup>[[1]](#Footnote1)</sup>
+[**r**]**slave**, [**r**]**private** or [**r**]**unbindable** propagation flag.
+Propagation property can be specified only for bind mounted volumes and not for
+internal volumes or named volumes. For mount propagation to work source mount
+point (mount point where source dir is mounted on) has to have right propagation
+properties. For shared volumes, source mount point has to be shared. And for
+slave volumes, source mount has to be either shared or slave.
+<sup>[[1]](#Footnote1)</sup>
If you want to recursively mount a volume and all of its submounts into a
container, then you can use the **rbind** option. By default the bind option is
diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md
index 7f7b4853d..246d235ee 100644
--- a/docs/tutorials/README.md
+++ b/docs/tutorials/README.md
@@ -12,7 +12,7 @@ Learn how to setup Podman and perform some basic commands with the utility.
The steps required to setup rootless Podman are enumerated.
-**[Setup Mac/Windows](mac_win_client.md)
+**[Setup Mac/Windows](mac_win_client.md)**
Special setup for running the Podman remote client on a Mac or Windows PC and connecting to Podman running on a Linux VM are documented.
diff --git a/go.mod b/go.mod
index 530e6b829..bd9effa19 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.7
+ github.com/containers/storage v1.23.8
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
diff --git a/go.sum b/go.sum
index fc68b6bde..ad40d8f83 100644
--- a/go.sum
+++ b/go.sum
@@ -101,6 +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/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=
@@ -305,6 +307,8 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.11.1 h1:bPb7nMRdOZYDrpPMTA3EInUQrdgoBinqUuSwlGdKDdE=
github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
+github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 162f70326..f78d74ef7 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -270,7 +270,7 @@ func parseMountOptionsForInspect(options []string, mount *define.InspectMount) {
isRW = false
case "rw":
// Do nothing, silently discard
- case "shared", "slave", "private", "rshared", "rslave", "rprivate":
+ case "shared", "slave", "private", "rshared", "rslave", "rprivate", "unbindable", "runbindable":
mountProp = opt
case "z", "Z":
zZ = opt
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index bf74ca954..83d5c20cb 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -344,7 +344,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
Type: "bind",
Source: srcPath,
Destination: dstPath,
- Options: []string{"bind", "private"},
+ Options: []string{"bind", "rprivate"},
}
if c.IsReadOnly() && dstPath != "/dev/shm" {
newMount.Options = append(newMount.Options, "ro", "nosuid", "noexec", "nodev")
diff --git a/libpod/kube.go b/libpod/kube.go
index cd5064c84..067e7827d 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -327,7 +327,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
period := *c.config.Spec.Linux.Resources.CPU.Period
if quota > 0 && period > 0 {
- cpuLimitMilli := int64(1000 * float64(quota) / float64(period))
+ cpuLimitMilli := int64(1000 * util.PeriodAndQuotaToCores(period, quota))
// Kubernetes: precision finer than 1m is not allowed
if cpuLimitMilli >= 1 {
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index e4e6d87e6..055a243c0 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -86,8 +86,8 @@ func (r *Runtime) HasVolume(name string) (bool, error) {
// Volumes retrieves all volumes
// Filters can be provided which will determine which volumes are included in the
-// output. Multiple filters are handled by ANDing their output, so only volumes
-// matching all filters are returned
+// output. If multiple filters are used, a volume will be returned if
+// any of the filters are matched
func (r *Runtime) Volumes(filters ...VolumeFilter) ([]*Volume, error) {
r.lock.RLock()
defer r.lock.RUnlock()
@@ -101,11 +101,15 @@ func (r *Runtime) Volumes(filters ...VolumeFilter) ([]*Volume, error) {
return nil, err
}
+ if len(filters) == 0 {
+ return vols, nil
+ }
+
volsFiltered := make([]*Volume, 0, len(vols))
for _, vol := range vols {
- include := true
+ include := false
for _, filter := range filters {
- include = include && filter(vol)
+ include = include || filter(vol)
}
if include {
diff --git a/nix/default.nix b/nix/default.nix
index cc8786ce0..a1a8c5287 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -44,7 +44,7 @@ let
export CFLAGS='-static'
export LDFLAGS='-s -w -static-libgcc -static'
export EXTRA_LDFLAGS='-s -w -linkmode external -extldflags "-static -lm"'
- export BUILDTAGS='static netgo exclude_graphdriver_btrfs exclude_graphdriver_devicemapper seccomp apparmor selinux'
+ export BUILDTAGS='static netgo osusergo exclude_graphdriver_btrfs exclude_graphdriver_devicemapper seccomp apparmor selinux'
'';
buildPhase = ''
patchShebangs .
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 57de0f3b1..fbba00984 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -36,8 +36,6 @@ const (
kubeDirectoryPermission = 0755
// https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
kubeFilePermission = 0644
- // Kubernetes sets CPUPeriod to 100000us (100ms): https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
- defaultCPUPeriod = 100000
)
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
@@ -515,10 +513,9 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
return nil, errors.Wrap(err, "Failed to set CPU quota")
}
if milliCPU > 0 {
- containerConfig.Resources.CPUPeriod = defaultCPUPeriod
- // CPU quota is a fraction of the period: milliCPU / 1000.0 * period
- // Or, without floating point math:
- containerConfig.Resources.CPUQuota = milliCPU * defaultCPUPeriod / 1000
+ period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000)
+ containerConfig.Resources.CPUPeriod = period
+ containerConfig.Resources.CPUQuota = quota
}
containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory())
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index ebf5ec196..b441daf08 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -445,7 +445,7 @@ func getBindMount(args []string) (spec.Mount, error) {
}
setExec = true
newMount.Options = append(newMount.Options, kv[0])
- case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z":
+ case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z":
newMount.Options = append(newMount.Options, kv[0])
case "bind-propagation":
if len(kv) == 1 {
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index fcb7641d2..2d40dba8f 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -350,3 +350,8 @@ func deviceFromPath(path string) (*spec.LinuxDevice, error) {
Minor: int64(unix.Minor(devNumber)),
}, nil
}
+
+func supportAmbientCapabilities() bool {
+ err := unix.Prctl(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, 0, 0, 0)
+ return err == nil
+}
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index d17cd4a9a..dee140282 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -135,7 +135,9 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec.Process.Capabilities.Bounding = caplist
configSpec.Process.Capabilities.Inheritable = caplist
- if s.User == "" || s.User == "root" || s.User == "0" {
+ user := strings.Split(s.User, ":")[0]
+
+ if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" {
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
} else {
@@ -145,6 +147,12 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
}
configSpec.Process.Capabilities.Effective = userCaps
configSpec.Process.Capabilities.Permitted = userCaps
+
+ // Ambient capabilities were added to Linux 4.3. Set ambient
+ // capabilities only when the kernel supports them.
+ if supportAmbientCapabilities() {
+ configSpec.Process.Capabilities.Ambient = userCaps
+ }
}
g.SetProcessNoNewPrivileges(s.NoNewPrivileges)
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index eab2657e3..580aaf4f2 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -57,7 +57,7 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'rw' and 'ro' can be used")
}
foundWrite = true
- case "private", "rprivate", "slave", "rslave", "shared", "rshared":
+ case "private", "rprivate", "slave", "rslave", "shared", "rshared", "unbindable", "runbindable":
if foundProp {
return nil, errors.Wrapf(ErrDupeMntOption, "only one root propagation mode can be used")
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index a9aad657d..415fd169b 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -653,3 +653,26 @@ func CreateCidFile(cidfile string, id string) error {
cidFile.Close()
return nil
}
+
+// DefaultCPUPeriod is the default CPU period is 100us, which is the same default
+// as Kubernetes.
+const DefaultCPUPeriod uint64 = 100000
+
+// CoresToPeriodAndQuota converts a fraction of cores to the equivalent
+// Completely Fair Scheduler (CFS) parameters period and quota.
+//
+// Cores is a fraction of the CFS period that a container may use. Period and
+// Quota are in microseconds.
+func CoresToPeriodAndQuota(cores float64) (uint64, int64) {
+ return DefaultCPUPeriod, int64(cores * float64(DefaultCPUPeriod))
+}
+
+// PeriodAndQuotaToCores takes the CFS parameters period and quota and returns
+// a fraction that represents the limit to the number of cores that can be
+// utilized over the scheduling period.
+//
+// Cores is a fraction of the CFS period that a container may use. Period and
+// Quota are in microseconds.
+func PeriodAndQuotaToCores(period uint64, quota int64) float64 {
+ return float64(quota) / float64(period)
+}
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index a9b37844e..cb737bd76 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -257,3 +257,23 @@ func TestValidateSysctlBadSysctl(t *testing.T) {
_, err := ValidateSysctls(strSlice)
assert.Error(t, err)
}
+
+func TestCoresToPeriodAndQuota(t *testing.T) {
+ cores := 1.0
+ expectedPeriod := DefaultCPUPeriod
+ expectedQuota := int64(DefaultCPUPeriod)
+
+ actualPeriod, actualQuota := CoresToPeriodAndQuota(cores)
+ assert.Equal(t, actualPeriod, expectedPeriod, "Period does not match")
+ assert.Equal(t, actualQuota, expectedQuota, "Quota does not match")
+}
+
+func TestPeriodAndQuotaToCores(t *testing.T) {
+ var (
+ period uint64 = 100000
+ quota int64 = 50000
+ expectedCores = 0.5
+ )
+
+ assert.Equal(t, PeriodAndQuotaToCores(period, quota), expectedCores)
+}
diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at
index 2c38954b6..aa167a97a 100644
--- a/test/apiv2/30-volumes.at
+++ b/test/apiv2/30-volumes.at
@@ -35,6 +35,8 @@ t GET libpod/volumes/json 200 \
.[0].CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.*
# -G --data-urlencode 'filters={"name":["foo1"]}'
t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22foo1%22%5D%7D 200 length=1 .[0].Name=foo1
+# -G --data-urlencode 'filters={"name":["foo1","foo2"]}'
+t GET libpod/volumes/json?filters=%7B%22name%22%3A%20%5B%22foo1%22%2C%20%22foo2%22%5D%7D 200 length=2 .[0].Name=foo1 .[1].Name=foo2
# -G --data-urlencode 'filters={"name":["notexist"]}'
t GET libpod/volumes/json?filters=%7B%22name%22%3A%5B%22notexists%22%5D%7D 200 length=0
diff --git a/test/apiv2/rest_api/__init__.py b/test/apiv2/rest_api/__init__.py
index e69de29bb..5f0777d58 100644
--- a/test/apiv2/rest_api/__init__.py
+++ b/test/apiv2/rest_api/__init__.py
@@ -0,0 +1,132 @@
+import configparser
+import json
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+class Podman(object):
+ """
+ Instances hold the configuration and setup for running podman commands
+ """
+
+ def __init__(self):
+ """Initialize a Podman instance with global options"""
+ binary = os.getenv("PODMAN", "bin/podman")
+ self.cmd = [binary, "--storage-driver=vfs"]
+
+ cgroupfs = os.getenv("CGROUP_MANAGER", "cgroupfs")
+ self.cmd.append(f"--cgroup-manager={cgroupfs}")
+
+ if os.getenv("DEBUG"):
+ self.cmd.append("--log-level=debug")
+
+ self.anchor_directory = tempfile.mkdtemp(prefix="podman_restapi_")
+ self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
+ self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
+
+ os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
+ self.anchor_directory, "registry.conf"
+ )
+ p = configparser.ConfigParser()
+ p.read_dict(
+ {
+ "registries.search": {"registries": "['docker.io']"},
+ "registries.insecure": {"registries": "[]"},
+ "registries.block": {"registries": "[]"},
+ }
+ )
+ with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
+ p.write(w)
+
+ os.environ["CNI_CONFIG_PATH"] = os.path.join(
+ self.anchor_directory, "cni", "net.d"
+ )
+ os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
+ self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
+ cni_cfg = os.path.join(
+ os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
+ )
+ # json decoded and encoded to ensure legal json
+ buf = json.loads(
+ """
+ {
+ "cniVersion": "0.3.0",
+ "name": "podman",
+ "plugins": [{
+ "type": "bridge",
+ "bridge": "cni0",
+ "isGateway": true,
+ "ipMasq": true,
+ "ipam": {
+ "type": "host-local",
+ "subnet": "10.88.0.0/16",
+ "routes": [{
+ "dst": "0.0.0.0/0"
+ }]
+ }
+ },
+ {
+ "type": "portmap",
+ "capabilities": {
+ "portMappings": true
+ }
+ }
+ ]
+ }
+ """
+ )
+ with open(cni_cfg, "w") as w:
+ json.dump(buf, w)
+
+ def open(self, command, *args, **kwargs):
+ """Podman initialized instance to run a given command
+
+ :param self: Podman instance
+ :param command: podman sub-command to run
+ :param args: arguments and options for command
+ :param kwargs: See subprocess.Popen() for shell keyword
+ :return: subprocess.Popen() instance configured to run podman instance
+ """
+ cmd = self.cmd.copy()
+ cmd.append(command)
+ cmd.extend(args)
+
+ shell = kwargs.get("shell", False)
+
+ return subprocess.Popen(
+ cmd,
+ shell=shell,
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+
+ def run(self, command, *args, **kwargs):
+ """Podman initialized instance to run a given command
+
+ :param self: Podman instance
+ :param command: podman sub-command to run
+ :param args: arguments and options for command
+ :param kwargs: See subprocess.Popen() for shell and check keywords
+ :return: subprocess.Popen() instance configured to run podman instance
+ """
+ cmd = self.cmd.copy()
+ cmd.append(command)
+ cmd.extend(args)
+
+ check = kwargs.get("check", False)
+ shell = kwargs.get("shell", False)
+
+ return subprocess.run(
+ cmd,
+ shell=shell,
+ check=check,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+
+ def tear_down(self):
+ shutil.rmtree(self.anchor_directory, ignore_errors=True)
diff --git a/test/apiv2/rest_api/test_rest_v2_0_0.py b/test/apiv2/rest_api/test_rest_v2_0_0.py
index 3376f8402..5dfd1fc02 100644
--- a/test/apiv2/rest_api/test_rest_v2_0_0.py
+++ b/test/apiv2/rest_api/test_rest_v2_0_0.py
@@ -1,5 +1,4 @@
import json
-import os
import subprocess
import sys
import time
@@ -9,27 +8,25 @@ from multiprocessing import Process
import requests
from dateutil.parser import parse
+from test.apiv2.rest_api import Podman
+
PODMAN_URL = "http://localhost:8080"
def _url(path):
- return PODMAN_URL + "/v1.0.0/libpod" + path
-
-
-def podman():
- binary = os.getenv("PODMAN_BINARY")
- if binary is None:
- binary = "bin/podman"
- return binary
+ return PODMAN_URL + "/v2.0.0/libpod" + path
def ctnr(path):
- r = requests.get(_url("/containers/json?all=true"))
try:
+ r = requests.get(_url("/containers/json?all=true"))
ctnrs = json.loads(r.text)
except Exception as e:
- sys.stderr.write("Bad container response: {}/{}".format(r.text, e))
- raise e
+ msg = f"Bad container response: {e}"
+ if r is not None:
+ msg = msg + " " + r.text
+ sys.stderr.write(msg + "\n")
+ raise
return path.format(ctnrs[0]["Id"])
@@ -44,50 +41,50 @@ def validateObjectFields(buffer):
class TestApi(unittest.TestCase):
- podman = None
+ podman = None # initialized podman configuration for tests
+ service = None # podman service instance
def setUp(self):
super().setUp()
- if TestApi.podman.poll() is not None:
- sys.stderr.write(f"podman service returned {TestApi.podman.returncode}\n")
- sys.exit(2)
- requests.get(
- _url("/images/create?fromSrc=docker.io%2Falpine%3Alatest"))
- # calling out to podman is easier than the API for running a container
- subprocess.run([podman(), "run", "alpine", "/bin/ls"],
- check=True,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
+
+ try:
+ TestApi.podman.run("run", "alpine", "/bin/ls", check=True)
+ except subprocess.CalledProcessError as e:
+ if e.stdout:
+ sys.stdout.write("\nRun Stdout:\n" + e.stdout.decode("utf-8"))
+ if e.stderr:
+ sys.stderr.write("\nRun Stderr:\n" + e.stderr.decode("utf-8"))
+ raise
@classmethod
def setUpClass(cls):
super().setUpClass()
- TestApi.podman = subprocess.Popen(
- [
- podman(), "system", "service", "tcp:localhost:8080",
- "--log-level=debug", "--time=0"
- ],
- shell=False,
- stdin=subprocess.DEVNULL,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
+ TestApi.podman = Podman()
+ TestApi.service = TestApi.podman.open(
+ "system", "service", "tcp:localhost:8080", "--log-level=debug", "--time=0"
)
+ # give the service some time to be ready...
time.sleep(2)
+ returncode = TestApi.service.poll()
+ if returncode is not None:
+ raise subprocess.CalledProcessError(returncode, "podman system service")
+
+ r = requests.post(_url("/images/pull?reference=docker.io%2Falpine%3Alatest"))
+ if r.status_code != 200:
+ raise subprocess.CalledProcessError(
+ r.status_code, f"podman images pull docker.io/alpine:latest {r.text}"
+ )
+
@classmethod
def tearDownClass(cls):
- TestApi.podman.terminate()
- stdout, stderr = TestApi.podman.communicate(timeout=0.5)
+ TestApi.service.terminate()
+ stdout, stderr = TestApi.service.communicate(timeout=0.5)
if stdout:
- print("\nService Stdout:\n" + stdout.decode('utf-8'))
+ sys.stdout.write("\nService Stdout:\n" + stdout.decode("utf-8"))
if stderr:
- print("\nService Stderr:\n" + stderr.decode('utf-8'))
-
- if TestApi.podman.returncode > 0:
- sys.stderr.write(f"podman exited with error code {TestApi.podman.returncode}\n")
- sys.exit(2)
-
+ sys.stderr.write("\nService Stderr:\n" + stderr.decode("utf-8"))
return super().tearDownClass()
def test_info(self):
@@ -160,6 +157,7 @@ class TestApi(unittest.TestCase):
self.assertIsNone(r.text)
def test_attach_containers(self):
+ self.skipTest("FIXME: Test timeouts")
r = requests.post(_url(ctnr("/containers/{}/attach")), timeout=5)
self.assertIn(r.status_code, (101, 500), r.text)
@@ -242,5 +240,5 @@ class TestApi(unittest.TestCase):
self.assertEqual(r.status_code, 200, r.text)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/test/apiv2/rest_api/test_rest_v1_0_0.py b/test/apiv2/rest_api/v1_test_rest_v1_0_0.py
index 2e574e015..acd6273ef 100644
--- a/test/apiv2/rest_api/test_rest_v1_0_0.py
+++ b/test/apiv2/rest_api/v1_test_rest_v1_0_0.py
@@ -43,16 +43,16 @@ class TestApi(unittest.TestCase):
def setUp(self):
super().setUp()
if TestApi.podman.poll() is not None:
- sys.stderr.write("podman service returned {}",
- TestApi.podman.returncode)
+ sys.stderr.write("podman service returned {}", TestApi.podman.returncode)
sys.exit(2)
- requests.get(
- _url("/images/create?fromSrc=docker.io%2Falpine%3Alatest"))
+ requests.get(_url("/images/create?fromSrc=docker.io%2Falpine%3Alatest"))
# calling out to podman is easier than the API for running a container
- subprocess.run([podman(), "run", "alpine", "/bin/ls"],
- check=True,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
+ subprocess.run(
+ [podman(), "run", "alpine", "/bin/ls"],
+ check=True,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
@classmethod
def setUpClass(cls):
@@ -60,8 +60,12 @@ class TestApi(unittest.TestCase):
TestApi.podman = subprocess.Popen(
[
- podman(), "system", "service", "tcp:localhost:8080",
- "--log-level=debug", "--time=0"
+ podman(),
+ "system",
+ "service",
+ "tcp:localhost:8080",
+ "--log-level=debug",
+ "--time=0",
],
shell=False,
stdin=subprocess.DEVNULL,
@@ -75,13 +79,14 @@ class TestApi(unittest.TestCase):
TestApi.podman.terminate()
stdout, stderr = TestApi.podman.communicate(timeout=0.5)
if stdout:
- print("\nService Stdout:\n" + stdout.decode('utf-8'))
+ print("\nService Stdout:\n" + stdout.decode("utf-8"))
if stderr:
- print("\nService Stderr:\n" + stderr.decode('utf-8'))
+ print("\nService Stderr:\n" + stderr.decode("utf-8"))
if TestApi.podman.returncode > 0:
- sys.stderr.write("podman exited with error code {}\n".format(
- TestApi.podman.returncode))
+ sys.stderr.write(
+ "podman exited with error code {}\n".format(TestApi.podman.returncode)
+ )
sys.exit(2)
return super().tearDownClass()
@@ -222,13 +227,14 @@ class TestApi(unittest.TestCase):
def validateObjectFields(self, buffer):
- objs = json.loads(buffer)
- if not isinstance(objs, dict):
- for o in objs:
- _ = o["Id"]
- else:
- _ = objs["Id"]
- return objs
-
-if __name__ == '__main__':
+ objs = json.loads(buffer)
+ if not isinstance(objs, dict):
+ for o in objs:
+ _ = o["Id"]
+ else:
+ _ = objs["Id"]
+ return objs
+
+
+if __name__ == "__main__":
unittest.main()
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 3814d161d..678b2c882 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -613,12 +613,10 @@ func SkipIfRootlessCgroupsV1(reason string) {
}
}
-func SkipIfUnprevilegedCPULimits() {
+func SkipIfUnprivilegedCPULimits() {
info := GetHostDistributionInfo()
- if isRootless() &&
- info.Distribution == "fedora" &&
- (info.Version == "31" || info.Version == "32") {
- ginkgo.Skip("Rootless Fedora doesn't have permission to set CPU limits before version 33")
+ if isRootless() && info.Distribution == "fedora" {
+ ginkgo.Skip("Rootless Fedora doesn't have permission to set CPU limits")
}
}
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 6dcfa9bd8..1d683e987 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -1406,7 +1406,7 @@ spec:
It("podman play kube allows setting resource limits", func() {
SkipIfContainerized("Resource limits require a running systemd")
SkipIfRootlessCgroupsV1("Limits require root or cgroups v2")
- SkipIfUnprevilegedCPULimits()
+ SkipIfUnprivilegedCPULimits()
podmanTest.CgroupManager = "systemd"
var (
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index e6bba9f67..deb4419af 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -315,6 +315,39 @@ var _ = Describe("Podman run", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
+
+ session = podmanTest.Podman([]string{"run", "--user=1000:1000", "--cap-add=DAC_OVERRIDE", "--rm", ALPINE, "grep", "CapAmb", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("0000000000000002"))
+
+ session = podmanTest.Podman([]string{"run", "--user=1000:1000", "--rm", ALPINE, "grep", "CapAmb", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("0000000000000000"))
+
+ session = podmanTest.Podman([]string{"run", "--user=0", "--cap-add=DAC_OVERRIDE", "--rm", ALPINE, "grep", "CapAmb", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("0000000000000000"))
+
+ session = podmanTest.Podman([]string{"run", "--user=0:0", "--cap-add=DAC_OVERRIDE", "--rm", ALPINE, "grep", "CapAmb", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("0000000000000000"))
+
+ if os.Geteuid() > 0 {
+ if os.Getenv("SKIP_USERNS") != "" {
+ Skip("Skip userns tests.")
+ }
+ if _, err := os.Stat("/proc/self/uid_map"); err != nil {
+ Skip("User namespaces not supported.")
+ }
+ session = podmanTest.Podman([]string{"run", "--userns=keep-id", "--cap-add=DAC_OVERRIDE", "--rm", ALPINE, "grep", "CapAmb", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("0000000000000002"))
+ }
})
It("podman run user capabilities test with image", func() {
diff --git a/test/e2e/toolbox_test.go b/test/e2e/toolbox_test.go
index fbff8d19e..822159fc2 100644
--- a/test/e2e/toolbox_test.go
+++ b/test/e2e/toolbox_test.go
@@ -30,10 +30,12 @@ import (
"os"
"os/exec"
"os/user"
+ "path"
"strconv"
"strings"
"syscall"
+ "github.com/containers/podman/v2/pkg/rootless"
. "github.com/containers/podman/v2/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -371,10 +373,23 @@ var _ = Describe("Toolbox-specific testing", func() {
currentUser, err := user.Current()
Expect(err).To(BeNil())
+
session = podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:%s", currentUser.HomeDir, currentUser.HomeDir), "--userns=keep-id", fedoraToolbox, "sh", "-c", "echo $HOME"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(currentUser.HomeDir))
+
+ if rootless.IsRootless() {
+ location := path.Dir(currentUser.HomeDir)
+ volumeArg := fmt.Sprintf("%s:%s", location, location)
+ session = podmanTest.Podman([]string{"run",
+ "--userns=keep-id",
+ "--volume", volumeArg,
+ fedoraToolbox, "sh", "-c", "echo $HOME"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring(currentUser.HomeDir))
+ }
})
})
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index 1cb6440aa..cda118bf1 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -110,4 +110,27 @@ var _ = Describe("Podman volume ls", func() {
Expect(lsDangling.ExitCode()).To(Equal(0))
Expect(lsDangling.OutputToString()).To(ContainSubstring(volName1))
})
+ It("podman ls volume with multiple --filter flag", func() {
+ session := podmanTest.Podman([]string{"volume", "create", "--label", "foo=bar", "myvol"})
+ volName := session.OutputToString()
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "foo2=bar2", "anothervol"})
+ anotherVol := session.OutputToString()
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls", "--filter", "label=foo", "--filter", "label=foo2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(3))
+ Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName))
+ Expect(session.OutputToStringArray()[2]).To(ContainSubstring(anotherVol))
+
+ })
})
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 2d27ccba1..82bfa5ce3 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.23.7
+1.23.8
diff --git a/vendor/github.com/containers/storage/drivers/chown_unix.go b/vendor/github.com/containers/storage/drivers/chown_unix.go
index 1cadb089f..7c2a73f6b 100644
--- a/vendor/github.com/containers/storage/drivers/chown_unix.go
+++ b/vendor/github.com/containers/storage/drivers/chown_unix.go
@@ -50,22 +50,22 @@ func platformLChown(path string, info os.FileInfo, toHost, toContainer *idtools.
if uid != int(st.Uid) || gid != int(st.Gid) {
cap, err := system.Lgetxattr(path, "security.capability")
if err != nil && err != system.ErrNotSupportedPlatform {
- return fmt.Errorf("%s: Lgetxattr(%q): %v", os.Args[0], path, err)
+ return fmt.Errorf("%s: %v", os.Args[0], err)
}
// Make the change.
- if err := os.Lchown(path, uid, gid); err != nil {
- return fmt.Errorf("%s: chown(%q): %v", os.Args[0], path, err)
+ if err := system.Lchown(path, uid, gid); err != nil {
+ return fmt.Errorf("%s: %v", os.Args[0], err)
}
// Restore the SUID and SGID bits if they were originally set.
if (info.Mode()&os.ModeSymlink == 0) && info.Mode()&(os.ModeSetuid|os.ModeSetgid) != 0 {
- if err := os.Chmod(path, info.Mode()); err != nil {
- return fmt.Errorf("%s: chmod(%q): %v", os.Args[0], path, err)
+ if err := system.Chmod(path, info.Mode()); err != nil {
+ return fmt.Errorf("%s: %v", os.Args[0], err)
}
}
if cap != nil {
if err := system.Lsetxattr(path, "security.capability", cap, 0); err != nil {
- return fmt.Errorf("%s: Lsetxattr(%q): %v", os.Args[0], path, err)
+ return fmt.Errorf("%s: %v", os.Args[0], err)
}
}
diff --git a/vendor/github.com/containers/storage/drivers/copy/copy_linux.go b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go
index 1e380a5ac..5147b01d6 100644
--- a/vendor/github.com/containers/storage/drivers/copy/copy_linux.go
+++ b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go
@@ -12,6 +12,7 @@ package copy
import "C"
import (
"container/list"
+ "errors"
"fmt"
"io"
"os"
@@ -98,7 +99,7 @@ func legacyCopy(srcFile io.Reader, dstFile io.Writer) error {
func copyXattr(srcPath, dstPath, attr string) error {
data, err := system.Lgetxattr(srcPath, attr)
- if err != nil && err != unix.EOPNOTSUPP {
+ if err != nil && !errors.Is(err, unix.EOPNOTSUPP) {
return err
}
if data != nil {
@@ -269,7 +270,7 @@ func doCopyXattrs(srcPath, dstPath string) error {
}
xattrs, err := system.Llistxattr(srcPath)
- if err != nil && err != unix.EOPNOTSUPP {
+ if err != nil && !errors.Is(err, unix.EOPNOTSUPP) {
return err
}
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 398fe6531..a7cfeadc7 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -42,6 +42,8 @@ var (
untar = chrootarchive.UntarUncompressed
)
+const defaultPerms = os.FileMode(0555)
+
// This backend uses the overlay union filesystem for containers
// with diff directories for each layer.
@@ -571,15 +573,17 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if err := idtools.MkdirAllAs(path.Dir(dir), 0700, rootUID, rootGID); err != nil {
return err
}
+ perms := defaultPerms
if parent != "" {
st, err := system.Stat(d.dir(parent))
if err != nil {
return err
}
+ perms = os.FileMode(st.Mode())
rootUID = int(st.UID())
rootGID = int(st.GID())
}
- if err := idtools.MkdirAs(dir, 0700, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAs(dir, perms, rootUID, rootGID); err != nil {
return err
}
@@ -604,7 +608,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
}
}
- if err := idtools.MkdirAs(path.Join(dir, "diff"), 0755, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAs(path.Join(dir, "diff"), perms, rootUID, rootGID); err != nil {
return err
}
@@ -847,7 +851,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
return "", err
}
diffN := 1
- _, err = os.Stat(filepath.Join(dir, nameWithSuffix("diff", diffN)))
+ perms := defaultPerms
+ st, err := os.Stat(filepath.Join(dir, nameWithSuffix("diff", diffN)))
+ if err == nil {
+ perms = os.FileMode(st.Mode())
+ }
for err == nil {
absLowers = append(absLowers, filepath.Join(dir, nameWithSuffix("diff", diffN)))
relLowers = append(relLowers, dumbJoin(string(link), "..", nameWithSuffix("diff", diffN)))
@@ -908,7 +916,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
return "", err
}
diffDir := path.Join(dir, "diff")
- if err := idtools.MkdirAllAs(diffDir, 0755, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAllAs(diffDir, perms, rootUID, rootGID); err != nil {
return "", err
}
@@ -1241,11 +1249,16 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp
// Rotate the diff directories.
i := 0
- _, err = os.Stat(nameWithSuffix(diffDir, i))
+ perms := defaultPerms
+ st, err := os.Stat(nameWithSuffix(diffDir, i))
+ if err == nil {
+ perms = os.FileMode(st.Mode())
+ }
for err == nil {
i++
_, err = os.Stat(nameWithSuffix(diffDir, i))
}
+
for i > 0 {
err = os.Rename(nameWithSuffix(diffDir, i-1), nameWithSuffix(diffDir, i))
if err != nil {
@@ -1258,13 +1271,13 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp
// to the old upper layer in the index.
workDir := filepath.Join(dir, "work")
if err := os.RemoveAll(workDir); err == nil {
- if err := idtools.MkdirAs(workDir, 0755, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAs(workDir, defaultPerms, rootUID, rootGID); err != nil {
return err
}
}
// Re-create the directory that we're going to use as the upper layer.
- if err := idtools.MkdirAs(diffDir, 0755, rootUID, rootGID); err != nil {
+ if err := idtools.MkdirAs(diffDir, perms, rootUID, rootGID); err != nil {
return err
}
return nil
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index f38266a16..9d5a2b425 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -8,7 +8,7 @@ require (
github.com/Microsoft/hcsshim v0.8.9
github.com/docker/go-units v0.4.0
github.com/hashicorp/go-multierror v1.1.0
- github.com/klauspost/compress v1.11.1
+ github.com/klauspost/compress v1.11.2
github.com/klauspost/pgzip v1.2.5
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index 2aad798d8..681f77cbc 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -62,8 +62,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.11.1 h1:bPb7nMRdOZYDrpPMTA3EInUQrdgoBinqUuSwlGdKDdE=
-github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
+github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index a70806f40..72f00b8d6 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -1329,6 +1329,7 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
if err != nil {
return -1, err
}
+ defer uncompressed.Close()
uncompressedDigest := digest.Canonical.Digester()
uncompressedCounter := ioutils.NewWriteCounter(uncompressedDigest.Hash())
uidLog := make(map[uint32]struct{})
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index 4472511a2..345da2903 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -139,6 +139,7 @@ func IsArchivePath(path string) bool {
if err != nil {
return false
}
+ defer rdr.Close()
r := tar.NewReader(rdr)
_, err = r.Next()
return err == nil
@@ -398,7 +399,7 @@ func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
}
for _, xattr := range []string{"security.capability", "security.ima"} {
capability, err := system.Lgetxattr(path, xattr)
- if err != nil && err != system.EOPNOTSUPP && err != system.ErrNotSupportedPlatform {
+ if err != nil && !errors.Is(err, system.EOPNOTSUPP) && err != system.ErrNotSupportedPlatform {
return errors.Wrapf(err, "failed to read %q attribute from %q", xattr, path)
}
if capability != nil {
@@ -411,17 +412,17 @@ func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
// ReadUserXattrToTarHeader reads user.* xattr from filesystem to a tar header
func ReadUserXattrToTarHeader(path string, hdr *tar.Header) error {
xattrs, err := system.Llistxattr(path)
- if err != nil && err != system.EOPNOTSUPP && err != system.ErrNotSupportedPlatform {
+ if err != nil && !errors.Is(err, system.EOPNOTSUPP) && err != system.ErrNotSupportedPlatform {
return err
}
for _, key := range xattrs {
if strings.HasPrefix(key, "user.") {
value, err := system.Lgetxattr(path, key)
- if err == system.E2BIG {
- logrus.Errorf("archive: Skipping xattr for file %s since value is too big: %s", path, key)
- continue
- }
if err != nil {
+ if errors.Is(err, system.E2BIG) {
+ logrus.Errorf("archive: Skipping xattr for file %s since value is too big: %s", path, key)
+ continue
+ }
return err
}
if hdr.Xattrs == nil {
@@ -724,16 +725,16 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
}
}
- var errors []string
+ var errs []string
for key, value := range hdr.Xattrs {
if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil {
- if err == syscall.ENOTSUP || (err == syscall.EPERM && inUserns) {
+ if errors.Is(err, syscall.ENOTSUP) || (inUserns && errors.Is(err, syscall.EPERM)) {
// We ignore errors here because not all graphdrivers support
// xattrs *cough* old versions of AUFS *cough*. However only
// ENOTSUP should be emitted in that case, otherwise we still
// bail. We also ignore EPERM errors if we are running in a
// user namespace.
- errors = append(errors, err.Error())
+ errs = append(errs, err.Error())
continue
}
return err
@@ -741,9 +742,9 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
}
- if len(errors) > 0 {
+ if len(errs) > 0 {
logrus.WithFields(logrus.Fields{
- "errors": errors,
+ "errors": errs,
}).Warn("ignored xattrs in archive: underlying filesystem doesn't support them")
}
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
index ecfa45d73..da86e0c05 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
@@ -2,6 +2,7 @@ package archive
import (
"bytes"
+ "errors"
"fmt"
"os"
"path/filepath"
@@ -86,21 +87,21 @@ func walkchunk(path string, fi os.FileInfo, dir string, root *FileInfo) error {
}
info.stat = stat
info.capability, err = system.Lgetxattr(cpath, "security.capability") // lgetxattr(2): fs access
- if err != nil && err != system.EOPNOTSUPP {
+ if err != nil && !errors.Is(err, system.EOPNOTSUPP) {
return err
}
xattrs, err := system.Llistxattr(cpath)
- if err != nil && err != system.EOPNOTSUPP {
+ if err != nil && !errors.Is(err, system.EOPNOTSUPP) {
return err
}
for _, key := range xattrs {
if strings.HasPrefix(key, "user.") {
value, err := system.Lgetxattr(cpath, key)
- if err == system.E2BIG {
- logrus.Errorf("archive: Skipping xattr for file %s since value is too big: %s", cpath, key)
- continue
- }
if err != nil {
+ if errors.Is(err, system.E2BIG) {
+ logrus.Errorf("archive: Skipping xattr for file %s since value is too big: %s", cpath, key)
+ continue
+ }
return err
}
if info.xattrs == nil {
diff --git a/vendor/github.com/containers/storage/pkg/system/chmod.go b/vendor/github.com/containers/storage/pkg/system/chmod.go
new file mode 100644
index 000000000..a01d8abfb
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/system/chmod.go
@@ -0,0 +1,17 @@
+package system
+
+import (
+ "errors"
+ "os"
+ "syscall"
+)
+
+func Chmod(name string, mode os.FileMode) error {
+ err := os.Chmod(name, mode)
+
+ for err != nil && errors.Is(err, syscall.EINTR) {
+ err = os.Chmod(name, mode)
+ }
+
+ return err
+}
diff --git a/vendor/github.com/containers/storage/pkg/system/lchown.go b/vendor/github.com/containers/storage/pkg/system/lchown.go
new file mode 100644
index 000000000..eb2d8b464
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/system/lchown.go
@@ -0,0 +1,20 @@
+package system
+
+import (
+ "os"
+ "syscall"
+)
+
+func Lchown(name string, uid, gid int) error {
+ err := syscall.Lchown(name, uid, gid)
+
+ for err == syscall.EINTR {
+ err = syscall.Lchown(name, uid, gid)
+ }
+
+ if err != nil {
+ return &os.PathError{Op: "lchown", Path: name, Err: err}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/containers/storage/pkg/system/xattrs_linux.go b/vendor/github.com/containers/storage/pkg/system/xattrs_linux.go
index e94bb5d5c..10355848b 100644
--- a/vendor/github.com/containers/storage/pkg/system/xattrs_linux.go
+++ b/vendor/github.com/containers/storage/pkg/system/xattrs_linux.go
@@ -2,6 +2,7 @@ package system
import (
"bytes"
+ "os"
"golang.org/x/sys/unix"
)
@@ -26,7 +27,7 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = unix.Lgetxattr(path, attr, []byte{})
if errno != nil {
- return nil, errno
+ return nil, &os.PathError{Op: "lgetxattr", Path: path, Err: errno}
}
dest = make([]byte, sz)
sz, errno = unix.Lgetxattr(path, attr, dest)
@@ -36,7 +37,7 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
case errno == unix.ENODATA:
return nil, nil
case errno != nil:
- return nil, errno
+ return nil, &os.PathError{Op: "lgetxattr", Path: path, Err: errno}
}
return dest[:sz], nil
@@ -45,7 +46,11 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
// Lsetxattr sets the value of the extended attribute identified by attr
// and associated with the given path in the file system.
func Lsetxattr(path string, attr string, data []byte, flags int) error {
- return unix.Lsetxattr(path, attr, data, flags)
+ if err := unix.Lsetxattr(path, attr, data, flags); err != nil {
+ return &os.PathError{Op: "lsetxattr", Path: path, Err: err}
+ }
+
+ return nil
}
// Llistxattr lists extended attributes associated with the given path
@@ -58,14 +63,14 @@ func Llistxattr(path string) ([]string, error) {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = unix.Llistxattr(path, []byte{})
if errno != nil {
- return nil, errno
+ return nil, &os.PathError{Op: "llistxattr", Path: path, Err: errno}
}
dest = make([]byte, sz)
sz, errno = unix.Llistxattr(path, dest)
}
if errno != nil {
- return nil, errno
+ return nil, &os.PathError{Op: "llistxattr", Path: path, Err: errno}
}
var attrs []string
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index ea3e51082..07f7285f0 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -251,14 +251,14 @@ For streaming use a simple setup could look like this:
import "github.com/klauspost/compress/zstd"
func Decompress(in io.Reader, out io.Writer) error {
- d, err := zstd.NewReader(input)
+ d, err := zstd.NewReader(in)
if err != nil {
return err
}
defer d.Close()
// Copy content...
- _, err := io.Copy(out, d)
+ _, err = io.Copy(out, d)
return err
}
```
diff --git a/vendor/modules.txt b/vendor/modules.txt
index d0b50aceb..a7b35a318 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.7
+# github.com/containers/storage v1.23.8
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -334,7 +334,7 @@ github.com/inconshreveable/mousetrap
github.com/ishidawataru/sctp
# github.com/json-iterator/go v1.1.10
github.com/json-iterator/go
-# github.com/klauspost/compress v1.11.1
+# github.com/klauspost/compress v1.11.2
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0