Merge pull request #368 from rjnagal/diskinfo
Add a disk map to machine info.
This commit is contained in:
commit
cc0e999bed
@ -34,6 +34,7 @@ import (
|
||||
"github.com/google/cadvisor/manager"
|
||||
"github.com/google/cadvisor/pages"
|
||||
"github.com/google/cadvisor/pages/static"
|
||||
"github.com/google/cadvisor/utils/sysfs"
|
||||
"github.com/google/cadvisor/validate"
|
||||
)
|
||||
|
||||
@ -65,7 +66,12 @@ func main() {
|
||||
glog.Fatalf("Failed to connect to database: %s", err)
|
||||
}
|
||||
|
||||
containerManager, err := manager.New(storageDriver)
|
||||
sysFs, err := sysfs.NewRealSysFs()
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to create a system interface: %s", err)
|
||||
}
|
||||
|
||||
containerManager, err := manager.New(storageDriver, sysFs)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to create a Container Manager: %s", err)
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func cadvisorTestClient(path string, expectedPostObj, expectedPostObjEmpty, repl
|
||||
encoder := json.NewEncoder(w)
|
||||
encoder.Encode(replyObj)
|
||||
} else if r.URL.Path == "/api/v1.2/machine" {
|
||||
fmt.Fprint(w, `{"num_cores":8,"memory_capacity":31625871360}`)
|
||||
fmt.Fprint(w, `{"num_cores":8,"memory_capacity":31625871360, "disk_map":["8:0":{"name":"sda","major":8,"minor":0,"size":10737418240}]}`)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
fmt.Fprintf(w, "Page not found.")
|
||||
@ -78,6 +78,14 @@ func TestGetMachineinfo(t *testing.T) {
|
||||
minfo := &info.MachineInfo{
|
||||
NumCores: 8,
|
||||
MemoryCapacity: 31625871360,
|
||||
DiskMap: map[string]info.DiskInfo{
|
||||
"8:0": info.DiskInfo{
|
||||
Name: "sda",
|
||||
Major: 8,
|
||||
Minor: 0,
|
||||
Size: 10737418240,
|
||||
},
|
||||
},
|
||||
}
|
||||
client, server, err := cadvisorTestClient("/api/v1.2/machine", nil, nil, minfo, t)
|
||||
if err != nil {
|
||||
|
@ -22,6 +22,20 @@ type FsInfo struct {
|
||||
Capacity uint64 `json:"capacity"`
|
||||
}
|
||||
|
||||
type DiskInfo struct {
|
||||
// device name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Major number
|
||||
Major uint64 `json:"major"`
|
||||
|
||||
// Minor number
|
||||
Minor uint64 `json:"minor"`
|
||||
|
||||
// Size in bytes
|
||||
Size uint64 `json:"size"`
|
||||
}
|
||||
|
||||
type MachineInfo struct {
|
||||
// The number of cores in this machine.
|
||||
NumCores int `json:"num_cores"`
|
||||
@ -31,6 +45,9 @@ type MachineInfo struct {
|
||||
|
||||
// Filesystems on this machine.
|
||||
Filesystems []FsInfo `json:"filesystems"`
|
||||
|
||||
// Disk map
|
||||
DiskMap map[string]DiskInfo `json:"disk_map"`
|
||||
}
|
||||
|
||||
type VersionInfo struct {
|
||||
|
@ -27,12 +27,13 @@ import (
|
||||
"github.com/google/cadvisor/container/docker"
|
||||
"github.com/google/cadvisor/fs"
|
||||
"github.com/google/cadvisor/info"
|
||||
"github.com/google/cadvisor/utils/sysfs"
|
||||
)
|
||||
|
||||
var numCpuRegexp = regexp.MustCompile("processor\\t*: +[0-9]+")
|
||||
var memoryCapacityRegexp = regexp.MustCompile("MemTotal: *([0-9]+) kB")
|
||||
|
||||
func getMachineInfo() (*info.MachineInfo, error) {
|
||||
func getMachineInfo(sysFs sysfs.SysFs) (*info.MachineInfo, error) {
|
||||
// Get the number of CPUs from /proc/cpuinfo.
|
||||
out, err := ioutil.ReadFile("/proc/cpuinfo")
|
||||
if err != nil {
|
||||
@ -69,10 +70,17 @@ func getMachineInfo() (*info.MachineInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
diskMap, err := sysfs.GetBlockDeviceInfo(sysFs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
machineInfo := &info.MachineInfo{
|
||||
NumCores: numCores,
|
||||
MemoryCapacity: memoryCapacity,
|
||||
DiskMap: diskMap,
|
||||
}
|
||||
|
||||
for _, fs := range filesystems {
|
||||
machineInfo.Filesystems = append(machineInfo.Filesystems, info.FsInfo{fs.Device, fs.Capacity})
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"github.com/google/cadvisor/container/docker"
|
||||
"github.com/google/cadvisor/info"
|
||||
"github.com/google/cadvisor/storage"
|
||||
"github.com/google/cadvisor/utils/sysfs"
|
||||
)
|
||||
|
||||
var globalHousekeepingInterval = flag.Duration("global_housekeeping_interval", 1*time.Minute, "Interval between global housekeepings")
|
||||
@ -64,7 +65,7 @@ type Manager interface {
|
||||
}
|
||||
|
||||
// New takes a driver and returns a new manager.
|
||||
func New(driver storage.StorageDriver) (Manager, error) {
|
||||
func New(driver storage.StorageDriver, sysfs sysfs.SysFs) (Manager, error) {
|
||||
if driver == nil {
|
||||
return nil, fmt.Errorf("nil storage driver!")
|
||||
}
|
||||
@ -83,7 +84,7 @@ func New(driver storage.StorageDriver) (Manager, error) {
|
||||
cadvisorContainer: selfContainer,
|
||||
}
|
||||
|
||||
machineInfo, err := getMachineInfo()
|
||||
machineInfo, err := getMachineInfo(sysfs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -27,12 +27,14 @@ import (
|
||||
"github.com/google/cadvisor/info"
|
||||
itest "github.com/google/cadvisor/info/test"
|
||||
stest "github.com/google/cadvisor/storage/test"
|
||||
"github.com/google/cadvisor/utils/sysfs/fakesysfs"
|
||||
)
|
||||
|
||||
// TODO(vmarmol): Refactor these tests.
|
||||
|
||||
func createManagerAndAddContainers(
|
||||
driver *stest.MockStorageDriver,
|
||||
sysfs *fakesysfs.FakeSysFs,
|
||||
containers []string,
|
||||
f func(*container.MockContainerHandler),
|
||||
t *testing.T,
|
||||
@ -41,7 +43,7 @@ func createManagerAndAddContainers(
|
||||
driver = &stest.MockStorageDriver{}
|
||||
}
|
||||
container.ClearContainerHandlerFactories()
|
||||
mif, err := New(driver)
|
||||
mif, err := New(driver, sysfs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -81,8 +83,10 @@ func expectManagerWithContainers(containers []string, query *info.ContainerInfoR
|
||||
}
|
||||
|
||||
driver := &stest.MockStorageDriver{}
|
||||
sysfs := &fakesysfs.FakeSysFs{}
|
||||
m := createManagerAndAddContainers(
|
||||
driver,
|
||||
sysfs,
|
||||
containers,
|
||||
func(h *container.MockContainerHandler) {
|
||||
cinfo := infosMap[h.Name]
|
||||
@ -200,7 +204,7 @@ func TestDockerContainersInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
manager, err := New(&stest.MockStorageDriver{})
|
||||
manager, err := New(&stest.MockStorageDriver{}, &fakesysfs.FakeSysFs{})
|
||||
if err != nil {
|
||||
t.Fatalf("Expected manager.New to succeed: %s", err)
|
||||
}
|
||||
@ -210,7 +214,7 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewNilManager(t *testing.T) {
|
||||
_, err := New(nil)
|
||||
_, err := New(nil, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected nil manager to return error")
|
||||
}
|
||||
|
64
utils/sysfs/fakesysfs/fake.go
Normal file
64
utils/sysfs/fakesysfs/fake.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package fakesysfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// If we extend sysfs to support more interfaces, it might be worth making this a mock instead of a fake.
|
||||
type FileInfo struct {
|
||||
}
|
||||
|
||||
func (self *FileInfo) Name() string {
|
||||
return "sda"
|
||||
}
|
||||
|
||||
func (self *FileInfo) Size() int64 {
|
||||
return 1234567
|
||||
}
|
||||
|
||||
func (self *FileInfo) Mode() os.FileMode {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *FileInfo) ModTime() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (self *FileInfo) IsDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *FileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
type FakeSysFs struct {
|
||||
info FileInfo
|
||||
}
|
||||
|
||||
func (self *FakeSysFs) GetBlockDevices() ([]os.FileInfo, error) {
|
||||
return []os.FileInfo{&self.info}, nil
|
||||
}
|
||||
|
||||
func (self *FakeSysFs) GetBlockDeviceSize(name string) (string, error) {
|
||||
return "1234567", nil
|
||||
}
|
||||
|
||||
func (self *FakeSysFs) GetBlockDeviceNumbers(name string) (string, error) {
|
||||
return "8:0\n", nil
|
||||
}
|
108
utils/sysfs/sysfs.go
Normal file
108
utils/sysfs/sysfs.go
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cadvisor/info"
|
||||
)
|
||||
|
||||
const BlockDir = "/sys/block"
|
||||
|
||||
// Abstracts the lowest level calls to sysfs.
|
||||
type SysFs interface {
|
||||
// Get directory information for available block devices.
|
||||
GetBlockDevices() ([]os.FileInfo, error)
|
||||
// Get Size of a given block device.
|
||||
GetBlockDeviceSize(string) (string, error)
|
||||
// Get device major:minor number string.
|
||||
GetBlockDeviceNumbers(string) (string, error)
|
||||
}
|
||||
|
||||
type realSysFs struct{}
|
||||
|
||||
func NewRealSysFs() (SysFs, error) {
|
||||
return &realSysFs{}, nil
|
||||
}
|
||||
|
||||
func (self *realSysFs) GetBlockDevices() ([]os.FileInfo, error) {
|
||||
return ioutil.ReadDir(BlockDir)
|
||||
}
|
||||
|
||||
func (self *realSysFs) GetBlockDeviceNumbers(name string) (string, error) {
|
||||
dev, err := ioutil.ReadFile(path.Join(BlockDir, name, "/dev"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(dev), nil
|
||||
}
|
||||
|
||||
func (self *realSysFs) GetBlockDeviceSize(name string) (string, error) {
|
||||
size, err := ioutil.ReadFile(path.Join(BlockDir, name, "/size"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(size), nil
|
||||
}
|
||||
|
||||
// Get information about block devices present on the system.
|
||||
// Uses the passed in system interface to retrieve the low level OS information.
|
||||
func GetBlockDeviceInfo(sysfs SysFs) (map[string]info.DiskInfo, error) {
|
||||
disks, err := sysfs.GetBlockDevices()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
diskMap := make(map[string]info.DiskInfo)
|
||||
for _, disk := range disks {
|
||||
name := disk.Name()
|
||||
// Ignore loopback and ram devices.
|
||||
if strings.HasPrefix(name, "loop") || strings.HasPrefix(name, "ram") {
|
||||
continue
|
||||
}
|
||||
disk_info := info.DiskInfo{
|
||||
Name: name,
|
||||
}
|
||||
dev, err := sysfs.GetBlockDeviceNumbers(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n, err := fmt.Sscanf(dev, "%d:%d", &disk_info.Major, &disk_info.Minor)
|
||||
if err != nil || n != 2 {
|
||||
return nil, fmt.Errorf("could not parse device numbers from %s for device %s", dev, name)
|
||||
}
|
||||
out, err := sysfs.GetBlockDeviceSize(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Remove trailing newline before conversion.
|
||||
size, err := strconv.ParseUint(strings.TrimSpace(out), 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// size is in 512 bytes blocks.
|
||||
disk_info.Size = size * 512
|
||||
|
||||
device := fmt.Sprintf("%d:%d", disk_info.Major, disk_info.Minor)
|
||||
diskMap[device] = disk_info
|
||||
}
|
||||
return diskMap, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user