github.com/torfuzx/docker@v1.8.1/daemon/graphdriver/aufs/migrate.go (about) 1 // +build linux 2 3 package aufs 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path" 11 ) 12 13 type metadata struct { 14 ID string `json:"id"` 15 ParentID string `json:"parent,omitempty"` 16 Image string `json:"Image,omitempty"` 17 18 parent *metadata 19 } 20 21 func pathExists(pth string) bool { 22 if _, err := os.Stat(pth); err != nil { 23 return false 24 } 25 return true 26 } 27 28 // Migrate existing images and containers from docker < 0.7.x 29 // 30 // The format pre 0.7 is for docker to store the metadata and filesystem 31 // content in the same directory. For the migration to work we need to move Image layer 32 // data from /var/lib/docker/graph/<id>/layers to the diff of the registered id. 33 // 34 // Next we need to migrate the container's rw layer to diff of the driver. After the 35 // contents are migrated we need to register the image and container ids with the 36 // driver. 37 // 38 // For the migration we try to move the folder containing the layer files, if that 39 // fails because the data is currently mounted we will fallback to creating a 40 // symlink. 41 func (a *Driver) Migrate(pth string, setupInit func(p string) error) error { 42 if pathExists(path.Join(pth, "graph")) { 43 if err := a.migrateRepositories(pth); err != nil { 44 return err 45 } 46 if err := a.migrateImages(path.Join(pth, "graph")); err != nil { 47 return err 48 } 49 return a.migrateContainers(path.Join(pth, "containers"), setupInit) 50 } 51 return nil 52 } 53 54 func (a *Driver) migrateRepositories(pth string) error { 55 name := path.Join(pth, "repositories") 56 if err := os.Rename(name, name+"-aufs"); err != nil && !os.IsNotExist(err) { 57 return err 58 } 59 return nil 60 } 61 62 func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) error { 63 fis, err := ioutil.ReadDir(pth) 64 if err != nil { 65 return err 66 } 67 68 for _, fi := range fis { 69 if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "rw")) { 70 if err := tryRelocate(path.Join(pth, id, "rw"), path.Join(a.rootPath(), "diff", id)); err != nil { 71 return err 72 } 73 74 if !a.Exists(id) { 75 76 metadata, err := loadMetadata(path.Join(pth, id, "config.json")) 77 if err != nil { 78 return err 79 } 80 81 initID := fmt.Sprintf("%s-init", id) 82 if err := a.Create(initID, metadata.Image); err != nil { 83 return err 84 } 85 86 initPath, err := a.Get(initID, "") 87 if err != nil { 88 return err 89 } 90 // setup init layer 91 if err := setupInit(initPath); err != nil { 92 return err 93 } 94 95 if err := a.Create(id, initID); err != nil { 96 return err 97 } 98 } 99 } 100 } 101 return nil 102 } 103 104 func (a *Driver) migrateImages(pth string) error { 105 fis, err := ioutil.ReadDir(pth) 106 if err != nil { 107 return err 108 } 109 var ( 110 m = make(map[string]*metadata) 111 current *metadata 112 exists bool 113 ) 114 115 for _, fi := range fis { 116 if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "layer")) { 117 if current, exists = m[id]; !exists { 118 current, err = loadMetadata(path.Join(pth, id, "json")) 119 if err != nil { 120 return err 121 } 122 m[id] = current 123 } 124 } 125 } 126 127 for _, v := range m { 128 v.parent = m[v.ParentID] 129 } 130 131 migrated := make(map[string]bool) 132 for _, v := range m { 133 if err := a.migrateImage(v, pth, migrated); err != nil { 134 return err 135 } 136 } 137 return nil 138 } 139 140 func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool) error { 141 if !migrated[m.ID] { 142 if m.parent != nil { 143 a.migrateImage(m.parent, pth, migrated) 144 } 145 if err := tryRelocate(path.Join(pth, m.ID, "layer"), path.Join(a.rootPath(), "diff", m.ID)); err != nil { 146 return err 147 } 148 if !a.Exists(m.ID) { 149 if err := a.Create(m.ID, m.ParentID); err != nil { 150 return err 151 } 152 } 153 migrated[m.ID] = true 154 } 155 return nil 156 } 157 158 // tryRelocate will try to rename the old path to the new pack and if 159 // the operation fails, it will fallback to a symlink 160 func tryRelocate(oldPath, newPath string) error { 161 s, err := os.Lstat(newPath) 162 if err != nil && !os.IsNotExist(err) { 163 return err 164 } 165 // If the destination is a symlink then we already tried to relocate once before 166 // and it failed so we delete it and try to remove 167 if s != nil && s.Mode()&os.ModeSymlink != 0 { 168 if err := os.RemoveAll(newPath); err != nil { 169 return err 170 } 171 } 172 if err := os.Rename(oldPath, newPath); err != nil { 173 if sErr := os.Symlink(oldPath, newPath); sErr != nil { 174 return fmt.Errorf("Unable to relocate %s to %s: Rename err %s Symlink err %s", oldPath, newPath, err, sErr) 175 } 176 } 177 return nil 178 } 179 180 func loadMetadata(pth string) (*metadata, error) { 181 f, err := os.Open(pth) 182 if err != nil { 183 return nil, err 184 } 185 defer f.Close() 186 187 var ( 188 out = &metadata{} 189 dec = json.NewDecoder(f) 190 ) 191 192 if err := dec.Decode(out); err != nil { 193 return nil, err 194 } 195 return out, nil 196 }