mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
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 <jhonce@redhat.com>
This commit is contained in:
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containers/podman/v2/cmd/podman/parse"
|
||||
"github.com/containers/podman/v2/cmd/podman/registry"
|
||||
"github.com/containers/podman/v2/cmd/podman/utils"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
@ -97,10 +98,10 @@ func systemd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
switch format {
|
||||
case "json":
|
||||
switch {
|
||||
case parse.MatchesJSONFormat(format):
|
||||
return printJSON(report.Units)
|
||||
case "":
|
||||
case format == "":
|
||||
return printDefault(report.Units)
|
||||
default:
|
||||
return errors.Errorf("unknown --format argument: %s", format)
|
||||
|
@ -3,12 +3,13 @@ package network
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"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/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -39,31 +40,32 @@ func init() {
|
||||
flags.StringVarP(&networkInspectOptions.Format, "format", "f", "", "Pretty-print network to JSON or using a Go template")
|
||||
}
|
||||
|
||||
func networkInspect(cmd *cobra.Command, args []string) error {
|
||||
func networkInspect(_ *cobra.Command, args []string) error {
|
||||
responses, err := registry.ContainerEngine().NetworkInspect(registry.Context(), args, entities.NetworkInspectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.MarshalIndent(responses, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.ToLower(networkInspectOptions.Format) == "json" || networkInspectOptions.Format == "" {
|
||||
fmt.Println(string(b))
|
||||
} else {
|
||||
var w io.Writer = os.Stdout
|
||||
//There can be more than 1 in the inspect output.
|
||||
format := "{{range . }}" + networkInspectOptions.Format + "{{end}}"
|
||||
tmpl, err := template.New("inspectNetworks").Parse(format)
|
||||
|
||||
switch {
|
||||
case parse.MatchesJSONFormat(networkInspectOptions.Format) || networkInspectOptions.Format == "":
|
||||
b, err := json.MarshalIndent(responses, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tmpl.Execute(w, responses); err != nil {
|
||||
fmt.Println(string(b))
|
||||
default:
|
||||
row := report.NormalizeFormat(networkInspectOptions.Format)
|
||||
// There can be more than 1 in the inspect output.
|
||||
row = "{{range . }}" + row + "{{end}}"
|
||||
tmpl, err := template.New("inspectNetworks").Parse(row)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flusher, ok := w.(interface{ Flush() error }); ok {
|
||||
return flusher.Flush()
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 8, 2, 0, ' ', 0)
|
||||
defer w.Flush()
|
||||
|
||||
return tmpl.Execute(w, responses)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
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)
|
||||
}
|
||||
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
|
||||
}
|
||||
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)
|
||||
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
|
||||
}
|
||||
}
|
||||
if err := tmpl.Execute(w, lpr); err != nil {
|
||||
return err
|
||||
}
|
||||
if flusher, ok := w.(interface{ Flush() error }); ok {
|
||||
return flusher.Flush()
|
||||
}
|
||||
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}}"
|
||||
}
|
||||
if psInput.CtrStatus {
|
||||
headers += "\tSTATUS"
|
||||
row += "\t{{.ContainerStatuses}}"
|
||||
}
|
||||
if psInput.Namespace {
|
||||
headers += "\tCGROUP\tNAMESPACES"
|
||||
row += "\t{{.Cgroup}}\t{{.Namespace}}"
|
||||
}
|
||||
if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
|
||||
headers += "\t# OF CONTAINERS"
|
||||
row += "\t{{.NumberOfContainers}}"
|
||||
|
||||
if psInput.CtrNames {
|
||||
row = append(row, "{{.ContainerNames}}")
|
||||
}
|
||||
headers += "\tINFRA ID\n"
|
||||
row += "\t{{.InfraId}}\n"
|
||||
return headers, row
|
||||
|
||||
if psInput.CtrStatus {
|
||||
row = append(row, "{{.ContainerStatuses}}")
|
||||
}
|
||||
|
||||
if psInput.Namespace {
|
||||
row = append(row, "{{.Cgroup}}", "{{.Namespace}}")
|
||||
}
|
||||
|
||||
if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
|
||||
row = append(row, "{{.NumberOfContainers}}")
|
||||
}
|
||||
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 ""
|
||||
}
|
||||
|
@ -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
|
||||
if err := tmpl.Execute(w, headerNames); err != nil {
|
||||
return err
|
||||
}
|
||||
// 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
|
||||
}
|
||||
return headerNames
|
||||
return tmpl.Execute(w, stats)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
. "github.com/containers/podman/v2/test/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman ps", func() {
|
||||
@ -63,7 +64,7 @@ var _ = Describe("Podman ps", func() {
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "ps", "-q"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(result).To(Exit(0))
|
||||
Expect(len(result.OutputToStringArray())).Should(BeNumerically(">", 0))
|
||||
Expect(podid).To(ContainSubstring(result.OutputToStringArray()[0]))
|
||||
})
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
. "github.com/containers/podman/v2/test/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman pod stats", func() {
|
||||
@ -156,9 +157,9 @@ var _ = Describe("Podman pod stats", func() {
|
||||
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 := 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))
|
||||
Expect(stats).To(Exit(0))
|
||||
})
|
||||
|
||||
It("podman stats with invalid GO template", func() {
|
||||
|
Reference in New Issue
Block a user