summaryrefslogtreecommitdiff
path: root/cmd/podman/stats.go
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2020-04-16 12:25:26 -0500
committerBrent Baude <bbaude@redhat.com>2020-04-16 15:53:58 -0500
commit241326a9a8c20ad7f2bcf651416b836e7778e090 (patch)
tree4001e8e47a022bb1b9bfbf2332c42e1aeb802f9e /cmd/podman/stats.go
parent88c6fd06cd54fb9a8826306dfdf1a77e400de5de (diff)
downloadpodman-241326a9a8c20ad7f2bcf651416b836e7778e090.tar.gz
podman-241326a9a8c20ad7f2bcf651416b836e7778e090.tar.bz2
podman-241326a9a8c20ad7f2bcf651416b836e7778e090.zip
Podman V2 birth
remote podman v1 and replace with podman v2. Signed-off-by: Brent Baude <bbaude@redhat.com>
Diffstat (limited to 'cmd/podman/stats.go')
-rw-r--r--cmd/podman/stats.go305
1 files changed, 0 insertions, 305 deletions
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
deleted file mode 100644
index 08fddc47a..000000000
--- a/cmd/podman/stats.go
+++ /dev/null
@@ -1,305 +0,0 @@
-package main
-
-import (
- "fmt"
- "reflect"
- "strings"
- "time"
-
- tm "github.com/buger/goterm"
- "github.com/containers/buildah/pkg/formats"
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/define"
- "github.com/containers/libpod/pkg/cgroups"
- "github.com/containers/libpod/pkg/rootless"
- "github.com/docker/go-units"
- "github.com/pkg/errors"
- "github.com/spf13/cobra"
-)
-
-type statsOutputParams struct {
- ID string `json:"id"`
- Name string `json:"name"`
- CPUPerc string `json:"cpu_percent"`
- MemUsage string `json:"mem_usage"`
- MemPerc string `json:"mem_percent"`
- NetIO string `json:"netio"`
- BlockIO string `json:"blocki"`
- PIDS string `json:"pids"`
-}
-
-var (
- statsCommand cliconfig.StatsValues
-
- statsDescription = "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers."
- _statsCommand = &cobra.Command{
- Use: "stats [flags] [CONTAINER...]",
- Short: "Display a live stream of container resource usage statistics",
- Long: statsDescription,
- RunE: func(cmd *cobra.Command, args []string) error {
- statsCommand.InputArgs = args
- statsCommand.GlobalFlags = MainGlobalOpts
- statsCommand.Remote = remoteclient
- return statsCmd(&statsCommand)
- },
- Example: `podman stats --all --no-stream
- podman stats ctrID
- podman stats --no-stream --format "table {{.ID}} {{.Name}} {{.MemUsage}}" ctrID`,
- }
-)
-
-func init() {
- statsCommand.Command = _statsCommand
- statsCommand.SetHelpTemplate(HelpTemplate())
- statsCommand.SetUsageTemplate(UsageTemplate())
- flags := statsCommand.Flags()
- flags.BoolVarP(&statsCommand.All, "all", "a", false, "Show all containers. Only running containers are shown by default. The default is false")
- flags.StringVar(&statsCommand.Format, "format", "", "Pretty-print container statistics to JSON or using a Go template")
- flags.BoolVarP(&statsCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- flags.BoolVar(&statsCommand.NoReset, "no-reset", false, "Disable resetting the screen between intervals")
- flags.BoolVar(&statsCommand.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false")
- markFlagHiddenForRemoteClient("latest", flags)
-}
-
-func statsCmd(c *cliconfig.StatsValues) error {
- if rootless.IsRootless() {
- unified, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return err
- }
- if !unified {
- return errors.New("stats is not supported in rootless mode without cgroups v2")
- }
- }
-
- all := c.All
- latest := c.Latest
- ctr := 0
- if all {
- ctr += 1
- }
- if latest {
- ctr += 1
- }
- if len(c.InputArgs) > 0 {
- ctr += 1
- }
-
- if ctr > 1 {
- return errors.Errorf("--all, --latest and containers cannot be used together")
- }
-
- runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.DeferredShutdown(false)
-
- times := -1
- if c.NoStream {
- times = 1
- }
-
- var ctrs []*libpod.Container
-
- containerFunc := runtime.GetRunningContainers
- switch {
- case len(c.InputArgs) > 0:
- containerFunc = func() ([]*libpod.Container, error) { return runtime.GetContainersByList(c.InputArgs) }
- case latest:
- containerFunc = func() ([]*libpod.Container, error) {
- lastCtr, err := runtime.GetLatestContainer()
- if err != nil {
- return nil, err
- }
- return []*libpod.Container{lastCtr}, nil
- }
- case all:
- containerFunc = runtime.GetAllContainers
- }
-
- ctrs, err = containerFunc()
- if err != nil {
- return errors.Wrapf(err, "unable to get list of containers")
- }
-
- containerStats := map[string]*libpod.ContainerStats{}
- for _, ctr := range ctrs {
- initialStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
- if err != nil {
- // when doing "all", don't worry about containers that are not running
- cause := errors.Cause(err)
- if c.All && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
- continue
- }
- if cause == cgroups.ErrCgroupV1Rootless {
- err = cause
- }
- return err
- }
- containerStats[ctr.ID()] = initialStats
- }
-
- format := genStatsFormat(c.Format)
-
- step := 1
- if times == -1 {
- times = 1
- step = 0
- }
- for i := 0; i < times; i += step {
- reportStats := []*libpod.ContainerStats{}
- for _, ctr := range ctrs {
- id := ctr.ID()
- if _, ok := containerStats[ctr.ID()]; !ok {
- initialStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
- if errors.Cause(err) == define.ErrCtrRemoved || errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrStateInvalid {
- // skip dealing with a container that is gone
- continue
- }
- if err != nil {
- return err
- }
- containerStats[id] = initialStats
- }
- stats, err := ctr.GetContainerStats(containerStats[id])
- if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
- return err
- }
- // replace the previous measurement with the current one
- containerStats[id] = stats
- reportStats = append(reportStats, stats)
- }
- ctrs, err = containerFunc()
- if err != nil {
- return err
- }
- if strings.ToLower(format) != formats.JSONString && !c.NoReset {
- tm.Clear()
- tm.MoveCursor(1, 1)
- tm.Flush()
- }
- if err := outputStats(reportStats, format); err != nil {
- return err
- }
- time.Sleep(time.Second)
- }
- return nil
-}
-
-func outputStats(stats []*libpod.ContainerStats, format string) error {
- var out formats.Writer
- var outputStats []statsOutputParams
- for _, s := range stats {
- outputStats = append(outputStats, getStatsOutputParams(s))
- }
- if strings.ToLower(format) == formats.JSONString {
- out = formats.JSONStructArray{Output: statsToGeneric(outputStats, []statsOutputParams{})}
- } else {
- var mapOfHeaders map[string]string
- if len(outputStats) == 0 {
- params := getStatsOutputParamsEmpty()
- mapOfHeaders = params.headerMap()
- } else {
- mapOfHeaders = outputStats[0].headerMap()
- }
- out = formats.StdoutTemplateArray{Output: statsToGeneric(outputStats, []statsOutputParams{}), Template: format, Fields: mapOfHeaders}
- }
- return out.Out()
-}
-
-func genStatsFormat(format string) string {
- if format != "" {
- // "\t" from the command line is not being recognized as a tab
- // replacing the string "\t" to a tab character if the user passes in "\t"
- return strings.Replace(format, `\t`, "\t", -1)
- }
- return "table {{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDS}}"
-}
-
-// imagesToGeneric creates an empty array of interfaces for output
-func statsToGeneric(templParams []statsOutputParams, jsonParams []statsOutputParams) (genericParams []interface{}) {
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
- }
- for _, v := range jsonParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the header based on the template provided
-func (i *statsOutputParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(i))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- switch value {
- case "CPUPerc":
- value = "CPU%"
- case "MemUsage":
- value = "MemUsage/Limit"
- case "MemPerc":
- value = "Mem%"
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-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 floatToPercentString(f float64) string {
- strippedFloat, err := libpod.RemoveScientificNotationFromFloat(f)
- if err != nil || strippedFloat == 0 {
- // If things go bazinga, return a safe value
- return "--"
- }
- return fmt.Sprintf("%.2f", strippedFloat) + "%"
-}
-
-func pidsToString(pid uint64) string {
- if pid == 0 {
- // If things go bazinga, return a safe value
- return "--"
- }
- return fmt.Sprintf("%d", pid)
-}
-
-func getStatsOutputParams(stats *libpod.ContainerStats) statsOutputParams {
- return statsOutputParams{
- Name: stats.Name,
- ID: shortID(stats.ContainerID),
- CPUPerc: floatToPercentString(stats.CPU),
- MemUsage: combineHumanValues(stats.MemUsage, stats.MemLimit),
- MemPerc: floatToPercentString(stats.MemPerc),
- NetIO: combineHumanValues(stats.NetInput, stats.NetOutput),
- BlockIO: combineHumanValues(stats.BlockInput, stats.BlockOutput),
- PIDS: pidsToString(stats.PIDs),
- }
-}
-
-func getStatsOutputParamsEmpty() statsOutputParams {
- return statsOutputParams{
- Name: "",
- ID: "",
- CPUPerc: "",
- MemUsage: "",
- MemPerc: "",
- NetIO: "",
- BlockIO: "",
- PIDS: "",
- }
-}