Browse code

Windows: Support non-base-layered images

Previously, Windows only supported running with a OS-managed base image.
With this change, Windows supports normal, Linux-like layered images, too.

Signed-off-by: John Starks <jostarks@microsoft.com>

John Starks authored on 2016/03/29 10:14:05
Showing 6 changed files
... ...
@@ -373,8 +373,7 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro
373 373
 		}
374 374
 		// layer is intentionally not released
375 375
 
376
-		rootFS := image.NewRootFS()
377
-		rootFS.BaseLayer = filepath.Base(info.Path)
376
+		rootFS := image.NewRootFSWithBaseLayer(filepath.Base(info.Path))
378 377
 
379 378
 		// Create history for base layer
380 379
 		config, err := json.Marshal(&image.Image{
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"syscall"
6 6
 
7 7
 	"github.com/docker/docker/container"
8
+	"github.com/docker/docker/image"
8 9
 	"github.com/docker/docker/layer"
9 10
 	"github.com/docker/docker/libcontainerd"
10 11
 	"github.com/docker/docker/libcontainerd/windowsoci"
... ...
@@ -88,9 +89,15 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
88 88
 
89 89
 	// s.Windows.LayerPaths
90 90
 	var layerPaths []string
91
-	if img.RootFS != nil && img.RootFS.Type == "layers+base" {
91
+	if img.RootFS != nil && (img.RootFS.Type == image.TypeLayers || img.RootFS.Type == image.TypeLayersWithBase) {
92
+		// Get the layer path for each layer.
93
+		start := 1
94
+		if img.RootFS.Type == image.TypeLayersWithBase {
95
+			// Include an empty slice to get the base layer ID.
96
+			start = 0
97
+		}
92 98
 		max := len(img.RootFS.DiffIDs)
93
-		for i := 0; i <= max; i++ {
99
+		for i := start; i <= max; i++ {
94 100
 			img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
95 101
 			path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID())
96 102
 			if err != nil {
... ...
@@ -20,8 +20,9 @@ func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS)
20 20
 	}
21 21
 	// There must be an image that already references the baselayer.
22 22
 	for _, img := range is.Map() {
23
-		if img.RootFS.BaseLayerID() == v1img.Parent {
23
+		if img.RootFS.Type == image.TypeLayersWithBase && img.RootFS.BaseLayerID() == v1img.Parent {
24 24
 			rootFS.BaseLayer = img.RootFS.BaseLayer
25
+			rootFS.Type = image.TypeLayersWithBase
25 26
 			return nil
26 27
 		}
27 28
 	}
... ...
@@ -2,6 +2,14 @@ package image
2 2
 
3 3
 import "github.com/docker/docker/layer"
4 4
 
5
+// TypeLayers is used for RootFS.Type for filesystems organized into layers.
6
+const TypeLayers = "layers"
7
+
8
+// NewRootFS returns empty RootFS struct
9
+func NewRootFS() *RootFS {
10
+	return &RootFS{Type: TypeLayers}
11
+}
12
+
5 13
 // Append appends a new diffID to rootfs
6 14
 func (r *RootFS) Append(id layer.DiffID) {
7 15
 	r.DiffIDs = append(r.DiffIDs, id)
... ...
@@ -16,8 +16,3 @@ type RootFS struct {
16 16
 func (r *RootFS) ChainID() layer.ChainID {
17 17
 	return layer.CreateChainID(r.DiffIDs)
18 18
 }
19
-
20
-// NewRootFS returns empty RootFS struct
21
-func NewRootFS() *RootFS {
22
-	return &RootFS{Type: "layers"}
23
-}
... ...
@@ -10,6 +10,9 @@ import (
10 10
 	"github.com/docker/docker/layer"
11 11
 )
12 12
 
13
+// TypeLayersWithBase is used for RootFS.Type for Windows filesystems that have layers and a centrally-stored base layer.
14
+const TypeLayersWithBase = "layers+base"
15
+
13 16
 // RootFS describes images root filesystem
14 17
 // This is currently a placeholder that only supports layers. In the future
15 18
 // this can be made into an interface that supports different implementations.
... ...
@@ -21,17 +24,25 @@ type RootFS struct {
21 21
 
22 22
 // BaseLayerID returns the 64 byte hex ID for the baselayer name.
23 23
 func (r *RootFS) BaseLayerID() string {
24
+	if r.Type != TypeLayersWithBase {
25
+		panic("tried to get base layer ID without a base layer")
26
+	}
24 27
 	baseID := sha512.Sum384([]byte(r.BaseLayer))
25 28
 	return fmt.Sprintf("%x", baseID[:32])
26 29
 }
27 30
 
28 31
 // ChainID returns the ChainID for the top layer in RootFS.
29 32
 func (r *RootFS) ChainID() layer.ChainID {
30
-	baseDiffID := digest.FromBytes([]byte(r.BaseLayerID()))
31
-	return layer.CreateChainID(append([]layer.DiffID{layer.DiffID(baseDiffID)}, r.DiffIDs...))
33
+	ids := r.DiffIDs
34
+	if r.Type == TypeLayersWithBase {
35
+		// Add an extra ID for the base.
36
+		baseDiffID := layer.DiffID(digest.FromBytes([]byte(r.BaseLayerID())))
37
+		ids = append([]layer.DiffID{baseDiffID}, ids...)
38
+	}
39
+	return layer.CreateChainID(ids)
32 40
 }
33 41
 
34
-// NewRootFS returns empty RootFS struct
35
-func NewRootFS() *RootFS {
36
-	return &RootFS{Type: "layers+base"}
42
+// NewRootFSWithBaseLayer returns a RootFS struct with a base layer
43
+func NewRootFSWithBaseLayer(baseLayer string) *RootFS {
44
+	return &RootFS{Type: TypeLayersWithBase, BaseLayer: baseLayer}
37 45
 }