Refactor docker-specific functions from manager to docker

This commit is contained in:
Tim St. Clair 2016-04-15 16:07:15 -07:00
parent b983d32d96
commit 0c89fd1b71
8 changed files with 212 additions and 176 deletions

162
container/docker/docker.go Normal file
View File

@ -0,0 +1,162 @@
// 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"
"golang.org/x/net/context"
dockertypes "github.com/docker/engine-api/types"
"github.com/google/cadvisor/utils/machine"
)
func Status() (DockerStatus, error) {
client, err := Client()
if err != nil {
return DockerStatus{}, fmt.Errorf("unable to communicate with docker daemon: %v", err)
}
dockerInfo, err := client.Info(context.Background())
if err != nil {
return DockerStatus{}, err
}
out := 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() ([]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 := []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 := 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
}

View File

@ -19,7 +19,6 @@ import (
"fmt"
"path"
"regexp"
"strconv"
"strings"
"github.com/google/cadvisor/container"
@ -164,24 +163,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()

View File

@ -29,7 +29,6 @@ import (
info "github.com/google/cadvisor/info/v1"
docker "github.com/docker/engine-api/client"
dockertypes "github.com/docker/engine-api/types"
dockercontainer "github.com/docker/engine-api/types/container"
"github.com/opencontainers/runc/libcontainer/cgroups"
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
@ -349,63 +348,3 @@ func (self *dockerContainerHandler) StopWatchingSubcontainers() error {
func (self *dockerContainerHandler) Exists() bool {
return common.CgroupExists(self.cgroupPaths)
}
func DockerInfo() (dockertypes.Info, error) {
client, err := Client()
if err != nil {
return dockertypes.Info{}, fmt.Errorf("unable to communicate with docker daemon: %v", err)
}
return client.Info(context.Background())
}
func DockerImages() ([]dockertypes.Image, error) {
client, err := Client()
if err != nil {
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
}
return client.ImageList(context.Background(), dockertypes.ImageListOptions{All: false})
}
// 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
}

37
container/docker/types.go Normal file
View File

@ -0,0 +1,37 @@
// 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.
// Types used for docker containers.
package docker
type DockerStatus struct {
Version string `json:"version"`
KernelVersion string `json:"kernel_version"`
OS string `json:"os"`
Hostname string `json:"hostname"`
RootDir string `json:"root_dir"`
Driver string `json:"driver"`
DriverStatus map[string]string `json:"driver_status"`
ExecDriver string `json:"exec_driver"`
NumImages int `json:"num_images"`
NumContainers int `json:"num_containers"`
}
type DockerImage struct {
ID string `json:"id"`
RepoTags []string `json:"repo_tags"` // repository name and tags.
Created int64 `json:"created"` // unix time since creation.
VirtualSize int64 `json:"virtual_size"`
Size int64 `json:"size"`
}

View File

@ -112,10 +112,10 @@ type Manager interface {
CloseEventChannel(watch_id int)
// Get status information about docker.
DockerInfo() (DockerStatus, error)
DockerInfo() (docker.DockerStatus, error)
// Get details about interesting docker images.
DockerImages() ([]DockerImage, error)
DockerImages() ([]docker.DockerImage, error)
// Returns debugging information. Map of lines per category.
DebugInfo() map[string][]string
@ -134,7 +134,7 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
}
glog.Infof("cAdvisor running in container: %q", selfContainer)
dockerInfo, err := dockerInfo()
dockerStatus, err := docker.Status()
if err != nil {
glog.Warningf("Unable to connect to Docker: %v", err)
}
@ -146,8 +146,8 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
context := fs.Context{
Docker: fs.DockerContext{
Root: docker.RootDir(),
Driver: dockerInfo.Driver,
DriverStatus: dockerInfo.DriverStatus,
Driver: dockerStatus.Driver,
DriverStatus: dockerStatus.DriverStatus,
},
RktPath: rktPath,
}
@ -241,9 +241,6 @@ func (self *manager) Start() error {
glog.Errorf("Registration of the raw container factory failed: %v", err)
}
self.DockerInfo()
self.DockerImages()
if *enableLoadReader {
// Create cpu load reader.
cpuLoadReader, err := cpuload.New()
@ -1127,79 +1124,12 @@ func parseEventsStoragePolicy() events.StoragePolicy {
return policy
}
type DockerStatus struct {
Version string `json:"version"`
KernelVersion string `json:"kernel_version"`
OS string `json:"os"`
Hostname string `json:"hostname"`
RootDir string `json:"root_dir"`
Driver string `json:"driver"`
DriverStatus map[string]string `json:"driver_status"`
ExecDriver string `json:"exec_driver"`
NumImages int `json:"num_images"`
NumContainers int `json:"num_containers"`
func (m *manager) DockerImages() ([]docker.DockerImage, error) {
return docker.Images()
}
type DockerImage struct {
ID string `json:"id"`
RepoTags []string `json:"repo_tags"` // repository name and tags.
Created int64 `json:"created"` // unix time since creation.
VirtualSize int64 `json:"virtual_size"`
Size int64 `json:"size"`
}
func (m *manager) DockerImages() ([]DockerImage, error) {
images, err := docker.DockerImages()
if err != nil {
return nil, err
}
out := []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 := DockerImage{
ID: image.ID,
RepoTags: image.RepoTags,
Created: image.Created,
VirtualSize: image.VirtualSize,
Size: image.Size,
}
out = append(out, di)
}
return out, nil
}
func (m *manager) DockerInfo() (DockerStatus, error) {
return dockerInfo()
}
func dockerInfo() (DockerStatus, error) {
dockerInfo, err := docker.DockerInfo()
if err != nil {
return DockerStatus{}, err
}
versionInfo, err := getVersionInfo()
if err != nil {
return DockerStatus{}, err
}
out := DockerStatus{}
out.Version = versionInfo.DockerVersion
out.KernelVersion = dockerInfo.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 (m *manager) DockerInfo() (docker.DockerStatus, error) {
return docker.Status()
}
func (m *manager) DebugInfo() map[string][]string {
@ -1241,7 +1171,7 @@ func getVersionInfo() (*info.VersionInfo, error) {
kernel_version := machine.KernelVersion()
container_os := machine.ContainerOsVersion()
docker_version := machine.DockerVersion()
docker_version := docker.VersionString()
return &info.VersionInfo{
KernelVersion: kernel_version,

View File

@ -31,7 +31,7 @@ import (
const DockerPage = "/docker/"
func toStatusKV(status manager.DockerStatus) ([]keyVal, []keyVal) {
func toStatusKV(status docker.DockerStatus) ([]keyVal, []keyVal) {
ds := []keyVal{
{Key: "Driver", Value: status.Driver},
}

View File

@ -21,6 +21,7 @@ import (
"net/url"
"strings"
"github.com/google/cadvisor/container/docker"
httpmux "github.com/google/cadvisor/http/mux"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/manager"
@ -62,7 +63,7 @@ type pageData struct {
Root string
DockerStatus []keyVal
DockerDriverStatus []keyVal
DockerImages []manager.DockerImage
DockerImages []docker.DockerImage
}
func init() {

View File

@ -22,7 +22,6 @@ import (
"strings"
"syscall"
"github.com/google/cadvisor/container/docker"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/utils/cloudinfo"
@ -30,7 +29,6 @@ import (
"github.com/google/cadvisor/utils/sysinfo"
"github.com/golang/glog"
"golang.org/x/net/context"
)
var machineIdFilePath = flag.String("machine_id_file", "/etc/machine-id,/var/lib/dbus/machine-id", "Comma-separated list of files to check for machine-id. Use the first one that exists.")
@ -136,18 +134,6 @@ func ContainerOsVersion() string {
return container_os
}
func DockerVersion() string {
docker_version := "Unknown"
client, err := docker.Client()
if err == nil {
version, err := client.ServerVersion(context.Background())
if err == nil {
docker_version = version.Version
}
}
return docker_version
}
func KernelVersion() string {
uname := &syscall.Utsname{}