cadvisor/container/libcontainer/helpers.go

122 lines
3.4 KiB
Go

package libcontainer
import (
"bufio"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/docker/libcontainer"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/cgroups/fs"
"github.com/google/cadvisor/info"
)
// Get stats of the specified container
func GetStats(config *libcontainer.Config, state *libcontainer.State) (*info.ContainerStats, error) {
// TODO(vmarmol): Use libcontainer's Stats() in the new API when that is ready.
libcontainerStats, err := libcontainer.GetStats(config, state)
if err != nil {
return nil, err
}
return toContainerStats(libcontainerStats), nil
}
func GetStatsCgroupOnly(cgroup *cgroups.Cgroup) (*info.ContainerStats, error) {
s, err := fs.GetStats(cgroup)
if err != nil {
return nil, err
}
return toContainerStats(&libcontainer.ContainerStats{CgroupStats: s}), nil
}
// Convert libcontainer stats to info.ContainerStats.
func toContainerStats(libcontainerStats *libcontainer.ContainerStats) *info.ContainerStats {
s := libcontainerStats.CgroupStats
ret := new(info.ContainerStats)
ret.Timestamp = time.Now()
if s != nil {
ret.Cpu = new(info.CpuStats)
ret.Cpu.Usage.User = s.CpuStats.CpuUsage.UsageInUsermode
ret.Cpu.Usage.System = s.CpuStats.CpuUsage.UsageInKernelmode
n := len(s.CpuStats.CpuUsage.PercpuUsage)
ret.Cpu.Usage.PerCpu = make([]uint64, n)
ret.Cpu.Usage.Total = 0
for i := 0; i < n; i++ {
ret.Cpu.Usage.PerCpu[i] = s.CpuStats.CpuUsage.PercpuUsage[i]
ret.Cpu.Usage.Total += s.CpuStats.CpuUsage.PercpuUsage[i]
}
ret.Memory = new(info.MemoryStats)
ret.Memory.Usage = s.MemoryStats.Usage
if v, ok := s.MemoryStats.Stats["pgfault"]; ok {
ret.Memory.ContainerData.Pgfault = v
ret.Memory.HierarchicalData.Pgfault = v
}
if v, ok := s.MemoryStats.Stats["pgmajfault"]; ok {
ret.Memory.ContainerData.Pgmajfault = v
ret.Memory.HierarchicalData.Pgmajfault = v
}
if v, ok := s.MemoryStats.Stats["total_inactive_anon"]; ok {
ret.Memory.WorkingSet = ret.Memory.Usage - v
if v, ok := s.MemoryStats.Stats["total_active_file"]; ok {
ret.Memory.WorkingSet -= v
}
}
}
// TODO(vishh): Perform a deep copy or alias libcontainer network stats.
if libcontainerStats.NetworkStats != nil {
ret.Network = (*info.NetworkStats)(libcontainerStats.NetworkStats)
}
return ret
}
// Given a container name, returns the parent and name of the container to be fed to libcontainer.
func SplitName(containerName string) (string, string, error) {
parent, id := path.Split(containerName)
cgroupSelf, err := os.Open("/proc/self/cgroup")
if err != nil {
return "", "", err
}
scanner := bufio.NewScanner(cgroupSelf)
// Find how nested we are. Libcontainer takes container names relative to the current process.
subsys := []string{"memory", "cpu"}
nestedLevels := 0
for scanner.Scan() {
line := scanner.Text()
elems := strings.Split(line, ":")
if len(elems) < 3 {
continue
}
for _, s := range subsys {
if elems[1] == s {
if elems[2] == "/" {
// We're running at root, no nesting.
nestedLevels = 0
} else {
// Count how deeply nested we are.
nestedLevels = strings.Count(elems[2], "/")
}
break
}
}
}
if nestedLevels > 0 {
// we are running inside a docker container
upperLevel := strings.Repeat("../", nestedLevels)
parent = filepath.Join(upperLevel, parent)
}
// Strip the last "/"
if parent[len(parent)-1] == '/' {
parent = parent[:len(parent)-1]
}
return parent, id, nil
}