From a8863e6367ed58bfd8f68daf5bf4a4505d6b73dc Mon Sep 17 00:00:00 2001 From: Victor Marmol Date: Thu, 17 Jul 2014 10:25:10 -0700 Subject: [PATCH] Initial version of the raw container driver. --- container/docker/factory.go | 7 ++-- container/docker/handler.go | 58 +++----------------------- container/libcontainer/helpers.go | 63 ++++++++++++++++++++++++++++ container/raw/factory.go | 43 +++++++++++++++++++ container/raw/handler.go | 68 +++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 56 deletions(-) create mode 100644 container/libcontainer/helpers.go create mode 100644 container/raw/factory.go create mode 100644 container/raw/handler.go diff --git a/container/docker/factory.go b/container/docker/factory.go index 879595b6..e3c033df 100644 --- a/container/docker/factory.go +++ b/container/docker/factory.go @@ -34,7 +34,7 @@ type dockerFactory struct { machineInfoFactory info.MachineInfoFactory // Whether this system is using systemd. - hasSystemd bool + useSystemd bool } func (self *dockerFactory) String() string { @@ -50,6 +50,7 @@ func (self *dockerFactory) NewContainerHandler(name string) (handler container.C client, name, self.machineInfoFactory, + self.useSystemd, ) return } @@ -57,7 +58,7 @@ func (self *dockerFactory) NewContainerHandler(name string) (handler container.C // Docker handles all containers under /docker func (self *dockerFactory) CanHandle(name string) bool { // In systemd systems the containers are: /docker-{ID} - if self.hasSystemd { + if self.useSystemd { return strings.HasPrefix(name, "/docker-") } return name == "/docker" || strings.HasPrefix(name, "/docker/") @@ -107,7 +108,7 @@ func Register(factory info.MachineInfoFactory) error { } f := &dockerFactory{ machineInfoFactory: factory, - hasSystemd: systemd.UseSystemd(), + useSystemd: systemd.UseSystemd(), } log.Printf("Registering Docker factory") container.RegisterContainerHandlerFactory(f) diff --git a/container/docker/handler.go b/container/docker/handler.go index fd170d67..b689e3f8 100644 --- a/container/docker/handler.go +++ b/container/docker/handler.go @@ -27,10 +27,9 @@ import ( "github.com/docker/libcontainer" "github.com/docker/libcontainer/cgroups" - "github.com/docker/libcontainer/cgroups/fs" - "github.com/docker/libcontainer/cgroups/systemd" "github.com/fsouza/go-dockerclient" "github.com/google/cadvisor/container" + containerLibcontainer "github.com/google/cadvisor/container/libcontainer" "github.com/google/cadvisor/info" ) @@ -39,17 +38,20 @@ type dockerContainerHandler struct { name string aliases []string machineInfoFactory info.MachineInfoFactory + useSystemd bool } func newDockerContainerHandler( client *docker.Client, name string, machineInfoFactory info.MachineInfoFactory, + useSystemd bool, ) (container.ContainerHandler, error) { handler := &dockerContainerHandler{ client: client, name: name, machineInfoFactory: machineInfoFactory, + useSystemd: useSystemd, } if !handler.isDockerContainer() { return handler, nil @@ -190,39 +192,6 @@ func (self *dockerContainerHandler) GetSpec() (spec *info.ContainerSpec, err err return } -func libcontainerToContainerStats(s *cgroups.Stats, mi *info.MachineInfo) *info.ContainerStats { - ret := new(info.ContainerStats) - ret.Timestamp = time.Now() - 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 - } - } - return ret -} - func (self *dockerContainerHandler) GetStats() (stats *info.ContainerStats, err error) { if !self.isDockerContainer() { // Return empty stats for root containers. @@ -230,10 +199,6 @@ func (self *dockerContainerHandler) GetStats() (stats *info.ContainerStats, err stats.Timestamp = time.Now() return } - mi, err := self.machineInfoFactory.GetMachineInfo() - if err != nil { - return - } parent, id, err := self.splitName() if err != nil { return @@ -242,20 +207,7 @@ func (self *dockerContainerHandler) GetStats() (stats *info.ContainerStats, err Parent: parent, Name: id, } - - // TODO(vmarmol): Use libcontainer's Stats() in the new API when that is ready. - // Use systemd paths if systemd is being used. - var s *cgroups.Stats - if systemd.UseSystemd() { - s, err = systemd.GetStats(cg) - } else { - s, err = fs.GetStats(cg) - } - if err != nil { - return - } - stats = libcontainerToContainerStats(s, mi) - return + return containerLibcontainer.GetStats(cg, self.useSystemd) } func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { diff --git a/container/libcontainer/helpers.go b/container/libcontainer/helpers.go new file mode 100644 index 00000000..957be091 --- /dev/null +++ b/container/libcontainer/helpers.go @@ -0,0 +1,63 @@ +package libcontainer + +import ( + "time" + + "github.com/docker/libcontainer/cgroups" + "github.com/docker/libcontainer/cgroups/fs" + "github.com/docker/libcontainer/cgroups/systemd" + "github.com/google/cadvisor/info" +) + +// Get stats of the specified cgroup +func GetStats(cgroup *cgroups.Cgroup, useSystemd bool) (*info.ContainerStats, error) { + // TODO(vmarmol): Use libcontainer's Stats() in the new API when that is ready. + // Use systemd paths if systemd is being used. + var ( + s *cgroups.Stats + err error + ) + if useSystemd { + s, err = systemd.GetStats(cgroup) + } else { + s, err = fs.GetStats(cgroup) + } + if err != nil { + return nil, err + } + return toContainerStats(s), nil +} + +// Convert libcontainer stats to info.ContainerStats. +func toContainerStats(s *cgroups.Stats) *info.ContainerStats { + ret := new(info.ContainerStats) + ret.Timestamp = time.Now() + 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 + } + } + return ret +} diff --git a/container/raw/factory.go b/container/raw/factory.go new file mode 100644 index 00000000..575aa61c --- /dev/null +++ b/container/raw/factory.go @@ -0,0 +1,43 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package raw + +import ( + "log" + + "github.com/google/cadvisor/container" +) + +type rawFactory struct { +} + +func (self *rawFactory) String() string { + return "raw" +} + +func (self *rawFactory) NewContainerHandler(name string) (container.ContainerHandler, error) { + return newRawContainerHandler(name) +} + +// The raw factory can handle any container. +func (self *rawFactory) CanHandle(name string) bool { + return true +} + +func Register() error { + log.Printf("Registering Raw factory") + container.RegisterContainerHandlerFactory(new(rawFactory)) + return nil +} diff --git a/container/raw/handler.go b/container/raw/handler.go new file mode 100644 index 00000000..76abe821 --- /dev/null +++ b/container/raw/handler.go @@ -0,0 +1,68 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package raw + +import ( + "github.com/docker/libcontainer/cgroups" + "github.com/google/cadvisor/container" + "github.com/google/cadvisor/container/libcontainer" + "github.com/google/cadvisor/info" +) + +type rawContainerHandler struct { + name string +} + +func newRawContainerHandler(name string) (container.ContainerHandler, error) { + return &rawContainerHandler{ + name: name, + }, nil +} + +func (self *rawContainerHandler) ContainerReference() (info.ContainerReference, error) { + // We only know the container by its one name. + return info.ContainerReference{ + Name: self.name, + }, nil +} + +func (self *rawContainerHandler) GetSpec() (*info.ContainerSpec, error) { + // TODO(vmarmol): Implement + return new(info.ContainerSpec), nil +} + +func (self *rawContainerHandler) GetStats() (stats *info.ContainerStats, err error) { + cgroup := &cgroups.Cgroup{ + Parent: "/", + Name: self.name, + } + + return libcontainer.GetStats(cgroup, false) +} + +func (self *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { + // TODO(vmarmol): Implement + return make([]info.ContainerReference, 0, 0), nil +} + +func (self *rawContainerHandler) ListThreads(listType container.ListType) ([]int, error) { + // TODO(vmarmol): Implement + return nil, nil +} + +func (self *rawContainerHandler) ListProcesses(listType container.ListType) ([]int, error) { + // TODO(vmarmol): Implement + return nil, nil +}