summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/system/prune.go18
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--docs/source/markdown/podman-info.1.md151
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/define/info.go11
-rw-r--r--libpod/filters/helpers.go20
-rw-r--r--libpod/info.go17
-rw-r--r--pkg/bindings/test/system_test.go57
-rw-r--r--pkg/domain/entities/system.go6
-rw-r--r--pkg/domain/infra/abi/system.go12
-rw-r--r--pkg/domain/infra/tunnel/system.go2
-rw-r--r--pkg/signal/signal_linux.go1
-rw-r--r--pkg/signal/signal_linux_mipsx.go106
-rw-r--r--pkg/specgen/generate/kube/kube.go20
-rw-r--r--test/apiv2/45-system.at67
-rw-r--r--test/e2e/play_kube_test.go49
-rw-r--r--test/e2e/prune_test.go60
-rw-r--r--vendor/github.com/containers/common/pkg/config/containers.conf2
-rw-r--r--vendor/github.com/containers/common/pkg/config/default.go2
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go10
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/supported.go2
-rw-r--r--vendor/github.com/containers/common/version/version.go2
-rw-r--r--vendor/modules.txt2
24 files changed, 516 insertions, 109 deletions
diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go
index ea47e271f..a74363684 100644
--- a/cmd/podman/system/prune.go
+++ b/cmd/podman/system/prune.go
@@ -4,7 +4,6 @@ import (
"bufio"
"context"
"fmt"
- "net/url"
"os"
"strings"
@@ -12,8 +11,8 @@ import (
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/cmd/podman/validate"
+ lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -55,6 +54,8 @@ func init() {
}
func prune(cmd *cobra.Command, args []string) error {
+ var err error
+
// Prompt for confirmation if --force is not set
if !force {
reader := bufio.NewReader(os.Stdin)
@@ -79,16 +80,11 @@ Are you sure you want to continue? [y/N] `, volumeString)
}
}
- pruneOptions.ContainerPruneOptions = entities.ContainerPruneOptions{}
- for _, f := range filters {
- t := strings.SplitN(f, "=", 2)
- pruneOptions.ContainerPruneOptions.Filters = make(url.Values)
- if len(t) < 2 {
- return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
- }
- pruneOptions.ContainerPruneOptions.Filters.Add(t[0], t[1])
+ pruneOptions.Filters, err = lpfilters.ParseFilterArgumentsIntoFilters(filters)
+ if err != nil {
+ return err
}
- // TODO: support for filters in system prune
+
response, err := registry.ContainerEngine().SystemPrune(context.Background(), pruneOptions)
if err != nil {
return err
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 3be44a3a3..db79ebede 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -90,8 +90,8 @@ Recommends: crun
Recommends: container-selinux
Recommends: slirp4netns
Recommends: fuse-overlayfs
-%endif
Recommends: xz
+%endif
# vendored libraries
# awk '{print "Provides: bundled(golang("$1")) = "$2}' vendor.conf | sort
diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md
index dd01a0f49..4af51d3eb 100644
--- a/docs/source/markdown/podman-info.1.md
+++ b/docs/source/markdown/podman-info.1.md
@@ -31,17 +31,18 @@ Run podman info with plain text response:
$ podman info
host:
arch: amd64
- buildahVersion: 1.15.0
- cgroupVersion: v1
+ buildahVersion: 1.19.0-dev
+ cgroupManager: systemd
+ cgroupVersion: v2
conmon:
- package: conmon-2.0.16-2.fc32.x86_64
+ package: conmon-2.0.22-2.fc33.x86_64
path: /usr/bin/conmon
- version: 'conmon version 2.0.16, commit: 1044176f7dd177c100779d1c63931d6022e419bd'
+ version: 'conmon version 2.0.22, commit: 1be6c73605006a85f7ed60b7f76a51e28eb67e01'
cpus: 8
distribution:
distribution: fedora
- version: "32"
- eventLogger: file
+ version: "33"
+ eventLogger: journald
hostname: localhost.localdomain
idMappings:
gidmap:
@@ -58,33 +59,41 @@ host:
- container_id: 1
host_id: 100000
size: 65536
- kernel: 5.6.11-300.fc32.x86_64
+ kernel: 5.9.11-200.fc33.x86_64
linkmode: dynamic
- memFree: 1401929728
- memTotal: 16416161792
+ memFree: 837505024
+ memTotal: 16416481280
ociRuntime:
- name: runc
- package: containerd.io-1.2.10-3.2.fc31.x86_64
- path: /usr/bin/runc
+ name: crun
+ package: crun-0.16-1.fc33.x86_64
+ path: /usr/bin/crun
version: |-
- runc version 1.0.0-rc8+dev
- commit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
- spec: 1.0.1-dev
+ crun version 0.16
+ commit: eb0145e5ad4d8207e84a327248af76663d4e50dd
+ spec: 1.0.0
+ +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL
os: linux
remoteSocket:
- exists: false
- path: /run/user/1000/podman/podman.sock
- rootless: true
+ exists: true
+ path: /run/user/3267/podman/podman.sock
+ security:
+ apparmorEnabled: false
+ capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
+ rootless: true
+ seccompEnabled: true
+ selinuxEnabled: true
slirp4netns:
executable: /bin/slirp4netns
- package: slirp4netns-1.0.0-1.fc32.x86_64
+ package: slirp4netns-1.1.4-4.dev.giteecccdb.fc33.x86_64
version: |-
- slirp4netns version 1.0.0
- commit: a3be729152a33e692cd28b52f664defbf2e7810a
- libslirp: 4.2.0
- swapFree: 8291610624
- swapTotal: 8296329216
- uptime: 52h 29m 39.78s (Approximately 2.17 days)
+ slirp4netns version 1.1.4+dev
+ commit: eecccdb96f587b11d7764556ffacfeaffe4b6e11
+ libslirp: 4.3.1
+ SLIRP_CONFIG_VERSION_MAX: 3
+ libseccomp: 2.5.0
+ swapFree: 6509203456
+ swapTotal: 12591292416
+ uptime: 264h 14m 32.73s (Approximately 11.00 days)
registries:
search:
- registry.fedoraproject.org
@@ -94,19 +103,19 @@ registries:
store:
configFile: /home/dwalsh/.config/containers/storage.conf
containerStore:
- number: 2
+ number: 3
paused: 0
running: 0
- stopped: 2
+ stopped: 3
graphDriverName: overlay
graphOptions:
overlay.mount_program:
Executable: /home/dwalsh/bin/fuse-overlayfs
Package: Unknown
Version: |-
- fusermount3 version: 3.9.1
+ fusermount3 version: 3.9.3
fuse-overlayfs: version 0.7.2
- FUSE library version 3.9.1
+ FUSE library version 3.9.3
using FUSE kernel interface version 7.31
graphRoot: /home/dwalsh/.local/share/containers/storage
graphStatus:
@@ -115,36 +124,38 @@ store:
Supports d_type: "true"
Using metacopy: "false"
imageStore:
- number: 7
+ number: 77
runRoot: /run/user/3267/containers
volumePath: /home/dwalsh/.local/share/containers/storage/volumes
version:
- Built: 1589899246
- BuiltTime: Tue May 19 10:40:46 2020
- GitCommit: c3678ce3289f4195f3f16802411e795c6a587c9f-dirty
- GoVersion: go1.14.2
+ APIVersion: 3.0.0
+ Built: 1608562922
+ BuiltTime: Mon Dec 21 10:02:02 2020
+ GitCommit: d6925182cdaf94225908a386d02eae8fd3e01123-dirty
+ GoVersion: go1.15.5
OsArch: linux/amd64
- APIVersion: 1
- Version: 2.0.0
+ Version: 3.0.0-dev
+
```
Run podman info with JSON formatted response:
```
{
"host": {
"arch": "amd64",
- "buildahVersion": "1.15.0",
- "cgroupVersion": "v1",
+ "buildahVersion": "1.19.0-dev",
+ "cgroupManager": "systemd",
+ "cgroupVersion": "v2",
"conmon": {
- "package": "conmon-2.0.16-2.fc32.x86_64",
+ "package": "conmon-2.0.22-2.fc33.x86_64",
"path": "/usr/bin/conmon",
- "version": "conmon version 2.0.16, commit: 1044176f7dd177c100779d1c63931d6022e419bd"
+ "version": "conmon version 2.0.22, commit: 1be6c73605006a85f7ed60b7f76a51e28eb67e01"
},
"cpus": 8,
"distribution": {
"distribution": "fedora",
- "version": "32"
+ "version": "33"
},
- "eventLogger": "file",
+ "eventLogger": "journald",
"hostname": "localhost.localdomain",
"idMappings": {
"gidmap": [
@@ -172,45 +183,51 @@ Run podman info with JSON formatted response:
}
]
},
- "kernel": "5.6.11-300.fc32.x86_64",
- "memFree": 1380356096,
- "memTotal": 16416161792,
+ "kernel": "5.9.11-200.fc33.x86_64",
+ "memFree": 894574592,
+ "memTotal": 16416481280,
"ociRuntime": {
- "name": "runc",
- "package": "containerd.io-1.2.10-3.2.fc31.x86_64",
- "path": "/usr/bin/runc",
- "version": "runc version 1.0.0-rc8+dev\ncommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657\nspec: 1.0.1-dev"
+ "name": "crun",
+ "package": "crun-0.16-1.fc33.x86_64",
+ "path": "/usr/bin/crun",
+ "version": "crun version 0.16\ncommit: eb0145e5ad4d8207e84a327248af76663d4e50dd\nspec: 1.0.0\n+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL"
},
"os": "linux",
"remoteSocket": {
- "path": "/run/user/1000/podman/podman.sock",
- "exists": false
+ "path": "/run/user/3267/podman/podman.sock",
+ "exists": true
+ },
+ "security": {
+ "apparmorEnabled": false,
+ "capabilities": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT",
+ "rootless": true,
+ "seccompEnabled": true,
+ "selinuxEnabled": true
},
- "rootless": true,
"slirp4netns": {
"executable": "/bin/slirp4netns",
- "package": "slirp4netns-1.0.0-1.fc32.x86_64",
- "version": "slirp4netns version 1.0.0\ncommit: a3be729152a33e692cd28b52f664defbf2e7810a\nlibslirp: 4.2.0"
+ "package": "slirp4netns-1.1.4-4.dev.giteecccdb.fc33.x86_64",
+ "version": "slirp4netns version 1.1.4+dev\ncommit: eecccdb96f587b11d7764556ffacfeaffe4b6e11\nlibslirp: 4.3.1\nSLIRP_CONFIG_VERSION_MAX: 3\nlibseccomp: 2.5.0"
},
- "swapFree": 8291610624,
- "swapTotal": 8296329216,
- "uptime": "52h 27m 39.38s (Approximately 2.17 days)",
+ "swapFree": 6509203456,
+ "swapTotal": 12591292416,
+ "uptime": "264h 13m 12.39s (Approximately 11.00 days)",
"linkmode": "dynamic"
},
"store": {
"configFile": "/home/dwalsh/.config/containers/storage.conf",
"containerStore": {
- "number": 2,
+ "number": 3,
"paused": 0,
"running": 0,
- "stopped": 2
+ "stopped": 3
},
"graphDriverName": "overlay",
"graphOptions": {
"overlay.mount_program": {
"Executable": "/home/dwalsh/bin/fuse-overlayfs",
"Package": "Unknown",
- "Version": "fusermount3 version: 3.9.1\nfuse-overlayfs: version 0.7.2\nFUSE library version 3.9.1\nusing FUSE kernel interface version 7.31"
+ "Version": "fusermount3 version: 3.9.3\nfuse-overlayfs: version 0.7.2\nFUSE library version 3.9.3\nusing FUSE kernel interface version 7.31"
}
},
"graphRoot": "/home/dwalsh/.local/share/containers/storage",
@@ -221,7 +238,7 @@ Run podman info with JSON formatted response:
"Using metacopy": "false"
},
"imageStore": {
- "number": 7
+ "number": 77
},
"runRoot": "/run/user/3267/containers",
"volumePath": "/home/dwalsh/.local/share/containers/storage/volumes"
@@ -235,12 +252,12 @@ Run podman info with JSON formatted response:
]
},
"version": {
- "APIVersion": 1,
- "Version": "2.0.0",
- "GoVersion": "go1.14.2",
- "GitCommit": "c3678ce3289f4195f3f16802411e795c6a587c9f-dirty",
- "BuiltTime": "Tue May 19 10:40:46 2020",
- "Built": 1589899246,
+ "APIVersion": "3.0.0",
+ "Version": "3.0.0-dev",
+ "GoVersion": "go1.15.5",
+ "GitCommit": "d6925182cdaf94225908a386d02eae8fd3e01123-dirty",
+ "BuiltTime": "Mon Dec 21 10:02:02 2020",
+ "Built": 1608562922,
"OsArch": "linux/amd64"
}
}
diff --git a/go.mod b/go.mod
index bfa335a7b..b61e31681 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@ require (
github.com/containernetworking/cni v0.8.0
github.com/containernetworking/plugins v0.9.0
github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c
- github.com/containers/common v0.31.1
+ github.com/containers/common v0.31.2
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.9.0
github.com/containers/psgo v1.5.1
diff --git a/go.sum b/go.sum
index e2a9c7e2c..4f3394c36 100644
--- a/go.sum
+++ b/go.sum
@@ -96,8 +96,8 @@ github.com/containernetworking/plugins v0.9.0/go.mod h1:dbWv4dI0QrBGuVgj+TuVQ6wJ
github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c h1:DnJiPjBKeoZbzjkUA6YMf/r5ShYpNacK+EcQ/ui1Mxo=
github.com/containers/buildah v1.18.1-0.20201217112226-67470615779c/go.mod h1:hvIoL3urgYPL0zX8XlK05aWP6qfUnBNqTrsedsYw6OY=
github.com/containers/common v0.31.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
-github.com/containers/common v0.31.1 h1:oBINnZpYZ2u90HPMnVCXOhm/TsTaTB7wU/56l05hq44=
-github.com/containers/common v0.31.1/go.mod h1:Fehe82hQfJQvDspnRrV9rcdAWG3IalNHEt0F6QWNBHQ=
+github.com/containers/common v0.31.2 h1:sNYwvLA4B7SpEiAWTUvkItPlCrUa2vcxh0FTKXKoC3Q=
+github.com/containers/common v0.31.2/go.mod h1:Fehe82hQfJQvDspnRrV9rcdAWG3IalNHEt0F6QWNBHQ=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ=
diff --git a/libpod/define/info.go b/libpod/define/info.go
index f0e05801c..00146da48 100644
--- a/libpod/define/info.go
+++ b/libpod/define/info.go
@@ -12,6 +12,15 @@ type Info struct {
}
//HostInfo describes the libpod host
+type SecurityInfo struct {
+ AppArmorEnabled bool `json:"apparmorEnabled"`
+ DefaultCapabilities string `json:"capabilities"`
+ Rootless bool `json:"rootless"`
+ SECCOMPEnabled bool `json:"seccompEnabled"`
+ SELinuxEnabled bool `json:"selinuxEnabled"`
+}
+
+//HostInfo describes the libpod host
type HostInfo struct {
Arch string `json:"arch"`
BuildahVersion string `json:"buildahVersion"`
@@ -29,8 +38,8 @@ type HostInfo struct {
OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
OS string `json:"os"`
RemoteSocket *RemoteSocket `json:"remoteSocket,omitempty"`
- Rootless bool `json:"rootless"`
RuntimeInfo map[string]interface{} `json:"runtimeInfo,omitempty"`
+ Security SecurityInfo `json:"security"`
Slirp4NetNS SlirpInfo `json:"slirp4netns,omitempty"`
SwapFree int64 `json:"swapFree"`
SwapTotal int64 `json:"swapTotal"`
diff --git a/libpod/filters/helpers.go b/libpod/filters/helpers.go
new file mode 100644
index 000000000..859db3a9a
--- /dev/null
+++ b/libpod/filters/helpers.go
@@ -0,0 +1,20 @@
+package lpfilters
+
+import (
+ "net/url"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+func ParseFilterArgumentsIntoFilters(filters []string) (url.Values, error) {
+ parsedFilters := make(url.Values)
+ for _, f := range filters {
+ t := strings.SplitN(f, "=", 2)
+ if len(t) < 2 {
+ return parsedFilters, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ parsedFilters.Add(t[0], t[1])
+ }
+ return parsedFilters, nil
+}
diff --git a/libpod/info.go b/libpod/info.go
index 2f64a107e..1b3550abd 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,6 +13,8 @@ import (
"time"
"github.com/containers/buildah"
+ "github.com/containers/common/pkg/apparmor"
+ "github.com/containers/common/pkg/seccomp"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/linkmode"
"github.com/containers/podman/v2/pkg/cgroups"
@@ -20,6 +22,7 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/system"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -98,10 +101,16 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
MemFree: mi.MemFree,
MemTotal: mi.MemTotal,
OS: runtime.GOOS,
- Rootless: rootless.IsRootless(),
- Slirp4NetNS: define.SlirpInfo{},
- SwapFree: mi.SwapFree,
- SwapTotal: mi.SwapTotal,
+ Security: define.SecurityInfo{
+ AppArmorEnabled: apparmor.IsEnabled(),
+ DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","),
+ Rootless: rootless.IsRootless(),
+ SECCOMPEnabled: seccomp.IsEnabled(),
+ SELinuxEnabled: selinux.GetEnabled(),
+ },
+ Slirp4NetNS: define.SlirpInfo{},
+ SwapFree: mi.SwapFree,
+ SwapTotal: mi.SwapTotal,
}
// CGroups version
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 5cb0f9125..25fda5575 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -158,4 +158,61 @@ var _ = Describe("Podman system", func() {
// Volume should be pruned now as flag set true
Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
})
+
+ It("podman system prune running alpine container volume prune --filter", func() {
+ // Start a pod and leave it running
+ _, err := pods.Start(bt.conn, newpod, nil)
+ Expect(err).To(BeNil())
+
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err = bt.RunTopContainer(&name, bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Start second container and leave in running
+ var name2 = "top2"
+ _, err = bt.RunTopContainer(&name2, bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume with label should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value1",
+ }}, nil)
+ Expect(err).To(BeNil())
+
+ f := make(map[string][]string)
+ f["label"] = []string{"label1=idontmatch"}
+
+ options := new(system.PruneOptions).WithAll(true).WithVolumes(true).WithFilters(f)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
+ Expect(err).To(BeNil())
+ Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
+ // TODO fix system filter handling so all components can handle filters
+ // This check **should** be "Equal(0)" since we are passing label
+ // filters however the Prune function doesn't seem to pass filters
+ // to each component.
+ Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ To(BeNumerically(">", 0))
+ // Alpine image should not be pruned as used by running container
+ Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ ToNot(ContainElement("docker.io/library/alpine:latest"))
+ // Volume shouldn't be pruned because the PruneOptions filters doesn't match
+ Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+
+ // Fix filter and re prune
+ f["label"] = []string{"label1=value1"}
+ options = new(system.PruneOptions).WithAll(true).WithVolumes(true).WithFilters(f)
+ systemPruneResponse, err = system.Prune(bt.conn, options)
+ Expect(err).To(BeNil())
+
+ // Volume should be pruned because the PruneOptions filters now match
+ Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
+ })
})
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index 5266dc4cf..d5118f6a8 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -17,9 +17,9 @@ type ServiceOptions struct {
// SystemPruneOptions provides options to prune system.
type SystemPruneOptions struct {
- All bool
- Volume bool
- ContainerPruneOptions
+ All bool
+ Volume bool
+ Filters map[string][]string `json:"filters" schema:"filters"`
}
// SystemPruneReport provides report after system prune is executed.
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 17faa7fff..5f6c95d4f 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io/ioutil"
+ "net/url"
"os"
"os/exec"
"path/filepath"
@@ -180,7 +181,12 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
found = true
}
systemPruneReport.PodPruneReport = append(systemPruneReport.PodPruneReport, podPruneReport...)
- containerPruneReport, err := ic.ContainerPrune(ctx, options.ContainerPruneOptions)
+
+ // TODO: Figure out cleaner way to handle all of the different PruneOptions
+ containerPruneOptions := entities.ContainerPruneOptions{}
+ containerPruneOptions.Filters = (url.Values)(options.Filters)
+
+ containerPruneReport, err := ic.ContainerPrune(ctx, containerPruneOptions)
if err != nil {
return nil, err
}
@@ -217,7 +223,9 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
}
if options.Volume {
- volumePruneReport, err := ic.pruneVolumesHelper(ctx, nil)
+ volumePruneOptions := entities.VolumePruneOptions{}
+ volumePruneOptions.Filters = (url.Values)(options.Filters)
+ volumePruneReport, err := ic.VolumePrune(ctx, volumePruneOptions)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index 1e4b2e0b4..9013d44c2 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -20,7 +20,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
// SystemPrune prunes unused data from the system.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, opts entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
- options := new(system.PruneOptions).WithAll(opts.All).WithVolumes(opts.Volume).WithFilters(opts.ContainerPruneOptions.Filters)
+ options := new(system.PruneOptions).WithAll(opts.All).WithVolumes(opts.Volume).WithFilters(opts.Filters)
return system.Prune(ic.ClientCxt, options)
}
diff --git a/pkg/signal/signal_linux.go b/pkg/signal/signal_linux.go
index 72ab1b97b..305b9d21f 100644
--- a/pkg/signal/signal_linux.go
+++ b/pkg/signal/signal_linux.go
@@ -1,4 +1,5 @@
// +build linux
+// +build !mips,!mipsle,!mips64,!mips64le
// Signal handling for Linux only.
package signal
diff --git a/pkg/signal/signal_linux_mipsx.go b/pkg/signal/signal_linux_mipsx.go
new file mode 100644
index 000000000..67638e30a
--- /dev/null
+++ b/pkg/signal/signal_linux_mipsx.go
@@ -0,0 +1,106 @@
+// +build linux
+// +build mips mipsle mips64 mips64le
+
+// Special signal handling for mips architecture
+package signal
+
+// Copyright 2013-2018 Docker, Inc.
+
+// NOTE: this package has originally been copied from github.com/docker/docker.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 127
+)
+
+// signalMap is a map of Linux signals.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": unix.SIGABRT,
+ "ALRM": unix.SIGALRM,
+ "BUS": unix.SIGBUS,
+ "CHLD": unix.SIGCHLD,
+ "CLD": unix.SIGCLD,
+ "CONT": unix.SIGCONT,
+ "FPE": unix.SIGFPE,
+ "HUP": unix.SIGHUP,
+ "ILL": unix.SIGILL,
+ "INT": unix.SIGINT,
+ "IO": unix.SIGIO,
+ "IOT": unix.SIGIOT,
+ "KILL": unix.SIGKILL,
+ "PIPE": unix.SIGPIPE,
+ "POLL": unix.SIGPOLL,
+ "PROF": unix.SIGPROF,
+ "PWR": unix.SIGPWR,
+ "QUIT": unix.SIGQUIT,
+ "SEGV": unix.SIGSEGV,
+ "EMT": unix.SIGEMT,
+ "STOP": unix.SIGSTOP,
+ "SYS": unix.SIGSYS,
+ "TERM": unix.SIGTERM,
+ "TRAP": unix.SIGTRAP,
+ "TSTP": unix.SIGTSTP,
+ "TTIN": unix.SIGTTIN,
+ "TTOU": unix.SIGTTOU,
+ "URG": unix.SIGURG,
+ "USR1": unix.SIGUSR1,
+ "USR2": unix.SIGUSR2,
+ "VTALRM": unix.SIGVTALRM,
+ "WINCH": unix.SIGWINCH,
+ "XCPU": unix.SIGXCPU,
+ "XFSZ": unix.SIGXFSZ,
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ handledSigs := make([]os.Signal, 0, len(signalMap))
+ for _, s := range signalMap {
+ handledSigs = append(handledSigs, s)
+ }
+ signal.Notify(sigc, handledSigs...)
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ signal.Stop(sigc)
+ close(sigc)
+}
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 5cc7891ac..c64fe76a6 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -112,11 +112,18 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
return nil, err
}
s.WorkDir = "/"
+ // We will use "Docker field name" internally here to avoid confusion
+ // and reference the "Kubernetes field name" when referencing the YAML
+ // ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
+ entrypoint := []string{}
+ cmd := []string{}
if imageData != nil && imageData.Config != nil {
if imageData.Config.WorkingDir != "" {
s.WorkDir = imageData.Config.WorkingDir
}
- s.Command = imageData.Config.Entrypoint
+ // Pull entrypoint and cmd from image
+ entrypoint = imageData.Config.Entrypoint
+ cmd = imageData.Config.Cmd
s.Labels = imageData.Config.Labels
if len(imageData.Config.StopSignal) > 0 {
stopSignal, err := util.ParseSignal(imageData.Config.StopSignal)
@@ -126,13 +133,18 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
s.StopSignal = &stopSignal
}
}
+ // If only the yaml.Command is specified, set it as the entrypoint and drop the image Cmd
if len(containerYAML.Command) != 0 {
- s.Command = containerYAML.Command
+ entrypoint = containerYAML.Command
+ cmd = []string{}
}
- // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
+ // Only override the cmd field if yaml.Args is specified
+ // Keep the image entrypoint, or the yaml.command if specified
if len(containerYAML.Args) != 0 {
- s.Command = append(s.Command, containerYAML.Args...)
+ cmd = containerYAML.Args
}
+
+ s.Command = append(entrypoint, cmd...)
// FIXME,
// we are currently ignoring imageData.Config.ExposedPorts
if containerYAML.WorkingDir != "" {
diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at
new file mode 100644
index 000000000..7d14fd4b3
--- /dev/null
+++ b/test/apiv2/45-system.at
@@ -0,0 +1,67 @@
+# -*- sh -*-
+#
+# system related tests
+#
+
+## ensure system is clean
+t POST 'libpod/system/prune?volumes=true&all=true' params='' 200
+
+## podman system df
+t GET system/df 200 '{"LayersSize":0,"Images":[],"Containers":[],"Volumes":[],"BuildCache":[],"BuilderSize":0}'
+t GET libpod/system/df 200 '{"Images":[],"Containers":[],"Volumes":[]}'
+
+# Create volume. We expect df to report this volume next invocation of system/df
+t GET libpod/info 200
+volumepath=$(jq -r ".store.volumePath" <<<"$output")
+t POST libpod/volumes/create name=foo1 201 \
+ .Name=foo1 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo1/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels={} \
+ .Options=null
+
+t GET system/df 200 '.Volumes[0].Name=foo1'
+
+t GET libpod/system/df 200 '.Volumes[0].VolumeName=foo1'
+
+# Create two more volumes to test pruneing
+t POST libpod/volumes/create \
+ '"Name":"foo2","Label":{"testlabel1":""},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo2 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo2/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels.testlabel1="" \
+ .Options.o=nodev,noexec
+
+t POST libpod/volumes/create \
+ '"Name":"foo3","Label":{"testlabel1":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
+ .Name=foo3 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo3/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels.testlabel1=testonly \
+ .Options.o=nodev,noexec
+
+t GET system/df 200 '.Volumes | length=3'
+t GET libpod/system/df 200 '.Volumes | length=3'
+
+# Prune volumes
+
+# -G --data-urlencode 'volumes=true&filters={"label":["testlabel1=idontmatch"]}'
+t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=idontmatch%22%5D%7D' params='' 200
+
+# nothing should have been pruned
+t GET system/df 200 '.Volumes | length=3'
+t GET libpod/system/df 200 '.Volumes | length=3'
+
+# -G --data-urlencode 'volumes=true&filters={"label":["testlabel1=testonly"]}'
+# only foo3 should be pruned because of filter
+t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D' params='' 200 .VolumePruneReport[0].Id=foo3
+# only foo2 should be pruned because of filter
+t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1%22%5D%7D' params='' 200 .VolumePruneReport[0].Id=foo2
+# foo1, the last remaining volume should be pruned without any filters applied
+t POST 'libpod/system/prune?volumes=true' params='' 200 .VolumePruneReport[0].Id=foo1
+
+# TODO add other system prune tests for pods / images
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 3a2387559..4fec56105 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -820,8 +820,28 @@ var _ = Describe("Podman play kube", func() {
Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd))
})
+ // If you do not supply command or args for a Container, the defaults defined in the Docker image are used.
+ It("podman play kube test correct args and cmd when not specified", func() {
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil))))
+ err := generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+
+ // this image's ENTRYPOINT is `/entrypoint.sh` and it's COMMAND is `/etc/docker/registry/config.yml`
+ Expect(inspect.OutputToString()).To(ContainSubstring(`[/entrypoint.sh /etc/docker/registry/config.yml]`))
+ })
+
+ // If you supply a command but no args for a Container, only the supplied command is used.
+ // The default EntryPoint and the default Cmd defined in the Docker image are ignored.
It("podman play kube test correct command with only set command in yaml file", func() {
- pod := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"}), withArg(nil))))
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd([]string{"echo", "hello"}), withArg(nil))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -837,8 +857,9 @@ var _ = Describe("Podman play kube", func() {
Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello]`))
})
+ // If you supply only args for a Container, the default Entrypoint defined in the Docker image is run with the args that you supplied.
It("podman play kube test correct command with only set args in yaml file", func() {
- pod := getPod(withCtr(getCtr(withImage(redis), withCmd(nil), withArg([]string{"echo", "hello"}))))
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd(nil), withArg([]string{"echo", "hello"}))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -849,9 +870,27 @@ var _ = Describe("Podman play kube", func() {
inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
- // this image's ENTRYPOINT is called `docker-entrypoint.sh`
- // so result should be `docker-entrypoint.sh + withArg(...)`
- Expect(inspect.OutputToString()).To(ContainSubstring(`[docker-entrypoint.sh echo hello]`))
+ // this image's ENTRYPOINT is `/entrypoint.sh`
+ // so result should be `/entrypoint.sh + withArg(...)`
+ Expect(inspect.OutputToString()).To(ContainSubstring(`[/entrypoint.sh echo hello]`))
+ })
+
+ // If you supply a command and args,
+ // the default Entrypoint and the default Cmd defined in the Docker image are ignored.
+ // Your command is run with your args.
+ It("podman play kube test correct command with both set args and cmd in yaml file", func() {
+ pod := getPod(withCtr(getCtr(withImage(registry), withCmd([]string{"echo"}), withArg([]string{"hello"}))))
+ err := generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello]`))
})
It("podman play kube test correct output", func() {
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index c02ed5a50..3bc1012df 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -349,4 +349,64 @@ var _ = Describe("Podman prune", func() {
// all images are unused, so they all should be deleted!
Expect(len(images.OutputToStringArray())).To(Equal(len(CACHE_IMAGES)))
})
+
+ It("podman system prune --volumes --filter", func() {
+ session := podmanTest.Podman([]string{"volume", "create", "--label", "label1=value1", "myvol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv1", "myvol2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1=slv2", "myvol3"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "create", "--label", "sharedlabel1", "myvol4"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol5:/myvol5", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "-v", "myvol6:/myvol6", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(7))
+
+ session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=label1=value1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(6))
+
+ session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=sharedlabel1=slv1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(5))
+
+ session = podmanTest.Podman([]string{"system", "prune", "--force", "--volumes", "--filter", "label=sharedlabel1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(3))
+
+ podmanTest.Cleanup()
+ })
})
diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf
index 483727da0..0587469b2 100644
--- a/vendor/github.com/containers/common/pkg/config/containers.conf
+++ b/vendor/github.com/containers/common/pkg/config/containers.conf
@@ -380,7 +380,7 @@ default_sysctls = [
# Directory for temporary files. Must be tmpfs (wiped after reboot)
#
-# tmp_dir = "/var/run/libpod"
+# tmp_dir = "/run/libpod"
# Directory for libpod named volumes.
# By default, this will be configured relative to where containers/storage
diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go
index e3a7a8e76..6b7aee987 100644
--- a/vendor/github.com/containers/common/pkg/config/default.go
+++ b/vendor/github.com/containers/common/pkg/config/default.go
@@ -320,7 +320,7 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
func defaultTmpDir() (string, error) {
if !unshare.IsRootless() {
- return "/var/run/libpod", nil
+ return "/run/libpod", nil
}
runtimeDir, err := getRuntimeDir()
diff --git a/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go b/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go
index 84a4c6ed5..8b23ee2c0 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/seccomp_unsupported.go
@@ -1,10 +1,10 @@
-// +build !seccomp
+// +build !linux !seccomp
// SPDX-License-Identifier: Apache-2.0
// Copyright 2013-2018 Docker, Inc.
-package seccomp
+package seccomp
import (
"errors"
@@ -38,3 +38,9 @@ func LoadProfileFromConfig(config *Seccomp, specgen *specs.Spec) (*specs.LinuxSe
func IsEnabled() bool {
return false
}
+
+// IsSupported returns true if the system has been configured to support
+// seccomp.
+func IsSupported() bool {
+ return false
+}
diff --git a/vendor/github.com/containers/common/pkg/seccomp/supported.go b/vendor/github.com/containers/common/pkg/seccomp/supported.go
index 1177ef630..e04324c8a 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/supported.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/supported.go
@@ -1,4 +1,4 @@
-// +build !windows
+// +build linux,seccomp
package seccomp
diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go
index 3d671171f..4366848ea 100644
--- a/vendor/github.com/containers/common/version/version.go
+++ b/vendor/github.com/containers/common/version/version.go
@@ -1,4 +1,4 @@
package version
// Version is the version of the build.
-const Version = "0.31.2-dev"
+const Version = "0.31.2"
diff --git a/vendor/modules.txt b/vendor/modules.txt
index bb5c0023c..ceb9f6750 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -86,7 +86,7 @@ github.com/containers/buildah/pkg/parse
github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/util
-# github.com/containers/common v0.31.1
+# github.com/containers/common v0.31.2
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/apparmor/internal/supported
github.com/containers/common/pkg/auth