diff options
64 files changed, 1011 insertions, 490 deletions
diff --git a/.github/actions/check_cirrus_cron/cron_failures.sh b/.github/actions/check_cirrus_cron/cron_failures.sh index 2693df417..16419c6d6 100755 --- a/.github/actions/check_cirrus_cron/cron_failures.sh +++ b/.github/actions/check_cirrus_cron/cron_failures.sh @@ -67,7 +67,7 @@ jq --indent 4 --color-output . <./artifacts/reply.json || \ cat ./artifacts/reply.json echo "::endgroup::" -# Desireable to catch non-JSON encoded errors in reply. +# Desirable to catch non-JSON encoded errors in reply. if grep -qi 'error' ./artifacts/reply.json; then err "Found the word 'error' in reply" fi diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 25f4d0f79..f792b2713 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -278,7 +278,6 @@ func validCurrentCmdLine(cmd *cobra.Command, args []string, toComplete string) b return true } } - cobra.CompDebugln(err.Error(), true) return false } return true @@ -445,6 +444,29 @@ func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string) return getNetworks(cmd, toComplete) } +// AutocompleteDefaultOneArg - Autocomplete path only for the first argument. +func AutocompleteDefaultOneArg(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return nil, cobra.ShellCompDirectiveDefault + } + return nil, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteCommitCommand - Autocomplete podman commit command args. +func AutocompleteCommitCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if !validCurrentCmdLine(cmd, args, toComplete) { + return nil, cobra.ShellCompDirectiveNoFileComp + } + if len(args) == 0 { + return getContainers(cmd, toComplete, completeDefault) + } + if len(args) == 1 { + return getImages(cmd, toComplete) + } + // don't complete more than 2 args + return nil, cobra.ShellCompDirectiveNoFileComp +} + // AutocompleteCpCommand - Autocomplete podman cp command args. func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if !validCurrentCmdLine(cmd, args, toComplete) { @@ -465,6 +487,43 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string) return nil, cobra.ShellCompDirectiveNoFileComp } +// AutocompleteExecCommand - Autocomplete podman exec command args. +func AutocompleteExecCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if !validCurrentCmdLine(cmd, args, toComplete) { + return nil, cobra.ShellCompDirectiveNoFileComp + } + if len(args) == 0 { + return getContainers(cmd, toComplete, completeDefault, "running") + } + return nil, cobra.ShellCompDirectiveDefault +} + +// AutocompleteRunlabelCommand - Autocomplete podman container runlabel command args. +func AutocompleteRunlabelCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if !validCurrentCmdLine(cmd, args, toComplete) { + return nil, cobra.ShellCompDirectiveNoFileComp + } + if len(args) == 0 { + // FIXME: What labels can we recommend here? + return nil, cobra.ShellCompDirectiveNoFileComp + } + if len(args) == 1 { + return getImages(cmd, toComplete) + } + return nil, cobra.ShellCompDirectiveDefault +} + +// AutocompletePortCommand - Autocomplete podman port command args. +func AutocompletePortCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if !validCurrentCmdLine(cmd, args, toComplete) { + return nil, cobra.ShellCompDirectiveNoFileComp + } + if len(args) == 0 { + return getContainers(cmd, toComplete, completeDefault) + } + return nil, cobra.ShellCompDirectiveNoFileComp +} + // AutocompleteNetworkConnectCmd - Autocomplete podman network connect/disconnect command args. func AutocompleteNetworkConnectCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 0 { @@ -496,6 +555,23 @@ func AutocompleteTopCmd(cmd *cobra.Command, args []string, toComplete string) ([ return descriptors, cobra.ShellCompDirectiveNoFileComp } +// AutocompleteInspect - Autocomplete podman inspect. +func AutocompleteInspect(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if !validCurrentCmdLine(cmd, args, toComplete) { + return nil, cobra.ShellCompDirectiveNoFileComp + } + containers, _ := getContainers(cmd, toComplete, completeDefault) + images, _ := getImages(cmd, toComplete) + pods, _ := getPods(cmd, toComplete, completeDefault) + networks, _ := getNetworks(cmd, toComplete) + volumes, _ := getVolumes(cmd, toComplete) + suggestions := append(containers, images...) + suggestions = append(suggestions, pods...) + suggestions = append(suggestions, networks...) + suggestions = append(suggestions, volumes...) + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + // AutocompleteSystemConnections - Autocomplete system connections. func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if !validCurrentCmdLine(cmd, args, toComplete) { diff --git a/cmd/podman/containers/commit.go b/cmd/podman/containers/commit.go index c5c7673b2..ff06e10f7 100644 --- a/cmd/podman/containers/commit.go +++ b/cmd/podman/containers/commit.go @@ -24,7 +24,7 @@ var ( Long: commitDescription, RunE: commit, Args: cobra.RangeArgs(1, 2), - ValidArgsFunction: common.AutocompleteContainers, + ValidArgsFunction: common.AutocompleteCommitCommand, Example: `podman commit -q --message "committing container to image" reverent_golick image-committed podman commit -q --author "firstName lastName" reverent_golick image-committed podman commit -q --pause=false containerID image-committed diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go index fd3aa7680..9b0a01a2f 100644 --- a/cmd/podman/containers/cp.go +++ b/cmd/podman/containers/cp.go @@ -13,7 +13,7 @@ var ( You can copy from the container's file system to the local machine or the reverse, from the local filesystem to the container. If "-" is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT. The CONTAINER can be a running or stopped container. The SRC_PATH or DEST_PATH can be a file or directory. ` cpCommand = &cobra.Command{ - Use: "cp [options] SRC_PATH DEST_PATH", + Use: "cp [options] [CONTAINER:]SRC_PATH [CONTAINER:]DEST_PATH", Short: "Copy files/folders between a container and the local filesystem", Long: cpDescription, Args: cobra.ExactArgs(2), diff --git a/cmd/podman/containers/exec.go b/cmd/podman/containers/exec.go index 306bae58e..3d4918d50 100644 --- a/cmd/podman/containers/exec.go +++ b/cmd/podman/containers/exec.go @@ -26,7 +26,7 @@ var ( Long: execDescription, RunE: exec, DisableFlagsInUseLine: true, - ValidArgsFunction: common.AutocompleteContainersRunning, + ValidArgsFunction: common.AutocompleteExecCommand, Example: `podman exec -it ctrID ls podman exec -it -w /tmp myCtr pwd podman exec --user root ctrID ls`, diff --git a/cmd/podman/containers/logs.go b/cmd/podman/containers/logs.go index 1fa4ac11f..d4ede370a 100644 --- a/cmd/podman/containers/logs.go +++ b/cmd/podman/containers/logs.go @@ -69,6 +69,12 @@ var ( ) func init() { + // if run remotely we only allow one container arg + if registry.IsRemote() { + logsCommand.Use = "logs [options] CONTAINER" + containerLogsCommand.Use = logsCommand.Use + } + // logs registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go index ac31e158e..d59161149 100644 --- a/cmd/podman/containers/port.go +++ b/cmd/podman/containers/port.go @@ -26,7 +26,7 @@ var ( Args: func(cmd *cobra.Command, args []string) error { return validate.CheckAllLatestAndCIDFile(cmd, args, true, false) }, - ValidArgsFunction: common.AutocompleteContainers, + ValidArgsFunction: common.AutocompletePortCommand, Example: `podman port --all podman port ctrID 80/tcp podman port --latest 80`, diff --git a/cmd/podman/containers/runlabel.go b/cmd/podman/containers/runlabel.go index 2f6d2eb05..6ebba4935 100644 --- a/cmd/podman/containers/runlabel.go +++ b/cmd/podman/containers/runlabel.go @@ -30,7 +30,7 @@ var ( Long: runlabelDescription, RunE: runlabel, Args: cobra.MinimumNArgs(2), - ValidArgsFunction: common.AutocompleteImages, + ValidArgsFunction: common.AutocompleteRunlabelCommand, Example: `podman container runlabel run imageID podman container runlabel install imageID arg1 arg2 podman container runlabel --display run myImage`, diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go index 5e6abe243..e094e6bdd 100644 --- a/cmd/podman/diff.go +++ b/cmd/podman/diff.go @@ -18,7 +18,7 @@ var ( // Command: podman _diff_ Object_ID diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.` diffCmd = &cobra.Command{ - Use: "diff [options] {CONTAINER_ID | IMAGE_ID}", + Use: "diff [options] {CONTAINER|IMAGE}", Args: validate.IDOrLatestArgs, Short: "Display the changes to the object's file system", Long: diffDescription, diff --git a/cmd/podman/generate/kube.go b/cmd/podman/generate/kube.go index 0517db19a..cb608e7b5 100644 --- a/cmd/podman/generate/kube.go +++ b/cmd/podman/generate/kube.go @@ -22,7 +22,7 @@ var ( Whether the input is for a container or pod, Podman will always generate the specification as a pod.` kubeCmd = &cobra.Command{ - Use: "kube [options] CONTAINER... | POD", + Use: "kube [options] {CONTAINER...|POD}", Short: "Generate Kubernetes YAML from a container or pod.", Long: kubeDescription, RunE: kube, diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go index e9cf76aae..f9099d3b8 100644 --- a/cmd/podman/generate/systemd.go +++ b/cmd/podman/generate/systemd.go @@ -26,7 +26,7 @@ var ( The generated units can later be controlled via systemctl(1).` systemdCmd = &cobra.Command{ - Use: "systemd [options] CTR|POD", + Use: "systemd [options] {CONTAINER|POD}", Short: "Generate systemd units.", Long: systemdDescription, RunE: systemd, diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go index 739e1c265..fbea1e3d8 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -11,6 +11,7 @@ import ( "github.com/containers/buildah/pkg/parse" "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/config" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/pkg/domain/entities" @@ -44,7 +45,7 @@ var ( Long: buildDescription, Args: cobra.MaximumNArgs(1), RunE: build, - ValidArgsFunction: completion.AutocompleteDefault, + ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman build . podman build --creds=username:password -t imageName -f Containerfile.simple . podman build --layers --force-rm --tag imageName .`, @@ -115,6 +116,7 @@ func buildFlags(cmd *cobra.Command) { // --layers flag flag = layerFlags.Lookup("layers") useLayersVal := useLayers() + buildOpts.Layers = useLayersVal == "true" if err := flag.Value.Set(useLayersVal); err != nil { logrus.Errorf("unable to set --layers to %v: %v", useLayersVal, err) } @@ -274,11 +276,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil } } } - // Check to see if the BUILDAH_LAYERS environment variable is set and - // override command-line. - if _, ok := os.LookupEnv("BUILDAH_LAYERS"); ok { - flags.Layers = true - } + flags.Layers = buildOpts.Layers // `buildah bud --layers=false` acts like `docker build --squash` does. // That is all of the new layers created during the build process are diff --git a/cmd/podman/images/import.go b/cmd/podman/images/import.go index f38ab3b19..ac59935ad 100644 --- a/cmd/podman/images/import.go +++ b/cmd/podman/images/import.go @@ -25,18 +25,19 @@ var ( Short: "Import a tarball to create a filesystem image", Long: importDescription, RunE: importCon, - ValidArgsFunction: completion.AutocompleteDefault, + Args: cobra.RangeArgs(1, 2), + ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman import http://example.com/ctr.tar url-image cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported cat ctr.tar | podman import -`, } imageImportCommand = &cobra.Command{ - Args: cobra.MinimumNArgs(1), Use: importCommand.Use, Short: importCommand.Short, Long: importCommand.Long, RunE: importCommand.RunE, + Args: importCommand.Args, ValidArgsFunction: importCommand.ValidArgsFunction, Example: `podman image import http://example.com/ctr.tar url-image cat ctr.tar | podman -q image import --message "importing the ctr.tar tarball" - image-imported diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index 447b02fbe..d82083cd8 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -29,7 +29,7 @@ var ( // Command: podman push pushCmd = &cobra.Command{ - Use: "push [options] SOURCE [DESTINATION]", + Use: "push [options] IMAGE [DESTINATION]", Short: "Push an image to a specified destination", Long: pushDescription, RunE: imagePush, diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go index 9ef2d0c91..3a35c4fad 100644 --- a/cmd/podman/images/save.go +++ b/cmd/podman/images/save.go @@ -43,7 +43,7 @@ var ( } return nil }, - ValidArgsFunction: completion.AutocompleteNone, + ValidArgsFunction: common.AutocompleteImages, Example: `podman save --quiet -o myimage.tar imageID podman save --format docker-dir -o ubuntu-dir ubuntu podman save > alpine-all.tar alpine:latest`, diff --git a/cmd/podman/images/untag.go b/cmd/podman/images/untag.go index 17dc21203..3cf62713b 100644 --- a/cmd/podman/images/untag.go +++ b/cmd/podman/images/untag.go @@ -9,7 +9,7 @@ import ( var ( untagCommand = &cobra.Command{ - Use: "untag IMAGE [NAME...]", + Use: "untag IMAGE [IMAGE...]", Short: "Remove a name from a local image", Long: "Removes one or more names from a locally-stored image.", RunE: untag, diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index f62abe931..64daae951 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -20,12 +20,12 @@ var ( // Command: podman _inspect_ Object_ID inspectCmd = &cobra.Command{ - Use: "inspect [options] {CONTAINER_ID | IMAGE_ID} [...]", + Use: "inspect [options] {CONTAINER|IMAGE|POD|NETWORK|VOLUME} [...]", Short: "Display the configuration of object denoted by ID", RunE: inspectExec, Long: inspectDescription, TraverseChildren: true, - ValidArgsFunction: common.AutocompleteContainersAndImages, + ValidArgsFunction: common.AutocompleteInspect, Example: `podman inspect fedora podman inspect --type image fedora podman inspect CtrID ImgID diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go index a3b469491..89faa42a2 100644 --- a/cmd/podman/manifest/push.go +++ b/cmd/podman/manifest/push.go @@ -24,7 +24,7 @@ type manifestPushOptsWrapper struct { var ( manifestPushOpts = manifestPushOptsWrapper{} pushCmd = &cobra.Command{ - Use: "push [options] SOURCE DESTINATION", + Use: "push [options] LIST DESTINATION", Short: "Push a manifest list or image index to a registry", Long: "Pushes manifest lists and image indexes to registries.", RunE: push, diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go index 8db4bb89a..1a091f111 100644 --- a/cmd/podman/networks/create.go +++ b/cmd/podman/networks/create.go @@ -17,7 +17,7 @@ import ( var ( networkCreateDescription = `create CNI networks for containers and pods` networkCreateCommand = &cobra.Command{ - Use: "create [options] [NETWORK]", + Use: "create [options] [NAME]", Short: "network create", Long: networkCreateDescription, RunE: networkCreate, diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index db70ad7d4..5e227d05a 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -39,7 +39,7 @@ var ( Long: kubeDescription, RunE: kube, Args: cobra.ExactArgs(1), - ValidArgsFunction: completion.AutocompleteDefault, + ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman play kube nginx.yml podman play kube --creds user:password --seccomp-profile-root /custom/path apache.yml`, } diff --git a/cmd/podman/pods/prune.go b/cmd/podman/pods/prune.go index e069c9b7f..965c36398 100644 --- a/cmd/podman/pods/prune.go +++ b/cmd/podman/pods/prune.go @@ -7,7 +7,7 @@ import ( "os" "strings" - "github.com/containers/podman/v2/cmd/podman/common" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/validate" @@ -28,7 +28,7 @@ var ( Short: "Remove all stopped pods and their containers", Long: pruneDescription, RunE: prune, - ValidArgsFunction: common.AutocompletePods, + ValidArgsFunction: completion.AutocompleteNone, Example: `podman pod prune`, } ) diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go index 42482b5d9..f8bdbfa10 100644 --- a/cmd/podman/system/service.go +++ b/cmd/podman/system/service.go @@ -10,6 +10,7 @@ import ( "time" "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/rootless" @@ -32,7 +33,7 @@ Enable a listening service for API access to Podman commands. Short: "Run API service", Long: srvDescription, RunE: service, - ValidArgsFunction: completion.AutocompleteDefault, + ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman system service --time=0 unix:///tmp/podman.sock`, } diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go index 437cf7b2e..364852979 100644 --- a/cmd/podman/system/unshare.go +++ b/cmd/podman/system/unshare.go @@ -14,7 +14,7 @@ import ( var ( unshareDescription = "Runs a command in a modified user namespace." unshareCommand = &cobra.Command{ - Use: "unshare [COMMAND [ARG ...]]", + Use: "unshare [COMMAND [ARG...]]", DisableFlagsInUseLine: true, Short: "Run a command in a modified user namespace", Long: unshareDescription, diff --git a/completions/Readme.md b/completions/Readme.md index 9a3eac480..5c9d16f3c 100644 --- a/completions/Readme.md +++ b/completions/Readme.md @@ -4,4 +4,4 @@ Podman offers shell completion scripts for bash, zsh and fish. The completion sc The shell completion scripts are generated by `make completion`, do not edit these files directly. To install them you can run `sudo make install.completions`. -For information about these sripts see [`man podman-completion`](../docs/source/markdown/podman-completion.1.md) +For information about these scripts see [`man podman-completion`](../docs/source/markdown/podman-completion.1.md) diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md index 445888d30..032158c56 100644 --- a/docs/source/markdown/podman-generate-systemd.1.md +++ b/docs/source/markdown/podman-generate-systemd.1.md @@ -155,7 +155,7 @@ Podman-generated unit files include an `[Install]` section, which carries instal Once you have generated the systemd unit file, you can copy the generated systemd file to ```/etc/systemd/system``` for installing as a root user and to ```$HOME/.config/systemd/user``` for installing it as a non-root user. Enable the copied unit file or files using `systemctl enable`. -Note: Coping unit files to ```/etc/systemd/system``` and enabling it marks the unit file to be automatically started at boot. And smillarly, coping a unit file to ```$HOME/.config/systemd/user``` and enabling it marks the unit file to be automatically started on user login. +Note: Copying unit files to ```/etc/systemd/system``` and enabling it marks the unit file to be automatically started at boot. And similarly, copying a unit file to ```$HOME/.config/systemd/user``` and enabling it marks the unit file to be automatically started on user login. ``` diff --git a/docs/source/markdown/podman-network-connect.1.md b/docs/source/markdown/podman-network-connect.1.md index a31a415dc..cff4336d6 100644 --- a/docs/source/markdown/podman-network-connect.1.md +++ b/docs/source/markdown/podman-network-connect.1.md @@ -15,7 +15,7 @@ This command is not available for rootless users. ## OPTIONS #### **--alias** Add network-scoped alias for the container. If the network is using the `dnsname` CNI plugin, these aliases -can be used for name resolution on the given network. Multiple *--alias* options may be specificed as input. +can be used for name resolution on the given network. Multiple *--alias* options may be specified as input. ## EXAMPLE @@ -39,13 +39,13 @@ require ( github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 github.com/onsi/ginkgo v1.14.2 - github.com/onsi/gomega v1.10.3 + github.com/onsi/gomega v1.10.4 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 github.com/opencontainers/runc v1.0.0-rc91.0.20200708210054-ce54a9d4d79b github.com/opencontainers/runtime-spec v1.0.3-0.20200817204227-f9c09b4ea1df github.com/opencontainers/runtime-tools v0.9.0 - github.com/opencontainers/selinux v1.6.0 + github.com/opencontainers/selinux v1.7.0 github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 @@ -22,7 +22,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873 h1:93nQ7k53GjoMQ07HVP8g6Zj1fQZDDj7Xy2VkNNtvX8o= github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc= github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= @@ -94,13 +93,11 @@ github.com/containernetworking/plugins v0.8.7 h1:bU7QieuAp+sACI2vCzESJ3FoT860urY github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0= github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c h1:vyc2iYz9b2vfDiigpLyhiXNqXITt/dmDk74HpHzlQow= github.com/containers/buildah v1.18.1-0.20201125084616-dd26b137459c/go.mod h1:B+0OkXUogxdwsEy4ax3a5/vDtJjL6vCisiV6frQZJ4A= -github.com/containers/common v0.29.0 h1:hTMC+urdkk5bKfhL/OgCixIX5xjJgQ2l2jPG745ECFQ= github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA= github.com/containers/common v0.31.0 h1:SRnjfoqbjfaojpY9YJq9JBPEslwB5hoXJbaE+5zMFwM= github.com/containers/common v0.31.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA= 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 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q= github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ= github.com/containers/image/v5 v5.9.0 h1:dRmUtcluQcmasNo3DpnRoZjfU0rOu1qZeL6wlDJr10Q= github.com/containers/image/v5 v5.9.0/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ= @@ -230,7 +227,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= @@ -417,8 +413,9 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U= +github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -442,6 +439,8 @@ github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pK github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.7.0 h1:I3Qiu8dbuWHHHfwd4id7zXivJ1qWixGQx8nTvQsKnjs= +github.com/opencontainers/selinux v1.7.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/openshift/imagebuilder v1.1.8 h1:gjiIl8pbNj0eC4XWvFJHATdDvYm64p9/pLDLQWoLZPA= github.com/openshift/imagebuilder v1.1.8/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -561,6 +560,8 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7Zo github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA= github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -638,10 +639,10 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -694,7 +695,6 @@ golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 h1:5jaG59Zhd+8ZXe8C+lgiAGqkOaZBruqrWclLkgAww34= golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -702,7 +702,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -733,7 +732,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/libpod/image/pull.go b/libpod/image/pull.go index 2a2d16252..c37929927 100644 --- a/libpod/image/pull.go +++ b/libpod/image/pull.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "os" "path/filepath" "strings" @@ -378,29 +377,12 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa return images, nil } -// getShortNameMode looks up the `CONTAINERS_SHORT_NAME_ALIASING` environment -// variable. If it's "on", return `nil` to use the defaults from -// containers/image and the registries.conf files on the system. If it's -// "off", empty or unset, return types.ShortNameModeDisabled to turn off -// short-name aliasing by default. -// -// TODO: remove this function once we want to default to short-name aliasing. -func getShortNameMode() *types.ShortNameMode { - env := os.Getenv("CONTAINERS_SHORT_NAME_ALIASING") - if strings.ToLower(env) == "on" { - return nil // default to whatever registries.conf and c/image decide - } - mode := types.ShortNameModeDisabled - return &mode -} - // pullGoalFromPossiblyUnqualifiedName looks at inputName and determines the possible // image references to try pulling in combination with the registries.conf file as well func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(sys *types.SystemContext, writer io.Writer, inputName string) (*pullGoal, error) { if sys == nil { sys = &types.SystemContext{} } - sys.ShortNameMode = getShortNameMode() resolved, err := shortnames.Resolve(sys, inputName) if err != nil { diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 223eb2cd5..d8197415c 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -1,13 +1,8 @@ package compat import ( - "bytes" - "encoding/base64" - "encoding/json" "fmt" "net/http" - "os" - "time" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" @@ -15,6 +10,7 @@ import ( "github.com/containers/podman/v2/pkg/copy" "github.com/gorilla/schema" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) func Archive(w http.ResponseWriter, r *http.Request) { @@ -71,12 +67,12 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path)) return } - statHeader, err := fileInfoToDockerStats(info) + statHeader, err := copy.EncodeFileInfo(info) if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } - w.Header().Add("X-Docker-Container-Path-Stat", statHeader) + w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader) // Our work is done when the user is interested in the header only. if r.Method == http.MethodHead { @@ -91,47 +87,16 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De return } - w.WriteHeader(http.StatusOK) - if err := copy.Copy(&source, &destination, false); err != nil { + copier, err := copy.GetCopier(&source, &destination, false) + if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } -} - -func fileInfoToDockerStats(info *copy.FileInfo) (string, error) { - dockerStats := struct { - Name string `json:"name"` - Size int64 `json:"size"` - Mode os.FileMode `json:"mode"` - ModTime time.Time `json:"mtime"` - LinkTarget string `json:"linkTarget"` - }{ - Name: info.Name, - Size: info.Size, - Mode: info.Mode, - ModTime: info.ModTime, - LinkTarget: info.LinkTarget, - } - - jsonBytes, err := json.Marshal(&dockerStats) - if err != nil { - return "", errors.Wrap(err, "failed to serialize file stats") - } - - buff := bytes.NewBuffer(make([]byte, 0, 128)) - base64encoder := base64.NewEncoder(base64.StdEncoding, buff) - - _, err = base64encoder.Write(jsonBytes) - if err != nil { - return "", err - } - - err = base64encoder.Close() - if err != nil { - return "", err + w.WriteHeader(http.StatusOK) + if err := copier.Copy(); err != nil { + logrus.Errorf("Error during copy: %v", err) + return } - - return buff.String(), nil } func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { @@ -170,9 +135,14 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, return } - w.WriteHeader(http.StatusOK) - if err := copy.Copy(&source, &destination, false); err != nil { + copier, err := copy.GetCopier(&source, &destination, false) + if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } + w.WriteHeader(http.StatusOK) + if err := copier.Copy(); err != nil { + logrus.Errorf("Error during copy: %v", err) + return + } } diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 43478c1d3..415ff85cd 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -71,6 +71,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { ForceRm bool `schema:"forcerm"` HTTPProxy bool `schema:"httpproxy"` Labels string `schema:"labels"` + Layers bool `schema:"layers"` MemSwap int64 `schema:"memswap"` Memory int64 `schema:"memory"` NetworkMode string `schema:"networkmode"` @@ -165,6 +166,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Registry: query.Registry, IgnoreUnrecognizedInstructions: true, Quiet: query.Quiet, + Layers: query.Layers, Isolation: buildah.IsolationChroot, Compression: archive.Gzip, Args: buildArgs, diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 815ab4e86..d34ab87d9 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -41,6 +41,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO if options.NoCache { params.Set("nocache", "1") } + if options.Layers { + params.Set("layers", "1") + } // TODO cachefrom if options.PullPolicy == buildah.PullAlways { params.Set("pull", "1") diff --git a/pkg/copy/copy.go b/pkg/copy/copy.go index 0e68eb450..13893deb2 100644 --- a/pkg/copy/copy.go +++ b/pkg/copy/copy.go @@ -25,31 +25,61 @@ import ( // // **************************************************************************** -// Copy the source item to destination. Use extract to untar the source if -// it's a tar archive. -func Copy(source *CopyItem, destination *CopyItem, extract bool) error { +// Copier copies data from a source to a destination CopyItem. +type Copier struct { + copyFunc func() error + cleanUpFuncs []deferFunc +} + +// cleanUp releases resources the Copier may hold open. +func (c *Copier) cleanUp() { + for _, f := range c.cleanUpFuncs { + f() + } +} + +// Copy data from a source to a destination CopyItem. +func (c *Copier) Copy() error { + defer c.cleanUp() + return c.copyFunc() +} + +// GetCopiers returns a Copier to copy the source item to destination. Use +// extract to untar the source if it's a tar archive. +func GetCopier(source *CopyItem, destination *CopyItem, extract bool) (*Copier, error) { + copier := &Copier{} + // First, do the man-page dance. See podman-cp(1) for details. if err := enforceCopyRules(source, destination); err != nil { - return err + return nil, err } // Destination is a stream (e.g., stdout or an http body). if destination.info.IsStream { // Source is a stream (e.g., stdin or an http body). if source.info.IsStream { - _, err := io.Copy(destination.writer, source.reader) - return err + copier.copyFunc = func() error { + _, err := io.Copy(destination.writer, source.reader) + return err + } + return copier, nil } root, glob, err := source.buildahGlobs() if err != nil { - return err + return nil, err } - return buildahCopiah.Get(root, "", source.getOptions(), []string{glob}, destination.writer) + copier.copyFunc = func() error { + return buildahCopiah.Get(root, "", source.getOptions(), []string{glob}, destination.writer) + } + return copier, nil } // Destination is either a file or a directory. if source.info.IsStream { - return buildahCopiah.Put(destination.root, destination.resolved, source.putOptions(), source.reader) + copier.copyFunc = func() error { + return buildahCopiah.Put(destination.root, destination.resolved, source.putOptions(), source.reader) + } + return copier, nil } tarOptions := &archive.TarOptions{ @@ -71,33 +101,36 @@ func Copy(source *CopyItem, destination *CopyItem, extract bool) error { var tarReader io.ReadCloser if extract && archive.IsArchivePath(source.resolved) { if !destination.info.IsDir { - return errors.Errorf("cannot extract archive %q to file %q", source.original, destination.original) + return nil, errors.Errorf("cannot extract archive %q to file %q", source.original, destination.original) } reader, err := os.Open(source.resolved) if err != nil { - return err + return nil, err } - defer reader.Close() + copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() }) // The stream from stdin may be compressed (e.g., via gzip). decompressedStream, err := archive.DecompressStream(reader) if err != nil { - return err + return nil, err } - defer decompressedStream.Close() + copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { decompressedStream.Close() }) tarReader = decompressedStream } else { reader, err := archive.TarWithOptions(source.resolved, tarOptions) if err != nil { - return err + return nil, err } - defer reader.Close() + copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() }) tarReader = reader } - return buildahCopiah.Put(root, dir, source.putOptions(), tarReader) + copier.copyFunc = func() error { + return buildahCopiah.Put(root, dir, source.putOptions(), tarReader) + } + return copier, nil } // enforceCopyRules enforces the rules for copying from a source to a @@ -114,7 +147,6 @@ func enforceCopyRules(source, destination *CopyItem) error { return nil } - // Source is a *stream*. if source.info.IsStream { if !(destination.info.IsDir || destination.info.IsStream) { return errors.New("destination must be a directory or stream when copying from a stream") diff --git a/pkg/copy/fileinfo.go b/pkg/copy/fileinfo.go new file mode 100644 index 000000000..08b4eb377 --- /dev/null +++ b/pkg/copy/fileinfo.go @@ -0,0 +1,56 @@ +package copy + +import ( + "encoding/base64" + "encoding/json" + "net/http" + "os" + "strings" + "time" + + "github.com/pkg/errors" +) + +// XDockerContainerPathStatHeader is the *key* in http headers pointing to the +// base64 encoded JSON payload of stating a path in a container. +const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat" + +// FileInfo describes a file or directory and is returned by +// (*CopyItem).Stat(). +type FileInfo struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + ModTime time.Time `json:"mtime"` + IsDir bool `json:"isDir"` + IsStream bool `json:"isStream"` + LinkTarget string `json:"linkTarget"` +} + +// EncodeFileInfo serializes the specified FileInfo as a base64 encoded JSON +// payload. Intended for Docker compat. +func EncodeFileInfo(info *FileInfo) (string, error) { + buf, err := json.Marshal(&info) + if err != nil { + return "", errors.Wrap(err, "failed to serialize file stats") + } + return base64.URLEncoding.EncodeToString(buf), nil +} + +// ExtractFileInfoFromHeader extracts a base64 encoded JSON payload of a +// FileInfo in the http header. If no such header entry is found, nil is +// returned. Intended for Docker compat. +func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) { + rawData := header.Get(XDockerContainerPathStatHeader) + if len(rawData) == 0 { + return nil, nil + } + + info := FileInfo{} + base64Decoder := base64.NewDecoder(base64.URLEncoding, strings.NewReader(rawData)) + if err := json.NewDecoder(base64Decoder).Decode(&info); err != nil { + return nil, err + } + + return &info, nil +} diff --git a/pkg/copy/item.go b/pkg/copy/item.go index db6bca610..df8bf30b9 100644 --- a/pkg/copy/item.go +++ b/pkg/copy/item.go @@ -5,7 +5,6 @@ import ( "os" "path/filepath" "strings" - "time" buildahCopiah "github.com/containers/buildah/copier" "github.com/containers/buildah/pkg/chrootuser" @@ -75,18 +74,6 @@ type CopyItem struct { // deferFunc allows for returning functions that must be deferred at call sites. type deferFunc func() -// FileInfo describes a file or directory and is returned by -// (*CopyItem).Stat(). -type FileInfo struct { - Name string `json:"name"` - Size int64 `json:"size"` - Mode os.FileMode `json:"mode"` - ModTime time.Time `json:"mtime"` - IsDir bool `json:"isDir"` - IsStream bool `json:"isStream"` - LinkTarget string `json:"linkTarget"` -} - // Stat returns the FileInfo. func (item *CopyItem) Stat() (*FileInfo, error) { return &item.info, item.statError diff --git a/pkg/copy/parse.go b/pkg/copy/parse.go new file mode 100644 index 000000000..39e0e1547 --- /dev/null +++ b/pkg/copy/parse.go @@ -0,0 +1,61 @@ +package copy + +import ( + "strings" + + "github.com/pkg/errors" +) + +// ParseSourceAndDestination parses the source and destination input into a +// possibly specified container and path. The input format is described in +// podman-cp(1) as "[nameOrID:]path". Colons in paths are supported as long +// they start with a dot or slash. +// +// It returns, in order, the source container and path, followed by the +// destination container and path, and an error. Note that exactly one +// container must be specified. +func ParseSourceAndDestination(source, destination string) (string, string, string, string, error) { + sourceContainer, sourcePath := parseUserInput(source) + destContainer, destPath := parseUserInput(destination) + + numContainers := 0 + if len(sourceContainer) > 0 { + numContainers++ + } + if len(destContainer) > 0 { + numContainers++ + } + + if numContainers != 1 { + return "", "", "", "", errors.Errorf("invalid arguments %q, %q: exactly 1 container expected but %d specified", source, destination, numContainers) + } + + if len(sourcePath) == 0 || len(destPath) == 0 { + return "", "", "", "", errors.Errorf("invalid arguments %q, %q: you must specify paths", source, destination) + } + + return sourceContainer, sourcePath, destContainer, destPath, nil +} + +// parseUserInput parses the input string and returns, if specified, the name +// or ID of the container and the path. The input format is described in +// podman-cp(1) as "[nameOrID:]path". Colons in paths are supported as long +// they start with a dot or slash. +func parseUserInput(input string) (container string, path string) { + if len(input) == 0 { + return + } + path = input + + // If the input starts with a dot or slash, it cannot refer to a + // container. + if input[0] == '.' || input[0] == '/' { + return + } + + if spl := strings.SplitN(path, ":", 2); len(spl) == 2 { + container = spl[0] + path = spl[1] + } + return +} diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go index 9409df743..362053cce 100644 --- a/pkg/domain/infra/abi/cp.go +++ b/pkg/domain/infra/abi/cp.go @@ -2,46 +2,53 @@ package abi import ( "context" - "strings" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/pkg/copy" "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/pkg/errors" ) func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error { - srcCtr, srcPath := parsePath(ic.Libpod, source) - destCtr, destPath := parsePath(ic.Libpod, dest) - - if srcCtr != nil && destCtr != nil { - return errors.Errorf("invalid arguments %q, %q: you must use just one container", source, dest) + // Parse user input. + sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(source, dest) + if err != nil { + return err } - if srcCtr == nil && destCtr == nil { - return errors.Errorf("invalid arguments %q, %q: you must specify one container", source, dest) + + // Look up containers. + var sourceContainer, destContainer *libpod.Container + if len(sourceContainerStr) > 0 { + sourceContainer, err = ic.Libpod.LookupContainer(sourceContainerStr) + if err != nil { + return err + } } - if len(srcPath) == 0 || len(destPath) == 0 { - return errors.Errorf("invalid arguments %q, %q: you must specify paths", source, dest) + if len(destContainerStr) > 0 { + destContainer, err = ic.Libpod.LookupContainer(destContainerStr) + if err != nil { + return err + } } var sourceItem, destinationItem copy.CopyItem - var err error - // Copy from the container to the host. - if srcCtr != nil { - sourceItem, err = copy.CopyItemForContainer(srcCtr, srcPath, options.Pause, true) + + // Source ... container OR host. + if sourceContainer != nil { + sourceItem, err = copy.CopyItemForContainer(sourceContainer, sourcePath, options.Pause, true) defer sourceItem.CleanUp() if err != nil { return err } } else { - sourceItem, err = copy.CopyItemForHost(srcPath, true) + sourceItem, err = copy.CopyItemForHost(sourcePath, true) if err != nil { return err } } - if destCtr != nil { - destinationItem, err = copy.CopyItemForContainer(destCtr, destPath, options.Pause, false) + // Destination ... container OR host. + if destContainer != nil { + destinationItem, err = copy.CopyItemForContainer(destContainer, destPath, options.Pause, false) defer destinationItem.CleanUp() if err != nil { return err @@ -55,22 +62,9 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, } // Copy from the host to the container. - return copy.Copy(&sourceItem, &destinationItem, options.Extract) -} - -func parsePath(runtime *libpod.Runtime, path string) (*libpod.Container, string) { - if len(path) == 0 { - return nil, "" - } - if path[0] == '.' || path[0] == '/' { // A path cannot point to a container. - return nil, path - } - pathArr := strings.SplitN(path, ":", 2) - if len(pathArr) == 2 { - ctr, err := runtime.LookupContainer(pathArr[0]) - if err == nil { - return ctr, pathArr[1] - } + copier, err := copy.GetCopier(&sourceItem, &destinationItem, options.Extract) + if err != nil { + return err } - return nil, path + return copier.Copy() } diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index ad7128b42..600d64b1d 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -54,7 +54,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte } return buf, nil // no return if local image is not a list of images type - // continue on getting valid manifest through remote serice + // continue on getting valid manifest through remote service } else if errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported { return nil, errors.Wrapf(err, "loading manifest %q", name) } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 3584668c7..e65fef0a4 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -732,7 +732,8 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o } func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error { - return errors.New("not implemented") + return nil + // return containers.Copy(ic.ClientCxt, source, dest, options) } // Shutdown Libpod engine diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go index 2ef0f4c23..bb8edabb7 100644 --- a/pkg/specgen/generate/kube/volume.go +++ b/pkg/specgen/generate/kube/volume.go @@ -103,7 +103,7 @@ func VolumeFromSource(volumeSource v1.VolumeSource) (*KubeVolume, error) { } else if volumeSource.PersistentVolumeClaim != nil { return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim) } else { - return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the conly supported VolumeSource") + return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the only supported VolumeSource") } } diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 22db8be8a..5f38c34a1 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -12,22 +12,11 @@ # load helpers -# run 'podman help', parse the output looking for 'Available Commands'; -# return that list. -function podman_commands() { - dprint "$@" - run_podman help "$@" |\ - awk '/^Available Commands:/{ok=1;next}/^Options:/{ok=0}ok { print $1 }' |\ - grep . - "$output" -} - - function check_help() { local count=0 local -A found - for cmd in $(podman_commands "$@"); do + for cmd in $(_podman_commands "$@"); do # Human-readable podman command string, with multiple spaces collapsed command_string="podman $* $cmd" command_string=${command_string// / } # 'podman x' -> 'podman x' diff --git a/test/system/070-build.bats b/test/system/070-build.bats index 59da503a6..8e9a2d613 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -381,6 +381,48 @@ a${random3}z" run_podman rmi -f build_test } +@test "podman build --layers test" { + rand_content=$(random_string 50) + tmpdir=$PODMAN_TMPDIR/build-test + run mkdir -p $tmpdir + containerfile=$tmpdir/Containerfile + cat >$containerfile <<EOF +FROM $IMAGE +RUN echo $rand_content +EOF + + # Build twice to make sure second time uses cache + run_podman build -t build_test $tmpdir + if [[ "$output" =~ "Using cache" ]]; then + is "$output" "[no instance of 'Using cache']" "no cache used" + fi + + run_podman build -t build_test $tmpdir + is "$output" ".*cache" "used cache" + + run_podman build -t build_test --layers=true $tmpdir + is "$output" ".*cache" "used cache" + + run_podman build -t build_test --layers=false $tmpdir + if [[ "$output" =~ "Using cache" ]]; then + is "$output" "[no instance of 'Using cache']" "no cache used" + fi + + BUILDAH_LAYERS=false run_podman build -t build_test $tmpdir + if [[ "$output" =~ "Using cache" ]]; then + is "$output" "[no instance of 'Using cache']" "no cache used" + fi + + BUILDAH_LAYERS=false run_podman build -t build_test --layers=1 $tmpdir + is "$output" ".*cache" "used cache" + + BUILDAH_LAYERS=1 run_podman build -t build_test --layers=false $tmpdir + if [[ "$output" =~ "Using cache" ]]; then + is "$output" "[no instance of 'Using cache']" "no cache used" + fi + + run_podman rmi -a --force +} function teardown() { # A timeout or other error in 'build' can leave behind stale images diff --git a/test/system/600-completion.bats b/test/system/600-completion.bats new file mode 100644 index 000000000..1e43cdc41 --- /dev/null +++ b/test/system/600-completion.bats @@ -0,0 +1,272 @@ +#!/usr/bin/env bats -*- bats -*- +# +# Test podman shell completion +# +# Shell completion is provided via the cobra library +# It is implement by calling a hidden subcommand called "__complete" +# + +load helpers + +function check_shell_completion() { + local count=0 + + # Newline character; used for confirming string output + local nl=" +" + + for cmd in $(_podman_commands "$@"); do + # Human-readable podman command string, with multiple spaces collapsed + name="podman" + if is_remote; then + name="podman-remote" + fi + command_string="$name $* $cmd" + command_string=${command_string// / } # 'podman x' -> 'podman x' + + run_podman "$@" $cmd --help + local full_help="$output" + + # The line immediately after 'Usage:' gives us a 1-line synopsis + usage=$(echo "$full_help" | grep -A1 '^Usage:' | tail -1) + [ -n "$usage" ] || die "podman $cmd: no Usage message found" + + # If usage ends in '[command]', recurse into subcommands + if expr "$usage" : '.*\[command\]$' >/dev/null; then + check_shell_completion "$@" $cmd + continue + fi + + # Trim to command path so we only have the args + args="${usage/$command_string/}" + # Trim leading whitespaces + args="${args#"${args%%[![:space:]]*}"}" + + # Extra args is used to match the correct argument number for the command + # This is important because some commands provide different suggestions based + # on the number of arguments. + extra_args=() + + for arg in $args; do + + match=false + i=0 + while true; do + + case $arg in + + # If we have options than we need to check if we are getting flag completion + "[options]") + # skip this for remote it fails if a command only has the latest flag e.g podman top + if ! is_remote; then + run_completion "$@" $cmd "--" + # If this fails there is most likely a problem with the cobra library + is "${lines[0]}" "--.*" "Found flag in suggestions" + [ ${#lines[@]} -gt 2 ] || die "No flag suggestions" + _check_completion_end NoFileComp + fi + # continue the outer for args loop + continue 2 + ;; + + *CONTAINER*) + run_completion "$@" $cmd "${extra_args[@]}" "" + is "$output" ".*-$random_container_name${nl}" "Found expected container in suggestions" + + match=true + # resume + ;;& + + *POD*) + run_completion "$@" $cmd "${extra_args[@]}" "" + is "$output" ".*-$random_pod_name${nl}" "Found expected pod in suggestions" + _check_completion_end NoFileComp + + match=true + # resume + ;;& + + *IMAGE*) + run_completion "$@" $cmd "${extra_args[@]}" "" + is "$output" ".*localhost/$random_image_name:$random_image_tag${nl}" "Found expected image in suggestions" + + # check that we complete the image with and without tag after at least one char is typed + run_completion "$@" $cmd "${extra_args[@]}" "${random_image_name:0:1}" + is "$output" ".*$random_image_name:$random_image_tag${nl}" "Found expected image with tag in suggestions" + is "$output" ".*$random_image_name${nl}" "Found expected image without tag in suggestions" + + # check that we complete the image id after at least two chars are typed + run_completion "$@" $cmd "${extra_args[@]}" "${random_image_id:0:2}" + is "$output" ".*$random_image_id${nl}" "Found expected image id in suggestions" + + match=true + # resume + ;;& + + *NETWORK*) + run_completion "$@" $cmd "${extra_args[@]}" "" + is "$output" ".*$random_network_name${nl}" "Found network in suggestions" + _check_completion_end NoFileComp + + match=true + # resume + ;;& + + *VOLUME*) + run_completion "$@" $cmd "${extra_args[@]}" "" + is "$output" ".*$random_volume_name${nl}" "Found volume in suggestions" + _check_completion_end NoFileComp + + match=true + # resume + ;;& + + *REGISTRY*) + run_completion "$@" $cmd "${extra_args[@]}" "" + ### FIXME how can we get the configured registries? + _check_completion_end NoFileComp + ### FIXME this fails if no registries are configured + [[ ${#lines[@]} -gt 2 ]] || die "No registries found in suggestions" + + match=true + # resume + ;;& + + *PATH* | *CONTEXT* | *KUBEFILE* | *COMMAND* | *ARG...* | *URI*) + # default shell completion should be done for everthing which accepts a path + run_completion "$@" $cmd "${extra_args[@]}" "" + + # cp is a special case it returns ShellCompDirectiveNoSpace + if [[ "$cmd" == "cp" ]]; then + _check_completion_end NoSpace + else + _check_completion_end Default + [[ ${#lines[@]} -eq 2 ]] || die "Suggestions are in the output" + fi + ;; + + *) + if [[ "$match" == "false" ]]; then + dprint "UNKNOWN arg: $arg for $command_string ${extra_args[*]}" + fi + ;; + + esac + + # Increment the argument array + extra_args+=("arg") + + i=$(($i + 1)) + # If the argument ends with ...] than we accept 0...n args + # Loop three times to make sure we are not only completing the first arg + if [[ ! ${arg} =~ "..." ]] || [[ i -gt 3 ]]; then + break + fi + + done + + done + + # If the command takes no more parameters make sure we are getting no completion + if [[ ! ${args##* } =~ "..." ]]; then + run_completion "$@" $cmd "${extra_args[@]}" "" + _check_completion_end NoFileComp + if [ ${#lines[@]} -gt 2 ]; then + # checking for line count is not enough since we may inlcude additional debug output + # lines starting with [Debug] are allowed + i=0 + length=$(( ${#lines[@]} - 2 )) + while [[ i -lt length ]]; do + [[ "${lines[$i]:0:7}" == "[Debug]" ]] || die "Suggestions are in the output" + i=$(( i + 1 )) + done + fi + fi + + done + +} + +# run the completion cmd +function run_completion() { + PODMAN="$PODMAN_COMPLETION" run_podman "$@" +} + +# check for the given ShellCompDirective (always last line) +function _check_completion_end() { + is "${lines[-1]}" "Completion ended with directive: ShellCompDirective$1" "Completion has wrong ShellCompDirective set" +} + + +@test "podman shell completion test" { + + random_container_name=$(random_string 30) + random_pod_name=$(random_string 30) + random_image_name=$(random_string 30) + random_image_name=${random_image_name,,} # name must be lowercase + random_image_tag=$(random_string 5) + random_network_name=$(random_string 30) + random_volume_name=$(random_string 30) + + # create a container for each state since some commands are only suggesting running container for example + run_podman create --name created-$random_container_name $IMAGE + run_podman run --name running-$random_container_name -d $IMAGE top + run_podman run --name pause-$random_container_name -d $IMAGE top + run_podman pause pause-$random_container_name + run_podman run --name exited-$random_container_name -d $IMAGE echo exited + + # create pods for each state + run_podman pod create --name created-$random_pod_name + run_podman pod create --name running-$random_pod_name + run_podman run -d --name running-$random_pod_name-con --pod running-$random_pod_name $IMAGE top + run_podman pod create --name degraded-$random_pod_name + run_podman run -d --name degraded-$random_pod_name-con --pod degraded-$random_pod_name $IMAGE echo degraded + run_podman pod create --name exited-$random_pod_name + run_podman run -d --name exited-$random_pod_name-con --pod exited-$random_pod_name $IMAGE echo exited + run_podman pod stop exited-$random_pod_name + + # create image name (just tag with new names no need to pull) + run_podman image tag $IMAGE $random_image_name:$random_image_tag + run_podman image list --format '{{.ID}}' --filter reference=$random_image_name + random_image_id="${lines[0]}" + + # create network + run_podman network create $random_network_name + + # create volume + run_podman volume create $random_volume_name + + + # $PODMAN may be a space-separated string, e.g. if we include a --url. + local -a podman_as_array=($PODMAN) + # __completeNoDesc must be the first arg if we running the completion cmd + PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}" + + # Called with no args -- start with 'podman --help'. check_shell_completion() will + # recurse for any subcommands. + check_shell_completion + + # cleanup + run_podman volume rm $random_volume_name + + run_podman network rm $random_network_name + + run_podman image untag $IMAGE $random_image_name:$random_image_tag + + for state in created running degraded exited; do + run_podman pod rm --force $state-$random_pod_name + done + + for state in created running pause exited; do + run_podman rm --force $state-$random_container_name + done + + # Clean up the pod pause image + run_podman image list --format '{{.ID}} {{.Repository}}' + while read id name; do + if [[ "$name" =~ /pause ]]; then + run_podman rmi $id + fi + done <<<"$output" + +} diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 2cced10c2..6a7c6cc42 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -521,5 +521,15 @@ function remove_same_dev_warning() { output=$(printf '%s\n' "${lines[@]}") } +# run 'podman help', parse the output looking for 'Available Commands'; +# return that list. +function _podman_commands() { + dprint "$@" + run_podman help "$@" | + awk '/^Available Commands:/{ok=1;next}/^Options:/{ok=0}ok { print $1 }' | + grep . + "$output" +} + # END miscellaneous tools ############################################################################### diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml index e250be4ac..348e3014c 100644 --- a/vendor/github.com/onsi/gomega/.travis.yml +++ b/vendor/github.com/onsi/gomega/.travis.yml @@ -1,4 +1,7 @@ language: go +arch: + - amd64 + - ppc64le go: - 1.14.x diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md index 940953394..0f1765d84 100644 --- a/vendor/github.com/onsi/gomega/CHANGELOG.md +++ b/vendor/github.com/onsi/gomega/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.10.4 + +### Fixes +- update golang net library to more recent version without vulnerability (#406) [817a8b9] +- Correct spelling: alloted -> allotted (#403) [0bae715] +- fix a panic in MessageWithDiff with long message (#402) [ea06b9b] + ## 1.10.3 ### Fixes diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go index fae25adce..e59d7d75b 100644 --- a/vendor/github.com/onsi/gomega/format/format.go +++ b/vendor/github.com/onsi/gomega/format/format.go @@ -105,7 +105,13 @@ func MessageWithDiff(actual, message, expected string) string { tabLength := 4 spaceFromMessageToActual := tabLength + len("<string>: ") - len(message) - padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|" + + paddingCount := spaceFromMessageToActual + spacesBeforeFormattedMismatch + if paddingCount < 0 { + return Message(formattedActual, message, formattedExpected) + } + + padding := strings.Repeat(" ", paddingCount) + "|" return Message(formattedActual, message+padding, formattedExpected) } diff --git a/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go b/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go index 3caed8769..a41ad6232 100644 --- a/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go +++ b/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go @@ -9,17 +9,17 @@ import ( // ErrTimeout is returned by TimeoutCloser, TimeoutReader, and TimeoutWriter when the underlying Closer/Reader/Writer does not return within the specified timeout var ErrTimeout = errors.New("timeout occurred") -// TimeoutCloser returns an io.Closer that wraps the passed-in io.Closer. If the underlying Closer fails to close within the alloted timeout ErrTimeout is returned. +// TimeoutCloser returns an io.Closer that wraps the passed-in io.Closer. If the underlying Closer fails to close within the allotted timeout ErrTimeout is returned. func TimeoutCloser(c io.Closer, timeout time.Duration) io.Closer { return timeoutReaderWriterCloser{c: c, d: timeout} } -// TimeoutReader returns an io.Reader that wraps the passed-in io.Reader. If the underlying Reader fails to read within the alloted timeout ErrTimeout is returned. +// TimeoutReader returns an io.Reader that wraps the passed-in io.Reader. If the underlying Reader fails to read within the allotted timeout ErrTimeout is returned. func TimeoutReader(r io.Reader, timeout time.Duration) io.Reader { return timeoutReaderWriterCloser{r: r, d: timeout} } -// TimeoutWriter returns an io.Writer that wraps the passed-in io.Writer. If the underlying Writer fails to write within the alloted timeout ErrTimeout is returned. +// TimeoutWriter returns an io.Writer that wraps the passed-in io.Writer. If the underlying Writer fails to write within the allotted timeout ErrTimeout is returned. func TimeoutWriter(w io.Writer, timeout time.Duration) io.Writer { return timeoutReaderWriterCloser{w: w, d: timeout} } diff --git a/vendor/github.com/onsi/gomega/go.mod b/vendor/github.com/onsi/gomega/go.mod index 0a80d5ec3..02b99ab60 100644 --- a/vendor/github.com/onsi/gomega/go.mod +++ b/vendor/github.com/onsi/gomega/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/golang/protobuf v1.4.2 github.com/onsi/ginkgo v1.12.1 - golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 + golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 gopkg.in/yaml.v2 v2.3.0 ) diff --git a/vendor/github.com/onsi/gomega/go.sum b/vendor/github.com/onsi/gomega/go.sum index c54e9b88e..fc230153b 100644 --- a/vendor/github.com/onsi/gomega/go.sum +++ b/vendor/github.com/onsi/gomega/go.sum @@ -31,6 +31,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dD golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= @@ -42,6 +44,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwg golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go index 4af1a8c01..a8529f1ca 100644 --- a/vendor/github.com/onsi/gomega/gomega_dsl.go +++ b/vendor/github.com/onsi/gomega/gomega_dsl.go @@ -24,7 +24,7 @@ import ( "github.com/onsi/gomega/types" ) -const GOMEGA_VERSION = "1.10.3" +const GOMEGA_VERSION = "1.10.4" const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil. If you're using Ginkgo then you probably forgot to put your assertion in an It(). diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go index 10ac15a85..988adc8f4 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go @@ -27,14 +27,14 @@ var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be use // the container. A list of options can be passed into this function to alter // the labels. The labels returned will include a random MCS String, that is // guaranteed to be unique. -func InitLabels(options []string) (plabel string, mlabel string, Err error) { +func InitLabels(options []string) (plabel string, mlabel string, retErr error) { if !selinux.GetEnabled() { return "", "", nil } processLabel, mountLabel := selinux.ContainerLabels() if processLabel != "" { defer func() { - if Err != nil { + if retErr != nil { selinux.ReleaseLabel(mountLabel) } }() @@ -57,7 +57,6 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) { con := strings.SplitN(opt, ":", 2) if !validOptions[con[0]] { return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) - } if con[0] == "filetype" { mcon["type"] = con[1] diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go index 50760dc93..d9119908b 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go @@ -30,6 +30,11 @@ var ( // ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level ErrLevelSyntax = errors.New("invalid level syntax") + // ErrContextMissing is returned if a requested context is not found in a file. + ErrContextMissing = errors.New("context does not have a match") + // ErrVerifierNil is returned when a context verifier function is nil. + ErrVerifierNil = errors.New("verifier function is nil") + // CategoryRange allows the upper bound on the category range to be adjusted CategoryRange = DefaultCategoryRange ) @@ -63,8 +68,12 @@ func FileLabel(fpath string) (string, error) { return fileLabel(fpath) } -// SetFSCreateLabel tells kernel the label to create all file system objects -// created by this task. Setting label="" to return to default. +// SetFSCreateLabel tells the kernel what label to use for all file system objects +// created by this task. +// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until file system +// objects created by this task are finished to guarantee another goroutine does not migrate +// to the current thread before execution is complete. func SetFSCreateLabel(label string) error { return setFSCreateLabel(label) } @@ -113,19 +122,27 @@ func CalculateGlbLub(sourceRange, targetRange string) (string, error) { } // SetExecLabel sets the SELinux label that the kernel will use for any programs -// that are executed by the current process thread, or an error. +// that are executed by the current process thread, or an error. Calls to SetExecLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until execution +// of the program is finished to guarantee another goroutine does not migrate to the current +// thread before execution is complete. func SetExecLabel(label string) error { return setExecLabel(label) } // SetTaskLabel sets the SELinux label for the current thread, or an error. -// This requires the dyntransition permission. +// This requires the dyntransition permission. Calls to SetTaskLabel should +// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee +// the current thread does not run in a new mislabeled thread. func SetTaskLabel(label string) error { return setTaskLabel(label) } // SetSocketLabel takes a process label and tells the kernel to assign the -// label to the next socket that gets created +// label to the next socket that gets created. Calls to SetSocketLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until +// the the socket is created to guarantee another goroutine does not migrate +// to the current thread before execution is complete. func SetSocketLabel(label string) error { return setSocketLabel(label) } @@ -141,7 +158,10 @@ func PeerLabel(fd uintptr) (string, error) { } // SetKeyLabel takes a process label and tells the kernel to assign the -// label to the next kernel keyring that gets created +// label to the next kernel keyring that gets created. Calls to SetKeyLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until +// the kernel keyring is created to guarantee another goroutine does not migrate +// to the current thread before execution is complete. func SetKeyLabel(label string) error { return setKeyLabel(label) } @@ -247,3 +267,12 @@ func DupSecOpt(src string) ([]string, error) { func DisableSecOpt() []string { return disableSecOpt() } + +// GetDefaultContextWithLevel gets a single context for the specified SELinux user +// identity that is reachable from the specified scon context. The context is based +// on the per-user /etc/selinux/{SELINUXTYPE}/contexts/users/<username> if it exists, +// and falls back to the global /etc/selinux/{SELINUXTYPE}/contexts/default_contexts +// file. +func GetDefaultContextWithLevel(user, level, scon string) (string, error) { + return getDefaultContextWithLevel(user, level, scon) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index d6b0d49db..904f5b04f 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -28,6 +28,8 @@ const ( minSensLen = 2 contextFile = "/usr/share/containers/selinux/contexts" selinuxDir = "/etc/selinux/" + selinuxUsersDir = "contexts/users" + defaultContexts = "contexts/default_contexts" selinuxConfig = selinuxDir + "config" selinuxfsMount = "/sys/fs/selinux" selinuxTypeTag = "SELINUXTYPE" @@ -35,6 +37,8 @@ const ( xattrNameSelinux = "security.selinux" ) +var policyRoot = filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) + type selinuxState struct { enabledSet bool enabled bool @@ -54,6 +58,13 @@ type mlsRange struct { high *level } +type defaultSECtx struct { + user, level, scon string + userRdr, defaultRdr io.Reader + + verifier func(string) error +} + type levelItem byte const ( @@ -111,7 +122,7 @@ func verifySELinuxfsMount(mnt string) bool { if err == nil { break } - if err == unix.EAGAIN { + if err == unix.EAGAIN || err == unix.EINTR { continue } return false @@ -205,28 +216,16 @@ func getEnabled() bool { } func readConfig(target string) string { - var ( - val, key string - bufin *bufio.Reader - ) - in, err := os.Open(selinuxConfig) if err != nil { return "" } defer in.Close() - bufin = bufio.NewReader(in) + scanner := bufio.NewScanner(in) - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err != io.EOF { - return "" - } - done = true - } - line = strings.TrimSpace(line) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) if len(line) == 0 { // Skip blank lines continue @@ -236,7 +235,7 @@ func readConfig(target string) string { continue } if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) + key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) if key == target { return strings.Trim(val, "\"") } @@ -245,15 +244,17 @@ func readConfig(target string) string { return "" } -func getSELinuxPolicyRoot() string { - return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) -} - func isProcHandle(fh *os.File) error { var buf unix.Statfs_t - err := unix.Fstatfs(int(fh.Fd()), &buf) - if err != nil { - return errors.Wrapf(err, "statfs(%q) failed", fh.Name()) + + for { + err := unix.Fstatfs(int(fh.Fd()), &buf) + if err == nil { + break + } + if err != unix.EINTR { + return errors.Wrapf(err, "statfs(%q) failed", fh.Name()) + } } if buf.Type != unix.PROC_SUPER_MAGIC { return errors.Errorf("file %q is not on procfs", fh.Name()) @@ -307,9 +308,16 @@ func setFileLabel(fpath string, label string) error { if fpath == "" { return ErrEmptyPath } - if err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil { - return errors.Wrapf(err, "failed to set file label on %s", fpath) + for { + err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0) + if err == nil { + break + } + if err != unix.EINTR { + return errors.Wrapf(err, "failed to set file label on %s", fpath) + } } + return nil } @@ -751,7 +759,7 @@ func reserveLabel(label string) { if len(label) != 0 { con := strings.SplitN(label, ":", 4) if len(con) > 3 { - mcsAdd(con[3]) + _ = mcsAdd(con[3]) } } } @@ -828,11 +836,11 @@ func intToMcs(id int, catRange uint32) string { } for ORD > TIER { - ORD = ORD - TIER + ORD -= TIER TIER-- } TIER = SETSIZE - TIER - ORD = ORD + TIER + ORD += TIER return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) } @@ -844,16 +852,14 @@ func uniqMcs(catRange uint32) string { ) for { - binary.Read(rand.Reader, binary.LittleEndian, &n) + _ = binary.Read(rand.Reader, binary.LittleEndian, &n) c1 = n % catRange - binary.Read(rand.Reader, binary.LittleEndian, &n) + _ = binary.Read(rand.Reader, binary.LittleEndian, &n) c2 = n % catRange if c1 == c2 { continue - } else { - if c1 > c2 { - c1, c2 = c2, c1 - } + } else if c1 > c2 { + c1, c2 = c2, c1 } mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) if err := mcsAdd(mcs); err != nil { @@ -884,18 +890,13 @@ func openContextFile() (*os.File, error) { if f, err := os.Open(contextFile); err == nil { return f, nil } - lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts") + lxcPath := filepath.Join(policyRoot, "/contexts/lxc_contexts") return os.Open(lxcPath) } var labels = loadLabels() func loadLabels() map[string]string { - var ( - val, key string - bufin *bufio.Reader - ) - labels := make(map[string]string) in, err := openContextFile() if err != nil { @@ -903,18 +904,10 @@ func loadLabels() map[string]string { } defer in.Close() - bufin = bufio.NewReader(in) + scanner := bufio.NewScanner(in) - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err == io.EOF { - done = true - } else { - break - } - } - line = strings.TrimSpace(line) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) if len(line) == 0 { // Skip blank lines continue @@ -924,7 +917,7 @@ func loadLabels() map[string]string { continue } if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) + key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) labels[key] = strings.Trim(val, "\"") } } @@ -1015,7 +1008,7 @@ func copyLevel(src, dest string) (string, error) { return "", err } mcsDelete(tcon["level"]) - mcsAdd(scon["level"]) + _ = mcsAdd(scon["level"]) tcon["level"] = scon["level"] return tcon.Get(), nil } @@ -1095,3 +1088,124 @@ func dupSecOpt(src string) ([]string, error) { func disableSecOpt() []string { return []string{"disable"} } + +// findUserInContext scans the reader for a valid SELinux context +// match that is verified with the verifier. Invalid contexts are +// skipped. It returns a matched context or an empty string if no +// match is found. If a scanner error occurs, it is returned. +func findUserInContext(context Context, r io.Reader, verifier func(string) error) (string, error) { + fromRole := context["role"] + fromType := context["type"] + scanner := bufio.NewScanner(r) + + for scanner.Scan() { + fromConns := strings.Fields(scanner.Text()) + if len(fromConns) == 0 { + // Skip blank lines + continue + } + + line := fromConns[0] + + if line[0] == ';' || line[0] == '#' { + // Skip comments + continue + } + + // user context files contexts are formatted as + // role_r:type_t:s0 where the user is missing. + lineArr := strings.SplitN(line, ":", 4) + // skip context with typo, or role and type do not match + if len(lineArr) != 3 || + lineArr[0] != fromRole || + lineArr[1] != fromType { + continue + } + + for _, cc := range fromConns[1:] { + toConns := strings.SplitN(cc, ":", 4) + if len(toConns) != 3 { + continue + } + + context["role"] = toConns[0] + context["type"] = toConns[1] + + outConn := context.get() + if err := verifier(outConn); err != nil { + continue + } + + return outConn, nil + } + } + + if err := scanner.Err(); err != nil { + return "", errors.Wrap(err, "failed to scan for context") + } + + return "", nil +} + +func getDefaultContextFromReaders(c *defaultSECtx) (string, error) { + if c.verifier == nil { + return "", ErrVerifierNil + } + + context, err := newContext(c.scon) + if err != nil { + return "", errors.Wrapf(err, "failed to create label for %s", c.scon) + } + + // set so the verifier validates the matched context with the provided user and level. + context["user"] = c.user + context["level"] = c.level + + conn, err := findUserInContext(context, c.userRdr, c.verifier) + if err != nil { + return "", err + } + + if conn != "" { + return conn, nil + } + + conn, err = findUserInContext(context, c.defaultRdr, c.verifier) + if err != nil { + return "", err + } + + if conn != "" { + return conn, nil + } + + return "", errors.Wrapf(ErrContextMissing, "context not found: %q", c.scon) +} + +func getDefaultContextWithLevel(user, level, scon string) (string, error) { + userPath := filepath.Join(policyRoot, selinuxUsersDir, user) + defaultPath := filepath.Join(policyRoot, defaultContexts) + + fu, err := os.Open(userPath) + if err != nil { + return "", err + } + defer fu.Close() + + fd, err := os.Open(defaultPath) + if err != nil { + return "", err + } + defer fd.Close() + + c := defaultSECtx{ + user: user, + level: level, + scon: scon, + userRdr: fu, + defaultRdr: fd, + verifier: securityCheckContext, + } + + return getDefaultContextFromReaders(&c) +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go index c526b210f..e4b65c9e2 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -146,3 +146,7 @@ func dupSecOpt(src string) ([]string, error) { func disableSecOpt() []string { return []string{"disable"} } + +func getDefaultContextWithLevel(user, level, scon string) (string, error) { + return "", nil +} diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go index de5c80ef3..2365b4bda 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/xattrs.go @@ -6,21 +6,21 @@ import ( "golang.org/x/sys/unix" ) -// Returns a []byte slice if the xattr is set and nil otherwise -// Requires path and its attribute as arguments -func lgetxattr(path string, attr string) ([]byte, error) { +// lgetxattr returns a []byte slice containing the value of +// an extended attribute attr set for path. +func lgetxattr(path, attr string) ([]byte, error) { // Start with a 128 length byte array dest := make([]byte, 128) - sz, errno := unix.Lgetxattr(path, attr, dest) + sz, errno := doLgetxattr(path, attr, dest) for errno == unix.ERANGE { // Buffer too small, use zero-sized buffer to get the actual size - sz, errno = unix.Lgetxattr(path, attr, []byte{}) + sz, errno = doLgetxattr(path, attr, []byte{}) if errno != nil { return nil, errno } dest = make([]byte, sz) - sz, errno = unix.Lgetxattr(path, attr, dest) + sz, errno = doLgetxattr(path, attr, dest) } if errno != nil { return nil, errno @@ -28,3 +28,13 @@ func lgetxattr(path string, attr string) ([]byte, error) { return dest[:sz], nil } + +// doLgetxattr is a wrapper that retries on EINTR +func doLgetxattr(path, attr string, dest []byte) (int, error) { + for { + sz, err := unix.Lgetxattr(path, attr, dest) + if err != unix.EINTR { + return sz, err + } + } +} diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go index 63fde1842..437b12b3e 100644 --- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go +++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go @@ -20,17 +20,16 @@ type WalkFunc = filepath.WalkFunc // // Note that this implementation only supports primitive error handling: // -// * no errors are ever passed to WalkFn +// - no errors are ever passed to WalkFn; // -// * once a walkFn returns any error, all further processing stops -// and the error is returned to the caller of Walk; +// - once a walkFn returns any error, all further processing stops +// and the error is returned to the caller of Walk; // -// * filepath.SkipDir is not supported; -// -// * if more than one walkFn instance will return an error, only one -// of such errors will be propagated and returned by Walk, others -// will be silently discarded. +// - filepath.SkipDir is not supported; // +// - if more than one walkFn instance will return an error, only one +// of such errors will be propagated and returned by Walk, others +// will be silently discarded. func Walk(root string, walkFn WalkFunc) error { return WalkN(root, walkFn, runtime.NumCPU()*2) } @@ -38,6 +37,8 @@ func Walk(root string, walkFn WalkFunc) error { // WalkN is a wrapper for filepath.Walk which can call multiple walkFn // in parallel, allowing to handle each item concurrently. A maximum of // num walkFn will be called at any one time. +// +// Please see Walk documentation for caveats of using this function. func WalkN(root string, walkFn WalkFunc, num int) error { // make sure limit is sensible if num < 1 { diff --git a/vendor/github.com/willf/bitset/Makefile b/vendor/github.com/willf/bitset/Makefile deleted file mode 100644 index db8377106..000000000 --- a/vendor/github.com/willf/bitset/Makefile +++ /dev/null @@ -1,191 +0,0 @@ -# MAKEFILE -# -# @author Nicola Asuni <info@tecnick.com> -# @link https://github.com/willf/bitset -# ------------------------------------------------------------------------------ - -# List special make targets that are not associated with files -.PHONY: help all test format fmtcheck vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan qa deps clean nuke - -# Use bash as shell (Note: Ubuntu now uses dash which doesn't support PIPESTATUS). -SHELL=/bin/bash - -# CVS path (path to the parent dir containing the project) -CVSPATH=github.com/willf - -# Project owner -OWNER=willf - -# Project vendor -VENDOR=willf - -# Project name -PROJECT=bitset - -# Project version -VERSION=$(shell cat VERSION) - -# Name of RPM or DEB package -PKGNAME=${VENDOR}-${PROJECT} - -# Current directory -CURRENTDIR=$(shell pwd) - -# GO lang path -ifneq ($(GOPATH),) - ifeq ($(findstring $(GOPATH),$(CURRENTDIR)),) - # the defined GOPATH is not valid - GOPATH= - endif -endif -ifeq ($(GOPATH),) - # extract the GOPATH - GOPATH=$(firstword $(subst /src/, ,$(CURRENTDIR))) -endif - -# --- MAKE TARGETS --- - -# Display general help about this command -help: - @echo "" - @echo "$(PROJECT) Makefile." - @echo "GOPATH=$(GOPATH)" - @echo "The following commands are available:" - @echo "" - @echo " make qa : Run all the tests" - @echo " make test : Run the unit tests" - @echo "" - @echo " make format : Format the source code" - @echo " make fmtcheck : Check if the source code has been formatted" - @echo " make vet : Check for suspicious constructs" - @echo " make lint : Check for style errors" - @echo " make coverage : Generate the coverage report" - @echo " make cyclo : Generate the cyclomatic complexity report" - @echo " make ineffassign : Detect ineffectual assignments" - @echo " make misspell : Detect commonly misspelled words in source files" - @echo " make structcheck : Find unused struct fields" - @echo " make varcheck : Find unused global variables and constants" - @echo " make errcheck : Check that error return values are used" - @echo " make gosimple : Suggest code simplifications" - @echo " make astscan : GO AST scanner" - @echo "" - @echo " make docs : Generate source code documentation" - @echo "" - @echo " make deps : Get the dependencies" - @echo " make clean : Remove any build artifact" - @echo " make nuke : Deletes any intermediate file" - @echo "" - -# Alias for help target -all: help - -# Run the unit tests -test: - @mkdir -p target/test - @mkdir -p target/report - GOPATH=$(GOPATH) \ - go test \ - -covermode=atomic \ - -bench=. \ - -race \ - -cpuprofile=target/report/cpu.out \ - -memprofile=target/report/mem.out \ - -mutexprofile=target/report/mutex.out \ - -coverprofile=target/report/coverage.out \ - -v ./... | \ - tee >(PATH=$(GOPATH)/bin:$(PATH) go-junit-report > target/test/report.xml); \ - test $${PIPESTATUS[0]} -eq 0 - -# Format the source code -format: - @find . -type f -name "*.go" -exec gofmt -s -w {} \; - -# Check if the source code has been formatted -fmtcheck: - @mkdir -p target - @find . -type f -name "*.go" -exec gofmt -s -d {} \; | tee target/format.diff - @test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; } - -# Check for syntax errors -vet: - GOPATH=$(GOPATH) go vet . - -# Check for style errors -lint: - GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint . - -# Generate the coverage report -coverage: - @mkdir -p target/report - GOPATH=$(GOPATH) \ - go tool cover -html=target/report/coverage.out -o target/report/coverage.html - -# Report cyclomatic complexity -cyclo: - @mkdir -p target/report - GOPATH=$(GOPATH) gocyclo -avg ./ | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0 - -# Detect ineffectual assignments -ineffassign: - @mkdir -p target/report - GOPATH=$(GOPATH) ineffassign ./ | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0 - -# Detect commonly misspelled words in source files -misspell: - @mkdir -p target/report - GOPATH=$(GOPATH) misspell -error ./ | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0 - -# Find unused struct fields -structcheck: - @mkdir -p target/report - GOPATH=$(GOPATH) structcheck -a ./ | tee target/report/structcheck.txt - -# Find unused global variables and constants -varcheck: - @mkdir -p target/report - GOPATH=$(GOPATH) varcheck -e ./ | tee target/report/varcheck.txt - -# Check that error return values are used -errcheck: - @mkdir -p target/report - GOPATH=$(GOPATH) errcheck ./ | tee target/report/errcheck.txt - -# AST scanner -astscan: - @mkdir -p target/report - GOPATH=$(GOPATH) gosec . | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 || true - -# Generate source docs -docs: - @mkdir -p target/docs - nohup sh -c 'GOPATH=$(GOPATH) godoc -http=127.0.0.1:6060' > target/godoc_server.log 2>&1 & - wget --directory-prefix=target/docs/ --execute robots=off --retry-connrefused --recursive --no-parent --adjust-extension --page-requisites --convert-links http://127.0.0.1:6060/pkg/github.com/${VENDOR}/${PROJECT}/ ; kill -9 `lsof -ti :6060` - @echo '<html><head><meta http-equiv="refresh" content="0;./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html"/></head><a href="./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html">'${PKGNAME}' Documentation ...</a></html>' > target/docs/index.html - -# Alias to run all quality-assurance checks -qa: fmtcheck test vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan - -# --- INSTALL --- - -# Get the dependencies -deps: - GOPATH=$(GOPATH) go get ./... - GOPATH=$(GOPATH) go get golang.org/x/lint/golint - GOPATH=$(GOPATH) go get github.com/jstemmer/go-junit-report - GOPATH=$(GOPATH) go get github.com/axw/gocov/gocov - GOPATH=$(GOPATH) go get github.com/fzipp/gocyclo - GOPATH=$(GOPATH) go get github.com/gordonklaus/ineffassign - GOPATH=$(GOPATH) go get github.com/client9/misspell/cmd/misspell - GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/structcheck - GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/varcheck - GOPATH=$(GOPATH) go get github.com/kisielk/errcheck - GOPATH=$(GOPATH) go get github.com/securego/gosec/cmd/gosec/... - -# Remove any build artifact -clean: - GOPATH=$(GOPATH) go clean ./... - -# Deletes any intermediate file -nuke: - rm -rf ./target - GOPATH=$(GOPATH) go clean -i ./... diff --git a/vendor/github.com/willf/bitset/README.md b/vendor/github.com/willf/bitset/README.md index 6c62b20c6..50338e71d 100644 --- a/vendor/github.com/willf/bitset/README.md +++ b/vendor/github.com/willf/bitset/README.md @@ -2,10 +2,10 @@ *Go language library to map between non-negative integers and boolean values* -[![Master Build Status](https://secure.travis-ci.org/willf/bitset.png?branch=master)](https://travis-ci.org/willf/bitset?branch=master) +[![Test](https://github.com/willf/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest) [![Master Coverage Status](https://coveralls.io/repos/willf/bitset/badge.svg?branch=master&service=github)](https://coveralls.io/github/willf/bitset?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset) -[![GoDoc](https://godoc.org/github.com/willf/bitset?status.svg)](http://godoc.org/github.com/willf/bitset) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/willf/bitset?tab=doc)](https://pkg.go.dev/github.com/willf/bitset?tab=doc) ## Description @@ -63,8 +63,11 @@ func main() { As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets. -Godoc documentation is at: https://godoc.org/github.com/willf/bitset +Package documentation is at: https://pkg.go.dev/github.com/willf/bitset?tab=doc +## Memory Usage + +The memory usage of a bitset using N bits is at least N/8 bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). ## Implementation Note @@ -82,15 +85,10 @@ go get github.com/willf/bitset If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)") -This project include a Makefile that allows you to test and build the project with simple commands. -To see all available options: -```bash -make help -``` - ## Running all tests -Before committing the code, please check if it passes all tests using (note: this will install some dependencies): +Before committing the code, please check if it passes tests, has adequate coverage, etc. ```bash -make qa +go test +go test -cover ``` diff --git a/vendor/github.com/willf/bitset/bitset.go b/vendor/github.com/willf/bitset/bitset.go index 22e5d42e5..21e889da2 100644 --- a/vendor/github.com/willf/bitset/bitset.go +++ b/vendor/github.com/willf/bitset/bitset.go @@ -138,6 +138,9 @@ func (b *BitSet) Len() uint { // extendSetMaybe adds additional words to incorporate new bits if needed func (b *BitSet) extendSetMaybe(i uint) { if i >= b.length { // if we need more bits, make 'em + if i >= Cap() { + panic("You are exceeding the capacity") + } nsize := wordsNeeded(i + 1) if b.set == nil { b.set = make([]uint64, nsize) @@ -160,7 +163,12 @@ func (b *BitSet) Test(i uint) bool { return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0 } -// Set bit i to 1 +// Set bit i to 1, the capacity of the bitset is automatically +// increased accordingly. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. func (b *BitSet) Set(i uint) *BitSet { b.extendSetMaybe(i) b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1)) @@ -176,7 +184,11 @@ func (b *BitSet) Clear(i uint) *BitSet { return b } -// SetTo sets bit i to value +// SetTo sets bit i to value. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. func (b *BitSet) SetTo(i uint, value bool) *BitSet { if value { return b.Set(i) @@ -184,7 +196,11 @@ func (b *BitSet) SetTo(i uint, value bool) *BitSet { return b.Clear(i) } -// Flip bit at i +// Flip bit at i. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. func (b *BitSet) Flip(i uint) *BitSet { if i >= b.length { return b.Set(i) @@ -193,26 +209,51 @@ func (b *BitSet) Flip(i uint) *BitSet { return b } -// Shrink shrinks BitSet to desired length in bits. It clears all bits > length -// and reduces the size and length of the set. +// Shrink shrinks BitSet so that the provided value is the last possible +// set value. It clears all bits > the provided index and reduces the size +// and length of the set. +// +// Note that the parameter value is not the new length in bits: it is the +// maximal value that can be stored in the bitset after the function call. +// The new length in bits is the parameter value + 1. Thus it is not possible +// to use this function to set the length to 0, the minimal value of the length +// after this function call is 1. // // A new slice is allocated to store the new bits, so you may see an increase in // memory usage until the GC runs. Normally this should not be a problem, but if you // have an extremely large BitSet its important to understand that the old BitSet will // remain in memory until the GC frees it. -func (b *BitSet) Shrink(length uint) *BitSet { - idx := wordsNeeded(length + 1) +func (b *BitSet) Shrink(lastbitindex uint) *BitSet { + length := lastbitindex + 1 + idx := wordsNeeded(length) if idx > len(b.set) { return b } shrunk := make([]uint64, idx) copy(shrunk, b.set[:idx]) b.set = shrunk - b.length = length + 1 - b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)) - 1)) + b.length = length + b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)))) return b } +// Compact shrinks BitSet to so that we preserve all set bits, while minimizing +// memory usage. Compact calls Shrink. +func (b *BitSet) Compact() *BitSet { + idx := len(b.set) - 1 + for ; idx >= 0 && b.set[idx] == 0; idx-- { + } + newlength := uint((idx + 1) << log2WordSize) + if newlength >= b.length { + return b // nothing to do + } + if newlength > 0 { + return b.Shrink(newlength - 1) + } + // We preserve one word + return b.Shrink(63) +} + // InsertAt takes an index which indicates where a bit should be // inserted. Then it shifts all the bits in the set to the left by 1, starting // from the given index position, and sets the index position to 0. @@ -323,6 +364,9 @@ func (b *BitSet) DeleteAt(i uint) *BitSet { // including possibly the current index // along with an error code (true = valid, false = no set bit found) // for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} +// +// Users concerned with performance may want to use NextSetMany to +// retrieve several values at once. func (b *BitSet) NextSet(i uint) (uint, bool) { x := int(i >> log2WordSize) if x >= len(b.set) { @@ -358,6 +402,14 @@ func (b *BitSet) NextSet(i uint) (uint, bool) { // j += 1 // } // +// +// It is possible to retrieve all set bits as follow: +// +// indices := make([]uint, bitmap.Count()) +// bitmap.NextSetMany(0, indices) +// +// However if bitmap.Count() is large, it might be preferable to +// use several calls to NextSetMany, for performance reasons. func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { myanswer := buffer capacity := cap(buffer) @@ -809,7 +861,7 @@ func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { newset := New(uint(length)) if uint64(newset.length) != length { - return 0, errors.New("Unmarshalling error: type mismatch") + return 0, errors.New("unmarshalling error: type mismatch") } // Read remaining bytes as set diff --git a/vendor/github.com/willf/bitset/go.mod b/vendor/github.com/willf/bitset/go.mod new file mode 100644 index 000000000..583ecab78 --- /dev/null +++ b/vendor/github.com/willf/bitset/go.mod @@ -0,0 +1,3 @@ +module github.com/willf/bitset + +go 1.14 diff --git a/vendor/github.com/willf/bitset/go.sum b/vendor/github.com/willf/bitset/go.sum new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vendor/github.com/willf/bitset/go.sum diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index 8b129b794..7688d72c3 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -2632,7 +2632,9 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body func (s bodyWriterState) cancel() { if s.timer != nil { - s.timer.Stop() + if s.timer.Stop() { + s.resc <- nil + } } } diff --git a/vendor/modules.txt b/vendor/modules.txt index b78e059db..422a6d88d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -422,7 +422,7 @@ github.com/onsi/ginkgo/reporters/stenographer github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty github.com/onsi/ginkgo/types -# github.com/onsi/gomega v1.10.3 +# github.com/onsi/gomega v1.10.4 github.com/onsi/gomega github.com/onsi/gomega/format github.com/onsi/gomega/gbytes @@ -459,7 +459,7 @@ github.com/opencontainers/runtime-tools/generate github.com/opencontainers/runtime-tools/generate/seccomp github.com/opencontainers/runtime-tools/specerror github.com/opencontainers/runtime-tools/validate -# github.com/opencontainers/selinux v1.6.0 +# github.com/opencontainers/selinux v1.7.0 github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/pkg/pwalk @@ -568,7 +568,7 @@ github.com/vishvananda/netlink github.com/vishvananda/netlink/nl # github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df github.com/vishvananda/netns -# github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 +# github.com/willf/bitset v1.1.11 github.com/willf/bitset # github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b github.com/xeipuuv/gojsonpointer @@ -609,7 +609,7 @@ golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/ssh/terminal -# golang.org/x/net v0.0.0-20201110031124-69a78807bb2b +# golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/html |