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