Files
podman/pkg/domain/infra/abi/pods_stats.go
Matt Souza 090304a054 lint: reenable revive unused-parameter check
Signed-off-by: Matt Souza <medsouz99@gmail.com>
2025-10-01 10:42:08 -04:00

104 lines
3.0 KiB
Go

//go:build !remote
package abi
import (
"context"
"errors"
"fmt"
"strconv"
"github.com/containers/podman/v5/libpod"
"github.com/containers/podman/v5/libpod/define"
"github.com/containers/podman/v5/pkg/domain/entities"
"github.com/containers/podman/v5/pkg/rootless"
"github.com/docker/go-units"
"go.podman.io/common/pkg/cgroups"
)
// PodStats implements printing stats about pods.
func (ic *ContainerEngine) PodStats(_ context.Context, namesOrIds []string, options entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
// Cgroups v2 check for rootless.
if rootless.IsRootless() {
unified, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
return nil, err
}
if !unified {
return nil, errors.New("pod stats is not supported in rootless mode without cgroups v2")
}
}
// Get the (running) pods and convert them to the entities format.
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, fmt.Errorf("unable to get list of pods: %w", err)
}
return ic.podsToStatsReport(pods)
}
// podsToStatsReport converts a slice of pods into a corresponding slice of stats reports.
func (ic *ContainerEngine) podsToStatsReport(pods []*libpod.Pod) ([]*entities.PodStatsReport, error) {
reports := []*entities.PodStatsReport{}
for i := range pods { // Access by index to prevent potential loop-variable leaks.
podStats, err := pods[i].GetPodStats()
if err != nil {
// pod was removed, skip it
if errors.Is(err, define.ErrNoSuchPod) {
continue
}
return nil, err
}
podID := pods[i].ID()[:12]
for j := range podStats {
var podNetInput uint64
var podNetOutput uint64
for _, stats := range podStats[j].Network {
podNetInput += stats.RxBytes
podNetOutput += stats.TxBytes
}
r := entities.PodStatsReport{
CPU: floatToPercentString(podStats[j].CPU),
MemUsage: combineHumanValues(podStats[j].MemUsage, podStats[j].MemLimit),
MemUsageBytes: combineBytesValues(podStats[j].MemUsage, podStats[j].MemLimit),
Mem: floatToPercentString(podStats[j].MemPerc),
NetIO: combineHumanValues(podNetInput, podNetOutput),
BlockIO: combineHumanValues(podStats[j].BlockInput, podStats[j].BlockOutput),
PIDS: pidsToString(podStats[j].PIDs),
CID: podStats[j].ContainerID[:12],
Name: podStats[j].Name,
Pod: podID,
}
reports = append(reports, &r)
}
}
return reports, nil
}
func combineHumanValues(a, b uint64) string {
if a == 0 && b == 0 {
return "-- / --"
}
return fmt.Sprintf("%s / %s", units.HumanSize(float64(a)), units.HumanSize(float64(b)))
}
func combineBytesValues(a, b uint64) string {
if a == 0 && b == 0 {
return "-- / --"
}
return fmt.Sprintf("%s / %s", units.BytesSize(float64(a)), units.BytesSize(float64(b)))
}
func floatToPercentString(f float64) string {
return fmt.Sprintf("%.2f%%", f)
}
func pidsToString(pid uint64) string {
if pid == 0 {
// If things go bazinga, return a safe value
return "--"
}
return strconv.FormatUint(pid, 10)
}