@@ -29,6 +29,7 @@ import (
2929 "os"
3030 "os/exec"
3131 "path"
32+ "path/filepath"
3233 "regexp"
3334 "strconv"
3435 "strings"
@@ -41,22 +42,38 @@ import (
4142
4243var partitionRegex = regexp .MustCompile ("^(:?(:?s|xv)d[a-z]+\\ d*|dm-\\ d+)$" )
4344
45+ const (
46+ LabelSystemRoot = "root"
47+ LabelDockerImages = "docker-images"
48+ )
49+
4450type partition struct {
4551 mountpoint string
4652 major uint
4753 minor uint
4854}
4955
5056type RealFsInfo struct {
57+ // Map from block device path to partition information.
5158 partitions map [string ]partition
59+ // Map from label to block device path.
60+ // Labels are intent-specific tags that are auto-detected.
61+ labels map [string ]string
62+ }
63+
64+ type Context struct {
65+ // docker root directory.
66+ DockerRoot string
5267}
5368
54- func NewFsInfo () (FsInfo , error ) {
69+ func NewFsInfo (context Context ) (FsInfo , error ) {
5570 mounts , err := mount .GetMounts ()
5671 if err != nil {
5772 return nil , err
5873 }
5974 partitions := make (map [string ]partition , 0 )
75+ fsInfo := & RealFsInfo {}
76+ fsInfo .labels = make (map [string ]string , 0 )
6077 for _ , mount := range mounts {
6178 if ! strings .HasPrefix (mount .Fstype , "ext" ) && mount .Fstype != "btrfs" {
6279 continue
@@ -68,7 +85,84 @@ func NewFsInfo() (FsInfo, error) {
6885 partitions [mount .Source ] = partition {mount .Mountpoint , uint (mount .Major ), uint (mount .Minor )}
6986 }
7087 glog .Infof ("Filesystem partitions: %+v" , partitions )
71- return & RealFsInfo {partitions }, nil
88+ fsInfo .partitions = partitions
89+ fsInfo .addLabels (context )
90+ return fsInfo , nil
91+ }
92+
93+ func (self * RealFsInfo ) addLabels (context Context ) {
94+ dockerPaths := getDockerImagePaths (context )
95+ for src , p := range self .partitions {
96+ if p .mountpoint == "/" {
97+ if _ , ok := self .labels [LabelSystemRoot ]; ! ok {
98+ self .labels [LabelSystemRoot ] = src
99+ }
100+ }
101+ self .updateDockerImagesPath (src , p .mountpoint , dockerPaths )
102+ // TODO(rjnagal): Add label for docker devicemapper pool.
103+ }
104+ }
105+
106+ // Generate a list of possible mount points for docker image management from the docker root directory.
107+ // Right now, we look for each type of supported graph driver directories, but we can do better by parsing
108+ // some of the context from `docker info`.
109+ func getDockerImagePaths (context Context ) []string {
110+ // TODO(rjnagal): Detect docker root and graphdriver directories from docker info.
111+ dockerRoot := context .DockerRoot
112+ dockerImagePaths := []string {}
113+ for _ , dir := range []string {"devicemapper" , "btrfs" , "aufs" } {
114+ dockerImagePaths = append (dockerImagePaths , path .Join (dockerRoot , dir ))
115+ }
116+ for dockerRoot != "/" && dockerRoot != "." {
117+ dockerImagePaths = append (dockerImagePaths , dockerRoot )
118+ dockerRoot = filepath .Dir (dockerRoot )
119+ }
120+ dockerImagePaths = append (dockerImagePaths , "/" )
121+ return dockerImagePaths
122+ }
123+
124+ // This method compares the mountpoint with possible docker image mount points. If a match is found,
125+ // docker images label is added to the partition.
126+ func (self * RealFsInfo ) updateDockerImagesPath (source string , mountpoint string , dockerImagePaths []string ) {
127+ for _ , v := range dockerImagePaths {
128+ if v == mountpoint {
129+ if i , ok := self .labels [LabelDockerImages ]; ok {
130+ // pick the innermost mountpoint.
131+ mnt := self .partitions [i ].mountpoint
132+ if len (mnt ) < len (mountpoint ) {
133+ self .labels [LabelDockerImages ] = source
134+ }
135+ } else {
136+ self .labels [LabelDockerImages ] = source
137+ }
138+ }
139+ }
140+ }
141+
142+ func (self * RealFsInfo ) GetDeviceForLabel (label string ) (string , error ) {
143+ dev , ok := self .labels [label ]
144+ if ! ok {
145+ return "" , fmt .Errorf ("non-existent label %q" , label )
146+ }
147+ return dev , nil
148+ }
149+
150+ func (self * RealFsInfo ) GetLabelsForDevice (device string ) ([]string , error ) {
151+ labels := []string {}
152+ for label , dev := range self .labels {
153+ if dev == device {
154+ labels = append (labels , label )
155+ }
156+ }
157+ return labels , nil
158+ }
159+
160+ func (self * RealFsInfo ) GetMountpointForDevice (dev string ) (string , error ) {
161+ p , ok := self .partitions [dev ]
162+ if ! ok {
163+ return "" , fmt .Errorf ("no partition info for device %q" , dev )
164+ }
165+ return p .mountpoint , nil
72166}
73167
74168func (self * RealFsInfo ) GetFsInfoForPath (mountSet map [string ]struct {}) ([]Fs , error ) {
0 commit comments