diff options
Diffstat (limited to 'cmd')
56 files changed, 521 insertions, 332 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index dc0563a94..bcfee6891 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -21,7 +21,7 @@ var ( }, cli.BoolTFlag{ Name: "sig-proxy", - Usage: "proxy received signals to the process (default true)", + Usage: "Proxy received signals to the process (default true)", }, LatestFlag, } diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 02a125aab..0cd1bfbe3 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -25,7 +25,7 @@ var ( }, cli.BoolTFlag{ Name: "layers", - Usage: "cache intermediate layers during build. Use BUILDAH_LAYERS environment variable to override. ", + Usage: "Cache intermediate layers during build. Use BUILDAH_LAYERS environment variable to override. ", }, } buildDescription = "Builds an OCI or Docker image using instructions from one\n" + diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go index 824c97662..5c3363147 100644 --- a/cmd/podman/checkpoint.go +++ b/cmd/podman/checkpoint.go @@ -21,19 +21,19 @@ var ( checkpointFlags = []cli.Flag{ cli.BoolFlag{ Name: "keep, k", - Usage: "keep all temporary checkpoint files", + Usage: "Keep all temporary checkpoint files", }, cli.BoolFlag{ Name: "leave-running, R", - Usage: "leave the container running after writing checkpoint to disk", + Usage: "Leave the container running after writing checkpoint to disk", }, cli.BoolFlag{ Name: "tcp-established", - Usage: "checkpoint a container with established TCP connections", + Usage: "Checkpoint a container with established TCP connections", }, cli.BoolFlag{ Name: "all, a", - Usage: "checkpoint all running containers", + Usage: "Checkpoint all running containers", }, LatestFlag, } diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index 718717009..57126da4a 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -12,8 +12,6 @@ func getAppCommands() []cli.Command { createCommand, diffCommand, execCommand, - exportCommand, - importCommand, killCommand, kubeCommand, loadCommand, @@ -55,6 +53,10 @@ func getImageSubCommands() []cli.Command { } } +func getSystemSubCommands() []cli.Command { + return []cli.Command{infoCommand} +} + func getContainerSubCommands() []cli.Command { return []cli.Command{ attachCommand, @@ -93,58 +95,58 @@ func getMainAppFlags() []cli.Flag { return []cli.Flag{ cli.StringFlag{ Name: "cgroup-manager", - Usage: "cgroup manager to use (cgroupfs or systemd, default systemd)", + Usage: "Cgroup manager to use (cgroupfs or systemd, default systemd)", }, cli.StringFlag{ Name: "cni-config-dir", - Usage: "path of the configuration directory for CNI networks", + Usage: "Path of the configuration directory for CNI networks", }, cli.StringFlag{ Name: "conmon", - Usage: "path of the conmon binary", + Usage: "Path of the conmon binary", }, cli.StringFlag{ Name: "default-mounts-file", - Usage: "path to default mounts file", + Usage: "Path to default mounts file", Hidden: true, }, cli.StringSliceFlag{ Name: "hooks-dir", - Usage: "set the OCI hooks directory path (may be set multiple times)", + Usage: "Set the OCI hooks directory path (may be set multiple times)", }, cli.IntFlag{ Name: "max-workers", - Usage: "the maximum number of workers for parallel operations", + Usage: "The maximum number of workers for parallel operations", Hidden: true, }, cli.StringFlag{ Name: "namespace", - Usage: "set the libpod namespace, used to create separate views of the containers and pods on the system", + Usage: "Set the libpod namespace, used to create separate views of the containers and pods on the system", Value: "", }, cli.StringFlag{ Name: "root", - Usage: "path to the root directory in which data, including images, is stored", + Usage: "Path to the root directory in which data, including images, is stored", }, cli.StringFlag{ Name: "runroot", - Usage: "path to the 'run directory' where all state information is stored", + Usage: "Path to the 'run directory' where all state information is stored", }, cli.StringFlag{ Name: "runtime", - Usage: "path to the OCI-compatible binary used to run containers, default is /usr/bin/runc", + Usage: "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc", }, cli.StringFlag{ Name: "storage-driver, s", - Usage: "select which storage driver is used to manage storage of images and containers (default is overlay)", + Usage: "Select which storage driver is used to manage storage of images and containers (default is overlay)", }, cli.StringSliceFlag{ Name: "storage-opt", - Usage: "used to pass an option to the storage driver", + Usage: "Used to pass an option to the storage driver", }, cli.BoolFlag{ Name: "syslog", - Usage: "output logging information to syslog as well as the console", + Usage: "Output logging information to syslog as well as the console", }, } } diff --git a/cmd/podman/commands_remoteclient.go b/cmd/podman/commands_remoteclient.go index 6701e14a1..0adbd7b4c 100644 --- a/cmd/podman/commands_remoteclient.go +++ b/cmd/podman/commands_remoteclient.go @@ -16,6 +16,10 @@ func getContainerSubCommands() []cli.Command { return []cli.Command{} } +func getSystemSubCommands() []cli.Command { + return []cli.Command{} +} + func getMainAppFlags() []cli.Flag { return []cli.Flag{} } diff --git a/cmd/podman/common.go b/cmd/podman/common.go index d934c8699..82d60d62e 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -22,11 +22,11 @@ var ( stores = make(map[storage.Store]struct{}) LatestFlag = cli.BoolFlag{ Name: "latest, l", - Usage: "act on the latest container podman is aware of", + Usage: "Act on the latest container podman is aware of", } LatestPodFlag = cli.BoolFlag{ Name: "latest, l", - Usage: "act on the latest pod podman is aware of", + Usage: "Act on the latest pod podman is aware of", } WorkDirFlag = cli.StringFlag{ Name: "workdir, w", @@ -213,7 +213,7 @@ var createFlags = []cli.Flag{ }, cli.StringFlag{ Name: "conmon-pidfile", - Usage: "path to the file that will receive the PID of conmon", + Usage: "Path to the file that will receive the PID of conmon", }, cli.Uint64Flag{ Name: "cpu-period", diff --git a/cmd/podman/container.go b/cmd/podman/container.go index acbcbb644..29300a6a4 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -8,6 +8,7 @@ import ( var ( containerSubCommands = []cli.Command{ + exportCommand, inspectCommand, } containerDescription = "Manage containers" diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go index 92604e82f..09141e9a3 100644 --- a/cmd/podman/containers_prune.go +++ b/cmd/podman/containers_prune.go @@ -1,9 +1,11 @@ package main import ( - "github.com/containers/libpod/cmd/podman/libpodruntime" + "context" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -25,20 +27,11 @@ var ( } ) -func pruneContainersCmd(c *cli.Context) error { - var ( - deleteFuncs []shared.ParallelWorkerInput - ) - - ctx := getContext() - runtime, err := libpodruntime.GetRuntime(c) - if err != nil { - return errors.Wrapf(err, "could not get runtime") - } - defer runtime.Shutdown(false) +func pruneContainers(runtime *adapter.LocalRuntime, ctx context.Context, maxWorkers int, force bool) error { + var deleteFuncs []shared.ParallelWorkerInput filter := func(c *libpod.Container) bool { - state, _ := c.State() + state, err := c.State() if state == libpod.ContainerStateStopped || (state == libpod.ContainerStateExited && err == nil && c.PodID() == "") { return true } @@ -54,7 +47,7 @@ func pruneContainersCmd(c *cli.Context) error { for _, container := range delContainers { con := container f := func() error { - return runtime.RemoveContainer(ctx, con, c.Bool("force")) + return runtime.RemoveContainer(ctx, con, force) } deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{ @@ -62,13 +55,23 @@ func pruneContainersCmd(c *cli.Context) error { ParallelFunc: f, }) } + // Run the parallel funcs + deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) + return printParallelOutput(deleteErrors, errCount) +} + +func pruneContainersCmd(c *cli.Context) error { + runtime, err := adapter.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + maxWorkers := shared.Parallelize("rm") if c.GlobalIsSet("max-workers") { maxWorkers = c.GlobalInt("max-workers") } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - // Run the parallel funcs - deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) - return printParallelOutput(deleteErrors, errCount) + return pruneContainers(runtime, getContext(), maxWorkers, c.Bool("force")) } diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 065d08df4..2d85abd35 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -128,7 +129,12 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container var data *inspect.ImageData = nil if rootfs == "" && !rootless.SkipStorageSetup() { - newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false) + var writer io.Writer + if !c.Bool("quiet") { + writer = os.Stderr + } + + newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil) if err != nil { return nil, nil, err } diff --git a/cmd/podman/docker/types.go b/cmd/podman/docker/types.go index 90349a31c..eda618e40 100644 --- a/cmd/podman/docker/types.go +++ b/cmd/podman/docker/types.go @@ -69,8 +69,9 @@ type HealthConfig struct { Test []string `json:",omitempty"` // Zero means to inherit. Durations are expressed as integer nanoseconds. - Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. - Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + StartPeriod time.Duration `json:",omitempty"` // Time to wait after the container starts before running the first check. // Retries is the number of consecutive failures needed to consider a container as unhealthy. // Zero means inherit. diff --git a/cmd/podman/export.go b/cmd/podman/export.go index c0e63bd2a..eaa4e38a2 100644 --- a/cmd/podman/export.go +++ b/cmd/podman/export.go @@ -1,12 +1,9 @@ package main import ( - "io/ioutil" "os" - "strconv" - "github.com/containers/libpod/cmd/podman/libpodruntime" - "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/adapter" "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -43,7 +40,7 @@ func exportCmd(c *cli.Context) error { rootless.SetSkipStorageSetup(true) } - runtime, err := libpodruntime.GetRuntime(c) + runtime, err := adapter.GetRuntime(c) if err != nil { return errors.Wrapf(err, "could not get runtime") } @@ -58,52 +55,18 @@ func exportCmd(c *cli.Context) error { } output := c.String("output") + if runtime.Remote && (output == "/dev/stdout" || len(output) == 0) { + return errors.New("remote client usage must specify an output file (-o)") + } if output == "/dev/stdout" { file := os.Stdout if logrus.IsTerminal(file) { return errors.Errorf("refusing to export to terminal. Use -o flag or redirect") } } + if err := validateFileName(output); err != nil { return err } - - ctr, err := runtime.LookupContainer(args[0]) - if err != nil { - return errors.Wrapf(err, "error looking up container %q", args[0]) - } - - if os.Geteuid() != 0 { - state, err := ctr.State() - if err != nil { - return errors.Wrapf(err, "cannot read container state %q", ctr.ID()) - } - if state == libpod.ContainerStateRunning || state == 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)) - if err != nil { - return err - } - if became { - os.Exit(ret) - } - } else { - became, ret, err := rootless.BecomeRootInUserNS() - if err != nil { - return err - } - if became { - os.Exit(ret) - } - } - } - - return ctr.Export(output) + return runtime.Export(args[0], c.String("output")) } diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go index 765d0ee70..20a4a61ab 100644 --- a/cmd/podman/generate.go +++ b/cmd/podman/generate.go @@ -9,10 +9,10 @@ var ( containerKubeCommand, } - generateDescription = "generate structured data based for a containers and pods" + generateDescription = "Generate structured data based for a containers and pods" kubeCommand = cli.Command{ Name: "generate", - Usage: "generated structured data", + Usage: "Generate structured data", Description: generateDescription, ArgsUsage: "", Subcommands: generateSubCommands, diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go index f63bd431b..fc667fb5b 100644 --- a/cmd/podman/generate_kube.go +++ b/cmd/podman/generate_kube.go @@ -17,7 +17,7 @@ var ( containerKubeFlags = []cli.Flag{ cli.BoolFlag{ Name: "service, s", - Usage: "generate YAML for kubernetes service object", + Usage: "Generate YAML for kubernetes service object", }, } containerKubeDescription = "Generate Kubernetes Pod YAML" diff --git a/cmd/podman/image.go b/cmd/podman/image.go index a51a90b0e..6b451a1ca 100644 --- a/cmd/podman/image.go +++ b/cmd/podman/image.go @@ -8,6 +8,7 @@ import ( var ( imageSubCommands = []cli.Command{ + importCommand, historyCommand, imageExistsCommand, inspectCommand, diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 031f06618..9fdf0a780 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -90,11 +90,11 @@ var ( }, cli.BoolFlag{ Name: "digests", - Usage: "show digests", + Usage: "Show digests", }, cli.StringSliceFlag{ Name: "filter, f", - Usage: "filter output based on conditions provided (default [])", + Usage: "Filter output based on conditions provided (default [])", }, cli.StringFlag{ Name: "format", @@ -102,20 +102,20 @@ var ( }, cli.BoolFlag{ Name: "noheading, n", - Usage: "do not print column headings", + Usage: "Do not print column headings", }, cli.BoolFlag{ Name: "no-trunc, notruncate", - Usage: "do not truncate output", + Usage: "Do not truncate output", }, cli.BoolFlag{ Name: "quiet, q", - Usage: "display only image IDs", + Usage: "Display only image IDs", }, cli.StringFlag{ Name: "sort", Usage: "Sort by created, id, repository, size, or tag", - Value: "created", + Value: "Created", }, } @@ -133,7 +133,7 @@ var ( lsImagesCommand = cli.Command{ Name: "list", Aliases: []string{"ls"}, - Usage: "list images in local storage", + Usage: "List images in local storage", Description: imagesDescription, Flags: imagesFlags, Action: imagesCmd, @@ -188,13 +188,6 @@ func imagesCmd(c *cli.Context) error { } opts.outputformat = opts.setOutputFormat() - /* - podman does not implement --all for images - - intermediate images are only generated during the build process. they are - children to the image once built. until buildah supports caching builds, - it will not generate these intermediate images. - */ images, err := runtime.GetImages() if err != nil { return errors.Wrapf(err, "unable to get images") diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go index 06879e02d..844984bb9 100644 --- a/cmd/podman/images_prune.go +++ b/cmd/podman/images_prune.go @@ -2,7 +2,8 @@ package main import ( "fmt" - "github.com/containers/libpod/cmd/podman/libpodruntime" + + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/urfave/cli" ) @@ -13,33 +14,36 @@ var ( Removes all unnamed images from local storage ` - + pruneImageFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "Remove all unused images, not just dangling ones", + }, + } pruneImagesCommand = cli.Command{ Name: "prune", Usage: "Remove unused images", Description: pruneImagesDescription, Action: pruneImagesCmd, OnUsageError: usageErrorHandler, + Flags: pruneImageFlags, } ) func pruneImagesCmd(c *cli.Context) error { - runtime, err := libpodruntime.GetRuntime(c) + runtime, err := adapter.GetRuntime(c) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.Shutdown(false) - pruneImages, err := runtime.ImageRuntime().GetPruneImages() - if err != nil { - return err - } - - for _, i := range pruneImages { - if err := i.Remove(true); err != nil { - return errors.Wrapf(err, "failed to remove %s", i.ID()) + // Call prune; if any cids are returned, print them and then + // return err in case an error also came up + pruneCids, err := runtime.PruneImages(c.Bool("all")) + if len(pruneCids) > 0 { + for _, cid := range pruneCids { + fmt.Println(cid) } - fmt.Println(i.ID()) } - return nil + return err } diff --git a/cmd/podman/import.go b/cmd/podman/import.go index 144354fa6..661bd5a65 100644 --- a/cmd/podman/import.go +++ b/cmd/podman/import.go @@ -2,16 +2,8 @@ package main import ( "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "os" - "github.com/containers/libpod/cmd/podman/libpodruntime" - "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/util" - "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/urfave/cli" ) @@ -51,7 +43,7 @@ func importCmd(c *cli.Context) error { return err } - runtime, err := libpodruntime.GetRuntime(c) + runtime, err := adapter.GetRuntime(c) if err != nil { return errors.Wrapf(err, "could not get runtime") } @@ -60,7 +52,6 @@ func importCmd(c *cli.Context) error { var ( source string reference string - writer io.Writer ) args := c.Args() @@ -80,67 +71,13 @@ func importCmd(c *cli.Context) error { return err } - changes := v1.ImageConfig{} - if c.IsSet("change") || c.IsSet("c") { - changes, err = util.GetImageConfig(c.StringSlice("change")) - if err != nil { - return errors.Wrapf(err, "error adding config changes to image %q", source) - } + quiet := c.Bool("quiet") + if runtime.Remote { + quiet = false } - - history := []v1.History{ - {Comment: c.String("message")}, - } - - config := v1.Image{ - Config: changes, - History: history, - } - - writer = nil - if !c.Bool("quiet") { - writer = os.Stderr - } - - // if source is a url, download it and save to a temp file - u, err := url.ParseRequestURI(source) - if err == nil && u.Scheme != "" { - file, err := downloadFromURL(source) - if err != nil { - return err - } - defer os.Remove(file) - source = file - } - - newImage, err := runtime.ImageRuntime().Import(getContext(), source, reference, writer, image.SigningOptions{}, config) + iid, err := runtime.Import(getContext(), source, reference, c.StringSlice("change"), c.String("message"), quiet) if err == nil { - fmt.Println(newImage.ID()) + fmt.Println(iid) } return err } - -// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar" -// and temporarily saves in it /var/tmp/importxyz, which is deleted after the image is imported -func downloadFromURL(source string) (string, error) { - fmt.Printf("Downloading from %q\n", source) - - outFile, err := ioutil.TempFile("/var/tmp", "import") - if err != nil { - return "", errors.Wrap(err, "error creating file") - } - defer outFile.Close() - - response, err := http.Get(source) - if err != nil { - return "", errors.Wrapf(err, "error downloading %q", source) - } - defer response.Body.Close() - - _, err = io.Copy(outFile, response.Body) - if err != nil { - return "", errors.Wrapf(err, "error saving %s to %s", source, outFile.Name()) - } - - return outFile.Name(), nil -} diff --git a/cmd/podman/info.go b/cmd/podman/info.go index 3888829a3..19078cea5 100644 --- a/cmd/podman/info.go +++ b/cmd/podman/info.go @@ -26,10 +26,10 @@ var ( infoFlags = []cli.Flag{ cli.BoolFlag{ Name: "debug, D", - Usage: "display additional debug information", + Usage: "Display additional debug information", }, cli.StringFlag{ - Name: "format", + Name: "format, f", Usage: "Change the output format to JSON or a Go template", }, } diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 3ef740463..1346da9fb 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -32,7 +32,7 @@ var ( Usage: "Change the output format to a Go template", }, cli.BoolFlag{ - Name: "size", + Name: "size, s", Usage: "Display total file size if the type is container", }, LatestFlag, @@ -40,7 +40,7 @@ var ( inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type." inspectCommand = cli.Command{ Name: "inspect", - Usage: "Displays the configuration of a container or image", + Usage: "Display the configuration of a container or image", Description: inspectDescription, Flags: sortFlags(inspectFlags), Action: inspectCmd, diff --git a/cmd/podman/main.go b/cmd/podman/main.go index c10590006..8c08b2bfb 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -88,13 +88,16 @@ func main() { app.Commands = []cli.Command{ containerCommand, + exportCommand, historyCommand, imageCommand, imagesCommand, + importCommand, infoCommand, inspectCommand, pullCommand, rmiCommand, + systemCommand, tagCommand, versionCommand, } @@ -185,21 +188,21 @@ func main() { app.Flags = []cli.Flag{ cli.StringFlag{ Name: "config, c", - Usage: "path of a libpod config file detailing container server configuration options", + Usage: "Path of a libpod config file detailing container server configuration options", Hidden: true, }, cli.StringFlag{ Name: "cpu-profile", - Usage: "path for the cpu profiling results", + Usage: "Path for the cpu profiling results", }, cli.StringFlag{ Name: "log-level", - Usage: "log messages above specified level: debug, info, warn, error (default), fatal or panic", + Usage: "Log messages above specified level: debug, info, warn, error (default), fatal or panic", Value: "error", }, cli.StringFlag{ Name: "tmpdir", - Usage: "path to the tmp directory", + Usage: "Path to the tmp directory", }, } diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go index 86a6b2ad1..f71d47434 100644 --- a/cmd/podman/mount.go +++ b/cmd/podman/mount.go @@ -33,7 +33,7 @@ var ( }, cli.BoolFlag{ Name: "notruncate", - Usage: "do not truncate output", + Usage: "Do not truncate output", }, LatestFlag, } diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go index fcb2f3cb8..2e7182871 100644 --- a/cmd/podman/pause.go +++ b/cmd/podman/pause.go @@ -15,7 +15,7 @@ var ( pauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "pause all running containers", + Usage: "Pause all running containers", }, } pauseDescription = ` @@ -25,7 +25,7 @@ var ( ` pauseCommand = cli.Command{ Name: "pause", - Usage: "Pauses all the processes in one or more containers", + Usage: "Pause all the processes in one or more containers", Description: pauseDescription, Flags: pauseFlags, Action: pauseCmd, diff --git a/cmd/podman/play.go b/cmd/podman/play.go index adbab3480..4e09b2689 100644 --- a/cmd/podman/play.go +++ b/cmd/podman/play.go @@ -12,7 +12,7 @@ var ( playDescription = "Play a pod and its containers from a structured file." playCommand = cli.Command{ Name: "play", - Usage: "play a container or pod", + Usage: "Play a container or pod", Description: playDescription, ArgsUsage: "", Subcommands: playSubCommands, diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index 2ce2e21bb..2d97e0e95 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -32,11 +32,11 @@ var ( }, cli.StringFlag{ Name: "cert-dir", - Usage: "`pathname` of a directory containing TLS certificates and keys", + Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.StringFlag{ Name: "creds", - Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", + Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.BoolFlag{ Name: "quiet, q", @@ -44,11 +44,11 @@ var ( }, cli.StringFlag{ Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", + Usage: "`Pathname` of signature policy file (not usually used)", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } playKubeDescription = "Play a Pod and its containers based on a Kubrernetes YAML" @@ -58,7 +58,7 @@ var ( Description: playKubeDescription, Action: playKubeYAMLCmd, Flags: sortFlags(playKubeFlags), - ArgsUsage: "kubernetes YAML file", + ArgsUsage: "Kubernetes YAML file", UseShortOptionHandling: true, OnUsageError: usageErrorHandler, } @@ -146,7 +146,7 @@ func playKubeYAMLCmd(c *cli.Context) error { } for _, container := range podYAML.Spec.Containers { - newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false) + newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil) if err != nil { return err } diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go index 77178b14d..c7bbf31cd 100644 --- a/cmd/podman/pod_inspect.go +++ b/cmd/podman/pod_inspect.go @@ -14,10 +14,10 @@ var ( podInspectFlags = []cli.Flag{ LatestPodFlag, } - podInspectDescription = "display the configuration for a pod by name or id" + podInspectDescription = "Display the configuration for a pod by name or id" podInspectCommand = cli.Command{ Name: "inspect", - Usage: "displays a pod configuration", + Usage: "Displays a pod configuration", Description: podInspectDescription, Flags: sortFlags(podInspectFlags), Action: podInspectCmd, diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go index e8de0debc..f29a0b8d1 100644 --- a/cmd/podman/pod_pause.go +++ b/cmd/podman/pod_pause.go @@ -13,7 +13,7 @@ var ( podPauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "pause all running pods", + Usage: "Pause all running pods", }, LatestPodFlag, } diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go index e956b2f70..d9800cbf7 100644 --- a/cmd/podman/pod_restart.go +++ b/cmd/podman/pod_restart.go @@ -13,7 +13,7 @@ var ( podRestartFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "restart all pods", + Usage: "Restart all pods", }, LatestPodFlag, } diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go index f0a7926c9..2178340a4 100644 --- a/cmd/podman/pod_start.go +++ b/cmd/podman/pod_start.go @@ -13,7 +13,7 @@ var ( podStartFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "start all running pods", + Usage: "Start all running pods", }, LatestPodFlag, } diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go index 2e29445b4..0f0e215e6 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -19,22 +19,22 @@ var ( podStatsFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "show stats for all pods. Only running pods are shown by default.", + Usage: "Show stats for all pods. Only running pods are shown by default.", }, cli.BoolFlag{ Name: "no-stream", - Usage: "disable streaming stats and only pull the first result, default setting is false", + Usage: "Disable streaming stats and only pull the first result, default setting is false", }, cli.BoolFlag{ Name: "no-reset", - Usage: "disable resetting the screen between intervals", + Usage: "Disable resetting the screen between intervals", }, cli.StringFlag{ Name: "format", - Usage: "pretty-print container statistics to JSON or using a Go template", + Usage: "Pretty-print container statistics to JSON or using a Go template", }, LatestPodFlag, } - podStatsDescription = "display a live stream of resource usage statistics for the containers in or more pods" + podStatsDescription = "Display a live stream of resource usage statistics for the containers in or more pods" podStatsCommand = cli.Command{ Name: "stats", Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for containers in one or more pods", diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go index d49ba8a00..148b4d518 100644 --- a/cmd/podman/pod_stop.go +++ b/cmd/podman/pod_stop.go @@ -12,7 +12,7 @@ var ( podStopFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "stop all running pods", + Usage: "Stop all running pods", }, LatestPodFlag, cli.UintFlag{ diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go index 5256f680c..ed1a00cf8 100644 --- a/cmd/podman/pod_unpause.go +++ b/cmd/podman/pod_unpause.go @@ -13,7 +13,7 @@ var ( podUnpauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "unpause all paused pods", + Usage: "Unpause all paused pods", }, LatestPodFlag, } diff --git a/cmd/podman/port.go b/cmd/podman/port.go index 3355e751b..6875c648a 100644 --- a/cmd/podman/port.go +++ b/cmd/podman/port.go @@ -15,7 +15,7 @@ var ( portFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "display port information for all containers", + Usage: "Display port information for all containers", }, LatestFlag, } diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index 0ad3f4c73..1708c671c 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -606,19 +606,50 @@ func portsToString(ports []ocicni.PortMapping) string { } func printFormat(format string, containers []shared.PsContainerOutput) error { - out := template.New("output") - out, err := out.Parse(format + "\n") + // return immediately if no containers are present + if len(containers) == 0 { + return nil + } + + // Use a tabwriter to align column format + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + + // Make a map of the field names for the headers + headerNames := make(map[string]string) + v := reflect.ValueOf(containers[0]) + t := v.Type() + for i := 0; i < t.NumField(); i++ { + headerNames[t.Field(i).Name] = t.Field(i).Name + } + + // Spit out the header if "table" is present in the format + if strings.HasPrefix(format, "table") { + hformat := strings.Replace(strings.TrimSpace(format[5:]), " ", "\t", -1) + format = hformat + headerTmpl, err := template.New("header").Parse(hformat) + if err != nil { + return err + } + if err := headerTmpl.Execute(w, headerNames); err != nil { + return err + } + fmt.Fprintln(w, "") + } + // Spit out the data rows now + dataTmpl, err := template.New("data").Parse(format) if err != nil { return err } + for _, container := range containers { - if err := out.Execute(os.Stdout, container); err != nil { + if err := dataTmpl.Execute(w, container); err != nil { return err } - + fmt.Fprintln(w, "") } - return nil + // Flush the writer + return w.Flush() } func dumpJSON(containers []shared.PsContainerOutput) error { diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 2a78d0c54..2349265d0 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -41,7 +41,7 @@ var ( }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } @@ -123,7 +123,7 @@ func pullCmd(c *cli.Context) error { imgID = newImage[0].ID() } else { authfile := getAuthFile(c.String("authfile")) - newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true) + newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true, nil) if err != nil { return errors.Wrapf(err, "error pulling image %q", image) } diff --git a/cmd/podman/push.go b/cmd/podman/push.go index 82589f3f1..361a25e35 100644 --- a/cmd/podman/push.go +++ b/cmd/podman/push.go @@ -21,40 +21,40 @@ var ( pushFlags = []cli.Flag{ cli.StringFlag{ Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", + Usage: "`Pathname` of signature policy file (not usually used)", Hidden: true, }, cli.StringFlag{ Name: "creds", - Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", + Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.StringFlag{ Name: "cert-dir", - Usage: "`pathname` of a directory containing TLS certificates and keys", + Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.BoolFlag{ Name: "compress", - Usage: "compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)", + Usage: "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)", }, cli.StringFlag{ Name: "format, f", - Usage: "manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)", + Usage: "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, cli.BoolFlag{ Name: "remove-signatures", - Usage: "discard any pre-existing signatures in the image", + Usage: "Discard any pre-existing signatures in the image", }, cli.StringFlag{ Name: "sign-by", - Usage: "add a signature at the destination using the specified key", + Usage: "Add a signature at the destination using the specified key", }, cli.BoolFlag{ Name: "quiet, q", - Usage: "don't output progress information when pushing images", + Usage: "Don't output progress information when pushing images", }, cli.StringFlag{ Name: "authfile", diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index c6fe1025a..2e52ce5e4 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -17,11 +17,11 @@ var ( restartFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "restart all non-running containers", + Usage: "Restart all non-running containers", }, cli.BoolFlag{ Name: "running", - Usage: "restart only running containers when --all is used", + Usage: "Restart only running containers when --all is used", }, cli.UintFlag{ Name: "timeout, time, t", diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index bc2a71ba0..664475e22 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -21,18 +21,18 @@ var ( restoreFlags = []cli.Flag{ cli.BoolFlag{ Name: "keep, k", - Usage: "keep all temporary checkpoint files", + Usage: "Keep all temporary checkpoint files", }, // restore --all would make more sense if there would be // dedicated state for container which are checkpointed. // TODO: add ContainerStateCheckpointed cli.BoolFlag{ Name: "tcp-established", - Usage: "checkpoint a container with established TCP connections", + Usage: "Checkpoint a container with established TCP connections", }, cli.BoolFlag{ Name: "all, a", - Usage: "restore all checkpointed containers", + Usage: "Restore all checkpointed containers", }, LatestFlag, } diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go index fbf860eb2..39757272e 100644 --- a/cmd/podman/rmi.go +++ b/cmd/podman/rmi.go @@ -15,16 +15,16 @@ var ( rmiFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "remove all images", + Usage: "Remove all images", }, cli.BoolFlag{ Name: "force, f", - Usage: "force removal of the image", + Usage: "Force removal of the image", }, } rmiCommand = cli.Command{ Name: "rmi", - Usage: "Removes one or more images from local storage", + Usage: "Remove one or more images from local storage", Description: rmiDescription, Action: rmiCmd, ArgsUsage: "IMAGE-NAME-OR-ID [...]", @@ -34,7 +34,7 @@ var ( } rmImageCommand = cli.Command{ Name: "rm", - Usage: "removes one or more images from local storage", + Usage: "Removes one or more images from local storage", Description: rmiDescription, Action: rmiCmd, ArgsUsage: "IMAGE-NAME-OR-ID [...]", diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 20cb85347..3ef546940 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -20,7 +20,7 @@ var runDescription = "Runs a command in a new container from the given image" var runFlags []cli.Flag = append(createFlags, cli.BoolTFlag{ Name: "sig-proxy", - Usage: "proxy received signals to the process (default true)", + Usage: "Proxy received signals to the process (default true)", }) var runCommand = cli.Command{ @@ -131,6 +131,7 @@ func runCmd(c *cli.Context) error { ctrExitCode, err := readExitFile(runtime.GetConfig().TmpDir, ctr.ID()) if err != nil { logrus.Errorf("Cannot get exit code: %v", err) + exitCode = 127 } else { exitCode = ctrExitCode } diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go index 48a296260..38905b5ca 100644 --- a/cmd/podman/runlabel.go +++ b/cmd/podman/runlabel.go @@ -24,15 +24,15 @@ var ( }, cli.BoolFlag{ Name: "display", - Usage: "preview the command that the label would run", + Usage: "Preview the command that the label would run", }, cli.StringFlag{ Name: "cert-dir", - Usage: "`pathname` of a directory containing TLS certificates and keys", + Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.StringFlag{ Name: "creds", - Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", + Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.StringFlag{ Name: "name", @@ -59,15 +59,15 @@ var ( }, cli.BoolFlag{ Name: "pull, p", - Usage: "pull the image if it does not exist locally prior to executing the label contents", + Usage: "Pull the image if it does not exist locally prior to executing the label contents", }, cli.StringFlag{ Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", + Usage: "`Pathname` of signature policy file (not usually used)", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } @@ -166,7 +166,7 @@ func runlabelCmd(c *cli.Context) error { return err } if runLabel == "" { - return nil + return errors.Errorf("%s does not have a label of %s", runlabelImage, label) } cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, c.String("name"), opts, extraArgs) diff --git a/cmd/podman/save.go b/cmd/podman/save.go index 139f3918a..325140b76 100644 --- a/cmd/podman/save.go +++ b/cmd/podman/save.go @@ -29,7 +29,7 @@ var ( saveFlags = []cli.Flag{ cli.BoolFlag{ Name: "compress", - Usage: "compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)", + Usage: "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)", }, cli.StringFlag{ Name: "output, o", diff --git a/cmd/podman/search.go b/cmd/podman/search.go index 442ebb57f..81469a0f8 100644 --- a/cmd/podman/search.go +++ b/cmd/podman/search.go @@ -30,23 +30,23 @@ var ( }, cli.StringSliceFlag{ Name: "filter, f", - Usage: "filter output based on conditions provided (default [])", + Usage: "Filter output based on conditions provided (default [])", }, cli.StringFlag{ Name: "format", - Usage: "change the output format to a Go template", + Usage: "Change the output format to a Go template", }, cli.IntFlag{ Name: "limit", - Usage: "limit the number of results", + Usage: "Limit the number of results", }, cli.BoolFlag{ Name: "no-trunc", - Usage: "do not truncate the output", + Usage: "Do not truncate the output", }, cli.BoolTFlag{ Name: "tls-verify", - Usage: "require HTTPS and verify certificates when contacting registries (default: true)", + Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, } searchDescription = ` diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index 9040c4a5c..f84fb8261 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -609,7 +609,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim registryCreds = creds } dockerRegistryOptions.DockerRegistryCreds = registryCreds - newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false) + newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false, &label) } else { newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage) } diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go index 1d9aecdc9..22aa07230 100644 --- a/cmd/podman/sign.go +++ b/cmd/podman/sign.go @@ -104,7 +104,7 @@ func signCmd(c *cli.Context) error { } // create the signstore file - newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false) + newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false, nil) if err != nil { return errors.Wrapf(err, "error pulling image %s", signimage) } diff --git a/cmd/podman/start.go b/cmd/podman/start.go index df34deec2..f6e1d9882 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -29,7 +29,7 @@ var ( }, cli.BoolTFlag{ Name: "sig-proxy", - Usage: "proxy received signals to the process (default true if attaching, false otherwise)", + Usage: "Proxy received signals to the process (default true if attaching, false otherwise)", }, LatestFlag, } diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index f6beac1a8..769354b23 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -31,23 +31,23 @@ var ( statsFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "show all containers. Only running containers are shown by default. The default is false", + Usage: "Show all containers. Only running containers are shown by default. The default is false", }, cli.BoolFlag{ Name: "no-stream", - Usage: "disable streaming stats and only pull the first result, default setting is false", + Usage: "Disable streaming stats and only pull the first result, default setting is false", }, cli.StringFlag{ Name: "format", - Usage: "pretty-print container statistics to JSON or using a Go template", + Usage: "Pretty-print container statistics to JSON or using a Go template", }, cli.BoolFlag{ Name: "no-reset", - Usage: "disable resetting the screen between intervals", + Usage: "Disable resetting the screen between intervals", }, LatestFlag, } - statsDescription = "display a live stream of one or more containers' resource usage statistics" + statsDescription = "Display a live stream of one or more containers' resource usage statistics" statsCommand = cli.Command{ Name: "stats", Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers", diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index ade51705e..204515c70 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -21,7 +21,7 @@ var ( }, cli.BoolFlag{ Name: "all, a", - Usage: "stop all running containers", + Usage: "Stop all running containers", }, LatestFlag, } stopDescription = ` diff --git a/cmd/podman/system.go b/cmd/podman/system.go new file mode 100644 index 000000000..9596252ad --- /dev/null +++ b/cmd/podman/system.go @@ -0,0 +1,29 @@ +package main + +import ( + "sort" + + "github.com/urfave/cli" +) + +var ( + systemSubCommands = []cli.Command{ + pruneSystemCommand, + } + systemDescription = "Manage podman" + systemCommand = cli.Command{ + Name: "system", + Usage: "Manage podman", + Description: systemDescription, + ArgsUsage: "", + Subcommands: getSystemSubCommandsSorted(), + UseShortOptionHandling: true, + OnUsageError: usageErrorHandler, + } +) + +func getSystemSubCommandsSorted() []cli.Command { + systemSubCommands = append(systemSubCommands, getSystemSubCommands()...) + sort.Sort(commandSortedAlpha{systemSubCommands}) + return systemSubCommands +} diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go new file mode 100644 index 000000000..64d291560 --- /dev/null +++ b/cmd/podman/system_prune.go @@ -0,0 +1,107 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/libpod/adapter" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +var ( + pruneSystemDescription = ` + podman system prune + + Remove unused data +` + pruneSystemFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "Remove all unused data", + }, + cli.BoolFlag{ + Name: "force, f", + Usage: "Do not prompt for confirmation", + }, + cli.BoolFlag{ + Name: "volumes", + Usage: "Prune volumes", + }, + } + pruneSystemCommand = cli.Command{ + Name: "prune", + Usage: "Remove unused data", + Description: pruneSystemDescription, + Action: pruneSystemCmd, + OnUsageError: usageErrorHandler, + Flags: pruneSystemFlags, + } +) + +func pruneSystemCmd(c *cli.Context) error { + + // Prompt for confirmation if --force is not set + if !c.Bool("force") { + reader := bufio.NewReader(os.Stdin) + volumeString := "" + if c.Bool("volumes") { + volumeString = ` + - all volumes not used by at least one container` + } + fmt.Printf(` +WARNING! This will remove: + - all stopped containers%s + - all dangling images + - all build cache +Are you sure you want to continue? [y/N] `, volumeString) + ans, err := reader.ReadString('\n') + if err != nil { + return errors.Wrapf(err, "error reading input") + } + if strings.ToLower(ans)[0] != 'y' { + return nil + } + } + + runtime, err := adapter.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + ctx := getContext() + fmt.Println("Deleted Containers") + lasterr := pruneContainers(runtime, ctx, shared.Parallelize("rm"), false) + if c.Bool("volumes") { + fmt.Println("Deleted Volumes") + err := volumePrune(runtime, getContext()) + if err != nil { + if lasterr != nil { + logrus.Errorf("%q", lasterr) + } + lasterr = err + } + } + + // Call prune; if any cids are returned, print them and then + // return err in case an error also came up + pruneCids, err := runtime.PruneImages(c.Bool("all")) + if len(pruneCids) > 0 { + fmt.Println("Deleted Images") + for _, cid := range pruneCids { + fmt.Println(cid) + } + } + if err != nil { + if lasterr != nil { + logrus.Errorf("%q", lasterr) + } + lasterr = err + } + return lasterr +} diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go index 863f36d09..a99be6ba2 100644 --- a/cmd/podman/trust.go +++ b/cmd/podman/trust.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "sort" + "strings" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/formats" @@ -13,6 +14,7 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/trust" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -103,6 +105,7 @@ func showTrustCmd(c *cli.Context) error { var ( policyPath string systemRegistriesDirPath string + outjson interface{} ) if c.IsSet("policypath") { policyPath = c.String("policypath") @@ -127,30 +130,26 @@ func showTrustCmd(c *cli.Context) error { return nil } - var policyContentStruct trust.PolicyContent - if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { - return errors.Errorf("could not read trust policies") - } - policyJSON, showOutputMap, err := trust.GetPolicy(policyContentStruct, systemRegistriesDirPath) + policyContentStruct, err := trust.GetPolicy(policyPath) if err != nil { - return errors.Wrapf(err, "error reading registry config file") + return errors.Wrapf(err, "could not read trust policies") } + if c.Bool("json") { - var outjson interface{} + policyJSON, err := getPolicyJSON(policyContentStruct, systemRegistriesDirPath) + if err != nil { + return errors.Wrapf(err, "could not show trust policies in JSON format") + } outjson = policyJSON out := formats.JSONStruct{Output: outjson} return formats.Writer(out).Out() } - sortedRepos := sortPolicyJSONKey(policyJSON) - var output []interface{} - for _, reponame := range sortedRepos { - showOutput, exists := showOutputMap[reponame] - if exists { - output = append(output, interface{}(showOutput)) - } + showOutputMap, err := getPolicyShowOutput(policyContentStruct, systemRegistriesDirPath) + if err != nil { + return errors.Wrapf(err, "could not show trust policies") } - out := formats.StdoutTemplateArray{Output: output, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"} + out := formats.StdoutTemplateArray{Output: showOutputMap, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"} return formats.Writer(out).Out() } @@ -159,7 +158,11 @@ func setTrustCmd(c *cli.Context) error { if err != nil { return errors.Wrapf(err, "could not create runtime") } - + var ( + policyPath string + policyContentStruct trust.PolicyContent + newReposContent []trust.RepoContent + ) args := c.Args() if len(args) != 1 { return errors.Errorf("default or a registry name must be specified") @@ -182,17 +185,13 @@ func setTrustCmd(c *cli.Context) error { return errors.Errorf("At least one public key must be defined for type 'signedBy'") } - var policyPath string if c.IsSet("policypath") { policyPath = c.String("policypath") } else { policyPath = trust.DefaultPolicyPath(runtime.SystemContext()) } - var policyContentStruct trust.PolicyContent - policyFileExists := false _, err = os.Stat(policyPath) if !os.IsNotExist(err) { - policyFileExists = true policyContent, err := ioutil.ReadFile(policyPath) if err != nil { return errors.Wrapf(err, "unable to read %s", policyPath) @@ -200,11 +199,7 @@ func setTrustCmd(c *cli.Context) error { if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { return errors.Errorf("could not read trust policies") } - if args[0] != "default" && len(policyContentStruct.Default) == 0 { - return errors.Errorf("Default trust policy must be set.") - } } - var newReposContent []trust.RepoContent if len(pubkeysfile) != 0 { for _, filepath := range pubkeysfile { newReposContent = append(newReposContent, trust.RepoContent{Type: trusttype, KeyType: "GPGKeys", KeyPath: filepath}) @@ -215,8 +210,8 @@ func setTrustCmd(c *cli.Context) error { if args[0] == "default" { policyContentStruct.Default = newReposContent } else { - if policyFileExists == false && len(policyContentStruct.Default) == 0 { - return errors.Errorf("Default trust policy must be set to create the policy file.") + if len(policyContentStruct.Default) == 0 { + return errors.Errorf("Default trust policy must be set.") } registryExists := false for transport, transportval := range policyContentStruct.Transports { @@ -248,7 +243,7 @@ func setTrustCmd(c *cli.Context) error { return nil } -func sortPolicyJSONKey(m map[string]map[string]interface{}) []string { +func sortShowOutputMapKey(m map[string]trust.ShowOutput) []string { keys := make([]string, len(m)) i := 0 for k := range m { @@ -269,3 +264,106 @@ func isValidTrustType(t string) bool { func getDefaultPolicyPath() string { return trust.DefaultPolicyPath(&types.SystemContext{}) } + +func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) { + registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath) + if err != nil { + return nil, err + } + + policyJSON := make(map[string]map[string]interface{}) + if len(policyContentStruct.Default) > 0 { + policyJSON["* (default)"] = make(map[string]interface{}) + policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type + } + for transname, transval := range policyContentStruct.Transports { + for repo, repoval := range transval { + policyJSON[repo] = make(map[string]interface{}) + policyJSON[repo]["type"] = repoval[0].Type + policyJSON[repo]["transport"] = transname + keyarr := []string{} + uids := []string{} + for _, repoele := range repoval { + if len(repoele.KeyPath) > 0 { + keyarr = append(keyarr, repoele.KeyPath) + uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...) + } + if len(repoele.KeyData) > 0 { + keyarr = append(keyarr, string(repoele.KeyData)) + uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...) + } + } + policyJSON[repo]["keys"] = keyarr + policyJSON[repo]["sigstore"] = "" + registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs) + if registryNamespace != nil { + policyJSON[repo]["sigstore"] = registryNamespace.SigStore + } + } + } + return policyJSON, nil +} + +var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"} + +func trustTypeDescription(trustType string) string { + trustDescription, exist := typeDescription[trustType] + if !exist { + logrus.Warnf("invalid trust type %s", trustType) + } + return trustDescription +} + +func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]interface{}, error) { + var output []interface{} + + registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath) + if err != nil { + return nil, err + } + + trustShowOutputMap := make(map[string]trust.ShowOutput) + if len(policyContentStruct.Default) > 0 { + defaultPolicyStruct := trust.ShowOutput{ + Repo: "default", + Trusttype: trustTypeDescription(policyContentStruct.Default[0].Type), + } + trustShowOutputMap["* (default)"] = defaultPolicyStruct + } + for _, transval := range policyContentStruct.Transports { + for repo, repoval := range transval { + tempTrustShowOutput := trust.ShowOutput{ + Repo: repo, + Trusttype: repoval[0].Type, + } + keyarr := []string{} + uids := []string{} + for _, repoele := range repoval { + if len(repoele.KeyPath) > 0 { + keyarr = append(keyarr, repoele.KeyPath) + uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...) + } + if len(repoele.KeyData) > 0 { + keyarr = append(keyarr, string(repoele.KeyData)) + uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...) + } + } + tempTrustShowOutput.GPGid = strings.Join(uids, ", ") + + registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs) + if registryNamespace != nil { + tempTrustShowOutput.Sigstore = registryNamespace.SigStore + } + trustShowOutputMap[repo] = tempTrustShowOutput + } + } + + sortedRepos := sortShowOutputMapKey(trustShowOutputMap) + for _, reponame := range sortedRepos { + showOutput, exists := trustShowOutputMap[reponame] + if exists { + output = append(output, interface{}(showOutput)) + } + } + return output, nil +} diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go index 7c9b5897b..ab6925e65 100644 --- a/cmd/podman/umount.go +++ b/cmd/podman/umount.go @@ -15,11 +15,11 @@ var ( umountFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "umount all of the currently mounted containers", + Usage: "Umount all of the currently mounted containers", }, cli.BoolFlag{ Name: "force, f", - Usage: "force the complete umount all of the currently mounted containers", + Usage: "Force the complete umount all of the currently mounted containers", }, LatestFlag, } @@ -34,7 +34,7 @@ An unmount can be forced with the --force flag. umountCommand = cli.Command{ Name: "umount", Aliases: []string{"unmount"}, - Usage: "Unmounts working container's root filesystem", + Usage: "Unmount working container's root filesystem", Description: description, Flags: sortFlags(umountFlags), Action: umountCmd, diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go index d77e056f8..91b5fda33 100644 --- a/cmd/podman/unpause.go +++ b/cmd/podman/unpause.go @@ -15,7 +15,7 @@ var ( unpauseFlags = []cli.Flag{ cli.BoolFlag{ Name: "all, a", - Usage: "unpause all paused containers", + Usage: "Unpause all paused containers", }, } unpauseDescription = ` diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go index a7c195041..38ce77415 100644 --- a/cmd/podman/varlink.go +++ b/cmd/podman/varlink.go @@ -24,7 +24,7 @@ var ( varlinkFlags = []cli.Flag{ cli.IntFlag{ Name: "timeout, t", - Usage: "time until the varlink session expires in milliseconds. Use 0 to disable the timeout.", + Usage: "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout.", Value: 1000, }, } diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 86c3eb7ff..101232b0c 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -688,7 +688,7 @@ method Commit(name: string, image_name: string, changes: []string, author: strin # ImportImage imports an image from a source (like tarball) into local storage. The image can have additional # descriptions added to it using the message and changes options. See also [ExportImage](ExportImage). -method ImportImage(source: string, reference: string, message: string, changes: []string) -> (image: string) +method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string) # ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also # a booleon option to force compression. It also takes in a string array of tags to be able to save multiple @@ -987,17 +987,15 @@ method ContainerRunlabel(runlabel: Runlabel) -> () # of strings # #### Example # ~~~ -# $ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerMounts +# $ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts # { -# "mounts": [ -# "/var/lib/containers/storage/overlay/b215fb622c65ba3b06c6d2341be80b76a9de7ae415ce419e65228873d4f0dcc8/merged", -# "/var/lib/containers/storage/overlay/5eaf806073f79c0ed9a695180ad598e34f963f7407da1d2ccf3560bdab49b26f/merged", -# "/var/lib/containers/storage/overlay/1ecb6b1dbb251737c7a24a31869096839c3719d8b250bf075f75172ddcc701e1/merged", -# "/var/lib/containers/storage/overlay/7137b28a3c422165fe920cba851f2f8da271c6b5908672c451ebda03ad3919e2/merged" -# ] +# "mounts": { +# "04e4c255269ed2545e7f8bd1395a75f7949c50c223415c00c1d54bfa20f3b3d9": "/var/lib/containers/storage/overlay/a078925828f57e20467ca31cfca8a849210d21ec7e5757332b72b6924f441c17/merged", +# "1d58c319f9e881a644a5122ff84419dccf6d138f744469281446ab243ef38924": "/var/lib/containers/storage/overlay/948fcf93f8cb932f0f03fd52e3180a58627d547192ffe3b88e0013b98ddcd0d2/merged" +# } # } # ~~~ -method ListContainerMounts() -> (mounts: []string) +method ListContainerMounts() -> (mounts: [string]string) # MountContainer mounts a container by name or full/partial ID. Upon a successful mount, the destination # mount is returned as a string. @@ -1019,7 +1017,7 @@ method UnmountContainer(name: string, force: bool) -> () # ImagesPrune removes all unused images from the local store. Upon successful pruning, # the IDs of the removed images are returned. -method ImagesPrune() -> (pruned: []string) +method ImagesPrune(all: bool) -> (pruned: []string) # This function is not implemented yet. method ListContainerPorts(name: string) -> (notimplemented: NotImplemented) @@ -1052,6 +1050,9 @@ method ContainerInspectData(name: string) -> (config: string) # development of Podman only and generally should not be used. method ContainerStateData(name: string) -> (config: string) +method SendFile(type: string, length: int) -> (file_handle: string) +method ReceiveFile(path: string, delete: bool) -> (len: int) + # ImageNotFound means the image could not be found by the provided name or ID in local storage. error ImageNotFound (name: string) diff --git a/cmd/podman/version.go b/cmd/podman/version.go index fd7f06b7c..ce773ee2e 100644 --- a/cmd/podman/version.go +++ b/cmd/podman/version.go @@ -57,7 +57,7 @@ var ( } versionFlags = []cli.Flag{ cli.StringFlag{ - Name: "format", + Name: "format, f", Usage: "Change the output format to JSON or a Go template", }, } diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go index 652c50f42..41d95f9c7 100644 --- a/cmd/podman/volume_prune.go +++ b/cmd/podman/volume_prune.go @@ -2,12 +2,13 @@ package main import ( "bufio" + "context" "fmt" "os" "strings" - "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/adapter" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -37,21 +38,40 @@ var volumePruneCommand = cli.Command{ UseShortOptionHandling: true, } -func volumePruneCmd(c *cli.Context) error { +func volumePrune(runtime *adapter.LocalRuntime, ctx context.Context) error { var lastError error + volumes, err := runtime.GetAllVolumes() + if err != nil { + return err + } + + for _, vol := range volumes { + err = runtime.RemoveVolume(ctx, vol, false, true) + if err == nil { + fmt.Println(vol.Name()) + } else if err != libpod.ErrVolumeBeingUsed { + if lastError != nil { + logrus.Errorf("%q", lastError) + } + lastError = errors.Wrapf(err, "failed to remove volume %q", vol.Name()) + } + } + return lastError +} + +func volumePruneCmd(c *cli.Context) error { + if err := validateFlags(c, volumePruneFlags); err != nil { return err } - runtime, err := libpodruntime.GetRuntime(c) + runtime, err := adapter.GetRuntime(c) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - ctx := getContext() - // Prompt for confirmation if --force is not set if !c.Bool("force") { reader := bufio.NewReader(os.Stdin) @@ -66,21 +86,5 @@ func volumePruneCmd(c *cli.Context) error { } } - volumes, err := runtime.GetAllVolumes() - if err != nil { - return err - } - - for _, vol := range volumes { - err = runtime.RemoveVolume(ctx, vol, false, true) - if err == nil { - fmt.Println(vol.Name()) - } else if err != libpod.ErrVolumeBeingUsed { - if lastError != nil { - logrus.Errorf("%q", lastError) - } - lastError = errors.Wrapf(err, "failed to remove volume %q", vol.Name()) - } - } - return lastError + return volumePrune(runtime, getContext()) } |