lib: libcontainer references are linux only
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
cdc468afa8
commit
ef6aa87c75
5 changed files with 126 additions and 107 deletions
|
@ -17,7 +17,6 @@ import (
|
||||||
"github.com/kubernetes-incubator/cri-o/pkg/annotations"
|
"github.com/kubernetes-incubator/cri-o/pkg/annotations"
|
||||||
"github.com/kubernetes-incubator/cri-o/pkg/registrar"
|
"github.com/kubernetes-incubator/cri-o/pkg/registrar"
|
||||||
"github.com/kubernetes-incubator/cri-o/pkg/storage"
|
"github.com/kubernetes-incubator/cri-o/pkg/storage"
|
||||||
"github.com/opencontainers/runc/libcontainer"
|
|
||||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -771,20 +770,3 @@ func (c *ContainerServer) RemoveSandbox(id string) {
|
||||||
func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
|
func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
|
||||||
return c.state.sandboxes.List()
|
return c.state.sandboxes.List()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,11 +3,33 @@
|
||||||
package lib
|
package lib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-o/lib/sandbox"
|
"github.com/kubernetes-incubator/cri-o/lib/sandbox"
|
||||||
|
"github.com/kubernetes-incubator/cri-o/oci"
|
||||||
|
"github.com/opencontainers/runc/libcontainer"
|
||||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ContainerServer) addSandboxPlatform(sb *sandbox.Sandbox) {
|
func (c *ContainerServer) addSandboxPlatform(sb *sandbox.Sandbox) {
|
||||||
c.state.processLevels[selinux.NewContext(sb.ProcessLabel())["level"]]++
|
c.state.processLevels[selinux.NewContext(sb.ProcessLabel())["level"]]++
|
||||||
}
|
}
|
||||||
|
@ -24,3 +46,35 @@ func (c *ContainerServer) removeSandboxPlatform(sb *sandbox.Sandbox) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
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.CPUNano = cgroupStats.CpuStats.CpuUsage.TotalUsage
|
||||||
|
stats.SystemNano = time.Now().UnixNano()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
package lib
|
package lib
|
||||||
|
|
||||||
import "github.com/kubernetes-incubator/cri-o/lib/sandbox"
|
import (
|
||||||
|
"github.com/kubernetes-incubator/cri-o/lib/sandbox"
|
||||||
|
"github.com/kubernetes-incubator/cri-o/oci"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
func (c *ContainerServer) addSandboxPlatform(sb *sandbox.Sandbox) {
|
func (c *ContainerServer) addSandboxPlatform(sb *sandbox.Sandbox) {
|
||||||
// nothin' doin'
|
// nothin' doin'
|
||||||
|
@ -11,3 +15,8 @@ func (c *ContainerServer) addSandboxPlatform(sb *sandbox.Sandbox) {
|
||||||
func (c *ContainerServer) removeSandboxPlatform(sb *sandbox.Sandbox) {
|
func (c *ContainerServer) removeSandboxPlatform(sb *sandbox.Sandbox) {
|
||||||
// nothin' doin'
|
// nothin' doin'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ContainerServer) getContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
|
||||||
|
// nothin' doin'
|
||||||
|
return nil, errors.New("container stats not supported")
|
||||||
|
}
|
||||||
|
|
89
lib/stats.go
89
lib/stats.go
|
@ -1,14 +1,7 @@
|
||||||
package lib
|
package lib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-o/oci"
|
"github.com/kubernetes-incubator/cri-o/oci"
|
||||||
"github.com/opencontainers/runc/libcontainer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStats contains the statistics information for a running container
|
// ContainerStats contains the statistics information for a running container
|
||||||
|
@ -29,85 +22,5 @@ type ContainerStats struct {
|
||||||
|
|
||||||
// GetContainerStats gets the running stats for a given container
|
// GetContainerStats gets the running stats for a given container
|
||||||
func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
|
func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
|
||||||
previousCPU := previousStats.CPUNano
|
return c.getContainerStats(ctr, previousStats)
|
||||||
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.CPUNano = cgroupStats.CpuStats.CpuUsage.TotalUsage
|
|
||||||
stats.SystemNano = time.Now().UnixNano()
|
|
||||||
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 uint64, previousSystem int64) float64 {
|
|
||||||
var (
|
|
||||||
cpuPercent = 0.0
|
|
||||||
cpuDelta = float64(stats.CgroupStats.CpuStats.CpuUsage.TotalUsage - previousCPU)
|
|
||||||
systemDelta = float64(uint64(time.Now().UnixNano()) - uint64(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
|
|
||||||
}
|
}
|
||||||
|
|
61
lib/stats_linux.go
Normal file
61
lib/stats_linux.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/libcontainer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 uint64, previousSystem int64) float64 {
|
||||||
|
var (
|
||||||
|
cpuPercent = 0.0
|
||||||
|
cpuDelta = float64(stats.CgroupStats.CpuStats.CpuUsage.TotalUsage - previousCPU)
|
||||||
|
systemDelta = float64(uint64(time.Now().UnixNano()) - uint64(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue