drop things from vendor/ directory
Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
61
vendor/github.com/google/cadvisor/container/docker/client.go
generated
vendored
61
vendor/github.com/google/cadvisor/container/docker/client.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Handler for /validate content.
|
||||
// Validates cadvisor dependencies - kernel, os, docker setup.
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
dclient "github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
dockerClient *dclient.Client
|
||||
dockerClientErr error
|
||||
dockerClientOnce sync.Once
|
||||
)
|
||||
|
||||
// Client creates a Docker API client based on the given Docker flags
|
||||
func Client() (*dclient.Client, error) {
|
||||
dockerClientOnce.Do(func() {
|
||||
var client *http.Client
|
||||
if *ArgDockerTLS {
|
||||
client = &http.Client{}
|
||||
options := tlsconfig.Options{
|
||||
CAFile: *ArgDockerCA,
|
||||
CertFile: *ArgDockerCert,
|
||||
KeyFile: *ArgDockerKey,
|
||||
InsecureSkipVerify: false,
|
||||
}
|
||||
tlsc, err := tlsconfig.Client(options)
|
||||
if err != nil {
|
||||
dockerClientErr = err
|
||||
return
|
||||
}
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: tlsc,
|
||||
}
|
||||
}
|
||||
dockerClient, dockerClientErr = dclient.NewClientWithOpts(
|
||||
dclient.WithHost(*ArgDockerEndpoint),
|
||||
dclient.WithHTTPClient(client),
|
||||
dclient.WithAPIVersionNegotiation())
|
||||
})
|
||||
return dockerClient, dockerClientErr
|
||||
}
|
200
vendor/github.com/google/cadvisor/container/docker/docker.go
generated
vendored
200
vendor/github.com/google/cadvisor/container/docker/docker.go
generated
vendored
@@ -1,200 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Provides global docker information.
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"time"
|
||||
|
||||
v1 "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/machine"
|
||||
)
|
||||
|
||||
var dockerTimeout = 10 * time.Second
|
||||
|
||||
func defaultContext() context.Context {
|
||||
ctx, _ := context.WithTimeout(context.Background(), dockerTimeout)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func SetTimeout(timeout time.Duration) {
|
||||
dockerTimeout = timeout
|
||||
}
|
||||
|
||||
func Status() (v1.DockerStatus, error) {
|
||||
return StatusWithContext(defaultContext())
|
||||
}
|
||||
|
||||
func StatusWithContext(ctx context.Context) (v1.DockerStatus, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return v1.DockerStatus{}, fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
dockerInfo, err := client.Info(ctx)
|
||||
if err != nil {
|
||||
return v1.DockerStatus{}, err
|
||||
}
|
||||
return StatusFromDockerInfo(dockerInfo)
|
||||
}
|
||||
|
||||
func StatusFromDockerInfo(dockerInfo dockertypes.Info) (v1.DockerStatus, error) {
|
||||
out := v1.DockerStatus{}
|
||||
out.KernelVersion = machine.KernelVersion()
|
||||
out.OS = dockerInfo.OperatingSystem
|
||||
out.Hostname = dockerInfo.Name
|
||||
out.RootDir = dockerInfo.DockerRootDir
|
||||
out.Driver = dockerInfo.Driver
|
||||
out.NumImages = dockerInfo.Images
|
||||
out.NumContainers = dockerInfo.Containers
|
||||
out.DriverStatus = make(map[string]string, len(dockerInfo.DriverStatus))
|
||||
for _, v := range dockerInfo.DriverStatus {
|
||||
out.DriverStatus[v[0]] = v[1]
|
||||
}
|
||||
var err error
|
||||
ver, err := VersionString()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.Version = ver
|
||||
ver, err = APIVersionString()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.APIVersion = ver
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func Images() ([]v1.DockerImage, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
images, err := client.ImageList(defaultContext(), dockertypes.ImageListOptions{All: false})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := []v1.DockerImage{}
|
||||
const unknownTag = "<none>:<none>"
|
||||
for _, image := range images {
|
||||
if len(image.RepoTags) == 1 && image.RepoTags[0] == unknownTag {
|
||||
// images with repo or tags are uninteresting.
|
||||
continue
|
||||
}
|
||||
di := v1.DockerImage{
|
||||
ID: image.ID,
|
||||
RepoTags: image.RepoTags,
|
||||
Created: image.Created,
|
||||
VirtualSize: image.VirtualSize,
|
||||
Size: image.Size,
|
||||
}
|
||||
out = append(out, di)
|
||||
}
|
||||
return out, nil
|
||||
|
||||
}
|
||||
|
||||
// Checks whether the dockerInfo reflects a valid docker setup, and returns it if it does, or an
|
||||
// error otherwise.
|
||||
func ValidateInfo() (*dockertypes.Info, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
|
||||
dockerInfo, err := client.Info(defaultContext())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to detect Docker info: %v", err)
|
||||
}
|
||||
|
||||
// Fall back to version API if ServerVersion is not set in info.
|
||||
if dockerInfo.ServerVersion == "" {
|
||||
version, err := client.ServerVersion(defaultContext())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get docker version: %v", err)
|
||||
}
|
||||
dockerInfo.ServerVersion = version.Version
|
||||
}
|
||||
version, err := parseVersion(dockerInfo.ServerVersion, versionRe, 3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if version[0] < 1 {
|
||||
return nil, fmt.Errorf("cAdvisor requires docker version %v or above but we have found version %v reported as %q", []int{1, 0, 0}, version, dockerInfo.ServerVersion)
|
||||
}
|
||||
|
||||
if dockerInfo.Driver == "" {
|
||||
return nil, fmt.Errorf("failed to find docker storage driver")
|
||||
}
|
||||
|
||||
return &dockerInfo, nil
|
||||
}
|
||||
|
||||
func APIVersion() ([]int, error) {
|
||||
ver, err := APIVersionString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseVersion(ver, apiVersionRe, 2)
|
||||
}
|
||||
|
||||
func VersionString() (string, error) {
|
||||
dockerVersion := "Unknown"
|
||||
client, err := Client()
|
||||
if err == nil {
|
||||
version, err := client.ServerVersion(defaultContext())
|
||||
if err == nil {
|
||||
dockerVersion = version.Version
|
||||
}
|
||||
}
|
||||
return dockerVersion, err
|
||||
}
|
||||
|
||||
func APIVersionString() (string, error) {
|
||||
apiVersion := "Unknown"
|
||||
client, err := Client()
|
||||
if err == nil {
|
||||
version, err := client.ServerVersion(defaultContext())
|
||||
if err == nil {
|
||||
apiVersion = version.APIVersion
|
||||
}
|
||||
}
|
||||
return apiVersion, err
|
||||
}
|
||||
|
||||
func parseVersion(versionString string, regex *regexp.Regexp, length int) ([]int, error) {
|
||||
matches := regex.FindAllStringSubmatch(versionString, -1)
|
||||
if len(matches) != 1 {
|
||||
return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", versionString, regex.String())
|
||||
}
|
||||
versionStringArray := matches[0][1:]
|
||||
versionArray := make([]int, length)
|
||||
for index, versionStr := range versionStringArray {
|
||||
version, err := strconv.Atoi(versionStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", versionStr, versionString)
|
||||
}
|
||||
versionArray[index] = version
|
||||
}
|
||||
return versionArray, nil
|
||||
}
|
396
vendor/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
396
vendor/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
@@ -1,396 +0,0 @@
|
||||
// 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 docker
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver"
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
dockerutil "github.com/google/cadvisor/container/docker/utils"
|
||||
"github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/devicemapper"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/machine"
|
||||
"github.com/google/cadvisor/watcher"
|
||||
"github.com/google/cadvisor/zfs"
|
||||
|
||||
docker "github.com/docker/docker/client"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
var ArgDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint")
|
||||
var ArgDockerTLS = flag.Bool("docker-tls", false, "use TLS to connect to docker")
|
||||
var ArgDockerCert = flag.String("docker-tls-cert", "cert.pem", "path to client certificate")
|
||||
var ArgDockerKey = flag.String("docker-tls-key", "key.pem", "path to private key")
|
||||
var ArgDockerCA = flag.String("docker-tls-ca", "ca.pem", "path to trusted CA")
|
||||
|
||||
var dockerEnvMetadataWhiteList = flag.String("docker_env_metadata_whitelist", "", "DEPRECATED: this flag will be removed, please use `env_metadata_whitelist`. A comma-separated list of environment variable keys matched with specified prefix that needs to be collected for docker containers")
|
||||
|
||||
// The namespace under which Docker aliases are unique.
|
||||
const DockerNamespace = "docker"
|
||||
|
||||
// The retry times for getting docker root dir
|
||||
const rootDirRetries = 5
|
||||
|
||||
// The retry period for getting docker root dir, Millisecond
|
||||
const rootDirRetryPeriod time.Duration = 1000 * time.Millisecond
|
||||
|
||||
// Regexp that identifies docker cgroups, containers started with
|
||||
// --cgroup-parent have another prefix than 'docker'
|
||||
var dockerCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`)
|
||||
|
||||
var (
|
||||
// Basepath to all container specific information that libcontainer stores.
|
||||
dockerRootDir string
|
||||
|
||||
dockerRootDirFlag = flag.String("docker_root", "/var/lib/docker", "DEPRECATED: docker root is read from docker info (this is a fallback, default: /var/lib/docker)")
|
||||
|
||||
dockerRootDirOnce sync.Once
|
||||
|
||||
// flag that controls globally disabling thin_ls pending future enhancements.
|
||||
// in production, it has been found that thin_ls makes excessive use of iops.
|
||||
// in an iops restricted environment, usage of thin_ls must be controlled via blkio.
|
||||
// pending that enhancement, disable its usage.
|
||||
disableThinLs = true
|
||||
)
|
||||
|
||||
func RootDir() string {
|
||||
dockerRootDirOnce.Do(func() {
|
||||
for i := 0; i < rootDirRetries; i++ {
|
||||
status, err := Status()
|
||||
if err == nil && status.RootDir != "" {
|
||||
dockerRootDir = status.RootDir
|
||||
break
|
||||
} else {
|
||||
time.Sleep(rootDirRetryPeriod)
|
||||
}
|
||||
}
|
||||
if dockerRootDir == "" {
|
||||
dockerRootDir = *dockerRootDirFlag
|
||||
}
|
||||
})
|
||||
return dockerRootDir
|
||||
}
|
||||
|
||||
type storageDriver string
|
||||
|
||||
const (
|
||||
devicemapperStorageDriver storageDriver = "devicemapper"
|
||||
aufsStorageDriver storageDriver = "aufs"
|
||||
overlayStorageDriver storageDriver = "overlay"
|
||||
overlay2StorageDriver storageDriver = "overlay2"
|
||||
zfsStorageDriver storageDriver = "zfs"
|
||||
vfsStorageDriver storageDriver = "vfs"
|
||||
)
|
||||
|
||||
type dockerFactory struct {
|
||||
machineInfoFactory info.MachineInfoFactory
|
||||
|
||||
storageDriver storageDriver
|
||||
storageDir string
|
||||
|
||||
client *docker.Client
|
||||
|
||||
// Information about the mounted cgroup subsystems.
|
||||
cgroupSubsystems map[string]string
|
||||
|
||||
// Information about mounted filesystems.
|
||||
fsInfo fs.FsInfo
|
||||
|
||||
dockerVersion []int
|
||||
|
||||
dockerAPIVersion []int
|
||||
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
thinPoolName string
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
|
||||
zfsWatcher *zfs.ZfsWatcher
|
||||
}
|
||||
|
||||
func (f *dockerFactory) String() string {
|
||||
return DockerNamespace
|
||||
}
|
||||
|
||||
func (f *dockerFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dockerMetadataEnvAllowList := strings.Split(*dockerEnvMetadataWhiteList, ",")
|
||||
|
||||
// prefer using the unified metadataEnvAllowList
|
||||
if len(metadataEnvAllowList) != 0 {
|
||||
dockerMetadataEnvAllowList = metadataEnvAllowList
|
||||
}
|
||||
|
||||
handler, err = newDockerContainerHandler(
|
||||
client,
|
||||
name,
|
||||
f.machineInfoFactory,
|
||||
f.fsInfo,
|
||||
f.storageDriver,
|
||||
f.storageDir,
|
||||
f.cgroupSubsystems,
|
||||
inHostNamespace,
|
||||
dockerMetadataEnvAllowList,
|
||||
f.dockerVersion,
|
||||
f.includedMetrics,
|
||||
f.thinPoolName,
|
||||
f.thinPoolWatcher,
|
||||
f.zfsWatcher,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the Docker ID from the full container name.
|
||||
func ContainerNameToDockerId(name string) string {
|
||||
id := path.Base(name)
|
||||
|
||||
if matches := dockerCgroupRegexp.FindStringSubmatch(id); matches != nil {
|
||||
return matches[1]
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// isContainerName returns true if the cgroup with associated name
|
||||
// corresponds to a docker container.
|
||||
func isContainerName(name string) bool {
|
||||
// always ignore .mount cgroup even if associated with docker and delegate to systemd
|
||||
if strings.HasSuffix(name, ".mount") {
|
||||
return false
|
||||
}
|
||||
return dockerCgroupRegexp.MatchString(path.Base(name))
|
||||
}
|
||||
|
||||
// Docker handles all containers under /docker
|
||||
func (f *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||
// if the container is not associated with docker, we can't handle it or accept it.
|
||||
if !isContainerName(name) {
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
// Check if the container is known to docker and it is active.
|
||||
id := ContainerNameToDockerId(name)
|
||||
|
||||
// We assume that if Inspect fails then the container is not known to docker.
|
||||
ctnr, err := f.client.ContainerInspect(context.Background(), id)
|
||||
if err != nil || !ctnr.State.Running {
|
||||
return false, true, fmt.Errorf("error inspecting container: %v", err)
|
||||
}
|
||||
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
func (f *dockerFactory) DebugInfo() map[string][]string {
|
||||
return map[string][]string{}
|
||||
}
|
||||
|
||||
var (
|
||||
versionRegexpString = `(\d+)\.(\d+)\.(\d+)`
|
||||
versionRe = regexp.MustCompile(versionRegexpString)
|
||||
apiVersionRegexpString = `(\d+)\.(\d+)`
|
||||
apiVersionRe = regexp.MustCompile(apiVersionRegexpString)
|
||||
)
|
||||
|
||||
func startThinPoolWatcher(dockerInfo *dockertypes.Info) (*devicemapper.ThinPoolWatcher, error) {
|
||||
_, err := devicemapper.ThinLsBinaryPresent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ensureThinLsKernelVersion(machine.KernelVersion()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if disableThinLs {
|
||||
return nil, fmt.Errorf("usage of thin_ls is disabled to preserve iops")
|
||||
}
|
||||
|
||||
dockerThinPoolName, err := dockerutil.DockerThinPoolName(*dockerInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dockerMetadataDevice, err := dockerutil.DockerMetadataDevice(*dockerInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
thinPoolWatcher, err := devicemapper.NewThinPoolWatcher(dockerThinPoolName, dockerMetadataDevice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go thinPoolWatcher.Start()
|
||||
return thinPoolWatcher, nil
|
||||
}
|
||||
|
||||
func startZfsWatcher(dockerInfo *dockertypes.Info) (*zfs.ZfsWatcher, error) {
|
||||
filesystem, err := dockerutil.DockerZfsFilesystem(*dockerInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zfsWatcher, err := zfs.NewZfsWatcher(filesystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go zfsWatcher.Start()
|
||||
return zfsWatcher, nil
|
||||
}
|
||||
|
||||
func ensureThinLsKernelVersion(kernelVersion string) error {
|
||||
// kernel 4.4.0 has the proper bug fixes to allow thin_ls to work without corrupting the thin pool
|
||||
minKernelVersion := semver.MustParse("4.4.0")
|
||||
// RHEL 7 kernel 3.10.0 release >= 366 has the proper bug fixes backported from 4.4.0 to allow
|
||||
// thin_ls to work without corrupting the thin pool
|
||||
minRhel7KernelVersion := semver.MustParse("3.10.0")
|
||||
|
||||
matches := versionRe.FindStringSubmatch(kernelVersion)
|
||||
if len(matches) < 4 {
|
||||
return fmt.Errorf("error parsing kernel version: %q is not a semver", kernelVersion)
|
||||
}
|
||||
|
||||
sem, err := semver.Make(matches[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sem.GTE(minKernelVersion) {
|
||||
// kernel 4.4+ - good
|
||||
return nil
|
||||
}
|
||||
|
||||
// Certain RHEL/Centos 7.x kernels have a backport to fix the corruption bug
|
||||
if !strings.Contains(kernelVersion, ".el7") {
|
||||
// not a RHEL 7.x kernel - won't work
|
||||
return fmt.Errorf("kernel version 4.4.0 or later is required to use thin_ls - you have %q", kernelVersion)
|
||||
}
|
||||
|
||||
// RHEL/Centos 7.x from here on
|
||||
if sem.Major != 3 {
|
||||
// only 3.x kernels *may* work correctly
|
||||
return fmt.Errorf("RHEL/Centos 7.x kernel version 3.10.0-366 or later is required to use thin_ls - you have %q", kernelVersion)
|
||||
}
|
||||
|
||||
if sem.GT(minRhel7KernelVersion) {
|
||||
// 3.10.1+ - good
|
||||
return nil
|
||||
}
|
||||
|
||||
if sem.EQ(minRhel7KernelVersion) {
|
||||
// need to check release
|
||||
releaseRE := regexp.MustCompile(`^[^-]+-([0-9]+)\.`)
|
||||
releaseMatches := releaseRE.FindStringSubmatch(kernelVersion)
|
||||
if len(releaseMatches) != 2 {
|
||||
return fmt.Errorf("unable to determine RHEL/Centos 7.x kernel release from %q", kernelVersion)
|
||||
}
|
||||
|
||||
release, err := strconv.Atoi(releaseMatches[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing release %q: %v", releaseMatches[1], err)
|
||||
}
|
||||
|
||||
if release >= 366 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("RHEL/Centos 7.x kernel version 3.10.0-366 or later is required to use thin_ls - you have %q", kernelVersion)
|
||||
}
|
||||
|
||||
// Register root container before running this function!
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) error {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
|
||||
dockerInfo, err := ValidateInfo()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to validate Docker info: %v", err)
|
||||
}
|
||||
|
||||
// Version already validated above, assume no error here.
|
||||
dockerVersion, _ := parseVersion(dockerInfo.ServerVersion, versionRe, 3)
|
||||
|
||||
dockerAPIVersion, _ := APIVersion()
|
||||
|
||||
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems(includedMetrics)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
thinPoolName string
|
||||
zfsWatcher *zfs.ZfsWatcher
|
||||
)
|
||||
if includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
if storageDriver(dockerInfo.Driver) == devicemapperStorageDriver {
|
||||
thinPoolWatcher, err = startThinPoolWatcher(dockerInfo)
|
||||
if err != nil {
|
||||
klog.Errorf("devicemapper filesystem stats will not be reported: %v", err)
|
||||
}
|
||||
|
||||
// Safe to ignore error - driver status should always be populated.
|
||||
status, _ := StatusFromDockerInfo(*dockerInfo)
|
||||
thinPoolName = status.DriverStatus[dockerutil.DriverStatusPoolName]
|
||||
}
|
||||
|
||||
if storageDriver(dockerInfo.Driver) == zfsStorageDriver {
|
||||
zfsWatcher, err = startZfsWatcher(dockerInfo)
|
||||
if err != nil {
|
||||
klog.Errorf("zfs filesystem stats will not be reported: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
klog.V(1).Infof("Registering Docker factory")
|
||||
f := &dockerFactory{
|
||||
cgroupSubsystems: cgroupSubsystems,
|
||||
client: client,
|
||||
dockerVersion: dockerVersion,
|
||||
dockerAPIVersion: dockerAPIVersion,
|
||||
fsInfo: fsInfo,
|
||||
machineInfoFactory: factory,
|
||||
storageDriver: storageDriver(dockerInfo.Driver),
|
||||
storageDir: RootDir(),
|
||||
includedMetrics: includedMetrics,
|
||||
thinPoolName: thinPoolName,
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
zfsWatcher: zfsWatcher,
|
||||
}
|
||||
|
||||
container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
return nil
|
||||
}
|
517
vendor/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
517
vendor/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
@@ -1,517 +0,0 @@
|
||||
// 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 Docker containers.
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
dockerutil "github.com/google/cadvisor/container/docker/utils"
|
||||
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/devicemapper"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/zfs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
|
||||
dockercontainer "github.com/docker/docker/api/types/container"
|
||||
docker "github.com/docker/docker/client"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
// The read write layers exist here.
|
||||
aufsRWLayer = "diff"
|
||||
overlayRWLayer = "upper"
|
||||
overlay2RWLayer = "diff"
|
||||
|
||||
// Path to the directory where docker stores log files if the json logging driver is enabled.
|
||||
pathToContainersDir = "containers"
|
||||
)
|
||||
|
||||
type dockerContainerHandler struct {
|
||||
// machineInfoFactory provides info.MachineInfo
|
||||
machineInfoFactory info.MachineInfoFactory
|
||||
|
||||
// Absolute path to the cgroup hierarchies of this container.
|
||||
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
|
||||
cgroupPaths map[string]string
|
||||
|
||||
// the docker storage driver
|
||||
storageDriver storageDriver
|
||||
fsInfo fs.FsInfo
|
||||
rootfsStorageDir string
|
||||
|
||||
// Time at which this container was created.
|
||||
creationTime time.Time
|
||||
|
||||
// Metadata associated with the container.
|
||||
envs map[string]string
|
||||
labels map[string]string
|
||||
|
||||
// Image name used for this container.
|
||||
image string
|
||||
|
||||
// The network mode of the container
|
||||
networkMode dockercontainer.NetworkMode
|
||||
|
||||
// Filesystem handler.
|
||||
fsHandler common.FsHandler
|
||||
|
||||
// The IP address of the container
|
||||
ipAddress string
|
||||
|
||||
includedMetrics container.MetricSet
|
||||
|
||||
// the devicemapper poolname
|
||||
poolName string
|
||||
|
||||
// zfsParent is the parent for docker zfs
|
||||
zfsParent string
|
||||
|
||||
// Reference to the container
|
||||
reference info.ContainerReference
|
||||
|
||||
libcontainerHandler *containerlibcontainer.Handler
|
||||
}
|
||||
|
||||
var _ container.ContainerHandler = &dockerContainerHandler{}
|
||||
|
||||
func getRwLayerID(containerID, storageDir string, sd storageDriver, dockerVersion []int) (string, error) {
|
||||
const (
|
||||
// Docker version >=1.10.0 have a randomized ID for the root fs of a container.
|
||||
randomizedRWLayerMinorVersion = 10
|
||||
rwLayerIDFile = "mount-id"
|
||||
)
|
||||
if (dockerVersion[0] <= 1) && (dockerVersion[1] < randomizedRWLayerMinorVersion) {
|
||||
return containerID, nil
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadFile(path.Join(storageDir, "image", string(sd), "layerdb", "mounts", containerID, rwLayerIDFile))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to identify the read-write layer ID for container %q. - %v", containerID, err)
|
||||
}
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
// newDockerContainerHandler returns a new container.ContainerHandler
|
||||
func newDockerContainerHandler(
|
||||
client *docker.Client,
|
||||
name string,
|
||||
machineInfoFactory info.MachineInfoFactory,
|
||||
fsInfo fs.FsInfo,
|
||||
storageDriver storageDriver,
|
||||
storageDir string,
|
||||
cgroupSubsystems map[string]string,
|
||||
inHostNamespace bool,
|
||||
metadataEnvAllowList []string,
|
||||
dockerVersion []int,
|
||||
includedMetrics container.MetricSet,
|
||||
thinPoolName string,
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher,
|
||||
zfsWatcher *zfs.ZfsWatcher,
|
||||
) (container.ContainerHandler, error) {
|
||||
// Create the cgroup paths.
|
||||
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems, name)
|
||||
|
||||
// Generate the equivalent cgroup manager for this container.
|
||||
cgroupManager, err := containerlibcontainer.NewCgroupManager(name, cgroupPaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rootFs := "/"
|
||||
if !inHostNamespace {
|
||||
rootFs = "/rootfs"
|
||||
storageDir = path.Join(rootFs, storageDir)
|
||||
}
|
||||
|
||||
id := ContainerNameToDockerId(name)
|
||||
|
||||
// Add the Containers dir where the log files are stored.
|
||||
// FIXME: Give `otherStorageDir` a more descriptive name.
|
||||
otherStorageDir := path.Join(storageDir, pathToContainersDir, id)
|
||||
|
||||
rwLayerID, err := getRwLayerID(id, storageDir, storageDriver, dockerVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Determine the rootfs storage dir OR the pool name to determine the device.
|
||||
// For devicemapper, we only need the thin pool name, and that is passed in to this call
|
||||
var (
|
||||
rootfsStorageDir string
|
||||
zfsFilesystem string
|
||||
zfsParent string
|
||||
)
|
||||
switch storageDriver {
|
||||
case aufsStorageDriver:
|
||||
rootfsStorageDir = path.Join(storageDir, string(aufsStorageDriver), aufsRWLayer, rwLayerID)
|
||||
case overlayStorageDriver:
|
||||
rootfsStorageDir = path.Join(storageDir, string(storageDriver), rwLayerID, overlayRWLayer)
|
||||
case overlay2StorageDriver:
|
||||
rootfsStorageDir = path.Join(storageDir, string(storageDriver), rwLayerID, overlay2RWLayer)
|
||||
case vfsStorageDriver:
|
||||
rootfsStorageDir = path.Join(storageDir)
|
||||
case zfsStorageDriver:
|
||||
status, err := Status()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to determine docker status: %v", err)
|
||||
}
|
||||
zfsParent = status.DriverStatus[dockerutil.DriverStatusParentDataset]
|
||||
zfsFilesystem = path.Join(zfsParent, rwLayerID)
|
||||
}
|
||||
|
||||
// We assume that if Inspect fails then the container is not known to docker.
|
||||
ctnr, err := client.ContainerInspect(context.Background(), id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to inspect container %q: %v", id, err)
|
||||
}
|
||||
|
||||
// TODO: extract object mother method
|
||||
handler := &dockerContainerHandler{
|
||||
machineInfoFactory: machineInfoFactory,
|
||||
cgroupPaths: cgroupPaths,
|
||||
fsInfo: fsInfo,
|
||||
storageDriver: storageDriver,
|
||||
poolName: thinPoolName,
|
||||
rootfsStorageDir: rootfsStorageDir,
|
||||
envs: make(map[string]string),
|
||||
labels: ctnr.Config.Labels,
|
||||
includedMetrics: includedMetrics,
|
||||
zfsParent: zfsParent,
|
||||
}
|
||||
// Timestamp returned by Docker is in time.RFC3339Nano format.
|
||||
handler.creationTime, err = time.Parse(time.RFC3339Nano, ctnr.Created)
|
||||
if err != nil {
|
||||
// This should not happen, report the error just in case
|
||||
return nil, fmt.Errorf("failed to parse the create timestamp %q for container %q: %v", ctnr.Created, id, err)
|
||||
}
|
||||
handler.libcontainerHandler = containerlibcontainer.NewHandler(cgroupManager, rootFs, ctnr.State.Pid, includedMetrics)
|
||||
|
||||
// Add the name and bare ID as aliases of the container.
|
||||
handler.reference = info.ContainerReference{
|
||||
Id: id,
|
||||
Name: name,
|
||||
Aliases: []string{strings.TrimPrefix(ctnr.Name, "/"), id},
|
||||
Namespace: DockerNamespace,
|
||||
}
|
||||
handler.image = ctnr.Config.Image
|
||||
handler.networkMode = ctnr.HostConfig.NetworkMode
|
||||
// Only adds restartcount label if it's greater than 0
|
||||
if ctnr.RestartCount > 0 {
|
||||
handler.labels["restartcount"] = strconv.Itoa(ctnr.RestartCount)
|
||||
}
|
||||
|
||||
// Obtain the IP address for the container.
|
||||
// If the NetworkMode starts with 'container:' then we need to use the IP address of the container specified.
|
||||
// This happens in cases such as kubernetes where the containers doesn't have an IP address itself and we need to use the pod's address
|
||||
ipAddress := ctnr.NetworkSettings.IPAddress
|
||||
networkMode := string(ctnr.HostConfig.NetworkMode)
|
||||
if ipAddress == "" && strings.HasPrefix(networkMode, "container:") {
|
||||
containerID := strings.TrimPrefix(networkMode, "container:")
|
||||
c, err := client.ContainerInspect(context.Background(), containerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to inspect container %q: %v", id, err)
|
||||
}
|
||||
ipAddress = c.NetworkSettings.IPAddress
|
||||
}
|
||||
|
||||
handler.ipAddress = ipAddress
|
||||
|
||||
if includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
handler.fsHandler = &dockerFsHandler{
|
||||
fsHandler: common.NewFsHandler(common.DefaultPeriod, rootfsStorageDir, otherStorageDir, fsInfo),
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
zfsWatcher: zfsWatcher,
|
||||
deviceID: ctnr.GraphDriver.Data["DeviceId"],
|
||||
zfsFilesystem: zfsFilesystem,
|
||||
}
|
||||
}
|
||||
|
||||
// split env vars to get metadata map.
|
||||
for _, exposedEnv := range metadataEnvAllowList {
|
||||
if exposedEnv == "" {
|
||||
// if no dockerEnvWhitelist provided, len(metadataEnvAllowList) == 1, metadataEnvAllowList[0] == ""
|
||||
continue
|
||||
}
|
||||
|
||||
for _, envVar := range ctnr.Config.Env {
|
||||
if envVar != "" {
|
||||
splits := strings.SplitN(envVar, "=", 2)
|
||||
if len(splits) == 2 && strings.HasPrefix(splits[0], exposedEnv) {
|
||||
handler.envs[strings.ToLower(splits[0])] = splits[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
// dockerFsHandler is a composite FsHandler implementation the incorporates
|
||||
// the common fs handler, a devicemapper ThinPoolWatcher, and a zfsWatcher
|
||||
type dockerFsHandler struct {
|
||||
fsHandler common.FsHandler
|
||||
|
||||
// thinPoolWatcher is the devicemapper thin pool watcher
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
// deviceID is the id of the container's fs device
|
||||
deviceID string
|
||||
|
||||
// zfsWatcher is the zfs filesystem watcher
|
||||
zfsWatcher *zfs.ZfsWatcher
|
||||
// zfsFilesystem is the docker zfs filesystem
|
||||
zfsFilesystem string
|
||||
}
|
||||
|
||||
var _ common.FsHandler = &dockerFsHandler{}
|
||||
|
||||
func (h *dockerFsHandler) Start() {
|
||||
h.fsHandler.Start()
|
||||
}
|
||||
|
||||
func (h *dockerFsHandler) Stop() {
|
||||
h.fsHandler.Stop()
|
||||
}
|
||||
|
||||
func (h *dockerFsHandler) Usage() common.FsUsage {
|
||||
usage := h.fsHandler.Usage()
|
||||
|
||||
// When devicemapper is the storage driver, the base usage of the container comes from the thin pool.
|
||||
// We still need the result of the fsHandler for any extra storage associated with the container.
|
||||
// To correctly factor in the thin pool usage, we should:
|
||||
// * Usage the thin pool usage as the base usage
|
||||
// * Calculate the overall usage by adding the overall usage from the fs handler to the thin pool usage
|
||||
if h.thinPoolWatcher != nil {
|
||||
thinPoolUsage, err := h.thinPoolWatcher.GetUsage(h.deviceID)
|
||||
if err != nil {
|
||||
// TODO: ideally we should keep track of how many times we failed to get the usage for this
|
||||
// device vs how many refreshes of the cache there have been, and display an error e.g. if we've
|
||||
// had at least 1 refresh and we still can't find the device.
|
||||
klog.V(5).Infof("unable to get fs usage from thin pool for device %s: %v", h.deviceID, err)
|
||||
} else {
|
||||
usage.BaseUsageBytes = thinPoolUsage
|
||||
usage.TotalUsageBytes += thinPoolUsage
|
||||
}
|
||||
}
|
||||
|
||||
if h.zfsWatcher != nil {
|
||||
zfsUsage, err := h.zfsWatcher.GetUsage(h.zfsFilesystem)
|
||||
if err != nil {
|
||||
klog.V(5).Infof("unable to get fs usage from zfs for filesystem %s: %v", h.zfsFilesystem, err)
|
||||
} else {
|
||||
usage.BaseUsageBytes = zfsUsage
|
||||
usage.TotalUsageBytes += zfsUsage
|
||||
}
|
||||
}
|
||||
return usage
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) Start() {
|
||||
if h.fsHandler != nil {
|
||||
h.fsHandler.Start()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) Cleanup() {
|
||||
if h.fsHandler != nil {
|
||||
h.fsHandler.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) ContainerReference() (info.ContainerReference, error) {
|
||||
return h.reference, nil
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) needNet() bool {
|
||||
if h.includedMetrics.Has(container.NetworkUsageMetrics) {
|
||||
return !h.networkMode.IsContainer()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||
hasFilesystem := h.includedMetrics.Has(container.DiskUsageMetrics)
|
||||
spec, err := common.GetSpec(h.cgroupPaths, h.machineInfoFactory, h.needNet(), hasFilesystem)
|
||||
|
||||
spec.Labels = h.labels
|
||||
spec.Envs = h.envs
|
||||
spec.Image = h.image
|
||||
spec.CreationTime = h.creationTime
|
||||
|
||||
return spec, err
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error {
|
||||
mi, err := h.machineInfoFactory.GetMachineInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if h.includedMetrics.Has(container.DiskIOMetrics) {
|
||||
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
|
||||
}
|
||||
|
||||
if !h.includedMetrics.Has(container.DiskUsageMetrics) {
|
||||
return nil
|
||||
}
|
||||
var device string
|
||||
switch h.storageDriver {
|
||||
case devicemapperStorageDriver:
|
||||
// Device has to be the pool name to correlate with the device name as
|
||||
// set in the machine info filesystems.
|
||||
device = h.poolName
|
||||
case aufsStorageDriver, overlayStorageDriver, overlay2StorageDriver, vfsStorageDriver:
|
||||
deviceInfo, err := h.fsInfo.GetDirFsDevice(h.rootfsStorageDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to determine device info for dir: %v: %v", h.rootfsStorageDir, err)
|
||||
}
|
||||
device = deviceInfo.Device
|
||||
case zfsStorageDriver:
|
||||
device = h.zfsParent
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
limit uint64
|
||||
fsType string
|
||||
)
|
||||
|
||||
var fsInfo *info.FsInfo
|
||||
|
||||
// Docker does not impose any filesystem limits for containers. So use capacity as limit.
|
||||
for _, fs := range mi.Filesystems {
|
||||
if fs.Device == device {
|
||||
limit = fs.Capacity
|
||||
fsType = fs.Type
|
||||
fsInfo = &fs
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fsStat := info.FsStats{Device: device, Type: fsType, Limit: limit}
|
||||
usage := h.fsHandler.Usage()
|
||||
fsStat.BaseUsage = usage.BaseUsageBytes
|
||||
fsStat.Usage = usage.TotalUsageBytes
|
||||
fsStat.Inodes = usage.InodeUsage
|
||||
|
||||
if fsInfo != nil {
|
||||
fileSystems, err := h.fsInfo.GetGlobalFsInfo()
|
||||
|
||||
if err == nil {
|
||||
addDiskStats(fileSystems, fsInfo, &fsStat)
|
||||
} else {
|
||||
klog.Errorf("Unable to obtain diskstats for filesystem %s: %v", fsStat.Device, err)
|
||||
}
|
||||
}
|
||||
|
||||
stats.Filesystem = append(stats.Filesystem, fsStat)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addDiskStats(fileSystems []fs.Fs, fsInfo *info.FsInfo, fsStats *info.FsStats) {
|
||||
if fsInfo == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, fileSys := range fileSystems {
|
||||
if fsInfo.DeviceMajor == fileSys.DiskStats.Major &&
|
||||
fsInfo.DeviceMinor == fileSys.DiskStats.Minor {
|
||||
fsStats.ReadsCompleted = fileSys.DiskStats.ReadsCompleted
|
||||
fsStats.ReadsMerged = fileSys.DiskStats.ReadsMerged
|
||||
fsStats.SectorsRead = fileSys.DiskStats.SectorsRead
|
||||
fsStats.ReadTime = fileSys.DiskStats.ReadTime
|
||||
fsStats.WritesCompleted = fileSys.DiskStats.WritesCompleted
|
||||
fsStats.WritesMerged = fileSys.DiskStats.WritesMerged
|
||||
fsStats.SectorsWritten = fileSys.DiskStats.SectorsWritten
|
||||
fsStats.WriteTime = fileSys.DiskStats.WriteTime
|
||||
fsStats.IoInProgress = fileSys.DiskStats.IoInProgress
|
||||
fsStats.IoTime = fileSys.DiskStats.IoTime
|
||||
fsStats.WeightedIoTime = fileSys.DiskStats.WeightedIoTime
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(vmarmol): Get from libcontainer API instead of cgroup manager when we don't have to support older Dockers.
|
||||
func (h *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
|
||||
stats, err := h.libcontainerHandler.GetStats()
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// Clean up stats for containers that don't have their own network - this
|
||||
// includes containers running in Kubernetes pods that use the network of the
|
||||
// infrastructure container. This stops metrics being reported multiple times
|
||||
// for each container in a pod.
|
||||
if !h.needNet() {
|
||||
stats.Network = info.NetworkStats{}
|
||||
}
|
||||
|
||||
// Get filesystem stats.
|
||||
err = h.getFsStats(stats)
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||
// No-op for Docker driver.
|
||||
return []info.ContainerReference{}, nil
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) GetCgroupPath(resource string) (string, error) {
|
||||
var res string
|
||||
if !cgroups.IsCgroup2UnifiedMode() {
|
||||
res = resource
|
||||
}
|
||||
path, ok := h.cgroupPaths[res]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not find path for resource %q for container %q", resource, h.reference.Name)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) GetContainerLabels() map[string]string {
|
||||
return h.labels
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) GetContainerIPAddress() string {
|
||||
return h.ipAddress
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
|
||||
return h.libcontainerHandler.GetProcesses()
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) Exists() bool {
|
||||
return common.CgroupExists(h.cgroupPaths)
|
||||
}
|
||||
|
||||
func (h *dockerContainerHandler) Type() container.ContainerType {
|
||||
return container.ContainerTypeDocker
|
||||
}
|
30
vendor/github.com/google/cadvisor/container/docker/install/install.go
generated
vendored
30
vendor/github.com/google/cadvisor/container/docker/install/install.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// The install package registers docker.NewPlugin() as the "docker" container provider when imported
|
||||
package install
|
||||
|
||||
import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/docker"
|
||||
)
|
||||
|
||||
func init() {
|
||||
err := container.RegisterPlugin("docker", docker.NewPlugin())
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to register docker plugin: %v", err)
|
||||
}
|
||||
}
|
78
vendor/github.com/google/cadvisor/container/docker/plugin.go
generated
vendored
78
vendor/github.com/google/cadvisor/container/docker/plugin.go
generated
vendored
@@ -1,78 +0,0 @@
|
||||
// Copyright 2019 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 docker
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/watcher"
|
||||
)
|
||||
|
||||
const dockerClientTimeout = 10 * time.Second
|
||||
|
||||
// NewPlugin returns an implementation of container.Plugin suitable for passing to container.RegisterPlugin()
|
||||
func NewPlugin() container.Plugin {
|
||||
return &plugin{}
|
||||
}
|
||||
|
||||
type plugin struct{}
|
||||
|
||||
func (p *plugin) InitializeFSContext(context *fs.Context) error {
|
||||
SetTimeout(dockerClientTimeout)
|
||||
// Try to connect to docker indefinitely on startup.
|
||||
dockerStatus := retryDockerStatus()
|
||||
context.Docker = fs.DockerContext{
|
||||
Root: RootDir(),
|
||||
Driver: dockerStatus.Driver,
|
||||
DriverStatus: dockerStatus.DriverStatus,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *plugin) Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, includedMetrics container.MetricSet) (watcher.ContainerWatcher, error) {
|
||||
err := Register(factory, fsInfo, includedMetrics)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func retryDockerStatus() info.DockerStatus {
|
||||
startupTimeout := dockerClientTimeout
|
||||
maxTimeout := 4 * startupTimeout
|
||||
for {
|
||||
ctx, _ := context.WithTimeout(context.Background(), startupTimeout)
|
||||
dockerStatus, err := StatusWithContext(ctx)
|
||||
if err == nil {
|
||||
return dockerStatus
|
||||
}
|
||||
|
||||
switch err {
|
||||
case context.DeadlineExceeded:
|
||||
klog.Warningf("Timeout trying to communicate with docker during initialization, will retry")
|
||||
default:
|
||||
klog.V(5).Infof("Docker not connected: %v", err)
|
||||
return info.DockerStatus{}
|
||||
}
|
||||
|
||||
startupTimeout = 2 * startupTimeout
|
||||
if startupTimeout > maxTimeout {
|
||||
startupTimeout = maxTimeout
|
||||
}
|
||||
}
|
||||
}
|
77
vendor/github.com/google/cadvisor/container/docker/utils/docker.go
generated
vendored
77
vendor/github.com/google/cadvisor/container/docker/utils/docker.go
generated
vendored
@@ -1,77 +0,0 @@
|
||||
// Copyright 2016 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 utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
dockertypes "github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
const (
|
||||
DriverStatusPoolName = "Pool Name"
|
||||
DriverStatusMetadataFile = "Metadata file"
|
||||
DriverStatusParentDataset = "Parent Dataset"
|
||||
)
|
||||
|
||||
func DriverStatusValue(status [][2]string, target string) string {
|
||||
for _, v := range status {
|
||||
if strings.EqualFold(v[0], target) {
|
||||
return v[1]
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func DockerThinPoolName(info dockertypes.Info) (string, error) {
|
||||
poolName := DriverStatusValue(info.DriverStatus, DriverStatusPoolName)
|
||||
if len(poolName) == 0 {
|
||||
return "", fmt.Errorf("Could not get devicemapper pool name")
|
||||
}
|
||||
|
||||
return poolName, nil
|
||||
}
|
||||
|
||||
func DockerMetadataDevice(info dockertypes.Info) (string, error) {
|
||||
metadataDevice := DriverStatusValue(info.DriverStatus, DriverStatusMetadataFile)
|
||||
if len(metadataDevice) != 0 {
|
||||
return metadataDevice, nil
|
||||
}
|
||||
|
||||
poolName, err := DockerThinPoolName(info)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
metadataDevice = fmt.Sprintf("/dev/mapper/%s_tmeta", poolName)
|
||||
|
||||
if _, err := os.Stat(metadataDevice); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return metadataDevice, nil
|
||||
}
|
||||
|
||||
func DockerZfsFilesystem(info dockertypes.Info) (string, error) {
|
||||
filesystem := DriverStatusValue(info.DriverStatus, DriverStatusParentDataset)
|
||||
if len(filesystem) == 0 {
|
||||
return "", fmt.Errorf("Could not get zfs filesystem")
|
||||
}
|
||||
|
||||
return filesystem, nil
|
||||
}
|
113
vendor/github.com/google/cadvisor/zfs/watcher.go
generated
vendored
113
vendor/github.com/google/cadvisor/zfs/watcher.go
generated
vendored
@@ -1,113 +0,0 @@
|
||||
// Copyright 2016 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 zfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
zfs "github.com/mistifyio/go-zfs"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// zfsWatcher maintains a cache of filesystem -> usage stats for a
|
||||
// zfs filesystem
|
||||
type ZfsWatcher struct {
|
||||
filesystem string
|
||||
lock *sync.RWMutex
|
||||
cache map[string]uint64
|
||||
period time.Duration
|
||||
stopChan chan struct{}
|
||||
}
|
||||
|
||||
// NewThinPoolWatcher returns a new ThinPoolWatcher for the given devicemapper
|
||||
// thin pool name and metadata device or an error.
|
||||
func NewZfsWatcher(filesystem string) (*ZfsWatcher, error) {
|
||||
|
||||
return &ZfsWatcher{
|
||||
filesystem: filesystem,
|
||||
lock: &sync.RWMutex{},
|
||||
cache: make(map[string]uint64),
|
||||
period: 15 * time.Second,
|
||||
stopChan: make(chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Start starts the ZfsWatcher.
|
||||
func (w *ZfsWatcher) Start() {
|
||||
err := w.Refresh()
|
||||
if err != nil {
|
||||
klog.Errorf("encountered error refreshing zfs watcher: %v", err)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-w.stopChan:
|
||||
return
|
||||
case <-time.After(w.period):
|
||||
start := time.Now()
|
||||
err = w.Refresh()
|
||||
if err != nil {
|
||||
klog.Errorf("encountered error refreshing zfs watcher: %v", err)
|
||||
}
|
||||
|
||||
// print latency for refresh
|
||||
duration := time.Since(start)
|
||||
klog.V(5).Infof("zfs(%d) took %s", start.Unix(), duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the ZfsWatcher.
|
||||
func (w *ZfsWatcher) Stop() {
|
||||
close(w.stopChan)
|
||||
}
|
||||
|
||||
// GetUsage gets the cached usage value of the given filesystem.
|
||||
func (w *ZfsWatcher) GetUsage(filesystem string) (uint64, error) {
|
||||
w.lock.RLock()
|
||||
defer w.lock.RUnlock()
|
||||
|
||||
v, ok := w.cache[filesystem]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("no cached value for usage of filesystem %v", filesystem)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Refresh performs a zfs get
|
||||
func (w *ZfsWatcher) Refresh() error {
|
||||
w.lock.Lock()
|
||||
defer w.lock.Unlock()
|
||||
newCache := make(map[string]uint64)
|
||||
parent, err := zfs.GetDataset(w.filesystem)
|
||||
if err != nil {
|
||||
klog.Errorf("encountered error getting zfs filesystem: %s: %v", w.filesystem, err)
|
||||
return err
|
||||
}
|
||||
children, err := parent.Children(0)
|
||||
if err != nil {
|
||||
klog.Errorf("encountered error getting children of zfs filesystem: %s: %v", w.filesystem, err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ds := range children {
|
||||
newCache[ds.Name] = ds.Used
|
||||
}
|
||||
|
||||
w.cache = newCache
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user