github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/domain/infra/abi/pods_stats.go (about) 1 package abi 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/containers/common/pkg/cgroups" 8 "github.com/hanks177/podman/v4/libpod" 9 "github.com/hanks177/podman/v4/pkg/domain/entities" 10 "github.com/hanks177/podman/v4/pkg/rootless" 11 "github.com/hanks177/podman/v4/utils" 12 "github.com/docker/go-units" 13 "github.com/pkg/errors" 14 ) 15 16 // PodStats implements printing stats about pods. 17 func (ic *ContainerEngine) PodStats(ctx context.Context, namesOrIds []string, options entities.PodStatsOptions) ([]*entities.PodStatsReport, error) { 18 // Cgroups v2 check for rootless. 19 if rootless.IsRootless() { 20 unified, err := cgroups.IsCgroup2UnifiedMode() 21 if err != nil { 22 return nil, err 23 } 24 if !unified { 25 return nil, errors.New("pod stats is not supported in rootless mode without cgroups v2") 26 } 27 } 28 // Get the (running) pods and convert them to the entities format. 29 pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod) 30 if err != nil { 31 return nil, errors.Wrap(err, "unable to get list of pods") 32 } 33 return ic.podsToStatsReport(pods) 34 } 35 36 // podsToStatsReport converts a slice of pods into a corresponding slice of stats reports. 37 func (ic *ContainerEngine) podsToStatsReport(pods []*libpod.Pod) ([]*entities.PodStatsReport, error) { 38 reports := []*entities.PodStatsReport{} 39 for i := range pods { // Access by index to prevent potential loop-variable leaks. 40 podStats, err := pods[i].GetPodStats(nil) 41 if err != nil { 42 return nil, err 43 } 44 podID := pods[i].ID()[:12] 45 for j := range podStats { 46 r := entities.PodStatsReport{ 47 CPU: floatToPercentString(podStats[j].CPU), 48 MemUsage: combineHumanValues(podStats[j].MemUsage, podStats[j].MemLimit), 49 MemUsageBytes: combineBytesValues(podStats[j].MemUsage, podStats[j].MemLimit), 50 Mem: floatToPercentString(podStats[j].MemPerc), 51 NetIO: combineHumanValues(podStats[j].NetInput, podStats[j].NetOutput), 52 BlockIO: combineHumanValues(podStats[j].BlockInput, podStats[j].BlockOutput), 53 PIDS: pidsToString(podStats[j].PIDs), 54 CID: podStats[j].ContainerID[:12], 55 Name: podStats[j].Name, 56 Pod: podID, 57 } 58 reports = append(reports, &r) 59 } 60 } 61 62 return reports, nil 63 } 64 65 func combineHumanValues(a, b uint64) string { 66 if a == 0 && b == 0 { 67 return "-- / --" 68 } 69 return fmt.Sprintf("%s / %s", units.HumanSize(float64(a)), units.HumanSize(float64(b))) 70 } 71 72 func combineBytesValues(a, b uint64) string { 73 if a == 0 && b == 0 { 74 return "-- / --" 75 } 76 return fmt.Sprintf("%s / %s", units.BytesSize(float64(a)), units.BytesSize(float64(b))) 77 } 78 79 func floatToPercentString(f float64) string { 80 strippedFloat, err := utils.RemoveScientificNotationFromFloat(f) 81 if err != nil || strippedFloat == 0 { 82 // If things go bazinga, return a safe value 83 return "--" 84 } 85 return fmt.Sprintf("%.2f", strippedFloat) + "%" 86 } 87 88 func pidsToString(pid uint64) string { 89 if pid == 0 { 90 // If things go bazinga, return a safe value 91 return "--" 92 } 93 return fmt.Sprintf("%d", pid) 94 }