Переглянути джерело

Merge pull request #2183 from dotcloud/migrate-aufs

Migrate aufs to new device mapper backend
Solomon Hykes 11 роки тому
батько
коміт
4dedd9a9aa
2 змінених файлів з 91 додано та 6 видалено
  1. 90 5
      runtime.go
  2. 1 1
      runtime_test.go

+ 90 - 5
runtime.go

@@ -134,7 +134,7 @@ func (runtime *Runtime) containerRoot(id string) string {
 // Load reads the contents of a container from disk and registers
 // Load reads the contents of a container from disk and registers
 // it with Register.
 // it with Register.
 // This is typically done at startup.
 // This is typically done at startup.
-func (runtime *Runtime) Load(id string) (*Container, error) {
+func (runtime *Runtime) load(id string) (*Container, error) {
 	container := &Container{root: runtime.containerRoot(id)}
 	container := &Container{root: runtime.containerRoot(id)}
 	if err := container.FromDisk(); err != nil {
 	if err := container.FromDisk(); err != nil {
 		return nil, err
 		return nil, err
@@ -145,9 +145,6 @@ func (runtime *Runtime) Load(id string) (*Container, error) {
 	if container.State.Running {
 	if container.State.Running {
 		container.State.Ghost = true
 		container.State.Ghost = true
 	}
 	}
-	if err := runtime.Register(container); err != nil {
-		return nil, err
-	}
 	return container, nil
 	return container, nil
 }
 }
 
 
@@ -289,9 +286,14 @@ func (runtime *Runtime) restore() error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+
+	deviceSet := runtime.deviceSet
+	containers := []*Container{}
+	containersToMigrate := []*Container{}
+
 	for i, v := range dir {
 	for i, v := range dir {
 		id := v.Name()
 		id := v.Name()
-		container, err := runtime.Load(id)
+		container, err := runtime.load(id)
 		if i%21 == 0 && os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 		if i%21 == 0 && os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 			fmt.Printf("\b%c", wheel[i%4])
 			fmt.Printf("\b%c", wheel[i%4])
 		}
 		}
@@ -300,10 +302,93 @@ func (runtime *Runtime) restore() error {
 			continue
 			continue
 		}
 		}
 		utils.Debugf("Loaded container %v", container.ID)
 		utils.Debugf("Loaded container %v", container.ID)
+		containers = append(containers, container)
+
+		if !deviceSet.HasDevice(container.ID) {
+			containersToMigrate = append(containersToMigrate, container)
+		}
+	}
+
+	// Migrate AUFS containers to device mapper
+	if len(containersToMigrate) > 0 {
+		if err := migrateToDeviceMapper(runtime, containersToMigrate); err != nil {
+			return err
+		}
+	}
+
+	for _, container := range containers {
+		if err := runtime.Register(container); err != nil {
+			utils.Debugf("Failed to register container %s: %s", container.ID, err)
+			continue
+		}
 	}
 	}
 	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
 		fmt.Printf("\bdone.\n")
 		fmt.Printf("\bdone.\n")
 	}
 	}
+
+	return nil
+}
+
+func migrateToDeviceMapper(runtime *Runtime, containers []*Container) error {
+	var (
+		image    *Image
+		contents []os.FileInfo
+		err      error
+	)
+
+	fmt.Printf("Migrating %d containers to new storage backend\n", len(containers))
+	for _, container := range containers {
+		if container.State.Running {
+			fmt.Printf("WARNING - Cannot migrate %s because the container is running.  Please stop the container and relaunch the daemon!")
+			continue
+		}
+
+		fmt.Printf("Migrating %s\n", container.ID)
+
+		if contents, err = ioutil.ReadDir(container.rwPath()); err != nil {
+			if !os.IsNotExist(err) {
+				fmt.Printf("Error reading rw dir %s\n", err)
+			}
+			continue
+		}
+
+		if len(contents) == 0 {
+			fmt.Printf("Skipping migration of %s because rw layer contains no changes\n")
+			continue
+		}
+
+		if image, err = runtime.graph.Get(container.Image); err != nil {
+			fmt.Printf("Failed to fetch image %s\n", err)
+			continue
+		}
+
+		unmount := func() {
+			if err = image.Unmount(runtime, container.RootfsPath(), container.ID); err != nil {
+				fmt.Printf("Failed to unmount image %s\n", err)
+			}
+		}
+
+		if err = image.Mount(runtime, container.RootfsPath(), container.rwPath(), container.ID); err != nil {
+			fmt.Printf("Failed to mount image %s\n", err)
+			continue
+		}
+
+		if err = image.applyLayer(container.rwPath(), container.RootfsPath()); err != nil {
+			fmt.Printf("Failed to apply layer in storage backend %s\n", err)
+			unmount()
+			continue
+		}
+
+		unmount()
+
+		if err = os.RemoveAll(container.rwPath()); err != nil {
+			fmt.Printf("Failed to remove rw layer %s\n", err)
+		}
+
+		fmt.Printf("Successful migration for %s\n", container.ID)
+	}
+	fmt.Printf("Migration complete\n")
+
 	return nil
 	return nil
 }
 }
 
 

+ 1 - 1
runtime_test.go

@@ -154,7 +154,7 @@ func init() {
 	deviceset := devmapper.NewDeviceSetDM(unitTestStoreDevicesBase)
 	deviceset := devmapper.NewDeviceSetDM(unitTestStoreDevicesBase)
 	// Create a device, which triggers the initiation of the base FS
 	// Create a device, which triggers the initiation of the base FS
 	// This avoids other tests doing this and timing out
 	// This avoids other tests doing this and timing out
-	deviceset.AddDevice("init","")
+	deviceset.AddDevice("init", "")
 
 
 	// Make it our Store root
 	// Make it our Store root
 	if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, deviceset, false); err != nil {
 	if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, deviceset, false); err != nil {