From b9e70f0240db11e2e9c039cb4dd956df93c680e5 Mon Sep 17 00:00:00 2001 From: Vishnu Kannan Date: Mon, 29 Sep 2014 23:21:13 +0000 Subject: [PATCH] Filesystem stats are now per container. As of now, fs stats are reported only for the root cgroup. To make cadvisor detect all the disks, the rootfs of host needs to mounted inside cadvisor. --- README.md | 1 + container/raw/handler.go | 20 +++++++++++++------- deploy/Dockerfile | 1 + fs/fs.go | 27 ++++++++++++++++++--------- fs/types.go | 8 +++++--- info/container.go | 6 ++++-- 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 1d865fae..a19f1a21 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ To quickly tryout cAdvisor on your machine with Docker (version 0.11 or above), ``` sudo docker run \ + --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ diff --git a/container/raw/handler.go b/container/raw/handler.go index cc1e7002..6d6fd7a9 100644 --- a/container/raw/handler.go +++ b/container/raw/handler.go @@ -41,7 +41,7 @@ type rawContainerHandler struct { watcher *inotify.Watcher stopWatcher chan error watches map[string]struct{} - fsInfo fs.FsInfo + fsInfo fs.FsInfo } func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems, machineInfoFactory info.MachineInfoFactory) (container.ContainerHandler, error) { @@ -55,7 +55,7 @@ func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems, mac machineInfoFactory: machineInfoFactory, stopWatcher: make(chan error), watches: make(map[string]struct{}), - fsInfo: fs.NewFsInfo(), + fsInfo: fs.NewFsInfo(), }, nil } @@ -144,6 +144,10 @@ func (self *rawContainerHandler) GetSpec() (info.ContainerSpec, error) { } } + // Fs. + if self.name == "/" { + spec.HasFs = true + } return spec, nil } @@ -152,12 +156,14 @@ func (self *rawContainerHandler) GetStats() (*info.ContainerStats, error) { if err != nil { return nil, err } - // Get Filesystem information - fsStats, err := self.fsInfo.GetFsStats(self.name) - if err != nil { - return nil, err + // Get Filesystem information only for the root cgroup. + if self.name == "/" { + stats.Fs, err = self.fsInfo.GetFsStats() + if err != nil { + return nil, err + } } - stats.FsStats = fsStats + return stats, nil } diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 1c1b2d28..5702ab63 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -3,6 +3,7 @@ MAINTAINER dengnan@google.com vmarmol@google.com vishnuk@google.com # Grab cadvisor from the staging directory. ADD cadvisor /usr/bin/cadvisor +RUN mkdir /rootfs EXPOSE 8080 ENTRYPOINT ["/usr/bin/cadvisor"] diff --git a/fs/fs.go b/fs/fs.go index b99bd75c..a5bd2331 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -10,6 +10,7 @@ package fs import "C" import ( + "strings" "syscall" "unsafe" @@ -17,33 +18,41 @@ import ( "github.com/golang/glog" ) -const EXT_SUPER_MAGIC = 0xEF53 - type FsInfoImpl struct{} func NewFsInfo() FsInfo { return &FsInfoImpl{} } -func (*FsInfoImpl) GetFsStats(containerName string) ([]FsStat, error) { +func (*FsInfoImpl) GetFsStats() ([]FsStat, error) { filesystems := make([]FsStat, 0) - if containerName != "/" { - return filesystems, nil - } mounts, err := mount.GetMounts() if err != nil { return nil, err } + processedPartitions := make(map[string]bool, 0) for _, mount := range mounts { - if !strings.HasPrefix("ext", mount.FsType) || mount.Mountpoint != mount.Root { + if !strings.HasPrefix(mount.Fstype, "ext") { + continue + } + // Avoid bind mounts. + if _, ok := processedPartitions[mount.Source]; ok { continue } total, free, err := getVfsStats(mount.Mountpoint) if err != nil { glog.Errorf("Statvfs failed. Error: %v", err) } else { - glog.V(1).Infof("%s is an ext partition at %s. Total: %d, Free: %d", mount.Source, mount.Mountpoint, total, free) - filesystems = append(filesystems, FsStat{mount.Source, total, free}) + glog.V(1).Infof("%s is an %s partition at %s. Total: %d, Free: %d", mount.Source, mount.Fstype, mount.Mountpoint, total, free) + fsStat := FsStat{ + Device: mount.Source, + Major: uint(mount.Major), + Minor: uint(mount.Minor), + Capacity: total, + Free: free, + } + filesystems = append(filesystems, fsStat) + processedPartitions[mount.Source] = true } } return filesystems, nil diff --git a/fs/types.go b/fs/types.go index e527993e..78294b85 100644 --- a/fs/types.go +++ b/fs/types.go @@ -1,12 +1,14 @@ package fs type FsStat struct { - Name string `json:"name"` + Device string `json:"device,omitempty"` + Major uint `json:"major"` + Minor uint `json:"minor"` Capacity uint64 `json:"capacity"` Free uint64 `json:"free"` } type FsInfo interface { - // Returns capacity and free space, in bytes, of all the ext2, ext3, ext4 filesystems used by container 'containerName'. - GetFsStats(containerName string) ([]FsStat, error) + // Returns capacity and free space, in bytes, of all the ext2, ext3, ext4 filesystems on the host. + GetFsStats() ([]FsStat, error) } diff --git a/info/container.go b/info/container.go index dbfb698f..83197b39 100644 --- a/info/container.go +++ b/info/container.go @@ -17,7 +17,7 @@ package info import ( "reflect" "time" - + "github.com/google/cadvisor/fs" ) @@ -49,6 +49,8 @@ type ContainerSpec struct { Memory MemorySpec `json:"memory,omitempty"` HasNetwork bool `json:"has_network"` + + HasFs bool `json:"has_fs"` } // Container reference contains enough information to uniquely identify a container @@ -239,7 +241,7 @@ type ContainerStats struct { Memory *MemoryStats `json:"memory,omitempty"` Network *NetworkStats `json:"network,omitempty"` // Filesystem statistics - FsStats []fs.FsStat `json:"fs_stats,omitempty"` + Fs []fs.FsStat `json:"fs,omitempty"` } // Makes a deep copy of the ContainerStats and returns a pointer to the new