From d35aa3f293c2132bc32de9cf4dcffe8b5bf6f8c8 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Thu, 2 Dec 2021 11:45:48 -0700 Subject: [PATCH] Refactor podman pods to report.Formatter [NO NEW TESTS NEEDED] Support better compatibility output for podman pods commands See #10974 Depends on containers/common#831 Signed-off-by: Jhon Honce --- cmd/podman/pods/inspect.go | 19 +++------ cmd/podman/pods/ps.go | 63 +++++++++++++---------------- cmd/podman/pods/stats.go | 81 +++++++++++++++++++------------------- 3 files changed, 74 insertions(+), 89 deletions(-) diff --git a/cmd/podman/pods/inspect.go b/cmd/podman/pods/inspect.go index d4b8df90e8..fd34d255f0 100644 --- a/cmd/podman/pods/inspect.go +++ b/cmd/podman/pods/inspect.go @@ -3,6 +3,7 @@ package pods import ( "context" "os" + "text/template" "github.com/containers/common/pkg/report" "github.com/containers/podman/v3/cmd/podman/common" @@ -64,25 +65,17 @@ func inspect(cmd *cobra.Command, args []string) error { } if report.IsJSON(inspectOptions.Format) { - json.MarshalIndent(responses, "", " ") enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(responses) } - // cmd.Flags().Changed("format") must be true to reach this code - row := report.NormalizeFormat(inspectOptions.Format) - - t, err := report.NewTemplate("inspect").Parse(row) - if err != nil { - return err - } - - w, err := report.NewWriterDefault(os.Stdout) + // Cannot use report.New() as it enforces {{range .}} for OriginUser templates + tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs)) + format := report.NormalizeFormat(inspectOptions.Format) + tmpl, err = tmpl.Parse(format) if err != nil { return err } - err = t.Execute(w, *responses) - w.Flush() - return err + return tmpl.Execute(os.Stdout, *responses) } diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go index 808ec31b32..0b1c76cb2d 100644 --- a/cmd/podman/pods/ps.go +++ b/cmd/podman/pods/ps.go @@ -110,56 +110,49 @@ func pods(cmd *cobra.Command, _ []string) error { return nil } - // Formatted output below lpr := make([]ListPodReporter, 0, len(responses)) for _, r := range responses { lpr = append(lpr, ListPodReporter{r}) } - headers := report.Headers(ListPodReporter{}, map[string]string{ - "Id": "POD ID", - "Name": "NAME", - "Status": "STATUS", - "Labels": "LABELS", - "NumberOfContainers": "# OF CONTAINERS", - "Created": "CREATED", - "InfraID": "INFRA ID", - "ContainerIds": "IDS", - "ContainerNames": "NAMES", - "ContainerStatuses": "STATUS", - "Cgroup": "CGROUP", - "Namespace": "NAMESPACES", - }) - renderHeaders := true - row := podPsFormat() - if cmd.Flags().Changed("format") { - renderHeaders = report.HasTable(psInput.Format) - row = report.NormalizeFormat(psInput.Format) - } - format := report.EnforceRange(row) + rpt := report.New(os.Stdout, cmd.Name()) + defer rpt.Flush() - noHeading, _ := cmd.Flags().GetBool("noheading") - if noHeading { - renderHeaders = false + if cmd.Flags().Changed("format") { + rpt, err = rpt.Parse(report.OriginUser, psInput.Format) + } else { + rpt, err = rpt.Parse(report.OriginPodman, podPsFormat()) } - - tmpl, err := report.NewTemplate("list").Parse(format) if err != nil { return err } - w, err := report.NewWriterDefault(os.Stdout) - if err != nil { - return err + renderHeaders := true + if noHeading, _ := cmd.Flags().GetBool("noheading"); noHeading { + renderHeaders = false } - defer w.Flush() - if renderHeaders { - if err := tmpl.Execute(w, headers); err != nil { + if renderHeaders && rpt.RenderHeaders { + headers := report.Headers(ListPodReporter{}, map[string]string{ + "Id": "POD ID", + "Name": "NAME", + "Status": "STATUS", + "Labels": "LABELS", + "NumberOfContainers": "# OF CONTAINERS", + "Created": "CREATED", + "InfraID": "INFRA ID", + "ContainerIds": "IDS", + "ContainerNames": "NAMES", + "ContainerStatuses": "STATUS", + "Cgroup": "CGROUP", + "Namespace": "NAMESPACES", + }) + + if err := rpt.Execute(headers); err != nil { return err } } - return tmpl.Execute(w, lpr) + return rpt.Execute(lpr) } func podPsFormat() string { @@ -184,7 +177,7 @@ func podPsFormat() string { if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds { row = append(row, "{{.NumberOfContainers}}") } - return strings.Join(row, "\t") + "\n" + return "{{range . }}" + strings.Join(row, "\t") + "\n" + "{{end -}}" } // ListPodReporter is a struct for pod ps output diff --git a/cmd/podman/pods/stats.go b/cmd/podman/pods/stats.go index a7bba3064b..fbb9e0b526 100644 --- a/cmd/podman/pods/stats.go +++ b/cmd/podman/pods/stats.go @@ -67,15 +67,22 @@ func stats(cmd *cobra.Command, args []string) error { return err } - doJSON := report.IsJSON(cmd.Flag("format").Value.String()) - headers := report.Headers(entities.PodStatsReport{}, map[string]string{ - "CPU": "CPU %", - "MemUsage": "MEM USAGE/ LIMIT", - "MemUsageBytes": "MEM USAGE/ LIMIT", - "MEM": "MEM %", - "NET IO": "NET IO", - "BlockIO": "BLOCK IO", - }) + rpt := report.New(os.Stdout, cmd.Name()) + defer rpt.Flush() + + var err error + doJSON := report.IsJSON(statsOptions.Format) + if !doJSON { + if cmd.Flags().Changed("format") { + rpt, err = rpt.Parse(report.OriginUser, statsOptions.Format) + if err != nil { + return err + } + } else { + rpt = rpt.Init(os.Stdout, 12, 2, 2, ' ', 0) + rpt.Origin = report.OriginPodman + } + } for ; ; time.Sleep(time.Second) { reports, err := registry.ContainerEngine().PodStats(context.Background(), args, statsOptions.PodStatsOptions) @@ -84,30 +91,26 @@ func stats(cmd *cobra.Command, args []string) error { } // Print the stats in the requested format and configuration. if doJSON { - if err := printJSONPodStats(reports); err != nil { - return err - } + err = printJSONPodStats(reports) } else { if !statsOptions.NoReset { goterm.Clear() goterm.MoveCursor(1, 1) goterm.Flush() } - if cmd.Flags().Changed("format") { - row := report.NormalizeFormat(statsOptions.Format) - row = report.EnforceRange(row) - if err := printFormattedPodStatsLines(headers, row, reports); err != nil { - return err - } + if report.OriginUser == rpt.Origin { + err = userTemplate(rpt, reports) } else { - printPodStatsLines(reports) + err = defaultTemplate(rpt, reports) } } + if err != nil { + return err + } if statsOptions.NoStream { break } } - return nil } @@ -120,42 +123,38 @@ func printJSONPodStats(stats []*entities.PodStatsReport) error { return nil } -func printPodStatsLines(stats []*entities.PodStatsReport) error { - w, err := report.NewWriterDefault(os.Stdout) - if err != nil { - return err - } - +func defaultTemplate(rpt *report.Formatter, stats []*entities.PodStatsReport) error { 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") + fmt.Fprintf(rpt.Writer(), outFormat, "POD", "CID", "NAME", "CPU %", "MEM USAGE/ LIMIT", "MEM %", "NET IO", "BLOCK IO", "PIDS") if len(stats) == 0 { - fmt.Fprintf(w, outFormat, "--", "--", "--", "--", "--", "--", "--", "--", "--") + fmt.Fprintf(rpt.Writer(), 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) + fmt.Fprintf(rpt.Writer(), outFormat, i.Pod, i.CID, i.Name, i.CPU, i.MemUsage, i.Mem, i.NetIO, i.BlockIO, i.PIDS) } } - return w.Flush() + return rpt.Flush() } -func printFormattedPodStatsLines(headerNames []map[string]string, row string, stats []*entities.PodStatsReport) error { +func userTemplate(rpt *report.Formatter, stats []*entities.PodStatsReport) error { if len(stats) == 0 { return nil } - tmpl, err := report.NewTemplate("stats").Parse(row) - if err != nil { - return err - } + headers := report.Headers(entities.PodStatsReport{}, map[string]string{ + "CPU": "CPU %", + "MemUsage": "MEM USAGE/ LIMIT", + "MemUsageBytes": "MEM USAGE/ LIMIT", + "MEM": "MEM %", + "NET IO": "NET IO", + "BlockIO": "BLOCK IO", + }) - w, err := report.NewWriterDefault(os.Stdout) - if err != nil { + if err := rpt.Execute(headers); err != nil { return err } - defer w.Flush() - - if err := tmpl.Execute(w, headerNames); err != nil { + if err := rpt.Execute(stats); err != nil { return err } - return tmpl.Execute(w, stats) + return rpt.Flush() }