Browse code

LCOW: OCI Spec and Environment for container start

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2017/05/27 08:14:18
Showing 16 changed files
... ...
@@ -203,7 +203,7 @@ func TestFromScratch(t *testing.T) {
203 203
 	assert.True(t, req.state.hasFromImage())
204 204
 	assert.Equal(t, "", req.state.imageID)
205 205
 	// Windows does not set the default path. TODO @jhowardmsft LCOW support. This will need revisiting as we get further into the implementation
206
-	expected := "PATH=" + system.DefaultPathEnv
206
+	expected := "PATH=" + system.DefaultPathEnv(runtime.GOOS)
207 207
 	if runtime.GOOS == "windows" {
208 208
 		expected = ""
209 209
 	}
... ...
@@ -22,6 +22,7 @@ package dockerfile
22 22
 import (
23 23
 	"bytes"
24 24
 	"fmt"
25
+	"runtime"
25 26
 	"strings"
26 27
 
27 28
 	"github.com/docker/docker/api/types/container"
... ...
@@ -228,14 +229,19 @@ func (s *dispatchState) beginStage(stageName string, image builder.Image) {
228 228
 }
229 229
 
230 230
 // Add the default PATH to runConfig.ENV if one exists for the platform and there
231
-// is no PATH set. Note that windows won't have one as it's set by HCS
231
+// is no PATH set. Note that Windows containers on Windows won't have one as it's set by HCS
232 232
 func (s *dispatchState) setDefaultPath() {
233
-	if system.DefaultPathEnv == "" {
233
+	// TODO @jhowardmsft LCOW Support - This will need revisiting later
234
+	platform := runtime.GOOS
235
+	if platform == "windows" && system.LCOWSupported() {
236
+		platform = "linux"
237
+	}
238
+	if system.DefaultPathEnv(platform) == "" {
234 239
 		return
235 240
 	}
236 241
 	envMap := opts.ConvertKVStringsToMap(s.runConfig.Env)
237 242
 	if _, ok := envMap["PATH"]; !ok {
238
-		s.runConfig.Env = append(s.runConfig.Env, "PATH="+system.DefaultPathEnv)
243
+		s.runConfig.Env = append(s.runConfig.Env, "PATH="+system.DefaultPathEnv(platform))
239 244
 	}
240 245
 }
241 246
 
... ...
@@ -34,6 +34,7 @@ import (
34 34
 	"github.com/docker/docker/pkg/ioutils"
35 35
 	"github.com/docker/docker/pkg/signal"
36 36
 	"github.com/docker/docker/pkg/symlink"
37
+	"github.com/docker/docker/pkg/system"
37 38
 	"github.com/docker/docker/restartmanager"
38 39
 	"github.com/docker/docker/runconfig"
39 40
 	"github.com/docker/docker/volume"
... ...
@@ -1004,3 +1005,31 @@ func (container *Container) ConfigsDirPath() string {
1004 1004
 func (container *Container) ConfigFilePath(configRef swarmtypes.ConfigReference) string {
1005 1005
 	return filepath.Join(container.ConfigsDirPath(), configRef.ConfigID)
1006 1006
 }
1007
+
1008
+// CreateDaemonEnvironment creates a new environment variable slice for this container.
1009
+func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
1010
+	// Setup environment
1011
+	// TODO @jhowardmsft LCOW Support. This will need revisiting later.
1012
+	platform := container.Platform
1013
+	if platform == "" {
1014
+		platform = runtime.GOOS
1015
+	}
1016
+	env := []string{}
1017
+	if runtime.GOOS != "windows" || (runtime.GOOS == "windows" && system.LCOWSupported() && platform == "linux") {
1018
+		env = []string{
1019
+			"PATH=" + system.DefaultPathEnv(platform),
1020
+			"HOSTNAME=" + container.Config.Hostname,
1021
+		}
1022
+		if tty {
1023
+			env = append(env, "TERM=xterm")
1024
+		}
1025
+		env = append(env, linkedEnv...)
1026
+	}
1027
+
1028
+	// because the env on the container can override certain default values
1029
+	// we need to replace the 'env' keys where they match and append anything
1030
+	// else.
1031
+	//return ReplaceOrAppendEnvValues(linkedEnv, container.Config.Env)
1032
+	foo := ReplaceOrAppendEnvValues(env, container.Config.Env)
1033
+	return foo
1034
+}
... ...
@@ -35,27 +35,6 @@ type ExitStatus struct {
35 35
 	OOMKilled bool
36 36
 }
37 37
 
38
-// CreateDaemonEnvironment returns the list of all environment variables given the list of
39
-// environment variables related to links.
40
-// Sets PATH, HOSTNAME and if container.Config.Tty is set: TERM.
41
-// The defaults set here do not override the values in container.Config.Env
42
-func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string {
43
-	// Setup environment
44
-	env := []string{
45
-		"PATH=" + system.DefaultPathEnv,
46
-		"HOSTNAME=" + container.Config.Hostname,
47
-	}
48
-	if tty {
49
-		env = append(env, "TERM=xterm")
50
-	}
51
-	env = append(env, linkedEnv...)
52
-	// because the env on the container can override certain default values
53
-	// we need to replace the 'env' keys where they match and append anything
54
-	// else.
55
-	env = ReplaceOrAppendEnvValues(env, container.Config.Env)
56
-	return env
57
-}
58
-
59 38
 // TrySetNetworkMount attempts to set the network mounts given a provided destination and
60 39
 // the path to use for it; return true if the given destination was a network mount file
61 40
 func (container *Container) TrySetNetworkMount(destination string, path string) bool {
... ...
@@ -23,14 +23,6 @@ type ExitStatus struct {
23 23
 	ExitCode int
24 24
 }
25 25
 
26
-// CreateDaemonEnvironment creates a new environment variable slice for this container.
27
-func (container *Container) CreateDaemonEnvironment(_ bool, linkedEnv []string) []string {
28
-	// because the env on the container can override certain default values
29
-	// we need to replace the 'env' keys where they match and append anything
30
-	// else.
31
-	return ReplaceOrAppendEnvValues(linkedEnv, container.Config.Env)
32
-}
33
-
34 26
 // UnmountIpcMounts unmounts Ipc related mounts.
35 27
 // This is a NOOP on windows.
36 28
 func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
... ...
@@ -7,11 +7,17 @@ import (
7 7
 	"github.com/docker/docker/container"
8 8
 	"github.com/docker/docker/oci"
9 9
 	"github.com/docker/docker/pkg/sysinfo"
10
+	"github.com/docker/docker/pkg/system"
10 11
 	"github.com/opencontainers/runtime-spec/specs-go"
11 12
 )
12 13
 
13 14
 func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
14
-	s := oci.DefaultSpec()
15
+	img, err := daemon.GetImage(string(c.ImageID))
16
+	if err != nil {
17
+		return nil, err
18
+	}
19
+
20
+	s := oci.DefaultOSSpec(img.OS)
15 21
 
16 22
 	linkedEnv, err := daemon.setupLinkedContainers(c)
17 23
 	if err != nil {
... ...
@@ -95,7 +101,30 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
95 95
 	if !c.Config.ArgsEscaped {
96 96
 		s.Process.Args = escapeArgs(s.Process.Args)
97 97
 	}
98
+
98 99
 	s.Process.Cwd = c.Config.WorkingDir
100
+	s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
101
+	if c.Config.Tty {
102
+		s.Process.Terminal = c.Config.Tty
103
+		s.Process.ConsoleSize.Height = c.HostConfig.ConsoleSize[0]
104
+		s.Process.ConsoleSize.Width = c.HostConfig.ConsoleSize[1]
105
+	}
106
+	s.Process.User.Username = c.Config.User
107
+
108
+	if img.OS == "windows" {
109
+		daemon.createSpecWindowsFields(c, &s, isHyperV)
110
+	} else {
111
+		// TODO @jhowardmsft LCOW Support. Modify this check when running in dual-mode
112
+		if system.LCOWSupported() && img.OS == "linux" {
113
+			daemon.createSpecLinuxFields(c, &s)
114
+		}
115
+	}
116
+
117
+	return (*specs.Spec)(&s), nil
118
+}
119
+
120
+// Sets the Windows-specific fields of the OCI spec
121
+func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.Spec, isHyperV bool) {
99 122
 	if len(s.Process.Cwd) == 0 {
100 123
 		// We default to C:\ to workaround the oddity of the case that the
101 124
 		// default directory for cmd running as LocalSystem (or
... ...
@@ -106,17 +135,11 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
106 106
 		// as c:\. Hence, setting it to default of c:\ makes for consistency.
107 107
 		s.Process.Cwd = `C:\`
108 108
 	}
109
-	s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
110
-	s.Process.ConsoleSize.Height = c.HostConfig.ConsoleSize[0]
111
-	s.Process.ConsoleSize.Width = c.HostConfig.ConsoleSize[1]
112
-	s.Process.Terminal = c.Config.Tty
113
-	s.Process.User.Username = c.Config.User
114 109
 
115
-	// In spec.Root. This is not set for Hyper-V containers
110
+	s.Root.Readonly = false // Windows does not support a read-only root filesystem
116 111
 	if !isHyperV {
117
-		s.Root.Path = c.BaseFS
112
+		s.Root.Path = c.BaseFS // This is not set for Hyper-V containers
118 113
 	}
119
-	s.Root.Readonly = false // Windows does not support a read-only root filesystem
120 114
 
121 115
 	// In s.Windows.Resources
122 116
 	cpuShares := uint16(c.HostConfig.CPUShares)
... ...
@@ -157,7 +180,17 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
157 157
 			Iops: &c.HostConfig.IOMaximumIOps,
158 158
 		},
159 159
 	}
160
-	return (*specs.Spec)(&s), nil
160
+}
161
+
162
+// Sets the Linux-specific fields of the OCI spec
163
+// TODO: @jhowardmsft LCOW Support. We need to do a lot more pulling in what can
164
+// be pulled in from oci_linux.go.
165
+func (daemon *Daemon) createSpecLinuxFields(c *container.Container, s *specs.Spec) {
166
+	if len(s.Process.Cwd) == 0 {
167
+		s.Process.Cwd = `/`
168
+	}
169
+	s.Root.Path = "rootfs"
170
+	s.Root.Readonly = c.HostConfig.ReadonlyRootfs
161 171
 }
162 172
 
163 173
 func escapeArgs(args []string) []string {
... ...
@@ -1,6 +1,7 @@
1 1
 package libcontainerd
2 2
 
3 3
 import (
4
+	"encoding/json"
4 5
 	"errors"
5 6
 	"fmt"
6 7
 	"io"
... ...
@@ -96,8 +97,17 @@ const defaultOwner = "docker"
96 96
 func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) error {
97 97
 	clnt.lock(containerID)
98 98
 	defer clnt.unlock(containerID)
99
-	logrus.Debugln("libcontainerd: client.Create() with spec", spec)
99
+	if b, err := json.Marshal(spec); err == nil {
100
+		logrus.Debugln("libcontainerd: client.Create() with spec", string(b))
101
+	}
102
+	osName := spec.Platform.OS
103
+	if osName == "windows" {
104
+		return clnt.createWindows(containerID, checkpoint, checkpointDir, spec, attachStdio, options...)
105
+	}
106
+	return clnt.createLinux(containerID, checkpoint, checkpointDir, spec, attachStdio, options...)
107
+}
100 108
 
109
+func (clnt *client) createWindows(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) error {
101 110
 	configuration := &hcsshim.ContainerConfig{
102 111
 		SystemType: "Container",
103 112
 		Name:       containerID,
... ...
@@ -265,17 +275,100 @@ func (clnt *client) Create(containerID string, checkpoint string, checkpointDir
265 265
 	// Call start, and if it fails, delete the container from our
266 266
 	// internal structure, start will keep HCS in sync by deleting the
267 267
 	// container there.
268
-	logrus.Debugf("libcontainerd: Create() id=%s, Calling start()", containerID)
268
+	logrus.Debugf("libcontainerd: createWindows() id=%s, Calling start()", containerID)
269 269
 	if err := container.start(attachStdio); err != nil {
270 270
 		clnt.deleteContainer(containerID)
271 271
 		return err
272 272
 	}
273 273
 
274
-	logrus.Debugf("libcontainerd: Create() id=%s completed successfully", containerID)
274
+	logrus.Debugf("libcontainerd: createWindows() id=%s completed successfully", containerID)
275 275
 	return nil
276 276
 
277 277
 }
278 278
 
279
+func (clnt *client) createLinux(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) error {
280
+	logrus.Debugf("libcontainerd: createLinux(): containerId %s ", containerID)
281
+
282
+	// TODO @jhowardmsft LCOW Support: This needs to be configurable, not hard-coded.
283
+	// However, good-enough for the LCOW bring-up.
284
+	configuration := &hcsshim.ContainerConfig{
285
+		HvPartition:                 true,
286
+		Name:                        containerID,
287
+		SystemType:                  "container",
288
+		ContainerType:               "linux",
289
+		TerminateOnLastHandleClosed: true,
290
+		HvRuntime: &hcsshim.HvRuntime{
291
+			ImagePath: `c:\program files\lcow`,
292
+		},
293
+	}
294
+
295
+	var layerOpt *LayerOption
296
+	for _, option := range options {
297
+		if l, ok := option.(*LayerOption); ok {
298
+			layerOpt = l
299
+		}
300
+	}
301
+
302
+	// We must have a layer option with at least one path
303
+	if layerOpt == nil || layerOpt.LayerPaths == nil {
304
+		return fmt.Errorf("no layer option or paths were supplied to the runtime")
305
+	}
306
+
307
+	// LayerFolderPath (writeable layer) + Layers (Guid + path)
308
+	configuration.LayerFolderPath = layerOpt.LayerFolderPath
309
+	for _, layerPath := range layerOpt.LayerPaths {
310
+		_, filename := filepath.Split(layerPath)
311
+		g, err := hcsshim.NameToGuid(filename)
312
+		if err != nil {
313
+			return err
314
+		}
315
+		configuration.Layers = append(configuration.Layers, hcsshim.Layer{
316
+			ID:   g.ToString(),
317
+			Path: filepath.Join(layerPath, "layer.vhd"),
318
+		})
319
+	}
320
+
321
+	hcsContainer, err := hcsshim.CreateContainer(containerID, configuration)
322
+	if err != nil {
323
+		return err
324
+	}
325
+
326
+	// Construct a container object for calling start on it.
327
+	container := &container{
328
+		containerCommon: containerCommon{
329
+			process: process{
330
+				processCommon: processCommon{
331
+					containerID:  containerID,
332
+					client:       clnt,
333
+					friendlyName: InitFriendlyName,
334
+				},
335
+			},
336
+			processes: make(map[string]*process),
337
+		},
338
+		ociSpec:      spec,
339
+		hcsContainer: hcsContainer,
340
+	}
341
+
342
+	container.options = options
343
+	for _, option := range options {
344
+		if err := option.Apply(container); err != nil {
345
+			logrus.Errorf("libcontainerd: createLinux() %v", err)
346
+		}
347
+	}
348
+
349
+	// Call start, and if it fails, delete the container from our
350
+	// internal structure, start will keep HCS in sync by deleting the
351
+	// container there.
352
+	logrus.Debugf("libcontainerd: createLinux() id=%s, Calling start()", containerID)
353
+	if err := container.start(attachStdio); err != nil {
354
+		clnt.deleteContainer(containerID)
355
+		return err
356
+	}
357
+
358
+	logrus.Debugf("libcontainerd: createLinux() id=%s completed successfully", containerID)
359
+	return nil
360
+}
361
+
279 362
 // AddProcess is the handler for adding a process to an already running
280 363
 // container. It's called through docker exec. It returns the system pid of the
281 364
 // exec'd process.
... ...
@@ -292,13 +385,15 @@ func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendly
292 292
 	// create stdin, even if it's not used - it will be closed shortly. Stderr
293 293
 	// is only created if it we're not -t.
294 294
 	createProcessParms := hcsshim.ProcessConfig{
295
-		EmulateConsole:   procToAdd.Terminal,
296 295
 		CreateStdInPipe:  true,
297 296
 		CreateStdOutPipe: true,
298 297
 		CreateStdErrPipe: !procToAdd.Terminal,
299 298
 	}
300
-	createProcessParms.ConsoleSize[0] = uint(procToAdd.ConsoleSize.Height)
301
-	createProcessParms.ConsoleSize[1] = uint(procToAdd.ConsoleSize.Width)
299
+	if procToAdd.Terminal {
300
+		createProcessParms.EmulateConsole = true
301
+		createProcessParms.ConsoleSize[0] = uint(procToAdd.ConsoleSize.Height)
302
+		createProcessParms.ConsoleSize[1] = uint(procToAdd.ConsoleSize.Width)
303
+	}
302 304
 
303 305
 	// Take working directory from the process to add if it is defined,
304 306
 	// otherwise take from the first process.
... ...
@@ -1,6 +1,7 @@
1 1
 package libcontainerd
2 2
 
3 3
 import (
4
+	"encoding/json"
4 5
 	"fmt"
5 6
 	"io"
6 7
 	"io/ioutil"
... ...
@@ -10,6 +11,7 @@ import (
10 10
 
11 11
 	"github.com/Microsoft/hcsshim"
12 12
 	"github.com/Sirupsen/logrus"
13
+	"github.com/docker/docker/pkg/system"
13 14
 	"github.com/opencontainers/runtime-spec/specs-go"
14 15
 )
15 16
 
... ...
@@ -83,6 +85,16 @@ func (ctr *container) start(attachStdio StdioCallback) error {
83 83
 	createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ")
84 84
 	createProcessParms.User = ctr.ociSpec.Process.User.Username
85 85
 
86
+	// LCOW requires the raw OCI spec passed through HCS and onwards to GCS for the utility VM.
87
+	if system.LCOWSupported() && ctr.ociSpec.Platform.OS == "linux" {
88
+		ociBuf, err := json.Marshal(ctr.ociSpec)
89
+		if err != nil {
90
+			return err
91
+		}
92
+		ociRaw := json.RawMessage(ociBuf)
93
+		createProcessParms.OCISpecification = &ociRaw
94
+	}
95
+
86 96
 	// Start the command running in the container.
87 97
 	newProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
88 98
 	if err != nil {
... ...
@@ -228,11 +240,14 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
228 228
 	if !isFirstProcessToStart {
229 229
 		si.State = StateExitProcess
230 230
 	} else {
231
-		updatePending, err := ctr.hcsContainer.HasPendingUpdates()
232
-		if err != nil {
233
-			logrus.Warnf("libcontainerd: HasPendingUpdates() failed (container may have been killed): %s", err)
234
-		} else {
235
-			si.UpdatePending = updatePending
231
+		// Pending updates is only applicable for WCOW
232
+		if ctr.ociSpec.Platform.OS == "windows" {
233
+			updatePending, err := ctr.hcsContainer.HasPendingUpdates()
234
+			if err != nil {
235
+				logrus.Warnf("libcontainerd: HasPendingUpdates() failed (container may have been killed): %s", err)
236
+			} else {
237
+				si.UpdatePending = updatePending
238
+			}
236 239
 		}
237 240
 
238 241
 		logrus.Debugf("libcontainerd: shutting down container %s", ctr.containerID)
239 242
new file mode 100644
... ...
@@ -0,0 +1,221 @@
0
+package oci
1
+
2
+import (
3
+	"os"
4
+	"runtime"
5
+
6
+	"github.com/opencontainers/runtime-spec/specs-go"
7
+)
8
+
9
+func iPtr(i int64) *int64        { return &i }
10
+func u32Ptr(i int64) *uint32     { u := uint32(i); return &u }
11
+func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
12
+
13
+func defaultCapabilities() []string {
14
+	return []string{
15
+		"CAP_CHOWN",
16
+		"CAP_DAC_OVERRIDE",
17
+		"CAP_FSETID",
18
+		"CAP_FOWNER",
19
+		"CAP_MKNOD",
20
+		"CAP_NET_RAW",
21
+		"CAP_SETGID",
22
+		"CAP_SETUID",
23
+		"CAP_SETFCAP",
24
+		"CAP_SETPCAP",
25
+		"CAP_NET_BIND_SERVICE",
26
+		"CAP_SYS_CHROOT",
27
+		"CAP_KILL",
28
+		"CAP_AUDIT_WRITE",
29
+	}
30
+}
31
+
32
+// DefaultSpec returns the default spec used by docker for the current Platform
33
+func DefaultSpec() specs.Spec {
34
+	return DefaultOSSpec(runtime.GOOS)
35
+}
36
+
37
+// DefaultOSSpec returns the spec for a given OS
38
+func DefaultOSSpec(osName string) specs.Spec {
39
+	if osName == "windows" {
40
+		return DefaultWindowsSpec()
41
+	} else if osName == "solaris" {
42
+		return DefaultSolarisSpec()
43
+	} else {
44
+		return DefaultLinuxSpec()
45
+	}
46
+}
47
+
48
+// DefaultWindowsSpec create a default spec for running Windows containers
49
+func DefaultWindowsSpec() specs.Spec {
50
+	return specs.Spec{
51
+		Version: specs.Version,
52
+		Platform: specs.Platform{
53
+			OS:   runtime.GOOS,
54
+			Arch: runtime.GOARCH,
55
+		},
56
+		Windows: &specs.Windows{},
57
+	}
58
+}
59
+
60
+// DefaultSolarisSpec create a default spec for running Solaris containers
61
+func DefaultSolarisSpec() specs.Spec {
62
+	s := specs.Spec{
63
+		Version: "0.6.0",
64
+		Platform: specs.Platform{
65
+			OS:   "SunOS",
66
+			Arch: runtime.GOARCH,
67
+		},
68
+	}
69
+	s.Solaris = &specs.Solaris{}
70
+	return s
71
+}
72
+
73
+// DefaultLinuxSpec create a default spec for running Linux containers
74
+func DefaultLinuxSpec() specs.Spec {
75
+	s := specs.Spec{
76
+		Version: specs.Version,
77
+		Platform: specs.Platform{
78
+			OS:   "linux",
79
+			Arch: runtime.GOARCH,
80
+		},
81
+	}
82
+	s.Mounts = []specs.Mount{
83
+		{
84
+			Destination: "/proc",
85
+			Type:        "proc",
86
+			Source:      "proc",
87
+			Options:     []string{"nosuid", "noexec", "nodev"},
88
+		},
89
+		{
90
+			Destination: "/dev",
91
+			Type:        "tmpfs",
92
+			Source:      "tmpfs",
93
+			Options:     []string{"nosuid", "strictatime", "mode=755"},
94
+		},
95
+		{
96
+			Destination: "/dev/pts",
97
+			Type:        "devpts",
98
+			Source:      "devpts",
99
+			Options:     []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
100
+		},
101
+		{
102
+			Destination: "/sys",
103
+			Type:        "sysfs",
104
+			Source:      "sysfs",
105
+			Options:     []string{"nosuid", "noexec", "nodev", "ro"},
106
+		},
107
+		{
108
+			Destination: "/sys/fs/cgroup",
109
+			Type:        "cgroup",
110
+			Source:      "cgroup",
111
+			Options:     []string{"ro", "nosuid", "noexec", "nodev"},
112
+		},
113
+		{
114
+			Destination: "/dev/mqueue",
115
+			Type:        "mqueue",
116
+			Source:      "mqueue",
117
+			Options:     []string{"nosuid", "noexec", "nodev"},
118
+		},
119
+	}
120
+	s.Process.Capabilities = &specs.LinuxCapabilities{
121
+		Bounding:    defaultCapabilities(),
122
+		Permitted:   defaultCapabilities(),
123
+		Inheritable: defaultCapabilities(),
124
+		Effective:   defaultCapabilities(),
125
+	}
126
+
127
+	s.Linux = &specs.Linux{
128
+		MaskedPaths: []string{
129
+			"/proc/kcore",
130
+			"/proc/latency_stats",
131
+			"/proc/timer_list",
132
+			"/proc/timer_stats",
133
+			"/proc/sched_debug",
134
+		},
135
+		ReadonlyPaths: []string{
136
+			"/proc/asound",
137
+			"/proc/bus",
138
+			"/proc/fs",
139
+			"/proc/irq",
140
+			"/proc/sys",
141
+			"/proc/sysrq-trigger",
142
+		},
143
+		Namespaces: []specs.LinuxNamespace{
144
+			{Type: "mount"},
145
+			{Type: "network"},
146
+			{Type: "uts"},
147
+			{Type: "pid"},
148
+			{Type: "ipc"},
149
+		},
150
+		// Devices implicitly contains the following devices:
151
+		// null, zero, full, random, urandom, tty, console, and ptmx.
152
+		// ptmx is a bind-mount or symlink of the container's ptmx.
153
+		// See also: https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#default-devices
154
+		Devices: []specs.LinuxDevice{},
155
+		Resources: &specs.LinuxResources{
156
+			Devices: []specs.LinuxDeviceCgroup{
157
+				{
158
+					Allow:  false,
159
+					Access: "rwm",
160
+				},
161
+				{
162
+					Allow:  true,
163
+					Type:   "c",
164
+					Major:  iPtr(1),
165
+					Minor:  iPtr(5),
166
+					Access: "rwm",
167
+				},
168
+				{
169
+					Allow:  true,
170
+					Type:   "c",
171
+					Major:  iPtr(1),
172
+					Minor:  iPtr(3),
173
+					Access: "rwm",
174
+				},
175
+				{
176
+					Allow:  true,
177
+					Type:   "c",
178
+					Major:  iPtr(1),
179
+					Minor:  iPtr(9),
180
+					Access: "rwm",
181
+				},
182
+				{
183
+					Allow:  true,
184
+					Type:   "c",
185
+					Major:  iPtr(1),
186
+					Minor:  iPtr(8),
187
+					Access: "rwm",
188
+				},
189
+				{
190
+					Allow:  true,
191
+					Type:   "c",
192
+					Major:  iPtr(5),
193
+					Minor:  iPtr(0),
194
+					Access: "rwm",
195
+				},
196
+				{
197
+					Allow:  true,
198
+					Type:   "c",
199
+					Major:  iPtr(5),
200
+					Minor:  iPtr(1),
201
+					Access: "rwm",
202
+				},
203
+				{
204
+					Allow:  false,
205
+					Type:   "c",
206
+					Major:  iPtr(10),
207
+					Minor:  iPtr(229),
208
+					Access: "rwm",
209
+				},
210
+			},
211
+		},
212
+	}
213
+
214
+	// For LCOW support, don't mask /sys/firmware
215
+	if runtime.GOOS != "windows" {
216
+		s.Linux.MaskedPaths = append(s.Linux.MaskedPaths, "/sys/firmware")
217
+	}
218
+
219
+	return s
220
+}
0 221
deleted file mode 100644
... ...
@@ -1,176 +0,0 @@
1
-package oci
2
-
3
-import (
4
-	"os"
5
-	"runtime"
6
-
7
-	"github.com/opencontainers/runtime-spec/specs-go"
8
-)
9
-
10
-func iPtr(i int64) *int64        { return &i }
11
-func u32Ptr(i int64) *uint32     { u := uint32(i); return &u }
12
-func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
13
-
14
-func defaultCapabilities() []string {
15
-	return []string{
16
-		"CAP_CHOWN",
17
-		"CAP_DAC_OVERRIDE",
18
-		"CAP_FSETID",
19
-		"CAP_FOWNER",
20
-		"CAP_MKNOD",
21
-		"CAP_NET_RAW",
22
-		"CAP_SETGID",
23
-		"CAP_SETUID",
24
-		"CAP_SETFCAP",
25
-		"CAP_SETPCAP",
26
-		"CAP_NET_BIND_SERVICE",
27
-		"CAP_SYS_CHROOT",
28
-		"CAP_KILL",
29
-		"CAP_AUDIT_WRITE",
30
-	}
31
-}
32
-
33
-// DefaultSpec returns default oci spec used by docker.
34
-func DefaultSpec() specs.Spec {
35
-	s := specs.Spec{
36
-		Version: specs.Version,
37
-		Platform: specs.Platform{
38
-			OS:   runtime.GOOS,
39
-			Arch: runtime.GOARCH,
40
-		},
41
-	}
42
-	s.Mounts = []specs.Mount{
43
-		{
44
-			Destination: "/proc",
45
-			Type:        "proc",
46
-			Source:      "proc",
47
-			Options:     []string{"nosuid", "noexec", "nodev"},
48
-		},
49
-		{
50
-			Destination: "/dev",
51
-			Type:        "tmpfs",
52
-			Source:      "tmpfs",
53
-			Options:     []string{"nosuid", "strictatime", "mode=755"},
54
-		},
55
-		{
56
-			Destination: "/dev/pts",
57
-			Type:        "devpts",
58
-			Source:      "devpts",
59
-			Options:     []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
60
-		},
61
-		{
62
-			Destination: "/sys",
63
-			Type:        "sysfs",
64
-			Source:      "sysfs",
65
-			Options:     []string{"nosuid", "noexec", "nodev", "ro"},
66
-		},
67
-		{
68
-			Destination: "/sys/fs/cgroup",
69
-			Type:        "cgroup",
70
-			Source:      "cgroup",
71
-			Options:     []string{"ro", "nosuid", "noexec", "nodev"},
72
-		},
73
-		{
74
-			Destination: "/dev/mqueue",
75
-			Type:        "mqueue",
76
-			Source:      "mqueue",
77
-			Options:     []string{"nosuid", "noexec", "nodev"},
78
-		},
79
-	}
80
-	s.Process.Capabilities = &specs.LinuxCapabilities{
81
-		Bounding:    defaultCapabilities(),
82
-		Permitted:   defaultCapabilities(),
83
-		Inheritable: defaultCapabilities(),
84
-		Effective:   defaultCapabilities(),
85
-	}
86
-
87
-	s.Linux = &specs.Linux{
88
-		MaskedPaths: []string{
89
-			"/proc/kcore",
90
-			"/proc/latency_stats",
91
-			"/proc/timer_list",
92
-			"/proc/timer_stats",
93
-			"/proc/sched_debug",
94
-			"/sys/firmware",
95
-		},
96
-		ReadonlyPaths: []string{
97
-			"/proc/asound",
98
-			"/proc/bus",
99
-			"/proc/fs",
100
-			"/proc/irq",
101
-			"/proc/sys",
102
-			"/proc/sysrq-trigger",
103
-		},
104
-		Namespaces: []specs.LinuxNamespace{
105
-			{Type: "mount"},
106
-			{Type: "network"},
107
-			{Type: "uts"},
108
-			{Type: "pid"},
109
-			{Type: "ipc"},
110
-		},
111
-		// Devices implicitly contains the following devices:
112
-		// null, zero, full, random, urandom, tty, console, and ptmx.
113
-		// ptmx is a bind-mount or symlink of the container's ptmx.
114
-		// See also: https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#default-devices
115
-		Devices: []specs.LinuxDevice{},
116
-		Resources: &specs.LinuxResources{
117
-			Devices: []specs.LinuxDeviceCgroup{
118
-				{
119
-					Allow:  false,
120
-					Access: "rwm",
121
-				},
122
-				{
123
-					Allow:  true,
124
-					Type:   "c",
125
-					Major:  iPtr(1),
126
-					Minor:  iPtr(5),
127
-					Access: "rwm",
128
-				},
129
-				{
130
-					Allow:  true,
131
-					Type:   "c",
132
-					Major:  iPtr(1),
133
-					Minor:  iPtr(3),
134
-					Access: "rwm",
135
-				},
136
-				{
137
-					Allow:  true,
138
-					Type:   "c",
139
-					Major:  iPtr(1),
140
-					Minor:  iPtr(9),
141
-					Access: "rwm",
142
-				},
143
-				{
144
-					Allow:  true,
145
-					Type:   "c",
146
-					Major:  iPtr(1),
147
-					Minor:  iPtr(8),
148
-					Access: "rwm",
149
-				},
150
-				{
151
-					Allow:  true,
152
-					Type:   "c",
153
-					Major:  iPtr(5),
154
-					Minor:  iPtr(0),
155
-					Access: "rwm",
156
-				},
157
-				{
158
-					Allow:  true,
159
-					Type:   "c",
160
-					Major:  iPtr(5),
161
-					Minor:  iPtr(1),
162
-					Access: "rwm",
163
-				},
164
-				{
165
-					Allow:  false,
166
-					Type:   "c",
167
-					Major:  iPtr(10),
168
-					Minor:  iPtr(229),
169
-					Access: "rwm",
170
-				},
171
-			},
172
-		},
173
-	}
174
-
175
-	return s
176
-}
177 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-package oci
2
-
3
-import (
4
-	"runtime"
5
-
6
-	"github.com/opencontainers/runtime-spec/specs-go"
7
-)
8
-
9
-// DefaultSpec returns default oci spec used by docker.
10
-func DefaultSpec() specs.Spec {
11
-	s := specs.Spec{
12
-		Version: "0.6.0",
13
-		Platform: specs.Platform{
14
-			OS:   "SunOS",
15
-			Arch: runtime.GOARCH,
16
-		},
17
-	}
18
-	s.Solaris = &specs.Solaris{}
19
-	return s
20
-}
21 1
deleted file mode 100644
... ...
@@ -1,19 +0,0 @@
1
-package oci
2
-
3
-import (
4
-	"runtime"
5
-
6
-	"github.com/opencontainers/runtime-spec/specs-go"
7
-)
8
-
9
-// DefaultSpec returns default spec used by docker.
10
-func DefaultSpec() specs.Spec {
11
-	return specs.Spec{
12
-		Version: specs.Version,
13
-		Platform: specs.Platform{
14
-			OS:   runtime.GOOS,
15
-			Arch: runtime.GOARCH,
16
-		},
17
-		Windows: &specs.Windows{},
18
-	}
19
-}
20 1
new file mode 100644
... ...
@@ -0,0 +1,21 @@
0
+package system
1
+
2
+import "runtime"
3
+
4
+const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
5
+
6
+// DefaultPathEnv is unix style list of directories to search for
7
+// executables. Each directory is separated from the next by a colon
8
+// ':' character .
9
+func DefaultPathEnv(platform string) string {
10
+	if runtime.GOOS == "windows" {
11
+		if platform != runtime.GOOS && LCOWSupported() {
12
+			return defaultUnixPathEnv
13
+		}
14
+		// Deliberately empty on Windows containers on Windows as the default path will be set by
15
+		// the container. Docker has no context of what the default path should be.
16
+		return ""
17
+	}
18
+	return defaultUnixPathEnv
19
+
20
+}
... ...
@@ -2,11 +2,6 @@
2 2
 
3 3
 package system
4 4
 
5
-// DefaultPathEnv is unix style list of directories to search for
6
-// executables. Each directory is separated from the next by a colon
7
-// ':' character .
8
-const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
9
-
10 5
 // CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
11 6
 // is the system drive. This is a no-op on Linux.
12 7
 func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
... ...
@@ -8,10 +8,6 @@ import (
8 8
 	"strings"
9 9
 )
10 10
 
11
-// DefaultPathEnv is deliberately empty on Windows as the default path will be set by
12
-// the container. Docker has no context of what the default path should be.
13
-const DefaultPathEnv = ""
14
-
15 11
 // CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path.
16 12
 // This is used, for example, when validating a user provided path in docker cp.
17 13
 // If a drive letter is supplied, it must be the system drive. The drive letter
... ...
@@ -5,6 +5,7 @@ package v2
5 5
 import (
6 6
 	"os"
7 7
 	"path/filepath"
8
+	"runtime"
8 9
 	"strings"
9 10
 
10 11
 	"github.com/docker/docker/api/types"
... ...
@@ -108,7 +109,7 @@ func (p *Plugin) InitSpec(execRoot string) (*specs.Spec, error) {
108 108
 	}
109 109
 
110 110
 	envs := make([]string, 1, len(p.PluginObj.Settings.Env)+1)
111
-	envs[0] = "PATH=" + system.DefaultPathEnv
111
+	envs[0] = "PATH=" + system.DefaultPathEnv(runtime.GOOS)
112 112
 	envs = append(envs, p.PluginObj.Settings.Env...)
113 113
 
114 114
 	args := append(p.PluginObj.Config.Entrypoint, p.PluginObj.Settings.Args...)