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 }