From 26a5cdabca692358c9e2d363fb3f0861ee4d42bd Mon Sep 17 00:00:00 2001 From: Rohit Jnagal Date: Mon, 16 Jun 2014 17:20:09 +0000 Subject: [PATCH] Add version information for components we depend on. Docker-DCO-1.1-Signed-off-by: Rohit Jnagal (github: rjnagal) --- container/docker/factory.go | 6 ++-- info/machine.go | 12 +++++++ manager/machine.go | 65 +++++++++++++++++++++++++++++++++++++ manager/manager.go | 17 ++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/container/docker/factory.go b/container/docker/factory.go index 6630c712..ba8ffe51 100644 --- a/container/docker/factory.go +++ b/container/docker/factory.go @@ -25,7 +25,7 @@ import ( "github.com/google/cadvisor/info" ) -var argDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint") +var ArgDockerEndpoint = flag.String("docker", "unix:///var/run/docker.sock", "docker endpoint") type dockerFactory struct { machineInfoFactory info.MachineInfoFactory @@ -36,7 +36,7 @@ func (self *dockerFactory) String() string { } func (self *dockerFactory) NewContainerHandler(name string) (handler container.ContainerHandler, err error) { - client, err := docker.NewClient(*argDockerEndpoint) + client, err := docker.NewClient(*ArgDockerEndpoint) if err != nil { return } @@ -69,7 +69,7 @@ func parseDockerVersion(full_version_string string) ([]int, error) { // Register root container before running this function! func Register(factory info.MachineInfoFactory, paths ...string) error { - client, err := docker.NewClient(*argDockerEndpoint) + client, err := docker.NewClient(*ArgDockerEndpoint) if err != nil { return fmt.Errorf("unable to communicate with docker daemon: %v", err) } diff --git a/info/machine.go b/info/machine.go index 7d0f68c2..46d27dc0 100644 --- a/info/machine.go +++ b/info/machine.go @@ -22,6 +22,18 @@ type MachineInfo struct { MemoryCapacity int64 `json:"memory_capacity"` } +type VersionInfo struct { + // Kernel version. + KernelVersion string `json:"kernel_version"` + + // OS image being used for cadvisor container, or host image if running on host directly. + ContainerOsVersion string `json:"container_os_version"` + + // Docker version. + DockerVersion string `json:"docker_version"` +} + type MachineInfoFactory interface { GetMachineInfo() (*MachineInfo, error) + GetVersionInfo() (*VersionInfo, error) } diff --git a/manager/machine.go b/manager/machine.go index 8ec13d1b..81b2a782 100644 --- a/manager/machine.go +++ b/manager/machine.go @@ -15,11 +15,16 @@ package manager import ( + "bytes" "fmt" "io/ioutil" "regexp" "strconv" + "strings" + "syscall" + dclient "github.com/fsouza/go-dockerclient" + "github.com/google/cadvisor/container/docker" "github.com/google/cadvisor/info" ) @@ -59,3 +64,63 @@ func getMachineInfo() (*info.MachineInfo, error) { MemoryCapacity: memoryCapacity, }, nil } + +func getVersionInfo() (*info.VersionInfo, error) { + + kernel_version := getKernelVersion() + container_os := getContainerOsVersion() + docker_version := getDockerVersion() + + return &info.VersionInfo{ + KernelVersion: kernel_version, + ContainerOsVersion: container_os, + DockerVersion: docker_version, + }, nil +} + +func getContainerOsVersion() string { + container_os := "Unknown" + os_release, err := ioutil.ReadFile("/etc/os-release") + if err == nil { + // We might be running in a busybox or some hand-crafted image. + // It's useful to know why cadvisor didn't come up. + for _, line := range strings.Split(string(os_release), "\n") { + parsed := strings.Split(line, "\"") + if len(parsed) == 3 && parsed[0] == "PRETTY_NAME=" { + container_os = parsed[1] + break + } + } + } + return container_os +} + +func getDockerVersion() string { + docker_version := "Unknown" + client, err := dclient.NewClient(*docker.ArgDockerEndpoint) + if err == nil { + version, err := client.Version() + if err == nil { + docker_version = version.Get("Version") + } + } + return docker_version +} + +func getKernelVersion() string { + uname := &syscall.Utsname{} + + if err := syscall.Uname(uname); err != nil { + return "Unknown" + } + + release := make([]byte, len(uname.Release)) + i := 0 + for _, c := range uname.Release { + release[i] = byte(c) + i++ + } + release = release[:bytes.IndexByte(release, 0)] + + return string(release) +} diff --git a/manager/manager.go b/manager/manager.go index 3df5c927..7158d380 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -33,6 +33,9 @@ type Manager interface { // Get information about the machine. GetMachineInfo() (*info.MachineInfo, error) + + // Get version information about different components we depend on. + GetVersionInfo() (*info.VersionInfo, error) } func New() (Manager, error) { @@ -45,6 +48,14 @@ func New() (Manager, error) { } newManager.machineInfo = *machineInfo log.Printf("Machine: %+v", newManager.machineInfo) + + versionInfo, err := getVersionInfo() + if err != nil { + return nil, err + } + newManager.versionInfo = *versionInfo + log.Printf("Version: %+v", newManager.versionInfo) + return newManager, nil } @@ -52,6 +63,7 @@ type manager struct { containers map[string]*containerData containersLock sync.RWMutex machineInfo info.MachineInfo + versionInfo info.VersionInfo } // Start the container manager. @@ -140,6 +152,11 @@ func (m *manager) GetMachineInfo() (*info.MachineInfo, error) { return &ret, nil } +func (m *manager) GetVersionInfo() (*info.VersionInfo, error) { + ret := m.versionInfo + return &ret, nil +} + // Create a container. This expects to only be called from the global manager thread. func (m *manager) createContainer(containerName string) (*containerData, error) { cont, err := NewContainerData(containerName)