Bump cAdvisor (and dependencies) godeps version
This commit is contained in:
21
vendor/github.com/google/cadvisor/container/common/helpers.go
generated
vendored
21
vendor/github.com/google/cadvisor/container/common/helpers.go
generated
vendored
@@ -23,6 +23,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/utils"
|
||||
|
||||
@@ -201,3 +202,23 @@ func CgroupExists(cgroupPaths map[string]string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ListContainers(name string, cgroupPaths map[string]string, listType container.ListType) ([]info.ContainerReference, error) {
|
||||
containers := make(map[string]struct{})
|
||||
for _, cgroupPath := range cgroupPaths {
|
||||
err := ListDirectories(cgroupPath, name, listType == container.ListRecursive, containers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Make into container references.
|
||||
ret := make([]info.ContainerReference, 0, len(containers))
|
||||
for cont := range containers {
|
||||
ret = append(ret, info.ContainerReference{
|
||||
Name: cont,
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
30
vendor/github.com/google/cadvisor/container/container.go
generated
vendored
30
vendor/github.com/google/cadvisor/container/container.go
generated
vendored
@@ -27,23 +27,15 @@ const (
|
||||
ListRecursive
|
||||
)
|
||||
|
||||
// SubcontainerEventType indicates an addition or deletion event.
|
||||
type SubcontainerEventType int
|
||||
type ContainerType int
|
||||
|
||||
const (
|
||||
SubcontainerAdd SubcontainerEventType = iota
|
||||
SubcontainerDelete
|
||||
ContainerTypeRaw ContainerType = iota
|
||||
ContainerTypeDocker
|
||||
ContainerTypeRkt
|
||||
ContainerTypeSystemd
|
||||
)
|
||||
|
||||
// SubcontainerEvent represents a
|
||||
type SubcontainerEvent struct {
|
||||
// The type of event that occurred.
|
||||
EventType SubcontainerEventType
|
||||
|
||||
// The full container name of the container where the event occurred.
|
||||
Name string
|
||||
}
|
||||
|
||||
// Interface for container operation handlers.
|
||||
type ContainerHandler interface {
|
||||
// Returns the ContainerReference
|
||||
@@ -58,18 +50,9 @@ type ContainerHandler interface {
|
||||
// Returns the subcontainers of this container.
|
||||
ListContainers(listType ListType) ([]info.ContainerReference, error)
|
||||
|
||||
// Returns the threads inside this container.
|
||||
ListThreads(listType ListType) ([]int, error)
|
||||
|
||||
// Returns the processes inside this container.
|
||||
ListProcesses(listType ListType) ([]int, error)
|
||||
|
||||
// Registers a channel to listen for events affecting subcontainers (recursively).
|
||||
WatchSubcontainers(events chan SubcontainerEvent) error
|
||||
|
||||
// Stops watching for subcontainer changes.
|
||||
StopWatchingSubcontainers() error
|
||||
|
||||
// Returns absolute cgroup path for the requested resource.
|
||||
GetCgroupPath(resource string) (string, error)
|
||||
|
||||
@@ -85,4 +68,7 @@ type ContainerHandler interface {
|
||||
// Start starts any necessary background goroutines - must be cleaned up in Cleanup().
|
||||
// It is expected that most implementations will be a no-op.
|
||||
Start()
|
||||
|
||||
// Type of handler
|
||||
Type() ContainerType
|
||||
}
|
||||
|
12
vendor/github.com/google/cadvisor/container/docker/client.go
generated
vendored
12
vendor/github.com/google/cadvisor/container/docker/client.go
generated
vendored
@@ -20,18 +20,18 @@ package docker
|
||||
import (
|
||||
"sync"
|
||||
|
||||
dclient "github.com/fsouza/go-dockerclient"
|
||||
dclient "github.com/docker/engine-api/client"
|
||||
)
|
||||
|
||||
var (
|
||||
dockerClient *dclient.Client
|
||||
dockerClientErr error
|
||||
once sync.Once
|
||||
dockerClient *dclient.Client
|
||||
dockerClientErr error
|
||||
dockerClientOnce sync.Once
|
||||
)
|
||||
|
||||
func Client() (*dclient.Client, error) {
|
||||
once.Do(func() {
|
||||
dockerClient, dockerClientErr = dclient.NewClient(*ArgDockerEndpoint)
|
||||
dockerClientOnce.Do(func() {
|
||||
dockerClient, dockerClientErr = dclient.NewClient(*ArgDockerEndpoint, "", nil, nil)
|
||||
})
|
||||
return dockerClient, dockerClientErr
|
||||
}
|
||||
|
163
vendor/github.com/google/cadvisor/container/docker/docker.go
generated
vendored
Normal file
163
vendor/github.com/google/cadvisor/container/docker/docker.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
// 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"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
dockertypes "github.com/docker/engine-api/types"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/machine"
|
||||
)
|
||||
|
||||
func Status() (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(context.Background())
|
||||
if err != nil {
|
||||
return v1.DockerStatus{}, err
|
||||
}
|
||||
|
||||
out := v1.DockerStatus{}
|
||||
out.Version = VersionString()
|
||||
out.KernelVersion = machine.KernelVersion()
|
||||
out.OS = dockerInfo.OperatingSystem
|
||||
out.Hostname = dockerInfo.Name
|
||||
out.RootDir = dockerInfo.DockerRootDir
|
||||
out.Driver = dockerInfo.Driver
|
||||
out.ExecDriver = dockerInfo.ExecutionDriver
|
||||
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]
|
||||
}
|
||||
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(context.Background(), 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(context.Background())
|
||||
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(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get docker version: %v", err)
|
||||
}
|
||||
dockerInfo.ServerVersion = version.Version
|
||||
}
|
||||
version, err := parseDockerVersion(dockerInfo.ServerVersion)
|
||||
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)
|
||||
}
|
||||
|
||||
// Check that the libcontainer execdriver is used if the version is < 1.11
|
||||
// (execution drivers are no longer supported as of 1.11).
|
||||
if version[0] <= 1 && version[1] <= 10 &&
|
||||
!strings.HasPrefix(dockerInfo.ExecutionDriver, "native") {
|
||||
return nil, fmt.Errorf("docker found, but not using native exec driver")
|
||||
}
|
||||
|
||||
if dockerInfo.Driver == "" {
|
||||
return nil, fmt.Errorf("failed to find docker storage driver")
|
||||
}
|
||||
|
||||
return &dockerInfo, nil
|
||||
}
|
||||
|
||||
func Version() ([]int, error) {
|
||||
return parseDockerVersion(VersionString())
|
||||
}
|
||||
|
||||
func VersionString() string {
|
||||
docker_version := "Unknown"
|
||||
client, err := Client()
|
||||
if err == nil {
|
||||
version, err := client.ServerVersion(context.Background())
|
||||
if err == nil {
|
||||
docker_version = version.Version
|
||||
}
|
||||
}
|
||||
return docker_version
|
||||
}
|
||||
|
||||
// TODO: switch to a semantic versioning library.
|
||||
func parseDockerVersion(full_version_string string) ([]int, error) {
|
||||
matches := version_re.FindAllStringSubmatch(full_version_string, -1)
|
||||
if len(matches) != 1 {
|
||||
return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", full_version_string, version_regexp_string)
|
||||
}
|
||||
version_string_array := matches[0][1:]
|
||||
version_array := make([]int, 3)
|
||||
for index, version_string := range version_string_array {
|
||||
version, err := strconv.Atoi(version_string)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", version_string, full_version_string)
|
||||
}
|
||||
version_array[index] = version
|
||||
}
|
||||
return version_array, nil
|
||||
}
|
96
vendor/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
96
vendor/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
@@ -19,27 +19,26 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"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/manager/watcher"
|
||||
dockerutil "github.com/google/cadvisor/utils/docker"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
docker "github.com/docker/engine-api/client"
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var ArgDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint")
|
||||
|
||||
// The namespace under which Docker aliases are unique.
|
||||
var DockerNamespace = "docker"
|
||||
|
||||
// Basepath to all container specific information that libcontainer stores.
|
||||
// TODO: Deprecate this flag
|
||||
var dockerRootDir = flag.String("docker_root", "/var/lib/docker", "Absolute path to the Docker state root directory (default: /var/lib/docker)")
|
||||
var dockerRunDir = flag.String("docker_run", "/var/run/docker", "Absolute path to the Docker run directory (default: /var/run/docker)")
|
||||
const DockerNamespace = "docker"
|
||||
|
||||
// Regexp that identifies docker cgroups, containers started with
|
||||
// --cgroup-parent have another prefix than 'docker'
|
||||
@@ -47,24 +46,30 @@ var dockerCgroupRegexp = regexp.MustCompile(`([a-z0-9]{64})`)
|
||||
|
||||
var dockerEnvWhitelist = flag.String("docker_env_metadata_whitelist", "", "a comma-separated list of environment variable keys that needs to be collected for docker containers")
|
||||
|
||||
// TODO(vmarmol): Export run dir too for newer Dockers.
|
||||
// Directory holding Docker container state information.
|
||||
func DockerStateDir() string {
|
||||
return libcontainer.DockerStateDir(*dockerRootDir)
|
||||
}
|
||||
var (
|
||||
// Basepath to all container specific information that libcontainer stores.
|
||||
dockerRootDir string
|
||||
|
||||
const (
|
||||
dockerRootDirKey = "Root Dir"
|
||||
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
|
||||
)
|
||||
|
||||
func RootDir() string {
|
||||
return *dockerRootDir
|
||||
dockerRootDirOnce.Do(func() {
|
||||
status, err := Status()
|
||||
if err == nil && status.RootDir != "" {
|
||||
dockerRootDir = status.RootDir
|
||||
} else {
|
||||
dockerRootDir = *dockerRootDirFlag
|
||||
}
|
||||
})
|
||||
return dockerRootDir
|
||||
}
|
||||
|
||||
type storageDriver string
|
||||
|
||||
const (
|
||||
// TODO: Add support for devicemapper storage usage.
|
||||
devicemapperStorageDriver storageDriver = "devicemapper"
|
||||
aufsStorageDriver storageDriver = "aufs"
|
||||
overlayStorageDriver storageDriver = "overlay"
|
||||
@@ -88,6 +93,8 @@ type dockerFactory struct {
|
||||
dockerVersion []int
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
}
|
||||
|
||||
func (self *dockerFactory) String() string {
|
||||
@@ -114,6 +121,7 @@ func (self *dockerFactory) NewContainerHandler(name string, inHostNamespace bool
|
||||
metadataEnvs,
|
||||
self.dockerVersion,
|
||||
self.ignoreMetrics,
|
||||
self.thinPoolWatcher,
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -146,7 +154,7 @@ func (self *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||
id := ContainerNameToDockerId(name)
|
||||
|
||||
// We assume that if Inspect fails then the container is not known to docker.
|
||||
ctnr, err := self.client.InspectContainer(id)
|
||||
ctnr, err := self.client.ContainerInspect(context.Background(), id)
|
||||
if err != nil || !ctnr.State.Running {
|
||||
return false, canAccept, fmt.Errorf("error inspecting container: %v", err)
|
||||
}
|
||||
@@ -163,24 +171,6 @@ var (
|
||||
version_re = regexp.MustCompile(version_regexp_string)
|
||||
)
|
||||
|
||||
// TODO: switch to a semantic versioning library.
|
||||
func parseDockerVersion(full_version_string string) ([]int, error) {
|
||||
matches := version_re.FindAllStringSubmatch(full_version_string, -1)
|
||||
if len(matches) != 1 {
|
||||
return nil, fmt.Errorf("version string \"%v\" doesn't match expected regular expression: \"%v\"", full_version_string, version_regexp_string)
|
||||
}
|
||||
version_string_array := matches[0][1:]
|
||||
version_array := make([]int, 3)
|
||||
for index, version_string := range version_string_array {
|
||||
version, err := strconv.Atoi(version_string)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while parsing \"%v\" in \"%v\"", version_string, full_version_string)
|
||||
}
|
||||
version_array[index] = version
|
||||
}
|
||||
return version_array, nil
|
||||
}
|
||||
|
||||
// Register root container before running this function!
|
||||
func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
client, err := Client()
|
||||
@@ -196,16 +186,35 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
||||
// Version already validated above, assume no error here.
|
||||
dockerVersion, _ := parseDockerVersion(dockerInfo.ServerVersion)
|
||||
|
||||
storageDir := dockerInfo.DockerRootDir
|
||||
if storageDir == "" {
|
||||
storageDir = *dockerRootDir
|
||||
}
|
||||
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
|
||||
}
|
||||
|
||||
glog.Infof("Registering Docker factory")
|
||||
var (
|
||||
dockerStorageDriver = storageDriver(dockerInfo.Driver)
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher = nil
|
||||
)
|
||||
|
||||
if dockerStorageDriver == devicemapperStorageDriver {
|
||||
// If the storage drive is devicemapper, create and start a
|
||||
// ThinPoolWatcher to monitor the size of container CoW layers with
|
||||
// thin_ls.
|
||||
dockerThinPoolName, err := dockerutil.DockerThinPoolName(*dockerInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't find device mapper thin pool name: %v", err)
|
||||
}
|
||||
|
||||
dockerMetadataDevice, err := dockerutil.DockerMetadataDevice(*dockerInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't determine devicemapper metadata device")
|
||||
}
|
||||
|
||||
thinPoolWatcher = devicemapper.NewThinPoolWatcher(dockerThinPoolName, dockerMetadataDevice)
|
||||
go thinPoolWatcher.Start()
|
||||
}
|
||||
|
||||
glog.Infof("registering Docker factory")
|
||||
f := &dockerFactory{
|
||||
cgroupSubsystems: cgroupSubsystems,
|
||||
client: client,
|
||||
@@ -213,10 +222,11 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
|
||||
fsInfo: fsInfo,
|
||||
machineInfoFactory: factory,
|
||||
storageDriver: storageDriver(dockerInfo.Driver),
|
||||
storageDir: storageDir,
|
||||
storageDir: RootDir(),
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
}
|
||||
|
||||
container.RegisterContainerHandlerFactory(f)
|
||||
container.RegisterContainerHandlerFactory(f, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
return nil
|
||||
}
|
||||
|
210
vendor/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
210
vendor/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
@@ -25,13 +25,18 @@ import (
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/devicemapper"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
dockerutil "github.com/google/cadvisor/utils/docker"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
docker "github.com/docker/engine-api/client"
|
||||
dockercontainer "github.com/docker/engine-api/types/container"
|
||||
"github.com/golang/glog"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -55,10 +60,18 @@ type dockerContainerHandler struct {
|
||||
// Manager of this container's cgroups.
|
||||
cgroupManager cgroups.Manager
|
||||
|
||||
// the docker storage driver
|
||||
storageDriver storageDriver
|
||||
fsInfo fs.FsInfo
|
||||
rootfsStorageDir string
|
||||
|
||||
// devicemapper state
|
||||
|
||||
// the devicemapper poolname
|
||||
poolName string
|
||||
// the devicemapper device id for the container
|
||||
deviceID string
|
||||
|
||||
// Time at which this container was created.
|
||||
creationTime time.Time
|
||||
|
||||
@@ -76,14 +89,19 @@ type dockerContainerHandler struct {
|
||||
rootFs string
|
||||
|
||||
// The network mode of the container
|
||||
networkMode string
|
||||
networkMode dockercontainer.NetworkMode
|
||||
|
||||
// Filesystem handler.
|
||||
fsHandler common.FsHandler
|
||||
|
||||
ignoreMetrics container.MetricSet
|
||||
|
||||
// thin pool watcher
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -101,6 +119,7 @@ func getRwLayerID(containerID, storageDir string, sd storageDriver, dockerVersio
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
// newDockerContainerHandler returns a new container.ContainerHandler
|
||||
func newDockerContainerHandler(
|
||||
client *docker.Client,
|
||||
name string,
|
||||
@@ -113,6 +132,7 @@ func newDockerContainerHandler(
|
||||
metadataEnvs []string,
|
||||
dockerVersion []int,
|
||||
ignoreMetrics container.MetricSet,
|
||||
thinPoolWatcher *devicemapper.ThinPoolWatcher,
|
||||
) (container.ContainerHandler, error) {
|
||||
// Create the cgroup paths.
|
||||
cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints))
|
||||
@@ -144,14 +164,27 @@ func newDockerContainerHandler(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var rootfsStorageDir string
|
||||
|
||||
// Determine the rootfs storage dir OR the pool name to determine the device
|
||||
var (
|
||||
rootfsStorageDir string
|
||||
poolName string
|
||||
)
|
||||
switch storageDriver {
|
||||
case aufsStorageDriver:
|
||||
rootfsStorageDir = path.Join(storageDir, string(aufsStorageDriver), aufsRWLayer, rwLayerID)
|
||||
case overlayStorageDriver:
|
||||
rootfsStorageDir = path.Join(storageDir, string(overlayStorageDriver), rwLayerID)
|
||||
case devicemapperStorageDriver:
|
||||
status, err := Status()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to determine docker status: %v", err)
|
||||
}
|
||||
|
||||
poolName = status.DriverStatus[dockerutil.DriverStatusPoolName]
|
||||
}
|
||||
|
||||
// TODO: extract object mother method
|
||||
handler := &dockerContainerHandler{
|
||||
id: id,
|
||||
client: client,
|
||||
@@ -162,21 +195,24 @@ func newDockerContainerHandler(
|
||||
storageDriver: storageDriver,
|
||||
fsInfo: fsInfo,
|
||||
rootFs: rootFs,
|
||||
poolName: poolName,
|
||||
rootfsStorageDir: rootfsStorageDir,
|
||||
envs: make(map[string]string),
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
}
|
||||
|
||||
if !ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
handler.fsHandler = common.NewFsHandler(time.Minute, rootfsStorageDir, otherStorageDir, fsInfo)
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
}
|
||||
|
||||
// We assume that if Inspect fails then the container is not known to docker.
|
||||
ctnr, err := client.InspectContainer(id)
|
||||
ctnr, err := client.ContainerInspect(context.Background(), id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to inspect container %q: %v", id, err)
|
||||
}
|
||||
handler.creationTime = ctnr.Created
|
||||
// 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.pid = ctnr.State.Pid
|
||||
|
||||
// Add the name and bare ID as aliases of the container.
|
||||
@@ -184,6 +220,15 @@ func newDockerContainerHandler(
|
||||
handler.labels = ctnr.Config.Labels
|
||||
handler.image = ctnr.Config.Image
|
||||
handler.networkMode = ctnr.HostConfig.NetworkMode
|
||||
handler.deviceID = ctnr.GraphDriver.Data["DeviceId"]
|
||||
|
||||
if !ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
handler.fsHandler = &dockerFsHandler{
|
||||
fsHandler: common.NewFsHandler(time.Minute, rootfsStorageDir, otherStorageDir, fsInfo),
|
||||
thinPoolWatcher: thinPoolWatcher,
|
||||
deviceID: handler.deviceID,
|
||||
}
|
||||
}
|
||||
|
||||
// split env vars to get metadata map.
|
||||
for _, exposedEnv := range metadataEnvs {
|
||||
@@ -198,6 +243,48 @@ func newDockerContainerHandler(
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
// dockerFsHandler is a composite FsHandler implementation the incorporates
|
||||
// the common fs handler and a devicemapper ThinPoolWatcher.
|
||||
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
|
||||
}
|
||||
|
||||
var _ common.FsHandler = &dockerFsHandler{}
|
||||
|
||||
func (h *dockerFsHandler) Start() {
|
||||
h.fsHandler.Start()
|
||||
}
|
||||
|
||||
func (h *dockerFsHandler) Stop() {
|
||||
h.fsHandler.Stop()
|
||||
}
|
||||
|
||||
func (h *dockerFsHandler) Usage() (uint64, uint64) {
|
||||
baseUsage, 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 {
|
||||
glog.Errorf("unable to get fs usage from thin pool for device %v: %v", h.deviceID, err)
|
||||
} else {
|
||||
baseUsage = thinPoolUsage
|
||||
usage += thinPoolUsage
|
||||
}
|
||||
}
|
||||
|
||||
return baseUsage, usage
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) Start() {
|
||||
if self.fsHandler != nil {
|
||||
self.fsHandler.Start()
|
||||
@@ -222,7 +309,7 @@ func (self *dockerContainerHandler) ContainerReference() (info.ContainerReferenc
|
||||
|
||||
func (self *dockerContainerHandler) needNet() bool {
|
||||
if !self.ignoreMetrics.Has(container.NetworkUsageMetrics) {
|
||||
return !strings.HasPrefix(self.networkMode, "container:")
|
||||
return !self.networkMode.IsContainer()
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -242,17 +329,22 @@ func (self *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error
|
||||
if self.ignoreMetrics.Has(container.DiskUsageMetrics) {
|
||||
return nil
|
||||
}
|
||||
var device string
|
||||
switch self.storageDriver {
|
||||
case devicemapperStorageDriver:
|
||||
// Device has to be the pool name to correlate with the device name as
|
||||
// set in the machine info filesystems.
|
||||
device = self.poolName
|
||||
case aufsStorageDriver, overlayStorageDriver, zfsStorageDriver:
|
||||
deviceInfo, err := self.fsInfo.GetDirFsDevice(self.rootfsStorageDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to determine device info for dir: %v: %v", self.rootfsStorageDir, err)
|
||||
}
|
||||
device = deviceInfo.Device
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
deviceInfo, err := self.fsInfo.GetDirFsDevice(self.rootfsStorageDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mi, err := self.machineInfoFactory.GetMachineInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -265,16 +357,16 @@ func (self *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error
|
||||
|
||||
// Docker does not impose any filesystem limits for containers. So use capacity as limit.
|
||||
for _, fs := range mi.Filesystems {
|
||||
if fs.Device == deviceInfo.Device {
|
||||
if fs.Device == device {
|
||||
limit = fs.Capacity
|
||||
fsType = fs.Type
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fsStat := info.FsStats{Device: deviceInfo.Device, Type: fsType, Limit: limit}
|
||||
|
||||
fsStat := info.FsStats{Device: device, Type: fsType, Limit: limit}
|
||||
fsStat.BaseUsage, fsStat.Usage = self.fsHandler.Usage()
|
||||
|
||||
stats.Filesystem = append(stats.Filesystem, fsStat)
|
||||
|
||||
return nil
|
||||
@@ -316,11 +408,6 @@ func (self *dockerContainerHandler) GetCgroupPath(resource string) (string, erro
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) ListThreads(listType container.ListType) ([]int, error) {
|
||||
// TODO(vmarmol): Implement.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) GetContainerLabels() map[string]string {
|
||||
return self.labels
|
||||
}
|
||||
@@ -329,83 +416,10 @@ func (self *dockerContainerHandler) ListProcesses(listType container.ListType) (
|
||||
return containerlibcontainer.GetProcesses(self.cgroupManager)
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) WatchSubcontainers(events chan container.SubcontainerEvent) error {
|
||||
return fmt.Errorf("watch is unimplemented in the Docker container driver")
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) StopWatchingSubcontainers() error {
|
||||
// No-op for Docker driver.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *dockerContainerHandler) Exists() bool {
|
||||
return common.CgroupExists(self.cgroupPaths)
|
||||
}
|
||||
|
||||
func DockerInfo() (docker.DockerInfo, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return docker.DockerInfo{}, fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
info, err := client.Info()
|
||||
if err != nil {
|
||||
return docker.DockerInfo{}, err
|
||||
}
|
||||
return *info, nil
|
||||
}
|
||||
|
||||
func DockerImages() ([]docker.APIImages, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
images, err := client.ListImages(docker.ListImagesOptions{All: false})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// Checks whether the dockerInfo reflects a valid docker setup, and returns it if it does, or an
|
||||
// error otherwise.
|
||||
func ValidateInfo() (*docker.DockerInfo, error) {
|
||||
client, err := Client()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
|
||||
}
|
||||
|
||||
dockerInfo, err := client.Info()
|
||||
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.Version()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get docker version: %v", err)
|
||||
}
|
||||
dockerInfo.ServerVersion = version.Get("Version")
|
||||
}
|
||||
version, err := parseDockerVersion(dockerInfo.ServerVersion)
|
||||
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)
|
||||
}
|
||||
|
||||
// Check that the libcontainer execdriver is used if the version is < 1.11
|
||||
// (execution drivers are no longer supported as of 1.11).
|
||||
if version[0] <= 1 && version[1] <= 10 &&
|
||||
!strings.HasPrefix(dockerInfo.ExecutionDriver, "native") {
|
||||
return nil, fmt.Errorf("docker found, but not using native exec driver")
|
||||
}
|
||||
|
||||
if dockerInfo.Driver == "" {
|
||||
return nil, fmt.Errorf("failed to find docker storage driver")
|
||||
}
|
||||
|
||||
return dockerInfo, nil
|
||||
func (self *dockerContainerHandler) Type() container.ContainerType {
|
||||
return container.ContainerTypeDocker
|
||||
}
|
||||
|
24
vendor/github.com/google/cadvisor/container/factory.go
generated
vendored
24
vendor/github.com/google/cadvisor/container/factory.go
generated
vendored
@@ -18,6 +18,8 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/google/cadvisor/manager/watcher"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
@@ -67,17 +69,19 @@ func (ms MetricSet) Add(mk MetricKind) {
|
||||
// TODO(vmarmol): Consider not making this global.
|
||||
// Global list of factories.
|
||||
var (
|
||||
factories []ContainerHandlerFactory
|
||||
factories = map[watcher.ContainerWatchSource][]ContainerHandlerFactory{}
|
||||
factoriesLock sync.RWMutex
|
||||
)
|
||||
|
||||
// Register a ContainerHandlerFactory. These should be registered from least general to most general
|
||||
// as they will be asked in order whether they can handle a particular container.
|
||||
func RegisterContainerHandlerFactory(factory ContainerHandlerFactory) {
|
||||
func RegisterContainerHandlerFactory(factory ContainerHandlerFactory, watchTypes []watcher.ContainerWatchSource) {
|
||||
factoriesLock.Lock()
|
||||
defer factoriesLock.Unlock()
|
||||
|
||||
factories = append(factories, factory)
|
||||
for _, watchType := range watchTypes {
|
||||
factories[watchType] = append(factories[watchType], factory)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether there are any container handler factories registered.
|
||||
@@ -89,12 +93,12 @@ func HasFactories() bool {
|
||||
}
|
||||
|
||||
// Create a new ContainerHandler for the specified container.
|
||||
func NewContainerHandler(name string, inHostNamespace bool) (ContainerHandler, bool, error) {
|
||||
func NewContainerHandler(name string, watchType watcher.ContainerWatchSource, inHostNamespace bool) (ContainerHandler, bool, error) {
|
||||
factoriesLock.RLock()
|
||||
defer factoriesLock.RUnlock()
|
||||
|
||||
// Create the ContainerHandler with the first factory that supports it.
|
||||
for _, factory := range factories {
|
||||
for _, factory := range factories[watchType] {
|
||||
canHandle, canAccept, err := factory.CanHandleAndAccept(name)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Error trying to work out if we can handle %s: %v", name, err)
|
||||
@@ -120,7 +124,7 @@ func ClearContainerHandlerFactories() {
|
||||
factoriesLock.Lock()
|
||||
defer factoriesLock.Unlock()
|
||||
|
||||
factories = make([]ContainerHandlerFactory, 0, 4)
|
||||
factories = map[watcher.ContainerWatchSource][]ContainerHandlerFactory{}
|
||||
}
|
||||
|
||||
func DebugInfo() map[string][]string {
|
||||
@@ -129,9 +133,11 @@ func DebugInfo() map[string][]string {
|
||||
|
||||
// Get debug information for all factories.
|
||||
out := make(map[string][]string)
|
||||
for _, factory := range factories {
|
||||
for k, v := range factory.DebugInfo() {
|
||||
out[k] = v
|
||||
for _, factoriesSlice := range factories {
|
||||
for _, factory := range factoriesSlice {
|
||||
for k, v := range factory.DebugInfo() {
|
||||
out[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
|
4
vendor/github.com/google/cadvisor/container/libcontainer/helpers.go
generated
vendored
4
vendor/github.com/google/cadvisor/container/libcontainer/helpers.go
generated
vendored
@@ -299,10 +299,6 @@ func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) {
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
func DockerStateDir(dockerRoot string) string {
|
||||
return path.Join(dockerRoot, "containers")
|
||||
}
|
||||
|
||||
func DiskStatsCopy0(major, minor uint64) *info.PerDiskStats {
|
||||
disk := info.PerDiskStats{
|
||||
Major: major,
|
||||
|
20
vendor/github.com/google/cadvisor/container/mock.go
generated
vendored
20
vendor/github.com/google/cadvisor/container/mock.go
generated
vendored
@@ -72,26 +72,11 @@ func (self *MockContainerHandler) ListContainers(listType ListType) ([]info.Cont
|
||||
return args.Get(0).([]info.ContainerReference), args.Error(1)
|
||||
}
|
||||
|
||||
func (self *MockContainerHandler) ListThreads(listType ListType) ([]int, error) {
|
||||
args := self.Called(listType)
|
||||
return args.Get(0).([]int), args.Error(1)
|
||||
}
|
||||
|
||||
func (self *MockContainerHandler) ListProcesses(listType ListType) ([]int, error) {
|
||||
args := self.Called(listType)
|
||||
return args.Get(0).([]int), args.Error(1)
|
||||
}
|
||||
|
||||
func (self *MockContainerHandler) WatchSubcontainers(events chan SubcontainerEvent) error {
|
||||
args := self.Called(events)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (self *MockContainerHandler) StopWatchingSubcontainers() error {
|
||||
args := self.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (self *MockContainerHandler) Exists() bool {
|
||||
args := self.Called()
|
||||
return args.Get(0).(bool)
|
||||
@@ -107,6 +92,11 @@ func (self *MockContainerHandler) GetContainerLabels() map[string]string {
|
||||
return args.Get(0).(map[string]string)
|
||||
}
|
||||
|
||||
func (self *MockContainerHandler) Type() ContainerType {
|
||||
args := self.Called()
|
||||
return args.Get(0).(ContainerType)
|
||||
}
|
||||
|
||||
type FactoryForMockContainerHandler struct {
|
||||
Name string
|
||||
PrepareContainerHandlerFunc func(name string, handler *MockContainerHandler)
|
||||
|
3
vendor/github.com/google/cadvisor/container/raw/factory.go
generated
vendored
3
vendor/github.com/google/cadvisor/container/raw/factory.go
generated
vendored
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
watch "github.com/google/cadvisor/manager/watcher"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
@@ -90,6 +91,6 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, igno
|
||||
watcher: watcher,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
}
|
||||
container.RegisterContainerHandlerFactory(factory)
|
||||
container.RegisterContainerHandlerFactory(factory, []watch.ContainerWatchSource{watch.Raw})
|
||||
return nil
|
||||
}
|
||||
|
186
vendor/github.com/google/cadvisor/container/raw/handler.go
generated
vendored
186
vendor/github.com/google/cadvisor/container/raw/handler.go
generated
vendored
@@ -17,22 +17,18 @@ package raw
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/common"
|
||||
"github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/utils/machine"
|
||||
"github.com/google/cadvisor/machine"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"golang.org/x/exp/inotify"
|
||||
)
|
||||
|
||||
type rawContainerHandler struct {
|
||||
@@ -41,12 +37,6 @@ type rawContainerHandler struct {
|
||||
cgroupSubsystems *libcontainer.CgroupSubsystems
|
||||
machineInfoFactory info.MachineInfoFactory
|
||||
|
||||
// Inotify event watcher.
|
||||
watcher *common.InotifyWatcher
|
||||
|
||||
// Signal for watcher thread to stop.
|
||||
stopWatcher chan error
|
||||
|
||||
// Absolute path to the cgroup hierarchies of this container.
|
||||
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
|
||||
cgroupPaths map[string]string
|
||||
@@ -102,12 +92,10 @@ func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSu
|
||||
name: name,
|
||||
cgroupSubsystems: cgroupSubsystems,
|
||||
machineInfoFactory: machineInfoFactory,
|
||||
stopWatcher: make(chan error),
|
||||
cgroupPaths: cgroupPaths,
|
||||
cgroupManager: cgroupManager,
|
||||
fsInfo: fsInfo,
|
||||
externalMounts: externalMounts,
|
||||
watcher: watcher,
|
||||
rootFs: rootFs,
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
pid: pid,
|
||||
@@ -269,179 +257,17 @@ func (self *rawContainerHandler) GetContainerLabels() map[string]string {
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||
containers := make(map[string]struct{})
|
||||
for _, cgroupPath := range self.cgroupPaths {
|
||||
err := common.ListDirectories(cgroupPath, self.name, listType == container.ListRecursive, containers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Make into container references.
|
||||
ret := make([]info.ContainerReference, 0, len(containers))
|
||||
for cont := range containers {
|
||||
ret = append(ret, info.ContainerReference{
|
||||
Name: cont,
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) ListThreads(listType container.ListType) ([]int, error) {
|
||||
// TODO(vmarmol): Implement
|
||||
return nil, nil
|
||||
return common.ListContainers(self.name, self.cgroupPaths, listType)
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
|
||||
return libcontainer.GetProcesses(self.cgroupManager)
|
||||
}
|
||||
|
||||
// Watches the specified directory and all subdirectories. Returns whether the path was
|
||||
// already being watched and an error (if any).
|
||||
func (self *rawContainerHandler) watchDirectory(dir string, containerName string) (bool, error) {
|
||||
alreadyWatching, err := self.watcher.AddWatch(containerName, dir)
|
||||
if err != nil {
|
||||
return alreadyWatching, err
|
||||
}
|
||||
|
||||
// Remove the watch if further operations failed.
|
||||
cleanup := true
|
||||
defer func() {
|
||||
if cleanup {
|
||||
_, err := self.watcher.RemoveWatch(containerName, dir)
|
||||
if err != nil {
|
||||
glog.Warningf("Failed to remove inotify watch for %q: %v", dir, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// TODO(vmarmol): We should re-do this once we're done to ensure directories were not added in the meantime.
|
||||
// Watch subdirectories as well.
|
||||
entries, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return alreadyWatching, err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
// TODO(vmarmol): We don't have to fail here, maybe we can recover and try to get as many registrations as we can.
|
||||
_, err = self.watchDirectory(path.Join(dir, entry.Name()), path.Join(containerName, entry.Name()))
|
||||
if err != nil {
|
||||
return alreadyWatching, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup = false
|
||||
return alreadyWatching, nil
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) processEvent(event *inotify.Event, events chan container.SubcontainerEvent) error {
|
||||
// Convert the inotify event type to a container create or delete.
|
||||
var eventType container.SubcontainerEventType
|
||||
switch {
|
||||
case (event.Mask & inotify.IN_CREATE) > 0:
|
||||
eventType = container.SubcontainerAdd
|
||||
case (event.Mask & inotify.IN_DELETE) > 0:
|
||||
eventType = container.SubcontainerDelete
|
||||
case (event.Mask & inotify.IN_MOVED_FROM) > 0:
|
||||
eventType = container.SubcontainerDelete
|
||||
case (event.Mask & inotify.IN_MOVED_TO) > 0:
|
||||
eventType = container.SubcontainerAdd
|
||||
default:
|
||||
// Ignore other events.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Derive the container name from the path name.
|
||||
var containerName string
|
||||
for _, mount := range self.cgroupSubsystems.Mounts {
|
||||
mountLocation := path.Clean(mount.Mountpoint) + "/"
|
||||
if strings.HasPrefix(event.Name, mountLocation) {
|
||||
containerName = event.Name[len(mountLocation)-1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
if containerName == "" {
|
||||
return fmt.Errorf("unable to detect container from watch event on directory %q", event.Name)
|
||||
}
|
||||
|
||||
// Maintain the watch for the new or deleted container.
|
||||
switch {
|
||||
case eventType == container.SubcontainerAdd:
|
||||
// New container was created, watch it.
|
||||
alreadyWatched, err := self.watchDirectory(event.Name, containerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only report container creation once.
|
||||
if alreadyWatched {
|
||||
return nil
|
||||
}
|
||||
case eventType == container.SubcontainerDelete:
|
||||
// Container was deleted, stop watching for it.
|
||||
lastWatched, err := self.watcher.RemoveWatch(containerName, event.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only report container deletion once.
|
||||
if !lastWatched {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown event type %v", eventType)
|
||||
}
|
||||
|
||||
// Deliver the event.
|
||||
events <- container.SubcontainerEvent{
|
||||
EventType: eventType,
|
||||
Name: containerName,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) WatchSubcontainers(events chan container.SubcontainerEvent) error {
|
||||
// Watch this container (all its cgroups) and all subdirectories.
|
||||
for _, cgroupPath := range self.cgroupPaths {
|
||||
_, err := self.watchDirectory(cgroupPath, self.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Process the events received from the kernel.
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-self.watcher.Event():
|
||||
err := self.processEvent(event, events)
|
||||
if err != nil {
|
||||
glog.Warningf("Error while processing event (%+v): %v", event, err)
|
||||
}
|
||||
case err := <-self.watcher.Error():
|
||||
glog.Warningf("Error while watching %q:", self.name, err)
|
||||
case <-self.stopWatcher:
|
||||
err := self.watcher.Close()
|
||||
if err == nil {
|
||||
self.stopWatcher <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) StopWatchingSubcontainers() error {
|
||||
// Rendezvous with the watcher thread.
|
||||
self.stopWatcher <- nil
|
||||
return <-self.stopWatcher
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) Exists() bool {
|
||||
return common.CgroupExists(self.cgroupPaths)
|
||||
}
|
||||
|
||||
func (self *rawContainerHandler) Type() container.ContainerType {
|
||||
return container.ContainerTypeRaw
|
||||
}
|
||||
|
22
vendor/github.com/google/cadvisor/container/rkt/client.go
generated
vendored
22
vendor/github.com/google/cadvisor/container/rkt/client.go
generated
vendored
@@ -20,6 +20,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/blang/semver"
|
||||
rktapi "github.com/coreos/rkt/api/v1alpha"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
@@ -29,6 +30,7 @@ import (
|
||||
const (
|
||||
defaultRktAPIServiceAddr = "localhost:15441"
|
||||
timeout = 2 * time.Second
|
||||
minimumRktBinVersion = "1.6.0"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -55,7 +57,25 @@ func Client() (rktapi.PublicAPIClient, error) {
|
||||
return
|
||||
}
|
||||
|
||||
rktClient = rktapi.NewPublicAPIClient(apisvcConn)
|
||||
apisvc := rktapi.NewPublicAPIClient(apisvcConn)
|
||||
|
||||
resp, err := apisvc.GetInfo(context.Background(), &rktapi.GetInfoRequest{})
|
||||
if err != nil {
|
||||
rktClientErr = fmt.Errorf("rkt: GetInfo() failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
binVersion, err := semver.Make(resp.Info.RktVersion)
|
||||
if err != nil {
|
||||
rktClientErr = fmt.Errorf("rkt: couldn't parse RtVersion: %v", err)
|
||||
return
|
||||
}
|
||||
if binVersion.LT(semver.MustParse(minimumRktBinVersion)) {
|
||||
rktClientErr = fmt.Errorf("rkt: binary version is too old(%v), requires at least %v", resp.Info.RktVersion, minimumRktBinVersion)
|
||||
return
|
||||
}
|
||||
|
||||
rktClient = apisvc
|
||||
})
|
||||
|
||||
return rktClient, rktClientErr
|
||||
|
13
vendor/github.com/google/cadvisor/container/rkt/factory.go
generated
vendored
13
vendor/github.com/google/cadvisor/container/rkt/factory.go
generated
vendored
@@ -16,12 +16,12 @@ package rkt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/container/libcontainer"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/manager/watcher"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
@@ -58,14 +58,9 @@ func (self *rktFactory) NewContainerHandler(name string, inHostNamespace bool) (
|
||||
}
|
||||
|
||||
func (self *rktFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||
// will ignore all cgroup names that don't either correspond to the machine.slice that is the pod or the containers that belong to the pod
|
||||
// only works for machined rkt pods at the moment
|
||||
accept, err := verifyPod(name)
|
||||
|
||||
if strings.HasPrefix(name, "/machine.slice/machine-rkt\\x2d") {
|
||||
accept, err := verifyName(name)
|
||||
return true, accept, err
|
||||
}
|
||||
return false, false, fmt.Errorf("%s not handled by rkt handler", name)
|
||||
return accept, accept, err
|
||||
}
|
||||
|
||||
func (self *rktFactory) DebugInfo() map[string][]string {
|
||||
@@ -99,6 +94,6 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, igno
|
||||
ignoreMetrics: ignoreMetrics,
|
||||
rktPath: rktPath,
|
||||
}
|
||||
container.RegisterContainerHandlerFactory(factory)
|
||||
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Rkt})
|
||||
return nil
|
||||
}
|
||||
|
94
vendor/github.com/google/cadvisor/container/rkt/handler.go
generated
vendored
94
vendor/github.com/google/cadvisor/container/rkt/handler.go
generated
vendored
@@ -18,7 +18,6 @@ package rkt
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
rktapi "github.com/coreos/rkt/api/v1alpha"
|
||||
@@ -100,20 +99,19 @@ func newRktContainerHandler(name string, rktClient rktapi.PublicAPIClient, rktPa
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
var annotations []*rktapi.KeyValue
|
||||
if parsed.Container == "" {
|
||||
pid = int(resp.Pod.Pid)
|
||||
apiPod = resp.Pod
|
||||
annotations = resp.Pod.Annotations
|
||||
} else {
|
||||
var ok bool
|
||||
if annotations, ok = findAnnotations(resp.Pod.Apps, parsed.Container); !ok {
|
||||
glog.Warningf("couldn't find application in Pod matching %v", parsed.Container)
|
||||
}
|
||||
}
|
||||
labels = createLabels(annotations)
|
||||
}
|
||||
annotations := resp.Pod.Annotations
|
||||
if parsed.Container != "" { // As not empty string, an App container
|
||||
if contAnnotations, ok := findAnnotations(resp.Pod.Apps, parsed.Container); !ok {
|
||||
glog.Warningf("couldn't find app %v in pod", parsed.Container)
|
||||
} else {
|
||||
annotations = append(annotations, contAnnotations...)
|
||||
}
|
||||
} else { // The Pod container
|
||||
pid = int(resp.Pod.Pid)
|
||||
apiPod = resp.Pod
|
||||
}
|
||||
labels = createLabels(annotations)
|
||||
|
||||
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
|
||||
|
||||
@@ -196,7 +194,12 @@ func (handler *rktContainerHandler) Cleanup() {
|
||||
func (handler *rktContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||
hasNetwork := handler.hasNetwork && !handler.ignoreMetrics.Has(container.NetworkUsageMetrics)
|
||||
hasFilesystem := !handler.ignoreMetrics.Has(container.DiskUsageMetrics)
|
||||
return common.GetSpec(handler.cgroupPaths, handler.machineInfoFactory, hasNetwork, hasFilesystem)
|
||||
|
||||
spec, err := common.GetSpec(handler.cgroupPaths, handler.machineInfoFactory, hasNetwork, hasFilesystem)
|
||||
|
||||
spec.Labels = handler.labels
|
||||
|
||||
return spec, err
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) getFsStats(stats *info.ContainerStats) error {
|
||||
@@ -260,68 +263,17 @@ func (handler *rktContainerHandler) GetContainerLabels() map[string]string {
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||
containers := make(map[string]struct{})
|
||||
|
||||
// Rkt containers do not have subcontainers, only the "Pod" does.
|
||||
if handler.isPod == false {
|
||||
var ret []info.ContainerReference
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Turn the system.slice cgroups into the Pod's subcontainers
|
||||
for _, cgroupPath := range handler.cgroupPaths {
|
||||
err := common.ListDirectories(path.Join(cgroupPath, "system.slice"), path.Join(handler.name, "system.slice"), listType == container.ListRecursive, containers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create the container references. for the Pod's subcontainers
|
||||
ret := make([]info.ContainerReference, 0, len(handler.apiPod.Apps))
|
||||
for cont := range containers {
|
||||
aliases := make([]string, 1)
|
||||
parsed, err := parseName(cont)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("this should be impossible!, unable to parse rkt subcontainer name = %s", cont)
|
||||
}
|
||||
aliases = append(aliases, parsed.Pod+":"+parsed.Container)
|
||||
|
||||
labels := make(map[string]string)
|
||||
if annotations, ok := findAnnotations(handler.apiPod.Apps, parsed.Container); !ok {
|
||||
glog.Warningf("couldn't find application in Pod matching %v", parsed.Container)
|
||||
} else {
|
||||
labels = createLabels(annotations)
|
||||
}
|
||||
|
||||
ret = append(ret, info.ContainerReference{
|
||||
Name: cont,
|
||||
Aliases: aliases,
|
||||
Namespace: RktNamespace,
|
||||
Labels: labels,
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) ListThreads(listType container.ListType) ([]int, error) {
|
||||
// TODO(sjpotter): Implement? Not implemented with docker yet
|
||||
return nil, nil
|
||||
return common.ListContainers(handler.name, handler.cgroupPaths, listType)
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
|
||||
return libcontainer.GetProcesses(handler.cgroupManager)
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) WatchSubcontainers(events chan container.SubcontainerEvent) error {
|
||||
return fmt.Errorf("watch is unimplemented in the Rkt container driver")
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) StopWatchingSubcontainers() error {
|
||||
// No-op for Rkt driver.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) Exists() bool {
|
||||
return common.CgroupExists(handler.cgroupPaths)
|
||||
}
|
||||
|
||||
func (handler *rktContainerHandler) Type() container.ContainerType {
|
||||
return container.ContainerTypeRkt
|
||||
}
|
||||
|
88
vendor/github.com/google/cadvisor/container/rkt/helpers.go
generated
vendored
88
vendor/github.com/google/cadvisor/container/rkt/helpers.go
generated
vendored
@@ -20,7 +20,9 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
rktapi "github.com/coreos/rkt/api/v1alpha"
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type parsedName struct {
|
||||
@@ -28,34 +30,80 @@ type parsedName struct {
|
||||
Container string
|
||||
}
|
||||
|
||||
func verifyName(name string) (bool, error) {
|
||||
_, err := parseName(name)
|
||||
return err == nil, err
|
||||
func verifyPod(name string) (bool, error) {
|
||||
pod, err := cgroupToPod(name)
|
||||
|
||||
if err != nil || pod == nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Anything handler can handle is also accepted.
|
||||
// Accept cgroups that are sub the pod cgroup, except "system.slice"
|
||||
// - "system.slice" doesn't contain any processes itself
|
||||
accept := !strings.HasSuffix(name, "/system.slice")
|
||||
|
||||
return accept, nil
|
||||
}
|
||||
|
||||
func cgroupToPod(name string) (*rktapi.Pod, error) {
|
||||
rktClient, err := Client()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get rkt api service: %v", err)
|
||||
}
|
||||
|
||||
resp, err := rktClient.ListPods(context.Background(), &rktapi.ListPodsRequest{
|
||||
Filters: []*rktapi.PodFilter{
|
||||
{
|
||||
States: []rktapi.PodState{rktapi.PodState_POD_STATE_RUNNING},
|
||||
PodSubCgroups: []string{name},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list pods: %v", err)
|
||||
}
|
||||
|
||||
if len(resp.Pods) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if len(resp.Pods) != 1 {
|
||||
return nil, fmt.Errorf("returned %d (expected 1) pods for cgroup %v", len(resp.Pods), name)
|
||||
}
|
||||
|
||||
return resp.Pods[0], nil
|
||||
}
|
||||
|
||||
/* Parse cgroup name into a pod/container name struct
|
||||
Example cgroup fs name
|
||||
|
||||
pod - /sys/fs/cgroup/cpu/machine.slice/machine-rkt\\x2df556b64a\\x2d17a7\\x2d47d7\\x2d93ec\\x2def2275c3d67e.scope/
|
||||
container under pod - /sys/fs/cgroup/cpu/machine.slice/machine-rkt\\x2df556b64a\\x2d17a7\\x2d47d7\\x2d93ec\\x2def2275c3d67e.scope/system.slice/alpine-sh.service
|
||||
pod - /machine.slice/machine-rkt\\x2df556b64a\\x2d17a7\\x2d47d7\\x2d93ec\\x2def2275c3d67e.scope/
|
||||
or /system.slice/k8s-..../
|
||||
container under pod - /machine.slice/machine-rkt\\x2df556b64a\\x2d17a7\\x2d47d7\\x2d93ec\\x2def2275c3d67e.scope/system.slice/alpine-sh.service
|
||||
or /system.slice/k8s-..../system.slice/pause.service
|
||||
*/
|
||||
//TODO{sjpotter}: this currently only recognizes machined started pods, which actually doesn't help with k8s which uses them as systemd services, need a solution for both
|
||||
func parseName(name string) (*parsedName, error) {
|
||||
splits := strings.Split(name, "/")
|
||||
if len(splits) == 3 || len(splits) == 5 {
|
||||
parsed := &parsedName{}
|
||||
pod, err := cgroupToPod(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parseName: couldn't convert %v to a rkt pod: %v", name, err)
|
||||
}
|
||||
if pod == nil {
|
||||
return nil, fmt.Errorf("parseName: didn't return a pod for %v", name)
|
||||
}
|
||||
|
||||
if splits[1] == "machine.slice" {
|
||||
replacer := strings.NewReplacer("machine-rkt\\x2d", "", ".scope", "", "\\x2d", "-")
|
||||
parsed.Pod = replacer.Replace(splits[2])
|
||||
if len(splits) == 3 {
|
||||
return parsed, nil
|
||||
}
|
||||
if splits[3] == "system.slice" {
|
||||
parsed.Container = strings.Replace(splits[4], ".service", "", -1)
|
||||
return parsed, nil
|
||||
}
|
||||
splits := strings.Split(name, "/")
|
||||
|
||||
parsed := &parsedName{}
|
||||
|
||||
if len(splits) == 3 || len(splits) == 5 {
|
||||
parsed.Pod = pod.Id
|
||||
|
||||
if len(splits) == 5 {
|
||||
parsed.Container = strings.Replace(splits[4], ".service", "", -1)
|
||||
}
|
||||
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%s not handled by rkt handler", name)
|
||||
@@ -80,7 +128,7 @@ func getRootFs(root string, parsed *parsedName) string {
|
||||
|
||||
bytes, err := ioutil.ReadFile(tree)
|
||||
if err != nil {
|
||||
glog.Infof("ReadFile failed, couldn't read %v to get upper dir: %v", tree, err)
|
||||
glog.Errorf("ReadFile failed, couldn't read %v to get upper dir: %v", tree, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
|
3
vendor/github.com/google/cadvisor/container/systemd/factory.go
generated
vendored
3
vendor/github.com/google/cadvisor/container/systemd/factory.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/fs"
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/manager/watcher"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
@@ -52,6 +53,6 @@ func (f *systemdFactory) DebugInfo() map[string][]string {
|
||||
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics container.MetricSet) error {
|
||||
glog.Infof("Registering systemd factory")
|
||||
factory := &systemdFactory{}
|
||||
container.RegisterContainerHandlerFactory(factory)
|
||||
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Raw})
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user