Merge remote-tracking branch 'upstream/master'

Docker-DCO-1.1-Signed-off-by: Rohit Jnagal <jnagal@google.com> (github: rjnagal)
This commit is contained in:
Rohit Jnagal 2014-06-16 17:22:48 +00:00
commit 54fbc922a5
21 changed files with 197 additions and 36 deletions

View File

@ -1,9 +1,12 @@
language: go
go:
- 1.1
- 1.2
before_script:
- go get github.com/stretchr/testify/mock
- go get github.com/kr/pretty
script:
- go test -v -race github.com/google/cadvisor/container
- go test -v -race github.com/google/cadvisor/info
- go test -v -race github.com/google/cadvisor/client
- go test -v -race github.com/google/cadvisor/sampling
- go build -race github.com/google/cadvisor
- go test -v github.com/google/cadvisor/info
- go test -v github.com/google/cadvisor/client
- go test -v github.com/google/cadvisor/sampling
- go build github.com/google/cadvisor

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM google/golang-runtime
MAINTAINER dengnan@google.com vmarmol@google.com proppy@google.com
# TODO(vmarmol): Build from source.
# Get lmctfy and its dependencies.
RUN apt-get update -y --force-yes && apt-get install -y --no-install-recommends --force-yes pkg-config libapparmor1
ADD http://storage.googleapis.com/cadvisor-bin/lmctfy/libre2.so.0.0.0 /usr/lib/libre2.so.0
ADD http://storage.googleapis.com/cadvisor-bin/lmctfy/lmctfy /usr/bin/lmctfy
RUN chmod +x /usr/bin/lmctfy
# Install libprotobuf8.
ADD http://storage.googleapis.com/cadvisor-bin/lmctfy/libprotobuf8_2.5.0-9_amd64.deb /tmp/libprotobuf8_2.5.0-9_amd64.deb
ADD http://storage.googleapis.com/cadvisor-bin/lmctfy/libc6_2.19-1_amd64.deb /tmp/libc6_2.19-1_amd64.deb
RUN dpkg -i /tmp/libc6_2.19-1_amd64.deb /tmp/libprotobuf8_2.5.0-9_amd64.deb
# The image builds the app and exposes it on 8080.

View File

