Browse code

Windows: Graph remove custom interface and add central store

Signed-off-by: Stefan J. Wernli <swernli@microsoft.com>

Windows: add support for images stored in alternate location.

Signed-off-by: Stefan J. Wernli <swernli@microsoft.com>

Stefan J. Wernli authored on 2015/07/25 09:49:43
Showing 16 changed files
... ...
@@ -241,20 +241,12 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
241 241
 	}
242 242
 	defer container.Unmount()
243 243
 
244
-	if err := container.PrepareStorage(); err != nil {
245
-		return err
246
-	}
247
-
248 244
 	for _, ci := range copyInfos {
249 245
 		if err := b.addContext(container, ci.origPath, ci.destPath, ci.decompress); err != nil {
250 246
 			return err
251 247
 		}
252 248
 	}
253 249
 
254
-	if err := container.CleanupStorage(); err != nil {
255
-		return err
256
-	}
257
-
258 250
 	if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil {
259 251
 		return err
260 252
 	}
... ...
@@ -227,6 +227,21 @@ func (container *Container) GetRootResourcePath(path string) (string, error) {
227 227
 	return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
228 228
 }
229 229
 
230
+func (container *Container) ExportRw() (archive.Archive, error) {
231
+	if container.daemon == nil {
232
+		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
233
+	}
234
+	archive, err := container.daemon.Diff(container)
235
+	if err != nil {
236
+		return nil, err
237
+	}
238
+	return ioutils.NewReadCloserWrapper(archive, func() error {
239
+			err := archive.Close()
240
+			return err
241
+		}),
242
+		nil
243
+}
244
+
230 245
 func (container *Container) Start() (err error) {
231 246
 	container.Lock()
232 247
 	defer container.Unlock()
... ...
@@ -258,12 +273,6 @@ func (container *Container) Start() (err error) {
258 258
 		return err
259 259
 	}
260 260
 
261
-	// No-op if non-Windows. Once the container filesystem is mounted,
262
-	// prepare the layer to boot using the Windows driver.
263
-	if err := container.PrepareStorage(); err != nil {
264
-		return err
265
-	}
266
-
267 261
 	// Make sure NetworkMode has an acceptable value. We do this to ensure
268 262
 	// backwards API compatibility.
269 263
 	container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig)
