mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-10-29 12:49:55 +00:00
Move deps from _workspace/ to vendor/
godep restore pushd $GOPATH/src/github.com/appc/spec git co master popd go get go4.org/errorutil rm -rf Godeps godep save ./... git add vendor git add -f $(git ls-files --other vendor/) git co -- Godeps/LICENSES Godeps/.license_file_state Godeps/OWNERS
This commit is contained in:
251
vendor/github.com/google/cadvisor/pages/containers.go
generated
vendored
Normal file
251
vendor/github.com/google/cadvisor/pages/containers.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
// 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.
|
||||
|
||||
// Page for /containers/
|
||||
package pages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/manager"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const ContainersPage = "/containers/"
|
||||
|
||||
// from http://golang.org/doc/effective_go.html#constants
|
||||
type ByteSize float64
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
// KB - kilobyte
|
||||
KB ByteSize = 1 << (10 * iota)
|
||||
// MB - megabyte
|
||||
MB
|
||||
// GB - gigabyte
|
||||
GB
|
||||
// TB - terabyte
|
||||
TB
|
||||
// PB - petabyte
|
||||
PB
|
||||
// EB - exabyte
|
||||
EB
|
||||
// ZB - zettabyte
|
||||
ZB
|
||||
// YB - yottabyte
|
||||
YB
|
||||
)
|
||||
|
||||
func (b ByteSize) Size() string {
|
||||
for _, i := range [...]ByteSize{YB, ZB, EB, PB, TB, GB, MB, KB} {
|
||||
if b >= i {
|
||||
return fmt.Sprintf("%.2f", b/i)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%.2f", b)
|
||||
}
|
||||
|
||||
func (b ByteSize) Unit() string {
|
||||
switch {
|
||||
case b >= YB:
|
||||
return "YB"
|
||||
case b >= ZB:
|
||||
return "ZB"
|
||||
case b >= EB:
|
||||
return "EB"
|
||||
case b >= PB:
|
||||
return "PB"
|
||||
case b >= TB:
|
||||
return "TB"
|
||||
case b >= GB:
|
||||
return "GB"
|
||||
case b >= MB:
|
||||
return "MB"
|
||||
case b >= KB:
|
||||
return "KB"
|
||||
}
|
||||
return "B"
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"printMask": printMask,
|
||||
"printCores": printCores,
|
||||
"printShares": printShares,
|
||||
"printSize": printSize,
|
||||
"printUnit": printUnit,
|
||||
}
|
||||
|
||||
func printMask(mask string, numCores int) interface{} {
|
||||
masks := make([]string, numCores)
|
||||
activeCores := getActiveCores(mask)
|
||||
for i := 0; i < numCores; i++ {
|
||||
coreClass := "inactive-cpu"
|
||||
if activeCores[i] {
|
||||
coreClass = "active-cpu"
|
||||
}
|
||||
masks[i] = fmt.Sprintf("<span class=\"%s\">%d</span>", coreClass, i)
|
||||
}
|
||||
return template.HTML(strings.Join(masks, " "))
|
||||
}
|
||||
|
||||
func getActiveCores(mask string) map[int]bool {
|
||||
activeCores := make(map[int]bool)
|
||||
for _, corebits := range strings.Split(mask, ",") {
|
||||
cores := strings.Split(corebits, "-")
|
||||
if len(cores) == 1 {
|
||||
index, err := strconv.Atoi(cores[0])
|
||||
if err != nil {
|
||||
// Ignore malformed strings.
|
||||
continue
|
||||
}
|
||||
activeCores[index] = true
|
||||
} else if len(cores) == 2 {
|
||||
start, err := strconv.Atoi(cores[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
end, err := strconv.Atoi(cores[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for i := start; i <= end; i++ {
|
||||
activeCores[i] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return activeCores
|
||||
}
|
||||
|
||||
func printCores(millicores *uint64) string {
|
||||
cores := float64(*millicores) / 1000
|
||||
return strconv.FormatFloat(cores, 'f', 3, 64)
|
||||
}
|
||||
|
||||
func printShares(shares *uint64) string {
|
||||
return fmt.Sprintf("%d", *shares)
|
||||
}
|
||||
|
||||
// Size after which we consider memory to be "unlimited". This is not
|
||||
// MaxInt64 due to rounding by the kernel.
|
||||
const maxMemorySize = uint64(1 << 62)
|
||||
|
||||
func printSize(bytes uint64) string {
|
||||
if bytes >= maxMemorySize {
|
||||
return "unlimited"
|
||||
}
|
||||
return ByteSize(bytes).Size()
|
||||
}
|
||||
|
||||
func printUnit(bytes uint64) string {
|
||||
if bytes >= maxMemorySize {
|
||||
return ""
|
||||
}
|
||||
return ByteSize(bytes).Unit()
|
||||
}
|
||||
|
||||
func serveContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
|
||||
start := time.Now()
|
||||
|
||||
// The container name is the path after the handler
|
||||
containerName := u.Path[len(ContainersPage)-1:]
|
||||
|
||||
// Get the container.
|
||||
reqParams := info.ContainerInfoRequest{
|
||||
NumStats: 60,
|
||||
}
|
||||
cont, err := m.GetContainerInfo(containerName, &reqParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
|
||||
}
|
||||
displayName := getContainerDisplayName(cont.ContainerReference)
|
||||
|
||||
// Get the MachineInfo
|
||||
machineInfo, err := m.GetMachineInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rootDir := getRootDir(containerName)
|
||||
|
||||
// Make a list of the parent containers and their links
|
||||
pathParts := strings.Split(string(cont.Name), "/")
|
||||
parentContainers := make([]link, 0, len(pathParts))
|
||||
parentContainers = append(parentContainers, link{
|
||||
Text: "root",
|
||||
Link: path.Join(rootDir, ContainersPage),
|
||||
})
|
||||
for i := 1; i < len(pathParts); i++ {
|
||||
// Skip empty parts.
|
||||
if pathParts[i] == "" {
|
||||
continue
|
||||
}
|
||||
parentContainers = append(parentContainers, link{
|
||||
Text: pathParts[i],
|
||||
Link: path.Join(rootDir, ContainersPage, path.Join(pathParts[1:i+1]...)),
|
||||
})
|
||||
}
|
||||
|
||||
// Build the links for the subcontainers.
|
||||
subcontainerLinks := make([]link, 0, len(cont.Subcontainers))
|
||||
for _, sub := range cont.Subcontainers {
|
||||
if !m.Exists(sub.Name) {
|
||||
continue
|
||||
}
|
||||
subcontainerLinks = append(subcontainerLinks, link{
|
||||
Text: getContainerDisplayName(sub),
|
||||
Link: path.Join(rootDir, ContainersPage, sub.Name),
|
||||
})
|
||||
}
|
||||
|
||||
data := &pageData{
|
||||
DisplayName: displayName,
|
||||
ContainerName: escapeContainerName(cont.Name),
|
||||
ParentContainers: parentContainers,
|
||||
Subcontainers: subcontainerLinks,
|
||||
Spec: cont.Spec,
|
||||
Stats: cont.Stats,
|
||||
MachineInfo: machineInfo,
|
||||
IsRoot: cont.Name == "/",
|
||||
ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork || cont.Spec.HasFilesystem,
|
||||
CpuAvailable: cont.Spec.HasCpu,
|
||||
MemoryAvailable: cont.Spec.HasMemory,
|
||||
NetworkAvailable: cont.Spec.HasNetwork,
|
||||
FsAvailable: cont.Spec.HasFilesystem,
|
||||
CustomMetricsAvailable: cont.Spec.HasCustomMetrics,
|
||||
Root: rootDir,
|
||||
}
|
||||
err = pageTemplate.Execute(w, data)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to apply template: %s", err)
|
||||
}
|
||||
|
||||
glog.V(5).Infof("Request took %s", time.Since(start))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build a relative path to the root of the container page.
|
||||
func getRootDir(containerName string) string {
|
||||
// The root is at: container depth
|
||||
levels := (strings.Count(containerName, "/"))
|
||||
return strings.Repeat("../", levels)
|
||||
}
|
||||
243
vendor/github.com/google/cadvisor/pages/containers_html.go
generated
vendored
Normal file
243
vendor/github.com/google/cadvisor/pages/containers_html.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
// 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 pages
|
||||
|
||||
const containersHtmlTemplate = `
|
||||
<html>
|
||||
<head>
|
||||
<title>cAdvisor - {{.DisplayName}}</title>
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="{{.Root}}static/bootstrap-3.1.1.min.css">
|
||||
|
||||
<!-- Optional theme -->
|
||||
<link rel="stylesheet" href="{{.Root}}static/bootstrap-theme-3.1.1.min.css">
|
||||
|
||||
<link rel="stylesheet" href="{{.Root}}static/containers.css">
|
||||
|
||||
<!-- Latest compiled and minified JavaScript -->
|
||||
<script src="{{.Root}}static/jquery-1.10.2.min.js"></script>
|
||||
<script src="{{.Root}}static/bootstrap-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="{{.Root}}static/google-jsapi.js"></script>
|
||||
|
||||
<script type="text/javascript" src="{{.Root}}static/containers.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container theme-showcase" >
|
||||
<a href="{{.Root}}" class="col-sm-12" id="logo">
|
||||
</a>
|
||||
<div class="col-sm-12">
|
||||
<div class="page-header">
|
||||
<h1>{{.DisplayName}}</h1>
|
||||
</div>
|
||||
<ol class="breadcrumb">
|
||||
{{range $parentContainer := .ParentContainers}}
|
||||
<li><a href="{{$parentContainer.Link}}">{{$parentContainer.Text}}</a></li>
|
||||
{{end}}
|
||||
</ol>
|
||||
</div>
|
||||
{{if .IsRoot}}
|
||||
<div class="col-sm-12">
|
||||
<h4><a href="../docker">Docker Containers</a></h4>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .Subcontainers}}
|
||||
<div class="col-sm-12">
|
||||
<div class="page-header">
|
||||
<h3>Subcontainers</h3>
|
||||
</div>
|
||||
<div class="list-group">
|
||||
{{range $subcontainer := .Subcontainers}}
|
||||
<a href="{{$subcontainer.Link}}" class="list-group-item">{{$subcontainer.Text}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .DockerStatus}}
|
||||
<div class="col-sm-12">
|
||||
<div class="page-header">
|
||||
<h3>Driver Status</h3>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
{{range $dockerstatus := .DockerStatus}}
|
||||
<li class ="list-group-item"><span class="stat-label">{{$dockerstatus.Key}}</span> {{$dockerstatus.Value}}</li>
|
||||
{{end}}
|
||||
{{if .DockerDriverStatus}}
|
||||
<li class ="list-group-item"><span class="stat-label">Storage<br></span>
|
||||
<ul class="list-group">
|
||||
{{range $driverstatus := .DockerDriverStatus}}
|
||||
<li class="list-group-item"><span class="stat-label">{{$driverstatus.Key}}</span> {{$driverstatus.Value}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .DockerImages}}
|
||||
<div class="col-sm-12">
|
||||
<div class="page-header">
|
||||
<h3>Images</h3>
|
||||
</div>
|
||||
<div id="docker-images"></div>
|
||||
<br><br>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .ResourcesAvailable}}
|
||||
<div class="col-sm-12">
|
||||
<div class="page-header">
|
||||
<h3>Isolation</h3>
|
||||
</div>
|
||||
{{if .CpuAvailable}}
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item active isolation-title panel-title">CPU</li>
|
||||
{{if .Spec.Cpu.Limit}}
|
||||
<li class="list-group-item"><span class="stat-label">Shares</span> {{printShares .Spec.Cpu.Limit}} <span class="unit-label">shares</span></li>
|
||||
{{end}}
|
||||
{{if .Spec.Cpu.MaxLimit}}
|
||||
<li class="list-group-item"><span class="stat-label">Max Limit</span> {{printCores .Spec.Cpu.MaxLimit}} <span class="unit-label">cores</span></li>
|
||||
{{end}}
|
||||
{{if .Spec.Cpu.Mask}}
|
||||
<li class="list-group-item"><span class="stat-label">Allowed Cores</span> {{printMask .Spec.Cpu.Mask .MachineInfo.NumCores}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
{{if .MemoryAvailable}}
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item active isolation-title panel-title">Memory</li>
|
||||
{{if .Spec.Memory.Reservation}}
|
||||
<li class="list-group-item"><span class="stat-label">Reservation</span> {{printSize .Spec.Memory.Reservation}} <span class="unit-label">{{printUnit .Spec.Memory.Reservation}}</span></li>
|
||||
{{end}}
|
||||
{{if .Spec.Memory.Limit}}
|
||||
<li class="list-group-item"><span class="stat-label">Limit</span> {{printSize .Spec.Memory.Limit}} <span class="unit-label">{{printUnit .Spec.Memory.Limit}}</span></li>
|
||||
{{end}}
|
||||
{{if .Spec.Memory.SwapLimit}}
|
||||
<li class="list-group-item"><span class="stat-label">Swap Limit</span> {{printSize .Spec.Memory.SwapLimit}} <span class="unit-label">{{printUnit .Spec.Memory.SwapLimit}}</span></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="page-header">
|
||||
<h3>Usage</h3>
|
||||
</div>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Overview</h3>
|
||||
</div>
|
||||
<div id="usage-gauge" class="panel-body"></div>
|
||||
</div>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Processes</h3>
|
||||
</div>
|
||||
<div id="processes-top" class="panel-body"></div>
|
||||
</div>
|
||||
{{if .CpuAvailable}}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">CPU</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h4>Total Usage</h4>
|
||||
<div id="cpu-total-usage-chart"></div>
|
||||
<!-- <h4>CPU Load Average</h4>
|
||||
<div id="cpu-load-chart"></div> -->
|
||||
<h4>Usage per Core</h4>
|
||||
<div id="cpu-per-core-usage-chart"></div>
|
||||
<h4>Usage Breakdown</h4>
|
||||
<div id="cpu-usage-breakdown-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .MemoryAvailable}}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Memory</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h4>Total Usage</h4>
|
||||
<div id="memory-usage-chart"></div>
|
||||
<br/>
|
||||
<div class="row col-sm-12">
|
||||
<h4>Usage Breakdown</h4>
|
||||
<div class="col-sm-9">
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-danger" id="progress-hot-memory">
|
||||
<span class="sr-only">Hot Memory</span>
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-info" id="progress-cold-memory">
|
||||
<span class="sr-only">Cold Memory</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3" id="memory-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .NetworkAvailable}}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Network</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-default dropdown-toggle" type="button" id="network-selection-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span id="network-selection-text"></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul id="network-selection" class="dropdown-menu" role="menu" aria-labelledby="network-selection-dropdown">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h4>Throughput</h4>
|
||||
<div id="network-bytes-chart"></div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h4>Errors</h4>
|
||||
<div id="network-errors-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .FsAvailable}}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Filesystem</h3>
|
||||
</div>
|
||||
<div id="filesystem-usage" class="panel-body">
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .CustomMetricsAvailable}}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Application Metrics</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="custom-metrics-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
startPage({{.ContainerName}}, {{.CpuAvailable}}, {{.MemoryAvailable}}, {{.Root}}, {{.IsRoot}});
|
||||
drawImages({{.DockerImages}});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
156
vendor/github.com/google/cadvisor/pages/docker.go
generated
vendored
Normal file
156
vendor/github.com/google/cadvisor/pages/docker.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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 pages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/container/docker"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/manager"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const DockerPage = "/docker/"
|
||||
|
||||
func toStatusKV(status manager.DockerStatus) ([]keyVal, []keyVal) {
|
||||
ds := []keyVal{
|
||||
{Key: "Driver", Value: status.Driver},
|
||||
}
|
||||
for k, v := range status.DriverStatus {
|
||||
ds = append(ds, keyVal{Key: k, Value: v})
|
||||
}
|
||||
return []keyVal{
|
||||
{Key: "Docker Version", Value: status.Version},
|
||||
{Key: "Kernel Version", Value: status.KernelVersion},
|
||||
{Key: "OS Version", Value: status.OS},
|
||||
{Key: "Host Name", Value: status.Hostname},
|
||||
{Key: "Docker Root Directory", Value: status.RootDir},
|
||||
{Key: "Execution Driver", Value: status.ExecDriver},
|
||||
{Key: "Number of Images", Value: strconv.Itoa(status.NumImages)},
|
||||
{Key: "Number of Containers", Value: strconv.Itoa(status.NumContainers)},
|
||||
}, ds
|
||||
}
|
||||
|
||||
func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
|
||||
start := time.Now()
|
||||
|
||||
// The container name is the path after the handler
|
||||
containerName := u.Path[len(DockerPage)-1:]
|
||||
rootDir := getRootDir(containerName)
|
||||
|
||||
var data *pageData
|
||||
if containerName == "/" {
|
||||
// Get the containers.
|
||||
reqParams := info.ContainerInfoRequest{
|
||||
NumStats: 0,
|
||||
}
|
||||
conts, err := m.AllDockerContainers(&reqParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
|
||||
}
|
||||
subcontainers := make([]link, 0, len(conts))
|
||||
for _, cont := range conts {
|
||||
subcontainers = append(subcontainers, link{
|
||||
Text: getContainerDisplayName(cont.ContainerReference),
|
||||
Link: path.Join(rootDir, DockerPage, docker.ContainerNameToDockerId(cont.ContainerReference.Name)),
|
||||
})
|
||||
}
|
||||
|
||||
// Get Docker status
|
||||
status, err := m.DockerInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dockerStatus, driverStatus := toStatusKV(status)
|
||||
// Get Docker Images
|
||||
images, err := m.DockerImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dockerContainersText := "Docker Containers"
|
||||
data = &pageData{
|
||||
DisplayName: dockerContainersText,
|
||||
ParentContainers: []link{
|
||||
{
|
||||
Text: dockerContainersText,
|
||||
Link: path.Join(rootDir, DockerPage),
|
||||
}},
|
||||
Subcontainers: subcontainers,
|
||||
Root: rootDir,
|
||||
DockerStatus: dockerStatus,
|
||||
DockerDriverStatus: driverStatus,
|
||||
DockerImages: images,
|
||||
}
|
||||
} else {
|
||||
// Get the container.
|
||||
reqParams := info.ContainerInfoRequest{
|
||||
NumStats: 60,
|
||||
}
|
||||
cont, err := m.DockerContainer(containerName[1:], &reqParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
|
||||
}
|
||||
displayName := getContainerDisplayName(cont.ContainerReference)
|
||||
|
||||
// Make a list of the parent containers and their links
|
||||
var parentContainers []link
|
||||
parentContainers = append(parentContainers, link{
|
||||
Text: "Docker Containers",
|
||||
Link: path.Join(rootDir, DockerPage),
|
||||
})
|
||||
parentContainers = append(parentContainers, link{
|
||||
Text: displayName,
|
||||
Link: path.Join(rootDir, DockerPage, docker.ContainerNameToDockerId(cont.Name)),
|
||||
})
|
||||
|
||||
// Get the MachineInfo
|
||||
machineInfo, err := m.GetMachineInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = &pageData{
|
||||
DisplayName: displayName,
|
||||
ContainerName: escapeContainerName(cont.Name),
|
||||
ParentContainers: parentContainers,
|
||||
Spec: cont.Spec,
|
||||
Stats: cont.Stats,
|
||||
MachineInfo: machineInfo,
|
||||
ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork,
|
||||
CpuAvailable: cont.Spec.HasCpu,
|
||||
MemoryAvailable: cont.Spec.HasMemory,
|
||||
NetworkAvailable: cont.Spec.HasNetwork,
|
||||
FsAvailable: cont.Spec.HasFilesystem,
|
||||
CustomMetricsAvailable: cont.Spec.HasCustomMetrics,
|
||||
Root: rootDir,
|
||||
}
|
||||
}
|
||||
|
||||
err := pageTemplate.Execute(w, data)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to apply template: %s", err)
|
||||
}
|
||||
|
||||
glog.V(5).Infof("Request took %s", time.Since(start))
|
||||
return nil
|
||||
}
|
||||
173
vendor/github.com/google/cadvisor/pages/pages.go
generated
vendored
Normal file
173
vendor/github.com/google/cadvisor/pages/pages.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
// 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 pages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
httpmux "github.com/google/cadvisor/http/mux"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/manager"
|
||||
|
||||
auth "github.com/abbot/go-http-auth"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
var pageTemplate *template.Template
|
||||
|
||||
type link struct {
|
||||
// Text to show in the link.
|
||||
Text string
|
||||
|
||||
// Web address to link to.
|
||||
Link string
|
||||
}
|
||||
|
||||
type keyVal struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
type pageData struct {
|
||||
DisplayName string
|
||||
ContainerName string
|
||||
ParentContainers []link
|
||||
Subcontainers []link
|
||||
Spec info.ContainerSpec
|
||||
Stats []*info.ContainerStats
|
||||
MachineInfo *info.MachineInfo
|
||||
IsRoot bool
|
||||
ResourcesAvailable bool
|
||||
CpuAvailable bool
|
||||
MemoryAvailable bool
|
||||
NetworkAvailable bool
|
||||
FsAvailable bool
|
||||
CustomMetricsAvailable bool
|
||||
Root string
|
||||
DockerStatus []keyVal
|
||||
DockerDriverStatus []keyVal
|
||||
DockerImages []manager.DockerImage
|
||||
}
|
||||
|
||||
func init() {
|
||||
pageTemplate = template.New("containersTemplate").Funcs(funcMap)
|
||||
_, err := pageTemplate.Parse(containersHtmlTemplate)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to parse template: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func containerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
err := serveContainersPage(containerManager, w, r.URL)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func containerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
|
||||
return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
|
||||
err := serveContainersPage(containerManager, w, r.URL)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dockerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
err := serveDockerPage(containerManager, w, r.URL)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dockerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
|
||||
return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
|
||||
err := serveDockerPage(containerManager, w, r.URL)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register http handlers
|
||||
func RegisterHandlersDigest(mux httpmux.Mux, containerManager manager.Manager, authenticator *auth.DigestAuth) error {
|
||||
// Register the handler for the containers page.
|
||||
if authenticator != nil {
|
||||
mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
|
||||
mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
|
||||
} else {
|
||||
mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
|
||||
mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RegisterHandlersBasic(mux httpmux.Mux, containerManager manager.Manager, authenticator *auth.BasicAuth) error {
|
||||
// Register the handler for the containers and docker age.
|
||||
if authenticator != nil {
|
||||
mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
|
||||
mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
|
||||
} else {
|
||||
mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
|
||||
mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getContainerDisplayName(cont info.ContainerReference) string {
|
||||
// Pick a user-added alias as display name.
|
||||
displayName := ""
|
||||
for _, alias := range cont.Aliases {
|
||||
// ignore container id as alias.
|
||||
if strings.Contains(cont.Name, alias) {
|
||||
continue
|
||||
}
|
||||
// pick shortest display name if multiple aliases are available.
|
||||
if displayName == "" || len(displayName) >= len(alias) {
|
||||
displayName = alias
|
||||
}
|
||||
}
|
||||
|
||||
if displayName == "" {
|
||||
displayName = cont.Name
|
||||
} else if len(displayName) > 50 {
|
||||
// truncate display name to fit in one line.
|
||||
displayName = displayName[:50] + "..."
|
||||
}
|
||||
|
||||
// Add the full container name to the display name.
|
||||
if displayName != cont.Name {
|
||||
displayName = fmt.Sprintf("%s (%s)", displayName, cont.Name)
|
||||
}
|
||||
|
||||
return displayName
|
||||
}
|
||||
|
||||
// Escape the non-path characters on a container name.
|
||||
func escapeContainerName(containerName string) string {
|
||||
parts := strings.Split(containerName, "/")
|
||||
for i := range parts {
|
||||
parts[i] = url.QueryEscape(parts[i])
|
||||
}
|
||||
return strings.Join(parts, "/")
|
||||
}
|
||||
25
vendor/github.com/google/cadvisor/pages/static/bootstrap_min_css.go
generated
vendored
Normal file
25
vendor/github.com/google/cadvisor/pages/static/bootstrap_min_css.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
24
vendor/github.com/google/cadvisor/pages/static/bootstrap_min_js.go
generated
vendored
Normal file
24
vendor/github.com/google/cadvisor/pages/static/bootstrap_min_js.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
25
vendor/github.com/google/cadvisor/pages/static/bootstrap_theme_min_css.go
generated
vendored
Normal file
25
vendor/github.com/google/cadvisor/pages/static/bootstrap_theme_min_css.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
61
vendor/github.com/google/cadvisor/pages/static/containers_css.go
generated
vendored
Normal file
61
vendor/github.com/google/cadvisor/pages/static/containers_css.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
881
vendor/github.com/google/cadvisor/pages/static/containers_js.go
generated
vendored
Normal file
881
vendor/github.com/google/cadvisor/pages/static/containers_js.go
generated
vendored
Normal file
@@ -0,0 +1,881 @@
|
||||
// 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 static
|
||||
|
||||
const containersJs = gchartsJs + `
|
||||
function humanize(num, size, units) {
|
||||
var unit;
|
||||
for (unit = units.pop(); units.length && num >= size; unit = units.pop()) {
|
||||
num /= size;
|
||||
}
|
||||
return [num, unit];
|
||||
}
|
||||
|
||||
// Following the IEC naming convention
|
||||
function humanizeIEC(num) {
|
||||
var ret = humanize(num, 1024, ["TiB", "GiB", "MiB", "KiB", "B"]);
|
||||
return ret[0].toFixed(2) + " " + ret[1];
|
||||
}
|
||||
// Following the Metric naming convention
|
||||
function humanizeMetric(num) {
|
||||
var ret = humanize(num, 1000, ["TB", "GB", "MB", "KB", "Bytes"]);
|
||||
return ret[0].toFixed(2) + " " + ret[1];
|
||||
}
|
||||
|
||||
// Draw a table.
|
||||
function drawTable(seriesTitles, titleTypes, data, elementId, numPages, sortIndex) {
|
||||
var dataTable = new google.visualization.DataTable();
|
||||
for (var i = 0; i < seriesTitles.length; i++) {
|
||||
dataTable.addColumn(titleTypes[i], seriesTitles[i]);
|
||||
}
|
||||
dataTable.addRows(data);
|
||||
if (!(elementId in window.charts)) {
|
||||
window.charts[elementId] = new google.visualization.Table(document.getElementById(elementId));
|
||||
}
|
||||
|
||||
var cssClassNames = {
|
||||
'headerRow': '',
|
||||
'tableRow': 'table-row',
|
||||
'oddTableRow': 'table-row'
|
||||
};
|
||||
var opts = {
|
||||
alternatingRowStyle: true,
|
||||
page: 'enable',
|
||||
pageSize: numPages,
|
||||
allowHtml: true,
|
||||
sortColumn: sortIndex,
|
||||
sortAscending: false,
|
||||
cssClassNames: cssClassNames,
|
||||
};
|
||||
window.charts[elementId].draw(dataTable, opts);
|
||||
}
|
||||
|
||||
// Draw a line chart.
|
||||
function drawLineChart(seriesTitles, data, elementId, unit) {
|
||||
var min = Infinity;
|
||||
var max = -Infinity;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
// Convert the first column to a Date.
|
||||
if (data[i] != null) {
|
||||
data[i][0] = new Date(data[i][0]);
|
||||
}
|
||||
|
||||
// Find min, max.
|
||||
for (var j = 1; j < data[i].length; j++) {
|
||||
var val = data[i][j];
|
||||
if (val < min) {
|
||||
min = val;
|
||||
}
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want to show any values less than 0 so cap the min value at that.
|
||||
// At the same time, show 10% of the graph below the min value if we can.
|
||||
var minWindow = min - (max - min) / 10;
|
||||
if (minWindow < 0) {
|
||||
minWindow = 0;
|
||||
}
|
||||
|
||||
// Add the definition of each column and the necessary data.
|
||||
var dataTable = new google.visualization.DataTable();
|
||||
dataTable.addColumn('datetime', seriesTitles[0]);
|
||||
for (var i = 1; i < seriesTitles.length; i++) {
|
||||
dataTable.addColumn('number', seriesTitles[i]);
|
||||
}
|
||||
dataTable.addRows(data);
|
||||
|
||||
// Create and draw the visualization.
|
||||
if (!(elementId in window.charts)) {
|
||||
window.charts[elementId] = new google.visualization.LineChart(document.getElementById(elementId));
|
||||
}
|
||||
|
||||
// TODO(vmarmol): Look into changing the view window to get a smoother animation.
|
||||
var opts = {
|
||||
curveType: 'function',
|
||||
height: 300,
|
||||
legend:{position:"none"},
|
||||
focusTarget: "category",
|
||||
vAxis: {
|
||||
title: unit,
|
||||
viewWindow: {
|
||||
min: minWindow,
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
},
|
||||
};
|
||||
// If the whole data series has the same value, try to center it in the chart.
|
||||
if ( min == max) {
|
||||
opts.vAxis.viewWindow.max = 1.1 * max
|
||||
opts.vAxis.viewWindow.min = 0.9 * max
|
||||
}
|
||||
|
||||
window.charts[elementId].draw(dataTable, opts);
|
||||
}
|
||||
|
||||
// Gets the length of the interval in nanoseconds.
|
||||
function getInterval(current, previous) {
|
||||
var cur = new Date(current);
|
||||
var prev = new Date(previous);
|
||||
|
||||
// ms -> ns.
|
||||
return (cur.getTime() - prev.getTime()) * 1000000;
|
||||
}
|
||||
|
||||
// Checks if the specified stats include the specified resource.
|
||||
function hasResource(stats, resource) {
|
||||
return stats.stats.length > 0 && stats.stats[0][resource];
|
||||
}
|
||||
|
||||
// Draw a set of gauges. Data is comprised of an array of arrays with two elements:
|
||||
// a string label and a numeric value for the gauge.
|
||||
function drawGauges(elementId, gauges) {
|
||||
gauges.unshift(['Label', 'Value']);
|
||||
|
||||
// Create and populate the data table.
|
||||
var data = google.visualization.arrayToDataTable(gauges);
|
||||
|
||||
// Create and draw the visualization.
|
||||
var options = {
|
||||
height: 100,
|
||||
redFrom: 90, redTo: 100,
|
||||
yellowFrom:75, yellowTo: 90,
|
||||
minorTicks: 5,
|
||||
animation: {
|
||||
duration: 900,
|
||||
easing: 'linear'
|
||||
}
|
||||
};
|
||||
var chart = new google.visualization.Gauge(document.getElementById(elementId));
|
||||
chart.draw(data, options);
|
||||
}
|
||||
|
||||
// Get the machine info.
|
||||
function getMachineInfo(rootDir, callback) {
|
||||
$.getJSON(rootDir + "api/v1.0/machine", function(data) {
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
|
||||
// Get ps info.
|
||||
function getProcessInfo(rootDir, containerName, callback) {
|
||||
$.getJSON(rootDir + "api/v2.0/ps" + containerName)
|
||||
.done(function(data) {
|
||||
callback(data);
|
||||
})
|
||||
.fail(function(jqhxr, textStatus, error) {
|
||||
callback([]);
|
||||
});
|
||||
}
|
||||
|
||||
// Get the container stats for the specified container.
|
||||
function getStats(rootDir, containerName, callback) {
|
||||
// Request 60s of container history and no samples.
|
||||
var request = JSON.stringify({
|
||||
// Update main.statsRequestedByUI while updating "num_stats" here.
|
||||
"num_stats": 60,
|
||||
"num_samples": 0
|
||||
});
|
||||
$.post(rootDir + "api/v1.0/containers" + containerName, request, function(data) {
|
||||
callback(data);
|
||||
}, "json");
|
||||
}
|
||||
|
||||
// Draw the graph for CPU usage.
|
||||
function drawCpuTotalUsage(elementId, machineInfo, stats) {
|
||||
if (stats.spec.has_cpu && !hasResource(stats, "cpu")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var titles = ["Time", "Total"];
|
||||
var data = [];
|
||||
for (var i = 1; i < stats.stats.length; i++) {
|
||||
var cur = stats.stats[i];
|
||||
var prev = stats.stats[i - 1];
|
||||
var intervalInNs = getInterval(cur.timestamp, prev.timestamp);
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
elements.push((cur.cpu.usage.total - prev.cpu.usage.total) / intervalInNs);
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId, "Cores");
|
||||
}
|
||||
|
||||
// Draw the graph for CPU load.
|
||||
function drawCpuLoad(elementId, machineInfo, stats) {
|
||||
|
||||
var titles = ["Time", "Average"];
|
||||
var data = [];
|
||||
for (var i = 1; i < stats.stats.length; i++) {
|
||||
var cur = stats.stats[i];
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
elements.push(cur.cpu.load_average/1000);
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId, "Runnable threads");
|
||||
}
|
||||
|
||||
|
||||
// Draw the graph for per-core CPU usage.
|
||||
function drawCpuPerCoreUsage(elementId, machineInfo, stats) {
|
||||
if (stats.spec.has_cpu && !hasResource(stats, "cpu")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a title for each core.
|
||||
var titles = ["Time"];
|
||||
for (var i = 0; i < machineInfo.num_cores; i++) {
|
||||
titles.push("Core " + i);
|
||||
}
|
||||
var data = [];
|
||||
for (var i = 1; i < stats.stats.length; i++) {
|
||||
var cur = stats.stats[i];
|
||||
var prev = stats.stats[i - 1];
|
||||
var intervalInNs = getInterval(cur.timestamp, prev.timestamp);
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
for (var j = 0; j < machineInfo.num_cores; j++) {
|
||||
elements.push((cur.cpu.usage.per_cpu_usage[j] - prev.cpu.usage.per_cpu_usage[j]) / intervalInNs);
|
||||
}
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId, "Cores");
|
||||
}
|
||||
|
||||
// Draw the graph for CPU usage breakdown.
|
||||
function drawCpuUsageBreakdown(elementId, machineInfo, containerInfo) {
|
||||
if (containerInfo.spec.has_cpu && !hasResource(containerInfo, "cpu")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var titles = ["Time", "User", "Kernel"];
|
||||
var data = [];
|
||||
for (var i = 1; i < containerInfo.stats.length; i++) {
|
||||
var cur = containerInfo.stats[i];
|
||||
var prev = containerInfo.stats[i - 1];
|
||||
var intervalInNs = getInterval(cur.timestamp, prev.timestamp);
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
elements.push((cur.cpu.usage.user - prev.cpu.usage.user) / intervalInNs);
|
||||
elements.push((cur.cpu.usage.system - prev.cpu.usage.system) / intervalInNs);
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId, "Cores");
|
||||
}
|
||||
|
||||
// Draw the gauges for overall resource usage.
|
||||
function drawOverallUsage(elementId, machineInfo, containerInfo) {
|
||||
var cur = containerInfo.stats[containerInfo.stats.length - 1];
|
||||
var gauges = [];
|
||||
|
||||
var cpuUsage = 0;
|
||||
if (containerInfo.spec.has_cpu && containerInfo.stats.length >= 2) {
|
||||
var prev = containerInfo.stats[containerInfo.stats.length - 2];
|
||||
var rawUsage = cur.cpu.usage.total - prev.cpu.usage.total;
|
||||
var intervalInNs = getInterval(cur.timestamp, prev.timestamp);
|
||||
|
||||
// Convert to millicores and take the percentage
|
||||
cpuUsage = Math.round(((rawUsage / intervalInNs) / machineInfo.num_cores) * 100);
|
||||
if (cpuUsage > 100) {
|
||||
cpuUsage = 100;
|
||||
}
|
||||
gauges.push(['CPU', cpuUsage]);
|
||||
}
|
||||
|
||||
var memoryUsage = 0;
|
||||
if (containerInfo.spec.has_memory) {
|
||||
// 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);
|
||||
gauges.push(['Memory', memoryUsage]);
|
||||
}
|
||||
|
||||
var numGauges = gauges.length;
|
||||
if (cur.filesystem) {
|
||||
for (var i = 0; i < cur.filesystem.length; i++) {
|
||||
var data = cur.filesystem[i];
|
||||
var totalUsage = Math.floor((data.usage * 100.0) / data.capacity);
|
||||
var els = window.cadvisor.fsUsage.elements[data.device];
|
||||
|
||||
// Update the gauges in the right order.
|
||||
gauges[numGauges + els.index] = ['FS #' + (els.index + 1), totalUsage];
|
||||
}
|
||||
|
||||
// Limit the number of filesystem gauges displayed to 5.
|
||||
// 'Filesystem details' section still shows information for all filesystems.
|
||||
var max_gauges = numGauges + 5;
|
||||
if (gauges.length > max_gauges) {
|
||||
gauges = gauges.slice(0, max_gauges);
|
||||
}
|
||||
}
|
||||
|
||||
drawGauges(elementId, gauges);
|
||||
}
|
||||
|
||||
var oneMegabyte = 1024 * 1024;
|
||||
var oneGigabyte = 1024 * oneMegabyte;
|
||||
|
||||
function drawMemoryUsage(elementId, machineInfo, containerInfo) {
|
||||
if (containerInfo.spec.has_memory && !hasResource(containerInfo, "memory")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var titles = ["Time", "Total", "Hot"];
|
||||
var data = [];
|
||||
for (var i = 0; i < containerInfo.stats.length; i++) {
|
||||
var cur = containerInfo.stats[i];
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
elements.push(cur.memory.usage / oneMegabyte);
|
||||
elements.push(cur.memory.working_set / oneMegabyte);
|
||||
data.push(elements);
|
||||
}
|
||||
|
||||
// Get the memory limit, saturate to the machine size.
|
||||
var memory_limit = machineInfo.memory_capacity;
|
||||
if (containerInfo.spec.memory.limit && (containerInfo.spec.memory.limit < memory_limit)) {
|
||||
memory_limit = containerInfo.spec.memory.limit;
|
||||
}
|
||||
|
||||
// Updating the progress bar.
|
||||
var cur = containerInfo.stats[containerInfo.stats.length-1];
|
||||
var hotMemory = Math.floor((cur.memory.working_set * 100.0) / memory_limit);
|
||||
var totalMemory = Math.floor((cur.memory.usage * 100.0) / memory_limit);
|
||||
var coldMemory = totalMemory - hotMemory;
|
||||
$("#progress-hot-memory").width(hotMemory + "%");
|
||||
$("#progress-cold-memory").width(coldMemory + "%");
|
||||
$("#memory-text").text(humanizeIEC(cur.memory.usage) + " / " + humanizeIEC(memory_limit) + " ("+ totalMemory +"%)");
|
||||
|
||||
drawLineChart(titles, data, elementId, "Megabytes");
|
||||
}
|
||||
|
||||
// Get the index of the interface with the specified name.
|
||||
function getNetworkInterfaceIndex(interfaceName, interfaces) {
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
if (interfaces[i].name == interfaceName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Draw the graph for network tx/rx bytes.
|
||||
function drawNetworkBytes(elementId, machineInfo, stats) {
|
||||
if (stats.spec.has_network && !hasResource(stats, "network")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get interface index.
|
||||
var interfaceIndex = -1;
|
||||
if (stats.stats.length > 0) {
|
||||
interfaceIndex = getNetworkInterfaceIndex(window.cadvisor.network.interface, stats.stats[0].network.interfaces);
|
||||
}
|
||||
if (interfaceIndex < 0) {
|
||||
console.log("Unable to find interface\"", interfaceName, "\" in ", stats.stats.network);
|
||||
return;
|
||||
}
|
||||
|
||||
var titles = ["Time", "Tx bytes", "Rx bytes"];
|
||||
var data = [];
|
||||
for (var i = 1; i < stats.stats.length; i++) {
|
||||
var cur = stats.stats[i];
|
||||
var prev = stats.stats[i - 1];
|
||||
var intervalInSec = getInterval(cur.timestamp, prev.timestamp) / 1000000000;
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
elements.push((cur.network.interfaces[interfaceIndex].tx_bytes - prev.network.interfaces[interfaceIndex].tx_bytes) / intervalInSec);
|
||||
elements.push((cur.network.interfaces[interfaceIndex].rx_bytes - prev.network.interfaces[interfaceIndex].rx_bytes) / intervalInSec);
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId, "Bytes per second");
|
||||
}
|
||||
|
||||
// Draw the graph for network errors
|
||||
function drawNetworkErrors(elementId, machineInfo, stats) {
|
||||
if (stats.spec.has_network && !hasResource(stats, "network")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get interface index.
|
||||
var interfaceIndex = -1;
|
||||
if (stats.stats.length > 0) {
|
||||
interfaceIndex = getNetworkInterfaceIndex(window.cadvisor.network.interface, stats.stats[0].network.interfaces);
|
||||
}
|
||||
if (interfaceIndex < 0) {
|
||||
console.log("Unable to find interface\"", interfaceName, "\" in ", stats.stats.network);
|
||||
return;
|
||||
}
|
||||
|
||||
var titles = ["Time", "Tx", "Rx"];
|
||||
var data = [];
|
||||
for (var i = 1; i < stats.stats.length; i++) {
|
||||
var cur = stats.stats[i];
|
||||
var prev = stats.stats[i - 1];
|
||||
var intervalInSec = getInterval(cur.timestamp, prev.timestamp) / 1000000000;
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
elements.push((cur.network.interfaces[interfaceIndex].tx_errors - prev.network.interfaces[interfaceIndex].tx_errors) / intervalInSec);
|
||||
elements.push((cur.network.interfaces[interfaceIndex].rx_errors - prev.network.interfaces[interfaceIndex].rx_errors) / intervalInSec);
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId, "Errors per second");
|
||||
}
|
||||
|
||||
// Update the filesystem usage values.
|
||||
function drawFileSystemUsage(machineInfo, stats) {
|
||||
var cur = stats.stats[stats.stats.length - 1];
|
||||
if (!cur.filesystem) {
|
||||
return;
|
||||
}
|
||||
|
||||
var el = $("<div>");
|
||||
for (var i = 0; i < cur.filesystem.length; i++) {
|
||||
var data = cur.filesystem[i];
|
||||
var totalUsage = Math.floor((data.usage * 100.0) / data.capacity);
|
||||
|
||||
// Update DOM elements.
|
||||
var els = window.cadvisor.fsUsage.elements[data.device];
|
||||
els.progressElement.width(totalUsage + "%");
|
||||
els.textElement.text(humanizeMetric(data.usage) + " / " + humanizeMetric(data.capacity)+ " (" + totalUsage + "%)");
|
||||
}
|
||||
}
|
||||
|
||||
function drawImages(images) {
|
||||
if (images == null || images.length == 0) {
|
||||
return;
|
||||
}
|
||||
window.charts = {};
|
||||
var titles = ["Repository", "Tags", "ID", "Virtual Size", "Creation Time"];
|
||||
var titleTypes = ['string', 'string', 'string', 'number', 'number'];
|
||||
var sortIndex = 0;
|
||||
var data = [];
|
||||
for (var i = 0; i < images.length; i++) {
|
||||
var elements = [];
|
||||
var tags = [];
|
||||
var repos = images[i].repo_tags[0].split(":");
|
||||
repos.splice(-1,1)
|
||||
for (var j = 0; j < images[i].repo_tags.length; j++) {
|
||||
var splits = images[i].repo_tags[j].split(":")
|
||||
if (splits.length > 1) {
|
||||
tags.push(splits[splits.length - 1])
|
||||
}
|
||||
}
|
||||
elements.push(repos.join(":"));
|
||||
elements.push(tags.join(", "));
|
||||
elements.push(images[i].id.substr(0,24));
|
||||
elements.push({v: images[i].virtual_size, f: humanizeIEC(images[i].virtual_size)});
|
||||
var d = new Date(images[i].created * 1000);
|
||||
elements.push({v: images[i].created, f: d.toLocaleString()});
|
||||
data.push(elements);
|
||||
}
|
||||
drawTable(titles, titleTypes, data, "docker-images", 30, sortIndex);
|
||||
}
|
||||
|
||||
function drawProcesses(isRoot, rootDir, processInfo) {
|
||||
if (processInfo.length == 0) {
|
||||
$("#processes-top").text("No processes found");
|
||||
return;
|
||||
}
|
||||
var titles = ["User", "PID", "PPID", "Start Time", "CPU %", "MEM %", "RSS", "Virtual Size", "Status", "Running Time", "Command"];
|
||||
var titleTypes = ['string', 'number', 'number', 'string', 'number', 'number', 'number', 'number', 'string', 'string', 'string'];
|
||||
var sortIndex = 4
|
||||
if (isRoot) {
|
||||
titles.push("Container");
|
||||
titleTypes.push('string');
|
||||
}
|
||||
var data = []
|
||||
for (var i = 0; i < processInfo.length; i++) {
|
||||
var elements = [];
|
||||
elements.push(processInfo[i].user);
|
||||
elements.push(processInfo[i].pid);
|
||||
elements.push(processInfo[i].parent_pid);
|
||||
elements.push(processInfo[i].start_time);
|
||||
elements.push({ v:processInfo[i].percent_cpu, f:processInfo[i].percent_cpu.toFixed(2)});
|
||||
elements.push({ v:processInfo[i].percent_mem, f:processInfo[i].percent_mem.toFixed(2)});
|
||||
elements.push({ v:processInfo[i].rss, f:humanizeIEC(processInfo[i].rss)});
|
||||
elements.push({ v:processInfo[i].virtual_size, f:humanizeIEC(processInfo[i].virtual_size)});
|
||||
elements.push(processInfo[i].status);
|
||||
elements.push(processInfo[i].running_time);
|
||||
elements.push(processInfo[i].cmd);
|
||||
if (isRoot) {
|
||||
var cgroup = processInfo[i].cgroup_path
|
||||
// Use the raw cgroup link as it works for all containers.
|
||||
var cgroupLink = '<a href="' + rootDir + 'containers/' + cgroup +'">' + cgroup.substr(0,30) + ' </a>';
|
||||
elements.push({v:cgroup, f:cgroupLink});
|
||||
}
|
||||
data.push(elements);
|
||||
}
|
||||
drawTable(titles, titleTypes, data, "processes-top", 25, sortIndex);
|
||||
}
|
||||
|
||||
// Draw the filesystem usage nodes.
|
||||
function startFileSystemUsage(elementId, machineInfo, stats) {
|
||||
window.cadvisor.fsUsage = {};
|
||||
|
||||
// A map of device name to DOM elements.
|
||||
window.cadvisor.fsUsage.elements = {};
|
||||
|
||||
var cur = stats.stats[stats.stats.length - 1];
|
||||
var el = $("<div>");
|
||||
if (!cur.filesystem) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < cur.filesystem.length; i++) {
|
||||
var data = cur.filesystem[i];
|
||||
el.append($("<div>")
|
||||
.addClass("row col-sm-12")
|
||||
.append($("<h4>")
|
||||
.text("FS #" + (i + 1) + ": " + data.device)));
|
||||
|
||||
var progressElement = $("<div>").addClass("progress-bar progress-bar-danger");
|
||||
el.append($("<div>")
|
||||
.addClass("col-sm-9")
|
||||
.append($("<div>")
|
||||
.addClass("progress")
|
||||
.append(progressElement)));
|
||||
|
||||
var textElement = $("<div>").addClass("col-sm-3");
|
||||
el.append(textElement);
|
||||
|
||||
window.cadvisor.fsUsage.elements[data.device] = {
|
||||
'progressElement': progressElement,
|
||||
'textElement': textElement,
|
||||
'index': i,
|
||||
};
|
||||
}
|
||||
$("#" + elementId).empty().append(el);
|
||||
|
||||
drawFileSystemUsage(machineInfo, stats);
|
||||
}
|
||||
|
||||
// Expects an array of closures to call. After each execution the JS runtime is given control back before continuing.
|
||||
// This function returns asynchronously
|
||||
function stepExecute(steps) {
|
||||
// No steps, stop.
|
||||
if (steps.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a step and execute it.
|
||||
var step = steps.shift();
|
||||
step();
|
||||
|
||||
// Schedule the next step.
|
||||
setTimeout(function() {
|
||||
stepExecute(steps);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// Draw all the charts on the page.
|
||||
function drawCharts(machineInfo, containerInfo) {
|
||||
var steps = [];
|
||||
|
||||
if (containerInfo.spec.has_cpu || containerInfo.spec.has_memory) {
|
||||
steps.push(function() {
|
||||
drawOverallUsage("usage-gauge", machineInfo, containerInfo)
|
||||
});
|
||||
}
|
||||
|
||||
// CPU.
|
||||
if (containerInfo.spec.has_cpu) {
|
||||
steps.push(function() {
|
||||
drawCpuTotalUsage("cpu-total-usage-chart", machineInfo, containerInfo);
|
||||
});
|
||||
// TODO(rjnagal): Re-enable CPU Load after understanding resource usage.
|
||||
// steps.push(function() {
|
||||
// drawCpuLoad("cpu-load-chart", machineInfo, containerInfo);
|
||||
// });
|
||||
steps.push(function() {
|
||||
drawCpuPerCoreUsage("cpu-per-core-usage-chart", machineInfo, containerInfo);
|
||||
});
|
||||
steps.push(function() {
|
||||
drawCpuUsageBreakdown("cpu-usage-breakdown-chart", machineInfo, containerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
// Memory.
|
||||
if (containerInfo.spec.has_memory) {
|
||||
steps.push(function() {
|
||||
drawMemoryUsage("memory-usage-chart", machineInfo, containerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
// Network.
|
||||
if (containerInfo.spec.has_network) {
|
||||
steps.push(function() {
|
||||
drawNetworkBytes("network-bytes-chart", machineInfo, containerInfo);
|
||||
});
|
||||
steps.push(function() {
|
||||
drawNetworkErrors("network-errors-chart", machineInfo, containerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
// Filesystem.
|
||||
if (containerInfo.spec.has_filesystem) {
|
||||
steps.push(function() {
|
||||
drawFileSystemUsage(machineInfo, containerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
// Custom Metrics
|
||||
if (containerInfo.spec.has_custom_metrics) {
|
||||
steps.push(function() {
|
||||
getCustomMetrics(window.cadvisor.rootDir, window.cadvisor.containerName, function(metricsInfo) {
|
||||
drawCustomMetrics("custom-metrics-chart", containerInfo, metricsInfo)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stepExecute(steps);
|
||||
}
|
||||
|
||||
function setNetwork(interfaceName) {
|
||||
$("#network-selection-text")
|
||||
.empty()
|
||||
.append($("<span>").text("Interface: "))
|
||||
.append($("<b>").text(interfaceName));
|
||||
window.cadvisor.network.interface = interfaceName;
|
||||
|
||||
// Draw the new stats.
|
||||
refreshStats();
|
||||
}
|
||||
|
||||
// Creates the network selection dropdown.
|
||||
function startNetwork(selectionElement, containerInfo) {
|
||||
if (!hasResource(containerInfo, "network") || containerInfo.stats.length == 0
|
||||
|| !containerInfo.stats[0].network.interfaces || containerInfo.stats[0].network.interfaces.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.cadvisor.network = {};
|
||||
window.cadvisor.network.interface = "";
|
||||
|
||||
// Add all interfaces to the dropdown.
|
||||
var el = $("#" + selectionElement);
|
||||
for (var i = 0; i < containerInfo.stats[0].network.interfaces.length; i++) {
|
||||
var interfaceName = containerInfo.stats[0].network.interfaces[i].name;
|
||||
el.append($("<li>")
|
||||
.attr("role", "presentation")
|
||||
.append($("<a>")
|
||||
.attr("role", "menuitem")
|
||||
.attr("tabindex", -1)
|
||||
.click(setNetwork.bind(null, interfaceName))
|
||||
.text(interfaceName)));
|
||||
}
|
||||
setNetwork(containerInfo.stats[0].network.interfaces[0].name);
|
||||
}
|
||||
|
||||
// Refresh the stats on the page.
|
||||
function refreshStats() {
|
||||
var machineInfo = window.cadvisor.machineInfo;
|
||||
getStats(window.cadvisor.rootDir, window.cadvisor.containerName, function(containerInfo){
|
||||
if (window.cadvisor.firstRun) {
|
||||
window.cadvisor.firstRun = false;
|
||||
|
||||
if (containerInfo.spec.has_filesystem) {
|
||||
startFileSystemUsage("filesystem-usage", machineInfo, containerInfo);
|
||||
}
|
||||
if (containerInfo.spec.has_network) {
|
||||
startNetwork("network-selection", containerInfo);
|
||||
}
|
||||
if (containerInfo.spec.has_custom_metrics) {
|
||||
startCustomMetrics("custom-metrics-chart", containerInfo);
|
||||
}
|
||||
}
|
||||
drawCharts(machineInfo, containerInfo);
|
||||
});
|
||||
}
|
||||
|
||||
function addAllLabels(containerInfo, metricsInfo) {
|
||||
if (metricsInfo.length == 0) {
|
||||
return;
|
||||
}
|
||||
var metricSpec = containerInfo.spec.custom_metrics;
|
||||
for (var containerName in metricsInfo) {
|
||||
var container = metricsInfo[containerName];
|
||||
for (i=0; i<metricSpec.length; i++) {
|
||||
metricName = metricSpec[i].name;
|
||||
metricLabelVal = container[metricName];
|
||||
firstLabel = true;
|
||||
for (var label in metricLabelVal) {
|
||||
if (label == "") {
|
||||
$('#button-'+metricName).hide();
|
||||
}
|
||||
|
||||
$("#"+metricName+"_labels").append($("<li>")
|
||||
.attr("role", "presentation")
|
||||
.append($("<a>")
|
||||
.attr("role", "menuitem")
|
||||
.click(setLabel.bind(null, metricName, label))
|
||||
.text(label)));
|
||||
if (firstLabel) {
|
||||
firstLabel = false;
|
||||
setLabel(metricName, label);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMetricIndex(metricName) {
|
||||
for (i = 0; i<window.cadvisor.metricLabelPair.length; ++i) {
|
||||
if (window.cadvisor.metricLabelPair[i][0] == metricName)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function setLabel(metric, label) {
|
||||
$("#"+metric+"-selection-text")
|
||||
.empty()
|
||||
.append($("<span>").text("Label: "))
|
||||
.append($("<b>").text(label))
|
||||
|
||||
index = getMetricIndex(metric);
|
||||
if (index == -1) {
|
||||
window.cadvisor.metricLabelPair.push([metric, label]);
|
||||
} else {
|
||||
window.cadvisor.metricLabelPair[index][1] = label;
|
||||
}
|
||||
|
||||
refreshStats();
|
||||
}
|
||||
|
||||
function getSelectedLabel(metricName) {
|
||||
index = getMetricIndex(metricName);
|
||||
if (index == -1)
|
||||
return "";
|
||||
return window.cadvisor.metricLabelPair[index][1];
|
||||
}
|
||||
|
||||
function startCustomMetrics(elementId, containerInfo) {
|
||||
var metricSpec = containerInfo.spec.custom_metrics;
|
||||
var metricStats = containerInfo.stats.custom_metrics;
|
||||
var el=$("<div>");
|
||||
|
||||
if (metricSpec.length < window.cadvisor.maxCustomMetrics)
|
||||
window.cadvisor.maxCustomMetrics = metricSpec.length
|
||||
for (i = 0; i<window.cadvisor.maxCustomMetrics; i++) {
|
||||
metricName = metricSpec[i].name;
|
||||
var divText = "<div class='dropdown'> <button class='btn btn-default dropdown-toggle' type='button' id='button-"+metricName;
|
||||
divText += "' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>";
|
||||
divText += "<span id='"+metricName+"-selection-text'></span> <span class='caret'></span> </button>";
|
||||
divText += "<ul id='"+metricName+"_labels' class='dropdown-menu' role='menu' aria-labelledby='button-"+metricName+ "'> </ul> </div>";
|
||||
divText += "<div id='"+elementId+"-"+metricName+"'> </div>";
|
||||
el.append($(divText));
|
||||
}
|
||||
el.append($("</div>"));
|
||||
|
||||
$("#"+elementId).append(el);
|
||||
}
|
||||
|
||||
function getCustomMetrics(rootDir, containerName, callback) {
|
||||
$.getJSON(rootDir + "api/v2.0/appmetrics/" + containerName)
|
||||
.done(function(data) {
|
||||
callback(data);
|
||||
})
|
||||
.fail(function(jqhxr, textStatus, error) {
|
||||
callback([]);
|
||||
});
|
||||
}
|
||||
|
||||
function drawCustomMetrics(elementId, containerInfo, metricsInfo) {
|
||||
if(metricsInfo.length == 0) {
|
||||
return;
|
||||
}
|
||||
var metricSpec = containerInfo.spec.custom_metrics;
|
||||
for (var containerName in metricsInfo) {
|
||||
var container = metricsInfo[containerName];
|
||||
for (i=0; i<window.cadvisor.maxCustomMetrics; i++) {
|
||||
metricName = metricSpec[i].name;
|
||||
metricUnits = metricSpec[i].units;
|
||||
var titles = ["Time", metricName];
|
||||
metricLabelVal = container[metricName];
|
||||
if (window.cadvisor.firstCustomCollection) {
|
||||
window.cadvisor.firstCustomCollection = false;
|
||||
addAllLabels(containerInfo, metricsInfo);
|
||||
}
|
||||
var data = [];
|
||||
selectedLabel = getSelectedLabel(metricName);
|
||||
metricVal = metricLabelVal[selectedLabel];
|
||||
for (var index in metricVal) {
|
||||
metric = metricVal[index];
|
||||
var elements = [];
|
||||
for (var attribute in metric) {
|
||||
value = metric[attribute];
|
||||
elements.push(value);
|
||||
}
|
||||
if (elements.length<2) {
|
||||
elements.push(0);
|
||||
}
|
||||
data.push(elements);
|
||||
}
|
||||
drawLineChart(titles, data, elementId+"-"+metricName, metricUnits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Executed when the page finishes loading.
|
||||
function startPage(containerName, hasCpu, hasMemory, rootDir, isRoot) {
|
||||
// Don't fetch data if we don't have any resource.
|
||||
if (!hasCpu && !hasMemory) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.charts = {};
|
||||
window.cadvisor = {};
|
||||
window.cadvisor.firstRun = true;
|
||||
window.cadvisor.rootDir = rootDir;
|
||||
window.cadvisor.containerName = containerName;
|
||||
|
||||
window.cadvisor.firstCustomCollection = true;
|
||||
window.cadvisor.metricLabelPair = [];
|
||||
window.cadvisor.maxCustomMetrics = 10;
|
||||
|
||||
// Draw process information at start and refresh every 60s.
|
||||
getProcessInfo(rootDir, containerName, function(processInfo) {
|
||||
drawProcesses(isRoot, rootDir, processInfo)
|
||||
});
|
||||
setInterval(function() {
|
||||
getProcessInfo(rootDir, containerName, function(processInfo) {
|
||||
drawProcesses(isRoot, rootDir, processInfo)
|
||||
});
|
||||
}, 60000);
|
||||
|
||||
// Get machine info, then get the stats every 1s.
|
||||
getMachineInfo(rootDir, function(machineInfo) {
|
||||
window.cadvisor.machineInfo = machineInfo;
|
||||
setInterval(function() {
|
||||
refreshStats();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
`
|
||||
1395
vendor/github.com/google/cadvisor/pages/static/gcharts_js.go
generated
vendored
Normal file
1395
vendor/github.com/google/cadvisor/pages/static/gcharts_js.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
57
vendor/github.com/google/cadvisor/pages/static/google_jsapi_js.go
generated
vendored
Normal file
57
vendor/github.com/google/cadvisor/pages/static/google_jsapi_js.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
24
vendor/github.com/google/cadvisor/pages/static/jquery_min_js.go
generated
vendored
Normal file
24
vendor/github.com/google/cadvisor/pages/static/jquery_min_js.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
59
vendor/github.com/google/cadvisor/pages/static/static.go
generated
vendored
Normal file
59
vendor/github.com/google/cadvisor/pages/static/static.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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.
|
||||
|
||||
// Handler for /static content.
|
||||
|
||||
package static
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
)
|
||||
|
||||
const StaticResource = "/static/"
|
||||
|
||||
var staticFiles = map[string]string{
|
||||
"containers.css": containersCss,
|
||||
"containers.js": containersJs,
|
||||
"bootstrap-3.1.1.min.css": bootstrapCss,
|
||||
"bootstrap-theme-3.1.1.min.css": bootstrapThemeCss,
|
||||
"jquery-1.10.2.min.js": jqueryJs,
|
||||
"bootstrap-3.1.1.min.js": bootstrapJs,
|
||||
"google-jsapi.js": googleJsapiJs,
|
||||
}
|
||||
|
||||
func HandleRequest(w http.ResponseWriter, u *url.URL) error {
|
||||
if len(u.Path) <= len(StaticResource) {
|
||||
return fmt.Errorf("unknown static resource %q", u.Path)
|
||||
}
|
||||
|
||||
// Get the static content if it exists.
|
||||
resource := u.Path[len(StaticResource):]
|
||||
content, ok := staticFiles[resource]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown static resource %q", resource)
|
||||
}
|
||||
|
||||
// Set Content-Type if we were able to detect it.
|
||||
contentType := mime.TypeByExtension(path.Ext(resource))
|
||||
if contentType != "" {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
}
|
||||
|
||||
_, err := w.Write([]byte(content))
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user