github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/volume/local/local.go (about)

     1  // Package local provides the default implementation for volumes. It
     2  // is used to mount data volume containers and directories local to
     3  // the host server.
     4  package local
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"sync"
    13  
    14  	"github.com/docker/docker/volume"
    15  )
    16  
    17  // VolumeDataPathName is the name of the directory where the volume data is stored.
    18  // It uses a very distintive name to avoid collisions migrating data between
    19  // Docker versions.
    20  const (
    21  	VolumeDataPathName = "_data"
    22  	volumesPathName    = "volumes"
    23  )
    24  
    25  // ErrNotFound is the typed error returned when the requested volume name can't be found
    26  var ErrNotFound = errors.New("volume not found")
    27  
    28  // New instantiates a new Root instance with the provided scope. Scope
    29  // is the base path that the Root instance uses to store its
    30  // volumes. The base path is created here if it does not exist.
    31  func New(scope string) (*Root, error) {
    32  	rootDirectory := filepath.Join(scope, volumesPathName)
    33  
    34  	if err := os.MkdirAll(rootDirectory, 0700); err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	r := &Root{
    39  		scope:   scope,
    40  		path:    rootDirectory,
    41  		volumes: make(map[string]*localVolume),
    42  	}
    43  
    44  	dirs, err := ioutil.ReadDir(rootDirectory)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	for _, d := range dirs {
    50  		name := filepath.Base(d.Name())
    51  		r.volumes[name] = &localVolume{
    52  			driverName: r.Name(),
    53  			name:       name,
    54  			path:       r.DataPath(name),
    55  		}
    56  	}
    57  
    58  	return r, nil
    59  }
    60  
    61  // Root implements the Driver interface for the volume package and
    62  // manages the creation/removal of volumes. It uses only standard vfs
    63  // commands to create/remove dirs within its provided scope.
    64  type Root struct {
    65  	m       sync.Mutex
    66  	scope   string
    67  	path    string
    68  	volumes map[string]*localVolume
    69  }
    70  
    71  // List lists all the volumes
    72  func (r *Root) List() []volume.Volume {
    73  	var ls []volume.Volume
    74  	for _, v := range r.volumes {
    75  		ls = append(ls, v)
    76  	}
    77  	return ls
    78  }
    79  
    80  // DataPath returns the constructed path of this volume.
    81  func (r *Root) DataPath(volumeName string) string {
    82  	return filepath.Join(r.path, volumeName, VolumeDataPathName)
    83  }
    84  
    85  // Name returns the name of Root, defined in the volume package in the DefaultDriverName constant.
    86  func (r *Root) Name() string {
    87  	return volume.DefaultDriverName
    88  }
    89  
    90  // Create creates a new volume.Volume with the provided name, creating
    91  // the underlying directory tree required for this volume in the
    92  // process.
    93  func (r *Root) Create(name string, _ map[string]string) (volume.Volume, error) {
    94  	r.m.Lock()
    95  	defer r.m.Unlock()
    96  
    97  	v, exists := r.volumes[name]
    98  	if exists {
    99  		return v, nil
   100  	}
   101  
   102  	path := r.DataPath(name)
   103  	if err := os.MkdirAll(path, 0755); err != nil {
   104  		if os.IsExist(err) {
   105  			return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path))
   106  		}
   107  		return nil, err
   108  	}
   109  	v = &localVolume{
   110  		driverName: r.Name(),
   111  		name:       name,
   112  		path:       path,
   113  	}
   114  	r.volumes[name] = v
   115  	return v, nil
   116  }
   117  
   118  // Remove removes the specified volume and all underlying data. If the
   119  // given volume does not belong to this driver and an error is
   120  // returned. The volume is reference counted, if all references are
   121  // not released then the volume is not removed.
   122  func (r *Root) Remove(v volume.Volume) error {
   123  	r.m.Lock()
   124  	defer r.m.Unlock()
   125  
   126  	lv, ok := v.(*localVolume)
   127  	if !ok {
   128  		return errors.New("unknown volume type")
   129  	}
   130  
   131  	realPath, err := filepath.EvalSymlinks(lv.path)
   132  	if err != nil {
   133  		if !os.IsNotExist(err) {
   134  			return err
   135  		}
   136  		realPath = filepath.Dir(lv.path)
   137  	}
   138  
   139  	if !r.scopedPath(realPath) {
   140  		return fmt.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath)
   141  	}
   142  
   143  	if err := removePath(realPath); err != nil {
   144  		return err
   145  	}
   146  
   147  	delete(r.volumes, lv.name)
   148  	return removePath(filepath.Dir(lv.path))
   149  }
   150  
   151  func removePath(path string) error {
   152  	if err := os.RemoveAll(path); err != nil {
   153  		if os.IsNotExist(err) {
   154  			return nil
   155  		}
   156  		return err
   157  	}
   158  	return nil
   159  }
   160  
   161  // Get looks up the volume for the given name and returns it if found
   162  func (r *Root) Get(name string) (volume.Volume, error) {
   163  	r.m.Lock()
   164  	v, exists := r.volumes[name]
   165  	r.m.Unlock()
   166  	if !exists {
   167  		return nil, ErrNotFound
   168  	}
   169  	return v, nil
   170  }
   171  
   172  // localVolume implements the Volume interface from the volume package and
   173  // represents the volumes created by Root.
   174  type localVolume struct {
   175  	m         sync.Mutex
   176  	usedCount int
   177  	// unique name of the volume
   178  	name string
   179  	// path is the path on the host where the data lives
   180  	path string
   181  	// driverName is the name of the driver that created the volume.
   182  	driverName string
   183  }
   184  
   185  // Name returns the name of the given Volume.
   186  func (v *localVolume) Name() string {
   187  	return v.name
   188  }
   189  
   190  // DriverName returns the driver that created the given Volume.
   191  func (v *localVolume) DriverName() string {
   192  	return v.driverName
   193  }
   194  
   195  // Path returns the data location.
   196  func (v *localVolume) Path() string {
   197  	return v.path
   198  }
   199  
   200  // Mount implements the localVolume interface, returning the data location.
   201  func (v *localVolume) Mount() (string, error) {
   202  	return v.path, nil
   203  }
   204  
   205  // Umount is for satisfying the localVolume interface and does not do anything in this driver.
   206  func (v *localVolume) Unmount() error {
   207  	return nil
   208  }