From 4c52e2ea1cf51cb915c901761c347d6ce60e64c7 Mon Sep 17 00:00:00 2001 From: Victor Marmol Date: Thu, 17 Jul 2014 13:39:47 -0700 Subject: [PATCH] Implement ListContainers and no-op GetSpec(). --- container/raw/factory.go | 47 +++++++++++++++++++++++++++++-- container/raw/handler.go | 60 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/container/raw/factory.go b/container/raw/factory.go index 575aa61c..50e5a62c 100644 --- a/container/raw/factory.go +++ b/container/raw/factory.go @@ -15,12 +15,20 @@ package raw import ( + "fmt" "log" + "github.com/docker/libcontainer/cgroups" "github.com/google/cadvisor/container" ) +type cgroupSubsystems struct { + // Cgroup subsystem mounts. + mounts []cgroups.Mount +} + type rawFactory struct { + cgroupSubsystems *cgroupSubsystems } func (self *rawFactory) String() string { @@ -28,7 +36,7 @@ func (self *rawFactory) String() string { } func (self *rawFactory) NewContainerHandler(name string) (container.ContainerHandler, error) { - return newRawContainerHandler(name) + return newRawContainerHandler(name, self.cgroupSubsystems) } // The raw factory can handle any container. @@ -37,7 +45,42 @@ func (self *rawFactory) CanHandle(name string) bool { } func Register() error { + // Get all cgroup mounts. + allCgroups, err := cgroups.GetCgroupMounts() + if err != nil { + return err + } + if len(allCgroups) == 0 { + return fmt.Errorf("failed to find cgroup mounts for the raw factory") + } + + // Trim the mounts to only the subsystems we care about. + supportedCgroups := make([]cgroups.Mount, 0, len(allCgroups)) + for _, mount := range allCgroups { + for _, subsystem := range mount.Subsystems { + if _, ok := supportedSubsystems[subsystem]; ok { + supportedCgroups = append(supportedCgroups, mount) + } + } + } + if len(supportedCgroups) == 0 { + return fmt.Errorf("failed to find supported cgroup mounts for the raw factory") + } + log.Printf("Registering Raw factory") - container.RegisterContainerHandlerFactory(new(rawFactory)) + factory := &rawFactory{ + cgroupSubsystems: &cgroupSubsystems{ + mounts: supportedCgroups, + }, + } + container.RegisterContainerHandlerFactory(factory) return nil } + +// Cgroup susbsystems we support listing (should be the minimal set we need stats from). +var supportedSubsystems map[string]struct{} = map[string]struct{}{ + "cpu": struct{}{}, + "cpuset": struct{}{}, + "cpuacct": struct{}{}, + "memory": struct{}{}, +} diff --git a/container/raw/handler.go b/container/raw/handler.go index 76abe821..47251276 100644 --- a/container/raw/handler.go +++ b/container/raw/handler.go @@ -15,6 +15,9 @@ package raw import ( + "io/ioutil" + "path/filepath" + "github.com/docker/libcontainer/cgroups" "github.com/google/cadvisor/container" "github.com/google/cadvisor/container/libcontainer" @@ -22,12 +25,14 @@ import ( ) type rawContainerHandler struct { - name string + name string + cgroupSubsystems *cgroupSubsystems } -func newRawContainerHandler(name string) (container.ContainerHandler, error) { +func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems) (container.ContainerHandler, error) { return &rawContainerHandler{ - name: name, + name: name, + cgroupSubsystems: cgroupSubsystems, }, nil } @@ -39,8 +44,12 @@ func (self *rawContainerHandler) ContainerReference() (info.ContainerReference, } func (self *rawContainerHandler) GetSpec() (*info.ContainerSpec, error) { + ret := new(info.ContainerSpec) + ret.Cpu = new(info.CpuSpec) + ret.Memory = new(info.MemorySpec) + // TODO(vmarmol): Implement - return new(info.ContainerSpec), nil + return ret, nil } func (self *rawContainerHandler) GetStats() (stats *info.ContainerStats, err error) { @@ -52,9 +61,48 @@ func (self *rawContainerHandler) GetStats() (stats *info.ContainerStats, err err return libcontainer.GetStats(cgroup, false) } +// Lists all directories under "path" and outputs the results as children of "parent". +func listDirectories(path string, parent string, recursive bool, output map[string]struct{}) error { + entries, err := ioutil.ReadDir(path) + if err != nil { + return err + } + for _, entry := range entries { + // We only grab directories. + if entry.IsDir() { + name := filepath.Join(parent, entry.Name()) + output[name] = struct{}{} + + // List subcontainers if asked to. + if recursive { + err := listDirectories(filepath.Join(path, entry.Name()), name, true, output) + if err != nil { + return err + } + } + } + } + return nil +} + func (self *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { - // TODO(vmarmol): Implement - return make([]info.ContainerReference, 0, 0), nil + containers := make(map[string]struct{}, 16) + for _, subsystem := range self.cgroupSubsystems.mounts { + err := listDirectories(filepath.Join(subsystem.Mountpoint, self.name), self.name, listType == container.LIST_RECURSIVE, containers) + if err != nil { + return nil, err + } + } + + // Make into container references. + ret := make([]info.ContainerReference, 0, len(containers)) + for cont, _ := range containers { + ret = append(ret, info.ContainerReference{ + Name: cont, + }) + } + + return ret, nil } func (self *rawContainerHandler) ListThreads(listType container.ListType) ([]int, error) {