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:
311
vendor/github.com/google/cadvisor/validate/validate.go
generated
vendored
Normal file
311
vendor/github.com/google/cadvisor/validate/validate.go
generated
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
// 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 /validate content.
|
||||
// Validates cadvisor dependencies - kernel, os, docker setup.
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cadvisor/container/docker"
|
||||
"github.com/google/cadvisor/manager"
|
||||
"github.com/google/cadvisor/utils"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
)
|
||||
|
||||
const (
|
||||
ValidatePage = "/validate/"
|
||||
Supported = "[Supported, but not recommended]"
|
||||
Unsupported = "[Unsupported]"
|
||||
Recommended = "[Supported and recommended]"
|
||||
Unknown = "[Unknown]"
|
||||
VersionFormat = "%d.%d%s"
|
||||
OutputFormat = "%s: %s\n\t%s\n\n"
|
||||
)
|
||||
|
||||
func getMajorMinor(version string) (int, int, error) {
|
||||
var major, minor int
|
||||
var ign string
|
||||
n, err := fmt.Sscanf(version, VersionFormat, &major, &minor, &ign)
|
||||
if n != 3 || err != nil {
|
||||
log.Printf("Failed to parse version for %s", version)
|
||||
return -1, -1, err
|
||||
}
|
||||
return major, minor, nil
|
||||
}
|
||||
|
||||
func validateKernelVersion(version string) (string, string) {
|
||||
desc := fmt.Sprintf("Kernel version is %s. Versions >= 2.6 are supported. 3.0+ are recommended.\n", version)
|
||||
major, minor, err := getMajorMinor(version)
|
||||
if err != nil {
|
||||
desc = fmt.Sprintf("Could not parse kernel version. %s", desc)
|
||||
return Unknown, desc
|
||||
}
|
||||
|
||||
if major < 2 {
|
||||
return Unsupported, desc
|
||||
}
|
||||
|
||||
if major == 2 && minor < 6 {
|
||||
return Unsupported, desc
|
||||
}
|
||||
|
||||
if major >= 3 {
|
||||
return Recommended, desc
|
||||
}
|
||||
|
||||
return Supported, desc
|
||||
}
|
||||
|
||||
func validateDockerVersion(version string) (string, string) {
|
||||
desc := fmt.Sprintf("Docker version is %s. Versions >= 1.0 are supported. 1.2+ are recommended.\n", version)
|
||||
major, minor, err := getMajorMinor(version)
|
||||
if err != nil {
|
||||
desc = fmt.Sprintf("Could not parse docker version. %s\n\t", desc)
|
||||
return Unknown, desc
|
||||
}
|
||||
if major < 1 {
|
||||
return Unsupported, desc
|
||||
}
|
||||
|
||||
if major == 1 && minor < 2 {
|
||||
return Supported, desc
|
||||
}
|
||||
|
||||
return Recommended, desc
|
||||
}
|
||||
|
||||
func getEnabledCgroups() (map[string]int, error) {
|
||||
out, err := ioutil.ReadFile("/proc/cgroups")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cgroups := make(map[string]int)
|
||||
for i, line := range strings.Split(string(out), "\n") {
|
||||
var cgroup string
|
||||
var ign, enabled int
|
||||
if i == 0 || line == "" {
|
||||
continue
|
||||
}
|
||||
n, err := fmt.Sscanf(line, "%s %d %d %d", &cgroup, &ign, &ign, &enabled)
|
||||
if n != 4 || err != nil {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("failed to parse /proc/cgroup entry %s", line)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
cgroups[cgroup] = enabled
|
||||
}
|
||||
return cgroups, nil
|
||||
}
|
||||
|
||||
func areCgroupsPresent(available map[string]int, desired []string) (bool, string) {
|
||||
for _, cgroup := range desired {
|
||||
enabled, ok := available[cgroup]
|
||||
if !ok {
|
||||
reason := fmt.Sprintf("Missing cgroup %s. Available cgroups: %v\n", cgroup, available)
|
||||
return false, reason
|
||||
}
|
||||
if enabled != 1 {
|
||||
reason := fmt.Sprintf("Cgroup %s not enabled. Available cgroups: %v\n", cgroup, available)
|
||||
return false, reason
|
||||
}
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func validateMemoryAccounting(available_cgroups map[string]int) string {
|
||||
ok, _ := areCgroupsPresent(available_cgroups, []string{"memory"})
|
||||
if !ok {
|
||||
return "\tHierarchical memory accounting status unknown: memory cgroup not enabled.\n"
|
||||
}
|
||||
mnt, err := cgroups.FindCgroupMountpoint("memory")
|
||||
if err != nil {
|
||||
return "\tHierarchical memory accounting status unknown: memory cgroup not mounted.\n"
|
||||
}
|
||||
hier, err := ioutil.ReadFile(path.Join(mnt, "memory.use_hierarchy"))
|
||||
if err != nil {
|
||||
return "\tHierarchical memory accounting status unknown: hierarchy interface unavailable.\n"
|
||||
}
|
||||
var enabled int
|
||||
n, err := fmt.Sscanf(string(hier), "%d", &enabled)
|
||||
if err != nil || n != 1 {
|
||||
return "\tHierarchical memory accounting status unknown: hierarchy interface unreadable.\n"
|
||||
}
|
||||
if enabled == 1 {
|
||||
return "\tHierarchical memory accounting enabled. Reported memory usage includes memory used by child containers.\n"
|
||||
}
|
||||
return "\tHierarchical memory accounting disabled. Memory usage does not include usage from child containers.\n"
|
||||
|
||||
}
|
||||
|
||||
func validateCgroups() (string, string) {
|
||||
required_cgroups := []string{"cpu", "cpuacct"}
|
||||
recommended_cgroups := []string{"memory", "blkio", "cpuset", "devices", "freezer"}
|
||||
available_cgroups, err := getEnabledCgroups()
|
||||
desc := fmt.Sprintf("\tFollowing cgroups are required: %v\n\tFollowing other cgroups are recommended: %v\n", required_cgroups, recommended_cgroups)
|
||||
if err != nil {
|
||||
desc = fmt.Sprintf("Could not parse /proc/cgroups.\n%s", desc)
|
||||
return Unknown, desc
|
||||
}
|
||||
ok, out := areCgroupsPresent(available_cgroups, required_cgroups)
|
||||
if !ok {
|
||||
out += desc
|
||||
return Unsupported, out
|
||||
}
|
||||
ok, out = areCgroupsPresent(available_cgroups, recommended_cgroups)
|
||||
if !ok {
|
||||
// supported, but not recommended.
|
||||
out += desc
|
||||
return Supported, out
|
||||
}
|
||||
out = fmt.Sprintf("Available cgroups: %v\n", available_cgroups)
|
||||
out += desc
|
||||
out += validateMemoryAccounting(available_cgroups)
|
||||
return Recommended, out
|
||||
}
|
||||
|
||||
func validateDockerInfo() (string, string) {
|
||||
info, err := docker.ValidateInfo()
|
||||
if err != nil {
|
||||
return Unsupported, fmt.Sprintf("Docker setup is invalid: %v", err)
|
||||
}
|
||||
|
||||
desc := fmt.Sprintf("Docker exec driver is %s. Storage driver is %s.\n", info.ExecutionDriver, info.Driver)
|
||||
stateFile := docker.DockerStateDir()
|
||||
if !utils.FileExists(stateFile) {
|
||||
desc += fmt.Sprintf("\tDocker container state directory %q is not accessible.\n", stateFile)
|
||||
return Unsupported, desc
|
||||
}
|
||||
desc += fmt.Sprintf("\tDocker container state directory is at %q and is accessible.\n", stateFile)
|
||||
return Recommended, desc
|
||||
}
|
||||
|
||||
func validateCgroupMounts() (string, string) {
|
||||
const recommendedMount = "/sys/fs/cgroup"
|
||||
desc := fmt.Sprintf("\tAny cgroup mount point that is detectible and accessible is supported. %s is recommended as a standard location.\n", recommendedMount)
|
||||
mnt, err := cgroups.FindCgroupMountpoint("cpu")
|
||||
if err != nil {
|
||||
out := "Could not locate cgroup mount point.\n"
|
||||
out += desc
|
||||
return Unknown, out
|
||||
}
|
||||
mnt = path.Dir(mnt)
|
||||
if !utils.FileExists(mnt) {
|
||||
out := fmt.Sprintf("Cgroup mount directory %s inaccessible.\n", mnt)
|
||||
out += desc
|
||||
return Unsupported, out
|
||||
}
|
||||
mounts, err := ioutil.ReadDir(mnt)
|
||||
if err != nil {
|
||||
out := fmt.Sprintf("Could not read cgroup mount directory %s.\n", mnt)
|
||||
out += desc
|
||||
return Unsupported, out
|
||||
}
|
||||
mountNames := "\tCgroup mount directories: "
|
||||
for _, mount := range mounts {
|
||||
mountNames += mount.Name() + " "
|
||||
}
|
||||
mountNames += "\n"
|
||||
out := fmt.Sprintf("Cgroups are mounted at %s.\n", mnt)
|
||||
out += mountNames
|
||||
out += desc
|
||||
info, err := ioutil.ReadFile("/proc/mounts")
|
||||
if err != nil {
|
||||
out := fmt.Sprintf("Could not read /proc/mounts.\n")
|
||||
out += desc
|
||||
return Unsupported, out
|
||||
}
|
||||
out += "\tCgroup mounts:\n"
|
||||
for _, line := range strings.Split(string(info), "\n") {
|
||||
if strings.Contains(line, " cgroup ") {
|
||||
out += "\t" + line + "\n"
|
||||
}
|
||||
}
|
||||
if mnt == recommendedMount {
|
||||
return Recommended, out
|
||||
}
|
||||
return Supported, out
|
||||
}
|
||||
|
||||
func validateIoScheduler(containerManager manager.Manager) (string, string) {
|
||||
var desc string
|
||||
mi, err := containerManager.GetMachineInfo()
|
||||
if err != nil {
|
||||
return Unknown, "Machine info not available\n\t"
|
||||
}
|
||||
cfq := false
|
||||
for _, disk := range mi.DiskMap {
|
||||
desc += fmt.Sprintf("\t Disk %q Scheduler type %q.\n", disk.Name, disk.Scheduler)
|
||||
if disk.Scheduler == "cfq" {
|
||||
cfq = true
|
||||
}
|
||||
}
|
||||
// Since we get lot of random block devices, report recommended if
|
||||
// at least one of them is on cfq. Report Supported otherwise.
|
||||
if cfq {
|
||||
desc = "At least one device supports 'cfq' I/O scheduler. Some disk stats can be reported.\n" + desc
|
||||
return Recommended, desc
|
||||
}
|
||||
desc = "None of the devices support 'cfq' I/O scheduler. No disk stats can be reported.\n" + desc
|
||||
return Supported, desc
|
||||
}
|
||||
|
||||
func HandleRequest(w http.ResponseWriter, containerManager manager.Manager) error {
|
||||
// Get cAdvisor version Info.
|
||||
versionInfo, err := containerManager.GetVersionInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out := fmt.Sprintf("cAdvisor version: %s\n\n", versionInfo.CadvisorVersion)
|
||||
|
||||
// No OS is preferred or unsupported as of now.
|
||||
out += fmt.Sprintf("OS version: %s\n\n", versionInfo.ContainerOsVersion)
|
||||
|
||||
kernelValidation, desc := validateKernelVersion(versionInfo.KernelVersion)
|
||||
out += fmt.Sprintf(OutputFormat, "Kernel version", kernelValidation, desc)
|
||||
|
||||
cgroupValidation, desc := validateCgroups()
|
||||
out += fmt.Sprintf(OutputFormat, "Cgroup setup", cgroupValidation, desc)
|
||||
|
||||
mountsValidation, desc := validateCgroupMounts()
|
||||
out += fmt.Sprintf(OutputFormat, "Cgroup mount setup", mountsValidation, desc)
|
||||
|
||||
dockerValidation, desc := validateDockerVersion(versionInfo.DockerVersion)
|
||||
out += fmt.Sprintf(OutputFormat, "Docker version", dockerValidation, desc)
|
||||
|
||||
dockerInfoValidation, desc := validateDockerInfo()
|
||||
out += fmt.Sprintf(OutputFormat, "Docker driver setup", dockerInfoValidation, desc)
|
||||
|
||||
ioSchedulerValidation, desc := validateIoScheduler(containerManager)
|
||||
out += fmt.Sprintf(OutputFormat, "Block device setup", ioSchedulerValidation, desc)
|
||||
|
||||
// Output debug info.
|
||||
debugInfo := containerManager.DebugInfo()
|
||||
for category, lines := range debugInfo {
|
||||
out += fmt.Sprintf(OutputFormat, category, "", strings.Join(lines, "\n\t"))
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(out))
|
||||
return err
|
||||
}
|
Reference in New Issue
Block a user