summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xAPI.md2
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/images.go10
-rw-r--r--cmd/podman/main_local.go2
-rw-r--r--cmd/podman/pod_rm.go2
-rw-r--r--cmd/podman/pods_prune.go4
-rw-r--r--cmd/podman/system_prune.go1
-rw-r--r--cmd/podman/varlink/io.podman.varlink3
-rw-r--r--completions/bash/podman1
-rw-r--r--docs/source/markdown/podman-images.1.md4
-rw-r--r--docs/source/markdown/podman-pod-prune.1.md11
-rw-r--r--docs/source/markdown/podman-pod-rm.1.md4
-rw-r--r--docs/source/markdown/podman-pod.1.md4
-rw-r--r--docs/source/markdown/podman.1.md39
-rw-r--r--docs/source/pod.rst4
-rw-r--r--go.mod2
-rw-r--r--go.sum2
-rw-r--r--libpod/image/image.go15
-rw-r--r--libpod/networking_linux.go34
-rw-r--r--libpod/options.go8
-rw-r--r--pkg/adapter/pods.go4
-rw-r--r--pkg/adapter/runtime_remote.go67
-rw-r--r--pkg/varlinkapi/images.go2
-rw-r--r--pkg/varlinkapi/pods.go2
-rw-r--r--test/e2e/pod_prune_test.go23
-rw-r--r--test/e2e/pod_rm_test.go8
-rw-r--r--test/e2e/run_networking_test.go14
-rw-r--r--test/system/010-images.bats15
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/copy/copy_linux.go16
-rw-r--r--vendor/github.com/containers/storage/drivers/vfs/copy_linux.go2
-rw-r--r--vendor/github.com/containers/storage/images.go11
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go108
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go29
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes.go5
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/changes_linux.go22
-rw-r--r--vendor/github.com/containers/storage/pkg/system/xattrs_linux.go41
-rw-r--r--vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go12
-rw-r--r--vendor/github.com/containers/storage/utils.go12
-rw-r--r--vendor/modules.txt2
40 files changed, 462 insertions, 88 deletions
diff --git a/API.md b/API.md
index c288e6b28..a02a8cf6f 100755
--- a/API.md
+++ b/API.md
@@ -1698,6 +1698,8 @@ isParent [bool](https://godoc.org/builtin#bool)
topLayer [string](https://godoc.org/builtin#string)
readOnly [bool](https://godoc.org/builtin#bool)
+
+history [[]string](#[]string)
### <a name="ImageHistory"></a>type ImageHistory
ImageHistory describes the returned structure from ImageHistory.
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 27d94f769..a34afa827 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -64,6 +64,7 @@ type ImagesValues struct {
NoTrunc bool
Quiet bool
Sort string
+ History bool
}
type EventValues struct {
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 7d498517c..6b16272f4 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -32,6 +32,7 @@ type imagesTemplateParams struct {
CreatedTime time.Time
Size string
ReadOnly bool
+ History string
}
type imagesJSONParams struct {
@@ -42,6 +43,7 @@ type imagesJSONParams struct {
Created time.Time `json:"created"`
Size *uint64 `json:"size"`
ReadOnly bool `json:"readonly"`
+ History []string `json:"history"`
}
type imagesOptions struct {
@@ -53,6 +55,7 @@ type imagesOptions struct {
outputformat string
sort string
all bool
+ history bool
}
// Type declaration and functions for sorting the images output
@@ -124,6 +127,7 @@ func imagesInit(command *cliconfig.ImagesValues) {
flags.BoolVar(&command.NoTrunc, "no-trunc", false, "Do not truncate output")
flags.BoolVarP(&command.Quiet, "quiet", "q", false, "Display only image IDs")
flags.StringVar(&command.Sort, "sort", "created", "Sort by created, id, repository, size, or tag")
+ flags.BoolVarP(&command.History, "history", "", false, "Display the image name history")
}
@@ -171,6 +175,7 @@ func imagesCmd(c *cliconfig.ImagesValues) error {
format: c.Format,
sort: c.Sort,
all: c.All,
+ history: c.History,
}
opts.outputformat = opts.setOutputFormat()
@@ -214,6 +219,9 @@ func (i imagesOptions) setOutputFormat() string {
format += "{{.Digest}}\t"
}
format += "{{.ID}}\t{{.Created}}\t{{.Size}}\t"
+ if i.history {
+ format += "{{if .History}}{{.History}}{{else}}<none>{{end}}\t"
+ }
return format
}
@@ -306,6 +314,7 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma
Created: units.HumanDuration(time.Since(createdTime)) + " ago",
Size: sizeStr,
ReadOnly: img.IsReadOnly(),
+ History: strings.Join(img.NamesHistory(), ", "),
}
imagesOutput = append(imagesOutput, params)
if opts.quiet { // Show only one image ID when quiet
@@ -336,6 +345,7 @@ func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage)
Created: img.Created(),
Size: size,
ReadOnly: img.IsReadOnly(),
+ History: img.NamesHistory(),
}
imagesOutput = append(imagesOutput, params)
}
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index 0484e3cf0..968d7331a 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -69,7 +69,7 @@ func init() {
rootCmd.PersistentFlags().StringArrayVar(&MainGlobalOpts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console")
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Trace, "trace", false, "Enable opentracing output")
}
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index fcf1d5bc7..02daf8764 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -12,7 +12,7 @@ import (
var (
podRmCommand cliconfig.PodRmValues
- podRmDescription = fmt.Sprintf(`podman rm will remove one or more pods from the host.
+ podRmDescription = fmt.Sprintf(`podman rm will remove one or more stopped pods and their containers from the host.
The pod name or ID can be used. A pod with containers will not be removed without --force. If --force is specified, all containers will be stopped, then removed.`)
_podRmCommand = &cobra.Command{
diff --git a/cmd/podman/pods_prune.go b/cmd/podman/pods_prune.go
index d40e37bdb..1c5c0bb58 100644
--- a/cmd/podman/pods_prune.go
+++ b/cmd/podman/pods_prune.go
@@ -17,7 +17,7 @@ var (
_prunePodsCommand = &cobra.Command{
Use: "prune",
Args: noSubArgs,
- Short: "Remove all stopped pods",
+ Short: "Remove all stopped pods and their containers",
Long: podPruneDescription,
RunE: func(cmd *cobra.Command, args []string) error {
podPruneCommand.InputArgs = args
@@ -32,7 +32,7 @@ func init() {
podPruneCommand.SetHelpTemplate(HelpTemplate())
podPruneCommand.SetUsageTemplate(UsageTemplate())
flags := podPruneCommand.Flags()
- flags.BoolVarP(&podPruneCommand.Force, "force", "f", false, "Force removal of a running pods. The default is false")
+ flags.BoolVarP(&podPruneCommand.Force, "force", "f", false, "Force removal of all running pods. The default is false")
}
func podPruneCmd(c *cliconfig.PodPruneValues) error {
diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go
index c4d76b2dd..ae5d7ed2d 100644
--- a/cmd/podman/system_prune.go
+++ b/cmd/podman/system_prune.go
@@ -82,7 +82,6 @@ Are you sure you want to continue? [y/N] `, volumeString)
fmt.Println("Deleted Pods")
pruneValues := cliconfig.PodPruneValues{
PodmanCommand: c.PodmanCommand,
- Force: c.Force,
}
ctx := getContext()
ok, failures, lasterr := runtime.PrunePods(ctx, &pruneValues)
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 4f810dd53..e76b9627e 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -70,7 +70,8 @@ type Image (
labels: [string]string,
isParent: bool,
topLayer: string,
- readOnly: bool
+ readOnly: bool,
+ history: []string
)
# ImageHistory describes the returned structure from ImageHistory.
diff --git a/completions/bash/podman b/completions/bash/podman
index 7b64c2a80..6d145030f 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1563,6 +1563,7 @@ _podman_images() {
--filter
-h
--help
+ --history
--no-trunc
--notruncate
-n
diff --git a/docs/source/markdown/podman-images.1.md b/docs/source/markdown/podman-images.1.md
index 3ac07fc43..21fca1dbd 100644
--- a/docs/source/markdown/podman-images.1.md
+++ b/docs/source/markdown/podman-images.1.md
@@ -52,6 +52,10 @@ Filter output based on conditions provided
Change the default output format. This can be of a supported type like 'json'
or a Go template.
+**--history**
+
+Display the history of image names. If an image gets re-tagged or untagged, then the image name history gets prepended (latest image first). This is especially useful when undoing a tag operation or an image does not contain any name because it has been untagged.
+
**--noheading**, **-n**
Omit the table headings from the listing of images.
diff --git a/docs/source/markdown/podman-pod-prune.1.md b/docs/source/markdown/podman-pod-prune.1.md
index f79961b2f..478f563c3 100644
--- a/docs/source/markdown/podman-pod-prune.1.md
+++ b/docs/source/markdown/podman-pod-prune.1.md
@@ -1,16 +1,21 @@
% podman-pod-prune(1)
## NAME
-podman-pod-prune - Remove all stopped pods
+podman-pod-prune - Remove all stopped pods and their containers
## SYNOPSIS
**podman pod prune**
## DESCRIPTION
-**podman pod prune** removes all stopped pods from local storage.
+**podman pod prune** removes all stopped pods and their containers from local storage.
+
+## OPTIONS
+
+**--force** **-f**
+Force removal of all running pods and their containers. The default is false.
## EXAMPLES
-Remove all stopped pods from local storage
+Remove all stopped pods and their containers from local storage
```
$ sudo podman pod prune
22b8813332948064b6566370088c5e0230eeaf15a58b1c5646859fd9fc364fe7
diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md
index aee582dc6..14da2071f 100644
--- a/docs/source/markdown/podman-pod-rm.1.md
+++ b/docs/source/markdown/podman-pod-rm.1.md
@@ -1,13 +1,13 @@
% podman-pod-rm(1)
## NAME
-podman\-pod\-rm - Remove one or more pods
+podman\-pod\-rm - Remove one or more stopped pods and containers
## SYNOPSIS
**podman pod rm** [*options*] *pod*
## DESCRIPTION
-**podman pod rm** will remove one or more pods from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. Without the \-f option, a pod cannot be removed if it has associated containers.
+**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod.
## OPTIONS
diff --git a/docs/source/markdown/podman-pod.1.md b/docs/source/markdown/podman-pod.1.md
index b3d002a06..e5a8207e9 100644
--- a/docs/source/markdown/podman-pod.1.md
+++ b/docs/source/markdown/podman-pod.1.md
@@ -18,10 +18,10 @@ podman pod is a set of subcommands that manage pods, or groups of containers.
| inspect | [podman-pod-inspect(1)](podman-pod-inspect.1.md) | Displays information describing a pod. |
| kill | [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in one or more pods. |
| pause | [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. |
-| prune | [podman-pod-prune(1)](podman-pod-prune.1.md) | Remove all stopped pods. |
+| prune | [podman-pod-prune(1)](podman-pod-prune.1.md) | Remove all stopped pods and their containers. |
| ps | [podman-pod-ps(1)](podman-pod-ps.1.md) | Prints out information about pods. |
| restart | [podman-pod-restart(1)](podman-pod-restart.1.md) | Restart one or more pods. |
-| rm | [podman-pod-rm(1)](podman-pod-rm.1.md) | Remove one or more pods. |
+| rm | [podman-pod-rm(1)](podman-pod-rm.1.md) | Remove one or more stopped pods and containers. |
| start | [podman-pod-start(1)](podman-pod-start.1.md) | Start one or more pods. |
| stats | [podman-pod-stats(1)](podman-pod-stats.1.md) | Display a live stream of resource usage stats for containers in one or more pods. |
| stop | [podman-pod-stop(1)](podman-pod-stop.1.md) | Stop one or more pods. |
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index f6fa1a457..c62f54fbb 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -21,10 +21,6 @@ created by the other.
## GLOBAL OPTIONS
-**--help**, **-h**
-
-Print usage statement
-
**--cgroup-manager**=*manager*
CGroup manager to use for container cgroups. Supported values are cgroupfs or systemd. Default is systemd unless overridden in the libpod.conf file.
@@ -32,6 +28,17 @@ CGroup manager to use for container cgroups. Supported values are cgroupfs or sy
Note: Setting this flag can cause certain commands to break when called on containers previously created by the other CGroup manager type.
Note: CGroup manager is not supported in rootless mode when using CGroups Version V1.
+**--cni-config-dir**
+Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d`)
+
+**--config**
+Path of a libpod config file detailing container server configuration options
+
+Default libpod config file is /usr/share/containers/libpod.conf. Override file is in /etc/containers/libpod.conf. In rootless mode the config file will be read from $HOME/.config/containers/libpod.conf.
+
+**--conmon**
+Path of the conmon binary (Default path is configured in `libpod.conf`)
+
**--cpu-profile**=*path*
Path to where the cpu performance results should be written
@@ -40,6 +47,10 @@ Path to where the cpu performance results should be written
Backend to use for storing events. Allowed values are **file**, **journald**, and **none**.
+**--help**, **-h**
+
+Print usage statement
+
**--hooks-dir**=*path*
Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated.
@@ -58,30 +69,30 @@ Podman and libpod currently support an additional `precreate` state which is cal
**--log-level**=*level*
-Log messages above specified level: debug, info, warn, error (default), fatal or panic
+Log messages above specified level: debug, info, warn, error (default), fatal or panic (default: "error")
**--namespace**=*namespace*
Set libpod namespace. Namespaces are used to separate groups of containers and pods in libpod's state.
When namespace is set, created containers and pods will join the given namespace, and only containers and pods in the given namespace will be visible to Podman.
+**--network-cmd-path**=*path*
+Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable.
+
**--root=***value*
Storage root dir in which data, including images, is stored (default: "/var/lib/containers/storage" for UID 0, "$HOME/.local/share/containers/storage" for other users).
-Default root dir is configured in /etc/containers/storage.conf.
+Default root dir is configured in `/etc/containers/storage.conf`.
**--runroot**=*value*
Storage state directory where all state information is stored (default: "/var/run/containers/storage" for UID 0, "/var/run/user/$UID/run" for other users).
-Default state dir is configured in /etc/containers/storage.conf.
+Default state dir is configured in `/etc/containers/storage.conf`.
**--runtime**=*value*
Name of the OCI runtime as specified in libpod.conf or absolute path to the OCI compatible binary used to run containers.
-**--network-cmd-path**=*path*
-Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable.
-
**--storage-driver**=*value*
Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for non-root users when *fuse-overlayfs* is not available. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all.
@@ -95,10 +106,16 @@ Storage driver option, Default storage driver options are configured in /etc/con
**--syslog**
-output logging information to syslog as well as the console
+Output logging information to syslog as well as the console.
On remote clients, logging is directed to the file ~/.config/containers/podman.log
+**--tmpdir**
+
+Path to the tmp directory, for libpod runtime content.
+
+NOTE --tmpdir is not used for the temporary storage of downloaded images. Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`.
+
**--version**, **-v**
Print the version
diff --git a/docs/source/pod.rst b/docs/source/pod.rst
index 391686ce5..2df377762 100644
--- a/docs/source/pod.rst
+++ b/docs/source/pod.rst
@@ -11,13 +11,13 @@ Pod
:doc:`pause <markdown/podman-pause.1>` Pause one or more pods
-:doc:`prune <markdown/podman-pod-prune.1>` Remove all stopped pods
+:doc:`prune <markdown/podman-pod-prune.1>` Remove all stopped pods and their containers
:doc:`ps <markdown/podman-pod-ps.1>` List pods
:doc:`restart <markdown/podman-pod-restart.1>` Restart one or more pods
-:doc:`rm <markdown/podman-pod-rm.1>` Remove one or more pods
+:doc:`rm <markdown/podman-pod-rm.1>` Remove one or more stopped pods and containers
:doc:`start <markdown/podman-pod-start.1>` Start one or more pods
diff --git a/go.mod b/go.mod
index 5760f910b..83eebaa9c 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,7 @@ require (
github.com/containers/conmon v2.0.2+incompatible // indirect
github.com/containers/image/v5 v5.0.0
github.com/containers/psgo v1.3.2
- github.com/containers/storage v1.14.0
+ github.com/containers/storage v1.15.0
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b
diff --git a/go.sum b/go.sum
index 23091d495..142a23c29 100644
--- a/go.sum
+++ b/go.sum
@@ -90,6 +90,8 @@ github.com/containers/storage v1.13.5 h1:/SUzGeOP2HDijpF7Yur21Ch6WTZC1BNeZF917CW
github.com/containers/storage v1.13.5/go.mod h1:HELz8Sn+UVbPaUZMI8RvIG9doD4y4z6Gtg4k7xdd2ZY=
github.com/containers/storage v1.14.0 h1:LbX6WZaDmkXt4DT4xWIg3YXAWd6oA4K9Fi6/KG1xt84=
github.com/containers/storage v1.14.0/go.mod h1:qGPsti/qC1xxX+xcpHfiTMT+8ThVE2Jf83wFHHqkDAY=
+github.com/containers/storage v1.15.0 h1:QNW7jJ94ccGcAbFIOSMHUAsUxvHceb71ecLye9EDrkk=
+github.com/containers/storage v1.15.0/go.mod h1:qGPsti/qC1xxX+xcpHfiTMT+8ThVE2Jf83wFHHqkDAY=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-iptables v0.4.2 h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
diff --git a/libpod/image/image.go b/libpod/image/image.go
index fa75be44d..129ccd376 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -335,6 +335,21 @@ func (i *Image) Names() []string {
return i.image.Names
}
+// NamesHistory returns a string array of names previously associated with the
+// image, which may be a mixture of tags and digests
+func (i *Image) NamesHistory() []string {
+ if len(i.image.Names) > 0 && len(i.image.NamesHistory) > 0 &&
+ // We compare the latest (time-referenced) tags for equality and skip
+ // it in the history if they match to not display them twice. We have
+ // to compare like this, because `i.image.Names` (latest last) gets
+ // appended on retag, whereas `i.image.NamesHistory` gets prepended
+ // (latest first)
+ i.image.Names[len(i.image.Names)-1] == i.image.NamesHistory[0] {
+ return i.image.NamesHistory[1:]
+ }
+ return i.image.NamesHistory
+}
+
// RepoTags returns a string array of repotags associated with the image
func (i *Image) RepoTags() ([]string, error) {
var repoTags []string
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index cba7b636a..a68338dbb 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -29,19 +29,40 @@ import (
// Get an OCICNI network config
func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP, staticMAC net.HardwareAddr) ocicni.PodNetwork {
- defaultNetwork := r.netPlugin.GetDefaultNetworkName()
+ var networkKey string
+ if len(networks) > 0 {
+ // This is inconsistent for >1 network, but it's probably the
+ // best we can do.
+ networkKey = networks[0]
+ } else {
+ networkKey = r.netPlugin.GetDefaultNetworkName()
+ }
network := ocicni.PodNetwork{
Name: name,
Namespace: name, // TODO is there something else we should put here? We don't know about Kube namespaces
ID: id,
NetNS: nsPath,
RuntimeConfig: map[string]ocicni.RuntimeConfig{
- defaultNetwork: {PortMappings: ports},
+ networkKey: {PortMappings: ports},
},
}
+ // If we have extra networks, add them
+ if len(networks) > 0 {
+ network.Networks = make([]ocicni.NetAttachment, len(networks))
+ for i, netName := range networks {
+ network.Networks[i].Name = netName
+ }
+ }
+
if staticIP != nil || staticMAC != nil {
- network.Networks = []ocicni.NetAttachment{{Name: defaultNetwork}}
+ // For static IP or MAC, we need to populate networks even if
+ // it's just the default.
+ if len(networks) == 0 {
+ // If len(networks) == 0 this is guaranteed to be the
+ // default network.
+ network.Networks = []ocicni.NetAttachment{{Name: networkKey}}
+ }
var rt ocicni.RuntimeConfig = ocicni.RuntimeConfig{PortMappings: ports}
if staticIP != nil {
rt.IP = staticIP.String()
@@ -50,12 +71,7 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
rt.MAC = staticMAC.String()
}
network.RuntimeConfig = map[string]ocicni.RuntimeConfig{
- defaultNetwork: rt,
- }
- } else {
- network.Networks = make([]ocicni.NetAttachment, len(networks))
- for i, netName := range networks {
- network.Networks[i].Name = netName
+ networkKey: rt,
}
}
diff --git a/libpod/options.go b/libpod/options.go
index bfbbb9e2d..f7f14eb26 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1041,8 +1041,8 @@ func WithStaticIP(ip net.IP) CtrCreateOption {
return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if the container is not creating a network namespace")
}
- if len(ctr.config.Networks) != 0 {
- return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining additional CNI networks")
+ if len(ctr.config.Networks) > 1 {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining more than 1 CNI network")
}
ctr.config.StaticIP = ip
@@ -1066,8 +1066,8 @@ func WithStaticMAC(mac net.HardwareAddr) CtrCreateOption {
return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if the container is not creating a network namespace")
}
- if len(ctr.config.Networks) != 0 {
- return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining additional CNI networks")
+ if len(ctr.config.Networks) > 1 {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining more than 1 CNI network")
}
ctr.config.StaticMAC = mac
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index e9f3d41a9..a726153c0 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -77,7 +77,7 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal
pool.Add(shared.Job{
ID: p.ID(),
Fn: func() error {
- err := r.Runtime.RemovePod(ctx, p, cli.Force, cli.Force)
+ err := r.Runtime.RemovePod(ctx, p, true, cli.Force)
if err != nil {
logrus.Debugf("Failed to remove pod %s: %s", p.ID(), err.Error())
}
@@ -101,7 +101,7 @@ func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValue
}
for _, p := range pods {
- if err := r.Runtime.RemovePod(ctx, p, cli.Force, cli.Force); err != nil {
+ if err := r.Runtime.RemovePod(ctx, p, true, cli.Force); err != nil {
errs = append(errs, err)
} else {
podids = append(podids, p.ID())
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index ddd4b5271..f9232897c 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -136,21 +136,22 @@ type ContainerImage struct {
}
type remoteImage struct {
- ID string
- Labels map[string]string
- RepoTags []string
- RepoDigests []string
- Parent string
- Size int64
- Created time.Time
- InputName string
- Names []string
- Digest digest.Digest
- Digests []digest.Digest
- isParent bool
- Runtime *LocalRuntime
- TopLayer string
- ReadOnly bool
+ ID string
+ Labels map[string]string
+ RepoTags []string
+ RepoDigests []string
+ Parent string
+ Size int64
+ Created time.Time
+ InputName string
+ Names []string
+ Digest digest.Digest
+ Digests []digest.Digest
+ isParent bool
+ Runtime *LocalRuntime
+ TopLayer string
+ ReadOnly bool
+ NamesHistory []string
}
// Container ...
@@ -232,21 +233,22 @@ func imageInListToContainerImage(i iopodman.Image, name string, runtime *LocalRu
digests = append(digests, digest.Digest(d))
}
ri := remoteImage{
- InputName: name,
- ID: i.Id,
- Digest: digest.Digest(i.Digest),
- Digests: digests,
- Labels: i.Labels,
- RepoTags: i.RepoTags,
- RepoDigests: i.RepoTags,
- Parent: i.ParentId,
- Size: i.Size,
- Created: created,
- Names: i.RepoTags,
- isParent: i.IsParent,
- Runtime: runtime,
- TopLayer: i.TopLayer,
- ReadOnly: i.ReadOnly,
+ InputName: name,
+ ID: i.Id,
+ Digest: digest.Digest(i.Digest),
+ Digests: digests,
+ Labels: i.Labels,
+ RepoTags: i.RepoTags,
+ RepoDigests: i.RepoTags,
+ Parent: i.ParentId,
+ Size: i.Size,
+ Created: created,
+ Names: i.RepoTags,
+ isParent: i.IsParent,
+ Runtime: runtime,
+ TopLayer: i.TopLayer,
+ ReadOnly: i.ReadOnly,
+ NamesHistory: i.History,
}
return &ContainerImage{ri}, nil
}
@@ -337,6 +339,11 @@ func (ci *ContainerImage) Names() []string {
return ci.remoteImage.Names
}
+// NamesHistory returns a string array of names previously associated with the image
+func (ci *ContainerImage) NamesHistory() []string {
+ return ci.remoteImage.NamesHistory
+}
+
// Created returns the time the image was created
func (ci *ContainerImage) Created() time.Time {
return ci.remoteImage.Created
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index c27088805..7abffa42a 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -70,6 +70,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
Labels: labels,
IsParent: isParent,
ReadOnly: image.IsReadOnly(),
+ History: image.NamesHistory(),
}
imageList = append(imageList, i)
}
@@ -111,6 +112,7 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error {
Labels: labels,
TopLayer: newImage.TopLayer(),
ReadOnly: newImage.IsReadOnly(),
+ History: newImage.NamesHistory(),
}
return call.ReplyGetImage(il)
}
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
index 9b659f66b..1ebe5d424 100644
--- a/pkg/varlinkapi/pods.go
+++ b/pkg/varlinkapi/pods.go
@@ -247,7 +247,7 @@ func (i *LibpodAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool
if err != nil {
return call.ReplyPodNotFound(name, err.Error())
}
- if err = i.Runtime.RemovePod(ctx, pod, force, force); err != nil {
+ if err = i.Runtime.RemovePod(ctx, pod, true, force); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
diff --git a/test/e2e/pod_prune_test.go b/test/e2e/pod_prune_test.go
index da0d425cb..389d3cb27 100644
--- a/test/e2e/pod_prune_test.go
+++ b/test/e2e/pod_prune_test.go
@@ -41,7 +41,24 @@ var _ = Describe("Podman pod prune", func() {
Expect(result.ExitCode()).To(Equal(0))
})
- It("podman pod prune doesn't remove a pod with a container", func() {
+ It("podman pod prune doesn't remove a pod with a running container", func() {
+ _, ec, podid := podmanTest.CreatePod("")
+ Expect(ec).To(Equal(0))
+
+ ec2 := podmanTest.RunTopContainerInPod("", podid)
+ ec2.WaitWithDefaultTimeout()
+ Expect(ec2.ExitCode()).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"pod", "prune"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To((Equal(0)))
+
+ result = podmanTest.Podman([]string{"ps", "-qa"})
+ result.WaitWithDefaultTimeout()
+ Expect(len(result.OutputToStringArray())).To(Equal(1))
+ })
+
+ It("podman pod prune removes a pod with a stopped container", func() {
_, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
@@ -50,11 +67,11 @@ var _ = Describe("Podman pod prune", func() {
result := podmanTest.Podman([]string{"pod", "prune"})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(125))
+ Expect(result.ExitCode()).To(Equal(0))
result = podmanTest.Podman([]string{"ps", "-qa"})
result.WaitWithDefaultTimeout()
- Expect(len(result.OutputToStringArray())).To(Equal(1))
+ Expect(len(result.OutputToStringArray())).To(Equal(0))
})
It("podman pod prune -f does remove a running container", func() {
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index c0277ca0d..90f178be6 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -77,7 +77,7 @@ var _ = Describe("Podman pod rm", func() {
Expect(result.OutputToString()).To(Not(ContainSubstring(podid2)))
})
- It("podman pod rm doesn't remove a pod with a container", func() {
+ It("podman pod rm removes a pod with a container", func() {
_, ec, podid := podmanTest.CreatePod("")
Expect(ec).To(Equal(0))
@@ -86,11 +86,11 @@ var _ = Describe("Podman pod rm", func() {
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
- Expect(result.ExitCode()).To(Equal(125))
+ Expect(result.ExitCode()).To(Equal(0))
result = podmanTest.Podman([]string{"ps", "-qa"})
result.WaitWithDefaultTimeout()
- Expect(len(result.OutputToStringArray())).To(Equal(1))
+ Expect(len(result.OutputToStringArray())).To(Equal(0))
})
It("podman pod rm -f does remove a running container", func() {
@@ -136,7 +136,7 @@ var _ = Describe("Podman pod rm", func() {
result := podmanTest.Podman([]string{"pod", "rm", "-a"})
result.WaitWithDefaultTimeout()
Expect(result).To(ExitWithError())
- foundExpectedError, _ := result.ErrorGrepString("contains containers and cannot be removed")
+ foundExpectedError, _ := result.ErrorGrepString("cannot be removed")
Expect(foundExpectedError).To(Equal(true))
num_pods = podmanTest.NumberOfPods()
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index ec12f709a..5e587b198 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -232,4 +232,18 @@ var _ = Describe("Podman run networking", func() {
Expect(session).To(ExitWithError())
Expect(session.ErrorToString()).To(ContainSubstring("stat /run/netns/xxy: no such file or directory"))
})
+
+ It("podman run in custom CNI network with --static-ip", func() {
+ SkipIfRootless()
+ netName := "podmantestnetwork"
+ ipAddr := "10.20.30.128"
+ create := podmanTest.Podman([]string{"network", "create", "--subnet", "10.20.30.0/24", netName})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(BeZero())
+
+ run := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "--net", netName, "--ip", ipAddr, ALPINE, "ip", "addr"})
+ run.WaitWithDefaultTimeout()
+ Expect(run.ExitCode()).To(BeZero())
+ Expect(run.OutputToString()).To(ContainSubstring(ipAddr))
+ })
})
diff --git a/test/system/010-images.bats b/test/system/010-images.bats
index 380623078..543876509 100644
--- a/test/system/010-images.bats
+++ b/test/system/010-images.bats
@@ -44,4 +44,19 @@ size | [0-9]\\\+
}
+@test "podman images - history output" {
+ run_podman images --format json
+ actual=$(echo $output | jq -r '.[0].history | length')
+ is "$actual" "0"
+
+ run_podman tag $PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG test-image
+ run_podman images --format json
+ actual=$(echo $output | jq -r '.[1].history | length')
+ is "$actual" "0"
+ actual=$(echo $output | jq -r '.[0].history | length')
+ is "$actual" "1"
+ actual=$(echo $output | jq -r '.[0].history[0]')
+ is "$actual" "$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG"
+}
+
# vim: filetype=sh
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 850e74240..141f2e805 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.14.0
+1.15.0
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 e52545d5b..c00b9e47d 100644
--- a/vendor/github.com/containers/storage/drivers/copy/copy_linux.go
+++ b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go
@@ -16,6 +16,7 @@ import (
"io"
"os"
"path/filepath"
+ "strings"
"syscall"
"time"
@@ -97,7 +98,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 {
+ if err != nil && err != unix.EOPNOTSUPP {
return err
}
if data != nil {
@@ -271,6 +272,19 @@ func doCopyXattrs(srcPath, dstPath string) error {
return err
}
+ xattrs, err := system.Llistxattr(srcPath)
+ if err != nil && err != unix.EOPNOTSUPP {
+ return err
+ }
+
+ for _, key := range xattrs {
+ if strings.HasPrefix(key, "user.") {
+ if err := copyXattr(srcPath, dstPath, key); err != nil {
+ return err
+ }
+ }
+ }
+
// We need to copy this attribute if it appears in an overlay upper layer, as
// this function is used to copy those. It is set by overlay if a directory
// is removed and then re-created and should not inherit anything from the
diff --git a/vendor/github.com/containers/storage/drivers/vfs/copy_linux.go b/vendor/github.com/containers/storage/drivers/vfs/copy_linux.go
index 8137fcf67..bf22a5f6f 100644
--- a/vendor/github.com/containers/storage/drivers/vfs/copy_linux.go
+++ b/vendor/github.com/containers/storage/drivers/vfs/copy_linux.go
@@ -3,5 +3,5 @@ package vfs
import "github.com/containers/storage/drivers/copy"
func dirCopy(srcDir, dstDir string) error {
- return copy.DirCopy(srcDir, dstDir, copy.Content, false)
+ return copy.DirCopy(srcDir, dstDir, copy.Content, true)
}
diff --git a/vendor/github.com/containers/storage/images.go b/vendor/github.com/containers/storage/images.go
index 5d6a2e48d..6373ebb41 100644
--- a/vendor/github.com/containers/storage/images.go
+++ b/vendor/github.com/containers/storage/images.go
@@ -47,6 +47,11 @@ type Image struct {
// or canonical references.
Names []string `json:"names,omitempty"`
+ // NamesHistory is an optional set of Names the image had in the past. The
+ // contained names are free from any duplicates, whereas the newest entry
+ // is the first one.
+ NamesHistory []string `json:"names-history,omitempty"`
+
// TopLayer is the ID of the topmost layer of the image itself, if the
// image contains one or more layers. Multiple images can refer to the
// same top layer.
@@ -155,6 +160,7 @@ func copyImage(i *Image) *Image {
Digest: i.Digest,
Digests: copyDigestSlice(i.Digests),
Names: copyStringSlice(i.Names),
+ NamesHistory: copyStringSlice(i.NamesHistory),
TopLayer: i.TopLayer,
MappedTopLayers: copyStringSlice(i.MappedTopLayers),
Metadata: i.Metadata,
@@ -481,6 +487,10 @@ func (r *imageStore) removeName(image *Image, name string) {
image.Names = stringSliceWithoutValue(image.Names, name)
}
+func (i *Image) addNameToHistory(name string) {
+ i.NamesHistory = dedupeNames(append([]string{name}, i.NamesHistory...))
+}
+
func (r *imageStore) SetNames(id string, names []string) error {
if !r.IsReadWrite() {
return errors.Wrapf(ErrStoreIsReadOnly, "not allowed to change image name assignments at %q", r.imagespath())
@@ -495,6 +505,7 @@ func (r *imageStore) SetNames(id string, names []string) error {
r.removeName(otherImage, name)
}
r.byname[name] = image
+ image.addNameToHistory(name)
}
image.Names = names
return r.Save()
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index 539acfe93..0dde97c18 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -59,6 +59,22 @@ func (j *Image) MarshalJSONBuf(buf fflib.EncodingBuffer) error {
}
buf.WriteByte(',')
}
+ if len(j.NamesHistory) != 0 {
+ buf.WriteString(`"names-history":`)
+ if j.NamesHistory != nil {
+ buf.WriteString(`[`)
+ for i, v := range j.NamesHistory {
+ if i != 0 {
+ buf.WriteString(`,`)
+ }
+ fflib.WriteJsonString(buf, string(v))
+ }
+ buf.WriteString(`]`)
+ } else {
+ buf.WriteString(`null`)
+ }
+ buf.WriteByte(',')
+ }
if len(j.TopLayer) != 0 {
buf.WriteString(`"layer":`)
fflib.WriteJsonString(buf, string(j.TopLayer))
@@ -171,6 +187,8 @@ const (
ffjtImageNames
+ ffjtImageNamesHistory
+
ffjtImageTopLayer
ffjtImageMappedTopLayers
@@ -194,6 +212,8 @@ var ffjKeyImageDigest = []byte("digest")
var ffjKeyImageNames = []byte("names")
+var ffjKeyImageNamesHistory = []byte("names-history")
+
var ffjKeyImageTopLayer = []byte("layer")
var ffjKeyImageMappedTopLayers = []byte("mapped-layers")
@@ -348,6 +368,11 @@ mainparse:
currentKey = ffjtImageNames
state = fflib.FFParse_want_colon
goto mainparse
+
+ } else if bytes.Equal(ffjKeyImageNamesHistory, kn) {
+ currentKey = ffjtImageNamesHistory
+ state = fflib.FFParse_want_colon
+ goto mainparse
}
}
@@ -400,6 +425,12 @@ mainparse:
goto mainparse
}
+ if fflib.EqualFoldRight(ffjKeyImageNamesHistory, kn) {
+ currentKey = ffjtImageNamesHistory
+ state = fflib.FFParse_want_colon
+ goto mainparse
+ }
+
if fflib.EqualFoldRight(ffjKeyImageNames, kn) {
currentKey = ffjtImageNames
state = fflib.FFParse_want_colon
@@ -444,6 +475,9 @@ mainparse:
case ffjtImageNames:
goto handle_Names
+ case ffjtImageNamesHistory:
+ goto handle_NamesHistory
+
case ffjtImageTopLayer:
goto handle_TopLayer
@@ -608,6 +642,80 @@ handle_Names:
state = fflib.FFParse_after_value
goto mainparse
+handle_NamesHistory:
+
+ /* handler: j.NamesHistory type=[]string kind=slice quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_left_brace && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for ", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+ j.NamesHistory = nil
+ } else {
+
+ j.NamesHistory = []string{}
+
+ wantVal := true
+
+ for {
+
+ var tmpJNamesHistory string
+
+ tok = fs.Scan()
+ if tok == fflib.FFTok_error {
+ goto tokerror
+ }
+ if tok == fflib.FFTok_right_brace {
+ break
+ }
+
+ if tok == fflib.FFTok_comma {
+ if wantVal == true {
+ // TODO(pquerna): this isn't an ideal error message, this handles
+ // things like [,,,] as an array value.
+ return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
+ }
+ continue
+ } else {
+ wantVal = true
+ }
+
+ /* handler: tmpJNamesHistory type=string kind=string quoted=false*/
+
+ {
+
+ {
+ if tok != fflib.FFTok_string && tok != fflib.FFTok_null {
+ return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for string", tok))
+ }
+ }
+
+ if tok == fflib.FFTok_null {
+
+ } else {
+
+ outBuf := fs.Output.Bytes()
+
+ tmpJNamesHistory = string(string(outBuf))
+
+ }
+ }
+
+ j.NamesHistory = append(j.NamesHistory, tmpJNamesHistory)
+
+ wantVal = false
+ }
+ }
+ }
+
+ state = fflib.FFParse_after_value
+ goto mainparse
+
handle_TopLayer:
/* handler: j.TopLayer type=string kind=string quoted=false*/
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index ba635ae91..d2752ae7c 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -387,7 +387,10 @@ func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
// to a tar header
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
- capability, _ := system.Lgetxattr(path, "security.capability")
+ capability, err := system.Lgetxattr(path, "security.capability")
+ if err != nil && err != system.EOPNOTSUPP {
+ return err
+ }
if capability != nil {
hdr.Xattrs = make(map[string]string)
hdr.Xattrs["security.capability"] = string(capability)
@@ -395,6 +398,27 @@ func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
return nil
}
+// 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 {
+ return err
+ }
+ for _, key := range xattrs {
+ if strings.HasPrefix(key, "user.") {
+ value, err := system.Lgetxattr(path, key)
+ if err != nil {
+ return err
+ }
+ if hdr.Xattrs == nil {
+ hdr.Xattrs = make(map[string]string)
+ }
+ hdr.Xattrs[key] = string(value)
+ }
+ }
+ return nil
+}
+
type tarWhiteoutConverter interface {
ConvertWrite(*tar.Header, string, os.FileInfo) (*tar.Header, error)
ConvertRead(*tar.Header, string) (bool, error)
@@ -469,6 +493,9 @@ func (ta *tarAppender) addTarFile(path, name string) error {
if err := ReadSecurityXattrToTarHeader(path, hdr); err != nil {
return err
}
+ if err := ReadUserXattrToTarHeader(path, hdr); err != nil {
+ return err
+ }
if ta.CopyPass {
copyPassHeader(hdr)
}
diff --git a/vendor/github.com/containers/storage/pkg/archive/changes.go b/vendor/github.com/containers/storage/pkg/archive/changes.go
index d3d6c8f74..3ce396070 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes.go
@@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"sort"
"strings"
"syscall"
@@ -263,6 +264,7 @@ type FileInfo struct {
children map[string]*FileInfo
capability []byte
added bool
+ xattrs map[string]string
}
// LookUp looks up the file information of a file.
@@ -331,7 +333,8 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
// breaks down is if some code intentionally hides a change by setting
// back mtime
if statDifferent(oldStat, oldInfo, newStat, info) ||
- !bytes.Equal(oldChild.capability, newChild.capability) {
+ !bytes.Equal(oldChild.capability, newChild.capability) ||
+ !reflect.DeepEqual(oldChild.xattrs, newChild.xattrs) {
change := Change{
Path: newChild.path(),
Kind: ChangeModify,
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 dc313d1ab..ceec53ada 100644
--- a/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
+++ b/vendor/github.com/containers/storage/pkg/archive/changes_linux.go
@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"sort"
+ "strings"
"syscall"
"unsafe"
@@ -83,7 +84,26 @@ func walkchunk(path string, fi os.FileInfo, dir string, root *FileInfo) error {
return err
}
info.stat = stat
- info.capability, _ = system.Lgetxattr(cpath, "security.capability") // lgetxattr(2): fs access
+ info.capability, err = system.Lgetxattr(cpath, "security.capability") // lgetxattr(2): fs access
+ if err != nil && err != system.EOPNOTSUPP {
+ return err
+ }
+ xattrs, err := system.Llistxattr(cpath)
+ if err != nil && err != system.EOPNOTSUPP {
+ return err
+ }
+ for _, key := range xattrs {
+ if strings.HasPrefix(key, "user.") {
+ value, err := system.Lgetxattr(cpath, key)
+ if err != nil {
+ return err
+ }
+ if info.xattrs == nil {
+ info.xattrs = make(map[string]string)
+ }
+ info.xattrs[key] = string(value)
+ }
+ }
parent.children[info.name] = info
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 98b111be4..0d6cd95e3 100644
--- a/vendor/github.com/containers/storage/pkg/system/xattrs_linux.go
+++ b/vendor/github.com/containers/storage/pkg/system/xattrs_linux.go
@@ -1,6 +1,16 @@
package system
-import "golang.org/x/sys/unix"
+import (
+ "bytes"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ // Operation not supported
+ EOPNOTSUPP syscall.Errno = unix.EOPNOTSUPP
+)
// Lgetxattr retrieves the value of the extended attribute identified by attr
// and associated with the given path in the file system.
@@ -27,3 +37,32 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
func Lsetxattr(path string, attr string, data []byte, flags int) error {
return unix.Lsetxattr(path, attr, data, flags)
}
+
+// Llistxattr lists extended attributes associated with the given path
+// in the file system.
+func Llistxattr(path string) ([]string, error) {
+ var dest []byte
+
+ for {
+ sz, err := unix.Llistxattr(path, dest)
+ if err != nil {
+ return nil, err
+ }
+
+ if sz > len(dest) {
+ dest = make([]byte, sz)
+ } else {
+ dest = dest[:sz]
+ break
+ }
+ }
+
+ var attrs []string
+ for _, token := range bytes.Split(dest, []byte{0}) {
+ if len(token) > 0 {
+ attrs = append(attrs, string(token))
+ }
+ }
+
+ return attrs, nil
+}
diff --git a/vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go b/vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go
index 0114f2227..b4cf4e6ca 100644
--- a/vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go
+++ b/vendor/github.com/containers/storage/pkg/system/xattrs_unsupported.go
@@ -2,6 +2,13 @@
package system
+import "syscall"
+
+const (
+ // Operation not supported
+ EOPNOTSUPP syscall.Errno = syscall.Errno(0)
+)
+
// Lgetxattr is not supported on platforms other than linux.
func Lgetxattr(path string, attr string) ([]byte, error) {
return nil, ErrNotSupportedPlatform
@@ -11,3 +18,8 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
func Lsetxattr(path string, attr string, data []byte, flags int) error {
return ErrNotSupportedPlatform
}
+
+// Llistxattr is not supported on platforms other than linux.
+func Llistxattr(path string) ([]string, error) {
+ return nil, ErrNotSupportedPlatform
+}
diff --git a/vendor/github.com/containers/storage/utils.go b/vendor/github.com/containers/storage/utils.go
index 54627731a..5aa7c0851 100644
--- a/vendor/github.com/containers/storage/utils.go
+++ b/vendor/github.com/containers/storage/utils.go
@@ -70,6 +70,18 @@ func ParseIDMapping(UIDMapSlice, GIDMapSlice []string, subUIDMap, subGIDMap stri
// GetRootlessRuntimeDir returns the runtime directory when running as non root
func GetRootlessRuntimeDir(rootlessUid int) (string, error) {
+ path, err := getRootlessRuntimeDir(rootlessUid)
+ if err != nil {
+ return "", err
+ }
+ path = filepath.Join(path, "containers")
+ if err := os.MkdirAll(path, 0700); err != nil {
+ return "", errors.Wrapf(err, "unable to make rootless runtime dir %s", path)
+ }
+ return path, nil
+}
+
+func getRootlessRuntimeDir(rootlessUid int) (string, error) {
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
if runtimeDir != "" {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8837e7efb..4fb9b9d44 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -125,7 +125,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.14.0
+# github.com/containers/storage v1.15.0
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs