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  }