diff --git a/cadvisor.go b/cadvisor.go index 75c12931..ccbfddea 100644 --- a/cadvisor.go +++ b/cadvisor.go @@ -52,7 +52,7 @@ func main() { } // Register the raw driver. - if err := raw.Register(); err != nil { + if err := raw.Register(containerManager); err != nil { log.Fatalf("raw registration failed: %v.", err) } diff --git a/container/raw/factory.go b/container/raw/factory.go index 83713cd9..976eecac 100644 --- a/container/raw/factory.go +++ b/container/raw/factory.go @@ -20,15 +20,21 @@ import ( "github.com/docker/libcontainer/cgroups" "github.com/google/cadvisor/container" + "github.com/google/cadvisor/info" ) type cgroupSubsystems struct { // Cgroup subsystem mounts. mounts []cgroups.Mount + + // Cgroup subsystem to their mount location. + mountPoints map[string]string } type rawFactory struct { - cgroupSubsystems *cgroupSubsystems + // Factory for machine information. + machineInfoFactory info.MachineInfoFactory + cgroupSubsystems *cgroupSubsystems } func (self *rawFactory) String() string { @@ -36,7 +42,7 @@ func (self *rawFactory) String() string { } func (self *rawFactory) NewContainerHandler(name string) (container.ContainerHandler, error) { - return newRawContainerHandler(name, self.cgroupSubsystems) + return newRawContainerHandler(name, self.cgroupSubsystems, self.machineInfoFactory) } // The raw factory can handle any container. @@ -44,7 +50,7 @@ func (self *rawFactory) CanHandle(name string) bool { return true } -func Register() error { +func Register(machineInfoFactory info.MachineInfoFactory) error { // Get all cgroup mounts. allCgroups, err := cgroups.GetCgroupMounts() if err != nil { @@ -56,10 +62,12 @@ func Register() error { // Trim the mounts to only the subsystems we care about. supportedCgroups := make([]cgroups.Mount, 0, len(allCgroups)) + mountPoints := make(map[string]string, len(allCgroups)) for _, mount := range allCgroups { for _, subsystem := range mount.Subsystems { if _, ok := supportedSubsystems[subsystem]; ok { supportedCgroups = append(supportedCgroups, mount) + mountPoints[subsystem] = mount.Mountpoint } } } @@ -69,8 +77,10 @@ func Register() error { log.Printf("Registering Raw factory") factory := &rawFactory{ + machineInfoFactory: machineInfoFactory, cgroupSubsystems: &cgroupSubsystems{ - mounts: supportedCgroups, + mounts: supportedCgroups, + mountPoints: mountPoints, }, } container.RegisterContainerHandlerFactory(factory) diff --git a/container/raw/handler.go b/container/raw/handler.go index 07a1a82e..c1424a6b 100644 --- a/container/raw/handler.go +++ b/container/raw/handler.go @@ -16,23 +16,30 @@ package raw import ( "io/ioutil" + "log" + "math" "path/filepath" + "strconv" + "strings" "github.com/docker/libcontainer/cgroups" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/info" + "github.com/google/cadvisor/utils" ) type rawContainerHandler struct { - name string - cgroupSubsystems *cgroupSubsystems + name string + cgroupSubsystems *cgroupSubsystems + machineInfoFactory info.MachineInfoFactory } -func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems) (container.ContainerHandler, error) { +func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems, machineInfoFactory info.MachineInfoFactory) (container.ContainerHandler, error) { return &rawContainerHandler{ - name: name, - cgroupSubsystems: cgroupSubsystems, + name: name, + cgroupSubsystems: cgroupSubsystems, + machineInfoFactory: machineInfoFactory, }, nil } @@ -43,13 +50,69 @@ func (self *rawContainerHandler) ContainerReference() (info.ContainerReference, }, nil } -func (self *rawContainerHandler) GetSpec() (*info.ContainerSpec, error) { - ret := new(info.ContainerSpec) - ret.Cpu = new(info.CpuSpec) - ret.Memory = new(info.MemorySpec) +func readInt64(path string, file string) uint64 { + cgroupFile := filepath.Join(path, file) - // TODO(vmarmol): Implement - return ret, nil + // Ignore non-existent files + if !utils.FileExists(cgroupFile) { + return 0 + } + + // Read + out, err := ioutil.ReadFile(cgroupFile) + if err != nil { + log.Printf("raw driver: Failed to read %q: %s", cgroupFile, err) + return 0 + } + val, err := strconv.ParseUint(strings.TrimSpace(string(out)), 10, 64) + if err != nil { + log.Printf("raw driver: Failed to parse in %q from file %q: %s", string(out), cgroupFile, err) + return 0 + } + + return val +} + +func (self *rawContainerHandler) GetSpec() (*info.ContainerSpec, error) { + spec := new(info.ContainerSpec) + + // The raw driver assumes unified hierarchy containers. + + // CPU. + cpuRoot, ok := self.cgroupSubsystems.mountPoints["cpu"] + if ok { + cpuRoot = filepath.Join(cpuRoot, self.name) + if utils.FileExists(cpuRoot) { + // Get machine info. + mi, err := self.machineInfoFactory.GetMachineInfo() + if err != nil { + return nil, err + } + + spec.Cpu = new(info.CpuSpec) + spec.Cpu.Limit = readInt64(cpuRoot, "cpu.shares") + + // TODO(vmarmol): Get CPUs from config.Cgroups.CpusetCpus + n := (mi.NumCores + 63) / 64 + spec.Cpu.Mask.Data = make([]uint64, n) + for i := 0; i < n; i++ { + spec.Cpu.Mask.Data[i] = math.MaxUint64 + } + } + } + + // Memory. + memoryRoot, ok := self.cgroupSubsystems.mountPoints["memory"] + if ok { + memoryRoot = filepath.Join(memoryRoot, self.name) + if utils.FileExists(memoryRoot) { + spec.Memory = new(info.MemorySpec) + spec.Memory.Limit = readInt64(memoryRoot, "memory.limit_in_bytes") + spec.Memory.SwapLimit = readInt64(memoryRoot, "memory.limit_in_bytes") + } + } + + return spec, nil } func (self *rawContainerHandler) GetStats() (stats *info.ContainerStats, err error) {