func runList(cmd *cobra.Command, args []string) int { var errors []error tabBuffer := new(bytes.Buffer) tabOut := getTabOutWithWriter(tabBuffer) if !flagNoLegend && flagFormat == outputFormatTabbed { if flagFullOutput { fmt.Fprintf(tabOut, "UUID\tAPP\tIMAGE NAME\tIMAGE ID\tSTATE\tCREATED\tSTARTED\tNETWORKS\n") } else { fmt.Fprintf(tabOut, "UUID\tAPP\tIMAGE NAME\tSTATE\tCREATED\tSTARTED\tNETWORKS\n") } } var pods []*lib.Pod if err := pkgPod.WalkPods(getDataDir(), pkgPod.IncludeMostDirs, func(p *pkgPod.Pod) { if flagFormat != outputFormatTabbed { pod, err := lib.NewPodFromInternalPod(p) if err != nil { errors = append(errors, err) } else { pods = append(pods, pod) } return } var pm schema.PodManifest var err error if p.PodManifestAvailable() { // TODO(vc): we should really hold a shared lock here to prevent gc of the pod _, manifest, err := p.PodManifest() if err != nil { errors = append(errors, newPodListReadError(p, err)) return } pm = *manifest } type printedApp struct { uuid string appName string imgName string imgID string state string nets string created string started string } var appsToPrint []printedApp uuid := p.UUID.String() state := p.State() nets := fmtNets(p.Nets) created, err := p.CreationTime() if err != nil { errors = append(errors, errwrap.Wrap(fmt.Errorf("unable to get creation time for pod %q", uuid), err)) } var createdStr string if flagFullOutput { createdStr = created.Format(defaultTimeLayout) } else { createdStr = humanize.Time(created) } started, err := p.StartTime() if err != nil { errors = append(errors, errwrap.Wrap(fmt.Errorf("unable to get start time for pod %q", uuid), err)) } var startedStr string if !started.IsZero() { if flagFullOutput { startedStr = started.Format(defaultTimeLayout) } else { startedStr = humanize.Time(started) } } if !flagFullOutput { uuid = uuid[:8] } if len(pm.Apps) == 0 { appsToPrint = append(appsToPrint, printedApp{ uuid: uuid, appName: "-", imgName: "-", imgID: "-", state: state, nets: nets, created: createdStr, started: startedStr, }) } for _, app := range pm.Apps { imageName, err := getImageName(p, app.Name) if err != nil { errors = append(errors, newPodListLoadImageManifestError(p, err)) imageName = "--" } var imageID string if flagFullOutput { imageID = app.Image.ID.String()[:19] } appsToPrint = append(appsToPrint, printedApp{ uuid: uuid, appName: app.Name.String(), imgName: imageName, imgID: imageID, state: state, nets: nets, created: createdStr, started: startedStr, }) // clear those variables so they won't be // printed for another apps in the pod as they // are actually describing a pod, not an app uuid = "" state = "" nets = "" createdStr = "" startedStr = "" } // if we reached that point, then it means that the // pod and all its apps are valid, so they can be // printed for _, app := range appsToPrint { if flagFullOutput { fmt.Fprintf(tabOut, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", app.uuid, app.appName, app.imgName, app.imgID, app.state, app.created, app.started, app.nets) } else { fmt.Fprintf(tabOut, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", app.uuid, app.appName, app.imgName, app.state, app.created, app.started, app.nets) } } }); err != nil { stderr.PrintE("failed to get pod handles", err) return 254 } switch flagFormat { case outputFormatTabbed: tabOut.Flush() stdout.Print(tabBuffer) case outputFormatJSON: result, err := json.Marshal(pods) if err != nil { stderr.PrintE("error marshaling the pods", err) return 254 } stdout.Print(string(result)) case outputFormatPrettyJSON: result, err := json.MarshalIndent(pods, "", "\t") if err != nil { stderr.PrintE("error marshaling the pods", err) return 254 } stdout.Print(string(result)) } if len(errors) > 0 { printErrors(errors, "listing pods") } return 0 }
// printStatus prints the pod's pid and per-app status codes func printStatus(p *pkgPod.Pod) error { if flagFormat != outputFormatTabbed { pod, err := lib.NewPodFromInternalPod(p) if err != nil { return fmt.Errorf("error converting pod: %v", err) } switch flagFormat { case outputFormatJSON: result, err := json.Marshal(pod) if err != nil { return fmt.Errorf("error marshaling the pod: %v", err) } stdout.Print(string(result)) case outputFormatPrettyJSON: result, err := json.MarshalIndent(pod, "", "\t") if err != nil { return fmt.Errorf("error marshaling the pod: %v", err) } stdout.Print(string(result)) } return nil } state := p.State() stdout.Printf("state=%s", state) created, err := p.CreationTime() if err != nil { return fmt.Errorf("unable to get creation time for pod %q: %v", p.UUID, err) } createdStr := created.Format(defaultTimeLayout) stdout.Printf("created=%s", createdStr) started, err := p.StartTime() if err != nil { return fmt.Errorf("unable to get start time for pod %q: %v", p.UUID, err) } var startedStr string if !started.IsZero() { startedStr = started.Format(defaultTimeLayout) stdout.Printf("started=%s", startedStr) } if state == pkgPod.Running { stdout.Printf("networks=%s", fmtNets(p.Nets)) } if state == pkgPod.Running || state == pkgPod.Deleting || state == pkgPod.ExitedDeleting || state == pkgPod.Exited || state == pkgPod.ExitedGarbage { var pid int pidCh := make(chan int, 1) // Wait slightly because the pid file might not be written yet when the state changes to 'Running'. go func() { for { pid, err := p.Pid() if err == nil { pidCh <- pid return } time.Sleep(time.Millisecond * 100) } }() select { case pid = <-pidCh: case <-time.After(time.Second): return fmt.Errorf("unable to get PID for pod %q: %v", p.UUID, err) } stdout.Printf("pid=%d\nexited=%t", pid, (state == pkgPod.Exited || state == pkgPod.ExitedGarbage)) if state != pkgPod.Running { stats, err := getExitStatuses(p) if err != nil { return fmt.Errorf("unable to get exit statuses for pod %q: %v", p.UUID, err) } for app, stat := range stats { stdout.Printf("app-%s=%d", app, stat) } } } return nil }