diff options
50 files changed, 743 insertions, 353 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index a7663f3e3..2946f0b91 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -52,7 +52,7 @@ Briefly describe the problem you are having in a few paragraphs. (paste your output here) ``` -**Output of `podman info`:** +**Output of `podman info --debug`:** ``` (paste your output here) @@ -229,6 +229,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in [error RuntimeError](#RuntimeError) +[error VolumeNotFound](#VolumeNotFound) + ## Methods ### <a name="BuildImage"></a>func BuildImage <div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;"> @@ -1741,3 +1743,6 @@ PodNotFound means the pod could not be found by the provided name or ID in local ### <a name="RuntimeError"></a>type RuntimeError RuntimeErrors generally means a runtime could not be found or gotten. +### <a name="VolumeNotFound"></a>type VolumeNotFound + +VolumeNotFound means the volume could not be found by the name or ID in local storage. @@ -83,18 +83,23 @@ Information about contributing to this project. ## Buildah and Podman relationship -Buildah and Podman are two complementary Open-source projects that are available on -most Linux platforms and both projects reside at [GitHub.com](https://github.com) -with [Buildah](https://buildah.io) [(GitHub)](https://github.com/containers/buildah) and -[Podman](https://podman.io) [(GitHub)](https://github.com/containers/libpod). Both Buildah and Podman are -command line tools that work on OCI images and containers. The two projects -differentiate in their specialization. +Buildah and Podman are two complementary open-source projects that are +available on most Linux platforms and both projects reside at +[GitHub.com](https://github.com) with Buildah +[here](https://github.com/containers/buildah) and Podman +[here](https://github.com/containers/libpod). Both, Buildah and Podman are +command line tools that work on Open Container Initiative (OCI) images and +containers. The two projects differentiate in their specialization. Buildah specializes in building OCI images. Buildah's commands replicate all -of the commands that are found in a Dockerfile. Buildah’s goal is also to -provide a lower level coreutils interface to build images, allowing people to build -containers without requiring a Dockerfile. The intent with Buildah is to allow other -scripting languages to build container images, without requiring a daemon. +of the commands that are found in a Dockerfile. This allows building images +with and without Dockerfiles while not requiring any root privileges. +Buildah’s ultimate goal is to provide a lower-level coreutils interface to +build images. The flexibility of building images without Dockerfiles allows +for the integration of other scripting languages into the build process. +Buildah follows a simple fork-exec model and does not run as a daemon +but it is based on a comprehensive API in golang, which can be vendored +into other tools. Podman specializes in all of the commands and functions that help you to maintain and modify OCI images, such as pulling and tagging. It also allows you to create, run, and maintain those containers @@ -103,12 +108,12 @@ created from those images. A major difference between Podman and Buildah is their concept of a container. Podman allows users to create "traditional containers" where the intent of these containers is to be long lived. While Buildah containers are really just created to allow content -to be added back to the container image. An easy way to think of it is the +to be added back to the container image. An easy way to think of it is the `buildah run` command emulates the RUN command in a Dockerfile while the `podman run` command emulates the `docker run` command in functionality. Because of this and their underlying -storage differences, you cannot see Podman containers from within Buildah or vice versa. +storage differences, you can not see Podman containers from within Buildah or vice versa. -In short Buildah is an efficient way to create OCI images while Podman allows +In short, Buildah is an efficient way to create OCI images while Podman allows you to manage and maintain those images and containers in a production environment using familiar container cli commands. For more details, see the [Container Tools Guide](https://github.com/containers/buildah/tree/master/docs/containertools). diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 34fe6a012..e40e35cb5 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -52,12 +52,22 @@ func init() { flags := buildCommand.Flags() flags.SetInterspersed(false) - flags.BoolVar(&layerValues.ForceRm, "force-rm", true, "Always remove intermediate containers after a build, even if the build is unsuccessful. (default true)") - flags.BoolVar(&layerValues.Layers, "layers", true, "Cache intermediate layers during build. Use BUILDAH_LAYERS environment variable to override") budFlags := buildahcli.GetBudFlags(&budFlagsValues) + flag := budFlags.Lookup("pull-always") + flag.Value.Set("true") + flag.DefValue = "true" + layerFlags := buildahcli.GetLayerFlags(&layerValues) + flag = layerFlags.Lookup("layers") + flag.Value.Set(useLayers()) + flag.DefValue = (useLayers()) + flag = layerFlags.Lookup("force-rm") + flag.Value.Set("true") + flag.DefValue = "true" + fromAndBugFlags := buildahcli.GetFromAndBudFlags(&fromAndBudValues, &userNSValues, &namespaceValues) flags.AddFlagSet(&budFlags) + flags.AddFlagSet(&layerFlags) flags.AddFlagSet(&fromAndBugFlags) } @@ -179,7 +189,7 @@ func buildCmd(c *cliconfig.BuildValues) error { } runtimeFlags := []string{} - for _, arg := range c.RuntimeOpts { + for _, arg := range c.RuntimeFlags { runtimeFlags = append(runtimeFlags, "--"+arg) } // end from buildah @@ -258,6 +268,7 @@ func buildCmd(c *cliconfig.BuildValues) error { RuntimeArgs: runtimeFlags, SignaturePolicyPath: c.SignaturePolicy, Squash: c.Squash, + Target: c.Target, } return runtime.Build(getContext(), c, options, dockerfiles) } @@ -271,3 +282,13 @@ func Tail(a []string) []string { } return []string{} } + +// useLayers returns false if BUILDAH_LAYERS is set to "0" or "false" +// otherwise it returns true +func useLayers() string { + layers := os.Getenv("BUILDAH_LAYERS") + if strings.ToLower(layers) == "false" || layers == "0" { + return "false" + } + return "true" +} diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index f0d3dbb39..20eb0f490 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -16,8 +16,8 @@ func getMainCommands() []*cobra.Command { _createCommand, _diffCommand, _execCommand, - generateCommand.Command, - _containerKubeCommand, + _generateCommand, + _playCommand, _psCommand, _loginCommand, _logoutCommand, @@ -38,7 +38,6 @@ func getMainCommands() []*cobra.Command { _topCommand, _umountCommand, _unpauseCommand, - volumeCommand.Command, _waitCommand, } diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 12b793d23..868f90d54 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -646,11 +646,6 @@ func parseCreateOpts(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l if util.StringInSlice(".", c.StringSlice("dns-search")) && len(c.StringSlice("dns-search")) > 1 { return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'") } - if !netMode.IsPrivate() { - if c.IsSet("dns-search") || c.IsSet("dns") || c.IsSet("dns-opt") { - return nil, errors.Errorf("specifying DNS flags when network mode is shared with the host or another container is not allowed") - } - } // Validate domains are good for _, dom := range c.StringSlice("dns-search") { diff --git a/cmd/podman/errors.go b/cmd/podman/errors.go new file mode 100644 index 000000000..2572b8779 --- /dev/null +++ b/cmd/podman/errors.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "syscall" + + "github.com/sirupsen/logrus" +) + +func outputError(err error) { + if MainGlobalOpts.LogLevel == "debug" { + logrus.Errorf(err.Error()) + } else { + if ee, ok := err.(*exec.ExitError); ok { + if status, ok := ee.Sys().(syscall.WaitStatus); ok { + exitCode = status.ExitStatus() + } + } + fmt.Fprintln(os.Stderr, "Error:", err.Error()) + } +} diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go index 66cb7a465..773d625ee 100644 --- a/cmd/podman/generate.go +++ b/cmd/podman/generate.go @@ -5,17 +5,18 @@ import ( "github.com/spf13/cobra" ) -var generateDescription = "Generate structured data based for a containers and pods" -var generateCommand = cliconfig.PodmanCommand{ - - Command: &cobra.Command{ +var ( + generateCommand cliconfig.PodmanCommand + generateDescription = "Generate structured data based for a containers and pods" + _generateCommand = &cobra.Command{ Use: "generate", Short: "Generated structured data", Long: generateDescription, - }, -} + } +) func init() { + generateCommand.Command = _generateCommand generateCommand.AddCommand(getGenerateSubCommands()...) generateCommand.SetUsageTemplate(UsageTemplate()) } diff --git a/cmd/podman/main.go b/cmd/podman/main.go index bb21f2f79..19bdb40d6 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -2,11 +2,9 @@ package main import ( "context" - "fmt" "io" "log/syslog" "os" - "os/exec" "runtime/pprof" "strings" "syscall" @@ -18,7 +16,7 @@ import ( "github.com/containers/libpod/pkg/tracing" "github.com/containers/libpod/version" "github.com/containers/storage/pkg/reexec" - opentracing "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" lsyslog "github.com/sirupsen/logrus/hooks/syslog" @@ -224,16 +222,7 @@ func main() { return } if err := rootCmd.Execute(); err != nil { - if MainGlobalOpts.LogLevel == "debug" { - logrus.Errorf(err.Error()) - } else { - if ee, ok := err.(*exec.ExitError); ok { - if status, ok := ee.Sys().(syscall.WaitStatus); ok { - exitCode = status.ExitStatus() - } - } - fmt.Fprintln(os.Stderr, "Error:", err.Error()) - } + outputError(err) } else { // The exitCode modified from 125, indicates an application // running inside of a container failed, as opposed to the diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index 9fc06dde9..a59460b71 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -52,8 +52,6 @@ func init() { flags.BoolVarP(&playKubeCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.StringVar(&playKubeCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") - - rootCmd.AddCommand(playKubeCommand.Command) } func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index 01ed70f52..2dcb491d7 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -7,6 +7,7 @@ import ( "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/image" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -61,15 +62,21 @@ func rmCmd(c *cliconfig.RmValues) error { } defer runtime.Shutdown(false) + failureCnt := 0 delContainers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all") if err != nil { if c.Force && len(c.InputArgs) > 0 { if errors.Cause(err) == libpod.ErrNoSuchCtr { err = nil + } else { + failureCnt++ } runtime.RemoveContainersFromStorage(c.InputArgs) } if len(delContainers) == 0 { + if err != nil && failureCnt == 0 { + exitCode = 1 + } return err } if err != nil { @@ -96,5 +103,16 @@ func rmCmd(c *cliconfig.RmValues) error { // Run the parallel funcs deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) - return printParallelOutput(deleteErrors, errCount) + err = printParallelOutput(deleteErrors, errCount) + if err != nil { + for _, result := range deleteErrors { + if result != nil && errors.Cause(result) != image.ErrNoSuchCtr { + failureCnt++ + } + } + if failureCnt == 0 { + exitCode = 1 + } + } + return err } diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go index fbaa19336..709ed14e0 100644 --- a/cmd/podman/rmi.go +++ b/cmd/podman/rmi.go @@ -5,6 +5,8 @@ import ( "os" "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter" "github.com/containers/storage" "github.com/pkg/errors" @@ -29,6 +31,17 @@ var ( } ) +func imageNotFound(err error) bool { + if errors.Cause(err) == image.ErrNoSuchImage { + return true + } + switch err.(type) { + case *iopodman.ImageNotFound: + return true + } + return false +} + func init() { rmiCommand.Command = _rmiCommand rmiCommand.SetUsageTemplate(UsageTemplate()) @@ -39,10 +52,8 @@ func init() { func rmiCmd(c *cliconfig.RmiValues) error { var ( - lastError error - deleted bool - deleteErr error - msg string + lastError error + failureCnt int ) ctx := getContext() @@ -64,19 +75,21 @@ func rmiCmd(c *cliconfig.RmiValues) error { images := args[:] removeImage := func(img *adapter.ContainerImage) { - deleted = true - msg, deleteErr = runtime.RemoveImage(ctx, img, c.Force) - if deleteErr != nil { - if errors.Cause(deleteErr) == storage.ErrImageUsedByContainer { + msg, err := runtime.RemoveImage(ctx, img, c.Force) + if err != nil { + if errors.Cause(err) == storage.ErrImageUsedByContainer { fmt.Printf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()) } + if !imageNotFound(err) { + failureCnt++ + } if lastError != nil { fmt.Fprintln(os.Stderr, lastError) } - lastError = deleteErr - } else { - fmt.Println(msg) + lastError = err + return } + fmt.Println(msg) } if removeAll { @@ -121,22 +134,21 @@ func rmiCmd(c *cliconfig.RmiValues) error { for _, i := range images { newImage, err := runtime.NewImageFromLocal(i) if err != nil { - fmt.Fprintln(os.Stderr, err) + if lastError != nil { + if !imageNotFound(lastError) { + failureCnt++ + } + fmt.Fprintln(os.Stderr, lastError) + } + lastError = err continue } removeImage(newImage) } } - // If the user calls remove all and there are none, it should not be a - // non-zero exit - if !deleted && removeAll { - return nil - } - // the user tries to remove images that do not exist, that should be a - // non-zero exit - if !deleted { - return errors.Errorf("no valid images to delete") + if imageNotFound(lastError) && failureCnt == 0 { + exitCode = 1 } return lastError diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index b9e4ea2ef..618af3481 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -1116,16 +1116,19 @@ method GetPodsByContext(all: bool, latest: bool, args: []string) -> (pods: []str method LoadImage(name: string, inputFile: string, quiet: bool, deleteFile: bool) -> (reply: MoreResponse) # ImageNotFound means the image could not be found by the provided name or ID in local storage. -error ImageNotFound (id: string) +error ImageNotFound (id: string, reason: string) # ContainerNotFound means the container could not be found by the provided name or ID in local storage. -error ContainerNotFound (id: string) +error ContainerNotFound (id: string, reason: string) # NoContainerRunning means none of the containers requested are running in a command that requires a running container. error NoContainerRunning () # PodNotFound means the pod could not be found by the provided name or ID in local storage. -error PodNotFound (name: string) +error PodNotFound (name: string, reason: string) + +# VolumeNotFound means the volume could not be found by the name or ID in local storage. +error VolumeNotFound (id: string, reason: string) # PodContainerError means a container associated with a pod failed to preform an operation. It contains # a container ID of the container that failed. diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh index 01c468901..de7ad4506 100644 --- a/contrib/cirrus/packer/fedora_setup.sh +++ b/contrib/cirrus/packer/fedora_setup.sh @@ -40,6 +40,7 @@ ooe.sh sudo dnf install -y \ golang-github-cpuguy83-go-md2man \ gpgme-devel \ iptables \ + iproute \ libassuan-devel \ libcap-devel \ libnet \ diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh index 7d49c5dc7..5b7e1d714 100644 --- a/contrib/cirrus/packer/ubuntu_setup.sh +++ b/contrib/cirrus/packer/ubuntu_setup.sh @@ -48,6 +48,7 @@ ooe.sh sudo -E apt-get -qq install \ gettext \ go-md2man \ golang \ + iproute \ iptables \ libaio-dev \ libapparmor-dev \ diff --git a/docs/podman-build.1.md b/docs/podman-build.1.md index 76e16b42c..fdae48b93 100644 --- a/docs/podman-build.1.md +++ b/docs/podman-build.1.md @@ -362,6 +362,12 @@ Specifies the name which will be assigned to the resulting image if the build process completes successfully. If _imageName_ does not include a registry name, the registry name *localhost* will be prepended to the image name. +**--target** *stageName* + +Set the target build stage to build. When building a Dockerfile with multiple build stages, --target +can be used to specify an intermediate build stage by name as the final stage for the resulting image. +Commands after the target stage will be skipped. + **--tls-verify** *bool-value* Require HTTPS and verify certificates when talking to container registries (defaults to true). diff --git a/docs/podman-container-cleanup.1.md b/docs/podman-container-cleanup.1.md index e375c12ec..2ad39d214 100644 --- a/docs/podman-container-cleanup.1.md +++ b/docs/podman-container-cleanup.1.md @@ -30,7 +30,7 @@ The latest option is not supported on the remote client. `podman container cleanup 860a4b23` -`podman container-cleanup -a` +`podman container cleanup -a` `podman container cleanup --latest` diff --git a/docs/podman-rm.1.md b/docs/podman-rm.1.md index 10ebe97f9..dc1729188 100644 --- a/docs/podman-rm.1.md +++ b/docs/podman-rm.1.md @@ -1,9 +1,11 @@ -% podman-rm(1) +% podman-container-rm(1) ## NAME -podman\-rm - Remove one or more containers +podman\-container\-rm (podman\-rm) - Remove one or more containers ## SYNOPSIS +**podman container rm** [*options*] *container* + **podman rm** [*options*] *container* ## DESCRIPTION @@ -57,8 +59,13 @@ Forcibly remove the latest container created. podman rm -f --latest ``` +## Exit Status +**_0_** if all specified containers removed +**_1_** if one of the specified containers did not exist, and no other failures +**_125_** if command fails for a reason other then an container did not exist + ## SEE ALSO -podman(1), podman-rmi(1) +podman(1), podman-image-rm(1) ## HISTORY August 2017, Originally compiled by Ryan Cole <rycole@redhat.com> diff --git a/docs/podman-rmi.1.md b/docs/podman-rmi.1.md index 9c080c9f1..8c22bba2c 100644 --- a/docs/podman-rmi.1.md +++ b/docs/podman-rmi.1.md @@ -1,9 +1,11 @@ -% podman-rmi(1) +% podman-image-rm(1) ## NAME -podman\-rmi - Removes one or more images +podman\-image\-rm (podman\-rmi) - Removes one or more images ## SYNOPSIS +**podman image rm** *image* ... + **podman rmi** *image* ... ## DESCRIPTION @@ -38,6 +40,10 @@ Remove all images and containers. ``` podman rmi -a -f ``` +## Exit Status +**_0_** if all specified images removed +**_1_** if one of the specified images did not exist, and no other failures +**_125_** if command fails for a reason other then an image did not exist ## SEE ALSO podman(1) diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index b928f61f5..bbf10a2ce 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -28,6 +28,8 @@ servers in the created `resolv.conf`). Additionally, an empty file is created in each container to indicate to programs they are running in a container. This file is located at `/run/.containerenv`. +When running from a user defined network namespace, the /etc/netns/NSNAME/resolv.conf will be used if it exists, otherwise /etc/resolv.conf will be used. + ## OPTIONS **--add-host**=[] @@ -694,21 +696,21 @@ Current supported mount TYPES are bind, and tmpfs. Common Options: - · src, source: mount source spec for bind and volume. Mandatory for bind. + · src, source: mount source spec for bind and volume. Mandatory for bind. - · dst, destination, target: mount destination spec. + · dst, destination, target: mount destination spec. - · ro, read-only: true or false (default). + · ro, read-only: true or false (default). Options specific to bind: - · bind-propagation: Z, z, shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2). + · bind-propagation: Z, z, shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2). Options specific to tmpfs: - · tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux. + · tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux. - · tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux. + · tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux. **--userns**="" diff --git a/libpod/container_commit.go b/libpod/container_commit.go index 026611e51..5c4fd1a31 100644 --- a/libpod/container_commit.go +++ b/libpod/container_commit.go @@ -162,7 +162,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai importBuilder.SetWorkDir(splitChange[1]) } } - candidates, _, err := util.ResolveName(destImage, "", sc, c.runtime.store) + candidates, _, _, err := util.ResolveName(destImage, "", sc, c.runtime.store) if err != nil { return nil, errors.Wrapf(err, "error resolving name %q", destImage) } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 86f94477e..f182b6bdf 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -26,7 +26,6 @@ import ( "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/secrets" "github.com/containers/storage/pkg/idtools" - "github.com/mrunalp/fileutils" "github.com/opencontainers/runc/libcontainer/user" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" @@ -677,20 +676,12 @@ func (c *Container) makeBindMounts() error { // If it doesn't, don't copy them resolvPath, exists := bindMounts["/etc/resolv.conf"] if exists { - resolvDest := filepath.Join(c.state.RunDir, "resolv.conf") - if err := fileutils.CopyFile(resolvPath, resolvDest); err != nil { - return errors.Wrapf(err, "error copying resolv.conf from dependency container %s of container %s", depCtr.ID(), c.ID()) - } - c.state.BindMounts["/etc/resolv.conf"] = resolvDest - } + c.state.BindMounts["/etc/resolv.conf"] = resolvPath + } hostsPath, exists := bindMounts["/etc/hosts"] if exists { - hostsDest := filepath.Join(c.state.RunDir, "hosts") - if err := fileutils.CopyFile(hostsPath, hostsDest); err != nil { - return errors.Wrapf(err, "error copying hosts file from dependency container %s of container %s", depCtr.ID(), c.ID()) - } - c.state.BindMounts["/etc/hosts"] = hostsDest + c.state.BindMounts["/etc/hosts"] = hostsPath } } else { newResolv, err := c.generateResolvConf() @@ -705,6 +696,14 @@ func (c *Container) makeBindMounts() error { } c.state.BindMounts["/etc/hosts"] = newHosts } + + if err := label.Relabel(c.state.BindMounts["/etc/hosts"], c.config.MountLabel, true); err != nil { + return err + } + + if err := label.Relabel(c.state.BindMounts["/etc/resolv.conf"], c.config.MountLabel, true); err != nil { + return err + } } // SHM is always added when we mount the container @@ -758,8 +757,24 @@ func (c *Container) makeBindMounts() error { // generateResolvConf generates a containers resolv.conf func (c *Container) generateResolvConf() (string, error) { + resolvConf := "/etc/resolv.conf" + for _, ns := range c.config.Spec.Linux.Namespaces { + if ns.Type == spec.NetworkNamespace { + if ns.Path != "" && !strings.HasPrefix(ns.Path, "/proc/") { + definedPath := filepath.Join("/etc/netns", filepath.Base(ns.Path), "resolv.conf") + _, err := os.Stat(definedPath) + if err == nil { + resolvConf = definedPath + } else if !os.IsNotExist(err) { + return "", errors.Wrapf(err, "failed to stat %s", definedPath) + } + } + break + } + } + // Determine the endpoint for resolv.conf in case it is a symlink - resolvPath, err := filepath.EvalSymlinks("/etc/resolv.conf") + resolvPath, err := filepath.EvalSymlinks(resolvConf) if err != nil { return "", err } @@ -809,7 +824,7 @@ func (c *Container) generateResolvConf() (string, error) { } // Relabel resolv.conf for the container - if err := label.Relabel(destPath, c.config.MountLabel, false); err != nil { + if err := label.Relabel(destPath, c.config.MountLabel, true); err != nil { return "", err } diff --git a/libpod/options.go b/libpod/options.go index 9aa020b56..e22c81f91 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -904,10 +904,10 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo } ctr.config.PostConfigureNetNS = postConfigureNetNS - ctr.config.CreateNetNS = true + ctr.config.NetMode = namespaces.NetworkMode(netmode) + ctr.config.CreateNetNS = !ctr.config.NetMode.IsUserDefined() ctr.config.PortMappings = portMappings ctr.config.Networks = networks - ctr.config.NetMode = namespaces.NetworkMode(netmode) return nil } diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index acc5d6b2a..dfbc7fe33 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -109,6 +109,13 @@ reexec_userns_join (int userns, int mountns) char uid[16]; char **argv; int pid; + char *cwd = getcwd (NULL, 0); + + if (cwd == NULL) + { + fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } sprintf (uid, "%d", geteuid ()); @@ -154,6 +161,13 @@ reexec_userns_join (int userns, int mountns) _exit (EXIT_FAILURE); } + if (chdir (cwd) < 0) + { + fprintf (stderr, "cannot chdir: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + free (cwd); + execvp (argv[0], argv); _exit (EXIT_FAILURE); @@ -190,6 +204,13 @@ reexec_in_user_namespace (int ready) char *listen_fds = NULL; char *listen_pid = NULL; bool do_socket_activation = false; + char *cwd = getcwd (NULL, 0); + + if (cwd == NULL) + { + fprintf (stderr, "error getting current working directory: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } listen_pid = getenv("LISTEN_PID"); listen_fds = getenv("LISTEN_FDS"); @@ -265,6 +286,13 @@ reexec_in_user_namespace (int ready) _exit (EXIT_FAILURE); } + if (chdir (cwd) < 0) + { + fprintf (stderr, "cannot chdir: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + free (cwd); + execvp (argv[0], argv); _exit (EXIT_FAILURE); diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 8da44a2f0..50e07ee74 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -446,7 +446,15 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l } if IsNS(string(c.NetMode)) { - // pass + split := strings.SplitN(string(c.NetMode), ":", 2) + if len(split[0]) != 2 { + return nil, errors.Errorf("invalid user defined network namespace %q", c.NetMode.UserDefined()) + } + _, err := os.Stat(split[1]) + if err != nil { + return nil, err + } + options = append(options, libpod.WithNetNS(portBindings, false, string(c.NetMode), networks)) } else if c.NetMode.IsContainer() { connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.Container()) if err != nil { diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 76b8963ff..28a636fa6 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -3,10 +3,12 @@ package createconfig import ( "os" "path" + "path/filepath" "strings" "github.com/containers/libpod/pkg/rootless" "github.com/containers/storage/pkg/mount" + pmount "github.com/containers/storage/pkg/mount" "github.com/docker/docker/daemon/caps" "github.com/docker/go-units" "github.com/opencontainers/runc/libcontainer/user" @@ -392,9 +394,65 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint configSpec.Linux.Resources = &spec.LinuxResources{} } + // Make sure that the bind mounts keep options like nosuid, noexec, nodev. + mounts, err := pmount.GetMounts() + if err != nil { + return nil, err + } + for i := range configSpec.Mounts { + m := &configSpec.Mounts[i] + isBind := false + for _, o := range m.Options { + if o == "bind" || o == "rbind" { + isBind = true + break + } + } + if !isBind { + continue + } + mount, err := findMount(m.Source, mounts) + if err != nil { + return nil, err + } + if mount == nil { + continue + } + next_option: + for _, o := range strings.Split(mount.Opts, ",") { + if o == "nosuid" || o == "noexec" || o == "nodev" { + for _, e := range m.Options { + if e == o { + continue next_option + } + } + m.Options = append(m.Options, o) + } + } + } + return configSpec, nil } +func findMount(target string, mounts []*pmount.Info) (*pmount.Info, error) { + var err error + target, err = filepath.Abs(target) + if err != nil { + return nil, errors.Wrapf(err, "cannot resolve %s", target) + } + var bestSoFar *pmount.Info + for _, i := range mounts { + if bestSoFar != nil && len(bestSoFar.Mountpoint) > len(i.Mountpoint) { + // Won't be better than what we have already found + continue + } + if strings.HasPrefix(target, i.Mountpoint) { + bestSoFar = i + } + } + return bestSoFar, nil +} + func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) { if config.PidMode.IsHost() && rootless.IsRootless() { return diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index 7345a1dd8..ad9f107a7 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -47,7 +47,7 @@ func (i *LibpodAPI) ListContainers(call iopodman.VarlinkCall) error { func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, id string) error { ctr, err := i.Runtime.LookupContainer(id) if err != nil { - return call.ReplyContainerNotFound(id) + return call.ReplyContainerNotFound(id, err.Error()) } opts := shared.PsOptions{ Namespace: true, @@ -64,7 +64,7 @@ func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, id string) error { func (i *LibpodAPI) InspectContainer(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } inspectInfo, err := ctr.Inspect(true) if err != nil { @@ -90,7 +90,7 @@ func (i *LibpodAPI) InspectContainer(call iopodman.VarlinkCall, name string) err func (i *LibpodAPI) ListContainerProcesses(call iopodman.VarlinkCall, name string, opts []string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } containerState, err := ctr.State() if err != nil { @@ -118,7 +118,7 @@ func (i *LibpodAPI) GetContainerLogs(call iopodman.VarlinkCall, name string) err var logs []string ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } logPath := ctr.LogPath() @@ -198,7 +198,7 @@ func (i *LibpodAPI) ListContainerChanges(call iopodman.VarlinkCall, name string) func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } outputFile, err := ioutil.TempFile("", "varlink_recv") if err != nil { @@ -220,7 +220,7 @@ func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath str func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } containerStats, err := ctr.GetContainerStats(&libpod.ContainerStats{}) if err != nil { @@ -251,7 +251,7 @@ func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) er func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } state, err := ctr.State() if err != nil { @@ -270,7 +270,7 @@ func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error func (i *LibpodAPI) StopContainer(call iopodman.VarlinkCall, name string, timeout int64) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } if err := ctr.StopWithTimeout(uint(timeout)); err != nil && err != libpod.ErrCtrStopped { return call.ReplyErrorOccurred(err.Error()) @@ -282,7 +282,7 @@ func (i *LibpodAPI) StopContainer(call iopodman.VarlinkCall, name string, timeou func (i *LibpodAPI) RestartContainer(call iopodman.VarlinkCall, name string, timeout int64) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } if err := ctr.RestartWithTimeout(getContext(), uint(timeout)); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -311,7 +311,7 @@ func (i *LibpodAPI) KillContainer(call iopodman.VarlinkCall, name string, signal } ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } if err := ctr.Kill(killSignal); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -323,7 +323,7 @@ func (i *LibpodAPI) KillContainer(call iopodman.VarlinkCall, name string, signal func (i *LibpodAPI) PauseContainer(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } if err := ctr.Pause(); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -335,7 +335,7 @@ func (i *LibpodAPI) PauseContainer(call iopodman.VarlinkCall, name string) error func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } if err := ctr.Unpause(); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -347,7 +347,7 @@ func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) err func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } exitCode, err := ctr.Wait() if err != nil { @@ -362,7 +362,7 @@ func (i *LibpodAPI) RemoveContainer(call iopodman.VarlinkCall, name string, forc ctx := getContext() ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -398,7 +398,7 @@ func (i *LibpodAPI) DeleteStoppedContainers(call iopodman.VarlinkCall) error { func (i *LibpodAPI) GetAttachSockets(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } status, err := ctr.State() @@ -427,7 +427,7 @@ func (i *LibpodAPI) ContainerCheckpoint(call iopodman.VarlinkCall, name string, ctx := getContext() ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } options := libpod.ContainerCheckpointOptions{ @@ -446,7 +446,7 @@ func (i *LibpodAPI) ContainerRestore(call iopodman.VarlinkCall, name string, kee ctx := getContext() ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } options := libpod.ContainerCheckpointOptions{ @@ -475,7 +475,7 @@ func getArtifact(ctr *libpod.Container) (*cc.CreateConfig, error) { func (i *LibpodAPI) ContainerConfig(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyErrorOccurred(err.Error()) + return call.ReplyContainerNotFound(name, err.Error()) } config := ctr.Config() b, err := json.Marshal(config) @@ -489,7 +489,7 @@ func (i *LibpodAPI) ContainerConfig(call iopodman.VarlinkCall, name string) erro func (i *LibpodAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifactName string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyErrorOccurred(err.Error()) + return call.ReplyContainerNotFound(name, err.Error()) } artifacts, err := ctr.GetArtifact(artifactName) if err != nil { @@ -506,7 +506,7 @@ func (i *LibpodAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifact func (i *LibpodAPI) ContainerInspectData(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyErrorOccurred(err.Error()) + return call.ReplyContainerNotFound(name, err.Error()) } data, err := ctr.Inspect(true) if err != nil { @@ -524,7 +524,7 @@ func (i *LibpodAPI) ContainerInspectData(call iopodman.VarlinkCall, name string) func (i *LibpodAPI) ContainerStateData(call iopodman.VarlinkCall, name string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyErrorOccurred(err.Error()) + return call.ReplyContainerNotFound(name, err.Error()) } data, err := ctr.ContainerState() if err != nil { diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index a27bdb9e5..210f139ce 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -73,7 +73,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error { func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error { newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id) if err != nil { - return call.ReplyImageNotFound(id) + return call.ReplyImageNotFound(id, err.Error()) } labels, err := newImage.Labels(getContext()) if err != nil { @@ -266,7 +266,7 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error { newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { - return call.ReplyImageNotFound(name) + return call.ReplyImageNotFound(name, err.Error()) } inspectInfo, err := newImage.Inspect(getContext()) if err != nil { @@ -284,7 +284,7 @@ func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error { func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error { newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { - return call.ReplyImageNotFound(name) + return call.ReplyImageNotFound(name, err.Error()) } history, err := newImage.History(getContext()) if err != nil { @@ -313,7 +313,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe ) newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { - return call.ReplyImageNotFound(err.Error()) + return call.ReplyImageNotFound(name, err.Error()) } destname := name if tag != "" { @@ -409,7 +409,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe func (i *LibpodAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error { newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { - return call.ReplyImageNotFound(name) + return call.ReplyImageNotFound(name, err.Error()) } if err := newImage.TagImage(tag); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -423,7 +423,7 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo ctx := getContext() newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { - return call.ReplyImageNotFound(name) + return call.ReplyImageNotFound(name, err.Error()) } _, err = i.Runtime.RemoveImage(ctx, newImage, force) if err != nil { @@ -512,7 +512,7 @@ func (i *LibpodAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error { func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error { ctr, err := i.Runtime.LookupContainer(name) if err != nil { - return call.ReplyContainerNotFound(name) + return call.ReplyContainerNotFound(name, err.Error()) } sc := image.GetSystemContext(i.Runtime.GetConfig().SignaturePolicyPath, "", false) var mimeType string @@ -576,7 +576,7 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination string, compress bool, tags []string) error { newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name) if err != nil { - return call.ReplyImageNotFound(name) + return call.ReplyImageNotFound(name, err.Error()) } additionalTags, err := image.GetAdditionalTags(tags) @@ -741,6 +741,9 @@ func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool) error { func (i *LibpodAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageSaveOptions) error { newImage, err := i.Runtime.ImageRuntime().NewFromLocal(options.Name) if err != nil { + if errors.Cause(err) == libpod.ErrNoSuchImage { + return call.ReplyImageNotFound(options.Name, err.Error()) + } return call.ReplyErrorOccurred(err.Error()) } diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go index 738a10b2a..4ca4c4270 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -86,7 +86,7 @@ func (i *LibpodAPI) ListPods(call iopodman.VarlinkCall) error { func (i *LibpodAPI) GetPod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } opts := shared.PsOptions{} @@ -102,7 +102,7 @@ func (i *LibpodAPI) GetPod(call iopodman.VarlinkCall, name string) error { func (i *LibpodAPI) InspectPod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } inspectData, err := pod.Inspect() if err != nil { @@ -119,7 +119,7 @@ func (i *LibpodAPI) InspectPod(call iopodman.VarlinkCall, name string) error { func (i *LibpodAPI) StartPod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } ctnrs, err := pod.AllContainers() if err != nil { @@ -140,7 +140,7 @@ func (i *LibpodAPI) StartPod(call iopodman.VarlinkCall, name string) error { func (i *LibpodAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int64) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } ctrErrs, err := pod.StopWithTimeout(getContext(), true, int(timeout)) callErr := handlePodCall(call, pod, ctrErrs, err) @@ -154,7 +154,7 @@ func (i *LibpodAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int6 func (i *LibpodAPI) RestartPod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } ctnrs, err := pod.AllContainers() if err != nil { @@ -181,7 +181,7 @@ func (i *LibpodAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64 pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } ctrErrs, err := pod.Kill(killSignal) callErr := handlePodCall(call, pod, ctrErrs, err) @@ -195,7 +195,7 @@ func (i *LibpodAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64 func (i *LibpodAPI) PausePod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } ctrErrs, err := pod.Pause() callErr := handlePodCall(call, pod, ctrErrs, err) @@ -209,7 +209,7 @@ func (i *LibpodAPI) PausePod(call iopodman.VarlinkCall, name string) error { func (i *LibpodAPI) UnpausePod(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } ctrErrs, err := pod.Unpause() callErr := handlePodCall(call, pod, ctrErrs, err) @@ -224,7 +224,7 @@ func (i *LibpodAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool ctx := getContext() pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } if err = i.Runtime.RemovePod(ctx, pod, force, force); err != nil { return call.ReplyErrorOccurred(err.Error()) @@ -237,7 +237,7 @@ func (i *LibpodAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool func (i *LibpodAPI) GetPodStats(call iopodman.VarlinkCall, name string) error { pod, err := i.Runtime.LookupPod(name) if err != nil { - return call.ReplyPodNotFound(name) + return call.ReplyPodNotFound(name, err.Error()) } prevStats := make(map[string]*libpod.ContainerStats) podStats, err := pod.GetPodStats(prevStats) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 4b4baa93c..33e05b872 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -28,8 +28,8 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration } // PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment -func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, env []string) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, uid, gid, env) +func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { + podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index bc1431bce..71dacfa80 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -128,4 +128,9 @@ var _ = Describe("Podman rm", func() { Expect(podmanTest.NumberOfContainers()).To(Equal(1)) }) + It("podman rm bogus container", func() { + session := podmanTest.Podman([]string{"rm", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) }) diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go index c160e1bc5..dcbda2df4 100644 --- a/test/e2e/rmi_test.go +++ b/test/e2e/rmi_test.go @@ -36,7 +36,7 @@ var _ = Describe("Podman rmi", func() { It("podman rmi bogus image", func() { session := podmanTest.Podman([]string{"rmi", "debian:6.0.10"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ExitCode()).To(Equal(1)) }) diff --git a/test/e2e/rootless_test.go b/test/e2e/rootless_test.go index 2b84d34c9..aa8ed6faa 100644 --- a/test/e2e/rootless_test.go +++ b/test/e2e/rootless_test.go @@ -60,7 +60,7 @@ var _ = Describe("Podman rootless", func() { for _, v := range commands { env := os.Environ() env = append(env, "USER=foo") - cmd := podmanTest.PodmanAsUser([]string{v}, 1000, 1000, env) + cmd := podmanTest.PodmanAsUser([]string{v}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) } @@ -128,13 +128,13 @@ var _ = Describe("Podman rootless", func() { env = append(env, "PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS=1") env = append(env, "USER=foo") - cmd := rootlessTest.PodmanAsUser([]string{"pod", "create", "--infra=false"}, 1000, 1000, env) + cmd := rootlessTest.PodmanAsUser([]string{"pod", "create", "--infra=false"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) podId := cmd.OutputToString() args := []string{"run", "--pod", podId, "--rootfs", mountPath, "echo", "hello"} - cmd = rootlessTest.PodmanAsUser(args, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser(args, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) Expect(cmd.LineInOutputContains("hello")).To(BeTrue()) @@ -158,7 +158,7 @@ var _ = Describe("Podman rootless", func() { env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", xdgRuntimeDir)) env = append(env, fmt.Sprintf("HOME=%s", home)) env = append(env, "USER=foo") - cmd := podmanTest.PodmanAsUser([]string{"search", "docker.io/busybox"}, 1000, 1000, env) + cmd := podmanTest.PodmanAsUser([]string{"search", "docker.io/busybox"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) }) @@ -175,65 +175,65 @@ var _ = Describe("Podman rootless", func() { allArgs := append([]string{"run"}, args...) allArgs = append(allArgs, "--rootfs", mountPath, "echo", "hello") - cmd := rootlessTest.PodmanAsUser(allArgs, 1000, 1000, env) + cmd := rootlessTest.PodmanAsUser(allArgs, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) Expect(cmd.LineInOutputContains("hello")).To(BeTrue()) - cmd = rootlessTest.PodmanAsUser([]string{"rm", "-l", "-f"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"rm", "-l", "-f"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) allArgs = append([]string{"run", "-d"}, args...) allArgs = append(allArgs, "--security-opt", "seccomp=unconfined", "--rootfs", mountPath, "top") - cmd = rootlessTest.PodmanAsUser(allArgs, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser(allArgs, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) - cmd = rootlessTest.PodmanAsUser([]string{"restart", "-l", "-t", "0"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"restart", "-l", "-t", "0"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) canUseExec := canExec() if canUseExec { - cmd = rootlessTest.PodmanAsUser([]string{"top", "-l"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"top", "-l"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) } - cmd = rootlessTest.PodmanAsUser([]string{"rm", "-l", "-f"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"rm", "-l", "-f"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) allArgs = append([]string{"run", "-d"}, args...) allArgs = append(allArgs, "--security-opt", "seccomp=unconfined", "--rootfs", mountPath, "unshare", "-r", "unshare", "-r", "top") - cmd = rootlessTest.PodmanAsUser(allArgs, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser(allArgs, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) - cmd = rootlessTest.PodmanAsUser([]string{"stop", "-l", "-t", "0"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"stop", "-l", "-t", "0"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) - cmd = rootlessTest.PodmanAsUser([]string{"inspect", "-l", "--type", "container", "--format", "{{ .State.Status }}"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"inspect", "-l", "--type", "container", "--format", "{{ .State.Status }}"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.LineInOutputContains("exited")).To(BeTrue()) - cmd = rootlessTest.PodmanAsUser([]string{"start", "-l"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"start", "-l"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) - cmd = rootlessTest.PodmanAsUser([]string{"stop", "-l", "-t", "0"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"stop", "-l", "-t", "0"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) - cmd = rootlessTest.PodmanAsUser([]string{"start", "-l"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"start", "-l"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) if len(args) == 0 { - cmd = rootlessTest.PodmanAsUser([]string{"inspect", "-l"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"inspect", "-l"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) data := cmd.InspectContainerToJSON() @@ -244,24 +244,23 @@ var _ = Describe("Podman rootless", func() { Skip("ioctl(NS_GET_PARENT) not supported.") } - cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "echo", "hello"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "echo", "hello"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) Expect(cmd.LineInOutputContains("hello")).To(BeTrue()) - cmd = rootlessTest.PodmanAsUser([]string{"ps", "-l", "-q"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"ps", "-l", "-q"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) cid := cmd.OutputToString() - cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "sh", "-c", "echo SeCreTMessage > /file"}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "sh", "-c", "echo SeCreTMessage > /file"}, 1000, 1000, "", env) cmd.WaitWithDefaultTimeout() Expect(cmd.ExitCode()).To(Equal(0)) - path := filepath.Join(home, "export.tar") - cmd = rootlessTest.PodmanAsUser([]string{"export", "-o", path, cid}, 1000, 1000, env) + cmd = rootlessTest.PodmanAsUser([]string{"export", "-o", "export.tar", cid}, 1000, 1000, home, env) cmd.WaitWithDefaultTimeout() - content, err := ioutil.ReadFile(path) + content, err := ioutil.ReadFile(filepath.Join(home, "export.tar")) Expect(err).To(BeNil()) Expect(strings.Contains(string(content), "SeCreTMessage")).To(BeTrue()) } diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 1c09a4d0b..a07e4d047 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -36,19 +36,19 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network connection with default bridge", func() { - session := podmanTest.Podman([]string{"run", "-dt", ALPINE, "wget", "www.projectatomic.io"}) + session := podmanTest.Podman([]string{"run", "-dt", ALPINE, "wget", "www.podman.io"}) session.Wait(90) Expect(session.ExitCode()).To(Equal(0)) }) It("podman run network connection with host", func() { - session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.projectatomic.io"}) + session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.podman.io"}) session.Wait(90) Expect(session.ExitCode()).To(Equal(0)) }) It("podman run network connection with loopback", func() { - session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.projectatomic.io"}) + session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.podman.io"}) session.Wait(90) Expect(session.ExitCode()).To(Equal(0)) }) @@ -178,4 +178,37 @@ var _ = Describe("Podman run networking", func() { Expect(exec4.ExitCode()).To(Equal(0)) Expect(exec4.OutputToString()).To(ContainSubstring("192.0.2.2 test1")) }) + + It("podman run network in user created network namespace", func() { + if Containerized() { + Skip("Can not be run within a container.") + } + SystemExec("ip", []string{"netns", "add", "xxx"}) + session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxx", ALPINE, "wget", "www.podman.io"}) + session.Wait(90) + Expect(session.ExitCode()).To(Equal(0)) + SystemExec("ip", []string{"netns", "delete", "xxx"}) + }) + + It("podman run n user created network namespace with resolv.conf", func() { + if Containerized() { + Skip("Can not be run within a container.") + } + SystemExec("ip", []string{"netns", "add", "xxx"}) + SystemExec("mkdir", []string{"-p", "/etc/netns/xxx"}) + SystemExec("bash", []string{"-c", "echo nameserver 11.11.11.11 > /etc/netns/xxx/resolv.conf"}) + session := podmanTest.Podman([]string{"run", "--net", "ns:/run/netns/xxx", ALPINE, "cat", "/etc/resolv.conf"}) + session.Wait(90) + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("11.11.11.11")) + SystemExec("ip", []string{"netns", "delete", "xxx"}) + SystemExec("rm", []string{"-rf", "/etc/netns/xxx"}) + }) + + It("podman run network in bogus user created network namespace", func() { + session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxy", ALPINE, "wget", "www.podman.io"}) + session.Wait(90) + Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session.ErrorToString()).To(ContainSubstring("stat /run/netns/xxy: no such file or directory")) + }) }) diff --git a/test/utils/podmantest_test.go b/test/utils/podmantest_test.go index 60e3e2a97..28f294a94 100644 --- a/test/utils/podmantest_test.go +++ b/test/utils/podmantest_test.go @@ -23,7 +23,7 @@ var _ = Describe("PodmanTest test", func() { FakeOutputs["check"] = []string{"check"} os.Setenv("HOOK_OPTION", "hook_option") env := os.Environ() - session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, env) + session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env) os.Unsetenv("HOOK_OPTION") session.WaitWithDefaultTimeout() Expect(session.Command.Process).ShouldNot(BeNil()) diff --git a/test/utils/utils.go b/test/utils/utils.go index aace018cd..098779321 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -61,7 +61,7 @@ func (p *PodmanTest) MakeOptions(args []string) []string { // PodmanAsUserBase exec podman as user. uid and gid is set for credentials useage. env is used // to record the env for debugging -func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, env []string) *PodmanSession { +func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string) *PodmanSession { var command *exec.Cmd podmanOptions := p.MakeOptions(args) podmanBinary := p.PodmanBinary @@ -74,14 +74,18 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, env []stri fmt.Printf("Running: (env: %v) %s %s\n", env, podmanBinary, strings.Join(podmanOptions, " ")) } if uid != 0 || gid != 0 { - nsEnterOpts := append([]string{"--userspec", fmt.Sprintf("%d:%d", uid, gid), "/", podmanBinary}, podmanOptions...) - command = exec.Command("chroot", nsEnterOpts...) + pythonCmd := fmt.Sprintf("import os; import sys; uid = %d; gid = %d; cwd = '%s'; os.setgid(gid); os.setuid(uid); os.chdir(cwd) if len(cwd)>0 else True; os.execv(sys.argv[1], sys.argv[1:])", gid, uid, cwd) + nsEnterOpts := append([]string{"-c", pythonCmd, podmanBinary}, podmanOptions...) + command = exec.Command("python", nsEnterOpts...) } else { command = exec.Command(podmanBinary, podmanOptions...) } if env != nil { command.Env = env } + if cwd != "" { + command.Dir = cwd + } session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) if err != nil { @@ -92,7 +96,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, env []stri // PodmanBase exec podman with default env. func (p *PodmanTest) PodmanBase(args []string) *PodmanSession { - return p.PodmanAsUserBase(args, 0, 0, nil) + return p.PodmanAsUserBase(args, 0, 0, "", nil) } // WaitForContainer waits on a started container diff --git a/vendor.conf b/vendor.conf index ff1a9c4d5..445f0844a 100644 --- a/vendor.conf +++ b/vendor.conf @@ -93,13 +93,13 @@ k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apim k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7 github.com/varlink/go 3ac79db6fd6aec70924193b090962f92985fe199 -github.com/containers/buildah 973bb88ef1861a5b782c722c471dd79b6732852c +github.com/containers/buildah v1.7 # TODO: Gotty has not been updated since 2012. Can we find replacement? github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512 # do not go beyond the below commit as the next one requires a more recent # docker which is in conflict with openshift/imagebuilder github.com/fsouza/go-dockerclient 29c1814d12c072344bb91aac5d2ff719db39c523 -github.com/openshift/imagebuilder 474d0f9df2cbabf006bd2b1c263a7b0789e228e0 +github.com/openshift/imagebuilder 36823496a6868f72bc36282cc475eb8a070c0934 github.com/ulikunitz/xz v0.5.5 github.com/coreos/go-iptables v0.4.0 github.com/google/shlex c34317bd91bf98fab745d77b03933cf8769299fe diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go index 8b9baea12..755bc348e 100644 --- a/vendor/github.com/containers/buildah/buildah.go +++ b/vendor/github.com/containers/buildah/buildah.go @@ -26,7 +26,7 @@ const ( Package = "buildah" // Version for the Package. Bump version in contrib/rpm/buildah.spec // too. - Version = "1.7-dev" + Version = "1.7" // The value we use to identify what type of information, currently a // serialized Builder structure, we are using as per-container state. // This should only be changed when we make incompatible changes to @@ -336,11 +336,6 @@ type BuilderOptions struct { // needs to be pulled and the image name alone can not be resolved to a // reference to a source image. No separator is implicitly added. Registry string - // Transport is a value which is prepended to the image's name, if it - // needs to be pulled and the image name alone, or the image name and - // the registry together, can not be resolved to a reference to a - // source image. No separator is implicitly added. - Transport string // PullBlobDirectory is the name of a directory in which we'll attempt // to store copies of layer blobs that we pull down, if any. It should // already exist. diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go index 56ab7aa57..d69eab52f 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/build.go +++ b/vendor/github.com/containers/buildah/imagebuildah/build.go @@ -62,11 +62,6 @@ type BuildOptions struct { // needs to be pulled and the image name alone can not be resolved to a // reference to a source image. No separator is implicitly added. Registry string - // Transport is a value which is prepended to the image's name, if it - // needs to be pulled and the image name alone, or the image name and - // the registry together, can not be resolved to a reference to a - // source image. No separator is implicitly added. - Transport string // IgnoreUnrecognizedInstructions tells us to just log instructions we // don't recognize, and try to keep going. IgnoreUnrecognizedInstructions bool @@ -171,6 +166,8 @@ type BuildOptions struct { ForceRmIntermediateCtrs bool // BlobDirectory is a directory which we'll use for caching layer blobs. BlobDirectory string + // Target the targeted FROM in the Dockerfile to build + Target string } // Executor is a buildah-based implementation of the imagebuilder.Executor @@ -184,7 +181,6 @@ type Executor struct { builder *buildah.Builder pullPolicy buildah.PullPolicy registry string - transport string ignoreUnrecognizedInstructions bool quiet bool runtime string @@ -580,7 +576,6 @@ func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) { contextDir: options.ContextDirectory, pullPolicy: options.PullPolicy, registry: options.Registry, - transport: options.Transport, ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions, quiet: options.Quiet, runtime: options.Runtime, @@ -670,7 +665,6 @@ func (b *Executor) Prepare(ctx context.Context, stage imagebuilder.Stage, from s FromImage: from, PullPolicy: b.pullPolicy, Registry: b.registry, - Transport: b.transport, PullBlobDirectory: b.blobDirectory, SignaturePolicyPath: b.signaturePolicyPath, ReportWriter: b.reportWriter, @@ -783,7 +777,7 @@ func (b *Executor) resolveNameToImageRef() (types.ImageReference, error) { if b.output != "" { imageRef, err = alltransports.ParseImageName(b.output) if err != nil { - candidates, _, err := util.ResolveName(b.output, "", b.systemContext, b.store) + candidates, _, _, err := util.ResolveName(b.output, "", b.systemContext, b.store) if err != nil { return nil, errors.Wrapf(err, "error parsing target image name %q", b.output) } @@ -1441,6 +1435,13 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt if err != nil { return "", nil, errors.Wrap(err, "error reading multiple stages") } + if options.Target != "" { + stagesTargeted, ok := stages.ThroughTarget(options.Target) + if !ok { + return "", nil, errors.Errorf("The target %q was not found in the provided Dockerfile", options.Target) + } + stages = stagesTargeted + } return exec.Build(ctx, stages) } diff --git a/vendor/github.com/containers/buildah/new.go b/vendor/github.com/containers/buildah/new.go index 7e7f97e49..01c2e733f 100644 --- a/vendor/github.com/containers/buildah/new.go +++ b/vendor/github.com/containers/buildah/new.go @@ -28,15 +28,14 @@ const ( minimumTruncatedIDLength = 3 ) -func pullAndFindImage(ctx context.Context, store storage.Store, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) { +func pullAndFindImage(ctx context.Context, store storage.Store, transport string, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) { pullOptions := PullOptions{ ReportWriter: options.ReportWriter, Store: store, SystemContext: options.SystemContext, - Transport: options.Transport, BlobDirectory: options.PullBlobDirectory, } - ref, err := pullImage(ctx, store, imageName, pullOptions, sc) + ref, err := pullImage(ctx, store, transport, imageName, pullOptions, sc) if err != nil { logrus.Debugf("error pulling image %q: %v", imageName, err) return nil, nil, err @@ -101,16 +100,16 @@ func newContainerIDMappingOptions(idmapOptions *IDMappingOptions) storage.IDMapp return options } -func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, *storage.Image, error) { +func resolveImage(ctx context.Context, systemContext *types.SystemContext, store storage.Store, options BuilderOptions) (types.ImageReference, string, *storage.Image, error) { type failure struct { resolvedImageName string err error } - - candidates, searchRegistriesWereUsedButEmpty, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store) + candidates, transport, searchRegistriesWereUsedButEmpty, err := util.ResolveName(options.FromImage, options.Registry, systemContext, store) if err != nil { - return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage) + return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", options.FromImage) } + failures := []failure{} for _, image := range candidates { var err error @@ -118,25 +117,25 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store if img, err := store.Image(image); err == nil && img != nil && strings.HasPrefix(img.ID, image) { ref, err := is.Transport.ParseStoreReference(store, img.ID) if err != nil { - return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID) + return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID) } - return ref, img, nil + return ref, transport, img, nil } } if options.PullPolicy == PullAlways { - pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) + pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext) if err != nil { logrus.Debugf("unable to pull and read image %q: %v", image, err) failures = append(failures, failure{resolvedImageName: image, err: err}) continue } - return pulledReference, pulledImg, nil + return pulledReference, transport, pulledImg, nil } srcRef, err := alltransports.ParseImageName(image) if err != nil { - if options.Transport == "" { + if transport == "" { logrus.Debugf("error parsing image name %q: %v", image, err) failures = append(failures, failure{ resolvedImageName: image, @@ -144,12 +143,13 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store }) continue } - logrus.Debugf("error parsing image name %q as given, trying with transport %q: %v", image, options.Transport, err) - transport := options.Transport + logrus.Debugf("error parsing image name %q as given, trying with transport %q: %v", image, transport, err) + + trans := transport if transport != util.DefaultTransport { - transport = transport + ":" + trans = trans + ":" } - srcRef2, err := alltransports.ParseImageName(transport + image) + srcRef2, err := alltransports.ParseImageName(trans + image) if err != nil { logrus.Debugf("error parsing image name %q: %v", transport+image, err) failures = append(failures, failure{ @@ -163,19 +163,19 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store destImage, err := localImageNameForReference(ctx, store, srcRef, options.FromImage) if err != nil { - return nil, nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef)) + return nil, "", nil, errors.Wrapf(err, "error computing local image name for %q", transports.ImageName(srcRef)) } if destImage == "" { - return nil, nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef)) + return nil, "", nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef)) } ref, err := is.Transport.ParseStoreReference(store, destImage) if err != nil { - return nil, nil, errors.Wrapf(err, "error parsing reference to image %q", destImage) + return nil, "", nil, errors.Wrapf(err, "error parsing reference to image %q", destImage) } img, err := is.Transport.GetStoreImage(store, ref) if err == nil { - return ref, img, nil + return ref, transport, img, nil } if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing { @@ -187,26 +187,26 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store continue } - pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) + pulledImg, pulledReference, err := pullAndFindImage(ctx, store, transport, image, options, systemContext) if err != nil { logrus.Debugf("unable to pull and read image %q: %v", image, err) failures = append(failures, failure{resolvedImageName: image, err: err}) continue } - return pulledReference, pulledImg, nil + return pulledReference, transport, pulledImg, nil } if len(failures) != len(candidates) { - return nil, nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures) + return nil, "", nil, fmt.Errorf("internal error: %d candidates (%#v) vs. %d failures (%#v)", len(candidates), candidates, len(failures), failures) } registriesConfPath := sysregistries.RegistriesConfPath(systemContext) switch len(failures) { case 0: if searchRegistriesWereUsedButEmpty { - return nil, nil, errors.Errorf("image name %q is a short name and no search registries are defined in %s.", options.FromImage, registriesConfPath) + return nil, "", nil, errors.Errorf("image name %q is a short name and no search registries are defined in %s.", options.FromImage, registriesConfPath) } - return nil, nil, fmt.Errorf("internal error: no pull candidates were available for %q for an unknown reason", options.FromImage) + return nil, "", nil, fmt.Errorf("internal error: no pull candidates were available for %q for an unknown reason", options.FromImage) case 1: err := failures[0].err @@ -216,7 +216,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store if searchRegistriesWereUsedButEmpty { err = errors.Wrapf(err, "(image name %q is a short name and no search registries are defined in %s)", options.FromImage, registriesConfPath) } - return nil, nil, err + return nil, "", nil, err default: // NOTE: a multi-line error string: @@ -224,7 +224,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store for _, f := range failures { e = e + fmt.Sprintf("\n* %q: %s", f.resolvedImageName, f.err.Error()) } - return nil, nil, errors.New(e) + return nil, "", nil, errors.New(e) } } @@ -250,21 +250,19 @@ func findUnusedContainer(name string, containers []storage.Container) string { } func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) { - var ref types.ImageReference - var img *storage.Image - var err error - + var ( + ref types.ImageReference + img *storage.Image + err error + ) if options.FromImage == BaseImageFakeName { options.FromImage = "" } - if options.Transport == "" { - options.Transport = util.DefaultTransport - } systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath) if options.FromImage != "" && options.FromImage != "scratch" { - ref, img, err = resolveImage(ctx, systemContext, store, options) + ref, _, img, err = resolveImage(ctx, systemContext, store, options) if err != nil { return nil, err } diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go index bbbbf3476..09f951b35 100644 --- a/vendor/github.com/containers/buildah/pkg/cli/common.go +++ b/vendor/github.com/containers/buildah/pkg/cli/common.go @@ -55,20 +55,21 @@ type BudResults struct { File []string Format string Iidfile string - NoCache bool Label []string Logfile string Loglevel int + NoCache bool Platform string Pull bool PullAlways bool Quiet bool Rm bool Runtime string - RuntimeOpts []string + RuntimeFlags []string SignaturePolicy string Squash bool Tag []string + Target string TlsVerify bool } @@ -138,7 +139,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet { fs.StringVar(&flags.CertDir, "cert-dir", "", "use certificates at the specified path to access the registry") fs.BoolVar(&flags.Compress, "compress", false, "This is legacy option, which has no effect on the image") fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry") - fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", false, "don't compress layers by default") + fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", true, "don't compress layers by default") fs.BoolVar(&flags.DisableContentTrust, "disable-content-trust", false, "This is a Docker specific option and is a NOOP") fs.StringSliceVarP(&flags.File, "file", "f", []string{}, "`pathname or URL` of a Dockerfile") fs.StringVar(&flags.Format, "format", DefaultFormat(), "`format` of the built image's manifest and metadata. Use BUILDAH_FORMAT environment variable to override.") @@ -153,10 +154,11 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet { fs.BoolVarP(&flags.Quiet, "quiet", "q", false, "refrain from announcing build instructions and image read/write progress") fs.BoolVar(&flags.Rm, "rm", true, "Remove intermediate containers after a successful build (default true)") fs.StringVar(&flags.Runtime, "runtime", util.Runtime(), "`path` to an alternate runtime. Use BUILDAH_RUNTIME environment variable to override.") - fs.StringSliceVar(&flags.RuntimeOpts, "runtime-flag", []string{}, "add global flags for the container runtime") + fs.StringSliceVar(&flags.RuntimeFlags, "runtime-flag", []string{}, "add global flags for the container runtime") fs.StringVar(&flags.SignaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)") fs.BoolVar(&flags.Squash, "squash", false, "Squash newly built layers into a single new layer. The build process does not currently support caching so this is a NOOP.") fs.StringSliceVarP(&flags.Tag, "tag", "t", []string{}, "tagged `name` to apply to the built image") + fs.StringVar(&flags.Target, "target", "", "set the target build stage to build") fs.BoolVar(&flags.TlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") return fs } diff --git a/vendor/github.com/containers/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go index ffc7c15bb..a26d15631 100644 --- a/vendor/github.com/containers/buildah/pkg/parse/parse.go +++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go @@ -251,9 +251,9 @@ func SystemContextFromOptions(c *cobra.Command) (*types.SystemContext, error) { } tlsVerify, err := c.Flags().GetBool("tls-verify") if err == nil && c.Flag("tls-verify").Changed { - ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(tlsVerify) - ctx.OCIInsecureSkipTLSVerify = tlsVerify - ctx.DockerDaemonInsecureSkipTLSVerify = tlsVerify + ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!tlsVerify) + ctx.OCIInsecureSkipTLSVerify = !tlsVerify + ctx.DockerDaemonInsecureSkipTLSVerify = !tlsVerify } creds, err := c.Flags().GetString("creds") if err == nil && c.Flag("creds").Changed { diff --git a/vendor/github.com/containers/buildah/pull.go b/vendor/github.com/containers/buildah/pull.go index aede1784b..d1f33fb01 100644 --- a/vendor/github.com/containers/buildah/pull.go +++ b/vendor/github.com/containers/buildah/pull.go @@ -9,10 +9,13 @@ import ( "github.com/containers/buildah/pkg/blobcache" "github.com/containers/buildah/util" cp "github.com/containers/image/copy" + "github.com/containers/image/directory" "github.com/containers/image/docker" + dockerarchive "github.com/containers/image/docker/archive" "github.com/containers/image/docker/reference" tarfile "github.com/containers/image/docker/tarfile" ociarchive "github.com/containers/image/oci/archive" + oci "github.com/containers/image/oci/layout" "github.com/containers/image/signature" is "github.com/containers/image/storage" "github.com/containers/image/transports" @@ -40,10 +43,6 @@ type PullOptions struct { // github.com/containers/image/types SystemContext to hold credentials // and other authentication/authorization information. SystemContext *types.SystemContext - // Transport is a value which is prepended to the image's name, if the - // image name alone can not be resolved to a reference to a source - // image. No separator is implicitly added. - Transport string // BlobDirectory is the name of a directory in which we'll attempt to // store copies of layer blobs that we pull down, if any. It should // already exist. @@ -51,10 +50,6 @@ type PullOptions struct { // AllTags is a boolean value that determines if all tagged images // will be downloaded from the repository. The default is false. AllTags bool - // Quiet is a boolean value that determines if minimal output to - // the user will be displayed, this is best used for logging. - // The default is false. - Quiet bool } func localImageNameForReference(ctx context.Context, store storage.Store, srcRef types.ImageReference, spec string) (string, error) { @@ -65,7 +60,7 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef file := split[len(split)-1] var name string switch srcRef.Transport().Name() { - case util.DockerArchive: + case dockerarchive.Transport.Name(): tarSource, err := tarfile.NewSourceFromFile(file) if err != nil { return "", errors.Wrapf(err, "error opening tarfile %q as a source image", file) @@ -92,7 +87,7 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef } } } - case util.OCIArchive: + case ociarchive.Transport.Name(): // retrieve the manifest from index.json to access the image name manifest, err := ociarchive.LoadManifestDescriptor(srcRef) if err != nil { @@ -107,7 +102,14 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef } else { name = manifest.Annotations["org.opencontainers.image.ref.name"] } - case util.DirTransport: + case directory.Transport.Name(): + // supports pull from a directory + name = split[1] + // remove leading "/" + if name[:1] == "/" { + name = name[1:] + } + case oci.Transport.Name(): // supports pull from a directory name = split[1] // remove leading "/" @@ -152,76 +154,71 @@ func localImageNameForReference(ctx context.Context, store storage.Store, srcRef // Pull copies the contents of the image from somewhere else to local storage. func Pull(ctx context.Context, imageName string, options PullOptions) error { - spec := imageName systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath) - srcRef, err := alltransports.ParseImageName(spec) - if err != nil { - if options.Transport == "" { - options.Transport = util.DefaultTransport - } - logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, options.Transport, err) - transport := options.Transport - if transport != util.DefaultTransport { - transport = transport + ":" - } - spec = transport + spec - srcRef2, err2 := alltransports.ParseImageName(spec) - if err2 != nil { - return errors.Wrapf(err2, "error parsing image name %q", imageName) - } - srcRef = srcRef2 + + boptions := BuilderOptions{ + FromImage: imageName, + SignaturePolicyPath: options.SignaturePolicyPath, + SystemContext: systemContext, + PullBlobDirectory: options.BlobDirectory, + ReportWriter: options.ReportWriter, } - if options.Quiet { - options.ReportWriter = nil // Turns off logging output + + storageRef, transport, img, err := resolveImage(ctx, systemContext, options.Store, boptions) + if err != nil { + return err } - var names []string + + var errs *multierror.Error if options.AllTags { - if srcRef.DockerReference() == nil { - return errors.New("Non-docker transport is currently not supported") + if transport != util.DefaultTransport { + return errors.New("Non-docker transport is not supported, for --all-tags pulling") + } + + spec := transport + storageRef.DockerReference().Name() + storageRef, err = alltransports.ParseImageName(spec) + if err != nil { + return errors.Wrapf(err, "error getting repository tags") } - tags, err := docker.GetRepositoryTags(ctx, systemContext, srcRef) + tags, err := docker.GetRepositoryTags(ctx, systemContext, storageRef) if err != nil { return errors.Wrapf(err, "error getting repository tags") } for _, tag := range tags { name := spec + ":" + tag - names = append(names, name) + if options.ReportWriter != nil { + options.ReportWriter.Write([]byte("Pulling " + name + "\n")) + } + ref, err := pullImage(ctx, options.Store, transport, name, options, systemContext) + if err != nil { + errs = multierror.Append(errs, err) + continue + } + img, err := is.Transport.GetStoreImage(options.Store, ref) + if err != nil { + errs = multierror.Append(errs, err) + continue + } + fmt.Printf("%s\n", img.ID) } } else { - names = append(names, spec) - } - var errs *multierror.Error - for _, name := range names { - if options.ReportWriter != nil { - options.ReportWriter.Write([]byte("Pulling " + name + "\n")) - } - ref, err := pullImage(ctx, options.Store, name, options, systemContext) - if err != nil { - errs = multierror.Append(errs, err) - continue - } - img, err := is.Transport.GetStoreImage(options.Store, ref) - if err != nil { - errs = multierror.Append(errs, err) - continue - } fmt.Printf("%s\n", img.ID) } return errs.ErrorOrNil() } -func pullImage(ctx context.Context, store storage.Store, imageName string, options PullOptions, sc *types.SystemContext) (types.ImageReference, error) { +func pullImage(ctx context.Context, store storage.Store, transport string, imageName string, options PullOptions, sc *types.SystemContext) (types.ImageReference, error) { spec := imageName srcRef, err := alltransports.ParseImageName(spec) if err != nil { - if options.Transport == "" { - options.Transport = util.DefaultTransport - } - logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, options.Transport, err) - transport := options.Transport - if transport != util.DefaultTransport { - transport = transport + ":" + logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, transport, err) + if transport == "" { + transport = util.DefaultTransport + } else { + if transport != util.DefaultTransport { + transport = transport + ":" + } } spec = transport + spec srcRef2, err2 := alltransports.ParseImageName(spec) diff --git a/vendor/github.com/containers/buildah/unshare/unshare.c b/vendor/github.com/containers/buildah/unshare/unshare.c index 3865e414f..8eefae41b 100644 --- a/vendor/github.com/containers/buildah/unshare/unshare.c +++ b/vendor/github.com/containers/buildah/unshare/unshare.c @@ -2,6 +2,8 @@ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/stat.h> +#include <sys/syscall.h> +#include <linux/memfd.h> #include <fcntl.h> #include <grp.h> #include <sched.h> @@ -12,6 +14,28 @@ #include <errno.h> #include <unistd.h> +#ifndef F_LINUX_SPECIFIC_BASE +#define F_LINUX_SPECIFIC_BASE 1024 +#endif +#ifndef F_ADD_SEALS +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) +#endif +#ifndef F_SEAL_SEAL +#define F_SEAL_SEAL 0x0001LU +#endif +#ifndef F_SEAL_SHRINK +#define F_SEAL_SHRINK 0x0002LU +#endif +#ifndef F_SEAL_GROW +#define F_SEAL_GROW 0x0004LU +#endif +#ifndef F_SEAL_WRITE +#define F_SEAL_WRITE 0x0008LU +#endif + +#define BUFSTEP 1024 + static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces"; static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone"; @@ -59,6 +83,119 @@ static void _check_proc_sys_file(const char *path) } } +static char **parse_proc_stringlist(const char *list) { + int fd, n, i, n_strings; + char *buf, *new_buf, **ret; + size_t size, new_size, used; + + fd = open(list, O_RDONLY); + if (fd == -1) { + return NULL; + } + buf = NULL; + size = 0; + used = 0; + for (;;) { + new_size = used + BUFSTEP; + new_buf = realloc(buf, new_size); + if (new_buf == NULL) { + free(buf); + fprintf(stderr, "realloc(%ld): out of memory\n", (long)(size + BUFSTEP)); + return NULL; + } + buf = new_buf; + size = new_size; + memset(buf + used, '\0', size - used); + n = read(fd, buf + used, size - used - 1); + if (n < 0) { + fprintf(stderr, "read(): %m\n"); + return NULL; + } + if (n == 0) { + break; + } + used += n; + } + close(fd); + n_strings = 0; + for (n = 0; n < used; n++) { + if ((n == 0) || (buf[n-1] == '\0')) { + n_strings++; + } + } + ret = calloc(n_strings + 1, sizeof(char *)); + if (ret == NULL) { + fprintf(stderr, "calloc(): out of memory\n"); + return NULL; + } + i = 0; + for (n = 0; n < used; n++) { + if ((n == 0) || (buf[n-1] == '\0')) { + ret[i++] = &buf[n]; + } + } + ret[i] = NULL; + return ret; +} + +static int buildah_reexec(void) { + char **argv, *exename; + int fd, mmfd, n_read, n_written; + struct stat st; + char buf[2048]; + + argv = parse_proc_stringlist("/proc/self/cmdline"); + if (argv == NULL) { + return -1; + } + fd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + fprintf(stderr, "open(\"/proc/self/exe\"): %m\n"); + return -1; + } + if (fstat(fd, &st) == -1) { + fprintf(stderr, "fstat(\"/proc/self/exe\"): %m\n"); + return -1; + } + exename = basename(argv[0]); + mmfd = syscall(SYS_memfd_create, exename, (long) MFD_ALLOW_SEALING | MFD_CLOEXEC); + if (mmfd == -1) { + fprintf(stderr, "memfd_create(): %m\n"); + return -1; + } + for (;;) { + n_read = read(fd, buf, sizeof(buf)); + if (n_read < 0) { + fprintf(stderr, "read(\"/proc/self/exe\"): %m\n"); + return -1; + } + if (n_read == 0) { + break; + } + n_written = write(mmfd, buf, n_read); + if (n_written < 0) { + fprintf(stderr, "write(anonfd): %m\n"); + return -1; + } + if (n_written != n_read) { + fprintf(stderr, "write(anonfd): short write (%d != %d)\n", n_written, n_read); + return -1; + } + } + close(fd); + if (fcntl(mmfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) == -1) { + close(mmfd); + fprintf(stderr, "Error sealing memfd copy: %m\n"); + return -1; + } + if (fexecve(mmfd, argv, environ) == -1) { + close(mmfd); + fprintf(stderr, "Error during reexec(...): %m\n"); + return -1; + } + return 0; +} + void _buildah_unshare(void) { int flags, pidfd, continuefd, n, pgrp, sid, ctty; @@ -132,5 +269,8 @@ void _buildah_unshare(void) _exit(1); } } + if (buildah_reexec() != 0) { + _exit(1); + } return; } diff --git a/vendor/github.com/containers/buildah/unshare/unshare.go b/vendor/github.com/containers/buildah/unshare/unshare.go index 2a970b8d6..1072c2035 100644 --- a/vendor/github.com/containers/buildah/unshare/unshare.go +++ b/vendor/github.com/containers/buildah/unshare/unshare.go @@ -56,8 +56,10 @@ func (c *Cmd) Start() error { c.Env = append(c.Env, fmt.Sprintf("_Buildah-unshare=%d", c.UnshareFlags)) // Please the libpod "rootless" package to find the expected env variables. - c.Env = append(c.Env, "_LIBPOD_USERNS_CONFIGURED=done") - c.Env = append(c.Env, fmt.Sprintf("_LIBPOD_ROOTLESS_UID=%d", os.Geteuid())) + if os.Geteuid() != 0 { + c.Env = append(c.Env, "_LIBPOD_USERNS_CONFIGURED=done") + c.Env = append(c.Env, fmt.Sprintf("_LIBPOD_ROOTLESS_UID=%d", os.Geteuid())) + } // Create the pipe for reading the child's PID. pidRead, pidWrite, err := os.Pipe() diff --git a/vendor/github.com/containers/buildah/util/util.go b/vendor/github.com/containers/buildah/util/util.go index e46f9b7cb..d98493634 100644 --- a/vendor/github.com/containers/buildah/util/util.go +++ b/vendor/github.com/containers/buildah/util/util.go @@ -11,14 +11,11 @@ import ( "strings" "syscall" - "github.com/containers/image/directory" - dockerarchive "github.com/containers/image/docker/archive" "github.com/containers/image/docker/reference" - ociarchive "github.com/containers/image/oci/archive" "github.com/containers/image/pkg/sysregistriesv2" "github.com/containers/image/signature" is "github.com/containers/image/storage" - "github.com/containers/image/tarball" + "github.com/containers/image/transports" "github.com/containers/image/types" "github.com/containers/storage" "github.com/containers/storage/pkg/idtools" @@ -43,36 +40,18 @@ var ( "index.docker.io": "library", "docker.io": "library", } - // Transports contains the possible transports used for images - Transports = map[string]string{ - dockerarchive.Transport.Name(): "", - ociarchive.Transport.Name(): "", - directory.Transport.Name(): "", - tarball.Transport.Name(): "", - } - // DockerArchive is the transport we prepend to an image name - // when saving to docker-archive - DockerArchive = dockerarchive.Transport.Name() - // OCIArchive is the transport we prepend to an image name - // when saving to oci-archive - OCIArchive = ociarchive.Transport.Name() - // DirTransport is the transport for pushing and pulling - // images to and from a directory - DirTransport = directory.Transport.Name() - // TarballTransport is the transport for importing a tar archive - // and creating a filesystem image - TarballTransport = tarball.Transport.Name() ) // ResolveName checks if name is a valid image name, and if that name doesn't // include a domain portion, returns a list of the names which it might -// correspond to in the set of configured registries, -// and a boolean which is true iff 1) the list of search registries was used, and 2) it was empty. +// correspond to in the set of configured registries, the transport used to +// pull the image, and a boolean which is true iff +// 1) the list of search registries was used, and 2) it was empty. // NOTE: The "list of search registries is empty" check does not count blocked registries, // and neither the implied "localhost" nor a possible firstRegistry are counted -func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) ([]string, bool, error) { +func ResolveName(name string, firstRegistry string, sc *types.SystemContext, store storage.Store) ([]string, string, bool, error) { if name == "" { - return nil, false, nil + return nil, "", false, nil } // Maybe it's a truncated image ID. Don't prepend a registry name, then. @@ -80,27 +59,28 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto if img, err := store.Image(name); err == nil && img != nil && strings.HasPrefix(img.ID, name) { // It's a truncated version of the ID of an image that's present in local storage; // we need only expand the ID. - return []string{img.ID}, false, nil + return []string{img.ID}, "", false, nil } } // If the image includes a transport's name as a prefix, use it as-is. + if strings.HasPrefix(name, DefaultTransport) { + return []string{strings.TrimPrefix(name, DefaultTransport)}, DefaultTransport, false, nil + } split := strings.SplitN(name, ":", 2) if len(split) == 2 { - if _, ok := Transports[split[0]]; ok { - return []string{split[1]}, false, nil + if trans := transports.Get(split[0]); trans != nil { + return []string{split[1]}, trans.Name(), false, nil } } - - name = strings.TrimPrefix(name, DefaultTransport) // If the image name already included a domain component, we're done. named, err := reference.ParseNormalizedNamed(name) if err != nil { - return nil, false, errors.Wrapf(err, "error parsing image name %q", name) + return nil, "", false, errors.Wrapf(err, "error parsing image name %q", name) } if named.String() == name { // Parsing produced the same result, so there was a domain name in there to begin with. - return []string{name}, false, nil + return []string{name}, DefaultTransport, false, nil } if reference.Domain(named) != "" && RegistryDefaultPathPrefix[reference.Domain(named)] != "" { // If this domain can cause us to insert something in the middle, check if that happened. @@ -117,7 +97,7 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto defaultPrefix := RegistryDefaultPathPrefix[reference.Domain(named)] + "/" if strings.HasPrefix(repoPath, defaultPrefix) && path.Join(domain, repoPath[len(defaultPrefix):])+tag+digest == name { // Yup, parsing just inserted a bit in the middle, so there was a domain name there to begin with. - return []string{name}, false, nil + return []string{name}, DefaultTransport, false, nil } } @@ -153,7 +133,7 @@ func ResolveName(name string, firstRegistry string, sc *types.SystemContext, sto candidate := path.Join(registry, middle, name) candidates = append(candidates, candidate) } - return candidates, searchRegistriesAreEmpty, nil + return candidates, DefaultTransport, searchRegistriesAreEmpty, nil } // ExpandNames takes unqualified names, parses them as image names, and returns @@ -164,7 +144,7 @@ func ExpandNames(names []string, firstRegistry string, systemContext *types.Syst expanded := make([]string, 0, len(names)) for _, n := range names { var name reference.Named - nameList, _, err := ResolveName(n, firstRegistry, systemContext, store) + nameList, _, _, err := ResolveName(n, firstRegistry, systemContext, store) if err != nil { return nil, errors.Wrapf(err, "error parsing name %q", n) } @@ -200,7 +180,7 @@ func FindImage(store storage.Store, firstRegistry string, systemContext *types.S var ref types.ImageReference var img *storage.Image var err error - names, _, err := ResolveName(image, firstRegistry, systemContext, store) + names, _, _, err := ResolveName(image, firstRegistry, systemContext, store) if err != nil { return nil, nil, errors.Wrapf(err, "error parsing name %q", image) } diff --git a/vendor/github.com/containers/buildah/vendor.conf b/vendor/github.com/containers/buildah/vendor.conf index bda5f3965..7438fc909 100644 --- a/vendor/github.com/containers/buildah/vendor.conf +++ b/vendor/github.com/containers/buildah/vendor.conf @@ -3,10 +3,13 @@ github.com/blang/semver v3.5.0 github.com/BurntSushi/toml v0.2.0 github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d github.com/containernetworking/cni v0.7.0-alpha1 -github.com/containers/image v1.3 +github.com/containers/image v1.4 +github.com/vbauerster/mpb v3.3.4 +github.com/mattn/go-isatty v0.0.4 +github.com/VividCortex/ewma v1.1.1 github.com/boltdb/bolt v1.3.1 github.com/containers/libpod v1.0 -github.com/containers/storage v1.9 +github.com/containers/storage v1.10 github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716 github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00 github.com/docker/docker-credential-helpers v0.6.1 @@ -21,7 +24,6 @@ github.com/gorilla/mux v1.6.2 github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/go-multierror v1.0.0 github.com/imdario/mergo v0.3.6 -github.com/mattn/go-runewidth v0.0.4 github.com/mattn/go-shellwords v1.0.3 github.com/Microsoft/go-winio v0.4.11 github.com/Microsoft/hcsshim v0.8.3 @@ -36,7 +38,7 @@ github.com/opencontainers/runc v1.0.0-rc6 github.com/opencontainers/runtime-spec v1.0.0 github.com/opencontainers/runtime-tools v0.8.0 github.com/opencontainers/selinux v1.1 -github.com/openshift/imagebuilder a4122153148e3b34161191f868565d8dffe65a69 +github.com/openshift/imagebuilder 36823496a6868f72bc36282cc475eb8a070c0934 github.com/ostreedev/ostree-go 9ab99253d365aac3a330d1f7281cf29f3d22820b github.com/pkg/errors v0.8.1 github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac @@ -55,7 +57,6 @@ golang.org/x/net 45ffb0cd1ba084b73e26dee67e667e1be5acce83 https://github.com/gol golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f https://github.com/golang/sync golang.org/x/sys 7fbe1cd0fcc20051e1fcb87fbabec4a1bacaaeba https://github.com/golang/sys golang.org/x/text e6919f6577db79269a6443b9dc46d18f2238fb5d https://github.com/golang/text -gopkg.in/cheggaaa/pb.v1 v1.0.27 gopkg.in/yaml.v2 v2.2.2 k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go github.com/klauspost/pgzip v1.2.1 @@ -63,17 +64,4 @@ github.com/klauspost/compress v1.4.1 github.com/klauspost/cpuid v1.2.0 github.com/onsi/gomega v1.4.3 github.com/spf13/cobra v0.0.3 -github.com/cpuguy83/go-md2man v1.0.8 github.com/spf13/pflag v1.0.3 -github.com/inconshreveable/mousetrap v1.0.0 -github.com/russross/blackfriday v2.0.1 -github.com/mitchellh/go-homedir v1.0.0 -github.com/spf13/viper v1.3.1 -github.com/fsnotify/fsnotify v1.4.7 -github.com/hashicorp/hcl v1.0.0 -github.com/magiconair/properties v1.8.0 -github.com/mitchellh/mapstructure v1.1.2 -github.com/pelletier/go-toml v1.2.0 -github.com/spf13/afero v1.2.0 -github.com/spf13/cast v1.3.0 -github.com/spf13/jwalterweatherman v1.0.0 diff --git a/vendor/github.com/openshift/imagebuilder/README.md b/vendor/github.com/openshift/imagebuilder/README.md index 2f9c110dd..f26b4a7e0 100644 --- a/vendor/github.com/openshift/imagebuilder/README.md +++ b/vendor/github.com/openshift/imagebuilder/README.md @@ -70,7 +70,7 @@ is ignored. ## Code Example -``` +```go f, err := os.Open("path/to/Dockerfile") if err != nil { return err diff --git a/vendor/github.com/openshift/imagebuilder/builder.go b/vendor/github.com/openshift/imagebuilder/builder.go index d37965df6..16682af7d 100644 --- a/vendor/github.com/openshift/imagebuilder/builder.go +++ b/vendor/github.com/openshift/imagebuilder/builder.go @@ -40,6 +40,7 @@ type Run struct { type Executor interface { Preserve(path string) error + EnsureContainerPath(path string) error Copy(excludes []string, copies ...Copy) error Run(run Run, config docker.Config) error UnrecognizedInstruction(step *Step) error @@ -52,6 +53,11 @@ func (logExecutor) Preserve(path string) error { return nil } +func (logExecutor) EnsureContainerPath(path string) error { + log.Printf("ENSURE %s", path) + return nil +} + func (logExecutor) Copy(excludes []string, copies ...Copy) error { for _, c := range copies { log.Printf("COPY %v -> %s (from:%s download:%t), chown: %s", c.Src, c.Dest, c.From, c.Download, c.Chown) @@ -75,6 +81,10 @@ func (noopExecutor) Preserve(path string) error { return nil } +func (noopExecutor) EnsureContainerPath(path string) error { + return nil +} + func (noopExecutor) Copy(excludes []string, copies ...Copy) error { return nil } @@ -153,6 +163,7 @@ func (stages Stages) ByName(name string) (Stage, bool) { return Stage{}, false } +// Get just the target stage. func (stages Stages) ByTarget(target string) (Stages, bool) { if len(target) == 0 { return stages, true @@ -165,6 +176,19 @@ func (stages Stages) ByTarget(target string) (Stages, bool) { return nil, false } +// Get all the stages up to and including the target. +func (stages Stages) ThroughTarget(target string) (Stages, bool) { + if len(target) == 0 { + return stages, true + } + for i, stage := range stages { + if stage.Name == target { + return stages[0 : i+1], true + } + } + return nil, false +} + type Stage struct { Position int Name string @@ -319,6 +343,13 @@ func (b *Builder) Run(step *Step, exec Executor, noRunsRemaining bool) error { if err := exec.Copy(b.Excludes, copies...); err != nil { return err } + + if len(b.RunConfig.WorkingDir) > 0 { + if err := exec.EnsureContainerPath(b.RunConfig.WorkingDir); err != nil { + return err + } + } + for _, run := range runs { config := b.Config() config.Env = step.Env diff --git a/vendor/github.com/openshift/imagebuilder/dispatchers.go b/vendor/github.com/openshift/imagebuilder/dispatchers.go index f6510c2fd..ff365848a 100644 --- a/vendor/github.com/openshift/imagebuilder/dispatchers.go +++ b/vendor/github.com/openshift/imagebuilder/dispatchers.go @@ -128,9 +128,20 @@ func add(b *Builder, args []string, attributes map[string]bool, flagArgs []strin if len(args) < 2 { return errAtLeastOneArgument("ADD") } + var chown string last := len(args) - 1 dest := makeAbsolute(args[last], b.RunConfig.WorkingDir) - b.PendingCopies = append(b.PendingCopies, Copy{Src: args[0:last], Dest: dest, Download: true}) + if len(flagArgs) > 0 { + for _, arg := range flagArgs { + switch { + case strings.HasPrefix(arg, "--chown="): + chown = strings.TrimPrefix(arg, "--chown=") + default: + return fmt.Errorf("ADD only supports the --chown=<uid:gid> flag") + } + } + } + b.PendingCopies = append(b.PendingCopies, Copy{Src: args[0:last], Dest: dest, Download: true, Chown: chown}) return nil } |