... ...
@@ -345,10 +354,6 @@ func (container *Container) isNetworkAllocated() bool {
345 345
 func (container *Container) cleanup() {
346 346
 	container.ReleaseNetwork()
347 347
 
348
-	if err := container.CleanupStorage(); err != nil {
349
-		logrus.Errorf("%v: Failed to cleanup storage: %v", container.ID, err)
350
-	}
351
-
352 348
 	if err := container.Unmount(); err != nil {
353 349
 		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
354 350
 	}
... ...
@@ -658,14 +663,8 @@ func (container *Container) Copy(resource string) (rc io.ReadCloser, err error)
658 658
 		return nil, err
659 659
 	}
660 660
 
661
-	if err := container.PrepareStorage(); err != nil {
662
-		container.Unmount()
663
-		return nil, err
664
-	}
665
-
666 661
 	reader := ioutils.NewReadCloserWrapper(archive, func() error {
667 662
 		err := archive.Close()
668
-		container.CleanupStorage()
669 663
 		container.UnmountVolumes(true)
670 664
 		container.Unmount()
671 665
 		container.Unlock()
... ...
@@ -18,9 +18,7 @@ import (
18 18
 	"github.com/docker/docker/daemon/execdriver"
19 19
 	"github.com/docker/docker/daemon/links"
20 20
 	"github.com/docker/docker/daemon/network"
21
-	"github.com/docker/docker/pkg/archive"
22 21
 	"github.com/docker/docker/pkg/directory"
23
-	"github.com/docker/docker/pkg/ioutils"
24 22
 	"github.com/docker/docker/pkg/nat"
25 23
 	"github.com/docker/docker/pkg/stringid"
26 24
 	"github.com/docker/docker/pkg/system"
... ...
@@ -948,21 +946,6 @@ func (container *Container) initializeNetworking() error {
948 948
 	return container.buildHostnameFile()
949 949
 }
950 950
 
951
-func (container *Container) ExportRw() (archive.Archive, error) {
952
-	if container.daemon == nil {
953
-		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
954
-	}
955
-	archive, err := container.daemon.Diff(container)
956
-	if err != nil {
957
-		return nil, err
958
-	}
959
-	return ioutils.NewReadCloserWrapper(archive, func() error {
960
-			err := archive.Close()
961
-			return err
962
-		}),
963
-		nil
964
-}
965
-
966 951
 func (container *Container) getIpcContainer() (*Container, error) {
967 952
 	containerID := container.hostConfig.IpcMode.Container()
968 953
 	c, err := container.daemon.Get(containerID)
... ...
@@ -1107,14 +1090,6 @@ func (container *Container) UnmountVolumes(forceSyscall bool) error {
1107 1107
 	return nil
1108 1108
 }
1109 1109
 
1110
-func (container *Container) PrepareStorage() error {
1111
-	return nil
1112
-}
1113
-
1114
-func (container *Container) CleanupStorage() error {
1115
-	return nil
1116
-}
1117
-
1118 1110
 func (container *Container) networkMounts() []execdriver.Mount {
1119 1111
 	var mounts []execdriver.Mount
1120 1112
 	mode := "Z"
... ...
@@ -4,14 +4,9 @@ package daemon
4 4
 
5 5
 import (
6 6
 	"fmt"
7
-	"path/filepath"
8 7
 	"strings"
9 8
 
10 9
 	"github.com/docker/docker/daemon/execdriver"
11
-	"github.com/docker/docker/daemon/graphdriver/windows"
12
-	"github.com/docker/docker/image"
13
-	"github.com/docker/docker/pkg/archive"
14
-	"github.com/microsoft/hcsshim"
15 10
 )
16 11
 
17 12
 // This is deliberately empty on Windows as the default path will be set by
... ...
@@ -98,25 +93,27 @@ func populateCommand(c *Container, env []string) error {
98 98
 
99 99
 	processConfig.Env = env
100 100
 
101
-	var layerFolder string
102 101
 	var layerPaths []string
103
-
104
-	// The following is specific to the Windows driver. We do this to
105
-	// enable VFS to continue operating for development purposes.
106
-	if wd, ok := c.daemon.driver.(*windows.WindowsGraphDriver); ok {
107
-		var err error
108
-		var img *image.Image
109
-		var ids []string
110
-
111
-		if img, err = c.daemon.graph.Get(c.ImageID); err != nil {
112
-			return fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err)
102
+	img, err := c.daemon.graph.Get(c.ImageID)
103
+	if err != nil {
104
+		return fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err)
105
+	}
106
+	for i := img; i != nil && err == nil; i, err = c.daemon.graph.GetParent(i) {
107
+		lp, err := c.daemon.driver.Get(i.ID, "")
108
+		if err != nil {
109
+			return fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", c.daemon.driver.String(), i.ID, err)
113 110
 		}
114
-		if ids, err = c.daemon.graph.ParentLayerIds(img); err != nil {
115
-			return fmt.Errorf("Failed to get parentlayer ids %s", img.ID)
111
+		layerPaths = append(layerPaths, lp)
112
+		err = c.daemon.driver.Put(i.ID)
113
+		if err != nil {
114
+			return fmt.Errorf("Failed to put layer path from graphdriver %s for ImageID %s - %s", c.daemon.driver.String(), i.ID, err)
116 115
 		}
117
-		layerPaths = wd.LayerIdsToPaths(ids)
118
-		layerFolder = filepath.Join(wd.Info().HomeDir, filepath.Base(c.ID))
119 116
 	}
117
+	m, err := c.daemon.driver.GetMetadata(c.ID)
118
+	if err != nil {
119
+		return fmt.Errorf("Failed to get layer metadata - %s", err)
120
+	}
121
+	layerFolder := m["dir"]
120 122
 
121 123
 	// TODO Windows: Factor out remainder of unused fields.
122 124
 	c.command = &execdriver.Command{
... ...
@@ -151,14 +148,6 @@ func (container *Container) AllocateNetwork() error {
151 151
 	return nil
152 152
 }
153 153
 
154
-func (container *Container) ExportRw() (archive.Archive, error) {
155
-	if container.IsRunning() {
156
-		return nil, fmt.Errorf("Cannot export a running container.")
157
-	}
158
-	// TODO Windows. Implementation (different to Linux)
159
-	return nil, nil
160
-}
161
-
162 154
 func (container *Container) UpdateNetwork() error {
163 155
 	return nil
164 156
 }
... ...
@@ -174,36 +163,6 @@ func (container *Container) UnmountVolumes(forceSyscall bool) error {
174 174
 	return nil
175 175
 }
176 176
 
177
-func (container *Container) PrepareStorage() error {
178
-	if wd, ok := container.daemon.driver.(*windows.WindowsGraphDriver); ok {
179
-		// Get list of paths to parent layers.
180
-		var ids []string
181
-		if container.ImageID != "" {
182
-			img, err := container.daemon.graph.Get(container.ImageID)
183
-			if err != nil {
184
-				return err
185
-			}
186
-
187
-			ids, err = container.daemon.graph.ParentLayerIds(img)
188
-			if err != nil {
189
-				return err
190
-			}
191
-		}
192
-
193
-		if err := hcsshim.PrepareLayer(wd.Info(), container.ID, wd.LayerIdsToPaths(ids)); err != nil {
194
-			return err
195
-		}
196
-	}
197
-	return nil
198
-}
199
-
200
-func (container *Container) CleanupStorage() error {
201
-	if wd, ok := container.daemon.driver.(*windows.WindowsGraphDriver); ok {
202
-		return hcsshim.UnprepareLayer(wd.Info(), container.ID)
203
-	}
204
-	return nil
205
-}
206
-
207 177
 // prepareMountPoints is a no-op on Windows
208 178
 func (container *Container) prepareMountPoints() error {
209 179
 	return nil
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"github.com/docker/docker/daemon/network"
25 25
 	"github.com/docker/docker/graph"
26 26
 	"github.com/docker/docker/image"
27
+	"github.com/docker/docker/pkg/archive"
27 28
 	"github.com/docker/docker/pkg/broadcastwriter"
28 29
 	"github.com/docker/docker/pkg/fileutils"
29 30
 	"github.com/docker/docker/pkg/graphdb"
... ...
@@ -683,6 +684,12 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
683 683
 		return nil, fmt.Errorf("Couldn't create Tag store repositories-%s: %s", d.driver.String(), err)
684 684
 	}
685 685
 
686
+	if restorer, ok := d.driver.(graphdriver.ImageRestorer); ok {
687
+		if _, err := restorer.RestoreCustomImages(repositories, g); err != nil {
688
+			return nil, fmt.Errorf("Couldn't restore custom images: %s", err)
689
+		}
690
+	}
691
+
686 692
 	d.netController, err = initNetworkController(config)
687 693
 	if err != nil {
688 694
 		return nil, fmt.Errorf("Error initializing network controller: %v", err)
... ...
@@ -840,6 +847,46 @@ func (daemon *Daemon) UnsubscribeToContainerStats(name string, ch chan interface
840 840
 	return nil
841 841
 }
842 842
 
843
+func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
844
+	initID := fmt.Sprintf("%s-init", container.ID)
845
+	return daemon.driver.Changes(container.ID, initID)
846
+}
847
+
848
+func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
849
+	initID := fmt.Sprintf("%s-init", container.ID)
850
+	return daemon.driver.Diff(container.ID, initID)
851
+}
852
+
853
+func (daemon *Daemon) createRootfs(container *Container) error {
854
+	// Step 1: create the container directory.
855
+	// This doubles as a barrier to avoid race conditions.
856
+	if err := os.Mkdir(container.root, 0700); err != nil {
857
+		return err
858
+	}
859
+	initID := fmt.Sprintf("%s-init", container.ID)
860
+	if err := daemon.driver.Create(initID, container.ImageID); err != nil {
861
+		return err
862
+	}
863
+	initPath, err := daemon.driver.Get(initID, "")
864
+	if err != nil {
865
+		return err
866
+	}
867
+
868
+	if err := setupInitLayer(initPath); err != nil {
869
+		daemon.driver.Put(initID)
870
+		return err
871
+	}
872
+
873
+	// We want to unmount init layer before we take snapshot of it
874
+	// for the actual container.
875
+	daemon.driver.Put(initID)
876
+
877
+	if err := daemon.driver.Create(container.ID, initID); err != nil {
878
+		return err
879
+	}
880
+	return nil
881
+}
882
+
843 883
 // FIXME: this is a convenience function for integration tests
844 884
 // which need direct access to daemon.graph.
845 885
 // Once the tests switch to using engine and jobs, this method
... ...
@@ -14,7 +14,6 @@ import (
14 14
 	"github.com/Sirupsen/logrus"
15 15
 	"github.com/docker/docker/autogen/dockerversion"
16 16
 	"github.com/docker/docker/daemon/graphdriver"
17
-	"github.com/docker/docker/pkg/archive"
18 17
 	"github.com/docker/docker/pkg/fileutils"
19 18
 	"github.com/docker/docker/pkg/parsers"
20 19
 	"github.com/docker/docker/pkg/parsers/kernel"
... ...
@@ -39,16 +38,6 @@ const (
39 39
 	platformSupported = true
40 40
 )
41 41
 
42
-func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
43
-	initID := fmt.Sprintf("%s-init", container.ID)
44
-	return daemon.driver.Changes(container.ID, initID)
45
-}
46
-
47
-func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
48
-	initID := fmt.Sprintf("%s-init", container.ID)
49
-	return daemon.driver.Diff(container.ID, initID)
50
-}
51
-
52 42
 func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error {
53 43
 	var (
54 44
 		labelOpts []string
... ...
@@ -74,36 +63,6 @@ func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error
74 74
 	return err
75 75
 }
76 76
 
77
-func (daemon *Daemon) createRootfs(container *Container) error {
78
-	// Step 1: create the container directory.
79
-	// This doubles as a barrier to avoid race conditions.
80
-	if err := os.Mkdir(container.root, 0700); err != nil {
81
-		return err
82
-	}
83
-	initID := fmt.Sprintf("%s-init", container.ID)
84
-	if err := daemon.driver.Create(initID, container.ImageID); err != nil {
85
-		return err
86
-	}
87
-	initPath, err := daemon.driver.Get(initID, "")
88
-	if err != nil {
89
-		return err
90
-	}
91
-
92
-	if err := setupInitLayer(initPath); err != nil {
93
-		daemon.driver.Put(initID)
94
-		return err
95
-	}
96
-
97
-	// We want to unmount init layer before we take snapshot of it
98
-	// for the actual container.
99
-	daemon.driver.Put(initID)
100
-
101
-	if err := daemon.driver.Create(container.ID, initID); err != nil {
102
-		return err
103
-	}
104
-	return nil
105
-}
106
-
107 77
 func checkKernel() error {
108 78
 	// Check for unsupported kernel versions
109 79
 	// FIXME: it would be cleaner to not test for specific versions, but rather
... ...
@@ -5,14 +5,11 @@ import (
5 5
 	"os"
6 6
 	"syscall"
7 7
 
8
-	"github.com/Sirupsen/logrus"
9 8
 	"github.com/docker/docker/daemon/graphdriver"
10
-	"github.com/docker/docker/daemon/graphdriver/windows"
11
-	"github.com/docker/docker/pkg/archive"
9
+	_ "github.com/docker/docker/daemon/graphdriver/windows"
12 10
 	"github.com/docker/docker/pkg/parsers"
13 11
 	"github.com/docker/docker/runconfig"
14 12
 	"github.com/docker/libnetwork"
15
-	"github.com/microsoft/hcsshim"
16 13
 )
17 14
 
18 15
 const (
... ...
@@ -20,55 +17,11 @@ const (
20 20
 	platformSupported    = true
21 21
 )
22 22
 
23
-func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
24
-	return daemon.driver.Changes(container.ID, container.ImageID)
25
-}
26
-
27
-func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
28
-	return daemon.driver.Diff(container.ID, container.ImageID)
29
-}
30
-
31 23
 func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error {
32 24
 	return nil
33 25
 }
34 26
 
35
-func (daemon *Daemon) createRootfs(container *Container) error {
36
-	// Step 1: create the container directory.
37
-	// This doubles as a barrier to avoid race conditions.
38
-	if err := os.Mkdir(container.root, 0700); err != nil {
39
-		return err
40
-	}
41
-
42
-	if wd, ok := daemon.driver.(*windows.WindowsGraphDriver); ok {
43
-		if container.ImageID != "" {
44
-			// Get list of paths to parent layers.
45
-			logrus.Debugln("createRootfs: Container has parent image:", container.ImageID)
46
-			img, err := daemon.graph.Get(container.ImageID)
47
-			if err != nil {
48
-				return err
49
-			}
50
-
51
-			ids, err := daemon.graph.ParentLayerIds(img)
52
-			if err != nil {
53
-				return err
54
-			}
55
-			logrus.Debugf("Got image ids: %d", len(ids))
56
-
57
-			if err := hcsshim.CreateSandboxLayer(wd.Info(), container.ID, container.ImageID, wd.LayerIdsToPaths(ids)); err != nil {
58
-				return err
59
-			}
60
-		} else {
61
-			if err := daemon.driver.Create(container.ID, container.ImageID); err != nil {
62
-				return err
63
-			}
64
-		}
65
-	} else {
66
-		// Fall-back code path to allow the use of the VFS driver for development
67
-		if err := daemon.driver.Create(container.ID, container.ImageID); err != nil {
68
-			return err
69
-		}
70
-
71
-	}
27
+func setupInitLayer(initLayer string) error {
72 28
 	return nil
73 29
 }
74 30
 
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"fmt"
5 5
 	"os"
6 6
 	"path"
7
-	"runtime"
8 7
 
9 8
 	"github.com/Sirupsen/logrus"
10 9
 )
... ...
@@ -117,12 +116,9 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
117 117
 		return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
118 118
 	}
119 119
 
120
-	// There will not be an -init on Windows, so don't fail by not attempting to delete it
121
-	if runtime.GOOS != "windows" {
122
-		initID := fmt.Sprintf("%s-init", container.ID)
123
-		if err := daemon.driver.Remove(initID); err != nil {
124
-			return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
125
-		}
120
+	initID := fmt.Sprintf("%s-init", container.ID)
121
+	if err := daemon.driver.Remove(initID); err != nil {
122
+		return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
126 123
 	}
127 124
 
128 125
 	if err = os.RemoveAll(container.root); err != nil {
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"errors"
10 10
 	"fmt"
11 11
 	"os"
12
+	"path/filepath"
12 13
 	"strconv"
13 14
 	"strings"
14 15
 
... ...
@@ -100,8 +101,13 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
100 100
 	}
101 101
 
102 102
 	for i := 0; i < len(c.LayerPaths); i++ {
103
+		_, filename := filepath.Split(c.LayerPaths[i])
104
+		g, err := hcsshim.NameToGuid(filename)
105
+		if err != nil {
106
+			return execdriver.ExitStatus{ExitCode: -1}, err
107
+		}
103 108
 		cu.Layers = append(cu.Layers, layer{
104
-			ID:   hcsshim.NewGUID(c.LayerPaths[i]).ToString(),
109
+			ID:   g.ToString(),
105 110
 			Path: c.LayerPaths[i],
106 111
 		})
107 112
 	}
... ...
@@ -1,19 +1,5 @@
1 1
 package graphdriver
2 2
 
3
-import (
4
-	"github.com/docker/docker/pkg/archive"
5
-	"github.com/microsoft/hcsshim"
6
-)
7
-
8
-type WindowsGraphDriver interface {
9
-	Driver
10
-	CopyDiff(id, sourceId string, parentLayerPaths []string) error
11
-	LayerIdsToPaths(ids []string) []string
12
-	Info() hcsshim.DriverInfo
13
-	Export(id string, parentLayerPaths []string) (archive.Archive, error)
14
-	Import(id string, layerData archive.Reader, parentLayerPaths []string) (int64, error)
15
-}
16
-
17 3
 var (
18 4
 	// Slice of drivers that should be used in order
19 5
 	priority = []string{
20 6
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package graphdriver
1
+
2
+import (
3
+	"github.com/docker/docker/image"
4
+	"github.com/docker/docker/pkg/archive"
5
+)
6
+
7
+// NOTE: These interfaces are used for implementing specific features of the Windows
8
+// graphdriver implementation.  The current versions are a short-term solution and
9
+// likely to change or possibly be eliminated, so avoid using them outside of the Windows
10
+// graphdriver code.
11
+
12
+// ImageRestorer interface allows the implementer to add a custom image to
13
+// the graph and tagstore.
14
+type ImageRestorer interface {
15
+	RestoreCustomImages(tagger Tagger, recorder Recorder) ([]string, error)
16
+}
17
+
18
+// Tagger is an interface that exposes the TagStore.Tag function without needing
19
+// to import graph.
20
+type Tagger interface {
21
+	Tag(repoName, tag, imageName string, force bool) error
22
+}
23
+
24
+// Recorder is an interface that exposes the Graph.Register and Graph.Exists
25
+// functions without needing to import graph.
26
+type Recorder interface {
27
+	Exists(id string) bool
28
+	Register(img *image.Image, layerData archive.Reader) error
29
+}
... ...
@@ -3,17 +3,26 @@
3 3
 package windows
4 4
 
5 5
 import (
6
+	"crypto/sha512"
7
+	"encoding/json"
6 8
 	"fmt"
9
+	"io/ioutil"
7 10
 	"os"
8 11
 	"path/filepath"
12
+	"runtime"
13
+	"strconv"
14
+	"strings"
9 15
 	"sync"
10 16
 	"time"
11 17
 
12 18
 	"github.com/Sirupsen/logrus"
19
+	"github.com/docker/docker/autogen/dockerversion"
13 20
 	"github.com/docker/docker/daemon/graphdriver"
21
+	"github.com/docker/docker/image"
14 22
 	"github.com/docker/docker/pkg/archive"
15 23
 	"github.com/docker/docker/pkg/chrootarchive"
16 24
 	"github.com/docker/docker/pkg/ioutils"
25
+	"github.com/docker/docker/pkg/random"
17 26
 	"github.com/microsoft/hcsshim"
18 27
 )
19 28
 
... ...
@@ -27,7 +36,7 @@ const (
27 27
 	filterDriver
28 28
 )
29 29
 
30
-type WindowsGraphDriver struct {
30
+type Driver struct {
31 31
 	info       hcsshim.DriverInfo
32 32
 	sync.Mutex // Protects concurrent modification to active
33 33
 	active     map[string]int
... ...
@@ -36,7 +45,7 @@ type WindowsGraphDriver struct {
36 36
 // New returns a new Windows storage filter driver.
37 37
 func InitFilter(home string, options []string) (graphdriver.Driver, error) {
38 38
 	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
39
-	d := &WindowsGraphDriver{
39
+	d := &Driver{
40 40
 		info: hcsshim.DriverInfo{
41 41
 			HomeDir: home,
42 42
 			Flavour: filterDriver,
... ...
@@ -49,7 +58,7 @@ func InitFilter(home string, options []string) (graphdriver.Driver, error) {
49 49
 // New returns a new Windows differencing disk driver.
50 50
 func InitDiff(home string, options []string) (graphdriver.Driver, error) {
51 51
 	logrus.Debugf("WindowsGraphDriver InitDiff at %s", home)
52
-	d := &WindowsGraphDriver{
52
+	d := &Driver{
53 53
 		info: hcsshim.DriverInfo{
54 54
 			HomeDir: home,
55 55
 			Flavour: diffDriver,
... ...
@@ -59,11 +68,7 @@ func InitDiff(home string, options []string) (graphdriver.Driver, error) {
59 59
 	return d, nil
60 60
 }
61 61
 
62
-func (d *WindowsGraphDriver) Info() hcsshim.DriverInfo {
63
-	return d.info
64
-}
65
-
66
-func (d *WindowsGraphDriver) String() string {
62
+func (d *Driver) String() string {
67 63
 	switch d.info.Flavour {
68 64
 	case diffDriver:
69 65
 		return "windowsdiff"
... ...
@@ -74,7 +79,7 @@ func (d *WindowsGraphDriver) String() string {
74 74
 	}
75 75
 }
76 76
 
77
-func (d *WindowsGraphDriver) Status() [][2]string {
77
+func (d *Driver) Status() [][2]string {
78 78
 	return [][2]string{
79 79
 		{"Windows", ""},
80 80
 	}
... ...
@@ -82,45 +87,137 @@ func (d *WindowsGraphDriver) Status() [][2]string {
82 82
 
83 83
 // Exists returns true if the given id is registered with
84 84
 // this driver
85
-func (d *WindowsGraphDriver) Exists(id string) bool {
86
-	result, err := hcsshim.LayerExists(d.info, id)
85
+func (d *Driver) Exists(id string) bool {
86
+	rId, err := d.resolveId(id)
87
+	if err != nil {
88
+		return false
89
+	}
90
+	result, err := hcsshim.LayerExists(d.info, rId)
87 91
 	if err != nil {
88 92
 		return false
89 93
 	}
90 94
 	return result
91 95
 }
92 96
 
93
-func (d *WindowsGraphDriver) Create(id, parent string) error {
94
-	return hcsshim.CreateLayer(d.info, id, parent)
97
+func (d *Driver) Create(id, parent string) error {
98
+	rPId, err := d.resolveId(parent)
99
+	if err != nil {
100
+		return err
101
+	}
102
+
103
+	parentChain, err := d.getLayerChain(rPId)
104
+	if err != nil {
105
+		return err
106
+	}
107
+
108
+	var layerChain []string
109
+
110
+	parentIsInit := strings.HasSuffix(rPId, "-init")
111
+
112
+	if !parentIsInit && rPId != "" {
113
+		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
114
+		if err != nil {
115
+			return err
116
+		}
117
+		layerChain = []string{parentPath}
118
+	}
119
+
120
+	layerChain = append(layerChain, parentChain...)
121
+
122
+	if parentIsInit {
123
+		if len(layerChain) == 0 {
124
+			return fmt.Errorf("Cannot create a read/write layer without a parent layer.")
125
+		}
126
+		if err := hcsshim.CreateSandboxLayer(d.info, id, layerChain[0], layerChain); err != nil {
127
+			return err
128
+		}
129
+	} else {
130
+		if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
131
+			return err
132
+		}
133
+	}
134
+
135
+	if _, err := os.Lstat(d.dir(parent)); err == nil {
136
+		if err := d.setLayerChain(id, layerChain); err != nil {
137
+			if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
138
+				logrus.Warnf("Failed to DestroyLayer %s: %s", id, err)
139
+			}
140
+			return err
141
+		}
142
+	} else if os.IsNotExist(err) {
143
+		// If the parent doesn't exist, this must be a special creation for an image
144
+		// registered at an alternate location. Use the parent id as the alternate ID.
145
+		if err := d.setId(id, parent); err != nil {
146
+			if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
147
+				logrus.Warnf("Failed to DestroyLayer %s: %s", id, err)
148
+			}
149
+			return err
150
+		}
151
+	} else {
152
+		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
153
+			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err)
154
+		}
155
+		return err
156
+	}
157
+
158
+	return nil
95 159
 }
96 160
 
97
-func (d *WindowsGraphDriver) dir(id string) string {
161
+func (d *Driver) dir(id string) string {
98 162
 	return filepath.Join(d.info.HomeDir, filepath.Base(id))
99 163
 }
100 164
 
101 165
 // Remove unmounts and removes the dir information
102
-func (d *WindowsGraphDriver) Remove(id string) error {
103
-	return hcsshim.DestroyLayer(d.info, id)
166
+func (d *Driver) Remove(id string) error {
167
+	rId, err := d.resolveId(id)
168
+	if err != nil {
169
+		return err
170
+	}
171
+
172
+	return hcsshim.DestroyLayer(d.info, rId)
104 173
 }
105 174
 
106 175
 // Get returns the rootfs path for the id. This will mount the dir at it's given path
107
-func (d *WindowsGraphDriver) Get(id, mountLabel string) (string, error) {
176
+func (d *Driver) Get(id, mountLabel string) (string, error) {
177
+	logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
108 178
 	var dir string
109 179
 
110 180
 	d.Lock()
111 181
 	defer d.Unlock()
112 182
 
113
-	if d.active[id] == 0 {
114
-		if err := hcsshim.ActivateLayer(d.info, id); err != nil {
183
+	rId, err := d.resolveId(id)
184
+	if err != nil {
185
+		return "", err
186
+	}
187
+
188
+	// Getting the layer paths must be done outside of the lock.
189
+	layerChain, err := d.getLayerChain(rId)
190
+	if err != nil {
191
+		return "", err
192
+	}
193
+
194
+	if d.active[rId] == 0 {
195
+		if err := hcsshim.ActivateLayer(d.info, rId); err != nil {
196
+			return "", err
197
+		}
198
+		if err := hcsshim.PrepareLayer(d.info, rId, layerChain); err != nil {
199
+			if err2 := hcsshim.DeactivateLayer(d.info, rId); err2 != nil {
200
+				logrus.Warnf("Failed to Deactivate %s: %s", id, err)
201
+			}
115 202
 			return "", err
116 203
 		}
117 204
 	}
118 205
 
119
-	mountPath, err := hcsshim.GetLayerMountPath(d.info, id)
206
+	mountPath, err := hcsshim.GetLayerMountPath(d.info, rId)
120 207
 	if err != nil {
208
+		if err2 := hcsshim.DeactivateLayer(d.info, rId); err2 != nil {
209
+			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
210
+		}
121 211
 		return "", err
122 212
 	}
123 213
 
214
+	d.active[rId]++
215
+
124 216
 	// If the layer has a mount path, use that. Otherwise, use the
125 217
 	// folder path.
126 218
 	if mountPath != "" {
... ...
@@ -129,61 +226,131 @@ func (d *WindowsGraphDriver) Get(id, mountLabel string) (string, error) {
129 129
 		dir = d.dir(id)
130 130
 	}
131 131
 
132
-	d.active[id]++
133
-
134 132
 	return dir, nil
135 133
 }
136 134
 
137
-func (d *WindowsGraphDriver) Put(id string) error {
135
+func (d *Driver) Put(id string) error {
138 136
 	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
139 137
 
138
+	rId, err := d.resolveId(id)
139
+	if err != nil {
140
+		return err
141
+	}
142
+
140 143
 	d.Lock()
141 144
 	defer d.Unlock()
142 145
 
143
-	if d.active[id] > 1 {
144
-		d.active[id]--
145
-	} else if d.active[id] == 1 {
146
-		if err := hcsshim.DeactivateLayer(d.info, id); err != nil {
146
+	if d.active[rId] > 1 {
147
+		d.active[rId]--
148
+	} else if d.active[rId] == 1 {
149
+		if err := hcsshim.UnprepareLayer(d.info, rId); err != nil {
147 150
 			return err
148 151
 		}
149
-		delete(d.active, id)
152
+		if err := hcsshim.DeactivateLayer(d.info, rId); err != nil {
153
+			return err
154
+		}
155
+		delete(d.active, rId)
150 156
 	}
151 157
 
152 158
 	return nil
153 159
 }
154 160
 
155
-func (d *WindowsGraphDriver) Cleanup() error {
161
+func (d *Driver) Cleanup() error {
156 162
 	return nil
157 163
 }
158 164
 
159 165
 // Diff produces an archive of the changes between the specified
160 166
 // layer and its parent layer which may be "".
161
-func (d *WindowsGraphDriver) Diff(id, parent string) (arch archive.Archive, err error) {
162
-	return nil, fmt.Errorf("The Windows graphdriver does not support Diff()")
167
+func (d *Driver) Diff(id, parent string) (arch archive.Archive, err error) {
168
+	rId, err := d.resolveId(id)
169
+	if err != nil {
170
+		return
171
+	}
172
+
173
+	// Getting the layer paths must be done outside of the lock.
174
+	layerChain, err := d.getLayerChain(rId)
175
+	if err != nil {
176
+		return
177
+	}
178
+
179
+	d.Lock()
180
+
181
+	// To support export, a layer must be activated but not prepared.
182
+	if d.info.Flavour == filterDriver {
183
+		if d.active[rId] == 0 {
184
+			if err = hcsshim.ActivateLayer(d.info, rId); err != nil {
185
+				d.Unlock()
186
+				return
187
+			}
188
+			defer func() {
189
+				if err := hcsshim.DeactivateLayer(d.info, rId); err != nil {
190
+					logrus.Warnf("Failed to Deactivate %s: %s", rId, err)
191
+				}
192
+			}()
193
+		} else {
194
+			if err = hcsshim.UnprepareLayer(d.info, rId); err != nil {
195
+				d.Unlock()
196
+				return
197
+			}
198
+			defer func() {
199
+				if err := hcsshim.PrepareLayer(d.info, rId, layerChain); err != nil {
200
+					logrus.Warnf("Failed to re-PrepareLayer %s: %s", rId, err)
201
+				}
202
+			}()
203
+		}
204
+	}
205
+
206
+	d.Unlock()
207
+
208
+	return d.exportLayer(rId, layerChain)
163 209
 }
164 210
 
165 211
 // Changes produces a list of changes between the specified layer
166 212
 // and its parent layer. If parent is "", then all changes will be ADD changes.
167
-func (d *WindowsGraphDriver) Changes(id, parent string) ([]archive.Change, error) {
213
+func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
168 214
 	return nil, fmt.Errorf("The Windows graphdriver does not support Changes()")
169 215
 }
170 216
 
171 217
 // ApplyDiff extracts the changeset from the given diff into the
172 218
 // layer with the specified id and parent, returning the size of the
173 219
 // new layer in bytes.
174
-func (d *WindowsGraphDriver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) {
175
-	start := time.Now().UTC()
176
-	logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
220
+func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) {
221
+	rPId, err := d.resolveId(parent)
222
+	if err != nil {
223
+		return
224
+	}
177 225
 
178
-	destination := d.dir(id)
179 226
 	if d.info.Flavour == diffDriver {
227
+		start := time.Now().UTC()
228
+		logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
229
+		destination := d.dir(id)
180 230
 		destination = filepath.Dir(destination)
231
+		if size, err = chrootarchive.ApplyUncompressedLayer(destination, diff); err != nil {
232
+			return
233
+		}
234
+		logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
235
+
236
+		return
181 237
 	}
182 238
 
183
-	if size, err = chrootarchive.ApplyLayer(destination, diff); err != nil {
239
+	parentChain, err := d.getLayerChain(rPId)
240
+	if err != nil {
241
+		return
242
+	}
243
+	parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
244
+	if err != nil {
245
+		return
246
+	}
247
+	layerChain := []string{parentPath}
248
+	layerChain = append(layerChain, parentChain...)
249
+
250
+	if size, err = d.importLayer(id, diff, layerChain); err != nil {
251
+		return
252
+	}
253
+
254
+	if err = d.setLayerChain(id, layerChain); err != nil {
184 255
 		return
185 256
 	}
186
-	logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
187 257
 
188 258
 	return
189 259
 }
... ...
@@ -191,8 +358,13 @@ func (d *WindowsGraphDriver) ApplyDiff(id, parent string, diff archive.Reader) (
191 191
 // DiffSize calculates the changes between the specified layer
192 192
 // and its parent and returns the size in bytes of the changes
193 193
 // relative to its base filesystem directory.
194
-func (d *WindowsGraphDriver) DiffSize(id, parent string) (size int64, err error) {
195
-	changes, err := d.Changes(id, parent)
194
+func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
195
+	rPId, err := d.resolveId(parent)
196
+	if err != nil {
197
+		return
198
+	}
199
+
200
+	changes, err := d.Changes(id, rPId)
196 201
 	if err != nil {
197 202
 		return
198 203
 	}
... ...
@@ -206,65 +378,88 @@ func (d *WindowsGraphDriver) DiffSize(id, parent string) (size int64, err error)
206 206
 	return archive.ChangesSize(layerFs, changes), nil
207 207
 }
208 208
 
209
-func (d *WindowsGraphDriver) CopyDiff(sourceId, id string, parentLayerPaths []string) error {
210
-	d.Lock()
211
-	defer d.Unlock()
209
+func (d *Driver) RestoreCustomImages(tagger graphdriver.Tagger, recorder graphdriver.Recorder) (imageIDs []string, err error) {
210
+	strData, err := hcsshim.GetSharedBaseImages()
211
+	if err != nil {
212
+		return nil, fmt.Errorf("Failed to restore base images: %s", err)
213
+	}
212 214
 
213
-	if d.info.Flavour == filterDriver && d.active[sourceId] == 0 {
214
-		if err := hcsshim.ActivateLayer(d.info, sourceId); err != nil {
215
-			return err
216
-		}
217
-		defer func() {
218
-			err := hcsshim.DeactivateLayer(d.info, sourceId)
219
-			if err != nil {
220
-				logrus.Warnf("Failed to Deactivate %s: %s", sourceId, err)
221
-			}
222
-		}()
215
+	type customImageInfo struct {
216
+		Name        string
217
+		Version     string
218
+		Path        string
219
+		Size        int64
220
+		CreatedTime time.Time
221
+	}
222
+	type customImageInfoList struct {
223
+		Images []customImageInfo
223 224
 	}
224 225
 
225
-	return hcsshim.CopyLayer(d.info, sourceId, id, parentLayerPaths)
226
-}
226
+	var infoData customImageInfoList
227 227
 
228
-func (d *WindowsGraphDriver) LayerIdsToPaths(ids []string) []string {
229
-	var paths []string
230
-	for _, id := range ids {
231
-		path, err := d.Get(id, "")
232
-		if err != nil {
233
-			logrus.Debug("LayerIdsToPaths: Error getting mount path for id", id, ":", err.Error())
234
-			return nil
235
-		}
236
-		if d.Put(id) != nil {
237
-			logrus.Debug("LayerIdsToPaths: Error putting mount path for id", id, ":", err.Error())
238
-			return nil
228
+	if err = json.Unmarshal([]byte(strData), &infoData); err != nil {
229
+		err = fmt.Errorf("JSON unmarshal returned error=%s", err)
230
+		logrus.Error(err)
231
+		return nil, err
232
+	}
233
+
234
+	for _, imageData := range infoData.Images {
235
+		_, folderName := filepath.Split(imageData.Path)
236
+
237
+		// Use crypto hash of the foldername to generate a docker style id.
238
+		h := sha512.Sum384([]byte(folderName))
239
+		id := fmt.Sprintf("%x", h[:32])
240
+
241
+		if !recorder.Exists(id) {
242
+			// Register the image.
243
+			img := &image.Image{
244
+				ID:            id,
245
+				Created:       imageData.CreatedTime,
246
+				DockerVersion: dockerversion.VERSION,
247
+				Architecture:  runtime.GOARCH,
248
+				OS:            runtime.GOOS,
249
+				Size:          imageData.Size,
250
+			}
251
+
252
+			if err := recorder.Register(img, nil); err != nil {
253
+				return nil, err
254
+			}
255
+
256
+			// Create tags for the new image.
257
+			if err := tagger.Tag(strings.ToLower(imageData.Name), imageData.Version, img.ID, true); err != nil {
258
+				return nil, err
259
+			}
260
+
261
+			// Create the alternate ID file.
262
+			if err := d.setId(img.ID, folderName); err != nil {
263
+				return nil, err
264
+			}
265
+
266
+			imageIDs = append(imageIDs, img.ID)
239 267
 		}
240
-		paths = append(paths, path)
241 268
 	}
242
-	return paths
269
+
270
+	return imageIDs, nil
243 271
 }
244 272
 
245
-func (d *WindowsGraphDriver) GetMetadata(id string) (map[string]string, error) {
246
-	return nil, nil
273
+func (d *Driver) GetMetadata(id string) (map[string]string, error) {
274
+	m := make(map[string]string)
275
+	m["dir"] = d.dir(id)
276
+	return m, nil
247 277
 }
248 278
 
249
-func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch archive.Archive, err error) {
250
-	layerFs, err := d.Get(id, "")
251
-	if err != nil {
252
-		return
253
-	}
254
-	defer func() {
255
-		if err != nil {
256
-			d.Put(id)
257
-		}
258
-	}()
279
+func (d *Driver) exportLayer(id string, parentLayerPaths []string) (arch archive.Archive, err error) {
280
+	layerFolder := d.dir(id)
259 281
 
260
-	tempFolder := layerFs + "-temp"
282
+	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
261 283
 	if err = os.MkdirAll(tempFolder, 0755); err != nil {
262 284
 		logrus.Errorf("Could not create %s %s", tempFolder, err)
263 285
 		return
264 286
 	}
265 287
 	defer func() {
266 288
 		if err != nil {
267
-			if err2 := os.RemoveAll(tempFolder); err2 != nil {
289
+			_, folderName := filepath.Split(tempFolder)
290
+			if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
268 291
 				logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
269 292
 			}
270 293
 		}
... ...
@@ -281,7 +476,8 @@ func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch
281 281
 	return ioutils.NewReadCloserWrapper(archive, func() error {
282 282
 		err := archive.Close()
283 283
 		d.Put(id)
284
-		if err2 := os.RemoveAll(tempFolder); err2 != nil {
284
+		_, folderName := filepath.Split(tempFolder)
285
+		if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
285 286
 			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
286 287
 		}
287 288
 		return err
... ...
@@ -289,24 +485,17 @@ func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch
289 289
 
290 290
 }
291 291
 
292
-func (d *WindowsGraphDriver) Import(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
293
-	layerFs, err := d.Get(id, "")
294
-	if err != nil {
295
-		return
296
-	}
297
-	defer func() {
298
-		if err != nil {
299
-			d.Put(id)
300
-		}
301
-	}()
292
+func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
293
+	layerFolder := d.dir(id)
302 294
 
303
-	tempFolder := layerFs + "-temp"
295
+	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
304 296
 	if err = os.MkdirAll(tempFolder, 0755); err != nil {
305 297
 		logrus.Errorf("Could not create %s %s", tempFolder, err)
306 298
 		return
307 299
 	}
308 300
 	defer func() {
309
-		if err2 := os.RemoveAll(tempFolder); err2 != nil {
301
+		_, folderName := filepath.Split(tempFolder)
302
+		if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
310 303
 			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
311 304
 		}
312 305
 	}()
... ...
@@ -324,3 +513,54 @@ func (d *WindowsGraphDriver) Import(id string, layerData archive.Reader, parentL
324 324
 
325 325
 	return
326 326
 }
327
+
328
+func (d *Driver) resolveId(id string) (string, error) {
329
+	content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerId"))
330
+	if os.IsNotExist(err) {
331
+		return id, nil
332
+	} else if err != nil {
333
+		return "", err
334
+	}
335
+	return string(content), nil
336
+}
337
+
338
+func (d *Driver) setId(id, altId string) error {
339
+	err := ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altId), 0600)
340
+	if err != nil {
341
+		return err
342
+	}
343
+	return nil
344
+}
345
+
346
+func (d *Driver) getLayerChain(id string) ([]string, error) {
347
+	jPath := filepath.Join(d.dir(id), "layerchain.json")
348
+	content, err := ioutil.ReadFile(jPath)
349
+	if os.IsNotExist(err) {
350
+		return nil, nil
351
+	} else if err != nil {
352
+		return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
353
+	}
354
+
355
+	var layerChain []string
356
+	err = json.Unmarshal(content, &layerChain)
357
+	if err != nil {
358
+		return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
359
+	}
360
+
361
+	return layerChain, nil
362
+}
363
+
364
+func (d *Driver) setLayerChain(id string, chain []string) error {
365
+	content, err := json.Marshal(&chain)
366
+	if err != nil {
367
+		return fmt.Errorf("Failed to marshall layerchain json - %s", err)
368
+	}
369
+
370
+	jPath := filepath.Join(d.dir(id), "layerchain.json")
371
+	err = ioutil.WriteFile(jPath, content, 0600)
372
+	if err != nil {
373
+		return fmt.Errorf("Unable to write layerchain file - %s", err)
374
+	}
375
+
376
+	return nil
377
+}
... ...
@@ -77,11 +77,12 @@ func (r *retainedLayers) Exists(layerID string) bool {
77 77
 
78 78
 // A Graph is a store for versioned filesystem images and the relationship between them.
79 79
 type Graph struct {
80
-	root       string
81
-	idIndex    *truncindex.TruncIndex
82
-	driver     graphdriver.Driver
83
-	imageMutex imageMutex // protect images in driver.
84
-	retained   *retainedLayers
80
+	root             string
81
+	idIndex          *truncindex.TruncIndex
82
+	driver           graphdriver.Driver
83
+	imageMutex       imageMutex // protect images in driver.
84
+	retained         *retainedLayers
85
+	tarSplitDisabled bool
85 86
 }
86 87
 
87 88
 // file names for ./graph/<ID>/
... ...
@@ -117,6 +118,12 @@ func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
117 117
 		driver:   driver,
118 118
 		retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
119 119
 	}
120
+
121
+	// Windows does not currently support tarsplit functionality.
122
+	if runtime.GOOS == "windows" {
123
+		graph.tarSplitDisabled = true
124
+	}
125
+
120 126
 	if err := graph.restore(); err != nil {
121 127
 		return nil, err
122 128
 	}
... ...
@@ -141,12 +148,6 @@ func (graph *Graph) restore() error {
141 141
 		}
142 142
 	}
143 143
 
144
-	baseIds, err := graph.restoreBaseImages()
145
-	if err != nil {
146
-		return err
147
-	}
148
-	ids = append(ids, baseIds...)
149
-
150 144
 	graph.idIndex = truncindex.NewTruncIndex(ids)
151 145
 	logrus.Debugf("Restored %d elements", len(ids))
152 146
 	return nil
... ...
@@ -285,6 +286,13 @@ func (graph *Graph) Register(img *image.Image, layerData archive.Reader) (err er
285 285
 	return nil
286 286
 }
287 287
 
288
+func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.Reader) error {
289
+	if err := graph.driver.Create(img.ID, img.Parent); err != nil {
290
+		return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
291
+	}
292
+	return nil
293
+}
294
+
288 295
 // TempLayerArchive creates a temporary archive of the given image's filesystem layer.
289 296
 //   The archive is stored on disk and will be automatically deleted as soon as has been read.
290 297
 //   If output is not nil, a human-readable progress bar will be written to it.
... ...
@@ -442,6 +450,16 @@ func (graph *Graph) Heads() map[string]*image.Image {
442 442
 	return heads
443 443
 }
444 444
 
445
+// TarLayer returns a tar archive of the image's filesystem layer.
446
+func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
447
+	rdr, err := graph.assembleTarLayer(img)
448
+	if err != nil {
449
+		logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
450
+		return graph.driver.Diff(img.ID, img.Parent)
451
+	}
452
+	return rdr, nil
453
+}
454
+
445 455
 func (graph *Graph) imageRoot(id string) string {
446 456
 	return filepath.Join(graph.root, id)
447 457
 }
... ...
@@ -535,30 +553,64 @@ func jsonPath(root string) string {
535 535
 	return filepath.Join(root, jsonFileName)
536 536
 }
537 537
 
538
-func (graph *Graph) disassembleAndApplyTarLayer(img *image.Image, layerData archive.Reader, root string) error {
539
-	// this is saving the tar-split metadata
540
-	mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
541
-	if err != nil {
542
-		return err
538
+// storeImage stores file system layer data for the given image to the
539
+// graph's storage driver. Image metadata is stored in a file
540
+// at the specified root directory.
541
+func (graph *Graph) storeImage(img *image.Image, layerData archive.Reader, root string) (err error) {
542
+	// Store the layer. If layerData is not nil, unpack it into the new layer
543
+	if layerData != nil {
544
+		if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
545
+			return err
546
+		}
543 547
 	}
544
-	mfz := gzip.NewWriter(mf)
545
-	metaPacker := storage.NewJSONPacker(mfz)
546
-	defer mf.Close()
547
-	defer mfz.Close()
548 548
 
549
-	inflatedLayerData, err := archive.DecompressStream(layerData)
550
-	if err != nil {
549
+	if err := graph.saveSize(root, img.Size); err != nil {
551 550
 		return err
552 551
 	}
553 552
 
554
-	// we're passing nil here for the file putter, because the ApplyDiff will
555
-	// handle the extraction of the archive
556
-	rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
553
+	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
557 554
 	if err != nil {
558 555
 		return err
559 556
 	}
560 557
 
561
-	if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, archive.Reader(rdr)); err != nil {
558
+	defer f.Close()
559
+
560
+	return json.NewEncoder(f).Encode(img)
561
+}
562
+
563
+func (graph *Graph) disassembleAndApplyTarLayer(img *image.Image, layerData archive.Reader, root string) (err error) {
564
+	var ar archive.Reader
565
+
566
+	if graph.tarSplitDisabled {
567
+		ar = layerData
568
+	} else {
569
+		// this is saving the tar-split metadata
570
+		mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
571
+		if err != nil {
572
+			return err
573
+		}
574
+
575
+		mfz := gzip.NewWriter(mf)
576
+		metaPacker := storage.NewJSONPacker(mfz)
577
+		defer mf.Close()
578
+		defer mfz.Close()
579
+
580
+		inflatedLayerData, err := archive.DecompressStream(layerData)
581
+		if err != nil {
582
+			return err
583
+		}
584
+
585
+		// we're passing nil here for the file putter, because the ApplyDiff will
586
+		// handle the extraction of the archive
587
+		rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
588
+		if err != nil {
589
+			return err
590
+		}
591
+
592
+		ar = archive.Reader(rdr)
593
+	}
594
+
595
+	if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, ar); err != nil {
562 596
 		return err
563 597
 	}
564 598
 
565 599
deleted file mode 100644
... ...
@@ -1,120 +0,0 @@
1
-// +build !windows
2
-
3
-package graph
4
-
5
-import (
6
-	"encoding/json"
7
-	"fmt"
8
-	"os"
9
-	"path/filepath"
10
-	"strings"
11
-	"syscall"
12
-
13
-	"github.com/Sirupsen/logrus"
14
-	"github.com/docker/docker/image"
15
-	"github.com/docker/docker/pkg/archive"
16
-	"github.com/docker/docker/pkg/system"
17
-)
18
-
19
-// SetupInitLayer populates a directory with mountpoints suitable
20
-// for bind-mounting dockerinit into the container. The mountpoint is simply an
21
-// empty file at /.dockerinit
22
-// This extra layer is used by all containers as the top-most ro layer. It protects
23
-// the container from unwanted side-effects on the rw layer.
24
-func SetupInitLayer(initLayer string) error {
25
-	for pth, typ := range map[string]string{
26
-		"/dev/pts":         "dir",
27
-		"/dev/shm":         "dir",
28
-		"/proc":            "dir",
29
-		"/sys":             "dir",
30
-		"/.dockerinit":     "file",
31
-		"/.dockerenv":      "file",
32
-		"/etc/resolv.conf": "file",
33
-		"/etc/hosts":       "file",
34
-		"/etc/hostname":    "file",
35
-		"/dev/console":     "file",
36
-		"/etc/mtab":        "/proc/mounts",
37
-	} {
38
-		parts := strings.Split(pth, "/")
39
-		prev := "/"
40
-		for _, p := range parts[1:] {
41
-			prev = filepath.Join(prev, p)
42
-			syscall.Unlink(filepath.Join(initLayer, prev))
43
-		}
44
-
45
-		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
46
-			if os.IsNotExist(err) {
47
-				if err := system.MkdirAll(filepath.Join(initLayer, filepath.Dir(pth)), 0755); err != nil {
48
-					return err
49
-				}
50
-				switch typ {
51
-				case "dir":
52
-					if err := system.MkdirAll(filepath.Join(initLayer, pth), 0755); err != nil {
53
-						return err
54
-					}
55
-				case "file":
56
-					f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
57
-					if err != nil {
58
-						return err
59
-					}
60
-					f.Close()
61
-				default:
62
-					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
63
-						return err
64
-					}
65
-				}
66
-			} else {
67
-				return err
68
-			}
69
-		}
70
-	}
71
-
72
-	// Layer is ready to use, if it wasn't before.
73
-	return nil
74
-}
75
-
76
-func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.Reader) error {
77
-	if err := graph.driver.Create(img.ID, img.Parent); err != nil {
78
-		return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
79
-	}
80
-	return nil
81
-}
82
-
83
-func (graph *Graph) restoreBaseImages() ([]string, error) {
84
-	return nil, nil
85
-}
86
-
87
-// storeImage stores file system layer data for the given image to the
88
-// graph's storage driver. Image metadata is stored in a file
89
-// at the specified root directory.
90
-func (graph *Graph) storeImage(img *image.Image, layerData archive.Reader, root string) (err error) {
91
-	// Store the layer. If layerData is not nil, unpack it into the new layer
92
-	if layerData != nil {
93
-		if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
94
-			return err
95
-		}
96
-	}
97
-
98
-	if err := graph.saveSize(root, img.Size); err != nil {
99
-		return err
100
-	}
101
-
102
-	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
103
-	if err != nil {
104
-		return err
105
-	}
106
-
107
-	defer f.Close()
108
-
109
-	return json.NewEncoder(f).Encode(img)
110
-}
111
-
112
-// TarLayer returns a tar archive of the image's filesystem layer.
113
-func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
114
-	rdr, err := graph.assembleTarLayer(img)
115
-	if err != nil {
116
-		logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
117
-		return graph.driver.Diff(img.ID, img.Parent)
118
-	}
119
-	return rdr, nil
120
-}
121 1
deleted file mode 100644
... ...
@@ -1,164 +0,0 @@
1
-// +build windows
2
-
3
-package graph
4
-
5
-import (
6
-	"encoding/json"
7
-	"fmt"
8
-	"os"
9
-
10
-	"github.com/Sirupsen/logrus"
11
-	"github.com/docker/docker/daemon/graphdriver/windows"
12
-	"github.com/docker/docker/image"
13
-	"github.com/docker/docker/pkg/archive"
14
-)
15
-
16
-// SetupInitLayer populates a directory with mountpoints suitable
17
-// for bind-mounting dockerinit into the container. T
18
-func SetupInitLayer(initLayer string) error {
19
-	return nil
20
-}
21
-
22
-func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.Reader) error {
23
-	if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
24
-		if img.Container != "" && layerData == nil {
25
-			logrus.Debugf("Copying from container %s.", img.Container)
26
-
27
-			var ids []string
28
-			if img.Parent != "" {
29
-				parentImg, err := graph.Get(img.Parent)
30
-				if err != nil {
31
-					return err
32
-				}
33
-
34
-				ids, err = graph.ParentLayerIds(parentImg)
35
-				if err != nil {
36
-					return err
37
-				}
38
-			}
39
-
40
-			if err := wd.CopyDiff(img.Container, img.ID, wd.LayerIdsToPaths(ids)); err != nil {
41
-				return fmt.Errorf("Driver %s failed to copy image rootfs %s: %s", graph.driver, img.Container, err)
42
-			}
43
-		} else if img.Parent == "" {
44
-			if err := graph.driver.Create(img.ID, img.Parent); err != nil {
45
-				return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
46
-			}
47
-		}
48
-	} else {
49
-		// This fallback allows the use of VFS during daemon development.
50
-		if err := graph.driver.Create(img.ID, img.Parent); err != nil {
51
-			return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
52
-		}
53
-	}
54
-	return nil
55
-}
56
-
57
-func (graph *Graph) restoreBaseImages() ([]string, error) {
58
-	// TODO Windows. This needs implementing (@swernli)
59
-	return nil, nil
60
-}
61
-
62
-// ParentLayerIds returns a list of all parent image IDs for the given image.
63
-func (graph *Graph) ParentLayerIds(img *image.Image) (ids []string, err error) {
64
-	for i := img; i != nil && err == nil; i, err = graph.GetParent(i) {
65
-		ids = append(ids, i.ID)
66
-	}
67
-
68
-	return
69
-}
70
-
71
-// storeImage stores file system layer data for the given image to the
72
-// graph's storage driver. Image metadata is stored in a file
73
-// at the specified root directory.
74
-func (graph *Graph) storeImage(img *image.Image, layerData archive.Reader, root string) (err error) {
75
-
76
-	if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
77
-		// Store the layer. If layerData is not nil and this isn't a base image,
78
-		// unpack it into the new layer
79
-		if layerData != nil && img.Parent != "" {
80
-			var ids []string
81
-			if img.Parent != "" {
82
-				parentImg, err := graph.Get(img.Parent)
83
-				if err != nil {
84
-					return err
85
-				}
86
-
87
-				ids, err = graph.ParentLayerIds(parentImg)
88
-				if err != nil {
89
-					return err
90
-				}
91
-			}
92
-
93
-			if img.Size, err = wd.Import(img.ID, layerData, wd.LayerIdsToPaths(ids)); err != nil {
94
-				return err
95
-			}
96
-		}
97
-
98
-		if err := graph.saveSize(root, img.Size); err != nil {
99
-			return err
100
-		}
101
-
102
-		f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
103
-		if err != nil {
104
-			return err
105
-		}
106
-
107
-		defer f.Close()
108
-
109
-		return json.NewEncoder(f).Encode(img)
110
-	}
111
-	// We keep this functionality here so that we can still work with the
112
-	// VFS driver during development. This will not be used for actual running
113
-	// of Windows containers. Without this code, it would not be possible to
114
-	// docker pull using the VFS driver.
115
-
116
-	// Store the layer. If layerData is not nil, unpack it into the new layer
117
-	if layerData != nil {
118
-		if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
119
-			return err
120
-		}
121
-	}
122
-
123
-	if err := graph.saveSize(root, img.Size); err != nil {
124
-		return err
125
-	}
126
-
127
-	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
128
-	if err != nil {
129
-		return err
130
-	}
131
-
132
-	defer f.Close()
133
-
134
-	return json.NewEncoder(f).Encode(img)
135
-}
136
-
137
-// TarLayer returns a tar archive of the image's filesystem layer.
138
-func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
139
-	if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
140
-		var ids []string
141
-		if img.Parent != "" {
142
-			parentImg, err := graph.Get(img.Parent)
143
-			if err != nil {
144
-				return nil, err
145
-			}
146
-
147
-			ids, err = graph.ParentLayerIds(parentImg)
148
-			if err != nil {
149
-				return nil, err
150
-			}
151
-		}
152
-
153
-		return wd.Export(img.ID, wd.LayerIdsToPaths(ids))
154
-	}
155
-	// We keep this functionality here so that we can still work with the VFS
156
-	// driver during development. VFS is not supported (and just will not work)
157
-	// for Windows containers.
158
-	rdr, err := graph.assembleTarLayer(img)
159
-	if err != nil {
160
-		logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
161
-		return graph.driver.Diff(img.ID, img.Parent)
162
-	}
163
-	return rdr, nil
164
-}
... ...
@@ -55,8 +55,8 @@ else
55 55
 	export DOCKER_HOST="$DOCKER_TEST_HOST"
56 56
 fi
57 57
 
58
-# give it a second to come up so it's "ready"
59
-tries=10
58
+# give it a little time to come up so it's "ready"
59
+tries=30
60 60
 while ! docker version &> /dev/null; do
61 61
 	(( tries-- ))
62 62
 	if [ $tries -le 0 ]; then