github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/storage/provider/dirfuncs.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provider 5 6 import ( 7 "io/ioutil" 8 "os" 9 "strconv" 10 "strings" 11 12 "github.com/juju/errors" 13 ) 14 15 // dirFuncs is used to allow the real directory operations to 16 // be stubbed out for testing. 17 type dirFuncs interface { 18 mkDirAll(path string, perm os.FileMode) error 19 lstat(path string) (fi os.FileInfo, err error) 20 fileCount(path string) (int, error) 21 calculateSize(path string) (sizeInMib uint64, _ error) 22 symlink(oldpath, newpath string) error 23 24 // bindMount remounts the directory "source" at "target", 25 // so that the source tree is available in both locations. 26 // If "target" already refers to "source" in this manner, 27 // then the bindMount operation is a no-op. 28 bindMount(source, target string) error 29 30 // mountPoint returns the mount-point that contains the 31 // specified path. 32 mountPoint(path string) (string, error) 33 34 // mountPointSource returns the source of the mount-point 35 // that contains the specified path. 36 mountPointSource(path string) (string, error) 37 } 38 39 // osDirFuncs is an implementation of dirFuncs that operates on the real 40 // filesystem. 41 type osDirFuncs struct { 42 run runCommandFunc 43 } 44 45 func (*osDirFuncs) mkDirAll(path string, perm os.FileMode) error { 46 return os.MkdirAll(path, perm) 47 } 48 49 func (*osDirFuncs) lstat(path string) (fi os.FileInfo, err error) { 50 return os.Lstat(path) 51 } 52 53 func (*osDirFuncs) fileCount(path string) (int, error) { 54 files, err := ioutil.ReadDir(path) 55 if err != nil { 56 return 0, errors.Annotate(err, "could not read directory") 57 } 58 return len(files), nil 59 } 60 61 func (*osDirFuncs) symlink(oldpath, newpath string) error { 62 return os.Symlink(oldpath, newpath) 63 } 64 65 func (o *osDirFuncs) calculateSize(path string) (sizeInMib uint64, _ error) { 66 output, err := df(o.run, path, "size") 67 if err != nil { 68 return 0, errors.Annotate(err, "getting size") 69 } 70 numBlocks, err := strconv.ParseUint(output, 10, 64) 71 if err != nil { 72 return 0, errors.Annotate(err, "parsing size") 73 } 74 return numBlocks / 1024, nil 75 } 76 77 func (o *osDirFuncs) bindMount(source, target string) error { 78 _, err := o.run("mount", "--bind", source, target) 79 return err 80 } 81 82 func (o *osDirFuncs) mountPoint(path string) (string, error) { 83 target, err := df(o.run, path, "target") 84 return target, err 85 } 86 87 func (o *osDirFuncs) mountPointSource(path string) (string, error) { 88 source, err := df(o.run, path, "source") 89 return source, err 90 } 91 92 func df(run runCommandFunc, path, field string) (string, error) { 93 output, err := run("df", "--output="+field, path) 94 if err != nil { 95 return "", errors.Trace(err) 96 } 97 // the first line contains the headers 98 lines := strings.SplitN(output, "\n", 2) 99 return strings.TrimSpace(lines[1]), nil 100 }