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