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  }