Fix usage of the latest go-dockerclient

This commit is contained in:
Tim St. Clair 2016-04-04 18:01:47 -07:00
parent d2bb061da0
commit d9c864324b
6 changed files with 91 additions and 127 deletions

View File

@ -27,7 +27,7 @@ import (
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/fsouza/go-dockerclient"
docker "github.com/fsouza/go-dockerclient"
"github.com/golang/glog"
)
@ -205,23 +205,21 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
}
}
information, err := client.Info()
dockerInfo, err := client.Info()
if err != nil {
return fmt.Errorf("failed to detect Docker info: %v", err)
}
// Check that the libcontainer execdriver is used.
execDriver := information.Get("ExecutionDriver")
if !strings.HasPrefix(execDriver, "native") {
if !strings.HasPrefix(dockerInfo.ExecutionDriver, "native") {
return fmt.Errorf("docker found, but not using native exec driver")
}
sd := information.Get("Driver")
if sd == "" {
if dockerInfo.Driver == "" {
return fmt.Errorf("failed to find docker storage driver")
}
storageDir := information.Get("DockerRootDir")
storageDir := dockerInfo.DockerRootDir
if storageDir == "" {
storageDir = *dockerRootDir
}
@ -237,7 +235,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo, ignoreMetrics c
dockerVersion: dockerVersion,
fsInfo: fsInfo,
machineInfoFactory: factory,
storageDriver: storageDriver(sd),
storageDriver: storageDriver(dockerInfo.Driver),
storageDir: storageDir,
ignoreMetrics: ignoreMetrics,
}

View File

@ -402,16 +402,16 @@ func (self *dockerContainerHandler) Exists() bool {
return containerlibcontainer.Exists(*dockerRootDir, *dockerRunDir, self.id)
}
func DockerInfo() (map[string]string, error) {
func DockerInfo() (docker.DockerInfo, error) {
client, err := Client()
if err != nil {
return nil, fmt.Errorf("unable to communicate with docker daemon: %v", err)
return docker.DockerInfo{}, fmt.Errorf("unable to communicate with docker daemon: %v", err)
}
info, err := client.Info()
if err != nil {
return nil, err
return docker.DockerInfo{}, err
}
return info.Map(), nil
return *info, nil
}
func DockerImages() ([]docker.APIImages, error) {

View File

@ -19,7 +19,6 @@ package fs
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
@ -63,9 +62,14 @@ type RealFsInfo struct {
type Context struct {
// docker root directory.
DockerRoot string
DockerInfo map[string]string
RktPath string
Docker DockerContext
RktPath string
}
type DockerContext struct {
Root string
Driver string
DriverStatus map[string]string
}
func NewFsInfo(context Context) (FsInfo, error) {
@ -117,22 +121,17 @@ func NewFsInfo(context Context) (FsInfo, error) {
// docker is using devicemapper for its storage driver. If a loopback device is being used, don't
// return any information or error, as we want to report based on the actual partition where the
// loopback file resides, inside of the loopback file itself.
func (self *RealFsInfo) getDockerDeviceMapperInfo(dockerInfo map[string]string) (string, *partition, error) {
if storageDriver, ok := dockerInfo["Driver"]; ok && storageDriver != DeviceMapper.String() {
func (self *RealFsInfo) getDockerDeviceMapperInfo(context DockerContext) (string, *partition, error) {
if context.Driver != DeviceMapper.String() {
return "", nil, nil
}
var driverStatus [][]string
if err := json.Unmarshal([]byte(dockerInfo["DriverStatus"]), &driverStatus); err != nil {
return "", nil, err
}
dataLoopFile := dockerStatusValue(driverStatus, "Data loop file")
dataLoopFile := context.DriverStatus["Data loop file"]
if len(dataLoopFile) > 0 {
return "", nil, nil
}
dev, major, minor, blockSize, err := dockerDMDevice(driverStatus, self.dmsetup)
dev, major, minor, blockSize, err := dockerDMDevice(context.DriverStatus, self.dmsetup)
if err != nil {
return "", nil, err
}
@ -163,7 +162,7 @@ func (self *RealFsInfo) addSystemRootLabel(mounts []*mount.Info) {
// addDockerImagesLabel attempts to determine which device contains the mount for docker images.
func (self *RealFsInfo) addDockerImagesLabel(context Context, mounts []*mount.Info) {
dockerDev, dockerPartition, err := self.getDockerDeviceMapperInfo(context.DockerInfo)
dockerDev, dockerPartition, err := self.getDockerDeviceMapperInfo(context.Docker)
if err != nil {
glog.Warningf("Could not get Docker devicemapper device: %v", err)
}
@ -198,7 +197,7 @@ func getDockerImagePaths(context Context) map[string]struct{} {
}
// TODO(rjnagal): Detect docker root and graphdriver directories from docker info.
dockerRoot := context.DockerRoot
dockerRoot := context.Docker.Root
for _, dir := range []string{"devicemapper", "btrfs", "aufs", "overlay", "zfs"} {
dockerImagePaths[path.Join(dockerRoot, dir)] = struct{}{}
}
@ -435,15 +434,6 @@ func getVfsStats(path string) (total uint64, free uint64, avail uint64, inodes u
return total, free, avail, inodes, inodesFree, nil
}
func dockerStatusValue(status [][]string, target string) string {
for _, v := range status {
if len(v) == 2 && strings.ToLower(v[0]) == strings.ToLower(target) {
return v[1]
}
}
return ""
}
// dmsetupClient knows to to interact with dmsetup to retrieve information about devicemapper.
type dmsetupClient interface {
table(poolName string) ([]byte, error)
@ -461,9 +451,9 @@ func (*defaultDmsetupClient) table(poolName string) ([]byte, error) {
// Devicemapper thin provisioning is detailed at
// https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt
func dockerDMDevice(driverStatus [][]string, dmsetup dmsetupClient) (string, uint, uint, uint, error) {
poolName := dockerStatusValue(driverStatus, "Pool Name")
if len(poolName) == 0 {
func dockerDMDevice(driverStatus map[string]string, dmsetup dmsetupClient) (string, uint, uint, uint, error) {
poolName, ok := driverStatus["Pool Name"]
if !ok || len(poolName) == 0 {
return "", 0, 0, 0, fmt.Errorf("Could not get dm pool name")
}

View File

@ -201,7 +201,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
tests := []struct {
name string
driver string
driverStatus string
driverStatus map[string]string
dmsetupTable string
dmsetupTableError error
expectedDevice string
@ -216,9 +216,9 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
expectedError: false,
},
{
name: "error unmarshaling driver status",
name: "nil driver status",
driver: "devicemapper",
driverStatus: "{[[[asdf",
driverStatus: nil,
expectedDevice: "",
expectedPartition: nil,
expectedError: true,
@ -226,7 +226,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{
name: "loopback",
driver: "devicemapper",
driverStatus: `[["Data loop file","/var/lib/docker/devicemapper/devicemapper/data"]]`,
driverStatus: map[string]string{"Data loop file": "/var/lib/docker/devicemapper/devicemapper/data"},
expectedDevice: "",
expectedPartition: nil,
expectedError: false,
@ -234,7 +234,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{
name: "missing pool name",
driver: "devicemapper",
driverStatus: `[[]]`,
driverStatus: map[string]string{},
expectedDevice: "",
expectedPartition: nil,
expectedError: true,
@ -242,7 +242,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{
name: "error invoking dmsetup",
driver: "devicemapper",
driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`,
driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"},
dmsetupTableError: errors.New("foo"),
expectedDevice: "",
expectedPartition: nil,
@ -251,7 +251,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{
name: "unable to parse dmsetup table",
driver: "devicemapper",
driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`,
driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"},
dmsetupTable: "no data here!",
expectedDevice: "",
expectedPartition: nil,
@ -260,7 +260,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{
name: "happy path",
driver: "devicemapper",
driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`,
driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"},
dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing",
expectedDevice: "vg_vagrant-docker--pool",
expectedPartition: &partition{
@ -280,12 +280,12 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
},
}
dockerInfo := map[string]string{
"Driver": tt.driver,
"DriverStatus": tt.driverStatus,
dockerCtx := DockerContext{
Driver: tt.driver,
DriverStatus: tt.driverStatus,
}
device, partition, err := fsInfo.getDockerDeviceMapperInfo(dockerInfo)
device, partition, err := fsInfo.getDockerDeviceMapperInfo(dockerCtx)
if tt.expectedError && err == nil {
t.Errorf("%s: expected error but got nil", tt.name)
@ -310,7 +310,7 @@ func TestAddDockerImagesLabel(t *testing.T) {
tests := []struct {
name string
driver string
driverStatus string
driverStatus map[string]string
dmsetupTable string
getDockerDeviceMapperInfoError error
mounts []*mount.Info
@ -320,7 +320,7 @@ func TestAddDockerImagesLabel(t *testing.T) {
{
name: "devicemapper, not loopback",
driver: "devicemapper",
driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`,
driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"},
dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing",
mounts: []*mount.Info{
{
@ -340,7 +340,7 @@ func TestAddDockerImagesLabel(t *testing.T) {
{
name: "devicemapper, loopback on non-root partition",
driver: "devicemapper",
driverStatus: `[["Data loop file","/var/lib/docker/devicemapper/devicemapper/data"]]`,
driverStatus: map[string]string{"Data loop file": "/var/lib/docker/devicemapper/devicemapper/data"},
mounts: []*mount.Info{
{
Source: "/dev/mapper/vg_vagrant-lv_root",
@ -403,10 +403,10 @@ func TestAddDockerImagesLabel(t *testing.T) {
}
context := Context{
DockerRoot: "/var/lib/docker",
DockerInfo: map[string]string{
"Driver": tt.driver,
"DriverStatus": tt.driverStatus,
Docker: DockerContext{
Root: "/var/lib/docker",
Driver: tt.driver,
DriverStatus: tt.driverStatus,
},
}

View File

@ -16,7 +16,6 @@
package manager
import (
"encoding/json"
"flag"
"fmt"
"os"
@ -61,7 +60,7 @@ type Manager interface {
// Stops the manager.
Stop() error
// Get information about a container.
// information about a container.
GetContainerInfo(containerName string, query *info.ContainerInfoRequest) (*info.ContainerInfo, error)
// Get V2 information about a container.
@ -132,7 +131,7 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
}
glog.Infof("cAdvisor running in container: %q", selfContainer)
dockerInfo, err := docker.DockerInfo()
dockerInfo, err := dockerInfo()
if err != nil {
glog.Warningf("Unable to connect to Docker: %v", err)
}
@ -141,7 +140,14 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, maxHousekeepingIn
glog.Warningf("unable to connect to Rkt api service: %v", err)
}
context := fs.Context{DockerRoot: docker.RootDir(), DockerInfo: dockerInfo, RktPath: rktPath}
context := fs.Context{
Docker: fs.DockerContext{
Root: docker.RootDir(),
Driver: dockerInfo.Driver,
DriverStatus: dockerInfo.DriverStatus,
},
RktPath: rktPath,
}
fsInfo, err := fs.NewFsInfo(context)
if err != nil {
return nil, err
@ -227,6 +233,7 @@ func (self *manager) Start() error {
glog.Errorf("Registration of the raw container factory failed: %v", err)
}
// FIXME - delete?
self.DockerInfo()
self.DockerImages()
@ -1159,58 +1166,31 @@ func (m *manager) DockerImages() ([]DockerImage, error) {
}
func (m *manager) DockerInfo() (DockerStatus, error) {
info, err := docker.DockerInfo()
return dockerInfo()
}
func dockerInfo() (DockerStatus, error) {
dockerInfo, err := docker.DockerInfo()
if err != nil {
return DockerStatus{}, err
}
versionInfo, err := m.GetVersionInfo()
versionInfo, err := getVersionInfo()
if err != nil {
return DockerStatus{}, err
}
out := DockerStatus{}
out.Version = versionInfo.DockerVersion
if val, ok := info["KernelVersion"]; ok {
out.KernelVersion = val
}
if val, ok := info["OperatingSystem"]; ok {
out.OS = val
}
if val, ok := info["Name"]; ok {
out.Hostname = val
}
if val, ok := info["DockerRootDir"]; ok {
out.RootDir = val
}
if val, ok := info["Driver"]; ok {
out.Driver = val
}
if val, ok := info["ExecutionDriver"]; ok {
out.ExecDriver = val
}
if val, ok := info["Images"]; ok {
n, err := strconv.Atoi(val)
if err == nil {
out.NumImages = n
}
}
if val, ok := info["Containers"]; ok {
n, err := strconv.Atoi(val)
if err == nil {
out.NumContainers = n
}
}
if val, ok := info["DriverStatus"]; ok {
var driverStatus [][]string
err := json.Unmarshal([]byte(val), &driverStatus)
if err != nil {
return DockerStatus{}, err
}
out.DriverStatus = make(map[string]string)
for _, v := range driverStatus {
if len(v) == 2 {
out.DriverStatus[v[0]] = v[1]
}
}
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
}

View File

@ -185,28 +185,24 @@ func validateCgroups() (string, string) {
}
func validateDockerInfo() (string, string) {
client, err := docker.Client()
if err == nil {
info, err := client.Info()
if err == nil {
execDriver := info.Get("ExecutionDriver")
storageDriver := info.Get("Driver")
desc := fmt.Sprintf("Docker exec driver is %s. Storage driver is %s.\n", execDriver, storageDriver)
if strings.Contains(execDriver, "native") {
stateFile := docker.DockerStateDir()
if !utils.FileExists(stateFile) {
desc += fmt.Sprintf("\tDocker container state directory %q is not accessible.\n", stateFile)
return Unsupported, desc
}
desc += fmt.Sprintf("\tDocker container state directory is at %q and is accessible.\n", stateFile)
return Recommended, desc
} else if strings.Contains(execDriver, "lxc") {
return Supported, desc
}
return Unknown, desc
}
info, err := docker.DockerInfo()
if err != nil {
return Unknown, "Docker remote API not reachable\n\t"
}
return Unknown, "Docker remote API not reachable\n\t"
desc := fmt.Sprintf("Docker exec driver is %s. Storage driver is %s.\n", info.ExecutionDriver, info.Driver)
if strings.Contains(info.ExecutionDriver, "native") {
stateFile := docker.DockerStateDir()
if !utils.FileExists(stateFile) {
desc += fmt.Sprintf("\tDocker container state directory %q is not accessible.\n", stateFile)
return Unsupported, desc
}
desc += fmt.Sprintf("\tDocker container state directory is at %q and is accessible.\n", stateFile)
return Recommended, desc
} else if strings.Contains(info.ExecutionDriver, "lxc") {
return Supported, desc
}
return Unknown, desc
}
func validateCgroupMounts() (string, string) {