github.com/gnuhub/docker@v1.6.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/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 }