Update cAdvisor godep.

- Registers factories in Start(). Allows waiting for Docker.
pull/6/head
Victor Marmol 2015-05-15 10:21:16 -07:00
parent 43e4654333
commit df222ac47f
8 changed files with 344 additions and 73 deletions

68
Godeps/Godeps.json generated
View File

@ -210,88 +210,88 @@
},
{
"ImportPath": "github.com/google/cadvisor/api",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/collector",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/container",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/events",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/fs",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/healthz",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/http",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/info/v1",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/info/v2",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/manager",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/metrics",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/pages",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/storage",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/summary",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/utils",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/validate",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/cadvisor/version",
"Comment": "0.13.0-48-g9535dd2",
"Rev": "9535dd21e2aca94f024528679d22e3637178cda0"
"Comment": "0.13.0-56-ga9f4b69",
"Rev": "a9f4b691c1e0336e5d8e310d5664046012988437"
},
{
"ImportPath": "github.com/google/go-github/github",

View File

@ -340,3 +340,27 @@ func (self *dockerContainerHandler) StopWatchingSubcontainers() error {
func (self *dockerContainerHandler) Exists() bool {
return containerLibcontainer.Exists(*dockerRootDir, *dockerRunDir, self.id)
}
func DockerInfo() (map[string]string, error) {
client, err := docker.NewClient(*ArgDockerEndpoint)
if err != nil {
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
}
info, err := client.Info()
if err != nil {
return nil, err
}
return info.Map(), nil
}
func DockerImages() ([]docker.APIImages, error) {
client, err := docker.NewClient(*ArgDockerEndpoint)
if err != nil {
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
}
images, err := client.ListImages(docker.ListImagesOptions{All: false})
if err != nil {
return nil, err
}
return images, nil
}

View File

@ -171,14 +171,15 @@ type RequestOptions struct {
}
type ProcessInfo struct {
User string `json:"user"`
Pid int `json:"pid"`
Ppid int `json:"parent_pid"`
StartTime string `json:"start_time"`
PercentCpu string `json:"percent_cpu"`
RSS string `json:"rss"`
VirtualSize string `json:"virtual_size"`
Status string `json:"status"`
RunningTime string `json:"running_time"`
Cmd string `json:"cmd"`
User string `json:"user"`
Pid int `json:"pid"`
Ppid int `json:"parent_pid"`
StartTime string `json:"start_time"`
PercentCpu string `json:"percent_cpu"`
PercentMemory string `json:"percent_mem"`
RSS string `json:"rss"`
VirtualSize string `json:"virtual_size"`
Status string `json:"status"`
RunningTime string `json:"running_time"`
Cmd string `json:"cmd"`
}

View File

@ -130,9 +130,9 @@ func (c *containerData) GetProcessList() ([]v2.ProcessInfo, error) {
}
}
// TODO(rjnagal): Take format as an option?
format := "user,pid,ppid,stime,pcpu,rss,vsz,stat,time,comm"
format := "user,pid,ppid,stime,pcpu,pmem,rss,vsz,stat,time,comm"
args := []string{"-e", "-o", format}
expectedFields := 10
expectedFields := 11
out, err := exec.Command("ps", args...).Output()
if err != nil {
return nil, fmt.Errorf("failed to execute ps command: %v", err)
@ -157,16 +157,17 @@ func (c *containerData) GetProcessList() ([]v2.ProcessInfo, error) {
}
if isRoot || pidMap[pid] == true {
processes = append(processes, v2.ProcessInfo{
User: fields[0],
Pid: pid,
Ppid: ppid,
StartTime: fields[3],
PercentCpu: fields[4],
RSS: fields[5],
VirtualSize: fields[6],
Status: fields[7],
RunningTime: fields[8],
Cmd: strings.Join(fields[9:], " "),
User: fields[0],
Pid: pid,
Ppid: ppid,
StartTime: fields[3],
PercentCpu: fields[4],
PercentMemory: fields[5],
RSS: fields[6],
VirtualSize: fields[7],
Status: fields[8],
RunningTime: fields[9],
Cmd: strings.Join(fields[10:], " "),
})
}
}

View File

@ -50,7 +50,8 @@ var eventStorageEventLimit = flag.String("event_storage_event_limit", "default=1
// The Manager interface defines operations for starting a manager and getting
// container and machine information.
type Manager interface {
// Start the manager.
// Start the manager. Calling other manager methods before this returns
// may produce undefined behavior.
Start() error
// Stops the manager.
@ -100,6 +101,12 @@ type Manager interface {
GetPastEvents(request *events.Request) ([]*info.Event, error)
CloseEventChannel(watch_id int)
// Get status information about docker.
DockerInfo() (DockerStatus, error)
// Get details about interesting docker images.
DockerImages() ([]DockerImage, error)
}
// New takes a memory storage and returns a new manager.
@ -144,19 +151,6 @@ func New(memoryStorage *memory.InMemoryStorage, sysfs sysfs.SysFs) (Manager, err
glog.Infof("Version: %+v", newManager.versionInfo)
newManager.eventHandler = events.NewEventManager(parseEventsStoragePolicy())
// Register Docker container factory.
err = docker.Register(newManager, fsInfo)
if err != nil {
glog.Errorf("Docker container factory registration failed: %v.", err)
}
// Register the raw driver.
err = raw.Register(newManager, fsInfo)
if err != nil {
glog.Errorf("Registration of the raw container factory failed: %v", err)
}
return newManager, nil
}
@ -186,6 +180,20 @@ type manager struct {
// Start the container manager.
func (self *manager) Start() error {
// Register Docker container factory.
err := docker.Register(self, self.fsInfo)
if err != nil {
glog.Errorf("Docker container factory registration failed: %v.", err)
}
// Register the raw driver.
err = raw.Register(self, self.fsInfo)
if err != nil {
glog.Errorf("Registration of the raw container factory failed: %v", err)
}
self.DockerInfo()
self.DockerImages()
if *enableLoadReader {
// Create cpu load reader.
@ -204,7 +212,7 @@ func (self *manager) Start() error {
}
// Watch for OOMs.
err := self.watchForNewOoms()
err = self.watchForNewOoms()
if err != nil {
glog.Errorf("Failed to start OOM watcher, will not get OOM events: %v", err)
}
@ -1022,3 +1030,104 @@ func parseEventsStoragePolicy() events.StoragePolicy {
return policy
}
type DockerStatus struct {
Version string `json:"version"`
KernelVersion string `json:"kernel_version"`
OS string `json:"os"`
Hostname string `json:"hostname"`
RootDir string `json:"root_dir"`
Driver string `json:"driver"`
DriverStatus map[string]string `json:"driver_status"`
ExecDriver string `json:"exec_driver"`
NumImages int `json:"num_images"`
NumContainers int `json:"num_containers"`
}
type DockerImage struct {
ID string `json:"id"`
RepoTags []string `json:"repo_tags"` // repository name and tags.
Created int64 `json:"created"` // unix time since creation.
VirtualSize int64 `json:"virtual_size"`
Size int64 `json:"size"`
}
func (m *manager) DockerImages() ([]DockerImage, error) {
images, err := docker.DockerImages()
if err != nil {
return nil, err
}
out := []DockerImage{}
const unknownTag = "<none>:<none>"
for _, image := range images {
if len(image.RepoTags) == 1 && image.RepoTags[0] == unknownTag {
// images with repo or tags are uninteresting.
continue
}
di := DockerImage{
ID: image.ID,
RepoTags: image.RepoTags,
Created: image.Created,
VirtualSize: image.VirtualSize,
Size: image.Size,
}
out = append(out, di)
}
return out, nil
}
func (m *manager) DockerInfo() (DockerStatus, error) {
info, err := docker.DockerInfo()
if err != nil {
return DockerStatus{}, err
}
out := DockerStatus{}
out.Version = m.versionInfo.DockerVersion
if val, ok := info["KernelVersion"]; ok {
out.KernelVersion = val
}
if val, ok := info["OperatingSystem"]; ok {
out.OS = val
}
if val, ok := info["Name"]; ok {
out.Hostname = val
}
if val, ok := info["DockerRootDir"]; ok {
out.RootDir = val
}
if val, ok := info["Driver"]; ok {
out.Driver = val
}
if val, ok := info["ExecutionDriver"]; ok {
out.ExecDriver = val
}
if val, ok := info["Images"]; ok {
n, err := strconv.Atoi(val)
if err == nil {
out.NumImages = n
}
}
if val, ok := info["Containers"]; ok {
n, err := strconv.Atoi(val)
if err == nil {
out.NumContainers = n
}
}
// cut, trim, cut - Example format:
// DriverStatus=[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirperm1 Supported","false"]]
if val, ok := info["DriverStatus"]; ok {
out.DriverStatus = make(map[string]string)
val = strings.TrimPrefix(val, "[[")
val = strings.TrimSuffix(val, "]]")
vals := strings.Split(val, "],[")
for _, v := range vals {
kv := strings.Split(v, "\",\"")
if len(kv) != 2 {
continue
} else {
out.DriverStatus[strings.Trim(kv[0], "\"")] = strings.Trim(kv[1], "\"")
}
}
}
return out, nil
}

View File

@ -104,3 +104,13 @@ func (c *ManagerMock) GetProcessList(name string, options v2.RequestOptions) ([]
args := c.Called()
return args.Get(0).([]v2.ProcessInfo), args.Error(1)
}
func (c *ManagerMock) DockerInfo() (DockerStatus, error) {
args := c.Called()
return args.Get(0).(DockerStatus), args.Error(1)
}
func (c *ManagerMock) DockerImages() ([]DockerImage, error) {
args := c.Called()
return args.Get(0).([]DockerImage), args.Error(1)
}

View File

@ -427,8 +427,8 @@ function drawFileSystemUsage(machineInfo, stats) {
}
function drawProcesses(processInfo) {
var titles = ["User", "PID", "PPID", "Start Time", "CPU %", "RSS", "Virtual Size", "Status", "Running Time", "Command"];
var titleTypes = ['string', 'number', 'number', 'string', 'string', 'string', 'string', 'string', 'string', 'string'];
var titles = ["User", "PID", "PPID", "Start Time", "CPU %", "MEM %", "RSS", "Virtual Size", "Status", "Running Time", "Command"];
var titleTypes = ['string', 'number', 'number', 'string', 'string', 'string', 'string', 'string', 'string', 'string', 'string'];
var data = []
for (var i = 1; i < processInfo.length; i++) {
var elements = [];
@ -437,6 +437,7 @@ function drawProcesses(processInfo) {
elements.push(processInfo[i].parent_pid);
elements.push(processInfo[i].start_time);
elements.push(processInfo[i].percent_cpu);
elements.push(processInfo[i].percent_mem);
elements.push(processInfo[i].rss);
elements.push(processInfo[i].virtual_size);
elements.push(processInfo[i].status);

View File

@ -0,0 +1,125 @@
// Copyright 2015 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 redis
import (
"encoding/json"
redis "github.com/garyburd/redigo/redis"
info "github.com/google/cadvisor/info/v1"
storage "github.com/google/cadvisor/storage"
"sync"
"time"
)
type redisStorage struct {
conn redis.Conn
machineName string
redisKey string
bufferDuration time.Duration
lastWrite time.Time
lock sync.Mutex
readyToFlush func() bool
}
type detailSpec struct {
Timestamp int64 `json:"timestamp"`
MachineName string `json:"machine_name,omitempty"`
ContainerName string `json:"container_Name,omitempty"`
ContainerStats *info.ContainerStats `json:"container_stats,omitempty"`
}
func (self *redisStorage) defaultReadyToFlush() bool {
return time.Since(self.lastWrite) >= self.bufferDuration
}
//We must add some defaut params (for example: MachineName,ContainerName...)because containerStats do not include them
func (self *redisStorage) containerStatsAndDefautValues(ref info.ContainerReference, stats *info.ContainerStats) *detailSpec {
timestamp := stats.Timestamp.UnixNano() / 1E3
var containerName string
if len(ref.Aliases) > 0 {
containerName = ref.Aliases[0]
} else {
containerName = ref.Name
}
detail := &detailSpec{
Timestamp: timestamp,
MachineName: self.machineName,
ContainerName: containerName,
ContainerStats: stats,
}
return detail
}
//Push the data into redis
func (self *redisStorage) AddStats(ref info.ContainerReference, stats *info.ContainerStats) error {
if stats == nil {
return nil
}
var seriesToFlush []byte
func() {
// AddStats will be invoked simultaneously from multiple threads and only one of them will perform a write.
self.lock.Lock()
defer self.lock.Unlock()
// Add some defaut params based on containerStats
detail := self.containerStatsAndDefautValues(ref, stats)
//To json
b, _ := json.Marshal(detail)
if self.readyToFlush() {
seriesToFlush = b
b = nil
self.lastWrite = time.Now()
}
}()
if len(seriesToFlush) > 0 {
//We use redis's "LPUSH" to push the data to the redis
self.conn.Send("LPUSH", self.redisKey, seriesToFlush)
}
return nil
}
// We just need to push the data to the redis, do not need to pull from the redis,
//so we do not override RecentStats()
func (self *redisStorage) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
return nil, nil
}
func (self *redisStorage) Close() error {
return self.conn.Close()
}
// Create a new redis storage driver.
// machineName: A unique identifier to identify the host that runs the current cAdvisor
// instance is running on.
// redisHost: The host which runs redis.
// redisKey: The key for the Data that stored in the redis
func New(machineName,
redisKey,
redisHost string,
bufferDuration time.Duration,
) (storage.StorageDriver, error) {
conn, err := redis.Dial("tcp", redisHost)
if err != nil {
return nil, err
}
ret := &redisStorage{
conn: conn,
machineName: machineName,
redisKey: redisKey,
bufferDuration: bufferDuration,
lastWrite: time.Now(),
}
ret.readyToFlush = ret.defaultReadyToFlush
return ret, nil
}