diff options
Diffstat (limited to 'cmd/podman')
73 files changed, 658 insertions, 830 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index b70ff649c..074675e45 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -35,8 +35,8 @@ func init() { flags.StringVar(&attachCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _") flags.BoolVar(&attachCommand.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false") flags.BoolVar(&attachCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true)") - flags.BoolVarP(&attachCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func attachCmd(c *cliconfig.AttachValues) error { diff --git a/cmd/podman/build.go b/cmd/podman/build.go index bb252f171..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) } @@ -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/checkpoint.go b/cmd/podman/checkpoint.go index 3484e8957..c9de5638b 100644 --- a/cmd/podman/checkpoint.go +++ b/cmd/podman/checkpoint.go @@ -29,6 +29,9 @@ var ( checkpointCommand.GlobalFlags = MainGlobalOpts return checkpointCmd(&checkpointCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman checkpoint --keep ctrID podman checkpoint --all podman checkpoint --leave-running --latest`, @@ -45,6 +48,7 @@ func init() { flags.BoolVar(&checkpointCommand.TcpEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections") flags.BoolVarP(&checkpointCommand.All, "all", "a", false, "Checkpoint all running containers") flags.BoolVarP(&checkpointCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func checkpointCmd(c *cliconfig.CheckpointValues) error { @@ -63,11 +67,6 @@ func checkpointCmd(c *cliconfig.CheckpointValues) error { KeepRunning: c.LeaveRunning, TCPEstablished: c.TcpEstablished, } - - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } - containers, lastError := getAllOrLatestContainers(&c.PodmanCommand, runtime, libpod.ContainerStateRunning, "running") for _, ctr := range containers { diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go index 89a4ba050..d68255aa2 100644 --- a/cmd/podman/cleanup.go +++ b/cmd/podman/cleanup.go @@ -26,6 +26,9 @@ var ( cleanupCommand.GlobalFlags = MainGlobalOpts return cleanupCmd(&cleanupCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman container cleanup --latest podman container cleanup ctrID1 ctrID2 ctrID3 podman container cleanup --all`, @@ -40,6 +43,7 @@ func init() { flags.BoolVarP(&cleanupCommand.All, "all", "a", false, "Cleans up all containers") flags.BoolVarP(&cleanupCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.BoolVar(&cleanupCommand.Remove, "rm", false, "After cleanup, remove the container entirely") + markFlagHiddenForRemoteClient("latest", flags) } func cleanupCmd(c *cliconfig.CleanupValues) error { @@ -49,10 +53,6 @@ func cleanupCmd(c *cliconfig.CleanupValues) error { } defer runtime.Shutdown(false) - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } - cleanupContainers, lastError := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all") ctx := getContext() diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index ca788529c..a9032202f 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -548,3 +548,7 @@ type SystemPruneValues struct { Force bool Volume bool } + +type SystemRenumberValues struct { + PodmanCommand +} diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index fa3839a53..fadcca689 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -6,6 +6,8 @@ import ( "github.com/spf13/cobra" ) +const remoteclient = false + // Commands that the local client implements func getMainCommands() []*cobra.Command { rootCommands := []*cobra.Command{ @@ -14,12 +16,9 @@ func getMainCommands() []*cobra.Command { _createCommand, _diffCommand, _execCommand, - _killCommand, - generateCommand.Command, - podCommand.Command, - _containerKubeCommand, + _generateCommand, + _playCommand, _psCommand, - _loadCommand, _loginCommand, _logoutCommand, _logsCommand, @@ -31,7 +30,6 @@ func getMainCommands() []*cobra.Command { _restoreCommand, _rmCommand, _runCommand, - _saveCommand, _searchCommand, _signCommand, _startCommand, @@ -40,7 +38,6 @@ func getMainCommands() []*cobra.Command { _topCommand, _umountCommand, _unpauseCommand, - volumeCommand.Command, _waitCommand, } @@ -54,7 +51,6 @@ func getMainCommands() []*cobra.Command { func getImageSubCommands() []*cobra.Command { return []*cobra.Command{ _loadCommand, - _saveCommand, _signCommand, } } @@ -96,19 +92,8 @@ func getContainerSubCommands() []*cobra.Command { // Commands that the local client implements func getPodSubCommands() []*cobra.Command { return []*cobra.Command{ - _podCreateCommand, - _podExistsCommand, - _podInspectCommand, - _podKillCommand, - _podPauseCommand, - _podPsCommand, - _podRestartCommand, - _podRmCommand, - _podStartCommand, _podStatsCommand, - _podStopCommand, _podTopCommand, - _podUnpauseCommand, } } @@ -137,5 +122,6 @@ func getTrustSubCommands() []*cobra.Command { func getSystemSubCommands() []*cobra.Command { return []*cobra.Command{ _pruneSystemCommand, + _renumberCommand, } } diff --git a/cmd/podman/commands_remoteclient.go b/cmd/podman/commands_remoteclient.go index ba0a4d47e..081043b25 100644 --- a/cmd/podman/commands_remoteclient.go +++ b/cmd/podman/commands_remoteclient.go @@ -6,6 +6,8 @@ import ( "github.com/spf13/cobra" ) +const remoteclient = true + // commands that only the remoteclient implements func getMainCommands() []*cobra.Command { return []*cobra.Command{} diff --git a/cmd/podman/common.go b/cmd/podman/common.go index fed07de7c..e297f3921 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "github.com/spf13/cobra" "os" "strings" @@ -36,16 +37,24 @@ func shortID(id string) string { } // checkAllAndLatest checks that --all and --latest are used correctly -func checkAllAndLatest(c *cliconfig.PodmanCommand) error { - argLen := len(c.InputArgs) - if (c.Bool("all") || c.Bool("latest")) && argLen > 0 { - return errors.Errorf("no arguments are needed with --all or --latest") +func checkAllAndLatest(c *cobra.Command, args []string, ignoreArgLen bool) error { + argLen := len(args) + if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil { + return errors.New("unable to lookup values for 'latest' or 'all'") } - if c.Bool("all") && c.Bool("latest") { + all, _ := c.Flags().GetBool("all") + latest, _ := c.Flags().GetBool("latest") + if all && latest { return errors.Errorf("--all and --latest cannot be used together") } - if argLen < 1 && !c.Bool("all") && !c.Bool("latest") { - return errors.Errorf("you must provide at least one pod name or id") + if ignoreArgLen { + return nil + } + if (all || latest) && argLen > 0 { + return errors.Errorf("no arguments are needed with --all or --latest") + } + if argLen < 1 && !all && !latest { + return errors.Errorf("you must provide at least one name or id") } return nil } 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/cp.go b/cmd/podman/cp.go index 89114fda1..d9f230b67 100644 --- a/cmd/podman/cp.go +++ b/cmd/podman/cp.go @@ -1,8 +1,10 @@ package main import ( + "io/ioutil" "os" "path/filepath" + "strconv" "strings" "github.com/containers/buildah/util" @@ -10,6 +12,7 @@ import ( "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/chrootuser" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/storage" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chrootarchive" @@ -48,6 +51,9 @@ func cpCmd(c *cliconfig.CpValues) error { if len(args) != 2 { return errors.Errorf("you must provide a source path and a destination path") } + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) if err != nil { @@ -76,6 +82,34 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin ctr = destCtr } + if os.Geteuid() != 0 { + s, err := ctr.State() + if err != nil { + return err + } + var became bool + var ret int + if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused { + data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile) + if err != nil { + return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile) + } + conmonPid, err := strconv.Atoi(string(data)) + if err != nil { + return errors.Wrapf(err, "cannot parse PID %q", data) + } + became, ret, err = rootless.JoinDirectUserAndMountNS(uint(conmonPid)) + } else { + became, ret, err = rootless.BecomeRootInUserNS() + } + if err != nil { + return err + } + if became { + os.Exit(ret) + } + } + mountPoint, err := ctr.Mount() if err != nil { return err diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 216f171a8..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") { @@ -868,6 +863,12 @@ func joinOrCreateRootlessUserNamespace(createConfig *cc.CreateConfig, runtime *l if err != nil { return false, -1, err } + if pid == 0 { + if createConfig.Pod != "" { + continue + } + return false, -1, errors.Errorf("dependency container %s is not running", ctr.ID()) + } return rootless.JoinNS(uint(pid)) } } 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/exec.go b/cmd/podman/exec.go index 9599be528..7040a7b09 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -48,7 +48,7 @@ func init() { flags.StringVarP(&execCommand.User, "user", "u", "", "Sets the username or UID used and optionally the groupname or GID for the specified command") flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container") - + markFlagHiddenForRemoteClient("latest", flags) } func execCmd(c *cliconfig.ExecValues) error { diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go index 7645bb716..74a4c841b 100644 --- a/cmd/podman/exists.go +++ b/cmd/podman/exists.go @@ -5,10 +5,9 @@ import ( "github.com/spf13/cobra" "os" - "github.com/containers/libpod/cmd/podman/libpodruntime" "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" ) @@ -124,14 +123,14 @@ func podExistsCmd(c *cliconfig.PodExistsValues) error { if len(args) > 1 || len(args) < 1 { return errors.New("you may only check for the existence of one pod at a time") } - 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) if _, err := runtime.LookupPod(args[0]); err != nil { - if errors.Cause(err) == libpod.ErrNoSuchPod { + if errors.Cause(err) == libpod.ErrNoSuchPod || err.Error() == "io.podman.PodNotFound" { os.Exit(1) } return err 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/formats/formats.go b/cmd/podman/formats/formats.go index c454c39bd..37f9b8a20 100644 --- a/cmd/podman/formats/formats.go +++ b/cmd/podman/formats/formats.go @@ -120,11 +120,8 @@ func (t StdoutTemplateArray) Out() error { fmt.Fprintln(w, "") continue } - // Only print new line at the end of the output if stdout is the terminal - if terminal.IsTerminal(int(os.Stdout.Fd())) { - fmt.Fprintln(w, "") - } } + fmt.Fprintln(w, "") return w.Flush() } 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/generate_kube.go b/cmd/podman/generate_kube.go index ddb2daa34..15f374c73 100644 --- a/cmd/podman/generate_kube.go +++ b/cmd/podman/generate_kube.go @@ -25,7 +25,9 @@ var ( containerKubeCommand.GlobalFlags = MainGlobalOpts return generateKubeYAMLCmd(&containerKubeCommand) }, - Example: "CONTAINER|POD-NAME", + Example: `podman generate kube ctrID + podman generate kube podID + podman generate kube --service podID`, } ) 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/image.go b/cmd/podman/image.go index 4f9c7cd6a..14053cb0d 100644 --- a/cmd/podman/image.go +++ b/cmd/podman/image.go @@ -24,10 +24,12 @@ var imageSubCommands = []*cobra.Command{ _imagesCommand, _importCommand, _inspectCommand, + _loadCommand, _pruneImagesCommand, _pullCommand, _pushCommand, _rmiCommand, + _saveCommand, _tagCommand, } 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 b269f6440..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" @@ -96,7 +96,9 @@ var ( imagesCommand.GlobalFlags = MainGlobalOpts return imagesCmd(&imagesCommand) }, - Example: "", + Example: `podman images --format json + podman images --sort repository --format "table {{.ID}} {{.Repository}} {{.Tag}}" + podman images --filter dangling=true`, } ) 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 a1f3ef81f..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" @@ -48,7 +48,7 @@ func init() { flags.StringVarP(&inspectCommand.Format, "format", "f", "", "Change the output format to a Go template") flags.BoolVarP(&inspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of if the type is a container") flags.BoolVarP(&inspectCommand.Size, "size", "s", false, "Display total file size if the type is container") - + markFlagHiddenForRemoteClient("latest", flags) } func inspectCmd(c *cliconfig.InspectValues) error { diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go index 1be4fa959..eb72d53e7 100644 --- a/cmd/podman/kill.go +++ b/cmd/podman/kill.go @@ -28,6 +28,9 @@ var ( killCommand.GlobalFlags = MainGlobalOpts return killCmd(&killCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman kill mywebserver podman kill 860a4b23 podman kill --signal TERM ctrID`, @@ -43,6 +46,7 @@ func init() { flags.StringVarP(&killCommand.Signal, "signal", "s", "KILL", "Signal to send to the container") flags.BoolVarP(&killCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } // killCmd kills one or more containers with a signal @@ -52,10 +56,6 @@ func killCmd(c *cliconfig.KillValues) error { killSignal uint = uint(syscall.SIGTERM) ) - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } - rootless.SetSkipStorageSetup(true) runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) if err != nil { diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index 0b9568b8d..880b281bd 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -8,8 +8,17 @@ import ( "github.com/pkg/errors" ) +// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber +func GetRuntimeRenumber(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { + return getRuntime(c, true) +} + // GetRuntime generates a new libpod runtime configured by command line options func GetRuntime(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { + return getRuntime(c, false) +} + +func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, error) { options := []libpod.RuntimeOption{} storageOpts, volumePath, err := util.GetDefaultStoreOptions() diff --git a/cmd/podman/load.go b/cmd/podman/load.go index 34a51cd0d..272cd78d2 100644 --- a/cmd/podman/load.go +++ b/cmd/podman/load.go @@ -6,12 +6,8 @@ import ( "io/ioutil" "os" - "github.com/containers/image/directory" - dockerarchive "github.com/containers/image/docker/archive" - ociarchive "github.com/containers/image/oci/archive" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" - "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -56,14 +52,16 @@ func loadCmd(c *cliconfig.LoadValues) error { return errors.New("too many arguments. Requires exactly 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) input := c.Input - + if runtime.Remote && len(input) == 0 { + return errors.New("the remote client requires you to load via -i and a tarball") + } if input == "/dev/stdin" { fi, err := os.Stdin.Stat() if err != nil { @@ -96,46 +94,10 @@ func loadCmd(c *cliconfig.LoadValues) error { return err } - var writer io.Writer - if !c.Quiet { - writer = os.Stderr - } - - ctx := getContext() - - var newImages []*image.Image - src, err := dockerarchive.ParseReference(input) // FIXME? We should add dockerarchive.NewReference() - if err == nil { - newImages, err = runtime.ImageRuntime().LoadFromArchiveReference(ctx, src, c.SignaturePolicy, writer) - } + names, err := runtime.LoadImage(getContext(), imageName, c) if err != nil { - // generate full src name with specified image:tag - src, err := ociarchive.NewReference(input, imageName) // imageName may be "" - if err == nil { - newImages, err = runtime.ImageRuntime().LoadFromArchiveReference(ctx, src, c.SignaturePolicy, writer) - } - if err != nil { - src, err := directory.NewReference(input) - if err == nil { - newImages, err = runtime.ImageRuntime().LoadFromArchiveReference(ctx, src, c.SignaturePolicy, writer) - } - if err != nil { - return errors.Wrapf(err, "error pulling %q", input) - } - } + return err } - fmt.Println("Loaded image(s): " + getImageNames(newImages)) + fmt.Println("Loaded image(s): " + names) return nil } - -func getImageNames(images []*image.Image) string { - var names string - for i := range images { - if i == 0 { - names = images[i].InputName - } else { - names += ", " + images[i].InputName - } - } - return names -} diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go index 6962a1f6d..97d835d8f 100644 --- a/cmd/podman/logs.go +++ b/cmd/podman/logs.go @@ -26,7 +26,9 @@ var ( logsCommand.GlobalFlags = MainGlobalOpts return logsCmd(&logsCommand) }, - Example: "CONTAINER", + Example: `podman logs ctrID + podman logs --tail 2 mywebserver + podman logs --follow=true --since 10m ctrID`, } ) @@ -44,6 +46,7 @@ func init() { flags.SetInterspersed(false) + markFlagHiddenForRemoteClient("latest", flags) } func logsCmd(c *cliconfig.LogsValues) error { diff --git a/cmd/podman/main.go b/cmd/podman/main.go index ecb72f58b..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" @@ -45,9 +43,12 @@ var mainCommands = []*cobra.Command{ _infoCommand, _inspectCommand, _killCommand, + _loadCommand, + podCommand.Command, _pullCommand, _pushCommand, _rmiCommand, + _saveCommand, _tagCommand, _versionCommand, imageCommand.Command, @@ -58,6 +59,7 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{ _versionCommand: true, _createCommand: true, _execCommand: true, + _cpCommand: true, _exportCommand: true, //// `info` must be executed in an user namespace. //// If this change, please also update libpod.refreshRootless() @@ -220,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/mount.go b/cmd/podman/mount.go index ce7c22d60..f4a7bd5ea 100644 --- a/cmd/podman/mount.go +++ b/cmd/podman/mount.go @@ -34,6 +34,9 @@ var ( mountCommand.GlobalFlags = MainGlobalOpts return mountCmd(&mountCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, true) + }, } ) @@ -46,6 +49,7 @@ func init() { flags.BoolVarP(&mountCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.BoolVar(&mountCommand.NoTrunc, "notruncate", false, "Do not truncate output") + markFlagHiddenForRemoteClient("latest", flags) } // jsonMountPoint stores info about each container 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 e988875ab..c1350bd4d 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -18,7 +18,23 @@ var podCommand = cliconfig.PodmanCommand{ }, } +//podSubCommands are implemented both in local and remote clients +var podSubCommands = []*cobra.Command{ + _podCreateCommand, + _podExistsCommand, + _podInspectCommand, + _podKillCommand, + _podPauseCommand, + _podPsCommand, + _podRestartCommand, + _podRmCommand, + _podStartCommand, + _podStopCommand, + _podUnpauseCommand, +} + func init() { + podCommand.AddCommand(podSubCommands...) podCommand.AddCommand(getPodSubCommands()...) podCommand.SetUsageTemplate(UsageTemplate()) } diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index 0a0b86aab..f1bbecb84 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -3,12 +3,10 @@ package main import ( "fmt" "os" - "strings" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" - "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -56,16 +54,29 @@ func init() { } func podCreateCmd(c *cliconfig.PodCreateValues) error { - var options []libpod.PodCreateOption - var err error + var ( + err error + podIdFile *os.File + ) - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + if len(c.InputArgs) > 0 { + return errors.New("podman pod create does not accept any arguments") + } + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - var podIdFile *os.File + if len(c.Publish) > 0 { + if !c.Infra { + return errors.Errorf("you must have an infra container to publish port bindings to the host") + } + } + + if !c.Infra && c.Flag("share").Changed && c.Share != "none" && c.Share != "" { + return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container") + } if c.Flag("pod-id-file").Changed && os.Geteuid() == 0 { podIdFile, err = libpod.OpenExclusiveFile(c.PodIDFile) if err != nil && os.IsExist(err) { @@ -78,67 +89,21 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error { defer podIdFile.Sync() } - if len(c.Publish) > 0 { - if !c.Infra { - return errors.Errorf("you must have an infra container to publish port bindings to the host") - } - } - - if !c.Infra && c.Flag("share").Changed && c.Share != "none" && c.Share != "" { - return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container") - } - - if c.Flag("cgroup-parent").Changed { - options = append(options, libpod.WithPodCgroupParent(c.CgroupParent)) - } - labels, err := getAllLabels(c.LabelFile, c.Labels) if err != nil { return errors.Wrapf(err, "unable to process labels") } - if len(labels) != 0 { - options = append(options, libpod.WithPodLabels(labels)) - } - - if c.Flag("name").Changed { - options = append(options, libpod.WithPodName(c.Name)) - } - - if c.Infra { - options = append(options, libpod.WithInfraContainer()) - nsOptions, err := shared.GetNamespaceOptions(strings.Split(c.Share, ",")) - if err != nil { - return err - } - options = append(options, nsOptions...) - } - if len(c.Publish) > 0 { - portBindings, err := shared.CreatePortBindings(c.Publish) - if err != nil { - return err - } - options = append(options, libpod.WithInfraContainerPorts(portBindings)) - - } - // always have containers use pod cgroups - // User Opt out is not yet supported - options = append(options, libpod.WithPodCgroups()) - - ctx := getContext() - pod, err := runtime.NewPod(ctx, options...) + podID, err := runtime.CreatePod(getContext(), c, labels) if err != nil { - return err + return errors.Wrapf(err, "unable to create pod") } - if podIdFile != nil { - _, err = podIdFile.WriteString(pod.ID()) + _, err = podIdFile.WriteString(podID) if err != nil { logrus.Error(err) } } - - fmt.Printf("%s\n", pod.ID()) - + fmt.Printf("%s\n", podID) return nil } diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go index 58b15328e..5a32b5c5d 100644 --- a/cmd/podman/pod_inspect.go +++ b/cmd/podman/pod_inspect.go @@ -5,8 +5,7 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" - "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -33,17 +32,15 @@ func init() { flags := podInspectCommand.Flags() flags.BoolVarP(&podInspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func podInspectCmd(c *cliconfig.PodInspectValues) error { var ( - pod *libpod.Pod + pod *adapter.Pod ) - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } args := c.InputArgs - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go index febc820cd..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" @@ -24,7 +24,12 @@ var ( podKillCommand.GlobalFlags = MainGlobalOpts return podKillCmd(&podKillCommand) }, - Example: "[POD_NAME_OR_ID]", + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, + Example: `podman pod kill podID + podman pod kill --signal TERM mywebserver + podman pod kill --latest`, } ) @@ -35,15 +40,12 @@ func init() { flags.BoolVarP(&podKillCommand.All, "all", "a", false, "Kill all containers in all pods") flags.BoolVarP(&podKillCommand.Latest, "latest", "l", false, "Act on the latest pod podman is aware of") flags.StringVarP(&podKillCommand.Signal, "signal", "s", "KILL", "Signal to send to the containers in the pod") + markFlagHiddenForRemoteClient("latest", flags) } // podKillCmd kills one or more pods with a signal func podKillCmd(c *cliconfig.PodKillValues) error { - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } @@ -61,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_pause.go b/cmd/podman/pod_pause.go index 2059727ae..284740d22 100644 --- a/cmd/podman/pod_pause.go +++ b/cmd/podman/pod_pause.go @@ -3,7 +3,7 @@ package main 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" @@ -21,7 +21,12 @@ var ( podPauseCommand.GlobalFlags = MainGlobalOpts return podPauseCmd(&podPauseCommand) }, - Example: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]", + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, + Example: `podman pod pause podID1 podID2 + podman pod pause --latest + podman pod pause --all`, } ) @@ -31,44 +36,37 @@ func init() { flags := podPauseCommand.Flags() flags.BoolVarP(&podPauseCommand.All, "all", "a", false, "Pause all running pods") flags.BoolVarP(&podPauseCommand.Latest, "latest", "l", false, "Act on the latest pod podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func podPauseCmd(c *cliconfig.PodPauseValues) error { - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + var lastError error + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod 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) + pauseIDs, conErrors, pauseErrors := runtime.PausePods(c) - for _, pod := range pods { - ctr_errs, err := pod.Pause() - if ctr_errs != nil { - for ctr, err := range ctr_errs { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to pause container %q on pod %q", ctr, pod.ID()) - } - continue - } - if err != nil { + for _, p := range pauseIDs { + fmt.Println(p) + } + if conErrors != nil && len(conErrors) > 0 { + for ctr, err := range conErrors { if lastError != nil { logrus.Errorf("%q", lastError) } - lastError = errors.Wrapf(err, "unable to pause pod %q", pod.ID()) - continue + lastError = errors.Wrapf(err, "unable to pause container %s", ctr) } - fmt.Println(pod.ID()) } - + if len(pauseErrors) > 0 { + lastError = pauseErrors[len(pauseErrors)-1] + // Remove the last error from the error slice + pauseErrors = pauseErrors[:len(pauseErrors)-1] + } + for _, err := range pauseErrors { + logrus.Errorf("%q", err) + } return lastError } diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go index 49af91a1e..70e077651 100644 --- a/cmd/podman/pod_ps.go +++ b/cmd/podman/pod_ps.go @@ -10,9 +10,9 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" - "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/util" "github.com/docker/go-units" "github.com/pkg/errors" @@ -29,6 +29,8 @@ const ( NUM_CTR_INFO = 10 ) +type PodFilter func(*adapter.Pod) bool + var ( bc_opts shared.PsOptions ) @@ -144,7 +146,7 @@ func init() { flags.BoolVar(&podPsCommand.NoTrunc, "no-trunc", false, "Do not truncate pod and container IDs") flags.BoolVarP(&podPsCommand.Quiet, "quiet", "q", false, "Print the numeric IDs of the pods only") flags.StringVar(&podPsCommand.Sort, "sort", "created", "Sort output by created, id, name, or number") - + markFlagHiddenForRemoteClient("latest", flags) } func podPsCmd(c *cliconfig.PodPsValues) error { @@ -152,7 +154,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { return errors.Wrapf(err, "error with flags passed") } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } @@ -173,7 +175,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { opts.Format = genPodPsFormat(c) - var filterFuncs []libpod.PodFilter + var filterFuncs []PodFilter if c.Filter != "" { filters := strings.Split(c.Filter, ",") for _, f := range filters { @@ -181,7 +183,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { if len(filterSplit) < 2 { return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) } - generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1], runtime) + generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1]) if err != nil { return errors.Wrapf(err, "invalid filter") } @@ -189,7 +191,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { } } - var pods []*libpod.Pod + var pods []*adapter.Pod if c.Latest { pod, err := runtime.GetLatestPod() if err != nil { @@ -203,7 +205,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { } } - podsFiltered := make([]*libpod.Pod, 0, len(pods)) + podsFiltered := make([]*adapter.Pod, 0, len(pods)) for _, pod := range pods { include := true for _, filter := range filterFuncs { @@ -215,7 +217,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { } } - return generatePodPsOutput(podsFiltered, opts, runtime) + return generatePodPsOutput(podsFiltered, opts) } // podPsCheckFlagsPassed checks if mutually exclusive flags are passed together @@ -234,10 +236,10 @@ func podPsCheckFlagsPassed(c *cliconfig.PodPsValues) error { return nil } -func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(pod *libpod.Pod) bool, error) { +func generatePodFilterFuncs(filter, filterValue string) (func(pod *adapter.Pod) bool, error) { switch filter { case "ctr-ids": - return func(p *libpod.Pod) bool { + return func(p *adapter.Pod) bool { ctrIds, err := p.AllContainersByID() if err != nil { return false @@ -245,7 +247,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) return util.StringInSlice(filterValue, ctrIds) }, nil case "ctr-names": - return func(p *libpod.Pod) bool { + return func(p *adapter.Pod) bool { ctrs, err := p.AllContainers() if err != nil { return false @@ -258,7 +260,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) return false }, nil case "ctr-number": - return func(p *libpod.Pod) bool { + return func(p *adapter.Pod) bool { ctrIds, err := p.AllContainersByID() if err != nil { return false @@ -274,7 +276,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) if !util.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) { return nil, errors.Errorf("%s is not a valid status", filterValue) } - return func(p *libpod.Pod) bool { + return func(p *adapter.Pod) bool { ctr_statuses, err := p.Status() if err != nil { return false @@ -291,19 +293,19 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) return false }, nil case "id": - return func(p *libpod.Pod) bool { + return func(p *adapter.Pod) bool { return strings.Contains(p.ID(), filterValue) }, nil case "name": - return func(p *libpod.Pod) bool { + return func(p *adapter.Pod) bool { return strings.Contains(p.Name(), filterValue) }, nil case "status": if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) { return nil, errors.Errorf("%s is not a valid pod status", filterValue) } - return func(p *libpod.Pod) bool { - status, err := shared.GetPodStatus(p) + return func(p *adapter.Pod) bool { + status, err := p.GetPodStatus() if err != nil { return false } @@ -448,7 +450,7 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP return psOutput, nil } -func getNamespaces(pod *libpod.Pod) []string { +func getNamespaces(pod *adapter.Pod) []string { var shared []string if pod.SharesPID() { shared = append(shared, "pid") @@ -475,7 +477,7 @@ func getNamespaces(pod *libpod.Pod) []string { } // getAndSortPodJSONOutput returns the container info in its raw, sorted form -func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) ([]podPsJSONParams, error) { +func getAndSortPodJSONParams(pods []*adapter.Pod, opts podPsOptions) ([]podPsJSONParams, error) { var ( psOutput []podPsJSONParams ) @@ -487,7 +489,7 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib return nil, err } ctrNum := len(ctrs) - status, err := shared.GetPodStatus(pod) + status, err := pod.GetPodStatus() if err != nil { return nil, err } @@ -497,7 +499,7 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib return nil, err } for _, ctr := range ctrs { - batchInfo, err := shared.BatchContainerOp(ctr, bc_opts) + batchInfo, err := adapter.BatchContainerOp(ctr, bc_opts) if err != nil { return nil, err } @@ -539,11 +541,11 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib return sortPodPsOutput(opts.Sort, psOutput) } -func generatePodPsOutput(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) error { +func generatePodPsOutput(pods []*adapter.Pod, opts podPsOptions) error { if len(pods) == 0 && opts.Format != formats.JSONString { return nil } - psOutput, err := getAndSortPodJSONParams(pods, opts, runtime) + psOutput, err := getAndSortPodJSONParams(pods, opts) if err != nil { return err } diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go index f75d84956..741fce588 100644 --- a/cmd/podman/pod_restart.go +++ b/cmd/podman/pod_restart.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" @@ -22,7 +22,12 @@ var ( podRestartCommand.GlobalFlags = MainGlobalOpts return podRestartCmd(&podRestartCommand) }, - Example: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]", + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, + Example: `podman pod restart podID1 podID2 + podman pod restart --latest + podman pod restart --all`, } ) @@ -33,44 +38,37 @@ func init() { flags.BoolVarP(&podRestartCommand.All, "all", "a", false, "Restart all running pods") flags.BoolVarP(&podRestartCommand.Latest, "latest", "l", false, "Restart the latest pod podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func podRestartCmd(c *cliconfig.PodRestartValues) error { - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + var lastError error + 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) + restartIDs, conErrors, restartErrors := runtime.RestartPods(getContext(), c) - ctx := getContext() - for _, pod := range pods { - ctr_errs, err := pod.Restart(ctx) - if ctr_errs != nil { - for ctr, err := range ctr_errs { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to restart container %q on pod %q", ctr, pod.ID()) - } - continue - } - if err != nil { + for _, p := range restartIDs { + fmt.Println(p) + } + if conErrors != nil && len(conErrors) > 0 { + for ctr, err := range conErrors { if lastError != nil { logrus.Errorf("%q", lastError) } - lastError = errors.Wrapf(err, "unable to restart pod %q", pod.ID()) - continue + lastError = errors.Wrapf(err, "unable to pause container %s", ctr) } - fmt.Println(pod.ID()) + } + if len(restartErrors) > 0 { + lastError = restartErrors[len(restartErrors)-1] + // Remove the last error from the error slice + restartErrors = restartErrors[:len(restartErrors)-1] + } + for _, err := range restartErrors { + logrus.Errorf("%q", err) } return lastError } diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go index 54cee2a50..ba16d03c7 100644 --- a/cmd/podman/pod_rm.go +++ b/cmd/podman/pod_rm.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" @@ -26,6 +26,9 @@ If --force is specified, all containers will be stopped, then removed. podRmCommand.GlobalFlags = MainGlobalOpts return podRmCmd(&podRmCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman pod rm mywebserverpod podman pod rm -f 860a4b23 podman pod rm -f -a`, @@ -39,39 +42,30 @@ func init() { flags.BoolVarP(&podRmCommand.All, "all", "a", false, "Remove all running pods") flags.BoolVarP(&podRmCommand.Force, "force", "f", false, "Force removal of a running pod by first stopping all containers, then removing all containers in the pod. The default is false") flags.BoolVarP(&podRmCommand.Latest, "latest", "l", false, "Remove the latest pod podman is aware of") - + markFlagHiddenForRemoteClient("latest", flags) } -// saveCmd saves the image to either docker-archive or oci +// podRmCmd deletes pods func podRmCmd(c *cliconfig.PodRmValues) error { - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - 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) + podRmIds, podRmErrors := runtime.RemovePods(getContext(), c) + for _, p := range podRmIds { + fmt.Println(p) + } + if len(podRmErrors) == 0 { + return nil + } + // Grab the last error + lastError := podRmErrors[len(podRmErrors)-1] + // Remove the last error from the error slice + podRmErrors = podRmErrors[:len(podRmErrors)-1] - ctx := getContext() - force := c.Force - - // 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) - - for _, pod := range pods { - err = runtime.RemovePod(ctx, pod, force, force) - if err != nil { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "failed to delete pod %v", pod.ID()) - } else { - fmt.Println(pod.ID()) - } + for _, err := range podRmErrors { + logrus.Errorf("%q", err) } return lastError } diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go index d093c51cf..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" @@ -26,6 +26,9 @@ var ( podStartCommand.GlobalFlags = MainGlobalOpts return podStartCmd(&podStartCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman pod start podID podman pod start --latest podman pod start --all`, @@ -38,45 +41,30 @@ func init() { flags := podStartCommand.Flags() flags.BoolVarP(&podStartCommand.All, "all", "a", false, "Start all pods") flags.BoolVarP(&podStartCommand.Latest, "latest", "l", false, "Start the latest pod podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func podStartCmd(c *cliconfig.PodStartValues) error { - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - 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_stats.go b/cmd/podman/pod_stats.go index b1779532f..907d6a547 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -47,6 +47,7 @@ func init() { flags.BoolVarP(&podStatsCommand.Latest, "latest", "l", false, "Provide stats on the latest pod podman is aware of") flags.BoolVar(&podStatsCommand.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false") flags.BoolVar(&podStatsCommand.NoReset, "no-reset", false, "Disable resetting the screen between intervals") + markFlagHiddenForRemoteClient("latest", flags) } func podStatsCmd(c *cliconfig.PodStatsValues) error { diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go index a9237347e..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" @@ -27,6 +27,9 @@ var ( podStopCommand.GlobalFlags = MainGlobalOpts return podStopCmd(&podStopCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman pod stop mywebserverpod podman pod stop --latest podman pod stop --timeout 0 490eb 3557fb`, @@ -40,50 +43,30 @@ func init() { flags.BoolVarP(&podStopCommand.All, "all", "a", false, "Stop all running pods") flags.BoolVarP(&podStopCommand.Latest, "latest", "l", false, "Stop the latest pod podman is aware of") flags.UintVarP(&podStopCommand.Timeout, "timeout", "t", 0, "Seconds to wait for pod stop before killing the container") + markFlagHiddenForRemoteClient("latest", flags) } func podStopCmd(c *cliconfig.PodStopValues) error { - timeout := -1 - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - 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) + } + if len(podStopErrors) == 0 { + return nil } - 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()) + // 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/pod_unpause.go b/cmd/podman/pod_unpause.go index a917919c3..16481d0e2 100644 --- a/cmd/podman/pod_unpause.go +++ b/cmd/podman/pod_unpause.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" @@ -22,7 +22,12 @@ var ( podUnpauseCommand.GlobalFlags = MainGlobalOpts return podUnpauseCmd(&podUnpauseCommand) }, - Example: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]", + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, + Example: `podman pod unpause podID1 podID2 + podman pod unpause --all + podman pod unpause --latest`, } ) @@ -32,44 +37,37 @@ func init() { flags := podUnpauseCommand.Flags() flags.BoolVarP(&podUnpauseCommand.All, "all", "a", false, "Unpause all running pods") flags.BoolVarP(&podUnpauseCommand.Latest, "latest", "l", false, "Unpause the latest pod podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func podUnpauseCmd(c *cliconfig.PodUnpauseValues) error { - if err := checkMutuallyExclusiveFlags(&c.PodmanCommand); err != nil { - return err - } - - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + var lastError error + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod 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) + unpauseIDs, conErrors, unpauseErrors := runtime.UnpausePods(c) - for _, pod := range pods { - ctr_errs, err := pod.Unpause() - if ctr_errs != nil { - for ctr, err := range ctr_errs { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "unable to unpause container %q on pod %q", ctr, pod.ID()) - } - continue - } - if err != nil { + for _, p := range unpauseIDs { + fmt.Println(p) + } + if conErrors != nil && len(conErrors) > 0 { + for ctr, err := range conErrors { if lastError != nil { logrus.Errorf("%q", lastError) } - lastError = errors.Wrapf(err, "unable to unpause pod %q", pod.ID()) - continue + lastError = errors.Wrapf(err, "unable to unpause container %s", ctr) } - fmt.Println(pod.ID()) } - + if len(unpauseErrors) > 0 { + lastError = unpauseErrors[len(unpauseErrors)-1] + // Remove the last error from the error slice + unpauseErrors = unpauseErrors[:len(unpauseErrors)-1] + } + for _, err := range unpauseErrors { + logrus.Errorf("%q", err) + } return lastError } diff --git a/cmd/podman/port.go b/cmd/podman/port.go index be84da065..bcf372a51 100644 --- a/cmd/podman/port.go +++ b/cmd/podman/port.go @@ -28,7 +28,12 @@ var ( portCommand.GlobalFlags = MainGlobalOpts return portCmd(&portCommand) }, - Example: "CONTAINER-NAME [mapping]", + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, true) + }, + Example: `podman port --all + podman port ctrID 80/tcp + podman port --latest 80`, } ) @@ -40,6 +45,7 @@ func init() { flags.BoolVarP(&portCommand.All, "all", "a", false, "Display port information for all containers") flags.BoolVarP(&portCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func portCmd(c *cliconfig.PortValues) error { diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index d7f0d9da0..9c165b836 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -191,6 +191,7 @@ func init() { flags.StringVar(&psCommand.Sort, "sort", "created", "Sort output by command, created, id, image, names, runningfor, size, or status") flags.BoolVar(&psCommand.Sync, "sync", false, "Sync container state with OCI runtime") + markFlagHiddenForRemoteClient("latest", flags) } func psCmd(c *cliconfig.PsValues) error { diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 0065e975a..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" @@ -74,19 +74,16 @@ func pullCmd(c *cliconfig.PullValues) error { args := c.InputArgs if len(args) == 0 { - logrus.Errorf("an image name must be specified") - return nil + return errors.Errorf("an image name must be specified") } if len(args) > 1 { - logrus.Errorf("too many arguments. Requires exactly 1") - return nil + return errors.Errorf("too many arguments. Requires exactly 1") } arr := strings.SplitN(args[0], ":", 2) if len(arr) == 2 { if c.Bool("all-tags") { - logrus.Errorf("tag can't be used with --all-tags") - return nil + return errors.Errorf("tag can't be used with --all-tags") } } ctx := getContext() 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/restart.go b/cmd/podman/restart.go index 97b689c02..58fb38874 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -26,6 +26,9 @@ var ( restartCommand.GlobalFlags = MainGlobalOpts return restartCmd(&restartCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman restart ctrID podman restart --latest podman restart ctrID1 ctrID2`, @@ -42,6 +45,7 @@ func init() { flags.UintVarP(&restartCommand.Timeout, "timeout", "t", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") flags.UintVar(&restartCommand.Timeout, "time", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") + markFlagHiddenForRemoteClient("latest", flags) } func restartCmd(c *cliconfig.RestartValues) error { diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index 2911bbdd6..5f6e7b892 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -29,6 +29,9 @@ var ( restoreCommand.GlobalFlags = MainGlobalOpts return restoreCmd(&restoreCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman container restore ctrID podman container restore --latest podman container restore --all`, @@ -45,6 +48,7 @@ func init() { // TODO: add ContainerStateCheckpointed flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections") + markFlagHiddenForRemoteClient("latest", flags) } func restoreCmd(c *cliconfig.RestoreValues) error { @@ -63,10 +67,6 @@ func restoreCmd(c *cliconfig.RestoreValues) error { TCPEstablished: c.TcpEstablished, } - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } - containers, lastError := getAllOrLatestContainers(&c.PodmanCommand, runtime, libpod.ContainerStateExited, "checkpointed") for _, ctr := range containers { diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index 2e5fe1dc0..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" @@ -28,6 +29,9 @@ Running containers will not be removed without the -f option. rmCommand.GlobalFlags = MainGlobalOpts return rmCmd(&rmCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman rm imageID podman rm mywebserver myflaskserver 860a4b23 podman rm --force --all`, @@ -42,6 +46,7 @@ func init() { flags.BoolVarP(&rmCommand.Force, "force", "f", false, "Force removal of a running container. The default is false") flags.BoolVarP(&rmCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.BoolVarP(&rmCommand.Volumes, "volumes", "v", false, "Remove the volumes associated with the container") + markFlagHiddenForRemoteClient("latest", flags) } // saveCmd saves the image to either docker-archive or oci @@ -57,19 +62,21 @@ func rmCmd(c *cliconfig.RmValues) error { } defer runtime.Shutdown(false) - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } - + 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/runlabel.go b/cmd/podman/runlabel.go index 54f210e62..d466651f3 100644 --- a/cmd/podman/runlabel.go +++ b/cmd/podman/runlabel.go @@ -13,7 +13,6 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/utils" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -87,8 +86,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error { args := c.InputArgs if len(args) < 2 { - logrus.Errorf("the runlabel command requires at least 2 arguments: LABEL IMAGE") - return nil + return errors.Errorf("the runlabel command requires at least 2 arguments: LABEL IMAGE") } if c.Display && c.Quiet { return errors.Errorf("the display and quiet flags cannot be used together.") diff --git a/cmd/podman/save.go b/cmd/podman/save.go index ff4a22453..161540deb 100644 --- a/cmd/podman/save.go +++ b/cmd/podman/save.go @@ -1,21 +1,12 @@ package main import ( - "fmt" - "io" "os" "strings" - "github.com/containers/image/directory" - dockerarchive "github.com/containers/image/docker/archive" - "github.com/containers/image/docker/reference" - "github.com/containers/image/manifest" - ociarchive "github.com/containers/image/oci/archive" - "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" - libpodImage "github.com/containers/libpod/libpod/image" - imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -23,9 +14,13 @@ import ( const ( ociManifestDir = "oci-dir" + ociArchive = "oci-archive" v2s2ManifestDir = "docker-dir" + v2s2Archive = "docker-archive" ) +var validFormats = []string{ociManifestDir, ociArchive, v2s2ManifestDir, v2s2Archive} + var ( saveCommand cliconfig.SaveValues saveDescription = ` @@ -41,6 +36,16 @@ var ( saveCommand.GlobalFlags = MainGlobalOpts return saveCmd(&saveCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + format, err := cmd.Flags().GetString("format") + if err != nil { + return err + } + if !util.StringInSlice(format, validFormats) { + return errors.Errorf("format value must be one of %s", strings.Join(validFormats, " ")) + } + return nil + }, Example: `podman save --quiet -o myimage.tar imageID podman save --format docker-dir -o ubuntu-dir ubuntu podman save > alpine-all.tar alpine:latest`, @@ -52,7 +57,7 @@ func init() { saveCommand.SetUsageTemplate(UsageTemplate()) flags := saveCommand.Flags() flags.BoolVar(&saveCommand.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)") - flags.StringVar(&saveCommand.Format, "format", "", "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-dir (directory with v2s2 manifest type)") + flags.StringVar(&saveCommand.Format, "format", v2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)") flags.StringVarP(&saveCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT") flags.BoolVarP(&saveCommand.Quiet, "quiet", "q", false, "Suppress the output") } @@ -64,7 +69,7 @@ func saveCmd(c *cliconfig.SaveValues) error { return errors.Errorf("need at least 1 argument") } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } @@ -74,11 +79,6 @@ func saveCmd(c *cliconfig.SaveValues) error { return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'") } - var writer io.Writer - if !c.Quiet { - writer = os.Stderr - } - output := c.Output if output == "/dev/stdout" { fi := os.Stdout @@ -89,87 +89,5 @@ func saveCmd(c *cliconfig.SaveValues) error { if err := validateFileName(output); err != nil { return err } - - source := args[0] - newImage, err := runtime.ImageRuntime().NewFromLocal(source) - if err != nil { - return err - } - - var destRef types.ImageReference - var manifestType string - switch c.Format { - case "oci-archive": - destImageName := imageNameForSaveDestination(newImage, source) - destRef, err = ociarchive.NewReference(output, destImageName) // destImageName may be "" - if err != nil { - return errors.Wrapf(err, "error getting OCI archive ImageReference for (%q, %q)", output, destImageName) - } - case "oci-dir": - destRef, err = directory.NewReference(output) - if err != nil { - return errors.Wrapf(err, "error getting directory ImageReference for %q", output) - } - manifestType = imgspecv1.MediaTypeImageManifest - case "docker-dir": - destRef, err = directory.NewReference(output) - if err != nil { - return errors.Wrapf(err, "error getting directory ImageReference for %q", output) - } - manifestType = manifest.DockerV2Schema2MediaType - case "docker-archive", "": - dst := output - destImageName := imageNameForSaveDestination(newImage, source) - if destImageName != "" { - dst = fmt.Sprintf("%s:%s", dst, destImageName) - } - destRef, err = dockerarchive.ParseReference(dst) // FIXME? Add dockerarchive.NewReference - if err != nil { - return errors.Wrapf(err, "error getting Docker archive ImageReference for %q", dst) - } - default: - return errors.Errorf("unknown format option %q", c.String("format")) - } - - // supports saving multiple tags to the same tar archive - var additionaltags []reference.NamedTagged - if len(args) > 1 { - additionaltags, err = libpodImage.GetAdditionalTags(args[1:]) - if err != nil { - return err - } - } - if err := newImage.PushImageToReference(getContext(), destRef, manifestType, "", "", writer, c.Bool("compress"), libpodImage.SigningOptions{}, &libpodImage.DockerRegistryOptions{}, additionaltags); err != nil { - if err2 := os.Remove(output); err2 != nil { - logrus.Errorf("error deleting %q: %v", output, err) - } - return errors.Wrapf(err, "unable to save %q", args) - } - - return nil -} - -// imageNameForSaveDestination returns a Docker-like reference appropriate for saving img, -// which the user referred to as imgUserInput; or an empty string, if there is no appropriate -// reference. -func imageNameForSaveDestination(img *libpodImage.Image, imgUserInput string) string { - if strings.Contains(img.ID(), imgUserInput) { - return "" - } - - prepend := "" - localRegistryPrefix := fmt.Sprintf("%s/", libpodImage.DefaultLocalRegistry) - if !strings.HasPrefix(imgUserInput, localRegistryPrefix) { - // we need to check if localhost was added to the image name in NewFromLocal - for _, name := range img.Names() { - // If the user is saving an image in the localhost registry, getLocalImage need - // a name that matches the format localhost/<tag1>:<tag2> or localhost/<tag>:latest to correctly - // set up the manifest and save. - if strings.HasPrefix(name, localRegistryPrefix) && (strings.HasSuffix(name, imgUserInput) || strings.HasSuffix(name, fmt.Sprintf("%s:latest", imgUserInput))) { - prepend = localRegistryPrefix - break - } - } - } - return fmt.Sprintf("%s%s", prepend, imgUserInput) + return runtime.SaveImage(getContext(), c) } diff --git a/cmd/podman/search.go b/cmd/podman/search.go index c8b64039a..f63131c84 100644 --- a/cmd/podman/search.go +++ b/cmd/podman/search.go @@ -1,19 +1,13 @@ package main import ( - "context" - "reflect" - "strconv" "strings" - "github.com/containers/image/docker" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" - "github.com/containers/libpod/libpod/common" - sysreg "github.com/containers/libpod/pkg/registries" + "github.com/containers/libpod/libpod/image" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -54,30 +48,6 @@ func init() { flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") } -type searchParams struct { - Index string - Name string - Description string - Stars int - Official string - Automated string -} - -type searchOpts struct { - filter []string - limit int - noTrunc bool - format string - authfile string - insecureSkipTLSVerify types.OptionalBool -} - -type searchFilterParams struct { - stars int - isAutomated *bool - isOfficial *bool -} - func searchCmd(c *cliconfig.SearchValues) error { args := c.InputArgs if len(args) > 1 { @@ -88,37 +58,29 @@ func searchCmd(c *cliconfig.SearchValues) error { } term := args[0] - // Check if search term has a registry in it - registry, err := sysreg.GetRegistry(term) + filter, err := image.ParseSearchFilter(c.Filter) if err != nil { - return errors.Wrapf(err, "error getting registry from %q", term) - } - if registry != "" { - term = term[len(registry)+1:] + return err } - format := genSearchFormat(c.Format) - opts := searchOpts{ - format: format, - noTrunc: c.NoTrunc, - limit: c.Limit, - filter: c.Filter, - authfile: getAuthFile(c.Authfile), + searchOptions := image.SearchOptions{ + NoTrunc: c.NoTrunc, + Limit: c.Limit, + Filter: *filter, + Authfile: getAuthFile(c.Authfile), } if c.Flag("tls-verify").Changed { - opts.insecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) - } - registries, err := getRegistries(registry) - if err != nil { - return err + searchOptions.InsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) } - filter, err := parseSearchFilter(&opts) + results, err := image.SearchImages(term, searchOptions) if err != nil { return err } - - return generateSearchOutput(term, registries, opts, *filter) + format := genSearchFormat(c.Format) + out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: results[0].HeaderMap()} + formats.Writer(out).Out() + return nil } func genSearchFormat(format string) string { @@ -130,175 +92,9 @@ func genSearchFormat(format string) string { return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t" } -func searchToGeneric(params []searchParams) (genericParams []interface{}) { +func searchToGeneric(params []image.SearchResult) (genericParams []interface{}) { for _, v := range params { genericParams = append(genericParams, interface{}(v)) } return genericParams } - -func (s *searchParams) headerMap() map[string]string { - v := reflect.Indirect(reflect.ValueOf(s)) - values := make(map[string]string, v.NumField()) - - for i := 0; i < v.NumField(); i++ { - key := v.Type().Field(i).Name - value := key - values[key] = strings.ToUpper(splitCamelCase(value)) - } - return values -} - -// getRegistries returns the list of registries to search, depending on an optional registry specification -func getRegistries(registry string) ([]string, error) { - var registries []string - if registry != "" { - registries = append(registries, registry) - } else { - var err error - registries, err = sysreg.GetRegistries() - if err != nil { - return nil, errors.Wrapf(err, "error getting registries to search") - } - } - return registries, nil -} - -func getSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) ([]searchParams, error) { - // Max number of queries by default is 25 - limit := maxQueries - if opts.limit != 0 { - limit = opts.limit - } - - sc := common.GetSystemContext("", opts.authfile, false) - sc.DockerInsecureSkipTLSVerify = opts.insecureSkipTLSVerify - sc.SystemRegistriesConfPath = sysreg.SystemRegistriesConfPath() // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place. - var paramsArr []searchParams - for _, reg := range registries { - results, err := docker.SearchRegistry(context.TODO(), sc, reg, term, limit) - if err != nil { - logrus.Errorf("error searching registry %q: %v", reg, err) - continue - } - index := reg - arr := strings.Split(reg, ".") - if len(arr) > 2 { - index = strings.Join(arr[len(arr)-2:], ".") - } - - // limit is the number of results to output - // if the total number of results is less than the limit, output all - // if the limit has been set by the user, output those number of queries - limit := maxQueries - if len(results) < limit { - limit = len(results) - } - if opts.limit != 0 && opts.limit < len(results) { - limit = opts.limit - } - - for i := 0; i < limit; i++ { - if len(opts.filter) > 0 { - // Check whether query matches filters - if !(matchesAutomatedFilter(filter, results[i]) && matchesOfficialFilter(filter, results[i]) && matchesStarFilter(filter, results[i])) { - continue - } - } - official := "" - if results[i].IsOfficial { - official = "[OK]" - } - automated := "" - if results[i].IsAutomated { - automated = "[OK]" - } - description := strings.Replace(results[i].Description, "\n", " ", -1) - if len(description) > 44 && !opts.noTrunc { - description = description[:descriptionTruncLength] + "..." - } - name := reg + "/" + results[i].Name - if index == "docker.io" && !strings.Contains(results[i].Name, "/") { - name = index + "/library/" + results[i].Name - } - params := searchParams{ - Index: index, - Name: name, - Description: description, - Official: official, - Automated: automated, - Stars: results[i].StarCount, - } - paramsArr = append(paramsArr, params) - } - } - return paramsArr, nil -} - -func generateSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) error { - searchOutput, err := getSearchOutput(term, registries, opts, filter) - if err != nil { - return err - } - if len(searchOutput) == 0 { - return nil - } - out := formats.StdoutTemplateArray{Output: searchToGeneric(searchOutput), Template: opts.format, Fields: searchOutput[0].headerMap()} - return formats.Writer(out).Out() -} - -func parseSearchFilter(opts *searchOpts) (*searchFilterParams, error) { - filterParams := &searchFilterParams{} - ptrTrue := true - ptrFalse := false - for _, filter := range opts.filter { - arr := strings.Split(filter, "=") - switch arr[0] { - case "stars": - if len(arr) < 2 { - return nil, errors.Errorf("invalid `stars` filter %q, should be stars=<value>", filter) - } - stars, err := strconv.Atoi(arr[1]) - if err != nil { - return nil, errors.Wrapf(err, "incorrect value type for stars filter") - } - filterParams.stars = stars - break - case "is-automated": - if len(arr) == 2 && arr[1] == "false" { - filterParams.isAutomated = &ptrFalse - } else { - filterParams.isAutomated = &ptrTrue - } - break - case "is-official": - if len(arr) == 2 && arr[1] == "false" { - filterParams.isOfficial = &ptrFalse - } else { - filterParams.isOfficial = &ptrTrue - } - break - default: - return nil, errors.Errorf("invalid filter type %q", filter) - } - } - return filterParams, nil -} - -func matchesStarFilter(filter searchFilterParams, result docker.SearchResult) bool { - return result.StarCount >= filter.stars -} - -func matchesAutomatedFilter(filter searchFilterParams, result docker.SearchResult) bool { - if filter.isAutomated != nil { - return result.IsAutomated == *filter.isAutomated - } - return true -} - -func matchesOfficialFilter(filter searchFilterParams, result docker.SearchResult) bool { - if filter.isOfficial != nil { - return result.IsOfficial == *filter.isOfficial - } - return true -} diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go index 30dd14845..5f65c40ac 100644 --- a/cmd/podman/shared/pod.go +++ b/cmd/podman/shared/pod.go @@ -26,6 +26,10 @@ func GetPodStatus(pod *libpod.Pod) (string, error) { if err != nil { return errored, err } + return CreatePodStatusResults(ctrStatuses) +} + +func CreatePodStatusResults(ctrStatuses map[string]libpod.ContainerStatus) (string, error) { ctrNum := len(ctrStatuses) if ctrNum == 0 { return created, nil diff --git a/cmd/podman/start.go b/cmd/podman/start.go index db8abae83..c645a35c4 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -44,6 +44,7 @@ func init() { flags.BoolVarP(&startCommand.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached") flags.BoolVarP(&startCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.BoolVar(&startCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true if attaching, false otherwise)") + markFlagHiddenForRemoteClient("latest", flags) } func startCmd(c *cliconfig.StartValues) error { diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index 642e54f49..2bbcd0a17 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -41,6 +41,9 @@ var ( statsCommand.GlobalFlags = MainGlobalOpts return statsCmd(&statsCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman stats --all --no-stream podman stats ctrID podman stats --no-stream --format "table {{.ID}} {{.Name}} {{.MemUsage}}" ctrID`, @@ -56,6 +59,7 @@ func init() { flags.BoolVarP(&statsCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.BoolVar(&statsCommand.NoReset, "no-reset", false, "Disable resetting the screen between intervals") flags.BoolVar(&statsCommand.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false") + markFlagHiddenForRemoteClient("latest", flags) } func statsCmd(c *cliconfig.StatsValues) error { diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index 94fdf321e..67c15b2a8 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -32,6 +32,9 @@ var ( stopCommand.GlobalFlags = MainGlobalOpts return stopCmd(&stopCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, false) + }, Example: `podman stop ctrID podman stop --latest podman stop --timeout 2 mywebserver 6e534f14da9d`, @@ -46,6 +49,7 @@ func init() { flags.BoolVarP(&stopCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.UintVar(&stopCommand.Timeout, "time", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") flags.UintVarP(&stopCommand.Timeout, "timeout", "t", libpod.CtrRemoveTimeout, "Seconds to wait for stop before killing the container") + markFlagHiddenForRemoteClient("latest", flags) } func stopCmd(c *cliconfig.StopValues) error { @@ -54,10 +58,6 @@ func stopCmd(c *cliconfig.StopValues) error { defer span.Finish() } - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } - rootless.SetSkipStorageSetup(true) runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) if err != nil { 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/system_renumber.go b/cmd/podman/system_renumber.go new file mode 100644 index 000000000..c8ce628b1 --- /dev/null +++ b/cmd/podman/system_renumber.go @@ -0,0 +1,49 @@ +package main + +import ( + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + renumberCommand cliconfig.SystemRenumberValues + renumberDescription = ` + podman system renumber + + Migrate lock numbers to handle a change in maximum number of locks. + Mandatory after the number of locks in libpod.conf is changed. +` + + _renumberCommand = &cobra.Command{ + Use: "renumber", + Short: "Migrate lock numbers", + Long: renumberDescription, + RunE: func(cmd *cobra.Command, args []string) error { + renumberCommand.InputArgs = args + renumberCommand.GlobalFlags = MainGlobalOpts + return renumberCmd(&renumberCommand) + }, + } +) + +func init() { + renumberCommand.Command = _renumberCommand + renumberCommand.SetUsageTemplate(UsageTemplate()) +} + +func renumberCmd(c *cliconfig.SystemRenumberValues) error { + // We need to pass one extra option to NewRuntime. + // This will inform the OCI runtime to start a renumber. + // That's controlled by the last argument to GetRuntime. + r, err := libpodruntime.GetRuntimeRenumber(&c.PodmanCommand) + if err != nil { + return errors.Wrapf(err, "error renumbering locks") + } + if err := r.Shutdown(false); err != nil { + return err + } + + return nil +} 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/top.go b/cmd/podman/top.go index d85e1be53..36d6bb6b4 100644 --- a/cmd/podman/top.go +++ b/cmd/podman/top.go @@ -55,6 +55,7 @@ func init() { flags.BoolVar(&topCommand.ListDescriptors, "list-descriptors", false, "") flags.MarkHidden("list-descriptors") flags.BoolVarP(&topCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func topCmd(c *cliconfig.TopValues) error { diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go index afa0e86db..6d9009388 100644 --- a/cmd/podman/umount.go +++ b/cmd/podman/umount.go @@ -31,6 +31,9 @@ An unmount can be forced with the --force flag. umountCommand.GlobalFlags = MainGlobalOpts return umountCmd(&umountCommand) }, + Args: func(cmd *cobra.Command, args []string) error { + return checkAllAndLatest(cmd, args, true) + }, Example: `podman umount ctrID podman umount ctrID1 ctrID2 ctrID3 podman umount --all`, @@ -44,6 +47,7 @@ func init() { flags.BoolVarP(&umountCommand.All, "all", "a", false, "Umount all of the currently mounted containers") flags.BoolVarP(&umountCommand.Force, "force", "f", false, "Force the complete umount all of the currently mounted containers") flags.BoolVarP(&umountCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func umountCmd(c *cliconfig.UmountValues) error { @@ -55,9 +59,6 @@ func umountCmd(c *cliconfig.UmountValues) error { force := c.Force umountAll := c.All - if err := checkAllAndLatest(&c.PodmanCommand); err != nil { - return err - } containers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all") if err != nil { diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go index c76e7f2a4..4ec0f8a13 100644 --- a/cmd/podman/utils.go +++ b/cmd/podman/utils.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "github.com/spf13/pflag" "os" gosignal "os/signal" @@ -158,13 +159,6 @@ func (f *RawTtyFormatter) Format(entry *logrus.Entry) ([]byte, error) { return bytes, err } -func checkMutuallyExclusiveFlags(c *cliconfig.PodmanCommand) error { - if err := checkAllAndLatest(c); err != nil { - return err - } - return nil -} - // For pod commands that have a latest and all flag, getPodsFromContext gets // pods the user specifies. If there's an error before getting pods, the pods slice // will be empty and error will be not nil. If an error occured after, the pod slice @@ -178,7 +172,7 @@ func getPodsFromContext(c *cliconfig.PodmanCommand, r *libpod.Runtime) ([]*libpo var err error if c.Bool("all") { - pods, err = r.Pods() + pods, err = r.GetAllPods() if err != nil { return nil, errors.Wrapf(err, "unable to get running pods") } @@ -251,3 +245,11 @@ func printParallelOutput(m map[string]error, errCount int) error { } return lastError } + +// markFlagHiddenForRemoteClient makes the flag not appear as part of the CLI +// on the remote-client +func markFlagHiddenForRemoteClient(flagName string, flags *pflag.FlagSet) { + if remoteclient { + flags.MarkHidden(flagName) + } +} diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 90cadf2b4..618af3481 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -26,6 +26,16 @@ type ContainerChanges ( deleted: []string ) +type ImageSaveOptions ( + name: string, + format: string, + output: string, + outputType: string, + moreTags: []string, + quiet: bool, + compress: bool +) + type VolumeCreateOpts ( volumeName: string, driver: string, @@ -72,6 +82,12 @@ type ImageSearchResult ( star_count: int ) +type ImageSearchFilter ( + is_official: ?bool, + is_automated: ?bool, + star_count: int +) + type Container ( id: string, image: string, @@ -681,7 +697,7 @@ method RemoveImage(name: string, force: bool) -> (image: string) # SearchImages searches available registries for images that contain the # contents of "query" in their name. If "limit" is given, limits the amount of # search results per registry. -method SearchImages(query: string, limit: ?int, tlsVerify: ?bool) -> (results: []ImageSearchResult) +method SearchImages(query: string, limit: ?int, tlsVerify: ?bool, filter: ImageSearchFilter) -> (results: []ImageSearchResult) # DeleteUnusedImages deletes any images not associated with a container. The IDs of the deleted images are returned # in a string array. @@ -719,16 +735,10 @@ method ImportImage(source: string, reference: string, message: string, changes: # error will be returned. See also [ImportImage](ImportImage). method ExportImage(name: string, destination: string, compress: bool, tags: []string) -> (image: string) -# PullImage pulls an image from a repository to local storage. After the pull is successful, the ID of the image -# is returned. -# #### Example -# ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.PullImage '{"name": "registry.fedoraproject.org/fedora"}' -# { -# "id": "426866d6fa419873f97e5cbd320eeb22778244c1dfffa01c944db3114f55772e" -# } -# ~~~ -method PullImage(name: string, certDir: string, creds: string, signaturePolicy: string, tlsVerify: ?bool) -> (id: string) +# PullImage pulls an image from a repository to local storage. After a successful pull, the image id and logs +# are returned as a [MoreResponse](#MoreResponse). This connection also will handle a WantsMores request to send +# status as it occurs. +method PullImage(name: string, certDir: string, creds: string, signaturePolicy: string, tlsVerify: ?bool) -> (reply: MoreResponse) # CreatePod creates a new empty pod. It uses a [PodCreate](#PodCreate) type for input. # On success, the ID of the newly created pod will be returned. @@ -1072,6 +1082,10 @@ method ContainerInspectData(name: string) -> (config: string) # development of Podman only and generally should not be used. method ContainerStateData(name: string) -> (config: string) +# PodStateData returns inspectr level information of a given pod in string form. This call is for +# development of Podman only and generally should not be used. +method PodStateData(name: string) -> (config: string) + # Sendfile allows a remote client to send a file to the host method SendFile(type: string, length: int) -> (file_handle: string) @@ -1090,17 +1104,31 @@ method GetVolumes(args: []string, all: bool) -> (volumes: []Volume) # VolumesPrune removes unused volumes on the host method VolumesPrune() -> (prunedNames: []string, prunedErrors: []string) +# ImageSave allows you to save an image from the local image storage to a tarball +method ImageSave(options: ImageSaveOptions) -> (reply: MoreResponse) + +# GetPodsByContext allows you to get a list pod ids depending on all, latest, or a list of +# pod names. The definition of latest pod means the latest by creation date. In a multi- +# user environment, results might differ from what you expect. +method GetPodsByContext(all: bool, latest: bool, args: []string) -> (pods: []string) + +# LoadImage allows you to load an image into local storage from a tarball. +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 f301749e9..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" ) @@ -28,7 +28,9 @@ not being used by any containers. To remove the volumes anyways, use the volumeRmCommand.GlobalFlags = MainGlobalOpts return volumeRmCmd(&volumeRmCommand) }, - Example: "[VOLUME-NAME ...]", + Example: `podman volume rm myvol1 myvol2 + podman volume rm --all + podman volume rm --force myvol`, } ) diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go index 616c8feb5..9df7cdbae 100644 --- a/cmd/podman/wait.go +++ b/cmd/podman/wait.go @@ -28,7 +28,9 @@ var ( waitCommand.GlobalFlags = MainGlobalOpts return waitCmd(&waitCommand) }, - Example: "CONTAINER-NAME [CONTAINER-NAME ...]", + Example: `podman wait --latest + podman wait --interval 5000 ctrID + podman wait ctrID1 ctrID2`, } ) @@ -38,6 +40,7 @@ func init() { flags := waitCommand.Flags() flags.UintVarP(&waitCommand.Interval, "interval", "i", 250, "Milliseconds to wait before polling for completion") flags.BoolVarP(&waitCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + markFlagHiddenForRemoteClient("latest", flags) } func waitCmd(c *cliconfig.WaitValues) error { |