diff --git a/fs/fs.go b/fs/fs.go index d6e9e27a..cbc4f984 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -76,6 +76,10 @@ func NewFsInfo(context Context) (FsInfo, error) { labels: make(map[string]string, 0), dmsetup: &defaultDmsetupClient{}, } + + fsInfo.addSystemRootLabel(mounts) + fsInfo.addDockerImagesLabel(context, mounts) + supportedFsType := map[string]bool{ // all ext systems are checked through prefix. "btrfs": true, @@ -102,12 +106,7 @@ func NewFsInfo(context Context) (FsInfo, error) { } } - // need to call this before the log line below printing out the partitions, as this function may - // add a "partition" for devicemapper to fsInfo.partitions - fsInfo.addDockerImagesLabel(context) - glog.Infof("Filesystem partitions: %+v", fsInfo.partitions) - fsInfo.addSystemRootLabel() return fsInfo, nil } @@ -144,18 +143,23 @@ func (self *RealFsInfo) getDockerDeviceMapperInfo(dockerInfo map[string]string) } // addSystemRootLabel attempts to determine which device contains the mount for /. -func (self *RealFsInfo) addSystemRootLabel() { - for src, p := range self.partitions { - if p.mountpoint == "/" { - if _, ok := self.labels[LabelSystemRoot]; !ok { - self.labels[LabelSystemRoot] = src +func (self *RealFsInfo) addSystemRootLabel(mounts []*mount.Info) { + for _, m := range mounts { + if m.Mountpoint == "/" { + self.partitions[m.Source] = partition{ + fsType: m.Fstype, + mountpoint: m.Mountpoint, + major: uint(m.Major), + minor: uint(m.Minor), } + self.labels[LabelSystemRoot] = m.Source + return } } } // addDockerImagesLabel attempts to determine which device contains the mount for docker images. -func (self *RealFsInfo) addDockerImagesLabel(context Context) { +func (self *RealFsInfo) addDockerImagesLabel(context Context, mounts []*mount.Info) { dockerDev, dockerPartition, err := self.getDockerDeviceMapperInfo(context.DockerInfo) if err != nil { glog.Warningf("Could not get Docker devicemapper device: %v", err) @@ -164,48 +168,50 @@ func (self *RealFsInfo) addDockerImagesLabel(context Context) { self.partitions[dockerDev] = *dockerPartition self.labels[LabelDockerImages] = dockerDev } else { - dockerPaths := getDockerImagePaths(context) - - for src, p := range self.partitions { - self.updateDockerImagesPath(src, p.mountpoint, dockerPaths) - } + self.updateDockerImagesPath(mounts, getDockerImagePaths(context)) } } // Generate a list of possible mount points for docker image management from the docker root directory. // Right now, we look for each type of supported graph driver directories, but we can do better by parsing // some of the context from `docker info`. -func getDockerImagePaths(context Context) []string { +func getDockerImagePaths(context Context) map[string]struct{} { + dockerImagePaths := map[string]struct{}{ + "/": {}, + } + // TODO(rjnagal): Detect docker root and graphdriver directories from docker info. dockerRoot := context.DockerRoot - dockerImagePaths := []string{} for _, dir := range []string{"devicemapper", "btrfs", "aufs", "overlay", "zfs"} { - dockerImagePaths = append(dockerImagePaths, path.Join(dockerRoot, dir)) + dockerImagePaths[path.Join(dockerRoot, dir)] = struct{}{} } for dockerRoot != "/" && dockerRoot != "." { - dockerImagePaths = append(dockerImagePaths, dockerRoot) + dockerImagePaths[dockerRoot] = struct{}{} dockerRoot = filepath.Dir(dockerRoot) } - dockerImagePaths = append(dockerImagePaths, "/") return dockerImagePaths } -// This method compares the mountpoint with possible docker image mount points. If a match is found, +// This method compares the mountpoints with possible docker image mount points. If a match is found, // docker images label is added to the partition. -func (self *RealFsInfo) updateDockerImagesPath(source string, mountpoint string, dockerImagePaths []string) { - for _, v := range dockerImagePaths { - if v == mountpoint { - if i, ok := self.labels[LabelDockerImages]; ok { - // pick the innermost mountpoint. - mnt := self.partitions[i].mountpoint - if len(mnt) < len(mountpoint) { - self.labels[LabelDockerImages] = source - } - } else { - self.labels[LabelDockerImages] = source +func (self *RealFsInfo) updateDockerImagesPath(mounts []*mount.Info, dockerImagePaths map[string]struct{}) { + var useMount *mount.Info + for _, m := range mounts { + if _, ok := dockerImagePaths[m.Mountpoint]; ok { + if useMount == nil || (len(useMount.Mountpoint) < len(m.Mountpoint)) { + useMount = m } } } + if useMount != nil { + self.partitions[useMount.Source] = partition{ + fsType: useMount.Fstype, + mountpoint: useMount.Mountpoint, + major: uint(useMount.Major), + minor: uint(useMount.Minor), + } + self.labels[LabelDockerImages] = useMount.Source + } } func (self *RealFsInfo) GetDeviceForLabel(label string) (string, error) { diff --git a/fs/fs_test.go b/fs/fs_test.go index 850cf82a..944b429d 100644 --- a/fs/fs_test.go +++ b/fs/fs_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "github.com/docker/docker/pkg/mount" "github.com/stretchr/testify/assert" ) @@ -161,22 +162,29 @@ func TestParseDMTable(t *testing.T) { } func TestAddSystemRootLabel(t *testing.T) { - fsInfo := &RealFsInfo{ - labels: map[string]string{}, - partitions: map[string]partition{ - "/dev/mapper/vg_vagrant-lv_root": { - mountpoint: "/", - }, - "vg_vagrant-docker--pool": { - mountpoint: "", - fsType: "devicemapper", + tests := []struct { + mounts []*mount.Info + expected string + }{ + { + mounts: []*mount.Info{ + {Source: "/dev/sda1", Mountpoint: "/foo"}, + {Source: "/dev/sdb1", Mountpoint: "/"}, }, + expected: "/dev/sdb1", }, } - fsInfo.addSystemRootLabel() - if e, a := "/dev/mapper/vg_vagrant-lv_root", fsInfo.labels[LabelSystemRoot]; e != a { - t.Errorf("expected %q, got %q", e, a) + for i, tt := range tests { + fsInfo := &RealFsInfo{ + labels: map[string]string{}, + partitions: map[string]partition{}, + } + fsInfo.addSystemRootLabel(tt.mounts) + + if source, ok := fsInfo.labels[LabelSystemRoot]; !ok || source != tt.expected { + t.Errorf("case %d: expected mount source '%s', got '%s'", i, tt.expected, source) + } } } @@ -305,7 +313,7 @@ func TestAddDockerImagesLabel(t *testing.T) { driverStatus string dmsetupTable string getDockerDeviceMapperInfoError error - partitions map[string]partition + mounts []*mount.Info expectedDockerDevice string expectedPartition *partition }{ @@ -314,10 +322,11 @@ func TestAddDockerImagesLabel(t *testing.T) { driver: "devicemapper", driverStatus: `[["Pool Name", "vg_vagrant-docker--pool"]]`, dmsetupTable: "0 53870592 thin-pool 253:2 253:3 1024 0 1 skip_block_zeroing", - partitions: map[string]partition{ - "/dev/mapper/vg_vagrant-lv_root": { - mountpoint: "/", - fsType: "devicemapper", + mounts: []*mount.Info{ + { + Source: "/dev/mapper/vg_vagrant-lv_root", + Mountpoint: "/", + Fstype: "devicemapper", }, }, expectedDockerDevice: "vg_vagrant-docker--pool", @@ -332,41 +341,62 @@ func TestAddDockerImagesLabel(t *testing.T) { name: "devicemapper, loopback on non-root partition", driver: "devicemapper", driverStatus: `[["Data loop file","/var/lib/docker/devicemapper/devicemapper/data"]]`, - partitions: map[string]partition{ - "/dev/mapper/vg_vagrant-lv_root": { - mountpoint: "/", - fsType: "devicemapper", + mounts: []*mount.Info{ + { + Source: "/dev/mapper/vg_vagrant-lv_root", + Mountpoint: "/", + Fstype: "devicemapper", }, - "/dev/sdb1": { - mountpoint: "/var/lib/docker/devicemapper", + { + Source: "/dev/sdb1", + Mountpoint: "/var/lib/docker/devicemapper", }, }, expectedDockerDevice: "/dev/sdb1", }, { name: "multiple mounts - innermost check", - partitions: map[string]partition{ - "/dev/sda1": { - mountpoint: "/", - fsType: "ext4", + mounts: []*mount.Info{ + { + Source: "/dev/sda1", + Mountpoint: "/", + Fstype: "ext4", }, - "/dev/sdb1": { - mountpoint: "/var/lib/docker", - fsType: "ext4", + { + Source: "/dev/sdb1", + Mountpoint: "/var/lib/docker", + Fstype: "ext4", }, - "/dev/sdb2": { - mountpoint: "/var/lib/docker/btrfs", - fsType: "btrfs", + { + Source: "/dev/sdb2", + Mountpoint: "/var/lib/docker/btrfs", + Fstype: "btrfs", }, }, expectedDockerDevice: "/dev/sdb2", }, + { + name: "root fs inside container, docker-images bindmount", + mounts: []*mount.Info{ + { + Source: "overlay", + Mountpoint: "/", + Fstype: "overlay", + }, + { + Source: "/dev/sda1", + Mountpoint: "/var/lib/docker", + Fstype: "ext4", + }, + }, + expectedDockerDevice: "/dev/sda1", + }, } for _, tt := range tests { fsInfo := &RealFsInfo{ labels: map[string]string{}, - partitions: tt.partitions, + partitions: map[string]partition{}, dmsetup: &testDmsetup{ data: []byte(tt.dmsetupTable), }, @@ -380,7 +410,7 @@ func TestAddDockerImagesLabel(t *testing.T) { }, } - fsInfo.addDockerImagesLabel(context) + fsInfo.addDockerImagesLabel(context, tt.mounts) if e, a := tt.expectedDockerDevice, fsInfo.labels[LabelDockerImages]; e != a { t.Errorf("%s: docker device: expected %q, got %q", tt.name, e, a)