add kpod stats function
Signed-off-by: Ryan Cole <rcyoalne@gmail.com>
This commit is contained in:
parent
dda5511a2b
commit
ceeed6c32e
92 changed files with 34227 additions and 218 deletions
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/kubernetes-incubator/cri-o/pkg/annotations"
|
||||
"github.com/kubernetes-incubator/cri-o/pkg/registrar"
|
||||
"github.com/kubernetes-incubator/cri-o/pkg/storage"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -195,6 +196,12 @@ func (c *ContainerServer) Update() error {
|
|||
if _, ok := oldPodContainers[id]; !ok {
|
||||
// this container's ID wasn't in the updated list -> removed
|
||||
removedPodContainers[id] = id
|
||||
} else {
|
||||
ctr := c.GetContainer(id)
|
||||
if ctr != nil {
|
||||
// if the container exists, update its state
|
||||
c.ContainerStateFromDisk(c.GetContainer(id))
|
||||
}
|
||||
}
|
||||
})
|
||||
for removedPodContainer := range removedPodContainers {
|
||||
|
@ -583,13 +590,31 @@ func (c *ContainerServer) RemoveContainer(ctr *oci.Container) {
|
|||
c.state.containers.Delete(ctr.ID())
|
||||
}
|
||||
|
||||
// ListContainers returns a list of all containers stored by the server state
|
||||
func (c *ContainerServer) ListContainers() []*oci.Container {
|
||||
// listContainers returns a list of all containers stored by the server state
|
||||
func (c *ContainerServer) listContainers() []*oci.Container {
|
||||
c.stateLock.Lock()
|
||||
defer c.stateLock.Unlock()
|
||||
return c.state.containers.List()
|
||||
}
|
||||
|
||||
// ListContainers returns a list of all containers stored by the server state
|
||||
// that match the given filter function
|
||||
func (c *ContainerServer) ListContainers(filters ...func(*oci.Container) bool) ([]*oci.Container, error) {
|
||||
containers := c.listContainers()
|
||||
if len(filters) == 0 {
|
||||
return containers, nil
|
||||
}
|
||||
filteredContainers := make([]*oci.Container, 0, len(containers))
|
||||
for _, container := range containers {
|
||||
for _, filter := range filters {
|
||||
if filter(container) {
|
||||
filteredContainers = append(filteredContainers, container)
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredContainers, nil
|
||||
}
|
||||
|
||||
// AddSandbox adds a sandbox to the sandbox state store
|
||||
func (c *ContainerServer) AddSandbox(sb *sandbox.Sandbox) {
|
||||
c.stateLock.Lock()
|
||||
|
@ -641,3 +666,20 @@ func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
|
|||
|
||||
return sbArray
|
||||
}
|
||||
|
||||
// LibcontainerStats gets the stats for the container with the given id from runc/libcontainer
|
||||
func (c *ContainerServer) LibcontainerStats(ctr *oci.Container) (*libcontainer.Stats, error) {
|
||||
// TODO: make this not hardcoded
|
||||
// was: c.runtime.Path(ociContainer) but that returns /usr/bin/runc - how do we get /run/runc?
|
||||
// runroot is /var/run/runc
|
||||
// Hardcoding probably breaks ClearContainers compatibility
|
||||
factory, err := loadFactory("/run/runc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
container, err := factory.Load(ctr.ID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return container.Stats()
|
||||
}
|
||||
|
|
|
@ -161,16 +161,15 @@ func MatchesReference(name, argName string) bool {
|
|||
}
|
||||
|
||||
// FormattedSize returns a human-readable formatted size for the image
|
||||
func FormattedSize(size int64) string {
|
||||
func FormattedSize(size float64) string {
|
||||
suffixes := [5]string{"B", "KB", "MB", "GB", "TB"}
|
||||
|
||||
count := 0
|
||||
formattedSize := float64(size)
|
||||
for formattedSize >= 1024 && count < 4 {
|
||||
formattedSize /= 1024
|
||||
for size >= 1024 && count < 4 {
|
||||
size /= 1024
|
||||
count++
|
||||
}
|
||||
return fmt.Sprintf("%.4g %s", formattedSize, suffixes[count])
|
||||
return fmt.Sprintf("%.4g %s", size, suffixes[count])
|
||||
}
|
||||
|
||||
// FindImage searches for a *storage.Image with a matching the given name or ID in the given store.
|
||||
|
|
111
libkpod/stats.go
Normal file
111
libkpod/stats.go
Normal file
|
@ -0,0 +1,111 @@
|
|||
package libkpod
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/oci"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
)
|
||||
|
||||
// ContainerStats contains the statistics information for a running container
|
||||
type ContainerStats struct {
|
||||
Container string
|
||||
CPU float64
|
||||
cpuNano uint64
|
||||
systemNano uint64
|
||||
MemUsage uint64
|
||||
MemLimit uint64
|
||||
MemPerc float64
|
||||
NetInput uint64
|
||||
NetOutput uint64
|
||||
BlockInput uint64
|
||||
BlockOutput uint64
|
||||
PIDs uint64
|
||||
}
|
||||
|
||||
// GetContainerStats gets the running stats for a given container
|
||||
func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
|
||||
previousCPU := previousStats.cpuNano
|
||||
previousSystem := previousStats.systemNano
|
||||
libcontainerStats, err := c.LibcontainerStats(ctr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cgroupStats := libcontainerStats.CgroupStats
|
||||
stats := new(ContainerStats)
|
||||
stats.Container = ctr.ID()
|
||||
stats.CPU = calculateCPUPercent(libcontainerStats, previousCPU, previousSystem)
|
||||
stats.MemUsage = cgroupStats.MemoryStats.Usage.Usage
|
||||
stats.MemLimit = getMemLimit(cgroupStats.MemoryStats.Usage.Limit)
|
||||
stats.MemPerc = float64(stats.MemUsage) / float64(stats.MemLimit)
|
||||
stats.PIDs = cgroupStats.PidsStats.Current
|
||||
stats.BlockInput, stats.BlockOutput = calculateBlockIO(libcontainerStats)
|
||||
stats.NetInput, stats.NetOutput = getContainerNetIO(libcontainerStats)
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func loadFactory(root string) (libcontainer.Factory, error) {
|
||||
abs, err := filepath.Abs(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cgroupManager := libcontainer.Cgroupfs
|
||||
return libcontainer.New(abs, cgroupManager, libcontainer.CriuPath(""))
|
||||
}
|
||||
|
||||
// getMemory limit returns the memory limit for a given cgroup
|
||||
// If the configured memory limit is larger than the total memory on the sys, the
|
||||
// physical system memory size is returned
|
||||
func getMemLimit(cgroupLimit uint64) uint64 {
|
||||
si := &syscall.Sysinfo_t{}
|
||||
err := syscall.Sysinfo(si)
|
||||
if err != nil {
|
||||
return cgroupLimit
|
||||
}
|
||||
|
||||
physicalLimit := uint64(si.Totalram)
|
||||
if cgroupLimit > physicalLimit {
|
||||
return physicalLimit
|
||||
}
|
||||
return cgroupLimit
|
||||
}
|
||||
|
||||
// Returns the total number of bytes transmitted and received for the given container stats
|
||||
func getContainerNetIO(stats *libcontainer.Stats) (received uint64, transmitted uint64) {
|
||||
for _, iface := range stats.Interfaces {
|
||||
received += iface.RxBytes
|
||||
transmitted += iface.TxBytes
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func calculateCPUPercent(stats *libcontainer.Stats, previousCPU, previousSystem uint64) float64 {
|
||||
var (
|
||||
cpuPercent = 0.0
|
||||
cpuDelta = float64(stats.CgroupStats.CpuStats.CpuUsage.TotalUsage - previousCPU)
|
||||
systemDelta = float64(uint64(time.Now().UnixNano()) - previousSystem)
|
||||
)
|
||||
if systemDelta > 0.0 && cpuDelta > 0.0 {
|
||||
// gets a ratio of container cpu usage total, multiplies it by the number of cores (4 cores running
|
||||
// at 100% utilization should be 400% utilization), and multiplies that by 100 to get a percentage
|
||||
cpuPercent = (cpuDelta / systemDelta) * float64(len(stats.CgroupStats.CpuStats.CpuUsage.PercpuUsage)) * 100
|
||||
}
|
||||
return cpuPercent
|
||||
}
|
||||
|
||||
func calculateBlockIO(stats *libcontainer.Stats) (read uint64, write uint64) {
|
||||
for _, blkIOEntry := range stats.CgroupStats.BlkioStats.IoServiceBytesRecursive {
|
||||
switch strings.ToLower(blkIOEntry.Op) {
|
||||
case "read":
|
||||
read += blkIOEntry.Value
|
||||
case "write":
|
||||
write += blkIOEntry.Value
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue