From f128bff232a9d9ee14376af83e7f917d3c47ceb8 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Thu, 8 Oct 2020 15:37:44 -0700 Subject: Restore --format table... Following commands: * systemd generate * networks inspect * pod stats * Fixed test where format was quoted and then quoted again * Fixed bug where output never printed '--' on missed reads * pod ps Signed-off-by: Jhon Honce --- cmd/podman/pods/ps.go | 108 ++++++++++++++++++++++------------------------- cmd/podman/pods/stats.go | 94 +++++++++++++---------------------------- 2 files changed, 81 insertions(+), 121 deletions(-) (limited to 'cmd/podman/pods') diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go index 7b755cb22..b7952e6e3 100644 --- a/cmd/podman/pods/ps.go +++ b/cmd/podman/pods/ps.go @@ -3,7 +3,6 @@ package pods import ( "context" "fmt" - "io" "os" "sort" "strings" @@ -11,7 +10,9 @@ import ( "text/template" "time" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" + "github.com/containers/podman/v2/cmd/podman/report" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/docker/go-units" @@ -34,10 +35,9 @@ var ( ) var ( - defaultHeaders = "POD ID\tNAME\tSTATUS\tCREATED" - inputFilters []string - noTrunc bool - psInput entities.PodPSOptions + inputFilters []string + noTrunc bool + psInput entities.PodPSOptions ) func init() { @@ -62,11 +62,6 @@ func init() { } func pods(cmd *cobra.Command, _ []string) error { - var ( - w io.Writer = os.Stdout - row string - ) - if psInput.Quiet && len(psInput.Format) > 0 { return errors.New("quiet and format cannot be used together") } @@ -89,80 +84,79 @@ func pods(cmd *cobra.Command, _ []string) error { return err } - if psInput.Format == "json" { + switch { + case parse.MatchesJSONFormat(psInput.Format): b, err := json.MarshalIndent(responses, "", " ") if err != nil { return err } fmt.Println(string(b)) return nil + case psInput.Quiet: + for _, p := range responses { + fmt.Println(p.Id) + } + return nil } + // Formatted output below lpr := make([]ListPodReporter, 0, len(responses)) for _, r := range responses { lpr = append(lpr, ListPodReporter{r}) } - headers, row := createPodPsOut() - if psInput.Quiet { - row = "{{.Id}}\n" - } - if cmd.Flag("format").Changed { - row = psInput.Format - if !strings.HasPrefix(row, "\n") { - row += "\n" - } - } - format := "{{range . }}" + row + "{{end}}" - if !psInput.Quiet && !cmd.Flag("format").Changed { - format = headers + format + + headers := report.Headers(ListPodReporter{}, map[string]string{ + "ContainerIds": "IDS", + "ContainerNames": "NAMES", + "ContainerStatuses": "STATUS", + "Namespace": "NAMESPACES", + "NumberOfContainers": "# OF CONTAINERS", + "InfraId": "INFRA ID", + }) + row := podPsFormat() + if cmd.Flags().Changed("format") { + row = report.NormalizeFormat(psInput.Format) } - tmpl, err := template.New("listPods").Parse(format) + row = "{{range . }}" + row + "{{end}}" + + tmpl, err := template.New("listPods").Parse(row) if err != nil { return err } - if !psInput.Quiet { - w = tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) - } - if err := tmpl.Execute(w, lpr); err != nil { - return err - } - if flusher, ok := w.(interface{ Flush() error }); ok { - return flusher.Flush() + w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) + defer w.Flush() + + if !psInput.Quiet && !cmd.Flag("format").Changed { + if err := tmpl.Execute(w, headers); err != nil { + return err + } } - return nil + return tmpl.Execute(w, lpr) } -func createPodPsOut() (string, string) { - var row string - headers := defaultHeaders - row += "{{.Id}}" - - row += "\t{{.Name}}\t{{.Status}}\t{{.Created}}" +func podPsFormat() string { + row := []string{"{{.Id}}", "{{.Name}}", "{{.Status}}", "{{.Created}}}"} if psInput.CtrIds { - headers += "\tIDS" - row += "\t{{.ContainerIds}}" + row = append(row, "{{.ContainerIds}}") } + if psInput.CtrNames { - headers += "\tNAMES" - row += "\t{{.ContainerNames}}" + row = append(row, "{{.ContainerNames}}") } + if psInput.CtrStatus { - headers += "\tSTATUS" - row += "\t{{.ContainerStatuses}}" + row = append(row, "{{.ContainerStatuses}}") } + if psInput.Namespace { - headers += "\tCGROUP\tNAMESPACES" - row += "\t{{.Cgroup}}\t{{.Namespace}}" + row = append(row, "{{.Cgroup}}", "{{.Namespace}}") } - if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds { - headers += "\t# OF CONTAINERS" - row += "\t{{.NumberOfContainers}}" + if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds { + row = append(row, "{{.NumberOfContainers}}") } - headers += "\tINFRA ID\n" - row += "\t{{.InfraId}}\n" - return headers, row + return strings.Join(row, "\t") + "\n" } // ListPodReporter is a struct for pod ps output @@ -180,7 +174,7 @@ func (l ListPodReporter) Labels() map[string]string { return l.ListPodsReport.Labels } -// NumberofContainers returns an int representation for +// NumberOfContainers returns an int representation for // the number of containers belonging to the pod func (l ListPodReporter) NumberOfContainers() int { return len(l.Containers) @@ -192,7 +186,7 @@ func (l ListPodReporter) ID() string { } // Id returns the Pod id -func (l ListPodReporter) Id() string { //nolint +func (l ListPodReporter) Id() string { // nolint if noTrunc { return l.ListPodsReport.Id } @@ -206,7 +200,7 @@ func (l ListPodReporter) InfraID() string { // InfraId returns the infra container id for the pod // depending on trunc -func (l ListPodReporter) InfraId() string { //nolint +func (l ListPodReporter) InfraId() string { // nolint if len(l.ListPodsReport.InfraId) == 0 { return "" } diff --git a/cmd/podman/pods/stats.go b/cmd/podman/pods/stats.go index 1d916dbfa..2f59e4e47 100644 --- a/cmd/podman/pods/stats.go +++ b/cmd/podman/pods/stats.go @@ -4,18 +4,16 @@ import ( "context" "fmt" "os" - "reflect" - "strings" "text/tabwriter" "text/template" "time" "github.com/buger/goterm" - "github.com/containers/buildah/pkg/formats" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" + "github.com/containers/podman/v2/cmd/podman/report" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/containers/podman/v2/pkg/util/camelcase" "github.com/spf13/cobra" ) @@ -67,11 +65,18 @@ func stats(cmd *cobra.Command, args []string) error { return err } - format := statsOptions.Format - doJSON := strings.ToLower(format) == formats.JSONString - header := getPodStatsHeader(format) + row := report.NormalizeFormat(statsOptions.Format) + doJSON := parse.MatchesJSONFormat(row) - for { + headers := report.Headers(entities.PodStatsReport{}, map[string]string{ + "CPU": "CPU %", + "MemUsage": "MEM USAGE/ LIMIT", + "MEM": "MEM %", + "NET IO": "NET IO", + "BlockIO": "BLOCK IO", + }) + + for ; ; time.Sleep(time.Second) { reports, err := registry.ContainerEngine().PodStats(context.Background(), args, statsOptions.PodStatsOptions) if err != nil { return err @@ -87,16 +92,17 @@ func stats(cmd *cobra.Command, args []string) error { goterm.MoveCursor(1, 1) goterm.Flush() } - if len(format) == 0 { + if cmd.Flags().Changed("format") { + if err := printFormattedPodStatsLines(headers, row, reports); err != nil { + return err + } + } else { printPodStatsLines(reports) - } else if err := printFormattedPodStatsLines(format, reports, header); err != nil { - return err } } if statsOptions.NoStream { break } - time.Sleep(time.Second) } return nil @@ -115,72 +121,32 @@ func printPodStatsLines(stats []*entities.PodStatsReport) { 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 { + if len(stats) == 0 { + fmt.Fprintf(w, outFormat, "--", "--", "--", "--", "--", "--", "--", "--", "--") + } else { + for _, i := range stats { fmt.Fprintf(w, outFormat, i.Pod, i.CID, i.Name, i.CPU, i.MemUsage, i.Mem, i.NetIO, i.BlockIO, i.PIDS) } } w.Flush() } -func printFormattedPodStatsLines(format string, stats []*entities.PodStatsReport, headerNames map[string]string) error { +func printFormattedPodStatsLines(headerNames []map[string]string, row string, stats []*entities.PodStatsReport) 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, "") - } + row = "{{range .}}" + row + "{{end}}" - // Spit out the data rows now - dataTmpl, err := template.New("data").Parse(format) + tmpl, err := template.New("pod stats").Parse(row) if err != nil { return err } - for _, s := range stats { - if err := dataTmpl.Execute(w, s); err != nil { - return err - } - fmt.Fprintln(w, "") - } - // Flush the writer - return w.Flush() - -} + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + defer w.Flush() -// getPodStatsHeader returns the stats header for the specified options. -func getPodStatsHeader(format string) map[string]string { - headerNames := make(map[string]string) - if format == "" { - return headerNames - } - // Make a map of the field names for the headers - v := reflect.ValueOf(entities.PodStatsReport{}) - t := v.Type() - for i := 0; i < t.NumField(); i++ { - split := camelcase.Split(t.Field(i).Name) - value := strings.ToUpper(strings.Join(split, " ")) - switch value { - case "CPU", "MEM": - value += " %" - case "MEM USAGE": - value = "MEM USAGE / LIMIT" - } - headerNames[t.Field(i).Name] = value + if err := tmpl.Execute(w, headerNames); err != nil { + return err } - return headerNames + return tmpl.Execute(w, stats) } -- cgit v1.2.3-54-g00ecf