diff options
59 files changed, 286 insertions, 112 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index 8b0fd7ffd..ecba91a90 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -34,8 +34,6 @@ func init() { 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") - - rootCmd.AddCommand(attachCommand.Command) } func attachCmd(c *cliconfig.AttachValues) error { diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 20f621e84..cebca18f1 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -58,8 +58,6 @@ func init() { flags.AddFlagSet(&budFlags) flags.AddFlagSet(&fromAndBugFlags) - - rootCmd.AddCommand(buildCommand.Command) } func getDockerfiles(files []string) []string { diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index e1eba1f31..fd438e2fc 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -6,24 +6,66 @@ import ( "github.com/spf13/cobra" ) +// Commands that the local client implements +func getMainCommands() []*cobra.Command { + rootCommands := []*cobra.Command{ + _attachCommand, + _buildCommand, + _commitCommand, + _createCommand, + _diffCommand, + _execCommand, + _killCommand, + generateCommand.Command, + podCommand.Command, + _containerKubeCommand, + _psCommand, + _loadCommand, + _loginCommand, + _logoutCommand, + _logsCommand, + _mountCommand, + _pauseCommand, + _portCommand, + _pushCommand, + _refreshCommand, + _restartCommand, + _restoreCommand, + _rmCommand, + _runCommmand, + _saveCommand, + _searchCommand, + _signCommand, + _startCommand, + _statsCommand, + _stopCommand, + _topCommand, + _umountCommand, + _unpauseCommand, + _varlinkCommand, + volumeCommand.Command, + _waitCommand, + } + return rootCommands +} + +// Commands that the local client implements func getImageSubCommands() []*cobra.Command { return []*cobra.Command{ _buildCommand, - _importCommand, _loadCommand, - _pullCommand, - _rmiCommand, + _pushCommand, _saveCommand, _signCommand, } } +// Commands that the local client implements func getContainerSubCommands() []*cobra.Command { return []*cobra.Command{ _attachCommand, _checkpointCommand, _cleanupCommand, - _containerExistsCommand, _commitCommand, _createCommand, _diffCommand, @@ -52,6 +94,7 @@ func getContainerSubCommands() []*cobra.Command { } } +// Commands that the local client implements func getPodSubCommands() []*cobra.Command { return []*cobra.Command{ _podCreateCommand, @@ -70,6 +113,7 @@ func getPodSubCommands() []*cobra.Command { } } +// Commands that the local client implements func getVolumeSubCommands() []*cobra.Command { return []*cobra.Command{ _volumeCreateCommand, @@ -80,18 +124,21 @@ func getVolumeSubCommands() []*cobra.Command { } } +// Commands that the local client implements func getGenerateSubCommands() []*cobra.Command { return []*cobra.Command{ _containerKubeCommand, } } +// Commands that the local client implements func getPlaySubCommands() []*cobra.Command { return []*cobra.Command{ _playKubeCommand, } } +// Commands that the local client implements func getTrustSubCommands() []*cobra.Command { return []*cobra.Command{ _setTrustCommand, @@ -99,9 +146,9 @@ func getTrustSubCommands() []*cobra.Command { } } +// Commands that the local client implements func getSystemSubCommands() []*cobra.Command { return []*cobra.Command{ - _infoCommand, _pruneSystemCommand, } } diff --git a/cmd/podman/commands_remoteclient.go b/cmd/podman/commands_remoteclient.go index 993137fde..e1f68405e 100644 --- a/cmd/podman/commands_remoteclient.go +++ b/cmd/podman/commands_remoteclient.go @@ -6,45 +6,54 @@ import ( "github.com/spf13/cobra" ) -//import "github.com/urfave/cli" -// +// commands that only the remoteclient implements +func getMainCommands() []*cobra.Command { + return []*cobra.Command{} +} + +// commands that only the remoteclient implements func getAppCommands() []*cobra.Command { return []*cobra.Command{} } +// commands that only the remoteclient implements func getImageSubCommands() []*cobra.Command { return []*cobra.Command{} } +// commands that only the remoteclient implements func getContainerSubCommands() []*cobra.Command { return []*cobra.Command{} } +// commands that only the remoteclient implements func getPodSubCommands() []*cobra.Command { return []*cobra.Command{} } +// commands that only the remoteclient implements func getVolumeSubCommands() []*cobra.Command { return []*cobra.Command{ _volumeCreateCommand, } } +// commands that only the remoteclient implements func getGenerateSubCommands() []*cobra.Command { return []*cobra.Command{} } +// commands that only the remoteclient implements func getPlaySubCommands() []*cobra.Command { return []*cobra.Command{} } +// commands that only the remoteclient implements func getTrustSubCommands() []*cobra.Command { return []*cobra.Command{} } -//func getMainAppFlags() []cli.Flag { -// return []cli.Flag{} -//} +// commands that only the remoteclient implements func getSystemSubCommands() []*cobra.Command { return []*cobra.Command{} } diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go index 6fd6b9761..e77903c36 100644 --- a/cmd/podman/commit.go +++ b/cmd/podman/commit.go @@ -47,7 +47,6 @@ func init() { flags.BoolVarP(&commitCommand.Pause, "pause", "p", false, "Pause container during commit") flags.BoolVarP(&commitCommand.Quiet, "quiet", "q", false, "Suppress output") - rootCmd.AddCommand(commitCommand.Command) } func commitCmd(c *cliconfig.CommitValues) error { diff --git a/cmd/podman/container.go b/cmd/podman/container.go index 969cb2dc8..6d9231482 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -15,7 +15,13 @@ var containerCommand = cliconfig.PodmanCommand{ }, } +// Commands that are universally implemented. +var containerCommands = []*cobra.Command{ + _containerExistsCommand, +} + func init() { + containerCommand.AddCommand(containerCommands...) containerCommand.AddCommand(getContainerSubCommands()...) rootCmd.AddCommand(containerCommand.Command) } diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 2f8742052..7aa371147 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -65,7 +65,6 @@ func init() { flags := createCommand.Flags() flags.SetInterspersed(true) - rootCmd.AddCommand(createCommand.Command) } func createCmd(c *cliconfig.CreateValues) error { diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go index 04a659ab6..1bcedbd1e 100644 --- a/cmd/podman/diff.go +++ b/cmd/podman/diff.go @@ -59,9 +59,8 @@ func init() { flags.MarkHidden("archive") - rootCmd.AddCommand(diffCommand.Command) - } + func formatJSON(output []diffOutputParams) (diffJSONOutput, error) { jsonStruct := diffJSONOutput{} for _, output := range output { diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index b4f66bc03..fa6e4af03 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -46,7 +46,6 @@ func init() { flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container") - rootCmd.AddCommand(execCommand.Command) } func execCmd(c *cliconfig.ExecValues) error { diff --git a/cmd/podman/export.go b/cmd/podman/export.go index bd9e38b0c..18fcc679c 100644 --- a/cmd/podman/export.go +++ b/cmd/podman/export.go @@ -33,7 +33,6 @@ func init() { exportCommand.Command = _exportCommand flags := exportCommand.Flags() flags.StringVarP(&exportCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT") - rootCmd.AddCommand(exportCommand.Command) } // exportCmd saves a container to a tarball on disk diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go index a5e15fdd6..d258c5194 100644 --- a/cmd/podman/generate.go +++ b/cmd/podman/generate.go @@ -17,5 +17,4 @@ var generateCommand = cliconfig.PodmanCommand{ func init() { generateCommand.AddCommand(getGenerateSubCommands()...) - rootCmd.AddCommand(generateCommand.Command) } diff --git a/cmd/podman/history.go b/cmd/podman/history.go index 97e501947..953c94b69 100644 --- a/cmd/podman/history.go +++ b/cmd/podman/history.go @@ -60,9 +60,8 @@ func init() { flags.BoolVar(&historyCommand.NoTrunc, "no-trunc", false, "Do not truncate the output") flags.BoolVarP(&historyCommand.Quiet, "quiet", "q", false, "Display the numeric IDs only") - rootCmd.AddCommand(historyCommand.Command) - } + func historyCmd(c *cliconfig.HistoryValues) error { runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { diff --git a/cmd/podman/image.go b/cmd/podman/image.go index ac7ff4944..e93c63267 100644 --- a/cmd/podman/image.go +++ b/cmd/podman/image.go @@ -20,10 +20,11 @@ var ( var imageSubCommands = []*cobra.Command{ _historyCommand, _imageExistsCommand, - _inspectCommand, _imagesCommand, + _importCommand, + _inspectCommand, _pruneImagesCommand, - _pushCommand, + _pullCommand, _rmiCommand, _tagCommand, } @@ -31,5 +32,4 @@ var imageSubCommands = []*cobra.Command{ func init() { imageCommand.AddCommand(imageSubCommands...) imageCommand.AddCommand(getImageSubCommands()...) - rootCmd.AddCommand(imageCommand.Command) } diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 6f5a3e9f1..329b8e8d9 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -114,8 +114,6 @@ func init() { flags.BoolVarP(&imagesCommand.Quiet, "quiet", "q", false, "Display only image IDs") flags.StringVar(&imagesCommand.Sort, "sort", "created", "Sort by created, id, repository, size, or tag") - rootCmd.AddCommand(imagesCommand.Command) - } func imagesCmd(c *cliconfig.ImagesValues) error { diff --git a/cmd/podman/import.go b/cmd/podman/import.go index 52d144eb3..15b33f818 100644 --- a/cmd/podman/import.go +++ b/cmd/podman/import.go @@ -36,7 +36,6 @@ func init() { flags.StringVarP(&importCommand.Message, "message", "m", "", "Set commit message for imported image") flags.BoolVarP(&importCommand.Quiet, "quiet", "q", false, "Suppress output") - rootCmd.AddCommand(importCommand.Command) } func importCmd(c *cliconfig.ImportValues) error { diff --git a/cmd/podman/info.go b/cmd/podman/info.go index 0896e16a4..177878e5a 100644 --- a/cmd/podman/info.go +++ b/cmd/podman/info.go @@ -37,7 +37,6 @@ func init() { flags.BoolVarP(&infoCommand.Debug, "debug", "D", false, "Display additional debug information") flags.StringVarP(&infoCommand.Format, "format", "f", "", "Change the output format to JSON or a Go template") - rootCmd.AddCommand(infoCommand.Command) } func infoCmd(c *cliconfig.InfoValues) error { diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index b2979c6ae..21ad067cd 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -46,7 +46,6 @@ func init() { 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") - rootCmd.AddCommand(inspectCommand.Command) } func inspectCmd(c *cliconfig.InspectValues) error { diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go index 04c0fd531..75ebbb6b0 100644 --- a/cmd/podman/kill.go +++ b/cmd/podman/kill.go @@ -40,7 +40,6 @@ 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") - rootCmd.AddCommand(killCommand.Command) } // killCmd kills one or more containers with a signal diff --git a/cmd/podman/load.go b/cmd/podman/load.go index 90268ca8f..c50cd1608 100644 --- a/cmd/podman/load.go +++ b/cmd/podman/load.go @@ -39,7 +39,6 @@ func init() { flags.BoolVarP(&loadCommand.Quiet, "quiet", "q", false, "Suppress the output") flags.StringVar(&loadCommand.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file (not usually used)") - rootCmd.AddCommand(loadCommand.Command) } // loadCmd gets the image/file to be loaded from the command line diff --git a/cmd/podman/login.go b/cmd/podman/login.go index 5ab0713e5..92102e940 100644 --- a/cmd/podman/login.go +++ b/cmd/podman/login.go @@ -44,7 +44,6 @@ func init() { flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") flags.StringVarP(&loginCommand.Username, "username", "u", "", "Username for registry") - rootCmd.AddCommand(loginCommand.Command) } // loginCmd uses the authentication package to store a user's authenticated credentials diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go index 02bde7857..4d0f156e4 100644 --- a/cmd/podman/logout.go +++ b/cmd/podman/logout.go @@ -32,7 +32,6 @@ func init() { flags.BoolVarP(&logoutCommand.All, "all", "a", false, "Remove the cached credentials for all registries in the auth file") flags.StringVar(&logoutCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override") - rootCmd.AddCommand(logoutCommand.Command) } // logoutCmd uses the authentication package to remove the authenticated of a registry diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go index 83f900e63..77c0b17f3 100644 --- a/cmd/podman/logs.go +++ b/cmd/podman/logs.go @@ -43,7 +43,6 @@ func init() { flags.SetInterspersed(false) - rootCmd.AddCommand(logsCommand.Command) } func logsCmd(c *cliconfig.LogsValues) error { diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 32ecaede7..49acde1f9 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -27,6 +27,24 @@ var ( exitCode = 125 ) +// Commands that the remote and local client have +// implemented. +var mainCommands = []*cobra.Command{ + _exportCommand, + _historyCommand, + _imagesCommand, + _importCommand, + _infoCommand, + _inspectCommand, + _killCommand, + _pullCommand, + _rmiCommand, + _tagCommand, + _versionCommand, + imageCommand.Command, + systemCommand.Command, +} + var cmdsNotRequiringRootless = map[*cobra.Command]bool{ _versionCommand: true, _createCommand: true, @@ -92,6 +110,8 @@ func init() { rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console") rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory") + rootCmd.AddCommand(mainCommands...) + rootCmd.AddCommand(getMainCommands()...) } func initConfig() { diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go index 36ca8bcfb..d16b17108 100644 --- a/cmd/podman/mount.go +++ b/cmd/podman/mount.go @@ -45,7 +45,6 @@ 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") - rootCmd.AddCommand(mountCommand.Command) } // jsonMountPoint stores info about each container diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go index 466a3b136..8d8501ff7 100644 --- a/cmd/podman/pause.go +++ b/cmd/podman/pause.go @@ -37,7 +37,6 @@ func init() { flags := pauseCommand.Flags() flags.BoolVarP(&pauseCommand.All, "all", "a", false, "Pause all running containers") - rootCmd.AddCommand(pauseCommand.Command) } func pauseCmd(c *cliconfig.PauseValues) error { diff --git a/cmd/podman/play.go b/cmd/podman/play.go index ff8320a6b..f083c9ff1 100644 --- a/cmd/podman/play.go +++ b/cmd/podman/play.go @@ -19,5 +19,4 @@ func init() { func init() { playCommand.AddCommand(getPlaySubCommands()...) - rootCmd.AddCommand(playCommand.Command) } diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go index 4104c39c7..4de824703 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -20,5 +20,4 @@ var podCommand = cliconfig.PodmanCommand{ func init() { podCommand.AddCommand(getPodSubCommands()...) - rootCmd.AddCommand(podCommand.Command) } diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go index ccbcf9f7c..02dee68ac 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -2,7 +2,11 @@ package main import ( "fmt" + "html/template" + "os" + "reflect" "strings" + "text/tabwriter" "time" "encoding/json" @@ -136,6 +140,25 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error { step = 0 } + headerNames := make(map[string]string) + if c.Format != "" { + // Make a map of the field names for the headers + v := reflect.ValueOf(podStatOut{}) + t := v.Type() + for i := 0; i < t.NumField(); i++ { + value := strings.ToUpper(splitCamelCase(t.Field(i).Name)) + switch value { + case "CPU": + value = value + " %" + case "MEM": + value = value + " %" + case "MEM USAGE": + value = "MEM USAGE / LIMIT" + } + headerNames[t.Field(i).Name] = value + } + } + for i := 0; i < times; i += step { var newStats []*libpod.PodContainerStats for _, p := range pods { @@ -163,7 +186,14 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error { outputJson(newStats) } else { - outputToStdOut(newStats) + results := podContainerStatsToPodStatOut(newStats) + if len(format) == 0 { + outputToStdOut(results) + } else { + if err := printPSFormat(c.Format, results, headerNames); err != nil { + return err + } + } } time.Sleep(time.Second) previousPodStats := new([]*libpod.PodContainerStats) @@ -177,28 +207,88 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error { return nil } -func outputToStdOut(stats []*libpod.PodContainerStats) { - outFormat := ("%-14s %-14s %-12s %-6s %-19s %-6s %-19s %-19s %-4s\n") - fmt.Printf(outFormat, "POD", "CID", "NAME", "CPU %", "MEM USAGE/ LIMIT", "MEM %", "NET IO", "BLOCK IO", "PIDS") - for _, i := range stats { - if len(i.ContainerStats) == 0 { - fmt.Printf(outFormat, i.Pod.ID()[:12], "--", "--", "--", "--", "--", "--", "--", "--") - } - for _, c := range i.ContainerStats { - cpu := floatToPercentString(c.CPU) - memUsage := combineHumanValues(c.MemUsage, c.MemLimit) - memPerc := floatToPercentString(c.MemPerc) - netIO := combineHumanValues(c.NetInput, c.NetOutput) - blockIO := combineHumanValues(c.BlockInput, c.BlockOutput) - pids := pidsToString(c.PIDs) - containerName := c.Name - if len(c.Name) > 10 { - containerName = containerName[:10] +func podContainerStatsToPodStatOut(stats []*libpod.PodContainerStats) []*podStatOut { + var out []*podStatOut + for _, p := range stats { + for _, c := range p.ContainerStats { + o := podStatOut{ + CPU: floatToPercentString(c.CPU), + MemUsage: combineHumanValues(c.MemUsage, c.MemLimit), + Mem: floatToPercentString(c.MemPerc), + NetIO: combineHumanValues(c.NetInput, c.NetOutput), + BlockIO: combineHumanValues(c.BlockInput, c.BlockOutput), + PIDS: pidsToString(c.PIDs), + CID: c.ContainerID[:12], + Name: c.Name, + Pod: p.Pod.ID()[:12], } - fmt.Printf(outFormat, i.Pod.ID()[:12], c.ContainerID[:12], containerName, cpu, memUsage, memPerc, netIO, blockIO, pids) + out = append(out, &o) + } + } + return out +} + +type podStatOut struct { + CPU string + MemUsage string + Mem string + NetIO string + BlockIO string + PIDS string + Pod string + CID string + Name string +} + +func printPSFormat(format string, stats []*podStatOut, headerNames map[string]string) error { + if len(stats) == 0 { + return nil + } + + // Use a tabwriter to align column format + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + // 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 stats { + if err := dataTmpl.Execute(w, container); err != nil { + return err + } + fmt.Fprintln(w, "") + } + // Flush the writer + return w.Flush() + +} + +func outputToStdOut(stats []*podStatOut) { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + outFormat := ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n") + fmt.Fprintf(w, outFormat, "POD", "CID", "NAME", "CPU %", "MEM USAGE/ LIMIT", "MEM %", "NET IO", "BLOCK IO", "PIDS") + for _, i := range stats { + if len(stats) == 0 { + fmt.Fprintf(w, outFormat, i.Pod, "--", "--", "--", "--", "--", "--", "--", "--") + } else { + fmt.Fprintf(w, outFormat, i.Pod, i.CID, i.Name, i.CPU, i.MemUsage, i.Mem, i.NetIO, i.BlockIO, i.PIDS) } } - fmt.Println() + w.Flush() } func getPreviousPodContainerStats(podID string, prev []*libpod.PodContainerStats) map[string]*libpod.ContainerStats { diff --git a/cmd/podman/port.go b/cmd/podman/port.go index 488ef2ffe..6b458c3c8 100644 --- a/cmd/podman/port.go +++ b/cmd/podman/port.go @@ -39,7 +39,6 @@ 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") - rootCmd.AddCommand(portCommand.Command) } func portCmd(c *cliconfig.PortValues) error { diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index 002975b87..dd5bf0ff2 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -187,9 +187,8 @@ 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") - rootCmd.AddCommand(psCommand.Command) - } + func psCmd(c *cliconfig.PsValues) error { var ( filterFuncs []libpod.ContainerFilter diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index d70719164..ad1469403 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -48,7 +48,6 @@ func init() { flags.StringVar(&pullCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") - rootCmd.AddCommand(pullCommand.Command) } // pullCmd gets the data from the command line and calls pullImage diff --git a/cmd/podman/push.go b/cmd/podman/push.go index a1ee00a65..49786e86f 100644 --- a/cmd/podman/push.go +++ b/cmd/podman/push.go @@ -52,7 +52,6 @@ func init() { flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.StringVar(&pushCommand.SignBy, "sign-by", "", "Add a signature at the destination using the specified key") flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") - rootCmd.AddCommand(pushCommand.Command) } func pushCmd(c *cliconfig.PushValues) error { diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go index 3890188b4..32b274169 100644 --- a/cmd/podman/refresh.go +++ b/cmd/podman/refresh.go @@ -27,7 +27,6 @@ var ( func init() { refreshCommand.Command = _refreshCommand - rootCmd.AddCommand(refreshCommand.Command) } func refreshCmd(c *cliconfig.RefreshValues) error { diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index f94e745ed..a305b364a 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -39,7 +39,6 @@ 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") - rootCmd.AddCommand(restartCommand.Command) } func restartCmd(c *cliconfig.RestartValues) error { diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index daee635f0..5f28c3087 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -42,7 +42,6 @@ func init() { // TODO: add ContainerStateCheckpointed flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections") - rootCmd.AddCommand(restoreCommand.Command) } func restoreCmd(c *cliconfig.RestoreValues) error { diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index bb9a913c9..f8aef6461 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -6,6 +6,7 @@ import ( "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/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -39,7 +40,6 @@ func init() { 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 (Not implemented yet)") - rootCmd.AddCommand(rmCommand.Command) } // saveCmd saves the image to either docker-archive or oci @@ -61,10 +61,18 @@ func rmCmd(c *cliconfig.RmValues) error { 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 + } + runtime.RemoveContainersFromStorage(c.InputArgs) + } if len(delContainers) == 0 { return err } - fmt.Println(err.Error()) + if err != nil { + fmt.Println(err.Error()) + } } for _, container := range delContainers { diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go index 70f58e844..4572fd530 100644 --- a/cmd/podman/rmi.go +++ b/cmd/podman/rmi.go @@ -32,8 +32,6 @@ func init() { flags := rmiCommand.Flags() flags.BoolVarP(&rmiCommand.All, "all", "a", false, "Remove all images") flags.BoolVarP(&rmiCommand.Force, "force", "f", false, "Force Removal of the image") - - rootCmd.AddCommand(rmiCommand.Command) } func rmiCmd(c *cliconfig.RmiValues) error { diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 76b29cb84..897e2d1b3 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -40,8 +40,6 @@ func init() { flags.SetInterspersed(false) flags.Bool("sig-proxy", true, "Proxy received signals to the process (default true)") getCreateFlags(&runCommmand.PodmanCommand) - - rootCmd.AddCommand(runCommmand.Command) } func runCmd(c *cliconfig.RunValues) error { diff --git a/cmd/podman/save.go b/cmd/podman/save.go index 766561f1a..62b891358 100644 --- a/cmd/podman/save.go +++ b/cmd/podman/save.go @@ -52,8 +52,6 @@ func init() { 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.StringVarP(&saveCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT") flags.BoolVarP(&saveCommand.Quiet, "quiet", "q", false, "Suppress the output") - - rootCmd.AddCommand(saveCommand.Command) } // saveCmd saves the image to either docker-archive or oci diff --git a/cmd/podman/search.go b/cmd/podman/search.go index b15da1f6d..10c29c918 100644 --- a/cmd/podman/search.go +++ b/cmd/podman/search.go @@ -50,8 +50,6 @@ func init() { flags.IntVar(&searchCommand.Limit, "limit", 0, "Limit the number of results") flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output") flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") - - rootCmd.AddCommand(searchCommand.Command) } type searchParams struct { diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go index a87c12556..2c3f6c09f 100644 --- a/cmd/podman/sign.go +++ b/cmd/podman/sign.go @@ -42,8 +42,6 @@ func init() { flags.StringVarP(&signCommand.Directory, "directory", "d", "", "Define an alternate directory to store signatures") flags.StringVar(&signCommand.SignBy, "sign-by", "", "Name of the signing key") - rootCmd.AddCommand(signCommand.Command) - } // SignatureStoreDir defines default directory to store signatures diff --git a/cmd/podman/start.go b/cmd/podman/start.go index 483ab4081..3a03db47a 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -42,8 +42,6 @@ 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)") - - rootCmd.AddCommand(startCommand.Command) } func startCmd(c *cliconfig.StartValues) error { diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index 8c79ed290..2af7fb9ea 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -53,8 +53,6 @@ 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") - - rootCmd.AddCommand(statsCommand.Command) } func statsCmd(c *cliconfig.StatsValues) error { diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index e2c16fe20..4700b2dde 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -42,8 +42,6 @@ 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") - - rootCmd.AddCommand(stopCommand.Command) } func stopCmd(c *cliconfig.StopValues) error { diff --git a/cmd/podman/system.go b/cmd/podman/system.go index f6b28fee1..b6bc1bfef 100644 --- a/cmd/podman/system.go +++ b/cmd/podman/system.go @@ -17,7 +17,11 @@ var ( } ) +var systemCommands = []*cobra.Command{ + _infoCommand, +} + func init() { + systemCommand.AddCommand(systemCommands...) systemCommand.AddCommand(getSystemSubCommands()...) - rootCmd.AddCommand(systemCommand.Command) } diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go index 2c7cf4abb..fdd29fc83 100644 --- a/cmd/podman/tag.go +++ b/cmd/podman/tag.go @@ -26,8 +26,6 @@ var ( func init() { tagCommand.Command = _tagCommand - rootCmd.AddCommand(tagCommand.Command) - } func tagCmd(c *cliconfig.TagValues) error { diff --git a/cmd/podman/top.go b/cmd/podman/top.go index a03830ee5..8555f701e 100644 --- a/cmd/podman/top.go +++ b/cmd/podman/top.go @@ -52,8 +52,6 @@ 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") - - rootCmd.AddCommand(topCommand.Command) } func topCmd(c *cliconfig.TopValues) error { diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go index 4622e8276..453560641 100644 --- a/cmd/podman/umount.go +++ b/cmd/podman/umount.go @@ -41,8 +41,6 @@ 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") - - rootCmd.AddCommand(umountCommand.Command) } func umountCmd(c *cliconfig.UmountValues) error { diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go index fb3a7b57a..de4e71ad9 100644 --- a/cmd/podman/unpause.go +++ b/cmd/podman/unpause.go @@ -37,8 +37,6 @@ func init() { unpauseCommand.Command = _unpauseCommand flags := unpauseCommand.Flags() flags.BoolVarP(&unpauseCommand.All, "all", "a", false, "Unpause all paused containers") - - rootCmd.AddCommand(unpauseCommand.Command) } func unpauseCmd(c *cliconfig.UnpauseValues) error { diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go index 2b76e034e..73ffcdb3f 100644 --- a/cmd/podman/varlink.go +++ b/cmd/podman/varlink.go @@ -1,4 +1,4 @@ -// +build varlink +// +build varlink,!remoteclient package main @@ -40,8 +40,6 @@ func init() { varlinkCommand.Command = _varlinkCommand flags := varlinkCommand.Flags() flags.Int64VarP(&varlinkCommand.Timeout, "timeout", "t", 1000, "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout") - - rootCmd.AddCommand(varlinkCommand.Command) } func varlinkCmd(c *cliconfig.VarlinkValues) error { diff --git a/cmd/podman/version.go b/cmd/podman/version.go index 0e7cd43d5..766dfdc0b 100644 --- a/cmd/podman/version.go +++ b/cmd/podman/version.go @@ -30,7 +30,6 @@ func init() { versionCommand.Command = _versionCommand flags := versionCommand.Flags() flags.StringVarP(&versionCommand.Format, "format", "f", "", "Change the output format to JSON or a Go template") - rootCmd.AddCommand(versionCommand.Command) } // versionCmd gets and prints version info for version command diff --git a/cmd/podman/volume.go b/cmd/podman/volume.go index bae778e52..d63db82e4 100644 --- a/cmd/podman/volume.go +++ b/cmd/podman/volume.go @@ -19,5 +19,4 @@ var volumeCommand = cliconfig.PodmanCommand{ func init() { volumeCommand.AddCommand(getVolumeSubCommands()...) - rootCmd.AddCommand(volumeCommand.Command) } diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go index fa195b7ce..9d2441b8f 100644 --- a/cmd/podman/wait.go +++ b/cmd/podman/wait.go @@ -37,8 +37,6 @@ 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") - - rootCmd.AddCommand(waitCommand.Command) } func waitCmd(c *cliconfig.WaitValues) error { diff --git a/docs/podman-rm.1.md b/docs/podman-rm.1.md index 4fcb0b6c5..f4513c2be 100644 --- a/docs/podman-rm.1.md +++ b/docs/podman-rm.1.md @@ -17,7 +17,9 @@ Remove all containers. Can be used in conjunction with -f as well. **--force, f** -Force the removal of a running and paused containers +Force the removal of running and paused containers. Forcing a containers removal also +removes containers from container storage even if the container is not known to podman. +Containers could have been created by a different container engine. **--latest, -l** diff --git a/docs/podman-stats.1.md b/docs/podman-stats.1.md index 8fc765326..d0b56b2e6 100644 --- a/docs/podman-stats.1.md +++ b/docs/podman-stats.1.md @@ -36,16 +36,17 @@ Valid placeholders for the Go template are listed below: | **Placeholder** | **Description** | | --------------- | --------------- | -| .ID | Container ID | +| .Pod | Pod ID | +| .CID | Container ID | | .Name | Container Name | -| .CPUPerc | CPU percentage | +| .CPU | CPU percentage | | .MemUsage | Memory usage | -| .MemPerc | Memory percentage | +| .Mem | Memory percentage | | .NetIO | Network IO | | .BlockIO | Block IO | | .PIDS | Number of PIDs | - +When using a GO template, you may preceed the format with `table` to print headers. ## EXAMPLE ``` diff --git a/libpod/errors.go b/libpod/errors.go index d6614141c..30a19d30f 100644 --- a/libpod/errors.go +++ b/libpod/errors.go @@ -2,15 +2,20 @@ package libpod import ( "errors" + + "github.com/containers/libpod/libpod/image" ) var ( // ErrNoSuchCtr indicates the requested container does not exist - ErrNoSuchCtr = errors.New("no such container") + ErrNoSuchCtr = image.ErrNoSuchCtr + // ErrNoSuchPod indicates the requested pod does not exist - ErrNoSuchPod = errors.New("no such pod") + ErrNoSuchPod = image.ErrNoSuchPod + // ErrNoSuchImage indicates the requested image does not exist - ErrNoSuchImage = errors.New("no such image") + ErrNoSuchImage = image.ErrNoSuchImage + // ErrNoSuchVolume indicates the requested volume does not exist ErrNoSuchVolume = errors.New("no such volume") diff --git a/libpod/kube.go b/libpod/kube.go index f34805e39..16cebf99b 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -401,7 +401,7 @@ func capAddDrop(caps *specs.LinuxCapabilities) (*v1.Capabilities, error) { func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) { priv := c.Privileged() ro := c.IsReadOnly() - allowPrivEscalation := !c.Spec().Process.NoNewPrivileges + allowPrivEscalation := !c.config.Spec.Process.NoNewPrivileges newCaps, err := capAddDrop(c.config.Spec.Process.Capabilities) if err != nil { @@ -421,7 +421,13 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) { } if c.User() != "" { - // It is *possible* that + if !c.batched { + c.lock.Lock() + defer c.lock.Unlock() + } + if err := c.syncContainer(); err != nil { + return nil, errors.Wrapf(err, "unable to sync container during YAML generation") + } logrus.Debugf("Looking in container for user: %s", c.User()) u, err := lookup.GetUser(c.state.Mountpoint, c.User()) if err != nil { diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 9afdef7b6..4f8192198 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -10,7 +10,9 @@ import ( "strings" "time" + "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/storage" "github.com/containers/storage/pkg/stringid" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -564,3 +566,16 @@ func (r *Runtime) Export(name string, path string) error { return ctr.Export(path) } + +// RemoveContainersFromStorage attempt to remove containers from storage that do not exist in libpod database +func (r *Runtime) RemoveContainersFromStorage(ctrs []string) { + for _, i := range ctrs { + // if the container does not exist in database, attempt to remove it from storage + if _, err := r.LookupContainer(i); err != nil && errors.Cause(err) == image.ErrNoSuchCtr { + r.storageService.UnmountContainerImage(i, true) + if err := r.storageService.DeleteContainer(i); err != nil && errors.Cause(err) != storage.ErrContainerUnknown { + logrus.Errorf("Failed to remove container %q from storage: %s", i, err) + } + } + } +} diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index 43d089a24..e330c3a39 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -147,5 +147,28 @@ var _ = Describe("Podman pod stats", func() { Expect(stats.ExitCode()).To(Equal(0)) Expect(stats.IsJSONOutputValid()).To(BeTrue()) }) + It("podman stats with GO template", func() { + _, ec, podid := podmanTest.CreatePod("") + Expect(ec).To(Equal(0)) + + session := podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + stats := podmanTest.Podman([]string{"pod", "stats", "-a", "--no-reset", "--no-stream", "--format", "\"table {{.CID}} {{.Pod}} {{.Mem}} {{.MemUsage}} {{.CPU}} {{.NetIO}} {{.BlockIO}} {{.PIDS}} {{.Pod}}\""}) + stats.WaitWithDefaultTimeout() + Expect(stats.ExitCode()).To(Equal(0)) + }) + + It("podman stats with invalid GO template", func() { + _, ec, podid := podmanTest.CreatePod("") + Expect(ec).To(Equal(0)) + + session := podmanTest.RunTopContainerInPod("", podid) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + stats := podmanTest.Podman([]string{"pod", "stats", "-a", "--no-reset", "--no-stream", "--format", "\"table {{.ID}} \""}) + stats.WaitWithDefaultTimeout() + Expect(stats.ExitCode()).ToNot(Equal(0)) + }) }) |