github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/volumes/repository.go (about) 1 package volumes 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "sync" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/daemon/graphdriver" 12 "github.com/docker/docker/pkg/stringid" 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 = stringid.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 nonexistent) 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 r.add(v) 81 return v, nil 82 } 83 84 func (r *Repository) restore() error { 85 dir, err := ioutil.ReadDir(r.configPath) 86 if err != nil { 87 return err 88 } 89 90 for _, v := range dir { 91 id := v.Name() 92 vol := &Volume{ 93 ID: id, 94 configPath: r.configPath + "/" + id, 95 containers: make(map[string]struct{}), 96 } 97 if err := vol.FromDisk(); err != nil { 98 if !os.IsNotExist(err) { 99 logrus.Debugf("Error restoring volume: %v", err) 100 continue 101 } 102 if err := vol.initialize(); err != nil { 103 logrus.Debugf("%s", err) 104 continue 105 } 106 } 107 r.add(vol) 108 } 109 return nil 110 } 111 112 func (r *Repository) Get(path string) *Volume { 113 r.lock.Lock() 114 vol := r.get(path) 115 r.lock.Unlock() 116 return vol 117 } 118 119 func (r *Repository) get(path string) *Volume { 120 path, err := filepath.EvalSymlinks(path) 121 if err != nil { 122 return nil 123 } 124 return r.volumes[filepath.Clean(path)] 125 } 126 127 func (r *Repository) add(volume *Volume) { 128 if vol := r.get(volume.Path); vol != nil { 129 return 130 } 131 r.volumes[volume.Path] = volume 132 } 133 134 func (r *Repository) Delete(path string) error { 135 r.lock.Lock() 136 defer r.lock.Unlock() 137 path, err := filepath.EvalSymlinks(path) 138 if err != nil { 139 return err 140 } 141 volume := r.get(filepath.Clean(path)) 142 if volume == nil { 143 return fmt.Errorf("Volume %s does not exist", path) 144 } 145 146 containers := volume.Containers() 147 if len(containers) > 0 { 148 return fmt.Errorf("Volume %s is being used and cannot be removed: used by containers %s", volume.Path, containers) 149 } 150 151 if err := os.RemoveAll(volume.configPath); err != nil { 152 return err 153 } 154 155 if !volume.IsBindMount { 156 if err := r.driver.Remove(volume.ID); err != nil { 157 if !os.IsNotExist(err) { 158 return err 159 } 160 } 161 } 162 163 delete(r.volumes, volume.Path) 164 return nil 165 } 166 167 func (r *Repository) createNewVolumePath(id string) (string, error) { 168 if err := r.driver.Create(id, ""); err != nil { 169 return "", err 170 } 171 172 path, err := r.driver.Get(id, "") 173 if err != nil { 174 return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %v", r.driver, id, err) 175 } 176 177 return path, nil 178 } 179 180 func (r *Repository) FindOrCreateVolume(path string, writable bool) (*Volume, error) { 181 r.lock.Lock() 182 defer r.lock.Unlock() 183 184 if path == "" { 185 return r.newVolume(path, writable) 186 } 187 188 if v := r.get(path); v != nil { 189 return v, nil 190 } 191 192 return r.newVolume(path, writable) 193 }