mirror of https://github.com/containers/podman.git
Merge pull request #14083 from baude/machinestats
Additional stats for podman info
This commit is contained in:
commit
e5a8b0ca5c
|
@ -39,6 +39,10 @@ host:
|
|||
package: conmon-2.0.29-2.fc34.x86_64
|
||||
path: /usr/bin/conmon
|
||||
version: 'conmon version 2.0.29, commit: '
|
||||
cpu_utilization:
|
||||
idle_percent: 96.84
|
||||
system_percent: 0.71
|
||||
user_percent: 2.45
|
||||
cpus: 8
|
||||
distribution:
|
||||
distribution: fedora
|
||||
|
@ -124,6 +128,8 @@ store:
|
|||
graphDriverName: overlay
|
||||
graphOptions: {}
|
||||
graphRoot: /home/dwalsh/.local/share/containers/storage
|
||||
graphRootAllocated: 510389125120
|
||||
graphRootUsed: 129170714624
|
||||
graphStatus:
|
||||
Backing Filesystem: extfs
|
||||
Native Overlay Diff: "true"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package define
|
||||
|
||||
import "github.com/containers/storage/pkg/idtools"
|
||||
import (
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
)
|
||||
|
||||
// Info is the overall struct that describes the host system
|
||||
// running libpod/podman
|
||||
|
@ -31,6 +33,7 @@ type HostInfo struct {
|
|||
CgroupControllers []string `json:"cgroupControllers"`
|
||||
Conmon *ConmonInfo `json:"conmon"`
|
||||
CPUs int `json:"cpus"`
|
||||
CPUUtilization *CPUUsage `json:"cpuUtilization"`
|
||||
Distribution DistributionInfo `json:"distribution"`
|
||||
EventLogger string `json:"eventLogger"`
|
||||
Hostname string `json:"hostname"`
|
||||
|
@ -108,11 +111,15 @@ type StoreInfo struct {
|
|||
GraphDriverName string `json:"graphDriverName"`
|
||||
GraphOptions map[string]interface{} `json:"graphOptions"`
|
||||
GraphRoot string `json:"graphRoot"`
|
||||
GraphStatus map[string]string `json:"graphStatus"`
|
||||
ImageCopyTmpDir string `json:"imageCopyTmpDir"`
|
||||
ImageStore ImageStore `json:"imageStore"`
|
||||
RunRoot string `json:"runRoot"`
|
||||
VolumePath string `json:"volumePath"`
|
||||
// GraphRootAllocated is how much space the graphroot has in bytes
|
||||
GraphRootAllocated uint64 `json:"graphRootAllocated"`
|
||||
// GraphRootUsed is how much of graphroot is used in bytes
|
||||
GraphRootUsed uint64 `json:"graphRootUsed"`
|
||||
GraphStatus map[string]string `json:"graphStatus"`
|
||||
ImageCopyTmpDir string `json:"imageCopyTmpDir"`
|
||||
ImageStore ImageStore `json:"imageStore"`
|
||||
RunRoot string `json:"runRoot"`
|
||||
VolumePath string `json:"volumePath"`
|
||||
}
|
||||
|
||||
// ImageStore describes the image store. Right now only the number
|
||||
|
@ -137,3 +144,9 @@ type Plugins struct {
|
|||
// FIXME what should we do with Authorization, docker seems to return nothing by default
|
||||
// Authorization []string `json:"authorization"`
|
||||
}
|
||||
|
||||
type CPUUsage struct {
|
||||
UserPercent float64 `json:"userPercent"`
|
||||
SystemPercent float64 `json:"systemPercent"`
|
||||
IdlePercent float64 `json:"idlePercent"`
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containers/buildah"
|
||||
|
@ -115,7 +117,10 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
|
|||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error getting available cgroup controllers")
|
||||
}
|
||||
|
||||
cpuUtil, err := getCPUUtilization()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info := define.HostInfo{
|
||||
Arch: runtime.GOARCH,
|
||||
BuildahVersion: buildah.Version,
|
||||
|
@ -123,6 +128,7 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
|
|||
CgroupControllers: availableControllers,
|
||||
Linkmode: linkmode.Linkmode(),
|
||||
CPUs: runtime.NumCPU(),
|
||||
CPUUtilization: cpuUtil,
|
||||
Distribution: hostDistributionInfo,
|
||||
LogDriver: r.config.Containers.LogDriver,
|
||||
EventLogger: r.eventer.String(),
|
||||
|
@ -285,17 +291,25 @@ func (r *Runtime) storeInfo() (*define.StoreInfo, error) {
|
|||
}
|
||||
imageInfo := define.ImageStore{Number: len(images)}
|
||||
|
||||
info := define.StoreInfo{
|
||||
ImageStore: imageInfo,
|
||||
ImageCopyTmpDir: os.Getenv("TMPDIR"),
|
||||
ContainerStore: conInfo,
|
||||
GraphRoot: r.store.GraphRoot(),
|
||||
RunRoot: r.store.RunRoot(),
|
||||
GraphDriverName: r.store.GraphDriverName(),
|
||||
GraphOptions: nil,
|
||||
VolumePath: r.config.Engine.VolumePath,
|
||||
ConfigFile: configFile,
|
||||
var grStats syscall.Statfs_t
|
||||
if err := syscall.Statfs(r.store.GraphRoot(), &grStats); err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to collect graph root usasge for %q", r.store.GraphRoot())
|
||||
}
|
||||
allocated := uint64(grStats.Bsize) * grStats.Blocks
|
||||
info := define.StoreInfo{
|
||||
ImageStore: imageInfo,
|
||||
ImageCopyTmpDir: os.Getenv("TMPDIR"),
|
||||
ContainerStore: conInfo,
|
||||
GraphRoot: r.store.GraphRoot(),
|
||||
GraphRootAllocated: allocated,
|
||||
GraphRootUsed: allocated - (uint64(grStats.Bsize) * grStats.Bfree),
|
||||
RunRoot: r.store.RunRoot(),
|
||||
GraphDriverName: r.store.GraphDriverName(),
|
||||
GraphOptions: nil,
|
||||
VolumePath: r.config.Engine.VolumePath,
|
||||
ConfigFile: configFile,
|
||||
}
|
||||
|
||||
graphOptions := map[string]interface{}{}
|
||||
for _, o := range r.store.GraphOptions() {
|
||||
split := strings.SplitN(o, "=", 2)
|
||||
|
@ -382,3 +396,44 @@ func (r *Runtime) GetHostDistributionInfo() define.DistributionInfo {
|
|||
}
|
||||
return dist
|
||||
}
|
||||
|
||||
// getCPUUtilization Returns a CPUUsage object that summarizes CPU
|
||||
// usage for userspace, system, and idle time.
|
||||
func getCPUUtilization() (*define.CPUUsage, error) {
|
||||
f, err := os.Open("/proc/stat")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
// Read firt line of /proc/stat
|
||||
for scanner.Scan() {
|
||||
break
|
||||
}
|
||||
// column 1 is user, column 3 is system, column 4 is idle
|
||||
stats := strings.Split(scanner.Text(), " ")
|
||||
return statToPercent(stats)
|
||||
}
|
||||
|
||||
func statToPercent(stats []string) (*define.CPUUsage, error) {
|
||||
// There is always an extra space between cpu and the first metric
|
||||
userTotal, err := strconv.ParseFloat(stats[2], 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to parse user value %q", stats[1])
|
||||
}
|
||||
systemTotal, err := strconv.ParseFloat(stats[4], 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to parse system value %q", stats[3])
|
||||
}
|
||||
idleTotal, err := strconv.ParseFloat(stats[5], 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to parse idle value %q", stats[4])
|
||||
}
|
||||
total := userTotal + systemTotal + idleTotal
|
||||
s := define.CPUUsage{
|
||||
UserPercent: math.Round((userTotal/total*100)*100) / 100,
|
||||
SystemPercent: math.Round((systemTotal/total*100)*100) / 100,
|
||||
IdlePercent: math.Round((idleTotal/total*100)*100) / 100,
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package libpod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/podman/v4/libpod/define"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_statToPercent(t *testing.T) {
|
||||
type args struct {
|
||||
in0 []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *define.CPUUsage
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "GoodParse",
|
||||
args: args{in0: []string{"cpu", " ", "33628064", "27537", "9696996", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}},
|
||||
want: &define.CPUUsage{
|
||||
UserPercent: 2.48,
|
||||
SystemPercent: 0.71,
|
||||
IdlePercent: 96.81,
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "BadUserValue",
|
||||
args: args{in0: []string{"cpu", " ", "k", "27537", "9696996", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}},
|
||||
want: nil,
|
||||
wantErr: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "BadSystemValue",
|
||||
args: args{in0: []string{"cpu", " ", "33628064", "27537", "k", "1314806705", "588142", "4775073", "2789228", "0", "598711", "0"}},
|
||||
want: nil,
|
||||
wantErr: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "BadIdleValue",
|
||||
args: args{in0: []string{"cpu", " ", "33628064", "27537", "9696996", "k", "588142", "4775073", "2789228", "0", "598711", "0"}},
|
||||
want: nil,
|
||||
wantErr: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := statToPercent(tt.args.in0)
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("statToPercent(%v)", tt.args.in0)) {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t, tt.want, got, "statToPercent(%v)", tt.args.in0)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue