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

View File

@ -402,16 +402,16 @@ func (self *dockerContainerHandler) Exists() bool {
return containerlibcontainer.Exists(*dockerRootDir, *dockerRunDir, self.id) return containerlibcontainer.Exists(*dockerRootDir, *dockerRunDir, self.id)
} }
func DockerInfo() (map[string]string, error) { func DockerInfo() (docker.DockerInfo, error) {
client, err := Client() client, err := Client()
if err != nil { 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() info, err := client.Info()
if err != nil { if err != nil {
return nil, err return docker.DockerInfo{}, err
} }
return info.Map(), nil return *info, nil
} }
func DockerImages() ([]docker.APIImages, error) { func DockerImages() ([]docker.APIImages, error) {

View File

@ -19,7 +19,6 @@ package fs
import ( import (
"bufio" "bufio"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -63,9 +62,14 @@ type RealFsInfo struct {
type Context struct { type Context struct {
// docker root directory. // docker root directory.
DockerRoot string Docker DockerContext
DockerInfo map[string]string RktPath string
RktPath string }
type DockerContext struct {
Root string
Driver string
DriverStatus map[string]string
} }
func NewFsInfo(context Context) (FsInfo, error) { 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 // 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 // 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. // loopback file resides, inside of the loopback file itself.
func (self *RealFsInfo) getDockerDeviceMapperInfo(dockerInfo map[string]string) (string, *partition, error) { func (self *RealFsInfo) getDockerDeviceMapperInfo(context DockerContext) (string, *partition, error) {
if storageDriver, ok := dockerInfo["Driver"]; ok && storageDriver != DeviceMapper.String() { if context.Driver != DeviceMapper.String() {
return "", nil, nil return "", nil, nil
} }
var driverStatus [][]string dataLoopFile := context.DriverStatus["Data loop file"]
if err := json.Unmarshal([]byte(dockerInfo["DriverStatus"]), &driverStatus); err != nil {
return "", nil, err
}
dataLoopFile := dockerStatusValue(driverStatus, "Data loop file")
if len(dataLoopFile) > 0 { if len(dataLoopFile) > 0 {
return "", nil, nil 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 { if err != nil {
return "", nil, err 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. // addDockerImagesLabel attempts to determine which device contains the mount for docker images.
func (self *RealFsInfo) addDockerImagesLabel(context Context, mounts []*mount.Info) { 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 { if err != nil {
glog.Warningf("Could not get Docker devicemapper device: %v", err) 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. // 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"} { for _, dir := range []string{"devicemapper", "btrfs", "aufs", "overlay", "zfs"} {
dockerImagePaths[path.Join(dockerRoot, dir)] = struct{}{} 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 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. // dmsetupClient knows to to interact with dmsetup to retrieve information about devicemapper.
type dmsetupClient interface { type dmsetupClient interface {
table(poolName string) ([]byte, error) table(poolName string) ([]byte, error)
@ -461,9 +451,9 @@ func (*defaultDmsetupClient) table(poolName string) ([]byte, error) {
// Devicemapper thin provisioning is detailed at // Devicemapper thin provisioning is detailed at
// https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt // https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt
func dockerDMDevice(driverStatus [][]string, dmsetup dmsetupClient) (string, uint, uint, uint, error) { func dockerDMDevice(driverStatus map[string]string, dmsetup dmsetupClient) (string, uint, uint, uint, error) {
poolName := dockerStatusValue(driverStatus, "Pool Name") poolName, ok := driverStatus["Pool Name"]
if len(poolName) == 0 { if !ok || len(poolName) == 0 {
return "", 0, 0, 0, fmt.Errorf("Could not get dm pool name") 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 { tests := []struct {
name string name string
driver string driver string
driverStatus string driverStatus map[string]string
dmsetupTable string dmsetupTable string
dmsetupTableError error dmsetupTableError error
expectedDevice string expectedDevice string
@ -216,9 +216,9 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
expectedError: false, expectedError: false,
}, },
{ {
name: "error unmarshaling driver status", name: "nil driver status",
driver: "devicemapper", driver: "devicemapper",
driverStatus: "{[[[asdf", driverStatus: nil,
expectedDevice: "", expectedDevice: "",
expectedPartition: nil, expectedPartition: nil,
expectedError: true, expectedError: true,
@ -226,7 +226,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{ {
name: "loopback", name: "loopback",
driver: "devicemapper", 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: "", expectedDevice: "",
expectedPartition: nil, expectedPartition: nil,
expectedError: false, expectedError: false,
@ -234,7 +234,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{ {
name: "missing pool name", name: "missing pool name",
driver: "devicemapper", driver: "devicemapper",
driverStatus: `[[]]`, driverStatus: map[string]string{},
expectedDevice: "", expectedDevice: "",
expectedPartition: nil, expectedPartition: nil,
expectedError: true, expectedError: true,
@ -242,7 +242,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{ {
name: "error invoking dmsetup", name: "error invoking dmsetup",
driver: "devicemapper", driver: "devicemapper",
driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`, driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"},
dmsetupTableError: errors.New("foo"), dmsetupTableError: errors.New("foo"),
expectedDevice: "", expectedDevice: "",
expectedPartition: nil, expectedPartition: nil,
@ -251,7 +251,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{ {
name: "unable to parse dmsetup table", name: "unable to parse dmsetup table",
driver: "devicemapper", driver: "devicemapper",
driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`, driverStatus: map[string]string{"Pool Name": "vg_vagrant-docker--pool"},
dmsetupTable: "no data here!", dmsetupTable: "no data here!",
expectedDevice: "", expectedDevice: "",
expectedPartition: nil, expectedPartition: nil,
@ -260,7 +260,7 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
{ {
name: "happy path", name: "happy path",
driver: "devicemapper", 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", dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing",
expectedDevice: "vg_vagrant-docker--pool", expectedDevice: "vg_vagrant-docker--pool",
expectedPartition: &partition{ expectedPartition: &partition{
@ -280,12 +280,12 @@ func TestGetDockerDeviceMapperInfo(t *testing.T) {
}, },
} }
dockerInfo := map[string]string{ dockerCtx := DockerContext{
"Driver": tt.driver, Driver: tt.driver,
"DriverStatus": tt.driverStatus, DriverStatus: tt.driverStatus,
} }
device, partition, err := fsInfo.getDockerDeviceMapperInfo(dockerInfo) device, partition, err := fsInfo.getDockerDeviceMapperInfo(dockerCtx)
if tt.expectedError && err == nil { if tt.expectedError && err == nil {
t.Errorf("%s: expected error but got nil", tt.name) t.Errorf("%s: expected error but got nil", tt.name)
@ -310,7 +310,7 @@ func TestAddDockerImagesLabel(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
driver string driver string
driverStatus string driverStatus map[string]string
dmsetupTable string dmsetupTable string
getDockerDeviceMapperInfoError error getDockerDeviceMapperInfoError error
mounts []*mount.Info mounts []*mount.Info
@ -320,7 +320,7 @@ func TestAddDockerImagesLabel(t *testing.T) {
{ {
name: "devicemapper, not loopback", name: "devicemapper, not loopback",
driver: "devicemapper", 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", dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing",
mounts: []*mount.Info{ mounts: []*mount.Info{
{ {
@ -340,7 +340,7 @@ func TestAddDockerImagesLabel(t *testing.T) {
{ {
name: "devicemapper, loopback on non-root partition", name: "devicemapper, loopback on non-root partition",
driver: "devicemapper", 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{ mounts: []*mount.Info{
{ {
Source: "/dev/mapper/vg_vagrant-lv_root", Source: "/dev/mapper/vg_vagrant-lv_root",
@ -403,10 +403,10 @@ func TestAddDockerImagesLabel(t *testing.T) {
} }
context := Context{ context := Context{
DockerRoot: "/var/lib/docker", Docker: DockerContext{
DockerInfo: map[string]string{ Root: "/var/lib/docker",
"Driver": tt.driver, Driver: tt.driver,
"DriverStatus": tt.driverStatus, DriverStatus: tt.driverStatus,
}, },
} }

View File

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

View File

@ -185,28 +185,24 @@ func validateCgroups() (string, string) {
} }
func validateDockerInfo() (string, string) { func validateDockerInfo() (string, string) {
client, err := docker.Client() info, err := docker.DockerInfo()
if err == nil { if err != nil {
info, err := client.Info() return Unknown, "Docker remote API not reachable\n\t"
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
}
} }
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) { func validateCgroupMounts() (string, string) {