diff options
68 files changed, 637 insertions, 330 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 2054381ec..e40e35cb5 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -9,7 +9,7 @@ import ( "github.com/containers/buildah/imagebuildah" buildahcli "github.com/containers/buildah/pkg/cli" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/docker/go-units" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -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) } @@ -272,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 d8fc44c2f..53aa62eb9 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, } @@ -94,13 +93,10 @@ func getContainerSubCommands() []*cobra.Command { func getPodSubCommands() []*cobra.Command { return []*cobra.Command{ _podCreateCommand, - _podKillCommand, _podPauseCommand, _podPsCommand, _podRestartCommand, - _podStartCommand, _podStatsCommand, - _podStopCommand, _podTopCommand, _podUnpauseCommand, } diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go index bae578e1d..6e4960429 100644 --- a/cmd/podman/containers_prune.go +++ b/cmd/podman/containers_prune.go @@ -6,7 +6,7 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" 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/exists.go b/cmd/podman/exists.go index aad203818..74a4c841b 100644 --- a/cmd/podman/exists.go +++ b/cmd/podman/exists.go @@ -6,8 +6,8 @@ import ( "os" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" ) diff --git a/cmd/podman/export.go b/cmd/podman/export.go index a593a4753..5873bad3d 100644 --- a/cmd/podman/export.go +++ b/cmd/podman/export.go @@ -4,7 +4,7 @@ import ( "os" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" 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/history.go b/cmd/podman/history.go index 6791257d9..103ef08e8 100644 --- a/cmd/podman/history.go +++ b/cmd/podman/history.go @@ -8,8 +8,8 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" - "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/adapter" "github.com/docker/go-units" "github.com/pkg/errors" "github.com/spf13/cobra" diff --git a/cmd/podman/imagefilters/filters.go b/cmd/podman/imagefilters/filters.go index 366510202..d01eb7436 100644 --- a/cmd/podman/imagefilters/filters.go +++ b/cmd/podman/imagefilters/filters.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/inspect" ) diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 56810eaeb..6e82195a9 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -11,8 +11,8 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/cmd/podman/imagefilters" - "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/adapter" "github.com/docker/go-units" "github.com/opencontainers/go-digest" "github.com/pkg/errors" diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go index cc0dcb99a..79dcd097c 100644 --- a/cmd/podman/images_prune.go +++ b/cmd/podman/images_prune.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/import.go b/cmd/podman/import.go index 053408ff3..a64b03d6d 100644 --- a/cmd/podman/import.go +++ b/cmd/podman/import.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/info.go b/cmd/podman/info.go index 06dbbd748..a1473dac9 100644 --- a/cmd/podman/info.go +++ b/cmd/podman/info.go @@ -7,7 +7,7 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/version" "github.com/pkg/errors" "github.com/spf13/cobra" diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 48b953207..46883b31d 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -8,7 +8,7 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" cc "github.com/containers/libpod/pkg/spec" "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" diff --git a/cmd/podman/load.go b/cmd/podman/load.go index 514c9f1e9..272cd78d2 100644 --- a/cmd/podman/load.go +++ b/cmd/podman/load.go @@ -7,7 +7,7 @@ import ( "os" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) 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/pod.go b/cmd/podman/pod.go index d65e0b384..4c7c416ce 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -22,7 +22,10 @@ var podCommand = cliconfig.PodmanCommand{ var podSubCommands = []*cobra.Command{ _podExistsCommand, _podInspectCommand, + _podKillCommand, _podRmCommand, + _podStartCommand, + _podStopCommand, } func init() { diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go index 1f4d1a3dd..5a32b5c5d 100644 --- a/cmd/podman/pod_inspect.go +++ b/cmd/podman/pod_inspect.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go index d0318b409..aaaae0f7d 100644 --- a/cmd/podman/pod_kill.go +++ b/cmd/podman/pod_kill.go @@ -5,7 +5,7 @@ import ( "syscall" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/pkg/adapter" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -45,7 +45,7 @@ func init() { // podKillCmd kills one or more pods with a signal func podKillCmd(c *cliconfig.PodKillValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } @@ -63,30 +63,20 @@ func podKillCmd(c *cliconfig.PodKillValues) error { killSignal = uint(sysSignal) } - // getPodsFromContext returns an error when a requested pod - // isn't found. The only fatal error scenerio is when there are no pods - // in which case the following loop will be skipped. - pods, lastError := getPodsFromContext(&c.PodmanCommand, runtime) + podKillIds, podKillErrors := runtime.KillPods(getContext(), c, killSignal) + for _, p := range podKillIds { + fmt.Println(p) + } + if len(podKillErrors) == 0 { + return nil + } + // Grab the last error + lastError := podKillErrors[len(podKillErrors)-1] + // Remove the last error from the error slice + podKillErrors = podKillErrors[:len(podKillErrors)-1] - for _, pod := range pods { - ctr_errs, err := pod.Kill(killSignal) - if ctr_errs != nil { - for ctr, err := range ctr_errs { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to kill container %q in pod %q", ctr, pod.ID()) - } - continue - } - if err != nil { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to kill pod %q", pod.ID()) - continue - } - fmt.Println(pod.ID()) + for _, err := range podKillErrors { + logrus.Errorf("%q", err) } return lastError } diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go index b552b9f42..ba16d03c7 100644 --- a/cmd/podman/pod_rm.go +++ b/cmd/podman/pod_rm.go @@ -2,9 +2,9 @@ package main import ( "fmt" - "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go index 3bba5c2e9..5761afd52 100644 --- a/cmd/podman/pod_start.go +++ b/cmd/podman/pod_start.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -45,38 +45,26 @@ func init() { } func podStartCmd(c *cliconfig.PodStartValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.Shutdown(false) - // getPodsFromContext returns an error when a requested pod - // isn't found. The only fatal error scenerio is when there are no pods - // in which case the following loop will be skipped. - pods, lastError := getPodsFromContext(&c.PodmanCommand, runtime) - - ctx := getContext() - for _, pod := range pods { - ctr_errs, err := pod.Start(ctx) - if ctr_errs != nil { - for ctr, err := range ctr_errs { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to start container %q on pod %q", ctr, pod.ID()) - } - continue - } - if err != nil { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to start pod %q", pod.ID()) - continue - } - fmt.Println(pod.ID()) + podStartIDs, podStartErrors := runtime.StartPods(getContext(), c) + for _, p := range podStartIDs { + fmt.Println(p) + } + if len(podStartErrors) == 0 { + return nil } + // Grab the last error + lastError := podStartErrors[len(podStartErrors)-1] + // Remove the last error from the error slice + podStartErrors = podStartErrors[:len(podStartErrors)-1] + for _, err := range podStartErrors { + logrus.Errorf("%q", err) + } return lastError } diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go index 52c92b521..62d0d4aa5 100644 --- a/cmd/podman/pod_stop.go +++ b/cmd/podman/pod_stop.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -47,43 +47,26 @@ func init() { } func podStopCmd(c *cliconfig.PodStopValues) error { - timeout := -1 - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.Shutdown(false) - // getPodsFromContext returns an error when a requested pod - // isn't found. The only fatal error scenerio is when there are no pods - // in which case the following loop will be skipped. - pods, lastError := getPodsFromContext(&c.PodmanCommand, runtime) - - ctx := getContext() - - if c.Flag("timeout").Changed { - timeout = int(c.Timeout) + podStopIds, podStopErrors := runtime.StopPods(getContext(), c) + for _, p := range podStopIds { + fmt.Println(p) } - for _, pod := range pods { - // set cleanup to true to clean mounts and namespaces - ctr_errs, err := pod.StopWithTimeout(ctx, true, timeout) - if ctr_errs != nil { - for ctr, err := range ctr_errs { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to stop container %q on pod %q", ctr, pod.ID()) - } - continue - } - if err != nil { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to stop pod %q", pod.ID()) - continue - } - fmt.Println(pod.ID()) + if len(podStopErrors) == 0 { + return nil + } + // Grab the last error + lastError := podStopErrors[len(podStopErrors)-1] + // Remove the last error from the error slice + podStopErrors = podStopErrors[:len(podStopErrors)-1] + + for _, err := range podStopErrors { + logrus.Errorf("%q", err) } return lastError } diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 476bccb0e..71f555162 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -11,9 +11,9 @@ import ( "github.com/containers/image/transports/alltransports" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/libpod/common" image2 "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/util" opentracing "github.com/opentracing/opentracing-go" "github.com/pkg/errors" diff --git a/cmd/podman/push.go b/cmd/podman/push.go index 881d8cebc..56261a8d3 100644 --- a/cmd/podman/push.go +++ b/cmd/podman/push.go @@ -10,8 +10,8 @@ import ( "github.com/containers/image/manifest" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/util" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" 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 fb27772f5..709ed14e0 100644 --- a/cmd/podman/rmi.go +++ b/cmd/podman/rmi.go @@ -5,7 +5,9 @@ import ( "os" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "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" "github.com/spf13/cobra" @@ -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/save.go b/cmd/podman/save.go index ab421add6..161540deb 100644 --- a/cmd/podman/save.go +++ b/cmd/podman/save.go @@ -1,14 +1,15 @@ package main import ( + "os" + "strings" + "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "os" - "strings" ) const ( diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go index a91d7bf0a..a823dcad1 100644 --- a/cmd/podman/system_prune.go +++ b/cmd/podman/system_prune.go @@ -8,7 +8,7 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go index 422e9dbf6..2b9d67066 100644 --- a/cmd/podman/tag.go +++ b/cmd/podman/tag.go @@ -2,7 +2,7 @@ package main import ( "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) 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/cmd/podman/volume_create.go b/cmd/podman/volume_create.go index 6c8a78922..833191082 100644 --- a/cmd/podman/volume_create.go +++ b/cmd/podman/volume_create.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go index 3b4ba51d5..dc6afbc36 100644 --- a/cmd/podman/volume_inspect.go +++ b/cmd/podman/volume_inspect.go @@ -2,7 +2,7 @@ package main import ( "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go index 0edadc5ac..5adfc1e91 100644 --- a/cmd/podman/volume_ls.go +++ b/cmd/podman/volume_ls.go @@ -6,7 +6,7 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go index a2205140f..1f7931aa4 100644 --- a/cmd/podman/volume_prune.go +++ b/cmd/podman/volume_prune.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" diff --git a/cmd/podman/volume_rm.go b/cmd/podman/volume_rm.go index 14847a949..03b6ccae1 100644 --- a/cmd/podman/volume_rm.go +++ b/cmd/podman/volume_rm.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) 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/libpod/adapter/pods.go b/libpod/adapter/pods.go deleted file mode 100644 index 9841c20c0..000000000 --- a/libpod/adapter/pods.go +++ /dev/null @@ -1,54 +0,0 @@ -// +build !remoteclient - -package adapter - -import ( - "context" - "github.com/containers/libpod/libpod/adapter/shortcuts" - - "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/libpod" -) - -// Pod ... -type Pod struct { - *libpod.Pod -} - -// RemovePods ... -func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValues) ([]string, []error) { - var ( - errs []error - podids []string - ) - pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) - if err != nil { - errs = append(errs, err) - return nil, errs - } - - for _, p := range pods { - if err := r.RemovePod(ctx, p, cli.Force, cli.Force); err != nil { - errs = append(errs, err) - } else { - podids = append(podids, p.ID()) - } - } - return podids, errs -} - -// GetLatestPod gets the latest pod and wraps it in an adapter pod -func (r *LocalRuntime) GetLatestPod() (*Pod, error) { - pod := Pod{} - p, err := r.Runtime.GetLatestPod() - pod.Pod = p - return &pod, err -} - -// LookupPod gets a pod by name or id and wraps it in an adapter pod -func (r *LocalRuntime) LookupPod(nameOrID string) (*Pod, error) { - pod := Pod{} - p, err := r.Runtime.LookupPod(nameOrID) - pod.Pod = p - return &pod, err -} diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 2665dd81d..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 @@ -825,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/adapter/client.go b/pkg/adapter/client.go index 6512a5952..6512a5952 100644 --- a/libpod/adapter/client.go +++ b/pkg/adapter/client.go diff --git a/libpod/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 9623304e5..9623304e5 100644 --- a/libpod/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go diff --git a/libpod/adapter/images_remote.go b/pkg/adapter/images_remote.go index e7b38dccc..e7b38dccc 100644 --- a/libpod/adapter/images_remote.go +++ b/pkg/adapter/images_remote.go diff --git a/libpod/adapter/info_remote.go b/pkg/adapter/info_remote.go index 3b691ed17..3b691ed17 100644 --- a/libpod/adapter/info_remote.go +++ b/pkg/adapter/info_remote.go diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go new file mode 100644 index 000000000..f2bcbd473 --- /dev/null +++ b/pkg/adapter/pods.go @@ -0,0 +1,152 @@ +// +build !remoteclient + +package adapter + +import ( + "context" + "github.com/containers/libpod/pkg/adapter/shortcuts" + + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/libpod" +) + +// Pod ... +type Pod struct { + *libpod.Pod +} + +// RemovePods ... +func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValues) ([]string, []error) { + var ( + errs []error + podids []string + ) + pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + for _, p := range pods { + if err := r.RemovePod(ctx, p, cli.Force, cli.Force); err != nil { + errs = append(errs, err) + } else { + podids = append(podids, p.ID()) + } + } + return podids, errs +} + +// GetLatestPod gets the latest pod and wraps it in an adapter pod +func (r *LocalRuntime) GetLatestPod() (*Pod, error) { + pod := Pod{} + p, err := r.Runtime.GetLatestPod() + pod.Pod = p + return &pod, err +} + +// LookupPod gets a pod by name or id and wraps it in an adapter pod +func (r *LocalRuntime) LookupPod(nameOrID string) (*Pod, error) { + pod := Pod{} + p, err := r.Runtime.LookupPod(nameOrID) + pod.Pod = p + return &pod, err +} + +// StopPods is a wrapper to libpod to stop pods based on a cli context +func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValues) ([]string, []error) { + timeout := -1 + if cli.Flags().Changed("timeout") { + timeout = int(cli.Timeout) + } + var ( + errs []error + podids []string + ) + pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + for _, p := range pods { + stopped := true + conErrs, stopErr := p.StopWithTimeout(ctx, true, int(timeout)) + if stopErr != nil { + errs = append(errs, stopErr) + stopped = false + } + if conErrs != nil { + stopped = false + for _, err := range conErrs { + errs = append(errs, err) + } + } + if stopped { + podids = append(podids, p.ID()) + } + } + return podids, errs +} + +// KillPods is a wrapper to libpod to start pods based on the cli context +func (r *LocalRuntime) KillPods(ctx context.Context, cli *cliconfig.PodKillValues, signal uint) ([]string, []error) { + var ( + errs []error + podids []string + ) + pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) + if err != nil { + errs = append(errs, err) + return nil, errs + } + for _, p := range pods { + killed := true + conErrs, killErr := p.Kill(signal) + if killErr != nil { + errs = append(errs, killErr) + killed = false + } + if conErrs != nil { + killed = false + for _, err := range conErrs { + errs = append(errs, err) + } + } + if killed { + podids = append(podids, p.ID()) + } + } + return podids, errs +} + +// StartPods is a wrapper to start pods based on the cli context +func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartValues) ([]string, []error) { + var ( + errs []error + podids []string + ) + pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) + if err != nil { + errs = append(errs, err) + return nil, errs + } + for _, p := range pods { + started := true + conErrs, startErr := p.Start(ctx) + if startErr != nil { + errs = append(errs, startErr) + started = false + } + if conErrs != nil { + started = false + for _, err := range conErrs { + errs = append(errs, err) + } + } + if started { + podids = append(podids, p.ID()) + } + } + return podids, errs +} diff --git a/libpod/adapter/pods_remote.go b/pkg/adapter/pods_remote.go index 57c78821f..04484780a 100644 --- a/libpod/adapter/pods_remote.go +++ b/pkg/adapter/pods_remote.go @@ -96,3 +96,75 @@ func (p *Pod) Inspect() (*libpod.PodInspect, error) { } return &inspectData, nil } + +// StopPods stops pods based on the cli context from the remote client. +func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValues) ([]string, []error) { + var ( + stopErrs []error + stopPods []string + ) + var timeout int64 = -1 + if cli.Flags().Changed("timeout") { + timeout = int64(cli.Timeout) + } + podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs) + if err != nil { + return nil, []error{err} + } + + for _, p := range podIDs { + podID, err := iopodman.StopPod().Call(r.Conn, p, timeout) + if err != nil { + stopErrs = append(stopErrs, err) + } else { + stopPods = append(stopPods, podID) + } + } + return stopPods, stopErrs +} + +// KillPods kills pods over varlink for the remoteclient +func (r *LocalRuntime) KillPods(ctx context.Context, cli *cliconfig.PodKillValues, signal uint) ([]string, []error) { + var ( + killErrs []error + killPods []string + ) + + podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs) + if err != nil { + return nil, []error{err} + } + + for _, p := range podIDs { + podID, err := iopodman.KillPod().Call(r.Conn, p, int64(signal)) + if err != nil { + killErrs = append(killErrs, err) + } else { + killPods = append(killPods, podID) + } + } + return killPods, killErrs +} + +// StartPods starts pods for the remote client over varlink +func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartValues) ([]string, []error) { + var ( + startErrs []error + startPods []string + ) + + podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs) + if err != nil { + return nil, []error{err} + } + + for _, p := range podIDs { + podID, err := iopodman.StartPod().Call(r.Conn, p) + if err != nil { + startErrs = append(startErrs, err) + } else { + startPods = append(startPods, podID) + } + } + return startPods, startErrs +} diff --git a/libpod/adapter/runtime.go b/pkg/adapter/runtime.go index 4f5b98dbb..4f5b98dbb 100644 --- a/libpod/adapter/runtime.go +++ b/pkg/adapter/runtime.go diff --git a/libpod/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index ca2fad852..ca2fad852 100644 --- a/libpod/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go diff --git a/libpod/adapter/shortcuts/shortcuts.go b/pkg/adapter/shortcuts/shortcuts.go index 0633399ae..0633399ae 100644 --- a/libpod/adapter/shortcuts/shortcuts.go +++ b/pkg/adapter/shortcuts/shortcuts.go diff --git a/libpod/adapter/volumes_remote.go b/pkg/adapter/volumes_remote.go index beacd943a..beacd943a 100644 --- a/libpod/adapter/volumes_remote.go +++ b/pkg/adapter/volumes_remote.go 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/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 2988c5d84..ceeed6681 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -2,7 +2,7 @@ package varlinkapi import ( "encoding/json" - "github.com/containers/libpod/libpod/adapter/shortcuts" + "github.com/containers/libpod/pkg/adapter/shortcuts" "github.com/containers/libpod/pkg/rootless" "syscall" @@ -90,7 +90,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{} @@ -106,7 +106,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 { @@ -123,7 +123,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 { @@ -144,7 +144,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) @@ -158,7 +158,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 { @@ -185,7 +185,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) @@ -199,7 +199,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) @@ -213,7 +213,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) @@ -228,7 +228,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()) @@ -241,7 +241,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/pod_start_test.go b/test/e2e/pod_start_test.go index 77e8b586d..ce693012d 100644 --- a/test/e2e/pod_start_test.go +++ b/test/e2e/pod_start_test.go @@ -136,6 +136,5 @@ var _ = Describe("Podman pod start", func() { session = podmanTest.Podman([]string{"pod", "start", podid, "doesnotexist"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) - Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) }) }) diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go index b3d7df252..38f118964 100644 --- a/test/e2e/pod_stop_test.go +++ b/test/e2e/pod_stop_test.go @@ -137,6 +137,5 @@ var _ = Describe("Podman pod stop", func() { session = podmanTest.Podman([]string{"pod", "stop", podid1, "doesnotexist"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) - Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) }) }) 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/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 |