github.com/eljojo/docker@v1.6.0-rc4/volumes/repository.go (about)

     1  package volumes
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"sync"
     9  
    10  	log "github.com/Sirupsen/logrus"
    11  	"github.com/docker/docker/daemon/graphdriver"
    12  	"github.com/docker/docker/pkg/common"
    13  )
    14  
    15  type Repository struct {
    16  	configPath string
    17  	driver     graphdriver.Driver
    18  	volumes    map[string]*Volume
    19  	lock       sync.Mutex
    20  }
    21  
    22  func NewRepository(configPath string, driver graphdriver.Driver) (*Repository, error) {
    23  	abspath, err := filepath.Abs(configPath)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  
    28  	// Create the config path
    29  	if err := os.MkdirAll(abspath, 0700); err != nil && !os.IsExist(err) {
    30  		return nil, err
    31  	}
    32  
    33  	repo := &Repository{
    34  		driver:     driver,
    35  		configPath: abspath,
    36  		volumes:    make(map[string]*Volume),
    37  	}
    38  
    39  	return repo, repo.restore()
    40  }
    41  
    42  func (r *Repository) newVolume(path string, writable bool) (*Volume, error) {
    43  	var (
    44  		isBindMount bool
    45  		err         error
    46  		id          = common.GenerateRandomID()
    47  	)
    48  	if path != "" {
    49  		isBindMount = true
    50  	}
    51  
    52  	if path == "" {
    53  		path, err = r.createNewVolumePath(id)
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  	}
    58  	path = filepath.Clean(path)
    59  
    60  	// Ignore the error here since the path may not exist
    61  	// Really just want to make sure the path we are using is real(or non-existant)
    62  	if cleanPath, err := filepath.EvalSymlinks(path); err == nil {
    63  		path = cleanPath
    64  	}
    65  
    66  	v := &Volume{
    67  		ID:          id,
    68  		Path:        path,
    69  		repository:  r,
    70  		Writable:    writable,
    71  		containers:  make(map[string]struct{}),
    72  		configPath:  r.configPath + "/" + id,
    73  		IsBindMount: isBindMount,
    74  	}
    75  
    76  	if err := v.initialize(); err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	return v, r.add(v)
    81  }
    82  
    83  func (r *Repository) restore() error {
    84  	dir, err := ioutil.ReadDir(r.configPath)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	for _, v := range dir {
    90  		id := v.Name()
    91  		vol := &Volume{
    92  			ID:         id,
    93  			configPath: r.configPath + "/" + id,
    94  			containers: make(map[string]struct{}),
    95  		}
    96  		if err := vol.FromDisk(); err != nil {
    97  			if !os.IsNotExist(err) {
    98  				log.Debugf("Error restoring volume: %v", err)
    99  				continue
   100  			}
   101  			if err := vol.initialize(); err != nil {
   102  				log.Debugf("%s", err)
   103  				continue
   104  			}
   105  		}
   106  		if err := r.add(vol); err != nil {
   107  			log.Debugf("Error restoring volume: %v", err)
   108  		}
   109  	}
   110  	return nil
   111  }
   112  
   113  func (r *Repository) Get(path string) *Volume {
   114  	r.lock.Lock()
   115  	vol := r.get(path)
   116  	r.lock.Unlock()
   117  	return vol
   118  }
   119  
   120  func (r *Repository) get(path string) *Volume {
   121  	path, err := filepath.EvalSymlinks(path)
   122  	if err != nil {
   123  		return nil
   124  	}
   125  	return r.volumes[filepath.Clean(path)]
   126  }
   127  
   128  func (r *Repository) add(volume *Volume) error {
   129  	if vol := r.get(volume.Path); vol != nil {
   130  		return fmt.Errorf("Volume exists: %s", volume.ID)
   131  	}
   132  	r.volumes[volume.Path] = volume
   133  	return nil
   134  }
   135  
   136  func (r *Repository) Delete(path string) error {
   137  	r.lock.Lock()
   138  	defer r.lock.Unlock()
   139  	path, err := filepath.EvalSymlinks(path)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	volume := r.get(filepath.Clean(path))
   144  	if volume == nil {
   145  		return fmt.Errorf("Volume %s does not exist", path)
   146  	}
   147  
   148  	containers := volume.Containers()
   149  	if len(containers) > 0 {
   150  		return fmt.Errorf("Volume %s is being used and cannot be removed: used by containers %s", volume.Path, containers)
   151  	}
   152  
   153  	if err := os.RemoveAll(volume.configPath); err != nil {
   154  		return err
   155  	}
   156  
   157  	if !volume.IsBindMount {
   158  		if err := r.driver.Remove(volume.ID); err != nil {
   159  			if !os.IsNotExist(err) {
   160  				return err
   161  			}
   162  		}
   163  	}
   164  
   165  	delete(r.volumes, volume.Path)
   166  	return nil
   167  }
   168  
   169  func (r *Repository) createNewVolumePath(id string) (string, error) {
   170  	if err := r.driver.Create(id, ""); err != nil {
   171  		return "", err
   172  	}
   173  
   174  	path, err := r.driver.Get(id, "")
   175  	if err != nil {
   176  		return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %v", r.driver, id, err)
   177  	}
   178  
   179  	return path, nil
   180  }
   181  
   182  func (r *Repository) FindOrCreateVolume(path string, writable bool) (*Volume, error) {
   183  	r.lock.Lock()
   184  	defer r.lock.Unlock()
   185  
   186  	if path == "" {
   187  		return r.newVolume(path, writable)
   188  	}
   189  
   190  	if v := r.get(path); v != nil {
   191  		return v, nil
   192  	}
   193  
   194  	return r.newVolume(path, writable)
   195  }