lib: libcontainer references are linux only

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
Vincent Batts 2018-01-29 03:57:27 -05:00
parent cdc468afa8
commit ef6aa87c75
Signed by: vbatts
GPG Key ID: 10937E57733F1362
5 changed files with 126 additions and 107 deletions

View File

@ -17,7 +17,6 @@ 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"
@ -771,20 +770,3 @@ func (c *ContainerServer) RemoveSandbox(id string) {
func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
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()
}

View File

@ -3,11 +3,33 @@
package lib
import (
"path/filepath"
"time"
"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"
"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) {
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
}

View File

@ -2,7 +2,11 @@
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) {
// nothin' doin'
@ -11,3 +15,8 @@ func (c *ContainerServer) addSandboxPlatform(sb *sandbox.Sandbox) {
func (c *ContainerServer) removeSandboxPlatform(sb *sandbox.Sandbox) {
// nothin' doin'
}
func (c *ContainerServer) getContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
// nothin' doin'
return nil, errors.New("container stats not supported")
}

View File

@ -1,14 +1,7 @@
package lib
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
@ -29,85 +22,5 @@ type ContainerStats struct {
// 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.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
return c.getContainerStats(ctr, previousStats)
}

61
lib/stats_linux.go Normal file
View 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
}