github.com/dougm/docker@v1.5.0/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/utils" 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 = utils.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 r.lock.Lock() 130 defer r.lock.Unlock() 131 return r.add(volume) 132 } 133 134 func (r *Repository) add(volume *Volume) error { 135 if vol := r.get(volume.Path); vol != nil { 136 return fmt.Errorf("Volume exists: %s", volume.ID) 137 } 138 r.volumes[volume.Path] = volume 139 return nil 140 } 141 142 func (r *Repository) Remove(volume *Volume) { 143 r.lock.Lock() 144 r.remove(volume) 145 r.lock.Unlock() 146 } 147 148 func (r *Repository) remove(volume *Volume) { 149 delete(r.volumes, volume.Path) 150 } 151 152 func (r *Repository) Delete(path string) error { 153 r.lock.Lock() 154 defer r.lock.Unlock() 155 path, err := filepath.EvalSymlinks(path) 156 if err != nil { 157 return err 158 } 159 volume := r.get(filepath.Clean(path)) 160 if volume == nil { 161 return fmt.Errorf("Volume %s does not exist", path) 162 } 163 164 containers := volume.Containers() 165 if len(containers) > 0 { 166 return fmt.Errorf("Volume %s is being used and cannot be removed: used by containers %s", volume.Path, containers) 167 } 168 169 if err := os.RemoveAll(volume.configPath); err != nil { 170 return err 171 } 172 173 if !volume.IsBindMount { 174 if err := r.driver.Remove(volume.ID); err != nil { 175 if !os.IsNotExist(err) { 176 return err 177 } 178 } 179 } 180 181 r.remove(volume) 182 return nil 183 } 184 185 func (r *Repository) createNewVolumePath(id string) (string, error) { 186 if err := r.driver.Create(id, ""); err != nil { 187 return "", err 188 } 189 190 path, err := r.driver.Get(id, "") 191 if err != nil { 192 return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %v", r.driver, id, err) 193 } 194 195 return path, nil 196 } 197 198 func (r *Repository) FindOrCreateVolume(path string, writable bool) (*Volume, error) { 199 r.lock.Lock() 200 defer r.lock.Unlock() 201 202 if path == "" { 203 return r.newVolume(path, writable) 204 } 205 206 if v := r.get(path); v != nil { 207 return v, nil 208 } 209 210 return r.newVolume(path, writable) 211 }