Merge pull request #1724 from yguo0905/uuid
Add an API to get FsStats from filesystem UUID
This commit is contained in:
commit
81635163ce
@ -16,6 +16,7 @@ sudo docker run \
|
||||
--volume=/var/run:/var/run:rw \
|
||||
--volume=/sys:/sys:ro \
|
||||
--volume=/var/lib/docker/:/var/lib/docker:ro \
|
||||
--volume=/dev/disk/:/dev/disk:ro \
|
||||
--publish=8080:8080 \
|
||||
--detach=true \
|
||||
--name=cadvisor \
|
||||
|
@ -420,23 +420,30 @@ func (self *version2_0) HandleRequest(requestType string, request []string, m ma
|
||||
}
|
||||
return writeResult(specs, w)
|
||||
case storageApi:
|
||||
var err error
|
||||
fi := []v2.FsInfo{}
|
||||
label := r.URL.Query().Get("label")
|
||||
if len(label) == 0 {
|
||||
// Get all global filesystems info.
|
||||
fi, err = m.GetFsInfo("")
|
||||
uuid := r.URL.Query().Get("uuid")
|
||||
switch {
|
||||
case uuid != "":
|
||||
fi, err := m.GetFsInfoByFsUUID(uuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return writeResult(fi, w)
|
||||
case label != "":
|
||||
// Get a specific label.
|
||||
fi, err = m.GetFsInfo(label)
|
||||
fi, err := m.GetFsInfo(label)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeResult(fi, w)
|
||||
default:
|
||||
// Get all global filesystems info.
|
||||
fi, err := m.GetFsInfo("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeResult(fi, w)
|
||||
}
|
||||
return writeResult(fi, w)
|
||||
case eventsApi:
|
||||
return handleEventRequest(request, m, w, r)
|
||||
case psApi:
|
||||
|
61
fs/fs.go
61
fs/fs.go
@ -83,6 +83,8 @@ type RealFsInfo struct {
|
||||
mounts map[string]*mount.Info
|
||||
// devicemapper client
|
||||
dmsetup devicemapper.DmsetupClient
|
||||
// fsUUIDToDeviceName is a map from the filesystem UUID to its device name.
|
||||
fsUUIDToDeviceName map[string]string
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
@ -103,13 +105,19 @@ func NewFsInfo(context Context) (FsInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fsUUIDToDeviceName, err := getFsUUIDToDeviceNameMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Avoid devicemapper container mounts - these are tracked by the ThinPoolWatcher
|
||||
excluded := []string{fmt.Sprintf("%s/devicemapper/mnt", context.Docker.Root)}
|
||||
fsInfo := &RealFsInfo{
|
||||
partitions: processMounts(mounts, excluded),
|
||||
labels: make(map[string]string, 0),
|
||||
mounts: make(map[string]*mount.Info, 0),
|
||||
dmsetup: devicemapper.NewDmsetupClient(),
|
||||
partitions: processMounts(mounts, excluded),
|
||||
labels: make(map[string]string, 0),
|
||||
mounts: make(map[string]*mount.Info, 0),
|
||||
dmsetup: devicemapper.NewDmsetupClient(),
|
||||
fsUUIDToDeviceName: fsUUIDToDeviceName,
|
||||
}
|
||||
|
||||
for _, mount := range mounts {
|
||||
@ -121,11 +129,44 @@ func NewFsInfo(context Context) (FsInfo, error) {
|
||||
// add a "partition" for devicemapper to fsInfo.partitions
|
||||
fsInfo.addDockerImagesLabel(context, mounts)
|
||||
|
||||
glog.Infof("Filesystem UUIDs: %+v", fsInfo.fsUUIDToDeviceName)
|
||||
glog.Infof("Filesystem partitions: %+v", fsInfo.partitions)
|
||||
fsInfo.addSystemRootLabel(mounts)
|
||||
return fsInfo, nil
|
||||
}
|
||||
|
||||
// getFsUUIDToDeviceNameMap creates the filesystem uuid to device name map
|
||||
// using the information in /dev/disk/by-uuid. If the directory does not exist,
|
||||
// this function will return an empty map.
|
||||
func getFsUUIDToDeviceNameMap() (map[string]string, error) {
|
||||
const dir = "/dev/disk/by-uuid"
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
return make(map[string]string), nil
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fsUUIDToDeviceName := make(map[string]string)
|
||||
for _, file := range files {
|
||||
path := filepath.Join(dir, file.Name())
|
||||
target, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
glog.Infof("Failed to resolve symlink for %q", path)
|
||||
continue
|
||||
}
|
||||
device, err := filepath.Abs(filepath.Join(dir, target))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve the absolute path of %q", filepath.Join(dir, target))
|
||||
}
|
||||
fsUUIDToDeviceName[file.Name()] = device
|
||||
}
|
||||
return fsUUIDToDeviceName, nil
|
||||
}
|
||||
|
||||
func processMounts(mounts []*mount.Info, excludedMountpointPrefixes []string) map[string]partition {
|
||||
partitions := make(map[string]partition, 0)
|
||||
|
||||
@ -433,6 +474,18 @@ func minor(devNumber uint64) uint {
|
||||
return uint((devNumber & 0xff) | ((devNumber >> 12) & 0xfff00))
|
||||
}
|
||||
|
||||
func (self *RealFsInfo) GetDeviceInfoByFsUUID(uuid string) (*DeviceInfo, error) {
|
||||
deviceName, found := self.fsUUIDToDeviceName[uuid]
|
||||
if !found {
|
||||
return nil, ErrNoSuchDevice
|
||||
}
|
||||
p, found := self.partitions[deviceName]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("cannot find device %q in partitions", deviceName)
|
||||
}
|
||||
return &DeviceInfo{deviceName, p.major, p.minor}, nil
|
||||
}
|
||||
|
||||
func (self *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) {
|
||||
buf := new(syscall.Stat_t)
|
||||
err := syscall.Stat(dir, buf)
|
||||
|
13
fs/types.go
13
fs/types.go
@ -14,7 +14,10 @@
|
||||
|
||||
package fs
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DeviceInfo struct {
|
||||
Device string
|
||||
@ -59,6 +62,9 @@ type DiskStats struct {
|
||||
WeightedIoTime uint64
|
||||
}
|
||||
|
||||
// ErrNoSuchDevice is the error indicating the requested device does not exist.
|
||||
var ErrNoSuchDevice = errors.New("cadvisor: no such device")
|
||||
|
||||
type FsInfo interface {
|
||||
// Returns capacity and free space, in bytes, of all the ext2, ext3, ext4 filesystems on the host.
|
||||
GetGlobalFsInfo() ([]Fs, error)
|
||||
@ -72,6 +78,11 @@ type FsInfo interface {
|
||||
// Returns number of inodes used by 'dir'.
|
||||
GetDirInodeUsage(dir string, timeout time.Duration) (uint64, error)
|
||||
|
||||
// GetDeviceInfoByFsUUID returns the information of the device with the
|
||||
// specified filesystem uuid. If no such device exists, this function will
|
||||
// return the ErrNoSuchDevice error.
|
||||
GetDeviceInfoByFsUUID(uuid string) (*DeviceInfo, error)
|
||||
|
||||
// Returns the block device info of the filesystem on which 'dir' resides.
|
||||
GetDirFsDevice(dir string) (*DeviceInfo, error)
|
||||
|
||||
|
@ -199,6 +199,9 @@ type DerivedStats struct {
|
||||
}
|
||||
|
||||
type FsInfo struct {
|
||||
// Time of generation of these stats.
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
|
||||
// The block device name associated with the filesystem.
|
||||
Device string `json:"device"`
|
||||
|
||||
|
@ -101,6 +101,11 @@ type Manager interface {
|
||||
// Get version information about different components we depend on.
|
||||
GetVersionInfo() (*info.VersionInfo, error)
|
||||
|
||||
// GetFsInfoByFsUUID returns the information of the device having the
|
||||
// specified filesystem uuid. If no such device with the UUID exists, this
|
||||
// function will return the fs.ErrNoSuchDevice error.
|
||||
GetFsInfoByFsUUID(uuid string) (v2.FsInfo, error)
|
||||
|
||||
// Get filesystem information for the filesystem that contains the given directory
|
||||
GetDirFsInfo(dir string) (v2.FsInfo, error)
|
||||
|
||||
@ -676,24 +681,19 @@ func (self *manager) getRequestedContainers(containerName string, options v2.Req
|
||||
}
|
||||
|
||||
func (self *manager) GetDirFsInfo(dir string) (v2.FsInfo, error) {
|
||||
dirDevice, err := self.fsInfo.GetDirFsDevice(dir)
|
||||
device, err := self.fsInfo.GetDirFsDevice(dir)
|
||||
if err != nil {
|
||||
return v2.FsInfo{}, fmt.Errorf("error trying to get filesystem Device for dir %v: err: %v", dir, err)
|
||||
return v2.FsInfo{}, fmt.Errorf("failed to get device for dir %q: %v", dir, err)
|
||||
}
|
||||
dirMountpoint, err := self.fsInfo.GetMountpointForDevice(dirDevice.Device)
|
||||
if err != nil {
|
||||
return v2.FsInfo{}, fmt.Errorf("error trying to get MountPoint for Root Device: %v, err: %v", dirDevice, err)
|
||||
}
|
||||
infos, err := self.GetFsInfo("")
|
||||
return self.getFsInfoByDeviceName(device.Device)
|
||||
}
|
||||
|
||||
func (self *manager) GetFsInfoByFsUUID(uuid string) (v2.FsInfo, error) {
|
||||
device, err := self.fsInfo.GetDeviceInfoByFsUUID(uuid)
|
||||
if err != nil {
|
||||
return v2.FsInfo{}, err
|
||||
}
|
||||
for _, info := range infos {
|
||||
if info.Mountpoint == dirMountpoint {
|
||||
return info, nil
|
||||
}
|
||||
}
|
||||
return v2.FsInfo{}, fmt.Errorf("did not find fs info for dir: %v", dir)
|
||||
return self.getFsInfoByDeviceName(device.Device)
|
||||
}
|
||||
|
||||
func (self *manager) GetFsInfo(label string) ([]v2.FsInfo, error) {
|
||||
@ -726,6 +726,7 @@ func (self *manager) GetFsInfo(label string) ([]v2.FsInfo, error) {
|
||||
}
|
||||
|
||||
fi := v2.FsInfo{
|
||||
Timestamp: stats[0].Timestamp,
|
||||
Device: fs.Device,
|
||||
Mountpoint: mountpoint,
|
||||
Capacity: fs.Limit,
|
||||
@ -1265,6 +1266,23 @@ func (m *manager) DebugInfo() map[string][]string {
|
||||
return debugInfo
|
||||
}
|
||||
|
||||
func (self *manager) getFsInfoByDeviceName(deviceName string) (v2.FsInfo, error) {
|
||||
mountPoint, err := self.fsInfo.GetMountpointForDevice(deviceName)
|
||||
if err != nil {
|
||||
return v2.FsInfo{}, fmt.Errorf("failed to get mount point for device %q: %v", deviceName, err)
|
||||
}
|
||||
infos, err := self.GetFsInfo("")
|
||||
if err != nil {
|
||||
return v2.FsInfo{}, err
|
||||
}
|
||||
for _, info := range infos {
|
||||
if info.Mountpoint == mountPoint {
|
||||
return info, nil
|
||||
}
|
||||
}
|
||||
return v2.FsInfo{}, fmt.Errorf("cannot find filesystem info for device %q", deviceName)
|
||||
}
|
||||
|
||||
func getVersionInfo() (*info.VersionInfo, error) {
|
||||
|
||||
kernel_version := machine.KernelVersion()
|
||||
|
Loading…
Reference in New Issue
Block a user