github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/domain/infra/abi/pods_stats.go (about) 1 package abi 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/containers/podman/v2/libpod" 8 "github.com/containers/podman/v2/pkg/cgroups" 9 "github.com/containers/podman/v2/pkg/domain/entities" 10 "github.com/containers/podman/v2/pkg/rootless" 11 "github.com/containers/podman/v2/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 Mem: floatToPercentString(podStats[j].MemPerc), 50 NetIO: combineHumanValues(podStats[j].NetInput, podStats[j].NetOutput), 51 BlockIO: combineHumanValues(podStats[j].BlockInput, podStats[j].BlockOutput), 52 PIDS: pidsToString(podStats[j].PIDs), 53 CID: podStats[j].ContainerID[:12], 54 Name: podStats[j].Name, 55 Pod: podID, 56 } 57 reports = append(reports, &r) 58 } 59 } 60 61 return reports, nil 62 } 63 64 func combineHumanValues(a, b uint64) string { 65 if a == 0 && b == 0 { 66 return "-- / --" 67 } 68 return fmt.Sprintf("%s / %s", units.HumanSize(float64(a)), units.HumanSize(float64(b))) 69 } 70 71 func floatToPercentString(f float64) string { 72 strippedFloat, err := utils.RemoveScientificNotationFromFloat(f) 73 if err != nil || strippedFloat == 0 { 74 // If things go bazinga, return a safe value 75 return "--" 76 } 77 return fmt.Sprintf("%.2f", strippedFloat) + "%" 78 } 79 80 func pidsToString(pid uint64) string { 81 if pid == 0 { 82 // If things go bazinga, return a safe value 83 return "--" 84 } 85 return fmt.Sprintf("%d", pid) 86 }