@ -25,6 +25,7 @@ import (
"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/docker"
"github.com/google/cadvisor/container/lmctfy"
"github.com/google/cadvisor/info"
"github.com/google/cadvisor/manager"
"github.com/google/cadvisor/pages"
"github.com/google/cadvisor/pages/static"
@ -92,6 +93,7 @@ func main() {
go containerManager.Start()
log.Printf("Starting cAdvisor version: %q", info.VERSION)
log.Print("About to serve on port ", *argPort)
addr := fmt.Sprintf(":%v", *argPort)

View File

@ -30,6 +30,7 @@ type ListType int
// Interface for container operation handlers.
type ContainerHandler interface {
ContainerReference() (info.ContainerReference, error)
GetSpec() (*info.ContainerSpec, error)
GetStats() (*info.ContainerStats, error)
ListContainers(listType ListType) ([]info.ContainerReference, error)

View File

@ -40,11 +40,11 @@ func (self *dockerFactory) NewContainerHandler(name string) (handler container.C
if err != nil {
return
}
handler = &dockerContainerHandler{
client: client,
name: name,
machineInfoFactory: self.machineInfoFactory,
}
handler, err = newDockerContainerHandler(
client,
name,
self.machineInfoFactory,
)
return
}

View File

@ -35,10 +35,43 @@ import (
type dockerContainerHandler struct {
client *docker.Client
name string
aliases []string
machineInfoFactory info.MachineInfoFactory
container.NoStatsSummary
}
func newDockerContainerHandler(
client *docker.Client,
name string,
machineInfoFactory info.MachineInfoFactory,
) (container.ContainerHandler, error) {
handler := &dockerContainerHandler{
client: client,
name: name,
machineInfoFactory: machineInfoFactory,
}
if !handler.isDockerContainer() {
return handler, nil
}
_, id, err := handler.splitName()
if err != nil {
return nil, fmt.Errorf("invalid docker container %v: %v", name, err)
}
ctnr, err := client.InspectContainer(id)
if err != nil {
return nil, fmt.Errorf("unable to inspect container %v: %v", name, err)
}
handler.aliases = append(handler.aliases, path.Join("/docker", ctnr.Name))
return handler, nil
}
func (self *dockerContainerHandler) ContainerReference() (info.ContainerReference, error) {
return info.ContainerReference{
Name: self.name,
Aliases: self.aliases,
}, nil
}
func (self *dockerContainerHandler) splitName() (string, string, error) {
parent, id := path.Split(self.name)
cgroupSelf, err := os.Open("/proc/self/cgroup")

View File

@ -114,7 +114,7 @@ func (self *factoryManager) NewContainerHandler(path string) (ContainerHandler,
err := fmt.Errorf("nil factory for container %v", path)
return nil, err
}
log.Printf("container handler factory for %v is %v\n", path, factory)
log.Printf("Container handler factory for %v is %v\n", path, factory)
return factory.NewContainerHandler(path)
}

View File

@ -26,6 +26,10 @@ type containerListFilter struct {
NoStatsSummary
}
func (self *containerListFilter) ContainerReference() (info.ContainerReference, error) {
return self.handler.ContainerReference()
}
func (self *containerListFilter) GetSpec() (*info.ContainerSpec, error) {
return self.handler.GetSpec()
}

View File

@ -32,6 +32,11 @@ func (self *mockContainerHandler) GetSpec() (*info.ContainerSpec, error) {
return args.Get(0).(*info.ContainerSpec), args.Error(1)
}
func (self *mockContainerHandler) ContainerReference() (info.ContainerReference, error) {
args := self.Called()
return args.Get(0).(info.ContainerReference), args.Error(1)
}
func (self *mockContainerHandler) GetStats() (*info.ContainerStats, error) {
args := self.Called()
return args.Get(0).(*info.ContainerStats), args.Error(1)

View File

@ -47,6 +47,10 @@ func New(name string) (container.ContainerHandler, error) {
return el, nil
}
func (self *lmctfyContainerHandler) ContainerReference() (info.ContainerReference, error) {
return info.ContainerReference{Name: self.Name}, nil
}
func getExitCode(err error) int {
msg, ok := err.(*exec.ExitError)
if ok {

View File

@ -1,3 +1,17 @@
// 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 container
import (

View File

@ -36,6 +36,10 @@ func (self *percentilesContainerHandlerWrapper) GetSpec() (*info.ContainerSpec,
return self.handler.GetSpec()
}
func (self *percentilesContainerHandlerWrapper) ContainerReference() (info.ContainerReference, error) {
return self.handler.ContainerReference()
}
func (self *percentilesContainerHandlerWrapper) updatePrevStats(stats *info.ContainerStats) {
if stats == nil || stats.Cpu == nil || stats.Memory == nil {
// discard incomplete stats

View File

@ -94,6 +94,12 @@ func containerWithTrace(duration time.Duration, cpuUsages []uint64, memUsages []
}
}
func (self *replayTrace) ContainerReference() (info.ContainerReference, error) {
return info.ContainerReference{
Name: "replay",
}, nil
}
func (self *replayTrace) GetStats() (*info.ContainerStats, error) {
stats := new(info.ContainerStats)
stats.Cpu = new(info.CpuStats)

18
info/version.go Normal file
View File

@ -0,0 +1,18 @@
// 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 info
// Version of cAdvisor.
const VERSION = "0.1.0"

View File

@ -91,7 +91,12 @@ func NewContainerData(containerName string) (*containerData, error) {
return nil, err
}
cont.handler = handler
cont.info.Name = containerName
ref, err := handler.ContainerReference()
if err != nil {
return nil, err
}
cont.info.Name = ref.Name
cont.info.Aliases = ref.Aliases
cont.info.Stats = list.New()
cont.stop = make(chan bool, 1)

View File

@ -124,7 +124,8 @@ func (m *manager) GetContainerInfo(containerName string) (*info.ContainerInfo, e
// Make a copy of the info for the user.
ret := &info.ContainerInfo{
ContainerReference: info.ContainerReference{
Name: cinfo.Name,
Name: cinfo.Name,
Aliases: cinfo.Aliases,
},
Subcontainers: cinfo.Subcontainers,
Spec: cinfo.Spec,
@ -169,9 +170,13 @@ func (m *manager) createContainer(containerName string) (*containerData, error)
m.containersLock.Lock()
defer m.containersLock.Unlock()
log.Printf("Added container: %s", containerName)
// Add the container name and all its aliases.
m.containers[containerName] = cont
for _, alias := range cont.info.Aliases {
m.containers[alias] = cont
}
}()
log.Printf("Added container: %s (aliases: %s)", containerName, cont.info.Aliases)
// Start the container's housekeeping.
cont.Start()
@ -193,9 +198,12 @@ func (m *manager) destroyContainer(containerName string) error {
return err
}
// Remove the container from our records.
// Remove the container from our records (and all its aliases).
delete(m.containers, containerName)
log.Printf("Destroyed container: %s", containerName)
for _, alias := range cont.info.Aliases {
delete(m.containers, alias)
}
log.Printf("Destroyed container: %s (aliases: %s)", containerName, cont.info.Aliases)
return nil
}
@ -219,7 +227,10 @@ func (m *manager) getContainersDiff() (added []info.ContainerReference, removed
// Determine which were added and which were removed.
allContainersSet := make(map[string]*containerData)
for name, d := range m.containers {
allContainersSet[name] = d
// Only add the canonical name.
if d.info.Name == name {
allContainersSet[name] = d
}
}
for _, c := range allContainers {
delete(allContainersSet, c.Name)

View File

@ -37,7 +37,6 @@ var funcMap = template.FuncMap{
"printMask": printMask,
"printCores": printCores,
"printMegabytes": printMegabytes,
"containerNameEquals": containerNameEquals,
"getMemoryUsage": getMemoryUsage,
"getMemoryUsagePercent": getMemoryUsagePercent,
"getHotMemoryPercent": getHotMemoryPercent,
@ -85,10 +84,6 @@ func containerLink(container info.ContainerReference, basenameOnly bool, cssClas
return template.HTML(fmt.Sprintf("<a class=\"%s\" href=\"%s%s\">%s</a>", cssClasses, ContainersPage[:len(ContainersPage)-1], containerName, displayName))
}
func containerNameEquals(c1 string, c2 string) bool {
return c1 == c2
}
func printMask(mask *info.CpuSpecMask, numCores int) interface{} {
// TODO(vmarmol): Detect this correctly.
// TODO(vmarmol): Support more than 64 cores.
@ -130,25 +125,31 @@ func printMegabytes(bytes uint64) string {
return strconv.FormatFloat(megabytes, 'f', 3, 64)
}
func toMemoryPercent(usage uint64, spec *info.ContainerSpec) int {
return int((usage * 100) / (spec.Memory.Limit))
func toMemoryPercent(usage uint64, spec *info.ContainerSpec, machine *info.MachineInfo) int {
// Saturate limit to the machine size.
limit := uint64(spec.Memory.Limit)
if limit > uint64(machine.MemoryCapacity) {
limit = uint64(machine.MemoryCapacity)
}
return int((usage * 100) / limit)
}
func getMemoryUsage(stats []*info.ContainerStats) string {
return strconv.FormatFloat(toMegabytes((stats[len(stats)-1].Memory.Usage)), 'f', 2, 64)
}
func getMemoryUsagePercent(spec *info.ContainerSpec, stats []*info.ContainerStats) int {
return toMemoryPercent((stats[len(stats)-1].Memory.Usage), spec)
func getMemoryUsagePercent(spec *info.ContainerSpec, stats []*info.ContainerStats, machine *info.MachineInfo) int {
return toMemoryPercent((stats[len(stats)-1].Memory.Usage), spec, machine)
}
func getHotMemoryPercent(spec *info.ContainerSpec, stats []*info.ContainerStats) int {
return toMemoryPercent((stats[len(stats)-1].Memory.WorkingSet), spec)
func getHotMemoryPercent(spec *info.ContainerSpec, stats []*info.ContainerStats, machine *info.MachineInfo) int {
return toMemoryPercent((stats[len(stats)-1].Memory.WorkingSet), spec, machine)
}
func getColdMemoryPercent(spec *info.ContainerSpec, stats []*info.ContainerStats) int {
func getColdMemoryPercent(spec *info.ContainerSpec, stats []*info.ContainerStats, machine *info.MachineInfo) int {
latestStats := stats[len(stats)-1].Memory
return toMemoryPercent((latestStats.Usage)-(latestStats.WorkingSet), spec)
return toMemoryPercent((latestStats.Usage)-(latestStats.WorkingSet), spec, machine)
}
func ServerContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {

View File

@ -132,16 +132,16 @@ const containersHtmlTemplate = `
<h4>Usage Breakdown</h4>
<div class="col-sm-9">
<div class="progress">
<div class="progress-bar progress-bar-danger" style="width: {{getHotMemoryPercent .Spec .Stats}}%">
<div class="progress-bar progress-bar-danger" style="width: {{getHotMemoryPercent .Spec .Stats .MachineInfo}}%">
<span class="sr-only">Hot Memory</span>
</div>
<div class="progress-bar progress-bar-info" style="width: {{getColdMemoryPercent .Spec .Stats}}%">
<div class="progress-bar progress-bar-info" style="width: {{getColdMemoryPercent .Spec .Stats .MachineInfo}}%">
<span class="sr-only">Cold Memory</span>
</div>
</div>
</div>
<div class="col-sm-3">
{{ getMemoryUsage .Stats }} MB ({{ getMemoryUsagePercent .Spec .Stats }}%)
{{ getMemoryUsage .Stats }} MB ({{ getMemoryUsagePercent .Spec .Stats .MachineInfo}}%)
</div>
</div>
<h4>Page Faults</h4>

View File

@ -154,7 +154,7 @@ function drawCpuUsageBreakdown(elementId, containerInfo) {
}
// Draw the gauges for overall resource usage.
function drawOverallUsage(elementId, containerInfo) {
function drawOverallUsage(elementId, machineInfo, containerInfo) {
var cur = containerInfo.stats[containerInfo.stats.length - 1];
var cpuUsage = 0;
@ -171,7 +171,13 @@ function drawOverallUsage(elementId, containerInfo) {
var memoryUsage = 0;
if (containerInfo.spec.memory) {
memoryUsage = Math.round((cur.memory.usage / containerInfo.spec.memory.limit) * 100);
// Saturate to the machine size.
var limit = containerInfo.spec.memory.limit;
if (limit > machineInfo.memory_capacity) {
limit = machineInfo.memory_capacity;
}
memoryUsage = Math.round((cur.memory.usage / limit) * 100);
}
drawGauge(elementId, cpuUsage, memoryUsage);
@ -236,7 +242,7 @@ function drawCharts(machineInfo, containerInfo) {
var steps = [];
steps.push(function() {
drawOverallUsage("usage-gauge", containerInfo)
drawOverallUsage("usage-gauge", machineInfo, containerInfo)
});
// CPU.

View File

@ -1,3 +1,17 @@
// 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 sampling
import (

View File

@ -1,3 +1,17 @@
// 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 sampling
import "testing"