Adding a disk usage progress bar.

This commit is contained in:
Vishnu Kannan 2014-09-30 23:38:34 +00:00
parent b9e70f0240
commit c21ff1f166
7 changed files with 77 additions and 23 deletions

View File

@ -45,6 +45,10 @@ type rawContainerHandler struct {
}
func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems, machineInfoFactory info.MachineInfoFactory) (container.ContainerHandler, error) {
fsInfo, err := fs.NewFsInfo()
if err != nil {
return nil, err
}
return &rawContainerHandler{
name: name,
cgroup: &cgroups.Cgroup{
@ -55,7 +59,7 @@ func newRawContainerHandler(name string, cgroupSubsystems *cgroupSubsystems, mac
machineInfoFactory: machineInfoFactory,
stopWatcher: make(chan error),
watches: make(map[string]struct{}),
fsInfo: fs.NewFsInfo(),
fsInfo: fsInfo,
}, nil
}
@ -146,7 +150,7 @@ func (self *rawContainerHandler) GetSpec() (info.ContainerSpec, error) {
// Fs.
if self.name == "/" {
spec.HasFs = true
spec.HasFilesystem = true
}
return spec, nil
}
@ -158,7 +162,7 @@ func (self *rawContainerHandler) GetStats() (*info.ContainerStats, error) {
}
// Get Filesystem information only for the root cgroup.
if self.name == "/" {
stats.Fs, err = self.fsInfo.GetFsStats()
stats.Filesystem, err = self.fsInfo.GetFsStats()
if err != nil {
return nil, err
}

View File

@ -3,7 +3,6 @@ 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"]

View File

@ -18,41 +18,50 @@ import (
"github.com/golang/glog"
)
type FsInfoImpl struct{}
func NewFsInfo() FsInfo {
return &FsInfoImpl{}
type partition struct {
mountpoint string
major uint32
minor uint32
}
func (*FsInfoImpl) GetFsStats() ([]FsStat, error) {
filesystems := make([]FsStat, 0)
type FsInfoImpl struct {
partitions map[string]partition
}
func NewFsInfo() (FsInfo, error) {
mounts, err := mount.GetMounts()
if err != nil {
return nil, err
}
processedPartitions := make(map[string]bool, 0)
partitions := make(map[string]partition, 0)
for _, mount := range mounts {
if !strings.HasPrefix(mount.Fstype, "ext") {
continue
}
// Avoid bind mounts.
if _, ok := processedPartitions[mount.Source]; ok {
if _, ok := partitions[mount.Source]; ok {
continue
}
total, free, err := getVfsStats(mount.Mountpoint)
partitions[mount.Source] = partition{mount.Mountpoint, uint32(mount.Major), uint32(mount.Minor)}
}
return &FsInfoImpl{partitions}, nil
}
func (self *FsInfoImpl) GetFsStats() ([]FsStats, error) {
filesystems := make([]FsStats, 0)
for device, partition := range self.partitions {
total, free, err := getVfsStats(partition.mountpoint)
if err != nil {
glog.Errorf("Statvfs failed. Error: %v", err)
} else {
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),
fsStat := FsStats{
Device: device,
Major: uint(partition.major),
Minor: uint(partition.minor),
Capacity: total,
Free: free,
}
filesystems = append(filesystems, fsStat)
processedPartitions[mount.Source] = true
}
}
return filesystems, nil

View File

@ -1,6 +1,6 @@
package fs
type FsStat struct {
type FsStats struct {
Device string `json:"device,omitempty"`
Major uint `json:"major"`
Minor uint `json:"minor"`
@ -10,5 +10,5 @@ type FsStat struct {
type FsInfo interface {
// Returns capacity and free space, in bytes, of all the ext2, ext3, ext4 filesystems on the host.
GetFsStats() ([]FsStat, error)
GetFsStats() ([]FsStats, error)
}

View File

@ -50,7 +50,7 @@ type ContainerSpec struct {
HasNetwork bool `json:"has_network"`
HasFs bool `json:"has_fs"`
HasFilesystem bool `json:"has_filesystem"`
}
// Container reference contains enough information to uniquely identify a container
@ -241,7 +241,7 @@ type ContainerStats struct {
Memory *MemoryStats `json:"memory,omitempty"`
Network *NetworkStats `json:"network,omitempty"`
// Filesystem statistics
Fs []fs.FsStat `json:"fs,omitempty"`
Filesystem []fs.FsStats `json:"filesystem,omitempty"`
}
// Makes a deep copy of the ContainerStats and returns a pointer to the new

View File

@ -27,6 +27,7 @@ import (
"time"
"github.com/golang/glog"
"github.com/google/cadvisor/fs"
"github.com/google/cadvisor/info"
"github.com/google/cadvisor/manager"
)
@ -98,6 +99,8 @@ var funcMap = template.FuncMap{
"getMemoryUsagePercent": getMemoryUsagePercent,
"getHotMemoryPercent": getHotMemoryPercent,
"getColdMemoryPercent": getColdMemoryPercent,
"getFsStats": getFsStats,
"getFsUsagePercent": getFsUsagePercent,
}
// TODO(vmarmol): Consider housekeeping Spec too so we can show changes through time. We probably don't need it ever second though.
@ -115,6 +118,7 @@ type pageData struct {
CpuAvailable bool
MemoryAvailable bool
NetworkAvailable bool
FsAvailable bool
}
func init() {
@ -252,6 +256,17 @@ func getColdMemoryPercent(spec *info.ContainerSpec, stats []*info.ContainerStats
return toMemoryPercent((latestStats.Usage)-(latestStats.WorkingSet), spec, machine)
}
func getFsStats(stats []*info.ContainerStats) []fs.FsStats {
if len(stats) == 0 {
return []fs.FsStats{}
}
return stats[len(stats)-1].Filesystem
}
func getFsUsagePercent(capacity, free uint64) uint64 {
return uint64((float64(capacity-free) / float64(capacity)) * 100)
}
func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
start := time.Now()
@ -312,6 +327,7 @@ func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL)
CpuAvailable: cont.Spec.HasCpu,
MemoryAvailable: cont.Spec.HasMemory,
NetworkAvailable: cont.Spec.HasNetwork,
FsAvailable: cont.Spec.HasFilesystem,
}
err = pageTemplate.Execute(w, data)
if err != nil {

View File

@ -147,6 +147,32 @@ const containersHtmlTemplate = `
</div>
</div>
{{end}}
{{if .FsAvailable}}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Filesystem</h3>
</div>
<div class="panel-body">
{{with getFsStats .Stats}}
{{range .}}
<div class="row col-sm-12">
<h4>Partition: {{.Device}}</h4>
</div>
<div class="col-sm-9">
<div class="progress">
<div id="memory-usage-chart"></div>
<div class="progress-bar progress-bar-danger" style="width: {{getFsUsagePercent .Capacity .Free}}%">
</div>
</div>
</div>
<div class="col-sm-3">
{{printSize .Capacity}} {{printUnit .Capacity}} ({{getFsUsagePercent .Capacity .Free}}%)
</div>
{{end}}
{{end}}
</div>
</div>
{{end}}
{{if .NetworkAvailable}}
<div class="panel panel-primary">
<div class="panel-heading">