github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podmanV2/pods/ps.go (about)

     1  package pods
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"strings"
    10  	"text/tabwriter"
    11  	"text/template"
    12  	"time"
    13  
    14  	"github.com/docker/go-units"
    15  
    16  	"github.com/containers/libpod/cmd/podmanV2/registry"
    17  	"github.com/containers/libpod/pkg/domain/entities"
    18  	"github.com/pkg/errors"
    19  	"github.com/spf13/cobra"
    20  )
    21  
    22  var (
    23  	psDescription = "List all pods on system including their names, ids and current state."
    24  
    25  	// Command: podman pod _ps_
    26  	psCmd = &cobra.Command{
    27  		Use:     "ps",
    28  		Aliases: []string{"ls", "list"},
    29  		Short:   "list pods",
    30  		Long:    psDescription,
    31  		RunE:    pods,
    32  	}
    33  )
    34  
    35  var (
    36  	defaultHeaders string = "POD ID\tNAME\tSTATUS\tCREATED"
    37  	inputFilters   string
    38  	noTrunc        bool
    39  	psInput        entities.PodPSOptions
    40  )
    41  
    42  func init() {
    43  	registry.Commands = append(registry.Commands, registry.CliCommand{
    44  		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
    45  		Command: psCmd,
    46  		Parent:  podCmd,
    47  	})
    48  	flags := psCmd.Flags()
    49  	flags.BoolVar(&psInput.CtrNames, "ctr-names", false, "Display the container names")
    50  	flags.BoolVar(&psInput.CtrIds, "ctr-ids", false, "Display the container UUIDs. If no-trunc is not set they will be truncated")
    51  	flags.BoolVar(&psInput.CtrStatus, "ctr-status", false, "Display the container status")
    52  	// TODO should we make this a [] ?
    53  	flags.StringVarP(&inputFilters, "filter", "f", "", "Filter output based on conditions given")
    54  	flags.StringVar(&psInput.Format, "format", "", "Pretty-print pods to JSON or using a Go template")
    55  	flags.BoolVarP(&psInput.Latest, "latest", "l", false, "Act on the latest pod podman is aware of")
    56  	flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod")
    57  	flags.BoolVar(&psInput.Namespace, "ns", false, "Display namespace information of the pod")
    58  	flags.BoolVar(&noTrunc, "no-trunc", false, "Do not truncate pod and container IDs")
    59  	flags.BoolVarP(&psInput.Quiet, "quiet", "q", false, "Print the numeric IDs of the pods only")
    60  	flags.StringVar(&psInput.Sort, "sort", "created", "Sort output by created, id, name, or number")
    61  	if registry.IsRemote() {
    62  		_ = flags.MarkHidden("latest")
    63  	}
    64  }
    65  
    66  func pods(cmd *cobra.Command, args []string) error {
    67  	var (
    68  		w   io.Writer = os.Stdout
    69  		row string
    70  		lpr []ListPodReporter
    71  	)
    72  	if cmd.Flag("filter").Changed {
    73  		for _, f := range strings.Split(inputFilters, ",") {
    74  			split := strings.Split(f, "=")
    75  			if len(split) < 2 {
    76  				return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
    77  			}
    78  			psInput.Filters[split[0]] = append(psInput.Filters[split[0]], split[1])
    79  		}
    80  	}
    81  	responses, err := registry.ContainerEngine().PodPs(context.Background(), psInput)
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	if psInput.Format == "json" {
    87  		b, err := json.MarshalIndent(responses, "", "  ")
    88  		if err != nil {
    89  			return err
    90  		}
    91  		fmt.Println(string(b))
    92  		return nil
    93  	}
    94  
    95  	for _, r := range responses {
    96  		lpr = append(lpr, ListPodReporter{r})
    97  	}
    98  	headers, row := createPodPsOut()
    99  	if psInput.Quiet {
   100  		if noTrunc {
   101  			row = "{{.Id}}\n"
   102  		} else {
   103  			row = "{{slice .Id 0 12}}\n"
   104  		}
   105  	}
   106  	if cmd.Flag("format").Changed {
   107  		row = psInput.Format
   108  		if !strings.HasPrefix(row, "\n") {
   109  			row += "\n"
   110  		}
   111  	}
   112  	format := "{{range . }}" + row + "{{end}}"
   113  	if !psInput.Quiet && !cmd.Flag("format").Changed {
   114  		format = headers + format
   115  	}
   116  	tmpl, err := template.New("listPods").Parse(format)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	if !psInput.Quiet {
   121  		w = tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
   122  	}
   123  	if err := tmpl.Execute(w, lpr); err != nil {
   124  		return err
   125  	}
   126  	if flusher, ok := w.(interface{ Flush() error }); ok {
   127  		return flusher.Flush()
   128  	}
   129  	return nil
   130  }
   131  
   132  func createPodPsOut() (string, string) {
   133  	var row string
   134  	headers := defaultHeaders
   135  	if noTrunc {
   136  		row += "{{.Id}}"
   137  	} else {
   138  		row += "{{slice .Id 0 12}}"
   139  	}
   140  
   141  	row += "\t{{.Name}}\t{{.Status}}\t{{.Created}}"
   142  
   143  	if psInput.CtrIds {
   144  		headers += "\tIDS"
   145  		row += "\t{{.ContainerIds}}"
   146  	}
   147  	if psInput.CtrNames {
   148  		headers += "\tNAMES"
   149  		row += "\t{{.ContainerNames}}"
   150  	}
   151  	if psInput.CtrStatus {
   152  		headers += "\tSTATUS"
   153  		row += "\t{{.ContainerStatuses}}"
   154  	}
   155  	if psInput.Namespace {
   156  		headers += "\tCGROUP\tNAMESPACES"
   157  		row += "\t{{.Cgroup}}\t{{.Namespace}}"
   158  	}
   159  	if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
   160  		headers += "\t# OF CONTAINERS"
   161  		row += "\t{{.NumberOfContainers}}"
   162  
   163  	}
   164  	headers += "\tINFRA ID\n"
   165  	if noTrunc {
   166  		row += "\t{{.InfraId}}\n"
   167  	} else {
   168  		row += "\t{{slice .InfraId 0 12}}\n"
   169  	}
   170  	return headers, row
   171  }
   172  
   173  // ListPodReporter is a struct for pod ps output
   174  type ListPodReporter struct {
   175  	*entities.ListPodsReport
   176  }
   177  
   178  // Created returns a human readable created time/date
   179  func (l ListPodReporter) Created() string {
   180  	return units.HumanDuration(time.Since(l.ListPodsReport.Created)) + " ago"
   181  }
   182  
   183  // NumberofContainers returns an int representation for
   184  // the number of containers belonging to the pod
   185  func (l ListPodReporter) NumberOfContainers() int {
   186  	return len(l.Containers)
   187  }
   188  
   189  // Added for backwards compatibility with podmanv1
   190  func (l ListPodReporter) InfraID() string {
   191  	return l.InfraId()
   192  }
   193  
   194  // InfraId returns the infra container id for the pod
   195  // depending on trunc
   196  func (l ListPodReporter) InfraId() string {
   197  	if noTrunc {
   198  		return l.ListPodsReport.InfraId
   199  	}
   200  	return l.ListPodsReport.InfraId[0:12]
   201  }
   202  
   203  func (l ListPodReporter) ContainerIds() string {
   204  	var ctrids []string
   205  	for _, c := range l.Containers {
   206  		id := c.Id
   207  		if !noTrunc {
   208  			id = id[0:12]
   209  		}
   210  		ctrids = append(ctrids, id)
   211  	}
   212  	return strings.Join(ctrids, ",")
   213  }
   214  
   215  func (l ListPodReporter) ContainerNames() string {
   216  	var ctrNames []string
   217  	for _, c := range l.Containers {
   218  		ctrNames = append(ctrNames, c.Names)
   219  	}
   220  	return strings.Join(ctrNames, ",")
   221  }
   222  
   223  func (l ListPodReporter) ContainerStatuses() string {
   224  	var statuses []string
   225  	for _, c := range l.Containers {
   226  		statuses = append(statuses, c.Status)
   227  	}
   228  	return strings.Join(statuses, ",")
   229  }