Browse code

Move runtime and container into sub pkg Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/03/08 11:42:29
Showing 21 changed files
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"github.com/dotcloud/docker/auth"
11 11
 	"github.com/dotcloud/docker/registry"
12 12
 	"github.com/dotcloud/docker/runconfig"
13
+	"github.com/dotcloud/docker/runtime"
13 14
 	"github.com/dotcloud/docker/utils"
14 15
 	"io"
15 16
 	"io/ioutil"
... ...
@@ -34,7 +35,7 @@ type BuildFile interface {
34 34
 }
35 35
 
36 36
 type buildFile struct {
37
-	runtime *Runtime
37
+	runtime *runtime.Runtime
38 38
 	srv     *Server
39 39
 
40 40
 	image      string
... ...
@@ -74,9 +75,9 @@ func (b *buildFile) clearTmp(containers map[string]struct{}) {
74 74
 }
75 75
 
76 76
 func (b *buildFile) CmdFrom(name string) error {
77
-	image, err := b.runtime.repositories.LookupImage(name)
77
+	image, err := b.runtime.Repositories().LookupImage(name)
78 78
 	if err != nil {
79
-		if b.runtime.graph.IsNotExist(err) {
79
+		if b.runtime.Graph().IsNotExist(err) {
80 80
 			remote, tag := utils.ParseRepositoryTag(name)
81 81
 			pullRegistryAuth := b.authConfig
82 82
 			if len(b.configFile.Configs) > 0 {
... ...
@@ -96,7 +97,7 @@ func (b *buildFile) CmdFrom(name string) error {
96 96
 			if err := job.Run(); err != nil {
97 97
 				return err
98 98
 			}
99
-			image, err = b.runtime.repositories.LookupImage(name)
99
+			image, err = b.runtime.Repositories().LookupImage(name)
100 100
 			if err != nil {
101 101
 				return err
102 102
 			}
... ...
@@ -110,7 +111,7 @@ func (b *buildFile) CmdFrom(name string) error {
110 110
 		b.config = image.Config
111 111
 	}
112 112
 	if b.config.Env == nil || len(b.config.Env) == 0 {
113
-		b.config.Env = append(b.config.Env, "HOME=/", "PATH="+defaultPathEnv)
113
+		b.config.Env = append(b.config.Env, "HOME=/", "PATH="+runtime.DefaultPathEnv)
114 114
 	}
115 115
 	// Process ONBUILD triggers if they exist
116 116
 	if nTriggers := len(b.config.OnBuild); nTriggers != 0 {
... ...
@@ -371,7 +372,7 @@ func (b *buildFile) checkPathForAddition(orig string) error {
371 371
 	return nil
372 372
 }
373 373
 
374
-func (b *buildFile) addContext(container *Container, orig, dest string, remote bool) error {
374
+func (b *buildFile) addContext(container *runtime.Container, orig, dest string, remote bool) error {
375 375
 	var (
376 376
 		origPath = path.Join(b.contextPath, orig)
377 377
 		destPath = path.Join(container.BasefsPath(), dest)
... ...
@@ -604,7 +605,7 @@ func (sf *StderrFormater) Write(buf []byte) (int, error) {
604 604
 	return len(buf), err
605 605
 }
606 606
 
607
-func (b *buildFile) create() (*Container, error) {
607
+func (b *buildFile) create() (*runtime.Container, error) {
608 608
 	if b.image == "" {
609 609
 		return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
610 610
 	}
... ...
@@ -625,7 +626,7 @@ func (b *buildFile) create() (*Container, error) {
625 625
 	return c, nil
626 626
 }
627 627
 
628
-func (b *buildFile) run(c *Container) error {
628
+func (b *buildFile) run(c *runtime.Container) error {
629 629
 	var errCh chan error
630 630
 
631 631
 	if b.verbose {
632 632
deleted file mode 100644
... ...
@@ -1,1143 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"encoding/json"
5
-	"errors"
6
-	"fmt"
7
-	"github.com/dotcloud/docker/archive"
8
-	"github.com/dotcloud/docker/engine"
9
-	"github.com/dotcloud/docker/execdriver"
10
-	"github.com/dotcloud/docker/graphdriver"
11
-	"github.com/dotcloud/docker/image"
12
-	"github.com/dotcloud/docker/links"
13
-	"github.com/dotcloud/docker/nat"
14
-	"github.com/dotcloud/docker/runconfig"
15
-	"github.com/dotcloud/docker/utils"
16
-	"io"
17
-	"io/ioutil"
18
-	"log"
19
-	"os"
20
-	"path"
21
-	"strings"
22
-	"sync"
23
-	"syscall"
24
-	"time"
25
-)
26
-
27
-const defaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
28
-
29
-var (
30
-	ErrNotATTY               = errors.New("The PTY is not a file")
31
-	ErrNoTTY                 = errors.New("No PTY found")
32
-	ErrContainerStart        = errors.New("The container failed to start. Unknown error")
33
-	ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.")
34
-)
35
-
36
-type Container struct {
37
-	sync.Mutex
38
-	root   string // Path to the "home" of the container, including metadata.
39
-	basefs string // Path to the graphdriver mountpoint
40
-
41
-	ID string
42
-
43
-	Created time.Time
44
-
45
-	Path string
46
-	Args []string
47
-
48
-	Config *runconfig.Config
49
-	State  State
50
-	Image  string
51
-
52
-	NetworkSettings *NetworkSettings
53
-
54
-	ResolvConfPath string
55
-	HostnamePath   string
56
-	HostsPath      string
57
-	Name           string
58
-	Driver         string
59
-	ExecDriver     string
60
-
61
-	command   *execdriver.Command
62
-	stdout    *utils.WriteBroadcaster
63
-	stderr    *utils.WriteBroadcaster
64
-	stdin     io.ReadCloser
65
-	stdinPipe io.WriteCloser
66
-
67
-	runtime *Runtime
68
-
69
-	waitLock chan struct{}
70
-	Volumes  map[string]string
71
-	// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
72
-	// Easier than migrating older container configs :)
73
-	VolumesRW  map[string]bool
74
-	hostConfig *runconfig.HostConfig
75
-
76
-	activeLinks map[string]*links.Link
77
-}
78
-
79
-// FIXME: move deprecated port stuff to nat to clean up the core.
80
-type PortMapping map[string]string // Deprecated
81
-
82
-type NetworkSettings struct {
83
-	IPAddress   string
84
-	IPPrefixLen int
85
-	Gateway     string
86
-	Bridge      string
87
-	PortMapping map[string]PortMapping // Deprecated
88
-	Ports       nat.PortMap
89
-}
90
-
91
-func (settings *NetworkSettings) PortMappingAPI() *engine.Table {
92
-	var outs = engine.NewTable("", 0)
93
-	for port, bindings := range settings.Ports {
94
-		p, _ := nat.ParsePort(port.Port())
95
-		if len(bindings) == 0 {
96
-			out := &engine.Env{}
97
-			out.SetInt("PublicPort", p)
98
-			out.Set("Type", port.Proto())
99
-			outs.Add(out)
100
-			continue
101
-		}
102
-		for _, binding := range bindings {
103
-			out := &engine.Env{}
104
-			h, _ := nat.ParsePort(binding.HostPort)
105
-			out.SetInt("PrivatePort", p)
106
-			out.SetInt("PublicPort", h)
107
-			out.Set("Type", port.Proto())
108
-			out.Set("IP", binding.HostIp)
109
-			outs.Add(out)
110
-		}
111
-	}
112
-	return outs
113
-}
114
-
115
-// Inject the io.Reader at the given path. Note: do not close the reader
116
-func (container *Container) Inject(file io.Reader, pth string) error {
117
-	if err := container.Mount(); err != nil {
118
-		return fmt.Errorf("inject: error mounting container %s: %s", container.ID, err)
119
-	}
120
-	defer container.Unmount()
121
-
122
-	// Return error if path exists
123
-	destPath := path.Join(container.basefs, pth)
124
-	if _, err := os.Stat(destPath); err == nil {
125
-		// Since err is nil, the path could be stat'd and it exists
126
-		return fmt.Errorf("%s exists", pth)
127
-	} else if !os.IsNotExist(err) {
128
-		// Expect err might be that the file doesn't exist, so
129
-		// if it's some other error, return that.
130
-
131
-		return err
132
-	}
133
-
134
-	// Make sure the directory exists
135
-	if err := os.MkdirAll(path.Join(container.basefs, path.Dir(pth)), 0755); err != nil {
136
-		return err
137
-	}
138
-
139
-	dest, err := os.Create(destPath)
140
-	if err != nil {
141
-		return err
142
-	}
143
-	defer dest.Close()
144
-
145
-	if _, err := io.Copy(dest, file); err != nil {
146
-		return err
147
-	}
148
-	return nil
149
-}
150
-
151
-func (container *Container) When() time.Time {
152
-	return container.Created
153
-}
154
-
155
-func (container *Container) FromDisk() error {
156
-	data, err := ioutil.ReadFile(container.jsonPath())
157
-	if err != nil {
158
-		return err
159
-	}
160
-	// Load container settings
161
-	// udp broke compat of docker.PortMapping, but it's not used when loading a container, we can skip it
162
-	if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
163
-		return err
164
-	}
165
-	return container.readHostConfig()
166
-}
167
-
168
-func (container *Container) ToDisk() (err error) {
169
-	data, err := json.Marshal(container)
170
-	if err != nil {
171
-		return
172
-	}
173
-	err = ioutil.WriteFile(container.jsonPath(), data, 0666)
174
-	if err != nil {
175
-		return
176
-	}
177
-	return container.writeHostConfig()
178
-}
179
-
180
-func (container *Container) readHostConfig() error {
181
-	container.hostConfig = &runconfig.HostConfig{}
182
-	// If the hostconfig file does not exist, do not read it.
183
-	// (We still have to initialize container.hostConfig,
184
-	// but that's OK, since we just did that above.)
185
-	_, err := os.Stat(container.hostConfigPath())
186
-	if os.IsNotExist(err) {
187
-		return nil
188
-	}
189
-	data, err := ioutil.ReadFile(container.hostConfigPath())
190
-	if err != nil {
191
-		return err
192
-	}
193
-	return json.Unmarshal(data, container.hostConfig)
194
-}
195
-
196
-func (container *Container) writeHostConfig() (err error) {
197
-	data, err := json.Marshal(container.hostConfig)
198
-	if err != nil {
199
-		return
200
-	}
201
-	return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
202
-}
203
-
204
-func (container *Container) generateEnvConfig(env []string) error {
205
-	data, err := json.Marshal(env)
206
-	if err != nil {
207
-		return err
208
-	}
209
-	p, err := container.EnvConfigPath()
210
-	if err != nil {
211
-		return err
212
-	}
213
-	ioutil.WriteFile(p, data, 0600)
214
-	return nil
215
-}
216
-
217
-func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
218
-	var cStdout, cStderr io.ReadCloser
219
-
220
-	var nJobs int
221
-	errors := make(chan error, 3)
222
-	if stdin != nil && container.Config.OpenStdin {
223
-		nJobs += 1
224
-		if cStdin, err := container.StdinPipe(); err != nil {
225
-			errors <- err
226
-		} else {
227
-			go func() {
228
-				utils.Debugf("attach: stdin: begin")
229
-				defer utils.Debugf("attach: stdin: end")
230
-				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
231
-				if container.Config.StdinOnce && !container.Config.Tty {
232
-					defer cStdin.Close()
233
-				} else {
234
-					defer func() {
235
-						if cStdout != nil {
236
-							cStdout.Close()
237
-						}
238
-						if cStderr != nil {
239
-							cStderr.Close()
240
-						}
241
-					}()
242
-				}
243
-				if container.Config.Tty {
244
-					_, err = utils.CopyEscapable(cStdin, stdin)
245
-				} else {
246
-					_, err = io.Copy(cStdin, stdin)
247
-				}
248
-				if err == io.ErrClosedPipe {
249
-					err = nil
250
-				}
251
-				if err != nil {
252
-					utils.Errorf("attach: stdin: %s", err)
253
-				}
254
-				errors <- err
255
-			}()
256
-		}
257
-	}
258
-	if stdout != nil {
259
-		nJobs += 1
260
-		if p, err := container.StdoutPipe(); err != nil {
261
-			errors <- err
262
-		} else {
263
-			cStdout = p
264
-			go func() {
265
-				utils.Debugf("attach: stdout: begin")
266
-				defer utils.Debugf("attach: stdout: end")
267
-				// If we are in StdinOnce mode, then close stdin
268
-				if container.Config.StdinOnce && stdin != nil {
269
-					defer stdin.Close()
270
-				}
271
-				if stdinCloser != nil {
272
-					defer stdinCloser.Close()
273
-				}
274
-				_, err := io.Copy(stdout, cStdout)
275
-				if err == io.ErrClosedPipe {
276
-					err = nil
277
-				}
278
-				if err != nil {
279
-					utils.Errorf("attach: stdout: %s", err)
280
-				}
281
-				errors <- err
282
-			}()
283
-		}
284
-	} else {
285
-		go func() {
286
-			if stdinCloser != nil {
287
-				defer stdinCloser.Close()
288
-			}
289
-			if cStdout, err := container.StdoutPipe(); err != nil {
290
-				utils.Errorf("attach: stdout pipe: %s", err)
291
-			} else {
292
-				io.Copy(&utils.NopWriter{}, cStdout)
293
-			}
294
-		}()
295
-	}
296
-	if stderr != nil {
297
-		nJobs += 1
298
-		if p, err := container.StderrPipe(); err != nil {
299
-			errors <- err
300
-		} else {
301
-			cStderr = p
302
-			go func() {
303
-				utils.Debugf("attach: stderr: begin")
304
-				defer utils.Debugf("attach: stderr: end")
305
-				// If we are in StdinOnce mode, then close stdin
306
-				if container.Config.StdinOnce && stdin != nil {
307
-					defer stdin.Close()
308
-				}
309
-				if stdinCloser != nil {
310
-					defer stdinCloser.Close()
311
-				}
312
-				_, err := io.Copy(stderr, cStderr)
313
-				if err == io.ErrClosedPipe {
314
-					err = nil
315
-				}
316
-				if err != nil {
317
-					utils.Errorf("attach: stderr: %s", err)
318
-				}
319
-				errors <- err
320
-			}()
321
-		}
322
-	} else {
323
-		go func() {
324
-			if stdinCloser != nil {
325
-				defer stdinCloser.Close()
326
-			}
327
-
328
-			if cStderr, err := container.StderrPipe(); err != nil {
329
-				utils.Errorf("attach: stdout pipe: %s", err)
330
-			} else {
331
-				io.Copy(&utils.NopWriter{}, cStderr)
332
-			}
333
-		}()
334
-	}
335
-
336
-	return utils.Go(func() error {
337
-		defer func() {
338
-			if cStdout != nil {
339
-				cStdout.Close()
340
-			}
341
-			if cStderr != nil {
342
-				cStderr.Close()
343
-			}
344
-		}()
345
-
346
-		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
347
-		// of closing the passed stdin? Add an intermediary io.Pipe?
348
-		for i := 0; i < nJobs; i += 1 {
349
-			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
350
-			if err := <-errors; err != nil {
351
-				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
352
-				return err
353
-			}
354
-			utils.Debugf("attach: job %d completed successfully", i+1)
355
-		}
356
-		utils.Debugf("attach: all jobs completed successfully")
357
-		return nil
358
-	})
359
-}
360
-
361
-func populateCommand(c *Container) {
362
-	var (
363
-		en           *execdriver.Network
364
-		driverConfig []string
365
-	)
366
-
367
-	if !c.Config.NetworkDisabled {
368
-		network := c.NetworkSettings
369
-		en = &execdriver.Network{
370
-			Gateway:     network.Gateway,
371
-			Bridge:      network.Bridge,
372
-			IPAddress:   network.IPAddress,
373
-			IPPrefixLen: network.IPPrefixLen,
374
-			Mtu:         c.runtime.config.Mtu,
375
-		}
376
-	}
377
-
378
-	if lxcConf := c.hostConfig.LxcConf; lxcConf != nil {
379
-		for _, pair := range lxcConf {
380
-			driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value))
381
-		}
382
-	}
383
-	resources := &execdriver.Resources{
384
-		Memory:     c.Config.Memory,
385
-		MemorySwap: c.Config.MemorySwap,
386
-		CpuShares:  c.Config.CpuShares,
387
-	}
388
-	c.command = &execdriver.Command{
389
-		ID:         c.ID,
390
-		Privileged: c.hostConfig.Privileged,
391
-		Rootfs:     c.RootfsPath(),
392
-		InitPath:   "/.dockerinit",
393
-		Entrypoint: c.Path,
394
-		Arguments:  c.Args,
395
-		WorkingDir: c.Config.WorkingDir,
396
-		Network:    en,
397
-		Tty:        c.Config.Tty,
398
-		User:       c.Config.User,
399
-		Config:     driverConfig,
400
-		Resources:  resources,
401
-	}
402
-	c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
403
-}
404
-
405
-func (container *Container) Start() (err error) {
406
-	container.Lock()
407
-	defer container.Unlock()
408
-
409
-	if container.State.IsRunning() {
410
-		return fmt.Errorf("The container %s is already running.", container.ID)
411
-	}
412
-
413
-	defer func() {
414
-		if err != nil {
415
-			container.cleanup()
416
-		}
417
-	}()
418
-
419
-	if err := container.Mount(); err != nil {
420
-		return err
421
-	}
422
-
423
-	if container.runtime.config.DisableNetwork {
424
-		container.Config.NetworkDisabled = true
425
-		container.buildHostnameAndHostsFiles("127.0.1.1")
426
-	} else {
427
-		if err := container.allocateNetwork(); err != nil {
428
-			return err
429
-		}
430
-		container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
431
-	}
432
-
433
-	// Make sure the config is compatible with the current kernel
434
-	if container.Config.Memory > 0 && !container.runtime.sysInfo.MemoryLimit {
435
-		log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
436
-		container.Config.Memory = 0
437
-	}
438
-	if container.Config.Memory > 0 && !container.runtime.sysInfo.SwapLimit {
439
-		log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
440
-		container.Config.MemorySwap = -1
441
-	}
442
-
443
-	if container.runtime.sysInfo.IPv4ForwardingDisabled {
444
-		log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
445
-	}
446
-
447
-	if err := prepareVolumesForContainer(container); err != nil {
448
-		return err
449
-	}
450
-
451
-	// Setup environment
452
-	env := []string{
453
-		"HOME=/",
454
-		"PATH=" + defaultPathEnv,
455
-		"HOSTNAME=" + container.Config.Hostname,
456
-	}
457
-
458
-	if container.Config.Tty {
459
-		env = append(env, "TERM=xterm")
460
-	}
461
-
462
-	// Init any links between the parent and children
463
-	runtime := container.runtime
464
-
465
-	children, err := runtime.Children(container.Name)
466
-	if err != nil {
467
-		return err
468
-	}
469
-
470
-	if len(children) > 0 {
471
-		container.activeLinks = make(map[string]*links.Link, len(children))
472
-
473
-		// If we encounter an error make sure that we rollback any network
474
-		// config and ip table changes
475
-		rollback := func() {
476
-			for _, link := range container.activeLinks {
477
-				link.Disable()
478
-			}
479
-			container.activeLinks = nil
480
-		}
481
-
482
-		for linkAlias, child := range children {
483
-			if !child.State.IsRunning() {
484
-				return fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
485
-			}
486
-
487
-			link, err := links.NewLink(
488
-				container.NetworkSettings.IPAddress,
489
-				child.NetworkSettings.IPAddress,
490
-				linkAlias,
491
-				child.Config.Env,
492
-				child.Config.ExposedPorts,
493
-				runtime.eng)
494
-
495
-			if err != nil {
496
-				rollback()
497
-				return err
498
-			}
499
-
500
-			container.activeLinks[link.Alias()] = link
501
-			if err := link.Enable(); err != nil {
502
-				rollback()
503
-				return err
504
-			}
505
-
506
-			for _, envVar := range link.ToEnv() {
507
-				env = append(env, envVar)
508
-			}
509
-		}
510
-	}
511
-
512
-	// because the env on the container can override certain default values
513
-	// we need to replace the 'env' keys where they match and append anything
514
-	// else.
515
-	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
516
-	if err := container.generateEnvConfig(env); err != nil {
517
-		return err
518
-	}
519
-
520
-	if container.Config.WorkingDir != "" {
521
-		container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
522
-		if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
523
-			return nil
524
-		}
525
-	}
526
-
527
-	envPath, err := container.EnvConfigPath()
528
-	if err != nil {
529
-		return err
530
-	}
531
-
532
-	if err := mountVolumesForContainer(container, envPath); err != nil {
533
-		return err
534
-	}
535
-
536
-	populateCommand(container)
537
-	container.command.Env = env
538
-
539
-	// Setup logging of stdout and stderr to disk
540
-	if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
541
-		return err
542
-	}
543
-	if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
544
-		return err
545
-	}
546
-	container.waitLock = make(chan struct{})
547
-
548
-	callbackLock := make(chan struct{})
549
-	callback := func(command *execdriver.Command) {
550
-		container.State.SetRunning(command.Pid())
551
-		if command.Tty {
552
-			// The callback is called after the process Start()
553
-			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
554
-			// which we close here.
555
-			if c, ok := command.Stdout.(io.Closer); ok {
556
-				c.Close()
557
-			}
558
-		}
559
-		if err := container.ToDisk(); err != nil {
560
-			utils.Debugf("%s", err)
561
-		}
562
-		close(callbackLock)
563
-	}
564
-
565
-	// We use a callback here instead of a goroutine and an chan for
566
-	// syncronization purposes
567
-	cErr := utils.Go(func() error { return container.monitor(callback) })
568
-
569
-	// Start should not return until the process is actually running
570
-	select {
571
-	case <-callbackLock:
572
-	case err := <-cErr:
573
-		return err
574
-	}
575
-	return nil
576
-}
577
-
578
-func (container *Container) Run() error {
579
-	if err := container.Start(); err != nil {
580
-		return err
581
-	}
582
-	container.Wait()
583
-	return nil
584
-}
585
-
586
-func (container *Container) Output() (output []byte, err error) {
587
-	pipe, err := container.StdoutPipe()
588
-	if err != nil {
589
-		return nil, err
590
-	}
591
-	defer pipe.Close()
592
-	if err := container.Start(); err != nil {
593
-		return nil, err
594
-	}
595
-	output, err = ioutil.ReadAll(pipe)
596
-	container.Wait()
597
-	return output, err
598
-}
599
-
600
-// Container.StdinPipe returns a WriteCloser which can be used to feed data
601
-// to the standard input of the container's active process.
602
-// Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
603
-// which can be used to retrieve the standard output (and error) generated
604
-// by the container's active process. The output (and error) are actually
605
-// copied and delivered to all StdoutPipe and StderrPipe consumers, using
606
-// a kind of "broadcaster".
607
-
608
-func (container *Container) StdinPipe() (io.WriteCloser, error) {
609
-	return container.stdinPipe, nil
610
-}
611
-
612
-func (container *Container) StdoutPipe() (io.ReadCloser, error) {
613
-	reader, writer := io.Pipe()
614
-	container.stdout.AddWriter(writer, "")
615
-	return utils.NewBufReader(reader), nil
616
-}
617
-
618
-func (container *Container) StderrPipe() (io.ReadCloser, error) {
619
-	reader, writer := io.Pipe()
620
-	container.stderr.AddWriter(writer, "")
621
-	return utils.NewBufReader(reader), nil
622
-}
623
-
624
-func (container *Container) buildHostnameAndHostsFiles(IP string) {
625
-	container.HostnamePath = path.Join(container.root, "hostname")
626
-	ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
627
-
628
-	hostsContent := []byte(`
629
-127.0.0.1	localhost
630
-::1		localhost ip6-localhost ip6-loopback
631
-fe00::0		ip6-localnet
632
-ff00::0		ip6-mcastprefix
633
-ff02::1		ip6-allnodes
634
-ff02::2		ip6-allrouters
635
-`)
636
-
637
-	container.HostsPath = path.Join(container.root, "hosts")
638
-
639
-	if container.Config.Domainname != "" {
640
-		hostsContent = append([]byte(fmt.Sprintf("%s\t%s.%s %s\n", IP, container.Config.Hostname, container.Config.Domainname, container.Config.Hostname)), hostsContent...)
641
-	} else if !container.Config.NetworkDisabled {
642
-		hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...)
643
-	}
644
-
645
-	ioutil.WriteFile(container.HostsPath, hostsContent, 0644)
646
-}
647
-
648
-func (container *Container) allocateNetwork() error {
649
-	if container.Config.NetworkDisabled {
650
-		return nil
651
-	}
652
-
653
-	var (
654
-		env *engine.Env
655
-		err error
656
-		eng = container.runtime.eng
657
-	)
658
-
659
-	if container.State.IsGhost() {
660
-		if container.runtime.config.DisableNetwork {
661
-			env = &engine.Env{}
662
-		} else {
663
-			currentIP := container.NetworkSettings.IPAddress
664
-
665
-			job := eng.Job("allocate_interface", container.ID)
666
-			if currentIP != "" {
667
-				job.Setenv("RequestIP", currentIP)
668
-			}
669
-
670
-			env, err = job.Stdout.AddEnv()
671
-			if err != nil {
672
-				return err
673
-			}
674
-
675
-			if err := job.Run(); err != nil {
676
-				return err
677
-			}
678
-		}
679
-	} else {
680
-		job := eng.Job("allocate_interface", container.ID)
681
-		env, err = job.Stdout.AddEnv()
682
-		if err != nil {
683
-			return err
684
-		}
685
-		if err := job.Run(); err != nil {
686
-			return err
687
-		}
688
-	}
689
-
690
-	if container.Config.PortSpecs != nil {
691
-		utils.Debugf("Migrating port mappings for container: %s", strings.Join(container.Config.PortSpecs, ", "))
692
-		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
693
-			return err
694
-		}
695
-		container.Config.PortSpecs = nil
696
-		if err := container.writeHostConfig(); err != nil {
697
-			return err
698
-		}
699
-	}
700
-
701
-	var (
702
-		portSpecs = make(nat.PortSet)
703
-		bindings  = make(nat.PortMap)
704
-	)
705
-
706
-	if !container.State.IsGhost() {
707
-		if container.Config.ExposedPorts != nil {
708
-			portSpecs = container.Config.ExposedPorts
709
-		}
710
-		if container.hostConfig.PortBindings != nil {
711
-			bindings = container.hostConfig.PortBindings
712
-		}
713
-	} else {
714
-		if container.NetworkSettings.Ports != nil {
715
-			for port, binding := range container.NetworkSettings.Ports {
716
-				portSpecs[port] = struct{}{}
717
-				bindings[port] = binding
718
-			}
719
-		}
720
-	}
721
-
722
-	container.NetworkSettings.PortMapping = nil
723
-
724
-	for port := range portSpecs {
725
-		binding := bindings[port]
726
-		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
727
-			binding = append(binding, nat.PortBinding{})
728
-		}
729
-
730
-		for i := 0; i < len(binding); i++ {
731
-			b := binding[i]
732
-
733
-			portJob := eng.Job("allocate_port", container.ID)
734
-			portJob.Setenv("HostIP", b.HostIp)
735
-			portJob.Setenv("HostPort", b.HostPort)
736
-			portJob.Setenv("Proto", port.Proto())
737
-			portJob.Setenv("ContainerPort", port.Port())
738
-
739
-			portEnv, err := portJob.Stdout.AddEnv()
740
-			if err != nil {
741
-				return err
742
-			}
743
-			if err := portJob.Run(); err != nil {
744
-				eng.Job("release_interface", container.ID).Run()
745
-				return err
746
-			}
747
-			b.HostIp = portEnv.Get("HostIP")
748
-			b.HostPort = portEnv.Get("HostPort")
749
-
750
-			binding[i] = b
751
-		}
752
-		bindings[port] = binding
753
-	}
754
-	container.writeHostConfig()
755
-
756
-	container.NetworkSettings.Ports = bindings
757
-
758
-	container.NetworkSettings.Bridge = env.Get("Bridge")
759
-	container.NetworkSettings.IPAddress = env.Get("IP")
760
-	container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
761
-	container.NetworkSettings.Gateway = env.Get("Gateway")
762
-
763
-	return nil
764
-}
765
-
766
-func (container *Container) releaseNetwork() {
767
-	if container.Config.NetworkDisabled {
768
-		return
769
-	}
770
-	eng := container.runtime.eng
771
-
772
-	eng.Job("release_interface", container.ID).Run()
773
-	container.NetworkSettings = &NetworkSettings{}
774
-}
775
-
776
-func (container *Container) monitor(callback execdriver.StartCallback) error {
777
-	var (
778
-		err      error
779
-		exitCode int
780
-	)
781
-
782
-	pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
783
-	exitCode, err = container.runtime.Run(container, pipes, callback)
784
-	if err != nil {
785
-		utils.Errorf("Error running container: %s", err)
786
-	}
787
-
788
-	if container.runtime.srv.IsRunning() {
789
-		container.State.SetStopped(exitCode)
790
-
791
-		// FIXME: there is a race condition here which causes this to fail during the unit tests.
792
-		// If another goroutine was waiting for Wait() to return before removing the container's root
793
-		// from the filesystem... At this point it may already have done so.
794
-		// This is because State.setStopped() has already been called, and has caused Wait()
795
-		// to return.
796
-		// FIXME: why are we serializing running state to disk in the first place?
797
-		//log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
798
-		if err := container.ToDisk(); err != nil {
799
-			utils.Errorf("Error dumping container state to disk: %s\n", err)
800
-		}
801
-	}
802
-
803
-	// Cleanup
804
-	container.cleanup()
805
-
806
-	// Re-create a brand new stdin pipe once the container exited
807
-	if container.Config.OpenStdin {
808
-		container.stdin, container.stdinPipe = io.Pipe()
809
-	}
810
-
811
-	if container.runtime != nil && container.runtime.srv != nil {
812
-		container.runtime.srv.LogEvent("die", container.ID, container.runtime.repositories.ImageName(container.Image))
813
-	}
814
-
815
-	close(container.waitLock)
816
-
817
-	return err
818
-}
819
-
820
-func (container *Container) cleanup() {
821
-	container.releaseNetwork()
822
-
823
-	// Disable all active links
824
-	if container.activeLinks != nil {
825
-		for _, link := range container.activeLinks {
826
-			link.Disable()
827
-		}
828
-	}
829
-	if container.Config.OpenStdin {
830
-		if err := container.stdin.Close(); err != nil {
831
-			utils.Errorf("%s: Error close stdin: %s", container.ID, err)
832
-		}
833
-	}
834
-	if err := container.stdout.CloseWriters(); err != nil {
835
-		utils.Errorf("%s: Error close stdout: %s", container.ID, err)
836
-	}
837
-	if err := container.stderr.CloseWriters(); err != nil {
838
-		utils.Errorf("%s: Error close stderr: %s", container.ID, err)
839
-	}
840
-	if container.command != nil && container.command.Terminal != nil {
841
-		if err := container.command.Terminal.Close(); err != nil {
842
-			utils.Errorf("%s: Error closing terminal: %s", container.ID, err)
843
-		}
844
-	}
845
-
846
-	unmountVolumesForContainer(container)
847
-
848
-	if err := container.Unmount(); err != nil {
849
-		log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
850
-	}
851
-}
852
-
853
-func (container *Container) kill(sig int) error {
854
-	container.Lock()
855
-	defer container.Unlock()
856
-
857
-	if !container.State.IsRunning() {
858
-		return nil
859
-	}
860
-	return container.runtime.Kill(container, sig)
861
-}
862
-
863
-func (container *Container) Kill() error {
864
-	if !container.State.IsRunning() {
865
-		return nil
866
-	}
867
-
868
-	// 1. Send SIGKILL
869
-	if err := container.kill(9); err != nil {
870
-		return err
871
-	}
872
-
873
-	// 2. Wait for the process to die, in last resort, try to kill the process directly
874
-	if err := container.WaitTimeout(10 * time.Second); err != nil {
875
-		if container.command == nil {
876
-			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", utils.TruncateID(container.ID))
877
-		}
878
-		log.Printf("Container %s failed to exit within 10 seconds of lxc-kill %s - trying direct SIGKILL", "SIGKILL", utils.TruncateID(container.ID))
879
-		if err := container.runtime.Kill(container, 9); err != nil {
880
-			return err
881
-		}
882
-	}
883
-
884
-	container.Wait()
885
-	return nil
886
-}
887
-
888
-func (container *Container) Stop(seconds int) error {
889
-	if !container.State.IsRunning() {
890
-		return nil
891
-	}
892
-
893
-	// 1. Send a SIGTERM
894
-	if err := container.kill(15); err != nil {
895
-		utils.Debugf("Error sending kill SIGTERM: %s", err)
896
-		log.Print("Failed to send SIGTERM to the process, force killing")
897
-		if err := container.kill(9); err != nil {
898
-			return err
899
-		}
900
-	}
901
-
902
-	// 2. Wait for the process to exit on its own
903
-	if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
904
-		log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
905
-		// 3. If it doesn't, then send SIGKILL
906
-		if err := container.Kill(); err != nil {
907
-			return err
908
-		}
909
-	}
910
-	return nil
911
-}
912
-
913
-func (container *Container) Restart(seconds int) error {
914
-	// Avoid unnecessarily unmounting and then directly mounting
915
-	// the container when the container stops and then starts
916
-	// again
917
-	if err := container.Mount(); err == nil {
918
-		defer container.Unmount()
919
-	}
920
-
921
-	if err := container.Stop(seconds); err != nil {
922
-		return err
923
-	}
924
-	return container.Start()
925
-}
926
-
927
-// Wait blocks until the container stops running, then returns its exit code.
928
-func (container *Container) Wait() int {
929
-	<-container.waitLock
930
-	return container.State.GetExitCode()
931
-}
932
-
933
-func (container *Container) Resize(h, w int) error {
934
-	return container.command.Terminal.Resize(h, w)
935
-}
936
-
937
-func (container *Container) ExportRw() (archive.Archive, error) {
938
-	if err := container.Mount(); err != nil {
939
-		return nil, err
940
-	}
941
-	if container.runtime == nil {
942
-		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
943
-	}
944
-	archive, err := container.runtime.Diff(container)
945
-	if err != nil {
946
-		container.Unmount()
947
-		return nil, err
948
-	}
949
-	return utils.NewReadCloserWrapper(archive, func() error {
950
-		err := archive.Close()
951
-		container.Unmount()
952
-		return err
953
-	}), nil
954
-}
955
-
956
-func (container *Container) Export() (archive.Archive, error) {
957
-	if err := container.Mount(); err != nil {
958
-		return nil, err
959
-	}
960
-
961
-	archive, err := archive.Tar(container.basefs, archive.Uncompressed)
962
-	if err != nil {
963
-		container.Unmount()
964
-		return nil, err
965
-	}
966
-	return utils.NewReadCloserWrapper(archive, func() error {
967
-		err := archive.Close()
968
-		container.Unmount()
969
-		return err
970
-	}), nil
971
-}
972
-
973
-func (container *Container) WaitTimeout(timeout time.Duration) error {
974
-	done := make(chan bool)
975
-	go func() {
976
-		container.Wait()
977
-		done <- true
978
-	}()
979
-
980
-	select {
981
-	case <-time.After(timeout):
982
-		return fmt.Errorf("Timed Out")
983
-	case <-done:
984
-		return nil
985
-	}
986
-}
987
-
988
-func (container *Container) Mount() error {
989
-	return container.runtime.Mount(container)
990
-}
991
-
992
-func (container *Container) Changes() ([]archive.Change, error) {
993
-	return container.runtime.Changes(container)
994
-}
995
-
996
-func (container *Container) GetImage() (*image.Image, error) {
997
-	if container.runtime == nil {
998
-		return nil, fmt.Errorf("Can't get image of unregistered container")
999
-	}
1000
-	return container.runtime.graph.Get(container.Image)
1001
-}
1002
-
1003
-func (container *Container) Unmount() error {
1004
-	return container.runtime.Unmount(container)
1005
-}
1006
-
1007
-func (container *Container) logPath(name string) string {
1008
-	return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.ID, name))
1009
-}
1010
-
1011
-func (container *Container) ReadLog(name string) (io.Reader, error) {
1012
-	return os.Open(container.logPath(name))
1013
-}
1014
-
1015
-func (container *Container) hostConfigPath() string {
1016
-	return path.Join(container.root, "hostconfig.json")
1017
-}
1018
-
1019
-func (container *Container) jsonPath() string {
1020
-	return path.Join(container.root, "config.json")
1021
-}
1022
-
1023
-func (container *Container) EnvConfigPath() (string, error) {
1024
-	p := path.Join(container.root, "config.env")
1025
-	if _, err := os.Stat(p); err != nil {
1026
-		if os.IsNotExist(err) {
1027
-			f, err := os.Create(p)
1028
-			if err != nil {
1029
-				return "", err
1030
-			}
1031
-			f.Close()
1032
-		} else {
1033
-			return "", err
1034
-		}
1035
-	}
1036
-	return p, nil
1037
-}
1038
-
1039
-// This method must be exported to be used from the lxc template
1040
-// This directory is only usable when the container is running
1041
-func (container *Container) RootfsPath() string {
1042
-	return path.Join(container.root, "root")
1043
-}
1044
-
1045
-// This is the stand-alone version of the root fs, without any additional mounts.
1046
-// This directory is usable whenever the container is mounted (and not unmounted)
1047
-func (container *Container) BasefsPath() string {
1048
-	return container.basefs
1049
-}
1050
-
1051
-func validateID(id string) error {
1052
-	if id == "" {
1053
-		return fmt.Errorf("Invalid empty id")
1054
-	}
1055
-	return nil
1056
-}
1057
-
1058
-// GetSize, return real size, virtual size
1059
-func (container *Container) GetSize() (int64, int64) {
1060
-	var (
1061
-		sizeRw, sizeRootfs int64
1062
-		err                error
1063
-		driver             = container.runtime.driver
1064
-	)
1065
-
1066
-	if err := container.Mount(); err != nil {
1067
-		utils.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err)
1068
-		return sizeRw, sizeRootfs
1069
-	}
1070
-	defer container.Unmount()
1071
-
1072
-	if differ, ok := container.runtime.driver.(graphdriver.Differ); ok {
1073
-		sizeRw, err = differ.DiffSize(container.ID)
1074
-		if err != nil {
1075
-			utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
1076
-			// FIXME: GetSize should return an error. Not changing it now in case
1077
-			// there is a side-effect.
1078
-			sizeRw = -1
1079
-		}
1080
-	} else {
1081
-		changes, _ := container.Changes()
1082
-		if changes != nil {
1083
-			sizeRw = archive.ChangesSize(container.basefs, changes)
1084
-		} else {
1085
-			sizeRw = -1
1086
-		}
1087
-	}
1088
-
1089
-	if _, err = os.Stat(container.basefs); err != nil {
1090
-		if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil {
1091
-			sizeRootfs = -1
1092
-		}
1093
-	}
1094
-	return sizeRw, sizeRootfs
1095
-}
1096
-
1097
-func (container *Container) Copy(resource string) (io.ReadCloser, error) {
1098
-	if err := container.Mount(); err != nil {
1099
-		return nil, err
1100
-	}
1101
-	var filter []string
1102
-	basePath := path.Join(container.basefs, resource)
1103
-	stat, err := os.Stat(basePath)
1104
-	if err != nil {
1105
-		container.Unmount()
1106
-		return nil, err
1107
-	}
1108
-	if !stat.IsDir() {
1109
-		d, f := path.Split(basePath)
1110
-		basePath = d
1111
-		filter = []string{f}
1112
-	} else {
1113
-		filter = []string{path.Base(basePath)}
1114
-		basePath = path.Dir(basePath)
1115
-	}
1116
-
1117
-	archive, err := archive.TarFilter(basePath, &archive.TarOptions{
1118
-		Compression: archive.Uncompressed,
1119
-		Includes:    filter,
1120
-	})
1121
-	if err != nil {
1122
-		return nil, err
1123
-	}
1124
-	return utils.NewReadCloserWrapper(archive, func() error {
1125
-		err := archive.Close()
1126
-		container.Unmount()
1127
-		return err
1128
-	}), nil
1129
-}
1130
-
1131
-// Returns true if the container exposes a certain port
1132
-func (container *Container) Exposes(p nat.Port) bool {
1133
-	_, exists := container.Config.ExposedPorts[p]
1134
-	return exists
1135
-}
1136
-
1137
-func (container *Container) GetPtyMaster() (*os.File, error) {
1138
-	ttyConsole, ok := container.command.Terminal.(execdriver.TtyTerminal)
1139
-	if !ok {
1140
-		return nil, ErrNoTTY
1141
-	}
1142
-	return ttyConsole.Master(), nil
1143
-}
1144 1
deleted file mode 100644
... ...
@@ -1,145 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"github.com/dotcloud/docker/nat"
5
-	"testing"
6
-)
7
-
8
-func TestParseNetworkOptsPrivateOnly(t *testing.T) {
9
-	ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::80"})
10
-	if err != nil {
11
-		t.Fatal(err)
12
-	}
13
-	if len(ports) != 1 {
14
-		t.Logf("Expected 1 got %d", len(ports))
15
-		t.FailNow()
16
-	}
17
-	if len(bindings) != 1 {
18
-		t.Logf("Expected 1 got %d", len(bindings))
19
-		t.FailNow()
20
-	}
21
-	for k := range ports {
22
-		if k.Proto() != "tcp" {
23
-			t.Logf("Expected tcp got %s", k.Proto())
24
-			t.Fail()
25
-		}
26
-		if k.Port() != "80" {
27
-			t.Logf("Expected 80 got %s", k.Port())
28
-			t.Fail()
29
-		}
30
-		b, exists := bindings[k]
31
-		if !exists {
32
-			t.Log("Binding does not exist")
33
-			t.FailNow()
34
-		}
35
-		if len(b) != 1 {
36
-			t.Logf("Expected 1 got %d", len(b))
37
-			t.FailNow()
38
-		}
39
-		s := b[0]
40
-		if s.HostPort != "" {
41
-			t.Logf("Expected \"\" got %s", s.HostPort)
42
-			t.Fail()
43
-		}
44
-		if s.HostIp != "192.168.1.100" {
45
-			t.Fail()
46
-		}
47
-	}
48
-}
49
-
50
-func TestParseNetworkOptsPublic(t *testing.T) {
51
-	ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100:8080:80"})
52
-	if err != nil {
53
-		t.Fatal(err)
54
-	}
55
-	if len(ports) != 1 {
56
-		t.Logf("Expected 1 got %d", len(ports))
57
-		t.FailNow()
58
-	}
59
-	if len(bindings) != 1 {
60
-		t.Logf("Expected 1 got %d", len(bindings))
61
-		t.FailNow()
62
-	}
63
-	for k := range ports {
64
-		if k.Proto() != "tcp" {
65
-			t.Logf("Expected tcp got %s", k.Proto())
66
-			t.Fail()
67
-		}
68
-		if k.Port() != "80" {
69
-			t.Logf("Expected 80 got %s", k.Port())
70
-			t.Fail()
71
-		}
72
-		b, exists := bindings[k]
73
-		if !exists {
74
-			t.Log("Binding does not exist")
75
-			t.FailNow()
76
-		}
77
-		if len(b) != 1 {
78
-			t.Logf("Expected 1 got %d", len(b))
79
-			t.FailNow()
80
-		}
81
-		s := b[0]
82
-		if s.HostPort != "8080" {
83
-			t.Logf("Expected 8080 got %s", s.HostPort)
84
-			t.Fail()
85
-		}
86
-		if s.HostIp != "192.168.1.100" {
87
-			t.Fail()
88
-		}
89
-	}
90
-}
91
-
92
-func TestParseNetworkOptsUdp(t *testing.T) {
93
-	ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
94
-	if err != nil {
95
-		t.Fatal(err)
96
-	}
97
-	if len(ports) != 1 {
98
-		t.Logf("Expected 1 got %d", len(ports))
99
-		t.FailNow()
100
-	}
101
-	if len(bindings) != 1 {
102
-		t.Logf("Expected 1 got %d", len(bindings))
103
-		t.FailNow()
104
-	}
105
-	for k := range ports {
106
-		if k.Proto() != "udp" {
107
-			t.Logf("Expected udp got %s", k.Proto())
108
-			t.Fail()
109
-		}
110
-		if k.Port() != "6000" {
111
-			t.Logf("Expected 6000 got %s", k.Port())
112
-			t.Fail()
113
-		}
114
-		b, exists := bindings[k]
115
-		if !exists {
116
-			t.Log("Binding does not exist")
117
-			t.FailNow()
118
-		}
119
-		if len(b) != 1 {
120
-			t.Logf("Expected 1 got %d", len(b))
121
-			t.FailNow()
122
-		}
123
-		s := b[0]
124
-		if s.HostPort != "" {
125
-			t.Logf("Expected \"\" got %s", s.HostPort)
126
-			t.Fail()
127
-		}
128
-		if s.HostIp != "192.168.1.100" {
129
-			t.Fail()
130
-		}
131
-	}
132
-}
133
-
134
-func TestGetFullName(t *testing.T) {
135
-	name, err := getFullName("testing")
136
-	if err != nil {
137
-		t.Fatal(err)
138
-	}
139
-	if name != "/testing" {
140
-		t.Fatalf("Expected /testing got %s", name)
141
-	}
142
-	if _, err := getFullName(""); err == nil {
143
-		t.Fatal("Error should not be nil")
144
-	}
145
-}
... ...
@@ -5,12 +5,12 @@ import (
5 5
 	"bytes"
6 6
 	"encoding/json"
7 7
 	"fmt"
8
-	"github.com/dotcloud/docker"
9 8
 	"github.com/dotcloud/docker/api"
10 9
 	"github.com/dotcloud/docker/dockerversion"
11 10
 	"github.com/dotcloud/docker/engine"
12 11
 	"github.com/dotcloud/docker/image"
13 12
 	"github.com/dotcloud/docker/runconfig"
13
+	"github.com/dotcloud/docker/runtime"
14 14
 	"github.com/dotcloud/docker/utils"
15 15
 	"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
16 16
 	"io"
... ...
@@ -600,7 +600,7 @@ func TestGetContainersByName(t *testing.T) {
600 600
 		t.Fatal(err)
601 601
 	}
602 602
 	assertHttpNotError(r, t)
603
-	outContainer := &docker.Container{}
603
+	outContainer := &runtime.Container{}
604 604
 	if err := json.Unmarshal(r.Body.Bytes(), outContainer); err != nil {
605 605
 		t.Fatal(err)
606 606
 	}
... ...
@@ -3,11 +3,11 @@ package docker
3 3
 import (
4 4
 	"bufio"
5 5
 	"fmt"
6
-	"github.com/dotcloud/docker"
7 6
 	"github.com/dotcloud/docker/api"
8 7
 	"github.com/dotcloud/docker/engine"
9 8
 	"github.com/dotcloud/docker/image"
10 9
 	"github.com/dotcloud/docker/pkg/term"
10
+	"github.com/dotcloud/docker/runtime"
11 11
 	"github.com/dotcloud/docker/utils"
12 12
 	"io"
13 13
 	"io/ioutil"
... ...
@@ -36,7 +36,7 @@ func closeWrap(args ...io.Closer) error {
36 36
 	return nil
37 37
 }
38 38
 
39
-func setRaw(t *testing.T, c *docker.Container) *term.State {
39
+func setRaw(t *testing.T, c *runtime.Container) *term.State {
40 40
 	pty, err := c.GetPtyMaster()
41 41
 	if err != nil {
42 42
 		t.Fatal(err)
... ...
@@ -48,7 +48,7 @@ func setRaw(t *testing.T, c *docker.Container) *term.State {
48 48
 	return state
49 49
 }
50 50
 
51
-func unsetRaw(t *testing.T, c *docker.Container, state *term.State) {
51
+func unsetRaw(t *testing.T, c *runtime.Container, state *term.State) {
52 52
 	pty, err := c.GetPtyMaster()
53 53
 	if err != nil {
54 54
 		t.Fatal(err)
... ...
@@ -56,8 +56,8 @@ func unsetRaw(t *testing.T, c *docker.Container, state *term.State) {
56 56
 	term.RestoreTerminal(pty.Fd(), state)
57 57
 }
58 58
 
59
-func waitContainerStart(t *testing.T, timeout time.Duration) *docker.Container {
60
-	var container *docker.Container
59
+func waitContainerStart(t *testing.T, timeout time.Duration) *runtime.Container {
60
+	var container *runtime.Container
61 61
 
62 62
 	setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
63 63
 		for {
... ...
@@ -3,11 +3,11 @@ package docker
3 3
 import (
4 4
 	"bytes"
5 5
 	"fmt"
6
-	"github.com/dotcloud/docker"
7 6
 	"github.com/dotcloud/docker/engine"
8 7
 	"github.com/dotcloud/docker/image"
9 8
 	"github.com/dotcloud/docker/nat"
10 9
 	"github.com/dotcloud/docker/runconfig"
10
+	"github.com/dotcloud/docker/runtime"
11 11
 	"github.com/dotcloud/docker/sysinit"
12 12
 	"github.com/dotcloud/docker/utils"
13 13
 	"io"
... ...
@@ -16,7 +16,7 @@ import (
16 16
 	"net/url"
17 17
 	"os"
18 18
 	"path/filepath"
19
-	"runtime"
19
+	goruntime "runtime"
20 20
 	"strconv"
21 21
 	"strings"
22 22
 	"syscall"
... ...
@@ -36,14 +36,14 @@ const (
36 36
 
37 37
 var (
38 38
 	// FIXME: globalRuntime is deprecated by globalEngine. All tests should be converted.
39
-	globalRuntime   *docker.Runtime
39
+	globalRuntime   *runtime.Runtime
40 40
 	globalEngine    *engine.Engine
41 41
 	startFds        int
42 42
 	startGoroutines int
43 43
 )
44 44
 
45 45
 // FIXME: nuke() is deprecated by Runtime.Nuke()
46
-func nuke(runtime *docker.Runtime) error {
46
+func nuke(runtime *runtime.Runtime) error {
47 47
 	return runtime.Nuke()
48 48
 }
49 49
 
... ...
@@ -120,7 +120,7 @@ func init() {
120 120
 
121 121
 	// Create the "global runtime" with a long-running daemon for integration tests
122 122
 	spawnGlobalDaemon()
123
-	startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
123
+	startFds, startGoroutines = utils.GetTotalUsedFds(), goruntime.NumGoroutine()
124 124
 }
125 125
 
126 126
 func setupBaseImage() {
... ...
@@ -173,7 +173,7 @@ func spawnGlobalDaemon() {
173 173
 
174 174
 // FIXME: test that ImagePull(json=true) send correct json output
175 175
 
176
-func GetTestImage(runtime *docker.Runtime) *image.Image {
176
+func GetTestImage(runtime *runtime.Runtime) *image.Image {
177 177
 	imgs, err := runtime.Graph().Map()
178 178
 	if err != nil {
179 179
 		log.Fatalf("Unable to get the test image: %s", err)
... ...
@@ -357,7 +357,7 @@ func TestGet(t *testing.T) {
357 357
 
358 358
 }
359 359
 
360
-func startEchoServerContainer(t *testing.T, proto string) (*docker.Runtime, *docker.Container, string) {
360
+func startEchoServerContainer(t *testing.T, proto string) (*runtime.Runtime, *runtime.Container, string) {
361 361
 	var (
362 362
 		err     error
363 363
 		id      string
... ...
@@ -18,6 +18,7 @@ import (
18 18
 	"github.com/dotcloud/docker/builtins"
19 19
 	"github.com/dotcloud/docker/engine"
20 20
 	"github.com/dotcloud/docker/runconfig"
21
+	"github.com/dotcloud/docker/runtime"
21 22
 	"github.com/dotcloud/docker/utils"
22 23
 )
23 24
 
... ...
@@ -27,7 +28,7 @@ import (
27 27
 
28 28
 // Create a temporary runtime suitable for unit testing.
29 29
 // Call t.Fatal() at the first error.
30
-func mkRuntime(f utils.Fataler) *docker.Runtime {
30
+func mkRuntime(f utils.Fataler) *runtime.Runtime {
31 31
 	eng := newTestEngine(f, false, "")
32 32
 	return mkRuntimeFromEngine(eng, f)
33 33
 	// FIXME:
... ...
@@ -139,7 +140,7 @@ func assertHttpError(r *httptest.ResponseRecorder, t utils.Fataler) {
139 139
 	}
140 140
 }
141 141
 
142
-func getContainer(eng *engine.Engine, id string, t utils.Fataler) *docker.Container {
142
+func getContainer(eng *engine.Engine, id string, t utils.Fataler) *runtime.Container {
143 143
 	runtime := mkRuntimeFromEngine(eng, t)
144 144
 	c := runtime.Get(id)
145 145
 	if c == nil {
... ...
@@ -160,14 +161,14 @@ func mkServerFromEngine(eng *engine.Engine, t utils.Fataler) *docker.Server {
160 160
 	return srv
161 161
 }
162 162
 
163
-func mkRuntimeFromEngine(eng *engine.Engine, t utils.Fataler) *docker.Runtime {
163
+func mkRuntimeFromEngine(eng *engine.Engine, t utils.Fataler) *runtime.Runtime {
164 164
 	iRuntime := eng.Hack_GetGlobalVar("httpapi.runtime")
165 165
 	if iRuntime == nil {
166 166
 		panic("Legacy runtime field not set in engine")
167 167
 	}
168
-	runtime, ok := iRuntime.(*docker.Runtime)
168
+	runtime, ok := iRuntime.(*runtime.Runtime)
169 169
 	if !ok {
170
-		panic("Legacy runtime field in engine does not cast to *docker.Runtime")
170
+		panic("Legacy runtime field in engine does not cast to *runtime.Runtime")
171 171
 	}
172 172
 	return runtime
173 173
 }
... ...
@@ -249,7 +250,7 @@ func readFile(src string, t *testing.T) (content string) {
249 249
 // dynamically replaced by the current test image.
250 250
 // The caller is responsible for destroying the container.
251 251
 // Call t.Fatal() at the first error.
252
-func mkContainer(r *docker.Runtime, args []string, t *testing.T) (*docker.Container, *runconfig.HostConfig, error) {
252
+func mkContainer(r *runtime.Runtime, args []string, t *testing.T) (*runtime.Container, *runconfig.HostConfig, error) {
253 253
 	config, hc, _, err := runconfig.Parse(args, nil)
254 254
 	defer func() {
255 255
 		if err != nil && t != nil {
... ...
@@ -280,7 +281,7 @@ func mkContainer(r *docker.Runtime, args []string, t *testing.T) (*docker.Contai
280 280
 // and return its standard output as a string.
281 281
 // The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
282 282
 // If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally.
283
-func runContainer(eng *engine.Engine, r *docker.Runtime, args []string, t *testing.T) (output string, err error) {
283
+func runContainer(eng *engine.Engine, r *runtime.Runtime, args []string, t *testing.T) (output string, err error) {
284 284
 	defer func() {
285 285
 		if err != nil && t != nil {
286 286
 			t.Fatal(err)
287 287
deleted file mode 100644
... ...
@@ -1,918 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"container/list"
5
-	"fmt"
6
-	"github.com/dotcloud/docker/archive"
7
-	"github.com/dotcloud/docker/daemonconfig"
8
-	"github.com/dotcloud/docker/dockerversion"
9
-	"github.com/dotcloud/docker/engine"
10
-	"github.com/dotcloud/docker/execdriver"
11
-	"github.com/dotcloud/docker/execdriver/lxc"
12
-	"github.com/dotcloud/docker/execdriver/native"
13
-	"github.com/dotcloud/docker/graph"
14
-	"github.com/dotcloud/docker/graphdriver"
15
-	"github.com/dotcloud/docker/graphdriver/aufs"
16
-	_ "github.com/dotcloud/docker/graphdriver/btrfs"
17
-	_ "github.com/dotcloud/docker/graphdriver/devmapper"
18
-	_ "github.com/dotcloud/docker/graphdriver/vfs"
19
-	"github.com/dotcloud/docker/image"
20
-	_ "github.com/dotcloud/docker/networkdriver/lxc"
21
-	"github.com/dotcloud/docker/networkdriver/portallocator"
22
-	"github.com/dotcloud/docker/pkg/graphdb"
23
-	"github.com/dotcloud/docker/pkg/sysinfo"
24
-	"github.com/dotcloud/docker/runconfig"
25
-	"github.com/dotcloud/docker/utils"
26
-	"io"
27
-	"io/ioutil"
28
-	"os"
29
-	"path"
30
-	"regexp"
31
-	"sort"
32
-	"strings"
33
-	"sync"
34
-	"time"
35
-)
36
-
37
-// Set the max depth to the aufs default that most
38
-// kernels are compiled with
39
-// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
40
-const MaxImageDepth = 127
41
-
42
-var (
43
-	defaultDns                = []string{"8.8.8.8", "8.8.4.4"}
44
-	validContainerNameChars   = `[a-zA-Z0-9_.-]`
45
-	validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
46
-)
47
-
48
-type Runtime struct {
49
-	repository     string
50
-	sysInitPath    string
51
-	containers     *list.List
52
-	graph          *graph.Graph
53
-	repositories   *graph.TagStore
54
-	idIndex        *utils.TruncIndex
55
-	sysInfo        *sysinfo.SysInfo
56
-	volumes        *graph.Graph
57
-	srv            *Server
58
-	eng            *engine.Engine
59
-	config         *daemonconfig.Config
60
-	containerGraph *graphdb.Database
61
-	driver         graphdriver.Driver
62
-	execDriver     execdriver.Driver
63
-}
64
-
65
-// List returns an array of all containers registered in the runtime.
66
-func (runtime *Runtime) List() []*Container {
67
-	containers := new(History)
68
-	for e := runtime.containers.Front(); e != nil; e = e.Next() {
69
-		containers.Add(e.Value.(*Container))
70
-	}
71
-	return *containers
72
-}
73
-
74
-func (runtime *Runtime) getContainerElement(id string) *list.Element {
75
-	for e := runtime.containers.Front(); e != nil; e = e.Next() {
76
-		container := e.Value.(*Container)
77
-		if container.ID == id {
78
-			return e
79
-		}
80
-	}
81
-	return nil
82
-}
83
-
84
-// Get looks for a container by the specified ID or name, and returns it.
85
-// If the container is not found, or if an error occurs, nil is returned.
86
-func (runtime *Runtime) Get(name string) *Container {
87
-	if c, _ := runtime.GetByName(name); c != nil {
88
-		return c
89
-	}
90
-
91
-	id, err := runtime.idIndex.Get(name)
92
-	if err != nil {
93
-		return nil
94
-	}
95
-
96
-	e := runtime.getContainerElement(id)
97
-	if e == nil {
98
-		return nil
99
-	}
100
-	return e.Value.(*Container)
101
-}
102
-
103
-// Exists returns a true if a container of the specified ID or name exists,
104
-// false otherwise.
105
-func (runtime *Runtime) Exists(id string) bool {
106
-	return runtime.Get(id) != nil
107
-}
108
-
109
-func (runtime *Runtime) containerRoot(id string) string {
110
-	return path.Join(runtime.repository, id)
111
-}
112
-
113
-// Load reads the contents of a container from disk
114
-// This is typically done at startup.
115
-func (runtime *Runtime) load(id string) (*Container, error) {
116
-	container := &Container{root: runtime.containerRoot(id)}
117
-	if err := container.FromDisk(); err != nil {
118
-		return nil, err
119
-	}
120
-	if container.ID != id {
121
-		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
122
-	}
123
-	if container.State.IsRunning() {
124
-		container.State.SetGhost(true)
125
-	}
126
-	return container, nil
127
-}
128
-
129
-// Register makes a container object usable by the runtime as <container.ID>
130
-func (runtime *Runtime) Register(container *Container) error {
131
-	if container.runtime != nil || runtime.Exists(container.ID) {
132
-		return fmt.Errorf("Container is already loaded")
133
-	}
134
-	if err := validateID(container.ID); err != nil {
135
-		return err
136
-	}
137
-	if err := runtime.ensureName(container); err != nil {
138
-		return err
139
-	}
140
-
141
-	container.runtime = runtime
142
-
143
-	// Attach to stdout and stderr
144
-	container.stderr = utils.NewWriteBroadcaster()
145
-	container.stdout = utils.NewWriteBroadcaster()
146
-	// Attach to stdin
147
-	if container.Config.OpenStdin {
148
-		container.stdin, container.stdinPipe = io.Pipe()
149
-	} else {
150
-		container.stdinPipe = utils.NopWriteCloser(ioutil.Discard) // Silently drop stdin
151
-	}
152
-	// done
153
-	runtime.containers.PushBack(container)
154
-	runtime.idIndex.Add(container.ID)
155
-
156
-	// FIXME: if the container is supposed to be running but is not, auto restart it?
157
-	//        if so, then we need to restart monitor and init a new lock
158
-	// If the container is supposed to be running, make sure of it
159
-	if container.State.IsRunning() {
160
-		if container.State.IsGhost() {
161
-			utils.Debugf("killing ghost %s", container.ID)
162
-
163
-			existingPid := container.State.Pid
164
-			container.State.SetGhost(false)
165
-			container.State.SetStopped(0)
166
-
167
-			if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") {
168
-				lxc.KillLxc(container.ID, 9)
169
-			} else {
170
-				command := &execdriver.Command{
171
-					ID: container.ID,
172
-				}
173
-				command.Process = &os.Process{Pid: existingPid}
174
-				runtime.execDriver.Kill(command, 9)
175
-			}
176
-			// ensure that the filesystem is also unmounted
177
-			unmountVolumesForContainer(container)
178
-			if err := container.Unmount(); err != nil {
179
-				utils.Debugf("ghost unmount error %s", err)
180
-			}
181
-		}
182
-
183
-		info := runtime.execDriver.Info(container.ID)
184
-		if !info.IsRunning() {
185
-			utils.Debugf("Container %s was supposed to be running but is not.", container.ID)
186
-			if runtime.config.AutoRestart {
187
-				utils.Debugf("Restarting")
188
-				unmountVolumesForContainer(container)
189
-				if err := container.Unmount(); err != nil {
190
-					utils.Debugf("restart unmount error %s", err)
191
-				}
192
-
193
-				container.State.SetGhost(false)
194
-				container.State.SetStopped(0)
195
-				if err := container.Start(); err != nil {
196
-					return err
197
-				}
198
-			} else {
199
-				utils.Debugf("Marking as stopped")
200
-				container.State.SetStopped(-127)
201
-				if err := container.ToDisk(); err != nil {
202
-					return err
203
-				}
204
-			}
205
-		}
206
-	} else {
207
-		// When the container is not running, we still initialize the waitLock
208
-		// chan and close it. Receiving on nil chan blocks whereas receiving on a
209
-		// closed chan does not. In this case we do not want to block.
210
-		container.waitLock = make(chan struct{})
211
-		close(container.waitLock)
212
-	}
213
-	return nil
214
-}
215
-
216
-func (runtime *Runtime) ensureName(container *Container) error {
217
-	if container.Name == "" {
218
-		name, err := generateRandomName(runtime)
219
-		if err != nil {
220
-			name = utils.TruncateID(container.ID)
221
-		}
222
-		container.Name = name
223
-
224
-		if err := container.ToDisk(); err != nil {
225
-			utils.Debugf("Error saving container name %s", err)
226
-		}
227
-		if !runtime.containerGraph.Exists(name) {
228
-			if _, err := runtime.containerGraph.Set(name, container.ID); err != nil {
229
-				utils.Debugf("Setting default id - %s", err)
230
-			}
231
-		}
232
-	}
233
-	return nil
234
-}
235
-
236
-func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
237
-	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
238
-	if err != nil {
239
-		return err
240
-	}
241
-	src.AddWriter(log, stream)
242
-	return nil
243
-}
244
-
245
-// Destroy unregisters a container from the runtime and cleanly removes its contents from the filesystem.
246
-func (runtime *Runtime) Destroy(container *Container) error {
247
-	if container == nil {
248
-		return fmt.Errorf("The given container is <nil>")
249
-	}
250
-
251
-	element := runtime.getContainerElement(container.ID)
252
-	if element == nil {
253
-		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
254
-	}
255
-
256
-	if err := container.Stop(3); err != nil {
257
-		return err
258
-	}
259
-
260
-	if err := runtime.driver.Remove(container.ID); err != nil {
261
-		return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", runtime.driver, container.ID, err)
262
-	}
263
-
264
-	initID := fmt.Sprintf("%s-init", container.ID)
265
-	if err := runtime.driver.Remove(initID); err != nil {
266
-		return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", runtime.driver, initID, err)
267
-	}
268
-
269
-	if _, err := runtime.containerGraph.Purge(container.ID); err != nil {
270
-		utils.Debugf("Unable to remove container from link graph: %s", err)
271
-	}
272
-
273
-	// Deregister the container before removing its directory, to avoid race conditions
274
-	runtime.idIndex.Delete(container.ID)
275
-	runtime.containers.Remove(element)
276
-	if err := os.RemoveAll(container.root); err != nil {
277
-		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
278
-	}
279
-	return nil
280
-}
281
-
282
-func (runtime *Runtime) restore() error {
283
-	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
284
-		fmt.Printf("Loading containers: ")
285
-	}
286
-	dir, err := ioutil.ReadDir(runtime.repository)
287
-	if err != nil {
288
-		return err
289
-	}
290
-	containers := make(map[string]*Container)
291
-	currentDriver := runtime.driver.String()
292
-
293
-	for _, v := range dir {
294
-		id := v.Name()
295
-		container, err := runtime.load(id)
296
-		if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
297
-			fmt.Print(".")
298
-		}
299
-		if err != nil {
300
-			utils.Errorf("Failed to load container %v: %v", id, err)
301
-			continue
302
-		}
303
-
304
-		// Ignore the container if it does not support the current driver being used by the graph
305
-		if container.Driver == "" && currentDriver == "aufs" || container.Driver == currentDriver {
306
-			utils.Debugf("Loaded container %v", container.ID)
307
-			containers[container.ID] = container
308
-		} else {
309
-			utils.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID)
310
-		}
311
-	}
312
-
313
-	register := func(container *Container) {
314
-		if err := runtime.Register(container); err != nil {
315
-			utils.Debugf("Failed to register container %s: %s", container.ID, err)
316
-		}
317
-	}
318
-
319
-	if entities := runtime.containerGraph.List("/", -1); entities != nil {
320
-		for _, p := range entities.Paths() {
321
-			if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
322
-				fmt.Print(".")
323
-			}
324
-			e := entities[p]
325
-			if container, ok := containers[e.ID()]; ok {
326
-				register(container)
327
-				delete(containers, e.ID())
328
-			}
329
-		}
330
-	}
331
-
332
-	// Any containers that are left over do not exist in the graph
333
-	for _, container := range containers {
334
-		// Try to set the default name for a container if it exists prior to links
335
-		container.Name, err = generateRandomName(runtime)
336
-		if err != nil {
337
-			container.Name = utils.TruncateID(container.ID)
338
-		}
339
-
340
-		if _, err := runtime.containerGraph.Set(container.Name, container.ID); err != nil {
341
-			utils.Debugf("Setting default id - %s", err)
342
-		}
343
-		register(container)
344
-	}
345
-
346
-	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
347
-		fmt.Printf(": done.\n")
348
-	}
349
-
350
-	return nil
351
-}
352
-
353
-// Create creates a new container from the given configuration with a given name.
354
-func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Container, []string, error) {
355
-	// Lookup image
356
-	img, err := runtime.repositories.LookupImage(config.Image)
357
-	if err != nil {
358
-		return nil, nil, err
359
-	}
360
-
361
-	// We add 2 layers to the depth because the container's rw and
362
-	// init layer add to the restriction
363
-	depth, err := img.Depth()
364
-	if err != nil {
365
-		return nil, nil, err
366
-	}
367
-
368
-	if depth+2 >= MaxImageDepth {
369
-		return nil, nil, fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
370
-	}
371
-
372
-	checkDeprecatedExpose := func(config *runconfig.Config) bool {
373
-		if config != nil {
374
-			if config.PortSpecs != nil {
375
-				for _, p := range config.PortSpecs {
376
-					if strings.Contains(p, ":") {
377
-						return true
378
-					}
379
-				}
380
-			}
381
-		}
382
-		return false
383
-	}
384
-
385
-	warnings := []string{}
386
-	if checkDeprecatedExpose(img.Config) || checkDeprecatedExpose(config) {
387
-		warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.")
388
-	}
389
-
390
-	if img.Config != nil {
391
-		if err := runconfig.Merge(config, img.Config); err != nil {
392
-			return nil, nil, err
393
-		}
394
-	}
395
-
396
-	if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
397
-		return nil, nil, fmt.Errorf("No command specified")
398
-	}
399
-
400
-	// Generate id
401
-	id := utils.GenerateRandomID()
402
-
403
-	if name == "" {
404
-		name, err = generateRandomName(runtime)
405
-		if err != nil {
406
-			name = utils.TruncateID(id)
407
-		}
408
-	} else {
409
-		if !validContainerNamePattern.MatchString(name) {
410
-			return nil, nil, fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
411
-		}
412
-	}
413
-
414
-	if name[0] != '/' {
415
-		name = "/" + name
416
-	}
417
-
418
-	// Set the enitity in the graph using the default name specified
419
-	if _, err := runtime.containerGraph.Set(name, id); err != nil {
420
-		if !graphdb.IsNonUniqueNameError(err) {
421
-			return nil, nil, err
422
-		}
423
-
424
-		conflictingContainer, err := runtime.GetByName(name)
425
-		if err != nil {
426
-			if strings.Contains(err.Error(), "Could not find entity") {
427
-				return nil, nil, err
428
-			}
429
-
430
-			// Remove name and continue starting the container
431
-			if err := runtime.containerGraph.Delete(name); err != nil {
432
-				return nil, nil, err
433
-			}
434
-		} else {
435
-			nameAsKnownByUser := strings.TrimPrefix(name, "/")
436
-			return nil, nil, fmt.Errorf(
437
-				"Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser,
438
-				utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser)
439
-		}
440
-	}
441
-
442
-	// Generate default hostname
443
-	// FIXME: the lxc template no longer needs to set a default hostname
444
-	if config.Hostname == "" {
445
-		config.Hostname = id[:12]
446
-	}
447
-
448
-	var args []string
449
-	var entrypoint string
450
-
451
-	if len(config.Entrypoint) != 0 {
452
-		entrypoint = config.Entrypoint[0]
453
-		args = append(config.Entrypoint[1:], config.Cmd...)
454
-	} else {
455
-		entrypoint = config.Cmd[0]
456
-		args = config.Cmd[1:]
457
-	}
458
-
459
-	container := &Container{
460
-		// FIXME: we should generate the ID here instead of receiving it as an argument
461
-		ID:              id,
462
-		Created:         time.Now().UTC(),
463
-		Path:            entrypoint,
464
-		Args:            args, //FIXME: de-duplicate from config
465
-		Config:          config,
466
-		hostConfig:      &runconfig.HostConfig{},
467
-		Image:           img.ID, // Always use the resolved image id
468
-		NetworkSettings: &NetworkSettings{},
469
-		Name:            name,
470
-		Driver:          runtime.driver.String(),
471
-		ExecDriver:      runtime.execDriver.Name(),
472
-	}
473
-	container.root = runtime.containerRoot(container.ID)
474
-	// Step 1: create the container directory.
475
-	// This doubles as a barrier to avoid race conditions.
476
-	if err := os.Mkdir(container.root, 0700); err != nil {
477
-		return nil, nil, err
478
-	}
479
-
480
-	initID := fmt.Sprintf("%s-init", container.ID)
481
-	if err := runtime.driver.Create(initID, img.ID); err != nil {
482
-		return nil, nil, err
483
-	}
484
-	initPath, err := runtime.driver.Get(initID)
485
-	if err != nil {
486
-		return nil, nil, err
487
-	}
488
-	defer runtime.driver.Put(initID)
489
-
490
-	if err := graph.SetupInitLayer(initPath); err != nil {
491
-		return nil, nil, err
492
-	}
493
-
494
-	if err := runtime.driver.Create(container.ID, initID); err != nil {
495
-		return nil, nil, err
496
-	}
497
-	resolvConf, err := utils.GetResolvConf()
498
-	if err != nil {
499
-		return nil, nil, err
500
-	}
501
-
502
-	if len(config.Dns) == 0 && len(runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
503
-		//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
504
-		runtime.config.Dns = defaultDns
505
-	}
506
-
507
-	// If custom dns exists, then create a resolv.conf for the container
508
-	if len(config.Dns) > 0 || len(runtime.config.Dns) > 0 {
509
-		var dns []string
510
-		if len(config.Dns) > 0 {
511
-			dns = config.Dns
512
-		} else {
513
-			dns = runtime.config.Dns
514
-		}
515
-		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
516
-		f, err := os.Create(container.ResolvConfPath)
517
-		if err != nil {
518
-			return nil, nil, err
519
-		}
520
-		defer f.Close()
521
-		for _, dns := range dns {
522
-			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
523
-				return nil, nil, err
524
-			}
525
-		}
526
-	} else {
527
-		container.ResolvConfPath = "/etc/resolv.conf"
528
-	}
529
-
530
-	// Step 2: save the container json
531
-	if err := container.ToDisk(); err != nil {
532
-		return nil, nil, err
533
-	}
534
-
535
-	// Step 3: register the container
536
-	if err := runtime.Register(container); err != nil {
537
-		return nil, nil, err
538
-	}
539
-	return container, warnings, nil
540
-}
541
-
542
-// Commit creates a new filesystem image from the current state of a container.
543
-// The image can optionally be tagged into a repository
544
-func (runtime *Runtime) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
545
-	// FIXME: freeze the container before copying it to avoid data corruption?
546
-	// FIXME: this shouldn't be in commands.
547
-	if err := container.Mount(); err != nil {
548
-		return nil, err
549
-	}
550
-	defer container.Unmount()
551
-
552
-	rwTar, err := container.ExportRw()
553
-	if err != nil {
554
-		return nil, err
555
-	}
556
-	defer rwTar.Close()
557
-
558
-	// Create a new image from the container's base layers + a new layer from container changes
559
-	var (
560
-		containerID, containerImage string
561
-		containerConfig             *runconfig.Config
562
-	)
563
-	if container != nil {
564
-		containerID = container.ID
565
-		containerImage = container.Image
566
-		containerConfig = container.Config
567
-	}
568
-	img, err := runtime.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
569
-	if err != nil {
570
-		return nil, err
571
-	}
572
-	// Register the image if needed
573
-	if repository != "" {
574
-		if err := runtime.repositories.Set(repository, tag, img.ID, true); err != nil {
575
-			return img, err
576
-		}
577
-	}
578
-	return img, nil
579
-}
580
-
581
-func getFullName(name string) (string, error) {
582
-	if name == "" {
583
-		return "", fmt.Errorf("Container name cannot be empty")
584
-	}
585
-	if name[0] != '/' {
586
-		name = "/" + name
587
-	}
588
-	return name, nil
589
-}
590
-
591
-func (runtime *Runtime) GetByName(name string) (*Container, error) {
592
-	fullName, err := getFullName(name)
593
-	if err != nil {
594
-		return nil, err
595
-	}
596
-	entity := runtime.containerGraph.Get(fullName)
597
-	if entity == nil {
598
-		return nil, fmt.Errorf("Could not find entity for %s", name)
599
-	}
600
-	e := runtime.getContainerElement(entity.ID())
601
-	if e == nil {
602
-		return nil, fmt.Errorf("Could not find container for entity id %s", entity.ID())
603
-	}
604
-	return e.Value.(*Container), nil
605
-}
606
-
607
-func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
608
-	name, err := getFullName(name)
609
-	if err != nil {
610
-		return nil, err
611
-	}
612
-	children := make(map[string]*Container)
613
-
614
-	err = runtime.containerGraph.Walk(name, func(p string, e *graphdb.Entity) error {
615
-		c := runtime.Get(e.ID())
616
-		if c == nil {
617
-			return fmt.Errorf("Could not get container for name %s and id %s", e.ID(), p)
618
-		}
619
-		children[p] = c
620
-		return nil
621
-	}, 0)
622
-
623
-	if err != nil {
624
-		return nil, err
625
-	}
626
-	return children, nil
627
-}
628
-
629
-func (runtime *Runtime) RegisterLink(parent, child *Container, alias string) error {
630
-	fullName := path.Join(parent.Name, alias)
631
-	if !runtime.containerGraph.Exists(fullName) {
632
-		_, err := runtime.containerGraph.Set(fullName, child.ID)
633
-		return err
634
-	}
635
-	return nil
636
-}
637
-
638
-// FIXME: harmonize with NewGraph()
639
-func NewRuntime(config *daemonconfig.Config, eng *engine.Engine) (*Runtime, error) {
640
-	runtime, err := NewRuntimeFromDirectory(config, eng)
641
-	if err != nil {
642
-		return nil, err
643
-	}
644
-	return runtime, nil
645
-}
646
-
647
-func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Runtime, error) {
648
-
649
-	// Set the default driver
650
-	graphdriver.DefaultDriver = config.GraphDriver
651
-
652
-	// Load storage driver
653
-	driver, err := graphdriver.New(config.Root)
654
-	if err != nil {
655
-		return nil, err
656
-	}
657
-	utils.Debugf("Using graph driver %s", driver)
658
-
659
-	runtimeRepo := path.Join(config.Root, "containers")
660
-
661
-	if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) {
662
-		return nil, err
663
-	}
664
-
665
-	if ad, ok := driver.(*aufs.Driver); ok {
666
-		utils.Debugf("Migrating existing containers")
667
-		if err := ad.Migrate(config.Root, graph.SetupInitLayer); err != nil {
668
-			return nil, err
669
-		}
670
-	}
671
-
672
-	utils.Debugf("Creating images graph")
673
-	g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver)
674
-	if err != nil {
675
-		return nil, err
676
-	}
677
-
678
-	// We don't want to use a complex driver like aufs or devmapper
679
-	// for volumes, just a plain filesystem
680
-	volumesDriver, err := graphdriver.GetDriver("vfs", config.Root)
681
-	if err != nil {
682
-		return nil, err
683
-	}
684
-	utils.Debugf("Creating volumes graph")
685
-	volumes, err := graph.NewGraph(path.Join(config.Root, "volumes"), volumesDriver)
686
-	if err != nil {
687
-		return nil, err
688
-	}
689
-	utils.Debugf("Creating repository list")
690
-	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g)
691
-	if err != nil {
692
-		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
693
-	}
694
-
695
-	if !config.DisableNetwork {
696
-		job := eng.Job("init_networkdriver")
697
-
698
-		job.SetenvBool("EnableIptables", config.EnableIptables)
699
-		job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication)
700
-		job.SetenvBool("EnableIpForward", config.EnableIpForward)
701
-		job.Setenv("BridgeIface", config.BridgeIface)
702
-		job.Setenv("BridgeIP", config.BridgeIP)
703
-		job.Setenv("DefaultBindingIP", config.DefaultIp.String())
704
-
705
-		if err := job.Run(); err != nil {
706
-			return nil, err
707
-		}
708
-	}
709
-
710
-	graphdbPath := path.Join(config.Root, "linkgraph.db")
711
-	graph, err := graphdb.NewSqliteConn(graphdbPath)
712
-	if err != nil {
713
-		return nil, err
714
-	}
715
-
716
-	localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
717
-	sysInitPath := utils.DockerInitPath(localCopy)
718
-	if sysInitPath == "" {
719
-		return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.io/en/latest/contributing/devenvironment for official build instructions.")
720
-	}
721
-
722
-	if sysInitPath != localCopy {
723
-		// When we find a suitable dockerinit binary (even if it's our local binary), we copy it into config.Root at localCopy for future use (so that the original can go away without that being a problem, for example during a package upgrade).
724
-		if err := os.Mkdir(path.Dir(localCopy), 0700); err != nil && !os.IsExist(err) {
725
-			return nil, err
726
-		}
727
-		if _, err := utils.CopyFile(sysInitPath, localCopy); err != nil {
728
-			return nil, err
729
-		}
730
-		if err := os.Chmod(localCopy, 0700); err != nil {
731
-			return nil, err
732
-		}
733
-		sysInitPath = localCopy
734
-	}
735
-
736
-	var (
737
-		ed      execdriver.Driver
738
-		sysInfo = sysinfo.New(false)
739
-	)
740
-
741
-	switch config.ExecDriver {
742
-	case "lxc":
743
-		// we want to five the lxc driver the full docker root because it needs
744
-		// to access and write config and template files in /var/lib/docker/containers/*
745
-		// to be backwards compatible
746
-		ed, err = lxc.NewDriver(config.Root, sysInfo.AppArmor)
747
-	case "native":
748
-		ed, err = native.NewDriver(path.Join(config.Root, "execdriver", "native"))
749
-	default:
750
-		return nil, fmt.Errorf("unknown exec driver %s", config.ExecDriver)
751
-	}
752
-	if err != nil {
753
-		return nil, err
754
-	}
755
-
756
-	runtime := &Runtime{
757
-		repository:     runtimeRepo,
758
-		containers:     list.New(),
759
-		graph:          g,
760
-		repositories:   repositories,
761
-		idIndex:        utils.NewTruncIndex(),
762
-		sysInfo:        sysInfo,
763
-		volumes:        volumes,
764
-		config:         config,
765
-		containerGraph: graph,
766
-		driver:         driver,
767
-		sysInitPath:    sysInitPath,
768
-		execDriver:     ed,
769
-		eng:            eng,
770
-	}
771
-
772
-	if err := runtime.restore(); err != nil {
773
-		return nil, err
774
-	}
775
-	return runtime, nil
776
-}
777
-
778
-func (runtime *Runtime) Close() error {
779
-	errorsStrings := []string{}
780
-	if err := portallocator.ReleaseAll(); err != nil {
781
-		utils.Errorf("portallocator.ReleaseAll(): %s", err)
782
-		errorsStrings = append(errorsStrings, err.Error())
783
-	}
784
-	if err := runtime.driver.Cleanup(); err != nil {
785
-		utils.Errorf("runtime.driver.Cleanup(): %s", err.Error())
786
-		errorsStrings = append(errorsStrings, err.Error())
787
-	}
788
-	if err := runtime.containerGraph.Close(); err != nil {
789
-		utils.Errorf("runtime.containerGraph.Close(): %s", err.Error())
790
-		errorsStrings = append(errorsStrings, err.Error())
791
-	}
792
-	if len(errorsStrings) > 0 {
793
-		return fmt.Errorf("%s", strings.Join(errorsStrings, ", "))
794
-	}
795
-	return nil
796
-}
797
-
798
-func (runtime *Runtime) Mount(container *Container) error {
799
-	dir, err := runtime.driver.Get(container.ID)
800
-	if err != nil {
801
-		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, runtime.driver, err)
802
-	}
803
-	if container.basefs == "" {
804
-		container.basefs = dir
805
-	} else if container.basefs != dir {
806
-		return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
807
-			runtime.driver, container.ID, container.basefs, dir)
808
-	}
809
-	return nil
810
-}
811
-
812
-func (runtime *Runtime) Unmount(container *Container) error {
813
-	runtime.driver.Put(container.ID)
814
-	return nil
815
-}
816
-
817
-func (runtime *Runtime) Changes(container *Container) ([]archive.Change, error) {
818
-	if differ, ok := runtime.driver.(graphdriver.Differ); ok {
819
-		return differ.Changes(container.ID)
820
-	}
821
-	cDir, err := runtime.driver.Get(container.ID)
822
-	if err != nil {
823
-		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
824
-	}
825
-	defer runtime.driver.Put(container.ID)
826
-	initDir, err := runtime.driver.Get(container.ID + "-init")
827
-	if err != nil {
828
-		return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
829
-	}
830
-	defer runtime.driver.Put(container.ID + "-init")
831
-	return archive.ChangesDirs(cDir, initDir)
832
-}
833
-
834
-func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
835
-	if differ, ok := runtime.driver.(graphdriver.Differ); ok {
836
-		return differ.Diff(container.ID)
837
-	}
838
-
839
-	changes, err := runtime.Changes(container)
840
-	if err != nil {
841
-		return nil, err
842
-	}
843
-
844
-	cDir, err := runtime.driver.Get(container.ID)
845
-	if err != nil {
846
-		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
847
-	}
848
-
849
-	archive, err := archive.ExportChanges(cDir, changes)
850
-	if err != nil {
851
-		return nil, err
852
-	}
853
-	return utils.NewReadCloserWrapper(archive, func() error {
854
-		err := archive.Close()
855
-		runtime.driver.Put(container.ID)
856
-		return err
857
-	}), nil
858
-}
859
-
860
-func (runtime *Runtime) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
861
-	return runtime.execDriver.Run(c.command, pipes, startCallback)
862
-}
863
-
864
-func (runtime *Runtime) Kill(c *Container, sig int) error {
865
-	return runtime.execDriver.Kill(c.command, sig)
866
-}
867
-
868
-// Nuke kills all containers then removes all content
869
-// from the content root, including images, volumes and
870
-// container filesystems.
871
-// Again: this will remove your entire docker runtime!
872
-func (runtime *Runtime) Nuke() error {
873
-	var wg sync.WaitGroup
874
-	for _, container := range runtime.List() {
875
-		wg.Add(1)
876
-		go func(c *Container) {
877
-			c.Kill()
878
-			wg.Done()
879
-		}(container)
880
-	}
881
-	wg.Wait()
882
-	runtime.Close()
883
-
884
-	return os.RemoveAll(runtime.config.Root)
885
-}
886
-
887
-// FIXME: this is a convenience function for integration tests
888
-// which need direct access to runtime.graph.
889
-// Once the tests switch to using engine and jobs, this method
890
-// can go away.
891
-func (runtime *Runtime) Graph() *graph.Graph {
892
-	return runtime.graph
893
-}
894
-
895
-// History is a convenience type for storing a list of containers,
896
-// ordered by creation date.
897
-type History []*Container
898
-
899
-func (history *History) Len() int {
900
-	return len(*history)
901
-}
902
-
903
-func (history *History) Less(i, j int) bool {
904
-	containers := *history
905
-	return containers[j].When().Before(containers[i].When())
906
-}
907
-
908
-func (history *History) Swap(i, j int) {
909
-	containers := *history
910
-	tmp := containers[i]
911
-	containers[i] = containers[j]
912
-	containers[j] = tmp
913
-}
914
-
915
-func (history *History) Add(container *Container) {
916
-	*history = append(*history, container)
917
-	sort.Sort(history)
918
-}
919 1
new file mode 100644
... ...
@@ -0,0 +1,1161 @@
0
+package runtime
1
+
2
+import (
3
+	"encoding/json"
4
+	"errors"
5
+	"fmt"
6
+	"github.com/dotcloud/docker/archive"
7
+	"github.com/dotcloud/docker/engine"
8
+	"github.com/dotcloud/docker/execdriver"
9
+	"github.com/dotcloud/docker/graphdriver"
10
+	"github.com/dotcloud/docker/image"
11
+	"github.com/dotcloud/docker/links"
12
+	"github.com/dotcloud/docker/nat"
13
+	"github.com/dotcloud/docker/runconfig"
14
+	"github.com/dotcloud/docker/utils"
15
+	"io"
16
+	"io/ioutil"
17
+	"log"
18
+	"os"
19
+	"path"
20
+	"strings"
21
+	"sync"
22
+	"syscall"
23
+	"time"
24
+)
25
+
26
+const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
27
+
28
+var (
29
+	ErrNotATTY               = errors.New("The PTY is not a file")
30
+	ErrNoTTY                 = errors.New("No PTY found")
31
+	ErrContainerStart        = errors.New("The container failed to start. Unknown error")
32
+	ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.")
33
+)
34
+
35
+type Container struct {
36
+	sync.Mutex
37
+	root   string // Path to the "home" of the container, including metadata.
38
+	basefs string // Path to the graphdriver mountpoint
39
+
40
+	ID string
41
+
42
+	Created time.Time
43
+
44
+	Path string
45
+	Args []string
46
+
47
+	Config *runconfig.Config
48
+	State  State
49
+	Image  string
50
+
51
+	NetworkSettings *NetworkSettings
52
+
53
+	ResolvConfPath string
54
+	HostnamePath   string
55
+	HostsPath      string
56
+	Name           string
57
+	Driver         string
58
+	ExecDriver     string
59
+
60
+	command   *execdriver.Command
61
+	stdout    *utils.WriteBroadcaster
62
+	stderr    *utils.WriteBroadcaster
63
+	stdin     io.ReadCloser
64
+	stdinPipe io.WriteCloser
65
+
66
+	runtime *Runtime
67
+
68
+	waitLock chan struct{}
69
+	Volumes  map[string]string
70
+	// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
71
+	// Easier than migrating older container configs :)
72
+	VolumesRW  map[string]bool
73
+	hostConfig *runconfig.HostConfig
74
+
75
+	activeLinks map[string]*links.Link
76
+}
77
+
78
+// FIXME: move deprecated port stuff to nat to clean up the core.
79
+type PortMapping map[string]string // Deprecated
80
+
81
+type NetworkSettings struct {
82
+	IPAddress   string
83
+	IPPrefixLen int
84
+	Gateway     string
85
+	Bridge      string
86
+	PortMapping map[string]PortMapping // Deprecated
87
+	Ports       nat.PortMap
88
+}
89
+
90
+func (settings *NetworkSettings) PortMappingAPI() *engine.Table {
91
+	var outs = engine.NewTable("", 0)
92
+	for port, bindings := range settings.Ports {
93
+		p, _ := nat.ParsePort(port.Port())
94
+		if len(bindings) == 0 {
95
+			out := &engine.Env{}
96
+			out.SetInt("PublicPort", p)
97
+			out.Set("Type", port.Proto())
98
+			outs.Add(out)
99
+			continue
100
+		}
101
+		for _, binding := range bindings {
102
+			out := &engine.Env{}
103
+			h, _ := nat.ParsePort(binding.HostPort)
104
+			out.SetInt("PrivatePort", p)
105
+			out.SetInt("PublicPort", h)
106
+			out.Set("Type", port.Proto())
107
+			out.Set("IP", binding.HostIp)
108
+			outs.Add(out)
109
+		}
110
+	}
111
+	return outs
112
+}
113
+
114
+// Inject the io.Reader at the given path. Note: do not close the reader
115
+func (container *Container) Inject(file io.Reader, pth string) error {
116
+	if err := container.Mount(); err != nil {
117
+		return fmt.Errorf("inject: error mounting container %s: %s", container.ID, err)
118
+	}
119
+	defer container.Unmount()
120
+
121
+	// Return error if path exists
122
+	destPath := path.Join(container.basefs, pth)
123
+	if _, err := os.Stat(destPath); err == nil {
124
+		// Since err is nil, the path could be stat'd and it exists
125
+		return fmt.Errorf("%s exists", pth)
126
+	} else if !os.IsNotExist(err) {
127
+		// Expect err might be that the file doesn't exist, so
128
+		// if it's some other error, return that.
129
+
130
+		return err
131
+	}
132
+
133
+	// Make sure the directory exists
134
+	if err := os.MkdirAll(path.Join(container.basefs, path.Dir(pth)), 0755); err != nil {
135
+		return err
136
+	}
137
+
138
+	dest, err := os.Create(destPath)
139
+	if err != nil {
140
+		return err
141
+	}
142
+	defer dest.Close()
143
+
144
+	if _, err := io.Copy(dest, file); err != nil {
145
+		return err
146
+	}
147
+	return nil
148
+}
149
+
150
+func (container *Container) When() time.Time {
151
+	return container.Created
152
+}
153
+
154
+func (container *Container) FromDisk() error {
155
+	data, err := ioutil.ReadFile(container.jsonPath())
156
+	if err != nil {
157
+		return err
158
+	}
159
+	// Load container settings
160
+	// udp broke compat of docker.PortMapping, but it's not used when loading a container, we can skip it
161
+	if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
162
+		return err
163
+	}
164
+	return container.readHostConfig()
165
+}
166
+
167
+func (container *Container) ToDisk() (err error) {
168
+	data, err := json.Marshal(container)
169
+	if err != nil {
170
+		return
171
+	}
172
+	err = ioutil.WriteFile(container.jsonPath(), data, 0666)
173
+	if err != nil {
174
+		return
175
+	}
176
+	return container.WriteHostConfig()
177
+}
178
+
179
+func (container *Container) readHostConfig() error {
180
+	container.hostConfig = &runconfig.HostConfig{}
181
+	// If the hostconfig file does not exist, do not read it.
182
+	// (We still have to initialize container.hostConfig,
183
+	// but that's OK, since we just did that above.)
184
+	_, err := os.Stat(container.hostConfigPath())
185
+	if os.IsNotExist(err) {
186
+		return nil
187
+	}
188
+	data, err := ioutil.ReadFile(container.hostConfigPath())
189
+	if err != nil {
190
+		return err
191
+	}
192
+	return json.Unmarshal(data, container.hostConfig)
193
+}
194
+
195
+func (container *Container) WriteHostConfig() (err error) {
196
+	data, err := json.Marshal(container.hostConfig)
197
+	if err != nil {
198
+		return
199
+	}
200
+	return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
201
+}
202
+
203
+func (container *Container) generateEnvConfig(env []string) error {
204
+	data, err := json.Marshal(env)
205
+	if err != nil {
206
+		return err
207
+	}
208
+	p, err := container.EnvConfigPath()
209
+	if err != nil {
210
+		return err
211
+	}
212
+	ioutil.WriteFile(p, data, 0600)
213
+	return nil
214
+}
215
+
216
+func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
217
+	var cStdout, cStderr io.ReadCloser
218
+
219
+	var nJobs int
220
+	errors := make(chan error, 3)
221
+	if stdin != nil && container.Config.OpenStdin {
222
+		nJobs += 1
223
+		if cStdin, err := container.StdinPipe(); err != nil {
224
+			errors <- err
225
+		} else {
226
+			go func() {
227
+				utils.Debugf("attach: stdin: begin")
228
+				defer utils.Debugf("attach: stdin: end")
229
+				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
230
+				if container.Config.StdinOnce && !container.Config.Tty {
231
+					defer cStdin.Close()
232
+				} else {
233
+					defer func() {
234
+						if cStdout != nil {
235
+							cStdout.Close()
236
+						}
237
+						if cStderr != nil {
238
+							cStderr.Close()
239
+						}
240
+					}()
241
+				}
242
+				if container.Config.Tty {
243
+					_, err = utils.CopyEscapable(cStdin, stdin)
244
+				} else {
245
+					_, err = io.Copy(cStdin, stdin)
246
+				}
247
+				if err == io.ErrClosedPipe {
248
+					err = nil
249
+				}
250
+				if err != nil {
251
+					utils.Errorf("attach: stdin: %s", err)
252
+				}
253
+				errors <- err
254
+			}()
255
+		}
256
+	}
257
+	if stdout != nil {
258
+		nJobs += 1
259
+		if p, err := container.StdoutPipe(); err != nil {
260
+			errors <- err
261
+		} else {
262
+			cStdout = p
263
+			go func() {
264
+				utils.Debugf("attach: stdout: begin")
265
+				defer utils.Debugf("attach: stdout: end")
266
+				// If we are in StdinOnce mode, then close stdin
267
+				if container.Config.StdinOnce && stdin != nil {
268
+					defer stdin.Close()
269
+				}
270
+				if stdinCloser != nil {
271
+					defer stdinCloser.Close()
272
+				}
273
+				_, err := io.Copy(stdout, cStdout)
274
+				if err == io.ErrClosedPipe {
275
+					err = nil
276
+				}
277
+				if err != nil {
278
+					utils.Errorf("attach: stdout: %s", err)
279
+				}
280
+				errors <- err
281
+			}()
282
+		}
283
+	} else {
284
+		go func() {
285
+			if stdinCloser != nil {
286
+				defer stdinCloser.Close()
287
+			}
288
+			if cStdout, err := container.StdoutPipe(); err != nil {
289
+				utils.Errorf("attach: stdout pipe: %s", err)
290
+			} else {
291
+				io.Copy(&utils.NopWriter{}, cStdout)
292
+			}
293
+		}()
294
+	}
295
+	if stderr != nil {
296
+		nJobs += 1
297
+		if p, err := container.StderrPipe(); err != nil {
298
+			errors <- err
299
+		} else {
300
+			cStderr = p
301
+			go func() {
302
+				utils.Debugf("attach: stderr: begin")
303
+				defer utils.Debugf("attach: stderr: end")
304
+				// If we are in StdinOnce mode, then close stdin
305
+				if container.Config.StdinOnce && stdin != nil {
306
+					defer stdin.Close()
307
+				}
308
+				if stdinCloser != nil {
309
+					defer stdinCloser.Close()
310
+				}
311
+				_, err := io.Copy(stderr, cStderr)
312
+				if err == io.ErrClosedPipe {
313
+					err = nil
314
+				}
315
+				if err != nil {
316
+					utils.Errorf("attach: stderr: %s", err)
317
+				}
318
+				errors <- err
319
+			}()
320
+		}
321
+	} else {
322
+		go func() {
323
+			if stdinCloser != nil {
324
+				defer stdinCloser.Close()
325
+			}
326
+
327
+			if cStderr, err := container.StderrPipe(); err != nil {
328
+				utils.Errorf("attach: stdout pipe: %s", err)
329
+			} else {
330
+				io.Copy(&utils.NopWriter{}, cStderr)
331
+			}
332
+		}()
333
+	}
334
+
335
+	return utils.Go(func() error {
336
+		defer func() {
337
+			if cStdout != nil {
338
+				cStdout.Close()
339
+			}
340
+			if cStderr != nil {
341
+				cStderr.Close()
342
+			}
343
+		}()
344
+
345
+		// FIXME: how to clean up the stdin goroutine without the unwanted side effect
346
+		// of closing the passed stdin? Add an intermediary io.Pipe?
347
+		for i := 0; i < nJobs; i += 1 {
348
+			utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
349
+			if err := <-errors; err != nil {
350
+				utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
351
+				return err
352
+			}
353
+			utils.Debugf("attach: job %d completed successfully", i+1)
354
+		}
355
+		utils.Debugf("attach: all jobs completed successfully")
356
+		return nil
357
+	})
358
+}
359
+
360
+func populateCommand(c *Container) {
361
+	var (
362
+		en           *execdriver.Network
363
+		driverConfig []string
364
+	)
365
+
366
+	if !c.Config.NetworkDisabled {
367
+		network := c.NetworkSettings
368
+		en = &execdriver.Network{
369
+			Gateway:     network.Gateway,
370
+			Bridge:      network.Bridge,
371
+			IPAddress:   network.IPAddress,
372
+			IPPrefixLen: network.IPPrefixLen,
373
+			Mtu:         c.runtime.config.Mtu,
374
+		}
375
+	}
376
+
377
+	if lxcConf := c.hostConfig.LxcConf; lxcConf != nil {
378
+		for _, pair := range lxcConf {
379
+			driverConfig = append(driverConfig, fmt.Sprintf("%s = %s", pair.Key, pair.Value))
380
+		}
381
+	}
382
+	resources := &execdriver.Resources{
383
+		Memory:     c.Config.Memory,
384
+		MemorySwap: c.Config.MemorySwap,
385
+		CpuShares:  c.Config.CpuShares,
386
+	}
387
+	c.command = &execdriver.Command{
388
+		ID:         c.ID,
389
+		Privileged: c.hostConfig.Privileged,
390
+		Rootfs:     c.RootfsPath(),
391
+		InitPath:   "/.dockerinit",
392
+		Entrypoint: c.Path,
393
+		Arguments:  c.Args,
394
+		WorkingDir: c.Config.WorkingDir,
395
+		Network:    en,
396
+		Tty:        c.Config.Tty,
397
+		User:       c.Config.User,
398
+		Config:     driverConfig,
399
+		Resources:  resources,
400
+	}
401
+	c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
402
+}
403
+
404
+func (container *Container) Start() (err error) {
405
+	container.Lock()
406
+	defer container.Unlock()
407
+
408
+	if container.State.IsRunning() {
409
+		return fmt.Errorf("The container %s is already running.", container.ID)
410
+	}
411
+
412
+	defer func() {
413
+		if err != nil {
414
+			container.cleanup()
415
+		}
416
+	}()
417
+
418
+	if err := container.Mount(); err != nil {
419
+		return err
420
+	}
421
+
422
+	if container.runtime.config.DisableNetwork {
423
+		container.Config.NetworkDisabled = true
424
+		container.buildHostnameAndHostsFiles("127.0.1.1")
425
+	} else {
426
+		if err := container.allocateNetwork(); err != nil {
427
+			return err
428
+		}
429
+		container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
430
+	}
431
+
432
+	// Make sure the config is compatible with the current kernel
433
+	if container.Config.Memory > 0 && !container.runtime.sysInfo.MemoryLimit {
434
+		log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
435
+		container.Config.Memory = 0
436
+	}
437
+	if container.Config.Memory > 0 && !container.runtime.sysInfo.SwapLimit {
438
+		log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
439
+		container.Config.MemorySwap = -1
440
+	}
441
+
442
+	if container.runtime.sysInfo.IPv4ForwardingDisabled {
443
+		log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
444
+	}
445
+
446
+	if err := prepareVolumesForContainer(container); err != nil {
447
+		return err
448
+	}
449
+
450
+	// Setup environment
451
+	env := []string{
452
+		"HOME=/",
453
+		"PATH=" + DefaultPathEnv,
454
+		"HOSTNAME=" + container.Config.Hostname,
455
+	}
456
+
457
+	if container.Config.Tty {
458
+		env = append(env, "TERM=xterm")
459
+	}
460
+
461
+	// Init any links between the parent and children
462
+	runtime := container.runtime
463
+
464
+	children, err := runtime.Children(container.Name)
465
+	if err != nil {
466
+		return err
467
+	}
468
+
469
+	if len(children) > 0 {
470
+		container.activeLinks = make(map[string]*links.Link, len(children))
471
+
472
+		// If we encounter an error make sure that we rollback any network
473
+		// config and ip table changes
474
+		rollback := func() {
475
+			for _, link := range container.activeLinks {
476
+				link.Disable()
477
+			}
478
+			container.activeLinks = nil
479
+		}
480
+
481
+		for linkAlias, child := range children {
482
+			if !child.State.IsRunning() {
483
+				return fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
484
+			}
485
+
486
+			link, err := links.NewLink(
487
+				container.NetworkSettings.IPAddress,
488
+				child.NetworkSettings.IPAddress,
489
+				linkAlias,
490
+				child.Config.Env,
491
+				child.Config.ExposedPorts,
492
+				runtime.eng)
493
+
494
+			if err != nil {
495
+				rollback()
496
+				return err
497
+			}
498
+
499
+			container.activeLinks[link.Alias()] = link
500
+			if err := link.Enable(); err != nil {
501
+				rollback()
502
+				return err
503
+			}
504
+
505
+			for _, envVar := range link.ToEnv() {
506
+				env = append(env, envVar)
507
+			}
508
+		}
509
+	}
510
+
511
+	// because the env on the container can override certain default values
512
+	// we need to replace the 'env' keys where they match and append anything
513
+	// else.
514
+	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
515
+	if err := container.generateEnvConfig(env); err != nil {
516
+		return err
517
+	}
518
+
519
+	if container.Config.WorkingDir != "" {
520
+		container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
521
+		if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
522
+			return nil
523
+		}
524
+	}
525
+
526
+	envPath, err := container.EnvConfigPath()
527
+	if err != nil {
528
+		return err
529
+	}
530
+
531
+	if err := mountVolumesForContainer(container, envPath); err != nil {
532
+		return err
533
+	}
534
+
535
+	populateCommand(container)
536
+	container.command.Env = env
537
+
538
+	// Setup logging of stdout and stderr to disk
539
+	if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
540
+		return err
541
+	}
542
+	if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
543
+		return err
544
+	}
545
+	container.waitLock = make(chan struct{})
546
+
547
+	callbackLock := make(chan struct{})
548
+	callback := func(command *execdriver.Command) {
549
+		container.State.SetRunning(command.Pid())
550
+		if command.Tty {
551
+			// The callback is called after the process Start()
552
+			// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
553
+			// which we close here.
554
+			if c, ok := command.Stdout.(io.Closer); ok {
555
+				c.Close()
556
+			}
557
+		}
558
+		if err := container.ToDisk(); err != nil {
559
+			utils.Debugf("%s", err)
560
+		}
561
+		close(callbackLock)
562
+	}
563
+
564
+	// We use a callback here instead of a goroutine and an chan for
565
+	// syncronization purposes
566
+	cErr := utils.Go(func() error { return container.monitor(callback) })
567
+
568
+	// Start should not return until the process is actually running
569
+	select {
570
+	case <-callbackLock:
571
+	case err := <-cErr:
572
+		return err
573
+	}
574
+	return nil
575
+}
576
+
577
+func (container *Container) Run() error {
578
+	if err := container.Start(); err != nil {
579
+		return err
580
+	}
581
+	container.Wait()
582
+	return nil
583
+}
584
+
585
+func (container *Container) Output() (output []byte, err error) {
586
+	pipe, err := container.StdoutPipe()
587
+	if err != nil {
588
+		return nil, err
589
+	}
590
+	defer pipe.Close()
591
+	if err := container.Start(); err != nil {
592
+		return nil, err
593
+	}
594
+	output, err = ioutil.ReadAll(pipe)
595
+	container.Wait()
596
+	return output, err
597
+}
598
+
599
+// Container.StdinPipe returns a WriteCloser which can be used to feed data
600
+// to the standard input of the container's active process.
601
+// Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
602
+// which can be used to retrieve the standard output (and error) generated
603
+// by the container's active process. The output (and error) are actually
604
+// copied and delivered to all StdoutPipe and StderrPipe consumers, using
605
+// a kind of "broadcaster".
606
+
607
+func (container *Container) StdinPipe() (io.WriteCloser, error) {
608
+	return container.stdinPipe, nil
609
+}
610
+
611
+func (container *Container) StdoutPipe() (io.ReadCloser, error) {
612
+	reader, writer := io.Pipe()
613
+	container.stdout.AddWriter(writer, "")
614
+	return utils.NewBufReader(reader), nil
615
+}
616
+
617
+func (container *Container) StderrPipe() (io.ReadCloser, error) {
618
+	reader, writer := io.Pipe()
619
+	container.stderr.AddWriter(writer, "")
620
+	return utils.NewBufReader(reader), nil
621
+}
622
+
623
+func (container *Container) buildHostnameAndHostsFiles(IP string) {
624
+	container.HostnamePath = path.Join(container.root, "hostname")
625
+	ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
626
+
627
+	hostsContent := []byte(`
628
+127.0.0.1	localhost
629
+::1		localhost ip6-localhost ip6-loopback
630
+fe00::0		ip6-localnet
631
+ff00::0		ip6-mcastprefix
632
+ff02::1		ip6-allnodes
633
+ff02::2		ip6-allrouters
634
+`)
635
+
636
+	container.HostsPath = path.Join(container.root, "hosts")
637
+
638
+	if container.Config.Domainname != "" {
639
+		hostsContent = append([]byte(fmt.Sprintf("%s\t%s.%s %s\n", IP, container.Config.Hostname, container.Config.Domainname, container.Config.Hostname)), hostsContent...)
640
+	} else if !container.Config.NetworkDisabled {
641
+		hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...)
642
+	}
643
+
644
+	ioutil.WriteFile(container.HostsPath, hostsContent, 0644)
645
+}
646
+
647
+func (container *Container) allocateNetwork() error {
648
+	if container.Config.NetworkDisabled {
649
+		return nil
650
+	}
651
+
652
+	var (
653
+		env *engine.Env
654
+		err error
655
+		eng = container.runtime.eng
656
+	)
657
+
658
+	if container.State.IsGhost() {
659
+		if container.runtime.config.DisableNetwork {
660
+			env = &engine.Env{}
661
+		} else {
662
+			currentIP := container.NetworkSettings.IPAddress
663
+
664
+			job := eng.Job("allocate_interface", container.ID)
665
+			if currentIP != "" {
666
+				job.Setenv("RequestIP", currentIP)
667
+			}
668
+
669
+			env, err = job.Stdout.AddEnv()
670
+			if err != nil {
671
+				return err
672
+			}
673
+
674
+			if err := job.Run(); err != nil {
675
+				return err
676
+			}
677
+		}
678
+	} else {
679
+		job := eng.Job("allocate_interface", container.ID)
680
+		env, err = job.Stdout.AddEnv()
681
+		if err != nil {
682
+			return err
683
+		}
684
+		if err := job.Run(); err != nil {
685
+			return err
686
+		}
687
+	}
688
+
689
+	if container.Config.PortSpecs != nil {
690
+		utils.Debugf("Migrating port mappings for container: %s", strings.Join(container.Config.PortSpecs, ", "))
691
+		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
692
+			return err
693
+		}
694
+		container.Config.PortSpecs = nil
695
+		if err := container.WriteHostConfig(); err != nil {
696
+			return err
697
+		}
698
+	}
699
+
700
+	var (
701
+		portSpecs = make(nat.PortSet)
702
+		bindings  = make(nat.PortMap)
703
+	)
704
+
705
+	if !container.State.IsGhost() {
706
+		if container.Config.ExposedPorts != nil {
707
+			portSpecs = container.Config.ExposedPorts
708
+		}
709
+		if container.hostConfig.PortBindings != nil {
710
+			bindings = container.hostConfig.PortBindings
711
+		}
712
+	} else {
713
+		if container.NetworkSettings.Ports != nil {
714
+			for port, binding := range container.NetworkSettings.Ports {
715
+				portSpecs[port] = struct{}{}
716
+				bindings[port] = binding
717
+			}
718
+		}
719
+	}
720
+
721
+	container.NetworkSettings.PortMapping = nil
722
+
723
+	for port := range portSpecs {
724
+		binding := bindings[port]
725
+		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
726
+			binding = append(binding, nat.PortBinding{})
727
+		}
728
+
729
+		for i := 0; i < len(binding); i++ {
730
+			b := binding[i]
731
+
732
+			portJob := eng.Job("allocate_port", container.ID)
733
+			portJob.Setenv("HostIP", b.HostIp)
734
+			portJob.Setenv("HostPort", b.HostPort)
735
+			portJob.Setenv("Proto", port.Proto())
736
+			portJob.Setenv("ContainerPort", port.Port())
737
+
738
+			portEnv, err := portJob.Stdout.AddEnv()
739
+			if err != nil {
740
+				return err
741
+			}
742
+			if err := portJob.Run(); err != nil {
743
+				eng.Job("release_interface", container.ID).Run()
744
+				return err
745
+			}
746
+			b.HostIp = portEnv.Get("HostIP")
747
+			b.HostPort = portEnv.Get("HostPort")
748
+
749
+			binding[i] = b
750
+		}
751
+		bindings[port] = binding
752
+	}
753
+	container.WriteHostConfig()
754
+
755
+	container.NetworkSettings.Ports = bindings
756
+
757
+	container.NetworkSettings.Bridge = env.Get("Bridge")
758
+	container.NetworkSettings.IPAddress = env.Get("IP")
759
+	container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
760
+	container.NetworkSettings.Gateway = env.Get("Gateway")
761
+
762
+	return nil
763
+}
764
+
765
+func (container *Container) releaseNetwork() {
766
+	if container.Config.NetworkDisabled {
767
+		return
768
+	}
769
+	eng := container.runtime.eng
770
+
771
+	eng.Job("release_interface", container.ID).Run()
772
+	container.NetworkSettings = &NetworkSettings{}
773
+}
774
+
775
+func (container *Container) monitor(callback execdriver.StartCallback) error {
776
+	var (
777
+		err      error
778
+		exitCode int
779
+	)
780
+
781
+	pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
782
+	exitCode, err = container.runtime.Run(container, pipes, callback)
783
+	if err != nil {
784
+		utils.Errorf("Error running container: %s", err)
785
+	}
786
+
787
+	if container.runtime.srv.IsRunning() {
788
+		container.State.SetStopped(exitCode)
789
+
790
+		// FIXME: there is a race condition here which causes this to fail during the unit tests.
791
+		// If another goroutine was waiting for Wait() to return before removing the container's root
792
+		// from the filesystem... At this point it may already have done so.
793
+		// This is because State.setStopped() has already been called, and has caused Wait()
794
+		// to return.
795
+		// FIXME: why are we serializing running state to disk in the first place?
796
+		//log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
797
+		if err := container.ToDisk(); err != nil {
798
+			utils.Errorf("Error dumping container state to disk: %s\n", err)
799
+		}
800
+	}
801
+
802
+	// Cleanup
803
+	container.cleanup()
804
+
805
+	// Re-create a brand new stdin pipe once the container exited
806
+	if container.Config.OpenStdin {
807
+		container.stdin, container.stdinPipe = io.Pipe()
808
+	}
809
+
810
+	if container.runtime != nil && container.runtime.srv != nil {
811
+		container.runtime.srv.LogEvent("die", container.ID, container.runtime.repositories.ImageName(container.Image))
812
+	}
813
+
814
+	close(container.waitLock)
815
+
816
+	return err
817
+}
818
+
819
+func (container *Container) cleanup() {
820
+	container.releaseNetwork()
821
+
822
+	// Disable all active links
823
+	if container.activeLinks != nil {
824
+		for _, link := range container.activeLinks {
825
+			link.Disable()
826
+		}
827
+	}
828
+	if container.Config.OpenStdin {
829
+		if err := container.stdin.Close(); err != nil {
830
+			utils.Errorf("%s: Error close stdin: %s", container.ID, err)
831
+		}
832
+	}
833
+	if err := container.stdout.CloseWriters(); err != nil {
834
+		utils.Errorf("%s: Error close stdout: %s", container.ID, err)
835
+	}
836
+	if err := container.stderr.CloseWriters(); err != nil {
837
+		utils.Errorf("%s: Error close stderr: %s", container.ID, err)
838
+	}
839
+	if container.command != nil && container.command.Terminal != nil {
840
+		if err := container.command.Terminal.Close(); err != nil {
841
+			utils.Errorf("%s: Error closing terminal: %s", container.ID, err)
842
+		}
843
+	}
844
+
845
+	unmountVolumesForContainer(container)
846
+
847
+	if err := container.Unmount(); err != nil {
848
+		log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
849
+	}
850
+}
851
+
852
+func (container *Container) KillSig(sig int) error {
853
+	container.Lock()
854
+	defer container.Unlock()
855
+
856
+	if !container.State.IsRunning() {
857
+		return nil
858
+	}
859
+	return container.runtime.Kill(container, sig)
860
+}
861
+
862
+func (container *Container) Kill() error {
863
+	if !container.State.IsRunning() {
864
+		return nil
865
+	}
866
+
867
+	// 1. Send SIGKILL
868
+	if err := container.KillSig(9); err != nil {
869
+		return err
870
+	}
871
+
872
+	// 2. Wait for the process to die, in last resort, try to kill the process directly
873
+	if err := container.WaitTimeout(10 * time.Second); err != nil {
874
+		if container.command == nil {
875
+			return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", utils.TruncateID(container.ID))
876
+		}
877
+		log.Printf("Container %s failed to exit within 10 seconds of lxc-kill %s - trying direct SIGKILL", "SIGKILL", utils.TruncateID(container.ID))
878
+		if err := container.runtime.Kill(container, 9); err != nil {
879
+			return err
880
+		}
881
+	}
882
+
883
+	container.Wait()
884
+	return nil
885
+}
886
+
887
+func (container *Container) Stop(seconds int) error {
888
+	if !container.State.IsRunning() {
889
+		return nil
890
+	}
891
+
892
+	// 1. Send a SIGTERM
893
+	if err := container.KillSig(15); err != nil {
894
+		utils.Debugf("Error sending kill SIGTERM: %s", err)
895
+		log.Print("Failed to send SIGTERM to the process, force killing")
896
+		if err := container.KillSig(9); err != nil {
897
+			return err
898
+		}
899
+	}
900
+
901
+	// 2. Wait for the process to exit on its own
902
+	if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
903
+		log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
904
+		// 3. If it doesn't, then send SIGKILL
905
+		if err := container.Kill(); err != nil {
906
+			return err
907
+		}
908
+	}
909
+	return nil
910
+}
911
+
912
+func (container *Container) Restart(seconds int) error {
913
+	// Avoid unnecessarily unmounting and then directly mounting
914
+	// the container when the container stops and then starts
915
+	// again
916
+	if err := container.Mount(); err == nil {
917
+		defer container.Unmount()
918
+	}
919
+
920
+	if err := container.Stop(seconds); err != nil {
921
+		return err
922
+	}
923
+	return container.Start()
924
+}
925
+
926
+// Wait blocks until the container stops running, then returns its exit code.
927
+func (container *Container) Wait() int {
928
+	<-container.waitLock
929
+	return container.State.GetExitCode()
930
+}
931
+
932
+func (container *Container) Resize(h, w int) error {
933
+	return container.command.Terminal.Resize(h, w)
934
+}
935
+
936
+func (container *Container) ExportRw() (archive.Archive, error) {
937
+	if err := container.Mount(); err != nil {
938
+		return nil, err
939
+	}
940
+	if container.runtime == nil {
941
+		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
942
+	}
943
+	archive, err := container.runtime.Diff(container)
944
+	if err != nil {
945
+		container.Unmount()
946
+		return nil, err
947
+	}
948
+	return utils.NewReadCloserWrapper(archive, func() error {
949
+		err := archive.Close()
950
+		container.Unmount()
951
+		return err
952
+	}), nil
953
+}
954
+
955
+func (container *Container) Export() (archive.Archive, error) {
956
+	if err := container.Mount(); err != nil {
957
+		return nil, err
958
+	}
959
+
960
+	archive, err := archive.Tar(container.basefs, archive.Uncompressed)
961
+	if err != nil {
962
+		container.Unmount()
963
+		return nil, err
964
+	}
965
+	return utils.NewReadCloserWrapper(archive, func() error {
966
+		err := archive.Close()
967
+		container.Unmount()
968
+		return err
969
+	}), nil
970
+}
971
+
972
+func (container *Container) WaitTimeout(timeout time.Duration) error {
973
+	done := make(chan bool)
974
+	go func() {
975
+		container.Wait()
976
+		done <- true
977
+	}()
978
+
979
+	select {
980
+	case <-time.After(timeout):
981
+		return fmt.Errorf("Timed Out")
982
+	case <-done:
983
+		return nil
984
+	}
985
+}
986
+
987
+func (container *Container) Mount() error {
988
+	return container.runtime.Mount(container)
989
+}
990
+
991
+func (container *Container) Changes() ([]archive.Change, error) {
992
+	return container.runtime.Changes(container)
993
+}
994
+
995
+func (container *Container) GetImage() (*image.Image, error) {
996
+	if container.runtime == nil {
997
+		return nil, fmt.Errorf("Can't get image of unregistered container")
998
+	}
999
+	return container.runtime.graph.Get(container.Image)
1000
+}
1001
+
1002
+func (container *Container) Unmount() error {
1003
+	return container.runtime.Unmount(container)
1004
+}
1005
+
1006
+func (container *Container) logPath(name string) string {
1007
+	return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.ID, name))
1008
+}
1009
+
1010
+func (container *Container) ReadLog(name string) (io.Reader, error) {
1011
+	return os.Open(container.logPath(name))
1012
+}
1013
+
1014
+func (container *Container) hostConfigPath() string {
1015
+	return path.Join(container.root, "hostconfig.json")
1016
+}
1017
+
1018
+func (container *Container) jsonPath() string {
1019
+	return path.Join(container.root, "config.json")
1020
+}
1021
+
1022
+func (container *Container) EnvConfigPath() (string, error) {
1023
+	p := path.Join(container.root, "config.env")
1024
+	if _, err := os.Stat(p); err != nil {
1025
+		if os.IsNotExist(err) {
1026
+			f, err := os.Create(p)
1027
+			if err != nil {
1028
+				return "", err
1029
+			}
1030
+			f.Close()
1031
+		} else {
1032
+			return "", err
1033
+		}
1034
+	}
1035
+	return p, nil
1036
+}
1037
+
1038
+// This method must be exported to be used from the lxc template
1039
+// This directory is only usable when the container is running
1040
+func (container *Container) RootfsPath() string {
1041
+	return path.Join(container.root, "root")
1042
+}
1043
+
1044
+// This is the stand-alone version of the root fs, without any additional mounts.
1045
+// This directory is usable whenever the container is mounted (and not unmounted)
1046
+func (container *Container) BasefsPath() string {
1047
+	return container.basefs
1048
+}
1049
+
1050
+func validateID(id string) error {
1051
+	if id == "" {
1052
+		return fmt.Errorf("Invalid empty id")
1053
+	}
1054
+	return nil
1055
+}
1056
+
1057
+// GetSize, return real size, virtual size
1058
+func (container *Container) GetSize() (int64, int64) {
1059
+	var (
1060
+		sizeRw, sizeRootfs int64
1061
+		err                error
1062
+		driver             = container.runtime.driver
1063
+	)
1064
+
1065
+	if err := container.Mount(); err != nil {
1066
+		utils.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err)
1067
+		return sizeRw, sizeRootfs
1068
+	}
1069
+	defer container.Unmount()
1070
+
1071
+	if differ, ok := container.runtime.driver.(graphdriver.Differ); ok {
1072
+		sizeRw, err = differ.DiffSize(container.ID)
1073
+		if err != nil {
1074
+			utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
1075
+			// FIXME: GetSize should return an error. Not changing it now in case
1076
+			// there is a side-effect.
1077
+			sizeRw = -1
1078
+		}
1079
+	} else {
1080
+		changes, _ := container.Changes()
1081
+		if changes != nil {
1082
+			sizeRw = archive.ChangesSize(container.basefs, changes)
1083
+		} else {
1084
+			sizeRw = -1
1085
+		}
1086
+	}
1087
+
1088
+	if _, err = os.Stat(container.basefs); err != nil {
1089
+		if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil {
1090
+			sizeRootfs = -1
1091
+		}
1092
+	}
1093
+	return sizeRw, sizeRootfs
1094
+}
1095
+
1096
+func (container *Container) Copy(resource string) (io.ReadCloser, error) {
1097
+	if err := container.Mount(); err != nil {
1098
+		return nil, err
1099
+	}
1100
+	var filter []string
1101
+	basePath := path.Join(container.basefs, resource)
1102
+	stat, err := os.Stat(basePath)
1103
+	if err != nil {
1104
+		container.Unmount()
1105
+		return nil, err
1106
+	}
1107
+	if !stat.IsDir() {
1108
+		d, f := path.Split(basePath)
1109
+		basePath = d
1110
+		filter = []string{f}
1111
+	} else {
1112
+		filter = []string{path.Base(basePath)}
1113
+		basePath = path.Dir(basePath)
1114
+	}
1115
+
1116
+	archive, err := archive.TarFilter(basePath, &archive.TarOptions{
1117
+		Compression: archive.Uncompressed,
1118
+		Includes:    filter,
1119
+	})
1120
+	if err != nil {
1121
+		return nil, err
1122
+	}
1123
+	return utils.NewReadCloserWrapper(archive, func() error {
1124
+		err := archive.Close()
1125
+		container.Unmount()
1126
+		return err
1127
+	}), nil
1128
+}
1129
+
1130
+// Returns true if the container exposes a certain port
1131
+func (container *Container) Exposes(p nat.Port) bool {
1132
+	_, exists := container.Config.ExposedPorts[p]
1133
+	return exists
1134
+}
1135
+
1136
+func (container *Container) GetPtyMaster() (*os.File, error) {
1137
+	ttyConsole, ok := container.command.Terminal.(execdriver.TtyTerminal)
1138
+	if !ok {
1139
+		return nil, ErrNoTTY
1140
+	}
1141
+	return ttyConsole.Master(), nil
1142
+}
1143
+
1144
+func (container *Container) HostConfig() *runconfig.HostConfig {
1145
+	return container.hostConfig
1146
+}
1147
+
1148
+func (container *Container) SetHostConfig(hostConfig *runconfig.HostConfig) {
1149
+	container.hostConfig = hostConfig
1150
+}
1151
+
1152
+func (container *Container) DisableLink(name string) {
1153
+	if container.activeLinks != nil {
1154
+		if link, exists := container.activeLinks[name]; exists {
1155
+			link.Disable()
1156
+		} else {
1157
+			utils.Debugf("Could not find active link for %s", name)
1158
+		}
1159
+	}
1160
+}
0 1161
new file mode 100644
... ...
@@ -0,0 +1,145 @@
0
+package runtime
1
+
2
+import (
3
+	"github.com/dotcloud/docker/nat"
4
+	"testing"
5
+)
6
+
7
+func TestParseNetworkOptsPrivateOnly(t *testing.T) {
8
+	ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::80"})
9
+	if err != nil {
10
+		t.Fatal(err)
11
+	}
12
+	if len(ports) != 1 {
13
+		t.Logf("Expected 1 got %d", len(ports))
14
+		t.FailNow()
15
+	}
16
+	if len(bindings) != 1 {
17
+		t.Logf("Expected 1 got %d", len(bindings))
18
+		t.FailNow()
19
+	}
20
+	for k := range ports {
21
+		if k.Proto() != "tcp" {
22
+			t.Logf("Expected tcp got %s", k.Proto())
23
+			t.Fail()
24
+		}
25
+		if k.Port() != "80" {
26
+			t.Logf("Expected 80 got %s", k.Port())
27
+			t.Fail()
28
+		}
29
+		b, exists := bindings[k]
30
+		if !exists {
31
+			t.Log("Binding does not exist")
32
+			t.FailNow()
33
+		}
34
+		if len(b) != 1 {
35
+			t.Logf("Expected 1 got %d", len(b))
36
+			t.FailNow()
37
+		}
38
+		s := b[0]
39
+		if s.HostPort != "" {
40
+			t.Logf("Expected \"\" got %s", s.HostPort)
41
+			t.Fail()
42
+		}
43
+		if s.HostIp != "192.168.1.100" {
44
+			t.Fail()
45
+		}
46
+	}
47
+}
48
+
49
+func TestParseNetworkOptsPublic(t *testing.T) {
50
+	ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100:8080:80"})
51
+	if err != nil {
52
+		t.Fatal(err)
53
+	}
54
+	if len(ports) != 1 {
55
+		t.Logf("Expected 1 got %d", len(ports))
56
+		t.FailNow()
57
+	}
58
+	if len(bindings) != 1 {
59
+		t.Logf("Expected 1 got %d", len(bindings))
60
+		t.FailNow()
61
+	}
62
+	for k := range ports {
63
+		if k.Proto() != "tcp" {
64
+			t.Logf("Expected tcp got %s", k.Proto())
65
+			t.Fail()
66
+		}
67
+		if k.Port() != "80" {
68
+			t.Logf("Expected 80 got %s", k.Port())
69
+			t.Fail()
70
+		}
71
+		b, exists := bindings[k]
72
+		if !exists {
73
+			t.Log("Binding does not exist")
74
+			t.FailNow()
75
+		}
76
+		if len(b) != 1 {
77
+			t.Logf("Expected 1 got %d", len(b))
78
+			t.FailNow()
79
+		}
80
+		s := b[0]
81
+		if s.HostPort != "8080" {
82
+			t.Logf("Expected 8080 got %s", s.HostPort)
83
+			t.Fail()
84
+		}
85
+		if s.HostIp != "192.168.1.100" {
86
+			t.Fail()
87
+		}
88
+	}
89
+}
90
+
91
+func TestParseNetworkOptsUdp(t *testing.T) {
92
+	ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
93
+	if err != nil {
94
+		t.Fatal(err)
95
+	}
96
+	if len(ports) != 1 {
97
+		t.Logf("Expected 1 got %d", len(ports))
98
+		t.FailNow()
99
+	}
100
+	if len(bindings) != 1 {
101
+		t.Logf("Expected 1 got %d", len(bindings))
102
+		t.FailNow()
103
+	}
104
+	for k := range ports {
105
+		if k.Proto() != "udp" {
106
+			t.Logf("Expected udp got %s", k.Proto())
107
+			t.Fail()
108
+		}
109
+		if k.Port() != "6000" {
110
+			t.Logf("Expected 6000 got %s", k.Port())
111
+			t.Fail()
112
+		}
113
+		b, exists := bindings[k]
114
+		if !exists {
115
+			t.Log("Binding does not exist")
116
+			t.FailNow()
117
+		}
118
+		if len(b) != 1 {
119
+			t.Logf("Expected 1 got %d", len(b))
120
+			t.FailNow()
121
+		}
122
+		s := b[0]
123
+		if s.HostPort != "" {
124
+			t.Logf("Expected \"\" got %s", s.HostPort)
125
+			t.Fail()
126
+		}
127
+		if s.HostIp != "192.168.1.100" {
128
+			t.Fail()
129
+		}
130
+	}
131
+}
132
+
133
+func TestGetFullName(t *testing.T) {
134
+	name, err := GetFullContainerName("testing")
135
+	if err != nil {
136
+		t.Fatal(err)
137
+	}
138
+	if name != "/testing" {
139
+		t.Fatalf("Expected /testing got %s", name)
140
+	}
141
+	if _, err := GetFullContainerName(""); err == nil {
142
+		t.Fatal("Error should not be nil")
143
+	}
144
+}
0 145
new file mode 100644
... ...
@@ -0,0 +1,953 @@
0
+package runtime
1
+
2
+import (
3
+	"container/list"
4
+	"fmt"
5
+	"github.com/dotcloud/docker/archive"
6
+	"github.com/dotcloud/docker/daemonconfig"
7
+	"github.com/dotcloud/docker/dockerversion"
8
+	"github.com/dotcloud/docker/engine"
9
+	"github.com/dotcloud/docker/execdriver"
10
+	"github.com/dotcloud/docker/execdriver/lxc"
11
+	"github.com/dotcloud/docker/execdriver/native"
12
+	"github.com/dotcloud/docker/graph"
13
+	"github.com/dotcloud/docker/graphdriver"
14
+	"github.com/dotcloud/docker/graphdriver/aufs"
15
+	_ "github.com/dotcloud/docker/graphdriver/btrfs"
16
+	_ "github.com/dotcloud/docker/graphdriver/devmapper"
17
+	_ "github.com/dotcloud/docker/graphdriver/vfs"
18
+	"github.com/dotcloud/docker/image"
19
+	_ "github.com/dotcloud/docker/networkdriver/lxc"
20
+	"github.com/dotcloud/docker/networkdriver/portallocator"
21
+	"github.com/dotcloud/docker/pkg/graphdb"
22
+	"github.com/dotcloud/docker/pkg/sysinfo"
23
+	"github.com/dotcloud/docker/runconfig"
24
+	"github.com/dotcloud/docker/utils"
25
+	"io"
26
+	"io/ioutil"
27
+	"os"
28
+	"path"
29
+	"regexp"
30
+	"sort"
31
+	"strings"
32
+	"sync"
33
+	"time"
34
+)
35
+
36
+// Set the max depth to the aufs default that most
37
+// kernels are compiled with
38
+// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
39
+const MaxImageDepth = 127
40
+
41
+var (
42
+	DefaultDns                = []string{"8.8.8.8", "8.8.4.4"}
43
+	validContainerNameChars   = `[a-zA-Z0-9_.-]`
44
+	validContainerNamePattern = regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
45
+)
46
+
47
+type Runtime struct {
48
+	repository     string
49
+	sysInitPath    string
50
+	containers     *list.List
51
+	graph          *graph.Graph
52
+	repositories   *graph.TagStore
53
+	idIndex        *utils.TruncIndex
54
+	sysInfo        *sysinfo.SysInfo
55
+	volumes        *graph.Graph
56
+	srv            Server
57
+	eng            *engine.Engine
58
+	config         *daemonconfig.Config
59
+	containerGraph *graphdb.Database
60
+	driver         graphdriver.Driver
61
+	execDriver     execdriver.Driver
62
+}
63
+
64
+// List returns an array of all containers registered in the runtime.
65
+func (runtime *Runtime) List() []*Container {
66
+	containers := new(History)
67
+	for e := runtime.containers.Front(); e != nil; e = e.Next() {
68
+		containers.Add(e.Value.(*Container))
69
+	}
70
+	return *containers
71
+}
72
+
73
+func (runtime *Runtime) getContainerElement(id string) *list.Element {
74
+	for e := runtime.containers.Front(); e != nil; e = e.Next() {
75
+		container := e.Value.(*Container)
76
+		if container.ID == id {
77
+			return e
78
+		}
79
+	}
80
+	return nil
81
+}
82
+
83
+// Get looks for a container by the specified ID or name, and returns it.
84
+// If the container is not found, or if an error occurs, nil is returned.
85
+func (runtime *Runtime) Get(name string) *Container {
86
+	if c, _ := runtime.GetByName(name); c != nil {
87
+		return c
88
+	}
89
+
90
+	id, err := runtime.idIndex.Get(name)
91
+	if err != nil {
92
+		return nil
93
+	}
94
+
95
+	e := runtime.getContainerElement(id)
96
+	if e == nil {
97
+		return nil
98
+	}
99
+	return e.Value.(*Container)
100
+}
101
+
102
+// Exists returns a true if a container of the specified ID or name exists,
103
+// false otherwise.
104
+func (runtime *Runtime) Exists(id string) bool {
105
+	return runtime.Get(id) != nil
106
+}
107
+
108
+func (runtime *Runtime) containerRoot(id string) string {
109
+	return path.Join(runtime.repository, id)
110
+}
111
+
112
+// Load reads the contents of a container from disk
113
+// This is typically done at startup.
114
+func (runtime *Runtime) load(id string) (*Container, error) {
115
+	container := &Container{root: runtime.containerRoot(id)}
116
+	if err := container.FromDisk(); err != nil {
117
+		return nil, err
118
+	}
119
+	if container.ID != id {
120
+		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
121
+	}
122
+	if container.State.IsRunning() {
123
+		container.State.SetGhost(true)
124
+	}
125
+	return container, nil
126
+}
127
+
128
+// Register makes a container object usable by the runtime as <container.ID>
129
+func (runtime *Runtime) Register(container *Container) error {
130
+	if container.runtime != nil || runtime.Exists(container.ID) {
131
+		return fmt.Errorf("Container is already loaded")
132
+	}
133
+	if err := validateID(container.ID); err != nil {
134
+		return err
135
+	}
136
+	if err := runtime.ensureName(container); err != nil {
137
+		return err
138
+	}
139
+
140
+	container.runtime = runtime
141
+
142
+	// Attach to stdout and stderr
143
+	container.stderr = utils.NewWriteBroadcaster()
144
+	container.stdout = utils.NewWriteBroadcaster()
145
+	// Attach to stdin
146
+	if container.Config.OpenStdin {
147
+		container.stdin, container.stdinPipe = io.Pipe()
148
+	} else {
149
+		container.stdinPipe = utils.NopWriteCloser(ioutil.Discard) // Silently drop stdin
150
+	}
151
+	// done
152
+	runtime.containers.PushBack(container)
153
+	runtime.idIndex.Add(container.ID)
154
+
155
+	// FIXME: if the container is supposed to be running but is not, auto restart it?
156
+	//        if so, then we need to restart monitor and init a new lock
157
+	// If the container is supposed to be running, make sure of it
158
+	if container.State.IsRunning() {
159
+		if container.State.IsGhost() {
160
+			utils.Debugf("killing ghost %s", container.ID)
161
+
162
+			existingPid := container.State.Pid
163
+			container.State.SetGhost(false)
164
+			container.State.SetStopped(0)
165
+
166
+			if container.ExecDriver == "" || strings.Contains(container.ExecDriver, "lxc") {
167
+				lxc.KillLxc(container.ID, 9)
168
+			} else {
169
+				command := &execdriver.Command{
170
+					ID: container.ID,
171
+				}
172
+				command.Process = &os.Process{Pid: existingPid}
173
+				runtime.execDriver.Kill(command, 9)
174
+			}
175
+			// ensure that the filesystem is also unmounted
176
+			unmountVolumesForContainer(container)
177
+			if err := container.Unmount(); err != nil {
178
+				utils.Debugf("ghost unmount error %s", err)
179
+			}
180
+		}
181
+
182
+		info := runtime.execDriver.Info(container.ID)
183
+		if !info.IsRunning() {
184
+			utils.Debugf("Container %s was supposed to be running but is not.", container.ID)
185
+			if runtime.config.AutoRestart {
186
+				utils.Debugf("Restarting")
187
+				unmountVolumesForContainer(container)
188
+				if err := container.Unmount(); err != nil {
189
+					utils.Debugf("restart unmount error %s", err)
190
+				}
191
+
192
+				container.State.SetGhost(false)
193
+				container.State.SetStopped(0)
194
+				if err := container.Start(); err != nil {
195
+					return err
196
+				}
197
+			} else {
198
+				utils.Debugf("Marking as stopped")
199
+				container.State.SetStopped(-127)
200
+				if err := container.ToDisk(); err != nil {
201
+					return err
202
+				}
203
+			}
204
+		}
205
+	} else {
206
+		// When the container is not running, we still initialize the waitLock
207
+		// chan and close it. Receiving on nil chan blocks whereas receiving on a
208
+		// closed chan does not. In this case we do not want to block.
209
+		container.waitLock = make(chan struct{})
210
+		close(container.waitLock)
211
+	}
212
+	return nil
213
+}
214
+
215
+func (runtime *Runtime) ensureName(container *Container) error {
216
+	if container.Name == "" {
217
+		name, err := generateRandomName(runtime)
218
+		if err != nil {
219
+			name = utils.TruncateID(container.ID)
220
+		}
221
+		container.Name = name
222
+
223
+		if err := container.ToDisk(); err != nil {
224
+			utils.Debugf("Error saving container name %s", err)
225
+		}
226
+		if !runtime.containerGraph.Exists(name) {
227
+			if _, err := runtime.containerGraph.Set(name, container.ID); err != nil {
228
+				utils.Debugf("Setting default id - %s", err)
229
+			}
230
+		}
231
+	}
232
+	return nil
233
+}
234
+
235
+func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
236
+	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
237
+	if err != nil {
238
+		return err
239
+	}
240
+	src.AddWriter(log, stream)
241
+	return nil
242
+}
243
+
244
+// Destroy unregisters a container from the runtime and cleanly removes its contents from the filesystem.
245
+func (runtime *Runtime) Destroy(container *Container) error {
246
+	if container == nil {
247
+		return fmt.Errorf("The given container is <nil>")
248
+	}
249
+
250
+	element := runtime.getContainerElement(container.ID)
251
+	if element == nil {
252
+		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
253
+	}
254
+
255
+	if err := container.Stop(3); err != nil {
256
+		return err
257
+	}
258
+
259
+	if err := runtime.driver.Remove(container.ID); err != nil {
260
+		return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", runtime.driver, container.ID, err)
261
+	}
262
+
263
+	initID := fmt.Sprintf("%s-init", container.ID)
264
+	if err := runtime.driver.Remove(initID); err != nil {
265
+		return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", runtime.driver, initID, err)
266
+	}
267
+
268
+	if _, err := runtime.containerGraph.Purge(container.ID); err != nil {
269
+		utils.Debugf("Unable to remove container from link graph: %s", err)
270
+	}
271
+
272
+	// Deregister the container before removing its directory, to avoid race conditions
273
+	runtime.idIndex.Delete(container.ID)
274
+	runtime.containers.Remove(element)
275
+	if err := os.RemoveAll(container.root); err != nil {
276
+		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
277
+	}
278
+	return nil
279
+}
280
+
281
+func (runtime *Runtime) restore() error {
282
+	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
283
+		fmt.Printf("Loading containers: ")
284
+	}
285
+	dir, err := ioutil.ReadDir(runtime.repository)
286
+	if err != nil {
287
+		return err
288
+	}
289
+	containers := make(map[string]*Container)
290
+	currentDriver := runtime.driver.String()
291
+
292
+	for _, v := range dir {
293
+		id := v.Name()
294
+		container, err := runtime.load(id)
295
+		if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
296
+			fmt.Print(".")
297
+		}
298
+		if err != nil {
299
+			utils.Errorf("Failed to load container %v: %v", id, err)
300
+			continue
301
+		}
302
+
303
+		// Ignore the container if it does not support the current driver being used by the graph
304
+		if container.Driver == "" && currentDriver == "aufs" || container.Driver == currentDriver {
305
+			utils.Debugf("Loaded container %v", container.ID)
306
+			containers[container.ID] = container
307
+		} else {
308
+			utils.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID)
309
+		}
310
+	}
311
+
312
+	register := func(container *Container) {
313
+		if err := runtime.Register(container); err != nil {
314
+			utils.Debugf("Failed to register container %s: %s", container.ID, err)
315
+		}
316
+	}
317
+
318
+	if entities := runtime.containerGraph.List("/", -1); entities != nil {
319
+		for _, p := range entities.Paths() {
320
+			if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
321
+				fmt.Print(".")
322
+			}
323
+			e := entities[p]
324
+			if container, ok := containers[e.ID()]; ok {
325
+				register(container)
326
+				delete(containers, e.ID())
327
+			}
328
+		}
329
+	}
330
+
331
+	// Any containers that are left over do not exist in the graph
332
+	for _, container := range containers {
333
+		// Try to set the default name for a container if it exists prior to links
334
+		container.Name, err = generateRandomName(runtime)
335
+		if err != nil {
336
+			container.Name = utils.TruncateID(container.ID)
337
+		}
338
+
339
+		if _, err := runtime.containerGraph.Set(container.Name, container.ID); err != nil {
340
+			utils.Debugf("Setting default id - %s", err)
341
+		}
342
+		register(container)
343
+	}
344
+
345
+	if os.Getenv("DEBUG") == "" && os.Getenv("TEST") == "" {
346
+		fmt.Printf(": done.\n")
347
+	}
348
+
349
+	return nil
350
+}
351
+
352
+// Create creates a new container from the given configuration with a given name.
353
+func (runtime *Runtime) Create(config *runconfig.Config, name string) (*Container, []string, error) {
354
+	// Lookup image
355
+	img, err := runtime.repositories.LookupImage(config.Image)
356
+	if err != nil {
357
+		return nil, nil, err
358
+	}
359
+
360
+	// We add 2 layers to the depth because the container's rw and
361
+	// init layer add to the restriction
362
+	depth, err := img.Depth()
363
+	if err != nil {
364
+		return nil, nil, err
365
+	}
366
+
367
+	if depth+2 >= MaxImageDepth {
368
+		return nil, nil, fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
369
+	}
370
+
371
+	checkDeprecatedExpose := func(config *runconfig.Config) bool {
372
+		if config != nil {
373
+			if config.PortSpecs != nil {
374
+				for _, p := range config.PortSpecs {
375
+					if strings.Contains(p, ":") {
376
+						return true
377
+					}
378
+				}
379
+			}
380
+		}
381
+		return false
382
+	}
383
+
384
+	warnings := []string{}
385
+	if checkDeprecatedExpose(img.Config) || checkDeprecatedExpose(config) {
386
+		warnings = append(warnings, "The mapping to public ports on your host via Dockerfile EXPOSE (host:port:port) has been deprecated. Use -p to publish the ports.")
387
+	}
388
+
389
+	if img.Config != nil {
390
+		if err := runconfig.Merge(config, img.Config); err != nil {
391
+			return nil, nil, err
392
+		}
393
+	}
394
+
395
+	if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
396
+		return nil, nil, fmt.Errorf("No command specified")
397
+	}
398
+
399
+	// Generate id
400
+	id := utils.GenerateRandomID()
401
+
402
+	if name == "" {
403
+		name, err = generateRandomName(runtime)
404
+		if err != nil {
405
+			name = utils.TruncateID(id)
406
+		}
407
+	} else {
408
+		if !validContainerNamePattern.MatchString(name) {
409
+			return nil, nil, fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
410
+		}
411
+	}
412
+
413
+	if name[0] != '/' {
414
+		name = "/" + name
415
+	}
416
+
417
+	// Set the enitity in the graph using the default name specified
418
+	if _, err := runtime.containerGraph.Set(name, id); err != nil {
419
+		if !graphdb.IsNonUniqueNameError(err) {
420
+			return nil, nil, err
421
+		}
422
+
423
+		conflictingContainer, err := runtime.GetByName(name)
424
+		if err != nil {
425
+			if strings.Contains(err.Error(), "Could not find entity") {
426
+				return nil, nil, err
427
+			}
428
+
429
+			// Remove name and continue starting the container
430
+			if err := runtime.containerGraph.Delete(name); err != nil {
431
+				return nil, nil, err
432
+			}
433
+		} else {
434
+			nameAsKnownByUser := strings.TrimPrefix(name, "/")
435
+			return nil, nil, fmt.Errorf(
436
+				"Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", nameAsKnownByUser,
437
+				utils.TruncateID(conflictingContainer.ID), nameAsKnownByUser)
438
+		}
439
+	}
440
+
441
+	// Generate default hostname
442
+	// FIXME: the lxc template no longer needs to set a default hostname
443
+	if config.Hostname == "" {
444
+		config.Hostname = id[:12]
445
+	}
446
+
447
+	var args []string
448
+	var entrypoint string
449
+
450
+	if len(config.Entrypoint) != 0 {
451
+		entrypoint = config.Entrypoint[0]
452
+		args = append(config.Entrypoint[1:], config.Cmd...)
453
+	} else {
454
+		entrypoint = config.Cmd[0]
455
+		args = config.Cmd[1:]
456
+	}
457
+
458
+	container := &Container{
459
+		// FIXME: we should generate the ID here instead of receiving it as an argument
460
+		ID:              id,
461
+		Created:         time.Now().UTC(),
462
+		Path:            entrypoint,
463
+		Args:            args, //FIXME: de-duplicate from config
464
+		Config:          config,
465
+		hostConfig:      &runconfig.HostConfig{},
466
+		Image:           img.ID, // Always use the resolved image id
467
+		NetworkSettings: &NetworkSettings{},
468
+		Name:            name,
469
+		Driver:          runtime.driver.String(),
470
+		ExecDriver:      runtime.execDriver.Name(),
471
+	}
472
+	container.root = runtime.containerRoot(container.ID)
473
+	// Step 1: create the container directory.
474
+	// This doubles as a barrier to avoid race conditions.
475
+	if err := os.Mkdir(container.root, 0700); err != nil {
476
+		return nil, nil, err
477
+	}
478
+
479
+	initID := fmt.Sprintf("%s-init", container.ID)
480
+	if err := runtime.driver.Create(initID, img.ID); err != nil {
481
+		return nil, nil, err
482
+	}
483
+	initPath, err := runtime.driver.Get(initID)
484
+	if err != nil {
485
+		return nil, nil, err
486
+	}
487
+	defer runtime.driver.Put(initID)
488
+
489
+	if err := graph.SetupInitLayer(initPath); err != nil {
490
+		return nil, nil, err
491
+	}
492
+
493
+	if err := runtime.driver.Create(container.ID, initID); err != nil {
494
+		return nil, nil, err
495
+	}
496
+	resolvConf, err := utils.GetResolvConf()
497
+	if err != nil {
498
+		return nil, nil, err
499
+	}
500
+
501
+	if len(config.Dns) == 0 && len(runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
502
+		runtime.config.Dns = DefaultDns
503
+	}
504
+
505
+	// If custom dns exists, then create a resolv.conf for the container
506
+	if len(config.Dns) > 0 || len(runtime.config.Dns) > 0 {
507
+		var dns []string
508
+		if len(config.Dns) > 0 {
509
+			dns = config.Dns
510
+		} else {
511
+			dns = runtime.config.Dns
512
+		}
513
+		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
514
+		f, err := os.Create(container.ResolvConfPath)
515
+		if err != nil {
516
+			return nil, nil, err
517
+		}
518
+		defer f.Close()
519
+		for _, dns := range dns {
520
+			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
521
+				return nil, nil, err
522
+			}
523
+		}
524
+	} else {
525
+		container.ResolvConfPath = "/etc/resolv.conf"
526
+	}
527
+
528
+	// Step 2: save the container json
529
+	if err := container.ToDisk(); err != nil {
530
+		return nil, nil, err
531
+	}
532
+
533
+	// Step 3: register the container
534
+	if err := runtime.Register(container); err != nil {
535
+		return nil, nil, err
536
+	}
537
+	return container, warnings, nil
538
+}
539
+
540
+// Commit creates a new filesystem image from the current state of a container.
541
+// The image can optionally be tagged into a repository
542
+func (runtime *Runtime) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
543
+	// FIXME: freeze the container before copying it to avoid data corruption?
544
+	// FIXME: this shouldn't be in commands.
545
+	if err := container.Mount(); err != nil {
546
+		return nil, err
547
+	}
548
+	defer container.Unmount()
549
+
550
+	rwTar, err := container.ExportRw()
551
+	if err != nil {
552
+		return nil, err
553
+	}
554
+	defer rwTar.Close()
555
+
556
+	// Create a new image from the container's base layers + a new layer from container changes
557
+	var (
558
+		containerID, containerImage string
559
+		containerConfig             *runconfig.Config
560
+	)
561
+	if container != nil {
562
+		containerID = container.ID
563
+		containerImage = container.Image
564
+		containerConfig = container.Config
565
+	}
566
+	img, err := runtime.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
567
+	if err != nil {
568
+		return nil, err
569
+	}
570
+	// Register the image if needed
571
+	if repository != "" {
572
+		if err := runtime.repositories.Set(repository, tag, img.ID, true); err != nil {
573
+			return img, err
574
+		}
575
+	}
576
+	return img, nil
577
+}
578
+
579
+func GetFullContainerName(name string) (string, error) {
580
+	if name == "" {
581
+		return "", fmt.Errorf("Container name cannot be empty")
582
+	}
583
+	if name[0] != '/' {
584
+		name = "/" + name
585
+	}
586
+	return name, nil
587
+}
588
+
589
+func (runtime *Runtime) GetByName(name string) (*Container, error) {
590
+	fullName, err := GetFullContainerName(name)
591
+	if err != nil {
592
+		return nil, err
593
+	}
594
+	entity := runtime.containerGraph.Get(fullName)
595
+	if entity == nil {
596
+		return nil, fmt.Errorf("Could not find entity for %s", name)
597
+	}
598
+	e := runtime.getContainerElement(entity.ID())
599
+	if e == nil {
600
+		return nil, fmt.Errorf("Could not find container for entity id %s", entity.ID())
601
+	}
602
+	return e.Value.(*Container), nil
603
+}
604
+
605
+func (runtime *Runtime) Children(name string) (map[string]*Container, error) {
606
+	name, err := GetFullContainerName(name)
607
+	if err != nil {
608
+		return nil, err
609
+	}
610
+	children := make(map[string]*Container)
611
+
612
+	err = runtime.containerGraph.Walk(name, func(p string, e *graphdb.Entity) error {
613
+		c := runtime.Get(e.ID())
614
+		if c == nil {
615
+			return fmt.Errorf("Could not get container for name %s and id %s", e.ID(), p)
616
+		}
617
+		children[p] = c
618
+		return nil
619
+	}, 0)
620
+
621
+	if err != nil {
622
+		return nil, err
623
+	}
624
+	return children, nil
625
+}
626
+
627
+func (runtime *Runtime) RegisterLink(parent, child *Container, alias string) error {
628
+	fullName := path.Join(parent.Name, alias)
629
+	if !runtime.containerGraph.Exists(fullName) {
630
+		_, err := runtime.containerGraph.Set(fullName, child.ID)
631
+		return err
632
+	}
633
+	return nil
634
+}
635
+
636
+// FIXME: harmonize with NewGraph()
637
+func NewRuntime(config *daemonconfig.Config, eng *engine.Engine) (*Runtime, error) {
638
+	runtime, err := NewRuntimeFromDirectory(config, eng)
639
+	if err != nil {
640
+		return nil, err
641
+	}
642
+	return runtime, nil
643
+}
644
+
645
+func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Runtime, error) {
646
+
647
+	// Set the default driver
648
+	graphdriver.DefaultDriver = config.GraphDriver
649
+
650
+	// Load storage driver
651
+	driver, err := graphdriver.New(config.Root)
652
+	if err != nil {
653
+		return nil, err
654
+	}
655
+	utils.Debugf("Using graph driver %s", driver)
656
+
657
+	runtimeRepo := path.Join(config.Root, "containers")
658
+
659
+	if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) {
660
+		return nil, err
661
+	}
662
+
663
+	if ad, ok := driver.(*aufs.Driver); ok {
664
+		utils.Debugf("Migrating existing containers")
665
+		if err := ad.Migrate(config.Root, graph.SetupInitLayer); err != nil {
666
+			return nil, err
667
+		}
668
+	}
669
+
670
+	utils.Debugf("Creating images graph")
671
+	g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver)
672
+	if err != nil {
673
+		return nil, err
674
+	}
675
+
676
+	// We don't want to use a complex driver like aufs or devmapper
677
+	// for volumes, just a plain filesystem
678
+	volumesDriver, err := graphdriver.GetDriver("vfs", config.Root)
679
+	if err != nil {
680
+		return nil, err
681
+	}
682
+	utils.Debugf("Creating volumes graph")
683
+	volumes, err := graph.NewGraph(path.Join(config.Root, "volumes"), volumesDriver)
684
+	if err != nil {
685
+		return nil, err
686
+	}
687
+	utils.Debugf("Creating repository list")
688
+	repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g)
689
+	if err != nil {
690
+		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
691
+	}
692
+
693
+	if !config.DisableNetwork {
694
+		job := eng.Job("init_networkdriver")
695
+
696
+		job.SetenvBool("EnableIptables", config.EnableIptables)
697
+		job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication)
698
+		job.SetenvBool("EnableIpForward", config.EnableIpForward)
699
+		job.Setenv("BridgeIface", config.BridgeIface)
700
+		job.Setenv("BridgeIP", config.BridgeIP)
701
+		job.Setenv("DefaultBindingIP", config.DefaultIp.String())
702
+
703
+		if err := job.Run(); err != nil {
704
+			return nil, err
705
+		}
706
+	}
707
+
708
+	graphdbPath := path.Join(config.Root, "linkgraph.db")
709
+	graph, err := graphdb.NewSqliteConn(graphdbPath)
710
+	if err != nil {
711
+		return nil, err
712
+	}
713
+
714
+	localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
715
+	sysInitPath := utils.DockerInitPath(localCopy)
716
+	if sysInitPath == "" {
717
+		return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.io/en/latest/contributing/devenvironment for official build instructions.")
718
+	}
719
+
720
+	if sysInitPath != localCopy {
721
+		// When we find a suitable dockerinit binary (even if it's our local binary), we copy it into config.Root at localCopy for future use (so that the original can go away without that being a problem, for example during a package upgrade).
722
+		if err := os.Mkdir(path.Dir(localCopy), 0700); err != nil && !os.IsExist(err) {
723
+			return nil, err
724
+		}
725
+		if _, err := utils.CopyFile(sysInitPath, localCopy); err != nil {
726
+			return nil, err
727
+		}
728
+		if err := os.Chmod(localCopy, 0700); err != nil {
729
+			return nil, err
730
+		}
731
+		sysInitPath = localCopy
732
+	}
733
+
734
+	var (
735
+		ed      execdriver.Driver
736
+		sysInfo = sysinfo.New(false)
737
+	)
738
+
739
+	switch config.ExecDriver {
740
+	case "lxc":
741
+		// we want to five the lxc driver the full docker root because it needs
742
+		// to access and write config and template files in /var/lib/docker/containers/*
743
+		// to be backwards compatible
744
+		ed, err = lxc.NewDriver(config.Root, sysInfo.AppArmor)
745
+	case "native":
746
+		ed, err = native.NewDriver(path.Join(config.Root, "execdriver", "native"))
747
+	default:
748
+		return nil, fmt.Errorf("unknown exec driver %s", config.ExecDriver)
749
+	}
750
+	if err != nil {
751
+		return nil, err
752
+	}
753
+
754
+	runtime := &Runtime{
755
+		repository:     runtimeRepo,
756
+		containers:     list.New(),
757
+		graph:          g,
758
+		repositories:   repositories,
759
+		idIndex:        utils.NewTruncIndex(),
760
+		sysInfo:        sysInfo,
761
+		volumes:        volumes,
762
+		config:         config,
763
+		containerGraph: graph,
764
+		driver:         driver,
765
+		sysInitPath:    sysInitPath,
766
+		execDriver:     ed,
767
+		eng:            eng,
768
+	}
769
+
770
+	if err := runtime.restore(); err != nil {
771
+		return nil, err
772
+	}
773
+	return runtime, nil
774
+}
775
+
776
+func (runtime *Runtime) Close() error {
777
+	errorsStrings := []string{}
778
+	if err := portallocator.ReleaseAll(); err != nil {
779
+		utils.Errorf("portallocator.ReleaseAll(): %s", err)
780
+		errorsStrings = append(errorsStrings, err.Error())
781
+	}
782
+	if err := runtime.driver.Cleanup(); err != nil {
783
+		utils.Errorf("runtime.driver.Cleanup(): %s", err.Error())
784
+		errorsStrings = append(errorsStrings, err.Error())
785
+	}
786
+	if err := runtime.containerGraph.Close(); err != nil {
787
+		utils.Errorf("runtime.containerGraph.Close(): %s", err.Error())
788
+		errorsStrings = append(errorsStrings, err.Error())
789
+	}
790
+	if len(errorsStrings) > 0 {
791
+		return fmt.Errorf("%s", strings.Join(errorsStrings, ", "))
792
+	}
793
+	return nil
794
+}
795
+
796
+func (runtime *Runtime) Mount(container *Container) error {
797
+	dir, err := runtime.driver.Get(container.ID)
798
+	if err != nil {
799
+		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, runtime.driver, err)
800
+	}
801
+	if container.basefs == "" {
802
+		container.basefs = dir
803
+	} else if container.basefs != dir {
804
+		return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
805
+			runtime.driver, container.ID, container.basefs, dir)
806
+	}
807
+	return nil
808
+}
809
+
810
+func (runtime *Runtime) Unmount(container *Container) error {
811
+	runtime.driver.Put(container.ID)
812
+	return nil
813
+}
814
+
815
+func (runtime *Runtime) Changes(container *Container) ([]archive.Change, error) {
816
+	if differ, ok := runtime.driver.(graphdriver.Differ); ok {
817
+		return differ.Changes(container.ID)
818
+	}
819
+	cDir, err := runtime.driver.Get(container.ID)
820
+	if err != nil {
821
+		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
822
+	}
823
+	defer runtime.driver.Put(container.ID)
824
+	initDir, err := runtime.driver.Get(container.ID + "-init")
825
+	if err != nil {
826
+		return nil, fmt.Errorf("Error getting container init rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
827
+	}
828
+	defer runtime.driver.Put(container.ID + "-init")
829
+	return archive.ChangesDirs(cDir, initDir)
830
+}
831
+
832
+func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
833
+	if differ, ok := runtime.driver.(graphdriver.Differ); ok {
834
+		return differ.Diff(container.ID)
835
+	}
836
+
837
+	changes, err := runtime.Changes(container)
838
+	if err != nil {
839
+		return nil, err
840
+	}
841
+
842
+	cDir, err := runtime.driver.Get(container.ID)
843
+	if err != nil {
844
+		return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err)
845
+	}
846
+
847
+	archive, err := archive.ExportChanges(cDir, changes)
848
+	if err != nil {
849
+		return nil, err
850
+	}
851
+	return utils.NewReadCloserWrapper(archive, func() error {
852
+		err := archive.Close()
853
+		runtime.driver.Put(container.ID)
854
+		return err
855
+	}), nil
856
+}
857
+
858
+func (runtime *Runtime) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
859
+	return runtime.execDriver.Run(c.command, pipes, startCallback)
860
+}
861
+
862
+func (runtime *Runtime) Kill(c *Container, sig int) error {
863
+	return runtime.execDriver.Kill(c.command, sig)
864
+}
865
+
866
+// Nuke kills all containers then removes all content
867
+// from the content root, including images, volumes and
868
+// container filesystems.
869
+// Again: this will remove your entire docker runtime!
870
+func (runtime *Runtime) Nuke() error {
871
+	var wg sync.WaitGroup
872
+	for _, container := range runtime.List() {
873
+		wg.Add(1)
874
+		go func(c *Container) {
875
+			c.Kill()
876
+			wg.Done()
877
+		}(container)
878
+	}
879
+	wg.Wait()
880
+	runtime.Close()
881
+
882
+	return os.RemoveAll(runtime.config.Root)
883
+}
884
+
885
+// FIXME: this is a convenience function for integration tests
886
+// which need direct access to runtime.graph.
887
+// Once the tests switch to using engine and jobs, this method
888
+// can go away.
889
+func (runtime *Runtime) Graph() *graph.Graph {
890
+	return runtime.graph
891
+}
892
+
893
+func (runtime *Runtime) Repositories() *graph.TagStore {
894
+	return runtime.repositories
895
+}
896
+
897
+func (runtime *Runtime) Config() *daemonconfig.Config {
898
+	return runtime.config
899
+}
900
+
901
+func (runtime *Runtime) SystemConfig() *sysinfo.SysInfo {
902
+	return runtime.sysInfo
903
+}
904
+
905
+func (runtime *Runtime) SystemInitPath() string {
906
+	return runtime.sysInitPath
907
+}
908
+
909
+func (runtime *Runtime) GraphDriver() graphdriver.Driver {
910
+	return runtime.driver
911
+}
912
+
913
+func (runtime *Runtime) ExecutionDriver() execdriver.Driver {
914
+	return runtime.execDriver
915
+}
916
+
917
+func (runtime *Runtime) Volumes() *graph.Graph {
918
+	return runtime.volumes
919
+}
920
+
921
+func (runtime *Runtime) ContainerGraph() *graphdb.Database {
922
+	return runtime.containerGraph
923
+}
924
+
925
+func (runtime *Runtime) SetServer(server Server) {
926
+	runtime.srv = server
927
+}
928
+
929
+// History is a convenience type for storing a list of containers,
930
+// ordered by creation date.
931
+type History []*Container
932
+
933
+func (history *History) Len() int {
934
+	return len(*history)
935
+}
936
+
937
+func (history *History) Less(i, j int) bool {
938
+	containers := *history
939
+	return containers[j].When().Before(containers[i].When())
940
+}
941
+
942
+func (history *History) Swap(i, j int) {
943
+	containers := *history
944
+	tmp := containers[i]
945
+	containers[i] = containers[j]
946
+	containers[j] = tmp
947
+}
948
+
949
+func (history *History) Add(container *Container) {
950
+	*history = append(*history, container)
951
+	sort.Sort(history)
952
+}
0 953
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+package runtime
1
+
2
+import (
3
+	"github.com/dotcloud/docker/utils"
4
+)
5
+
6
+type Server interface {
7
+	LogEvent(action, id, from string) *utils.JSONMessage
8
+}
0 9
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+package runtime
1
+
2
+import "sort"
3
+
4
+type containerSorter struct {
5
+	containers []*Container
6
+	by         func(i, j *Container) bool
7
+}
8
+
9
+func (s *containerSorter) Len() int {
10
+	return len(s.containers)
11
+}
12
+
13
+func (s *containerSorter) Swap(i, j int) {
14
+	s.containers[i], s.containers[j] = s.containers[j], s.containers[i]
15
+}
16
+
17
+func (s *containerSorter) Less(i, j int) bool {
18
+	return s.by(s.containers[i], s.containers[j])
19
+}
20
+
21
+func sortContainers(containers []*Container, predicate func(i, j *Container) bool) {
22
+	s := &containerSorter{containers, predicate}
23
+	sort.Sort(s)
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,81 @@
0
+package runtime
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/utils"
5
+	"sync"
6
+	"time"
7
+)
8
+
9
+type State struct {
10
+	sync.RWMutex
11
+	Running    bool
12
+	Pid        int
13
+	ExitCode   int
14
+	StartedAt  time.Time
15
+	FinishedAt time.Time
16
+	Ghost      bool
17
+}
18
+
19
+// String returns a human-readable description of the state
20
+func (s *State) String() string {
21
+	s.RLock()
22
+	defer s.RUnlock()
23
+
24
+	if s.Running {
25
+		if s.Ghost {
26
+			return fmt.Sprintf("Ghost")
27
+		}
28
+		return fmt.Sprintf("Up %s", utils.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
29
+	}
30
+	return fmt.Sprintf("Exit %d", s.ExitCode)
31
+}
32
+
33
+func (s *State) IsRunning() bool {
34
+	s.RLock()
35
+	defer s.RUnlock()
36
+
37
+	return s.Running
38
+}
39
+
40
+func (s *State) IsGhost() bool {
41
+	s.RLock()
42
+	defer s.RUnlock()
43
+
44
+	return s.Ghost
45
+}
46
+
47
+func (s *State) GetExitCode() int {
48
+	s.RLock()
49
+	defer s.RUnlock()
50
+
51
+	return s.ExitCode
52
+}
53
+
54
+func (s *State) SetGhost(val bool) {
55
+	s.Lock()
56
+	defer s.Unlock()
57
+
58
+	s.Ghost = val
59
+}
60
+
61
+func (s *State) SetRunning(pid int) {
62
+	s.Lock()
63
+	defer s.Unlock()
64
+
65
+	s.Running = true
66
+	s.Ghost = false
67
+	s.ExitCode = 0
68
+	s.Pid = pid
69
+	s.StartedAt = time.Now().UTC()
70
+}
71
+
72
+func (s *State) SetStopped(exitCode int) {
73
+	s.Lock()
74
+	defer s.Unlock()
75
+
76
+	s.Running = false
77
+	s.Pid = 0
78
+	s.FinishedAt = time.Now().UTC()
79
+	s.ExitCode = exitCode
80
+}
0 81
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+package runtime
1
+
2
+import (
3
+	"github.com/dotcloud/docker/nat"
4
+	"github.com/dotcloud/docker/pkg/namesgenerator"
5
+	"github.com/dotcloud/docker/runconfig"
6
+)
7
+
8
+func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
9
+	if config.PortSpecs != nil {
10
+		ports, bindings, err := nat.ParsePortSpecs(config.PortSpecs)
11
+		if err != nil {
12
+			return err
13
+		}
14
+		config.PortSpecs = nil
15
+		if len(bindings) > 0 {
16
+			if hostConfig == nil {
17
+				hostConfig = &runconfig.HostConfig{}
18
+			}
19
+			hostConfig.PortBindings = bindings
20
+		}
21
+
22
+		if config.ExposedPorts == nil {
23
+			config.ExposedPorts = make(nat.PortSet, len(ports))
24
+		}
25
+		for k, v := range ports {
26
+			config.ExposedPorts[k] = v
27
+		}
28
+	}
29
+	return nil
30
+}
31
+
32
+type checker struct {
33
+	runtime *Runtime
34
+}
35
+
36
+func (c *checker) Exists(name string) bool {
37
+	return c.runtime.containerGraph.Exists("/" + name)
38
+}
39
+
40
+// Generate a random and unique name
41
+func generateRandomName(runtime *Runtime) (string, error) {
42
+	return namesgenerator.GenerateRandomName(&checker{runtime})
43
+}
0 44
new file mode 100644
... ...
@@ -0,0 +1,332 @@
0
+package runtime
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/archive"
5
+	"github.com/dotcloud/docker/pkg/mount"
6
+	"github.com/dotcloud/docker/utils"
7
+	"io/ioutil"
8
+	"log"
9
+	"os"
10
+	"path/filepath"
11
+	"strings"
12
+	"syscall"
13
+)
14
+
15
+type BindMap struct {
16
+	SrcPath string
17
+	DstPath string
18
+	Mode    string
19
+}
20
+
21
+func prepareVolumesForContainer(container *Container) error {
22
+	if container.Volumes == nil || len(container.Volumes) == 0 {
23
+		container.Volumes = make(map[string]string)
24
+		container.VolumesRW = make(map[string]bool)
25
+		if err := applyVolumesFrom(container); err != nil {
26
+			return err
27
+		}
28
+	}
29
+
30
+	if err := createVolumes(container); err != nil {
31
+		return err
32
+	}
33
+	return nil
34
+}
35
+
36
+func mountVolumesForContainer(container *Container, envPath string) error {
37
+	// Setup the root fs as a bind mount of the base fs
38
+	var (
39
+		root    = container.RootfsPath()
40
+		runtime = container.runtime
41
+	)
42
+	if err := os.MkdirAll(root, 0755); err != nil && !os.IsExist(err) {
43
+		return nil
44
+	}
45
+
46
+	// Create a bind mount of the base fs as a place where we can add mounts
47
+	// without affecting the ability to access the base fs
48
+	if err := mount.Mount(container.basefs, root, "none", "bind,rw"); err != nil {
49
+		return err
50
+	}
51
+
52
+	// Make sure the root fs is private so the mounts here don't propagate to basefs
53
+	if err := mount.ForceMount(root, root, "none", "private"); err != nil {
54
+		return err
55
+	}
56
+
57
+	// Mount docker specific files into the containers root fs
58
+	if err := mount.Mount(runtime.sysInitPath, filepath.Join(root, "/.dockerinit"), "none", "bind,ro"); err != nil {
59
+		return err
60
+	}
61
+	if err := mount.Mount(envPath, filepath.Join(root, "/.dockerenv"), "none", "bind,ro"); err != nil {
62
+		return err
63
+	}
64
+	if err := mount.Mount(container.ResolvConfPath, filepath.Join(root, "/etc/resolv.conf"), "none", "bind,ro"); err != nil {
65
+		return err
66
+	}
67
+
68
+	if container.HostnamePath != "" && container.HostsPath != "" {
69
+		if err := mount.Mount(container.HostnamePath, filepath.Join(root, "/etc/hostname"), "none", "bind,ro"); err != nil {
70
+			return err
71
+		}
72
+		if err := mount.Mount(container.HostsPath, filepath.Join(root, "/etc/hosts"), "none", "bind,ro"); err != nil {
73
+			return err
74
+		}
75
+	}
76
+
77
+	// Mount user specified volumes
78
+	for r, v := range container.Volumes {
79
+		mountAs := "ro"
80
+		if container.VolumesRW[r] {
81
+			mountAs = "rw"
82
+		}
83
+
84
+		r = filepath.Join(root, r)
85
+		if p, err := utils.FollowSymlinkInScope(r, root); err != nil {
86
+			return err
87
+		} else {
88
+			r = p
89
+		}
90
+
91
+		if err := mount.Mount(v, r, "none", fmt.Sprintf("bind,%s", mountAs)); err != nil {
92
+			return err
93
+		}
94
+	}
95
+	return nil
96
+}
97
+
98
+func unmountVolumesForContainer(container *Container) {
99
+	var (
100
+		root   = container.RootfsPath()
101
+		mounts = []string{
102
+			root,
103
+			filepath.Join(root, "/.dockerinit"),
104
+			filepath.Join(root, "/.dockerenv"),
105
+			filepath.Join(root, "/etc/resolv.conf"),
106
+		}
107
+	)
108
+
109
+	if container.HostnamePath != "" && container.HostsPath != "" {
110
+		mounts = append(mounts, filepath.Join(root, "/etc/hostname"), filepath.Join(root, "/etc/hosts"))
111
+	}
112
+
113
+	for r := range container.Volumes {
114
+		mounts = append(mounts, filepath.Join(root, r))
115
+	}
116
+
117
+	for i := len(mounts) - 1; i >= 0; i-- {
118
+		if lastError := mount.Unmount(mounts[i]); lastError != nil {
119
+			log.Printf("Failed to umount %v: %v", mounts[i], lastError)
120
+		}
121
+	}
122
+}
123
+
124
+func applyVolumesFrom(container *Container) error {
125
+	if container.Config.VolumesFrom != "" {
126
+		for _, containerSpec := range strings.Split(container.Config.VolumesFrom, ",") {
127
+			var (
128
+				mountRW   = true
129
+				specParts = strings.SplitN(containerSpec, ":", 2)
130
+			)
131
+
132
+			switch len(specParts) {
133
+			case 0:
134
+				return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
135
+			case 2:
136
+				switch specParts[1] {
137
+				case "ro":
138
+					mountRW = false
139
+				case "rw": // mountRW is already true
140
+				default:
141
+					return fmt.Errorf("Malformed volumes-from specification: %s", containerSpec)
142
+				}
143
+			}
144
+
145
+			c := container.runtime.Get(specParts[0])
146
+			if c == nil {
147
+				return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
148
+			}
149
+
150
+			for volPath, id := range c.Volumes {
151
+				if _, exists := container.Volumes[volPath]; exists {
152
+					continue
153
+				}
154
+				if err := os.MkdirAll(filepath.Join(container.basefs, volPath), 0755); err != nil {
155
+					return err
156
+				}
157
+				container.Volumes[volPath] = id
158
+				if isRW, exists := c.VolumesRW[volPath]; exists {
159
+					container.VolumesRW[volPath] = isRW && mountRW
160
+				}
161
+			}
162
+
163
+		}
164
+	}
165
+	return nil
166
+}
167
+
168
+func getBindMap(container *Container) (map[string]BindMap, error) {
169
+	var (
170
+		// Create the requested bind mounts
171
+		binds = make(map[string]BindMap)
172
+		// Define illegal container destinations
173
+		illegalDsts = []string{"/", "."}
174
+	)
175
+
176
+	for _, bind := range container.hostConfig.Binds {
177
+		// FIXME: factorize bind parsing in parseBind
178
+		var (
179
+			src, dst, mode string
180
+			arr            = strings.Split(bind, ":")
181
+		)
182
+
183
+		if len(arr) == 2 {
184
+			src = arr[0]
185
+			dst = arr[1]
186
+			mode = "rw"
187
+		} else if len(arr) == 3 {
188
+			src = arr[0]
189
+			dst = arr[1]
190
+			mode = arr[2]
191
+		} else {
192
+			return nil, fmt.Errorf("Invalid bind specification: %s", bind)
193
+		}
194
+
195
+		// Bail if trying to mount to an illegal destination
196
+		for _, illegal := range illegalDsts {
197
+			if dst == illegal {
198
+				return nil, fmt.Errorf("Illegal bind destination: %s", dst)
199
+			}
200
+		}
201
+
202
+		bindMap := BindMap{
203
+			SrcPath: src,
204
+			DstPath: dst,
205
+			Mode:    mode,
206
+		}
207
+		binds[filepath.Clean(dst)] = bindMap
208
+	}
209
+	return binds, nil
210
+}
211
+
212
+func createVolumes(container *Container) error {
213
+	binds, err := getBindMap(container)
214
+	if err != nil {
215
+		return err
216
+	}
217
+
218
+	volumesDriver := container.runtime.volumes.Driver()
219
+	// Create the requested volumes if they don't exist
220
+	for volPath := range container.Config.Volumes {
221
+		volPath = filepath.Clean(volPath)
222
+		volIsDir := true
223
+		// Skip existing volumes
224
+		if _, exists := container.Volumes[volPath]; exists {
225
+			continue
226
+		}
227
+		var srcPath string
228
+		var isBindMount bool
229
+		srcRW := false
230
+		// If an external bind is defined for this volume, use that as a source
231
+		if bindMap, exists := binds[volPath]; exists {
232
+			isBindMount = true
233
+			srcPath = bindMap.SrcPath
234
+			if strings.ToLower(bindMap.Mode) == "rw" {
235
+				srcRW = true
236
+			}
237
+			if stat, err := os.Stat(bindMap.SrcPath); err != nil {
238
+				return err
239
+			} else {
240
+				volIsDir = stat.IsDir()
241
+			}
242
+			// Otherwise create an directory in $ROOT/volumes/ and use that
243
+		} else {
244
+
245
+			// Do not pass a container as the parameter for the volume creation.
246
+			// The graph driver using the container's information ( Image ) to
247
+			// create the parent.
248
+			c, err := container.runtime.volumes.Create(nil, "", "", "", "", nil, nil)
249
+			if err != nil {
250
+				return err
251
+			}
252
+			srcPath, err = volumesDriver.Get(c.ID)
253
+			if err != nil {
254
+				return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
255
+			}
256
+			srcRW = true // RW by default
257
+		}
258
+
259
+		if p, err := filepath.EvalSymlinks(srcPath); err != nil {
260
+			return err
261
+		} else {
262
+			srcPath = p
263
+		}
264
+
265
+		container.Volumes[volPath] = srcPath
266
+		container.VolumesRW[volPath] = srcRW
267
+
268
+		// Create the mountpoint
269
+		volPath = filepath.Join(container.basefs, volPath)
270
+		rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.basefs)
271
+		if err != nil {
272
+			return err
273
+		}
274
+
275
+		if _, err := os.Stat(rootVolPath); err != nil {
276
+			if os.IsNotExist(err) {
277
+				if volIsDir {
278
+					if err := os.MkdirAll(rootVolPath, 0755); err != nil {
279
+						return err
280
+					}
281
+				} else {
282
+					if err := os.MkdirAll(filepath.Dir(rootVolPath), 0755); err != nil {
283
+						return err
284
+					}
285
+					if f, err := os.OpenFile(rootVolPath, os.O_CREATE, 0755); err != nil {
286
+						return err
287
+					} else {
288
+						f.Close()
289
+					}
290
+				}
291
+			}
292
+		}
293
+
294
+		// Do not copy or change permissions if we are mounting from the host
295
+		if srcRW && !isBindMount {
296
+			volList, err := ioutil.ReadDir(rootVolPath)
297
+			if err != nil {
298
+				return err
299
+			}
300
+			if len(volList) > 0 {
301
+				srcList, err := ioutil.ReadDir(srcPath)
302
+				if err != nil {
303
+					return err
304
+				}
305
+				if len(srcList) == 0 {
306
+					// If the source volume is empty copy files from the root into the volume
307
+					if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
308
+						return err
309
+					}
310
+
311
+					var stat syscall.Stat_t
312
+					if err := syscall.Stat(rootVolPath, &stat); err != nil {
313
+						return err
314
+					}
315
+					var srcStat syscall.Stat_t
316
+					if err := syscall.Stat(srcPath, &srcStat); err != nil {
317
+						return err
318
+					}
319
+					// Change the source volume's ownership if it differs from the root
320
+					// files that were just copied
321
+					if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
322
+						if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
323
+							return err
324
+						}
325
+					}
326
+				}
327
+			}
328
+		}
329
+	}
330
+	return nil
331
+}
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/dotcloud/docker/pkg/graphdb"
14 14
 	"github.com/dotcloud/docker/registry"
15 15
 	"github.com/dotcloud/docker/runconfig"
16
+	"github.com/dotcloud/docker/runtime"
16 17
 	"github.com/dotcloud/docker/utils"
17 18
 	"io"
18 19
 	"io/ioutil"
... ...
@@ -24,7 +25,7 @@ import (
24 24
 	"os/signal"
25 25
 	"path"
26 26
 	"path/filepath"
27
-	"runtime"
27
+	goruntime "runtime"
28 28
 	"strconv"
29 29
 	"strings"
30 30
 	"sync"
... ...
@@ -41,9 +42,9 @@ func InitServer(job *engine.Job) engine.Status {
41 41
 	if err != nil {
42 42
 		return job.Error(err)
43 43
 	}
44
-	if srv.runtime.config.Pidfile != "" {
44
+	if srv.runtime.Config().Pidfile != "" {
45 45
 		job.Logf("Creating pidfile")
46
-		if err := utils.CreatePidFile(srv.runtime.config.Pidfile); err != nil {
46
+		if err := utils.CreatePidFile(srv.runtime.Config().Pidfile); err != nil {
47 47
 			// FIXME: do we need fatal here instead of returning a job error?
48 48
 			log.Fatal(err)
49 49
 		}
... ...
@@ -54,7 +55,7 @@ func InitServer(job *engine.Job) engine.Status {
54 54
 	go func() {
55 55
 		sig := <-c
56 56
 		log.Printf("Received signal '%v', exiting\n", sig)
57
-		utils.RemovePidFile(srv.runtime.config.Pidfile)
57
+		utils.RemovePidFile(srv.runtime.Config().Pidfile)
58 58
 		srv.Close()
59 59
 		os.Exit(0)
60 60
 	}()
... ...
@@ -181,10 +182,10 @@ func (srv *Server) ContainerKill(job *engine.Job) engine.Status {
181 181
 			if err := container.Kill(); err != nil {
182 182
 				return job.Errorf("Cannot kill container %s: %s", name, err)
183 183
 			}
184
-			srv.LogEvent("kill", container.ID, srv.runtime.repositories.ImageName(container.Image))
184
+			srv.LogEvent("kill", container.ID, srv.runtime.Repositories().ImageName(container.Image))
185 185
 		} else {
186 186
 			// Otherwise, just send the requested signal
187
-			if err := container.kill(int(sig)); err != nil {
187
+			if err := container.KillSig(int(sig)); err != nil {
188 188
 				return job.Errorf("Cannot kill container %s: %s", name, err)
189 189
 			}
190 190
 			// FIXME: Add event for signals
... ...
@@ -293,7 +294,7 @@ func (srv *Server) ContainerExport(job *engine.Job) engine.Status {
293 293
 			return job.Errorf("%s: %s", name, err)
294 294
 		}
295 295
 		// FIXME: factor job-specific LogEvent to engine.Job.Run()
296
-		srv.LogEvent("export", container.ID, srv.runtime.repositories.ImageName(container.Image))
296
+		srv.LogEvent("export", container.ID, srv.runtime.Repositories().ImageName(container.Image))
297 297
 		return engine.StatusOK
298 298
 	}
299 299
 	return job.Errorf("No such container: %s", name)
... ...
@@ -318,7 +319,7 @@ func (srv *Server) ImageExport(job *engine.Job) engine.Status {
318 318
 
319 319
 	utils.Debugf("Serializing %s", name)
320 320
 
321
-	rootRepo, err := srv.runtime.repositories.Get(name)
321
+	rootRepo, err := srv.runtime.Repositories().Get(name)
322 322
 	if err != nil {
323 323
 		return job.Error(err)
324 324
 	}
... ...
@@ -494,7 +495,7 @@ func (srv *Server) Build(job *engine.Job) engine.Status {
494 494
 		return job.Error(err)
495 495
 	}
496 496
 	if repoName != "" {
497
-		srv.runtime.repositories.Set(repoName, tag, id, false)
497
+		srv.runtime.Repositories().Set(repoName, tag, id, false)
498 498
 	}
499 499
 	return engine.StatusOK
500 500
 }
... ...
@@ -555,7 +556,7 @@ func (srv *Server) ImageLoad(job *engine.Job) engine.Status {
555 555
 
556 556
 		for imageName, tagMap := range repositories {
557 557
 			for tag, address := range tagMap {
558
-				if err := srv.runtime.repositories.Set(imageName, tag, address, true); err != nil {
558
+				if err := srv.runtime.Repositories().Set(imageName, tag, address, true); err != nil {
559 559
 					return job.Error(err)
560 560
 				}
561 561
 			}
... ...
@@ -588,13 +589,13 @@ func (srv *Server) recursiveLoad(address, tmpImageDir string) error {
588 588
 			return err
589 589
 		}
590 590
 		if img.Parent != "" {
591
-			if !srv.runtime.graph.Exists(img.Parent) {
591
+			if !srv.runtime.Graph().Exists(img.Parent) {
592 592
 				if err := srv.recursiveLoad(img.Parent, tmpImageDir); err != nil {
593 593
 					return err
594 594
 				}
595 595
 			}
596 596
 		}
597
-		if err := srv.runtime.graph.Register(imageJson, layer, img); err != nil {
597
+		if err := srv.runtime.Graph().Register(imageJson, layer, img); err != nil {
598 598
 			return err
599 599
 		}
600 600
 	}
... ...
@@ -650,7 +651,7 @@ func (srv *Server) ImageInsert(job *engine.Job) engine.Status {
650 650
 	sf := utils.NewStreamFormatter(job.GetenvBool("json"))
651 651
 
652 652
 	out := utils.NewWriteFlusher(job.Stdout)
653
-	img, err := srv.runtime.repositories.LookupImage(name)
653
+	img, err := srv.runtime.Repositories().LookupImage(name)
654 654
 	if err != nil {
655 655
 		return job.Error(err)
656 656
 	}
... ...
@@ -661,7 +662,7 @@ func (srv *Server) ImageInsert(job *engine.Job) engine.Status {
661 661
 	}
662 662
 	defer file.Body.Close()
663 663
 
664
-	config, _, _, err := runconfig.Parse([]string{img.ID, "echo", "insert", url, path}, srv.runtime.sysInfo)
664
+	config, _, _, err := runconfig.Parse([]string{img.ID, "echo", "insert", url, path}, srv.runtime.SystemConfig())
665 665
 	if err != nil {
666 666
 		return job.Error(err)
667 667
 	}
... ...
@@ -685,7 +686,7 @@ func (srv *Server) ImageInsert(job *engine.Job) engine.Status {
685 685
 }
686 686
 
687 687
 func (srv *Server) ImagesViz(job *engine.Job) engine.Status {
688
-	images, _ := srv.runtime.graph.Map()
688
+	images, _ := srv.runtime.Graph().Map()
689 689
 	if images == nil {
690 690
 		return engine.StatusOK
691 691
 	}
... ...
@@ -709,7 +710,7 @@ func (srv *Server) ImagesViz(job *engine.Job) engine.Status {
709 709
 
710 710
 	reporefs := make(map[string][]string)
711 711
 
712
-	for name, repository := range srv.runtime.repositories.Repositories {
712
+	for name, repository := range srv.runtime.Repositories().Repositories {
713 713
 		for tag, id := range repository {
714 714
 			reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
715 715
 		}
... ...
@@ -728,22 +729,22 @@ func (srv *Server) Images(job *engine.Job) engine.Status {
728 728
 		err       error
729 729
 	)
730 730
 	if job.GetenvBool("all") {
731
-		allImages, err = srv.runtime.graph.Map()
731
+		allImages, err = srv.runtime.Graph().Map()
732 732
 	} else {
733
-		allImages, err = srv.runtime.graph.Heads()
733
+		allImages, err = srv.runtime.Graph().Heads()
734 734
 	}
735 735
 	if err != nil {
736 736
 		return job.Error(err)
737 737
 	}
738 738
 	lookup := make(map[string]*engine.Env)
739
-	for name, repository := range srv.runtime.repositories.Repositories {
739
+	for name, repository := range srv.runtime.Repositories().Repositories {
740 740
 		if job.Getenv("filter") != "" {
741 741
 			if match, _ := path.Match(job.Getenv("filter"), name); !match {
742 742
 				continue
743 743
 			}
744 744
 		}
745 745
 		for tag, id := range repository {
746
-			image, err := srv.runtime.graph.Get(id)
746
+			image, err := srv.runtime.Graph().Get(id)
747 747
 			if err != nil {
748 748
 				log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err)
749 749
 				continue
... ...
@@ -793,7 +794,7 @@ func (srv *Server) Images(job *engine.Job) engine.Status {
793 793
 }
794 794
 
795 795
 func (srv *Server) DockerInfo(job *engine.Job) engine.Status {
796
-	images, _ := srv.runtime.graph.Map()
796
+	images, _ := srv.runtime.Graph().Map()
797 797
 	var imgcount int
798 798
 	if images == nil {
799 799
 		imgcount = 0
... ...
@@ -809,21 +810,21 @@ func (srv *Server) DockerInfo(job *engine.Job) engine.Status {
809 809
 	initPath := utils.DockerInitPath("")
810 810
 	if initPath == "" {
811 811
 		// if that fails, we'll just return the path from the runtime
812
-		initPath = srv.runtime.sysInitPath
812
+		initPath = srv.runtime.SystemInitPath()
813 813
 	}
814 814
 
815 815
 	v := &engine.Env{}
816 816
 	v.SetInt("Containers", len(srv.runtime.List()))
817 817
 	v.SetInt("Images", imgcount)
818
-	v.Set("Driver", srv.runtime.driver.String())
819
-	v.SetJson("DriverStatus", srv.runtime.driver.Status())
820
-	v.SetBool("MemoryLimit", srv.runtime.sysInfo.MemoryLimit)
821
-	v.SetBool("SwapLimit", srv.runtime.sysInfo.SwapLimit)
822
-	v.SetBool("IPv4Forwarding", !srv.runtime.sysInfo.IPv4ForwardingDisabled)
818
+	v.Set("Driver", srv.runtime.GraphDriver().String())
819
+	v.SetJson("DriverStatus", srv.runtime.GraphDriver().Status())
820
+	v.SetBool("MemoryLimit", srv.runtime.SystemConfig().MemoryLimit)
821
+	v.SetBool("SwapLimit", srv.runtime.SystemConfig().SwapLimit)
822
+	v.SetBool("IPv4Forwarding", !srv.runtime.SystemConfig().IPv4ForwardingDisabled)
823 823
 	v.SetBool("Debug", os.Getenv("DEBUG") != "")
824 824
 	v.SetInt("NFd", utils.GetTotalUsedFds())
825
-	v.SetInt("NGoroutines", runtime.NumGoroutine())
826
-	v.Set("ExecutionDriver", srv.runtime.execDriver.Name())
825
+	v.SetInt("NGoroutines", goruntime.NumGoroutine())
826
+	v.Set("ExecutionDriver", srv.runtime.ExecutionDriver().Name())
827 827
 	v.SetInt("NEventsListener", len(srv.listeners))
828 828
 	v.Set("KernelVersion", kernelVersion)
829 829
 	v.Set("IndexServerAddress", auth.IndexServerAddress())
... ...
@@ -840,13 +841,13 @@ func (srv *Server) ImageHistory(job *engine.Job) engine.Status {
840 840
 		return job.Errorf("Usage: %s IMAGE", job.Name)
841 841
 	}
842 842
 	name := job.Args[0]
843
-	foundImage, err := srv.runtime.repositories.LookupImage(name)
843
+	foundImage, err := srv.runtime.Repositories().LookupImage(name)
844 844
 	if err != nil {
845 845
 		return job.Error(err)
846 846
 	}
847 847
 
848 848
 	lookupMap := make(map[string][]string)
849
-	for name, repository := range srv.runtime.repositories.Repositories {
849
+	for name, repository := range srv.runtime.Repositories().Repositories {
850 850
 		for tag, id := range repository {
851 851
 			// If the ID already has a reverse lookup, do not update it unless for "latest"
852 852
 			if _, exists := lookupMap[id]; !exists {
... ...
@@ -891,7 +892,7 @@ func (srv *Server) ContainerTop(job *engine.Job) engine.Status {
891 891
 		if !container.State.IsRunning() {
892 892
 			return job.Errorf("Container %s is not running", name)
893 893
 		}
894
-		pids, err := srv.runtime.execDriver.GetPidsForContainer(container.ID)
894
+		pids, err := srv.runtime.ExecutionDriver().GetPidsForContainer(container.ID)
895 895
 		if err != nil {
896 896
 			return job.Error(err)
897 897
 		}
... ...
@@ -984,7 +985,7 @@ func (srv *Server) Containers(job *engine.Job) engine.Status {
984 984
 	outs := engine.NewTable("Created", 0)
985 985
 
986 986
 	names := map[string][]string{}
987
-	srv.runtime.containerGraph.Walk("/", func(p string, e *graphdb.Entity) error {
987
+	srv.runtime.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
988 988
 		names[e.ID()] = append(names[e.ID()], p)
989 989
 		return nil
990 990
 	}, -1)
... ...
@@ -1009,7 +1010,7 @@ func (srv *Server) Containers(job *engine.Job) engine.Status {
1009 1009
 		out := &engine.Env{}
1010 1010
 		out.Set("Id", container.ID)
1011 1011
 		out.SetList("Names", names[container.ID])
1012
-		out.Set("Image", srv.runtime.repositories.ImageName(container.Image))
1012
+		out.Set("Image", srv.runtime.Repositories().ImageName(container.Image))
1013 1013
 		if len(container.Args) > 0 {
1014 1014
 			out.Set("Command", fmt.Sprintf("\"%s %s\"", container.Path, strings.Join(container.Args, " ")))
1015 1015
 		} else {
... ...
@@ -1067,7 +1068,7 @@ func (srv *Server) ImageTag(job *engine.Job) engine.Status {
1067 1067
 	if len(job.Args) == 3 {
1068 1068
 		tag = job.Args[2]
1069 1069
 	}
1070
-	if err := srv.runtime.repositories.Set(job.Args[1], tag, job.Args[0], job.GetenvBool("force")); err != nil {
1070
+	if err := srv.runtime.Repositories().Set(job.Args[1], tag, job.Args[0], job.GetenvBool("force")); err != nil {
1071 1071
 		return job.Error(err)
1072 1072
 	}
1073 1073
 	return engine.StatusOK
... ...
@@ -1092,7 +1093,7 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoin
1092 1092
 		}
1093 1093
 		defer srv.poolRemove("pull", "layer:"+id)
1094 1094
 
1095
-		if !srv.runtime.graph.Exists(id) {
1095
+		if !srv.runtime.Graph().Exists(id) {
1096 1096
 			out.Write(sf.FormatProgress(utils.TruncateID(id), "Pulling metadata", nil))
1097 1097
 			imgJSON, imgSize, err := r.GetRemoteImageJSON(id, endpoint, token)
1098 1098
 			if err != nil {
... ...
@@ -1114,7 +1115,7 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoin
1114 1114
 				return err
1115 1115
 			}
1116 1116
 			defer layer.Close()
1117
-			if err := srv.runtime.graph.Register(imgJSON, utils.ProgressReader(layer, imgSize, out, sf, false, utils.TruncateID(id), "Downloading"), img); err != nil {
1117
+			if err := srv.runtime.Graph().Register(imgJSON, utils.ProgressReader(layer, imgSize, out, sf, false, utils.TruncateID(id), "Downloading"), img); err != nil {
1118 1118
 				out.Write(sf.FormatProgress(utils.TruncateID(id), "Error downloading dependent layers", nil))
1119 1119
 				return err
1120 1120
 			}
... ...
@@ -1249,11 +1250,11 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName
1249 1249
 		if askedTag != "" && tag != askedTag {
1250 1250
 			continue
1251 1251
 		}
1252
-		if err := srv.runtime.repositories.Set(localName, tag, id, true); err != nil {
1252
+		if err := srv.runtime.Repositories().Set(localName, tag, id, true); err != nil {
1253 1253
 			return err
1254 1254
 		}
1255 1255
 	}
1256
-	if err := srv.runtime.repositories.Save(); err != nil {
1256
+	if err := srv.runtime.Repositories().Save(); err != nil {
1257 1257
 		return err
1258 1258
 	}
1259 1259
 
... ...
@@ -1374,7 +1375,7 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]string, map[stri
1374 1374
 
1375 1375
 		tagsByImage[id] = append(tagsByImage[id], tag)
1376 1376
 
1377
-		for img, err := srv.runtime.graph.Get(id); img != nil; img, err = img.GetParent() {
1377
+		for img, err := srv.runtime.Graph().Get(id); img != nil; img, err = img.GetParent() {
1378 1378
 			if err != nil {
1379 1379
 				return nil, nil, err
1380 1380
 			}
... ...
@@ -1481,7 +1482,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName
1481 1481
 
1482 1482
 func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID, ep string, token []string, sf *utils.StreamFormatter) (checksum string, err error) {
1483 1483
 	out = utils.NewWriteFlusher(out)
1484
-	jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgID, "json"))
1484
+	jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.Graph().Root, imgID, "json"))
1485 1485
 	if err != nil {
1486 1486
 		return "", fmt.Errorf("Cannot retrieve the path for {%s}: %s", imgID, err)
1487 1487
 	}
... ...
@@ -1500,7 +1501,7 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID,
1500 1500
 		return "", err
1501 1501
 	}
1502 1502
 
1503
-	layerData, err := srv.runtime.graph.TempLayerArchive(imgID, archive.Uncompressed, sf, out)
1503
+	layerData, err := srv.runtime.Graph().TempLayerArchive(imgID, archive.Uncompressed, sf, out)
1504 1504
 	if err != nil {
1505 1505
 		return "", fmt.Errorf("Failed to generate layer archive: %s", err)
1506 1506
 	}
... ...
@@ -1552,17 +1553,17 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
1552 1552
 		return job.Error(err)
1553 1553
 	}
1554 1554
 
1555
-	img, err := srv.runtime.graph.Get(localName)
1555
+	img, err := srv.runtime.Graph().Get(localName)
1556 1556
 	r, err2 := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint)
1557 1557
 	if err2 != nil {
1558 1558
 		return job.Error(err2)
1559 1559
 	}
1560 1560
 
1561 1561
 	if err != nil {
1562
-		reposLen := len(srv.runtime.repositories.Repositories[localName])
1562
+		reposLen := len(srv.runtime.Repositories().Repositories[localName])
1563 1563
 		job.Stdout.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", localName, reposLen))
1564 1564
 		// If it fails, try to get the repository
1565
-		if localRepo, exists := srv.runtime.repositories.Repositories[localName]; exists {
1565
+		if localRepo, exists := srv.runtime.Repositories().Repositories[localName]; exists {
1566 1566
 			if err := srv.pushRepository(r, job.Stdout, localName, remoteName, localRepo, sf); err != nil {
1567 1567
 				return job.Error(err)
1568 1568
 			}
... ...
@@ -1618,13 +1619,13 @@ func (srv *Server) ImageImport(job *engine.Job) engine.Status {
1618 1618
 		defer progressReader.Close()
1619 1619
 		archive = progressReader
1620 1620
 	}
1621
-	img, err := srv.runtime.graph.Create(archive, "", "", "Imported from "+src, "", nil, nil)
1621
+	img, err := srv.runtime.Graph().Create(archive, "", "", "Imported from "+src, "", nil, nil)
1622 1622
 	if err != nil {
1623 1623
 		return job.Error(err)
1624 1624
 	}
1625 1625
 	// Optionally register the image at REPO/TAG
1626 1626
 	if repo != "" {
1627
-		if err := srv.runtime.repositories.Set(repo, tag, img.ID, true); err != nil {
1627
+		if err := srv.runtime.Repositories().Set(repo, tag, img.ID, true); err != nil {
1628 1628
 			return job.Error(err)
1629 1629
 		}
1630 1630
 	}
... ...
@@ -1643,11 +1644,11 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status {
1643 1643
 	if config.Memory != 0 && config.Memory < 524288 {
1644 1644
 		return job.Errorf("Minimum memory limit allowed is 512k")
1645 1645
 	}
1646
-	if config.Memory > 0 && !srv.runtime.sysInfo.MemoryLimit {
1646
+	if config.Memory > 0 && !srv.runtime.SystemConfig().MemoryLimit {
1647 1647
 		job.Errorf("Your kernel does not support memory limit capabilities. Limitation discarded.\n")
1648 1648
 		config.Memory = 0
1649 1649
 	}
1650
-	if config.Memory > 0 && !srv.runtime.sysInfo.SwapLimit {
1650
+	if config.Memory > 0 && !srv.runtime.SystemConfig().SwapLimit {
1651 1651
 		job.Errorf("Your kernel does not support swap limit capabilities. Limitation discarded.\n")
1652 1652
 		config.MemorySwap = -1
1653 1653
 	}
... ...
@@ -1655,14 +1656,14 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status {
1655 1655
 	if err != nil {
1656 1656
 		return job.Error(err)
1657 1657
 	}
1658
-	if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
1659
-		job.Errorf("Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v\n", defaultDns)
1660
-		config.Dns = defaultDns
1658
+	if !config.NetworkDisabled && len(config.Dns) == 0 && len(srv.runtime.Config().Dns) == 0 && utils.CheckLocalDns(resolvConf) {
1659
+		job.Errorf("Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v\n", runtime.DefaultDns)
1660
+		config.Dns = runtime.DefaultDns
1661 1661
 	}
1662 1662
 
1663 1663
 	container, buildWarnings, err := srv.runtime.Create(config, name)
1664 1664
 	if err != nil {
1665
-		if srv.runtime.graph.IsNotExist(err) {
1665
+		if srv.runtime.Graph().IsNotExist(err) {
1666 1666
 			_, tag := utils.ParseRepositoryTag(config.Image)
1667 1667
 			if tag == "" {
1668 1668
 				tag = graph.DEFAULTTAG
... ...
@@ -1671,10 +1672,10 @@ func (srv *Server) ContainerCreate(job *engine.Job) engine.Status {
1671 1671
 		}
1672 1672
 		return job.Error(err)
1673 1673
 	}
1674
-	if !container.Config.NetworkDisabled && srv.runtime.sysInfo.IPv4ForwardingDisabled {
1674
+	if !container.Config.NetworkDisabled && srv.runtime.SystemConfig().IPv4ForwardingDisabled {
1675 1675
 		job.Errorf("IPv4 forwarding is disabled.\n")
1676 1676
 	}
1677
-	srv.LogEvent("create", container.ID, srv.runtime.repositories.ImageName(container.Image))
1677
+	srv.LogEvent("create", container.ID, srv.runtime.Repositories().ImageName(container.Image))
1678 1678
 	// FIXME: this is necessary because runtime.Create might return a nil container
1679 1679
 	// with a non-nil error. This should not happen! Once it's fixed we
1680 1680
 	// can remove this workaround.
... ...
@@ -1702,7 +1703,7 @@ func (srv *Server) ContainerRestart(job *engine.Job) engine.Status {
1702 1702
 		if err := container.Restart(int(t)); err != nil {
1703 1703
 			return job.Errorf("Cannot restart container %s: %s\n", name, err)
1704 1704
 		}
1705
-		srv.LogEvent("restart", container.ID, srv.runtime.repositories.ImageName(container.Image))
1705
+		srv.LogEvent("restart", container.ID, srv.runtime.Repositories().ImageName(container.Image))
1706 1706
 	} else {
1707 1707
 		return job.Errorf("No such container: %s\n", name)
1708 1708
 	}
... ...
@@ -1724,7 +1725,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
1724 1724
 		if container == nil {
1725 1725
 			return job.Errorf("No such link: %s", name)
1726 1726
 		}
1727
-		name, err := getFullName(name)
1727
+		name, err := runtime.GetFullContainerName(name)
1728 1728
 		if err != nil {
1729 1729
 			job.Error(err)
1730 1730
 		}
... ...
@@ -1732,21 +1733,17 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
1732 1732
 		if parent == "/" {
1733 1733
 			return job.Errorf("Conflict, cannot remove the default name of the container")
1734 1734
 		}
1735
-		pe := srv.runtime.containerGraph.Get(parent)
1735
+		pe := srv.runtime.ContainerGraph().Get(parent)
1736 1736
 		if pe == nil {
1737 1737
 			return job.Errorf("Cannot get parent %s for name %s", parent, name)
1738 1738
 		}
1739 1739
 		parentContainer := srv.runtime.Get(pe.ID())
1740 1740
 
1741
-		if parentContainer != nil && parentContainer.activeLinks != nil {
1742
-			if link, exists := parentContainer.activeLinks[n]; exists {
1743
-				link.Disable()
1744
-			} else {
1745
-				utils.Debugf("Could not find active link for %s", name)
1746
-			}
1741
+		if parentContainer != nil {
1742
+			parentContainer.DisableLink(n)
1747 1743
 		}
1748 1744
 
1749
-		if err := srv.runtime.containerGraph.Delete(name); err != nil {
1745
+		if err := srv.runtime.ContainerGraph().Delete(name); err != nil {
1750 1746
 			return job.Error(err)
1751 1747
 		}
1752 1748
 		return engine.StatusOK
... ...
@@ -1765,13 +1762,13 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
1765 1765
 		if err := srv.runtime.Destroy(container); err != nil {
1766 1766
 			return job.Errorf("Cannot destroy container %s: %s", name, err)
1767 1767
 		}
1768
-		srv.LogEvent("destroy", container.ID, srv.runtime.repositories.ImageName(container.Image))
1768
+		srv.LogEvent("destroy", container.ID, srv.runtime.Repositories().ImageName(container.Image))
1769 1769
 
1770 1770
 		if removeVolume {
1771 1771
 			var (
1772 1772
 				volumes     = make(map[string]struct{})
1773 1773
 				binds       = make(map[string]struct{})
1774
-				usedVolumes = make(map[string]*Container)
1774
+				usedVolumes = make(map[string]*runtime.Container)
1775 1775
 			)
1776 1776
 
1777 1777
 			// the volume id is always the base of the path
... ...
@@ -1780,7 +1777,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
1780 1780
 			}
1781 1781
 
1782 1782
 			// populate bind map so that they can be skipped and not removed
1783
-			for _, bind := range container.hostConfig.Binds {
1783
+			for _, bind := range container.HostConfig().Binds {
1784 1784
 				source := strings.Split(bind, ":")[0]
1785 1785
 				// TODO: refactor all volume stuff, all of it
1786 1786
 				// this is very important that we eval the link
... ...
@@ -1819,7 +1816,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
1819 1819
 					log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.ID)
1820 1820
 					continue
1821 1821
 				}
1822
-				if err := srv.runtime.volumes.Delete(volumeId); err != nil {
1822
+				if err := srv.runtime.Volumes().Delete(volumeId); err != nil {
1823 1823
 					return job.Errorf("Error calling volumes.Delete(%q): %v", volumeId, err)
1824 1824
 				}
1825 1825
 			}
... ...
@@ -1841,9 +1838,9 @@ func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force boo
1841 1841
 		tag = graph.DEFAULTTAG
1842 1842
 	}
1843 1843
 
1844
-	img, err := srv.runtime.repositories.LookupImage(name)
1844
+	img, err := srv.runtime.Repositories().LookupImage(name)
1845 1845
 	if err != nil {
1846
-		if r, _ := srv.runtime.repositories.Get(repoName); r != nil {
1846
+		if r, _ := srv.runtime.Repositories().Get(repoName); r != nil {
1847 1847
 			return fmt.Errorf("No such image: %s:%s", repoName, tag)
1848 1848
 		}
1849 1849
 		return fmt.Errorf("No such image: %s", name)
... ...
@@ -1854,14 +1851,14 @@ func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force boo
1854 1854
 		tag = ""
1855 1855
 	}
1856 1856
 
1857
-	byParents, err := srv.runtime.graph.ByParent()
1857
+	byParents, err := srv.runtime.Graph().ByParent()
1858 1858
 	if err != nil {
1859 1859
 		return err
1860 1860
 	}
1861 1861
 
1862 1862
 	//If delete by id, see if the id belong only to one repository
1863 1863
 	if repoName == "" {
1864
-		for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
1864
+		for _, repoAndTag := range srv.runtime.Repositories().ByID()[img.ID] {
1865 1865
 			parsedRepo, parsedTag := utils.ParseRepositoryTag(repoAndTag)
1866 1866
 			if repoName == "" || repoName == parsedRepo {
1867 1867
 				repoName = parsedRepo
... ...
@@ -1884,7 +1881,7 @@ func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force boo
1884 1884
 
1885 1885
 	//Untag the current image
1886 1886
 	for _, tag := range tags {
1887
-		tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
1887
+		tagDeleted, err := srv.runtime.Repositories().Delete(repoName, tag)
1888 1888
 		if err != nil {
1889 1889
 			return err
1890 1890
 		}
... ...
@@ -1895,16 +1892,16 @@ func (srv *Server) DeleteImage(name string, imgs *engine.Table, first, force boo
1895 1895
 			srv.LogEvent("untag", img.ID, "")
1896 1896
 		}
1897 1897
 	}
1898
-	tags = srv.runtime.repositories.ByID()[img.ID]
1898
+	tags = srv.runtime.Repositories().ByID()[img.ID]
1899 1899
 	if (len(tags) <= 1 && repoName == "") || len(tags) == 0 {
1900 1900
 		if len(byParents[img.ID]) == 0 {
1901 1901
 			if err := srv.canDeleteImage(img.ID); err != nil {
1902 1902
 				return err
1903 1903
 			}
1904
-			if err := srv.runtime.repositories.DeleteAll(img.ID); err != nil {
1904
+			if err := srv.runtime.Repositories().DeleteAll(img.ID); err != nil {
1905 1905
 				return err
1906 1906
 			}
1907
-			if err := srv.runtime.graph.Delete(img.ID); err != nil {
1907
+			if err := srv.runtime.Graph().Delete(img.ID); err != nil {
1908 1908
 				return err
1909 1909
 			}
1910 1910
 			out := &engine.Env{}
... ...
@@ -1943,7 +1940,7 @@ func (srv *Server) ImageDelete(job *engine.Job) engine.Status {
1943 1943
 
1944 1944
 func (srv *Server) canDeleteImage(imgID string) error {
1945 1945
 	for _, container := range srv.runtime.List() {
1946
-		parent, err := srv.runtime.repositories.LookupImage(container.Image)
1946
+		parent, err := srv.runtime.Repositories().LookupImage(container.Image)
1947 1947
 		if err != nil {
1948 1948
 			return err
1949 1949
 		}
... ...
@@ -1963,7 +1960,7 @@ func (srv *Server) canDeleteImage(imgID string) error {
1963 1963
 func (srv *Server) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) {
1964 1964
 
1965 1965
 	// Retrieve all images
1966
-	images, err := srv.runtime.graph.Map()
1966
+	images, err := srv.runtime.Graph().Map()
1967 1967
 	if err != nil {
1968 1968
 		return nil, err
1969 1969
 	}
... ...
@@ -1980,7 +1977,7 @@ func (srv *Server) ImageGetCached(imgID string, config *runconfig.Config) (*imag
1980 1980
 	// Loop on the children of the given image and check the config
1981 1981
 	var match *image.Image
1982 1982
 	for elem := range imageMap[imgID] {
1983
-		img, err := srv.runtime.graph.Get(elem)
1983
+		img, err := srv.runtime.Graph().Get(elem)
1984 1984
 		if err != nil {
1985 1985
 			return nil, err
1986 1986
 		}
... ...
@@ -1993,7 +1990,7 @@ func (srv *Server) ImageGetCached(imgID string, config *runconfig.Config) (*imag
1993 1993
 	return match, nil
1994 1994
 }
1995 1995
 
1996
-func (srv *Server) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error {
1996
+func (srv *Server) RegisterLinks(container *runtime.Container, hostConfig *runconfig.HostConfig) error {
1997 1997
 	runtime := srv.runtime
1998 1998
 
1999 1999
 	if hostConfig != nil && hostConfig.Links != nil {
... ...
@@ -2017,7 +2014,7 @@ func (srv *Server) RegisterLinks(container *Container, hostConfig *runconfig.Hos
2017 2017
 		// After we load all the links into the runtime
2018 2018
 		// set them to nil on the hostconfig
2019 2019
 		hostConfig.Links = nil
2020
-		if err := container.writeHostConfig(); err != nil {
2020
+		if err := container.WriteHostConfig(); err != nil {
2021 2021
 			return err
2022 2022
 		}
2023 2023
 	}
... ...
@@ -2065,13 +2062,13 @@ func (srv *Server) ContainerStart(job *engine.Job) engine.Status {
2065 2065
 		if err := srv.RegisterLinks(container, hostConfig); err != nil {
2066 2066
 			return job.Error(err)
2067 2067
 		}
2068
-		container.hostConfig = hostConfig
2068
+		container.SetHostConfig(hostConfig)
2069 2069
 		container.ToDisk()
2070 2070
 	}
2071 2071
 	if err := container.Start(); err != nil {
2072 2072
 		return job.Errorf("Cannot start container %s: %s", name, err)
2073 2073
 	}
2074
-	srv.LogEvent("start", container.ID, runtime.repositories.ImageName(container.Image))
2074
+	srv.LogEvent("start", container.ID, runtime.Repositories().ImageName(container.Image))
2075 2075
 
2076 2076
 	return engine.StatusOK
2077 2077
 }
... ...
@@ -2091,7 +2088,7 @@ func (srv *Server) ContainerStop(job *engine.Job) engine.Status {
2091 2091
 		if err := container.Stop(int(t)); err != nil {
2092 2092
 			return job.Errorf("Cannot stop container %s: %s\n", name, err)
2093 2093
 		}
2094
-		srv.LogEvent("stop", container.ID, srv.runtime.repositories.ImageName(container.Image))
2094
+		srv.LogEvent("stop", container.ID, srv.runtime.Repositories().ImageName(container.Image))
2095 2095
 	} else {
2096 2096
 		return job.Errorf("No such container: %s\n", name)
2097 2097
 	}
... ...
@@ -2237,7 +2234,7 @@ func (srv *Server) ContainerAttach(job *engine.Job) engine.Status {
2237 2237
 	return engine.StatusOK
2238 2238
 }
2239 2239
 
2240
-func (srv *Server) ContainerInspect(name string) (*Container, error) {
2240
+func (srv *Server) ContainerInspect(name string) (*runtime.Container, error) {
2241 2241
 	if container := srv.runtime.Get(name); container != nil {
2242 2242
 		return container, nil
2243 2243
 	}
... ...
@@ -2245,7 +2242,7 @@ func (srv *Server) ContainerInspect(name string) (*Container, error) {
2245 2245
 }
2246 2246
 
2247 2247
 func (srv *Server) ImageInspect(name string) (*image.Image, error) {
2248
-	if image, err := srv.runtime.repositories.LookupImage(name); err == nil && image != nil {
2248
+	if image, err := srv.runtime.Repositories().LookupImage(name); err == nil && image != nil {
2249 2249
 		return image, nil
2250 2250
 	}
2251 2251
 	return nil, fmt.Errorf("No such image: %s", name)
... ...
@@ -2280,9 +2277,9 @@ func (srv *Server) JobInspect(job *engine.Job) engine.Status {
2280 2280
 			return job.Error(errContainer)
2281 2281
 		}
2282 2282
 		object = &struct {
2283
-			*Container
2283
+			*runtime.Container
2284 2284
 			HostConfig *runconfig.HostConfig
2285
-		}{container, container.hostConfig}
2285
+		}{container, container.HostConfig()}
2286 2286
 	default:
2287 2287
 		return job.Errorf("Unknown kind: %s", kind)
2288 2288
 	}
... ...
@@ -2322,7 +2319,7 @@ func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
2322 2322
 }
2323 2323
 
2324 2324
 func NewServer(eng *engine.Engine, config *daemonconfig.Config) (*Server, error) {
2325
-	runtime, err := NewRuntime(config, eng)
2325
+	runtime, err := runtime.NewRuntime(config, eng)
2326 2326
 	if err != nil {
2327 2327
 		return nil, err
2328 2328
 	}
... ...
@@ -2335,7 +2332,7 @@ func NewServer(eng *engine.Engine, config *daemonconfig.Config) (*Server, error)
2335 2335
 		listeners:   make(map[string]chan utils.JSONMessage),
2336 2336
 		running:     true,
2337 2337
 	}
2338
-	runtime.srv = srv
2338
+	runtime.SetServer(srv)
2339 2339
 	return srv, nil
2340 2340
 }
2341 2341
 
... ...
@@ -2403,7 +2400,7 @@ func (srv *Server) Close() error {
2403 2403
 
2404 2404
 type Server struct {
2405 2405
 	sync.RWMutex
2406
-	runtime     *Runtime
2406
+	runtime     *runtime.Runtime
2407 2407
 	pullingPool map[string]chan struct{}
2408 2408
 	pushingPool map[string]chan struct{}
2409 2409
 	events      []utils.JSONMessage
2410 2410
deleted file mode 100644
... ...
@@ -1,25 +0,0 @@
1
-package docker
2
-
3
-import "sort"
4
-
5
-type containerSorter struct {
6
-	containers []*Container
7
-	by         func(i, j *Container) bool
8
-}
9
-
10
-func (s *containerSorter) Len() int {
11
-	return len(s.containers)
12
-}
13
-
14
-func (s *containerSorter) Swap(i, j int) {
15
-	s.containers[i], s.containers[j] = s.containers[j], s.containers[i]
16
-}
17
-
18
-func (s *containerSorter) Less(i, j int) bool {
19
-	return s.by(s.containers[i], s.containers[j])
20
-}
21
-
22
-func sortContainers(containers []*Container, predicate func(i, j *Container) bool) {
23
-	s := &containerSorter{containers, predicate}
24
-	sort.Sort(s)
25
-}
26 1
deleted file mode 100644
... ...
@@ -1,81 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/utils"
6
-	"sync"
7
-	"time"
8
-)
9
-
10
-type State struct {
11
-	sync.RWMutex
12
-	Running    bool
13
-	Pid        int
14
-	ExitCode   int
15
-	StartedAt  time.Time
16
-	FinishedAt time.Time
17
-	Ghost      bool
18
-}
19
-
20
-// String returns a human-readable description of the state
21
-func (s *State) String() string {
22
-	s.RLock()
23
-	defer s.RUnlock()
24
-
25
-	if s.Running {
26
-		if s.Ghost {
27
-			return fmt.Sprintf("Ghost")
28
-		}
29
-		return fmt.Sprintf("Up %s", utils.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
30
-	}
31
-	return fmt.Sprintf("Exit %d", s.ExitCode)
32
-}
33
-
34
-func (s *State) IsRunning() bool {
35
-	s.RLock()
36
-	defer s.RUnlock()
37
-
38
-	return s.Running
39
-}
40
-
41
-func (s *State) IsGhost() bool {
42
-	s.RLock()
43
-	defer s.RUnlock()
44
-
45
-	return s.Ghost
46
-}
47
-
48
-func (s *State) GetExitCode() int {
49
-	s.RLock()
50
-	defer s.RUnlock()
51
-
52
-	return s.ExitCode
53
-}
54
-
55
-func (s *State) SetGhost(val bool) {
56
-	s.Lock()
57
-	defer s.Unlock()
58
-
59
-	s.Ghost = val
60
-}
61
-
62
-func (s *State) SetRunning(pid int) {
63
-	s.Lock()
64
-	defer s.Unlock()
65
-
66
-	s.Running = true
67
-	s.Ghost = false
68
-	s.ExitCode = 0
69
-	s.Pid = pid
70
-	s.StartedAt = time.Now().UTC()
71
-}
72
-
73
-func (s *State) SetStopped(exitCode int) {
74
-	s.Lock()
75
-	defer s.Unlock()
76
-
77
-	s.Running = false
78
-	s.Pid = 0
79
-	s.FinishedAt = time.Now().UTC()
80
-	s.ExitCode = exitCode
81
-}
... ...
@@ -2,9 +2,6 @@ package docker
2 2
 
3 3
 import (
4 4
 	"github.com/dotcloud/docker/archive"
5
-	"github.com/dotcloud/docker/nat"
6
-	"github.com/dotcloud/docker/pkg/namesgenerator"
7
-	"github.com/dotcloud/docker/runconfig"
8 5
 	"github.com/dotcloud/docker/utils"
9 6
 )
10 7
 
... ...
@@ -12,45 +9,8 @@ type Change struct {
12 12
 	archive.Change
13 13
 }
14 14
 
15
-func migratePortMappings(config *runconfig.Config, hostConfig *runconfig.HostConfig) error {
16
-	if config.PortSpecs != nil {
17
-		ports, bindings, err := nat.ParsePortSpecs(config.PortSpecs)
18
-		if err != nil {
19
-			return err
20
-		}
21
-		config.PortSpecs = nil
22
-		if len(bindings) > 0 {
23
-			if hostConfig == nil {
24
-				hostConfig = &runconfig.HostConfig{}
25
-			}
26
-			hostConfig.PortBindings = bindings
27
-		}
28
-
29
-		if config.ExposedPorts == nil {
30
-			config.ExposedPorts = make(nat.PortSet, len(ports))
31
-		}
32
-		for k, v := range ports {
33
-			config.ExposedPorts[k] = v
34
-		}
35
-	}
36
-	return nil
37
-}
38
-
39 15
 // Links come in the format of
40 16
 // name:alias
41 17
 func parseLink(rawLink string) (map[string]string, error) {
42 18
 	return utils.PartParser("name:alias", rawLink)
43 19
 }
44
-
45
-type checker struct {
46
-	runtime *Runtime
47
-}
48
-
49
-func (c *checker) Exists(name string) bool {
50
-	return c.runtime.containerGraph.Exists("/" + name)
51
-}
52
-
53
-// Generate a random and unique name
54
-func generateRandomName(runtime *Runtime) (string, error) {
55
-	return namesgenerator.GenerateRandomName(&checker{runtime})
56
-}
57 20
deleted file mode 100644
... ...
@@ -1,332 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/archive"
6
-	"github.com/dotcloud/docker/pkg/mount"
7
-	"github.com/dotcloud/docker/utils"
8
-	"io/ioutil"
9
-	"log"
10
-	"os"
11
-	"path/filepath"
12
-	"strings"
13
-	"syscall"
14
-)
15
-
16
-type BindMap struct {
17
-	SrcPath string
18
-	DstPath string
19
-	Mode    string
20
-}
21
-
22
-func prepareVolumesForContainer(container *Container) error {
23
-	if container.Volumes == nil || len(container.Volumes) == 0 {
24
-		container.Volumes = make(map[string]string)
25
-		container.VolumesRW = make(map[string]bool)
26
-		if err := applyVolumesFrom(container); err != nil {
27
-			return err
28
-		}
29
-	}
30
-
31
-	if err := createVolumes(container); err != nil {
32
-		return err
33
-	}
34
-	return nil
35
-}
36
-
37
-func mountVolumesForContainer(container *Container, envPath string) error {
38
-	// Setup the root fs as a bind mount of the base fs
39
-	var (
40
-		root    = container.RootfsPath()
41
-		runtime = container.runtime
42
-	)
43
-	if err := os.MkdirAll(root, 0755); err != nil && !os.IsExist(err) {
44
-		return nil
45
-	}
46
-
47
-	// Create a bind mount of the base fs as a place where we can add mounts
48
-	// without affecting the ability to access the base fs
49
-	if err := mount.Mount(container.basefs, root, "none", "bind,rw"); err != nil {
50
-		return err
51
-	}
52
-
53
-	// Make sure the root fs is private so the mounts here don't propagate to basefs
54
-	if err := mount.ForceMount(root, root, "none", "private"); err != nil {
55
-		return err
56
-	}
57
-
58
-	// Mount docker specific files into the containers root fs
59
-	if err := mount.Mount(runtime.sysInitPath, filepath.Join(root, "/.dockerinit"), "none", "bind,ro"); err != nil {
60
-		return err
61
-	}
62
-	if err := mount.Mount(envPath, filepath.Join(root, "/.dockerenv"), "none", "bind,ro"); err != nil {
63
-		return err
64
-	}
65
-	if err := mount.Mount(container.ResolvConfPath, filepath.Join(root, "/etc/resolv.conf"), "none", "bind,ro"); err != nil {
66
-		return err
67
-	}
68
-
69
-	if container.HostnamePath != "" && container.HostsPath != "" {
70
-		if err := mount.Mount(container.HostnamePath, filepath.Join(root, "/etc/hostname"), "none", "bind,ro"); err != nil {
71
-			return err
72
-		}
73
-		if err := mount.Mount(container.HostsPath, filepath.Join(root, "/etc/hosts"), "none", "bind,ro"); err != nil {
74
-			return err
75
-		}
76
-	}
77
-
78
-	// Mount user specified volumes
79
-	for r, v := range container.Volumes {
80
-		mountAs := "ro"
81
-		if container.VolumesRW[r] {
82
-			mountAs = "rw"
83
-		}
84
-
85
-		r = filepath.Join(root, r)
86
-		if p, err := utils.FollowSymlinkInScope(r, root); err != nil {
87
-			return err
88
-		} else {
89
-			r = p
90
-		}
91
-
92
-		if err := mount.Mount(v, r, "none", fmt.Sprintf("bind,%s", mountAs)); err != nil {
93
-			return err
94
-		}
95
-	}
96
-	return nil
97
-}
98
-
99
-func unmountVolumesForContainer(container *Container) {
100
-	var (
101
-		root   = container.RootfsPath()
102
-		mounts = []string{
103
-			root,
104
-			filepath.Join(root, "/.dockerinit"),
105
-			filepath.Join(root, "/.dockerenv"),
106
-			filepath.Join(root, "/etc/resolv.conf"),
107
-		}
108
-	)
109
-
110
-	if container.HostnamePath != "" && container.HostsPath != "" {
111
-		mounts = append(mounts, filepath.Join(root, "/etc/hostname"), filepath.Join(root, "/etc/hosts"))
112
-	}
113
-
114
-	for r := range container.Volumes {
115
-		mounts = append(mounts, filepath.Join(root, r))
116
-	}
117
-
118
-	for i := len(mounts) - 1; i >= 0; i-- {
119
-		if lastError := mount.Unmount(mounts[i]); lastError != nil {
120
-			log.Printf("Failed to umount %v: %v", mounts[i], lastError)
121
-		}
122
-	}
123
-}
124
-
125
-func applyVolumesFrom(container *Container) error {
126
-	if container.Config.VolumesFrom != "" {
127
-		for _, containerSpec := range strings.Split(container.Config.VolumesFrom, ",") {
128
-			var (
129
-				mountRW   = true
130
-				specParts = strings.SplitN(containerSpec, ":", 2)
131
-			)
132
-
133
-			switch len(specParts) {
134
-			case 0:
135
-				return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
136
-			case 2:
137
-				switch specParts[1] {
138
-				case "ro":
139
-					mountRW = false
140
-				case "rw": // mountRW is already true
141
-				default:
142
-					return fmt.Errorf("Malformed volumes-from specification: %s", containerSpec)
143
-				}
144
-			}
145
-
146
-			c := container.runtime.Get(specParts[0])
147
-			if c == nil {
148
-				return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
149
-			}
150
-
151
-			for volPath, id := range c.Volumes {
152
-				if _, exists := container.Volumes[volPath]; exists {
153
-					continue
154
-				}
155
-				if err := os.MkdirAll(filepath.Join(container.basefs, volPath), 0755); err != nil {
156
-					return err
157
-				}
158
-				container.Volumes[volPath] = id
159
-				if isRW, exists := c.VolumesRW[volPath]; exists {
160
-					container.VolumesRW[volPath] = isRW && mountRW
161
-				}
162
-			}
163
-
164
-		}
165
-	}
166
-	return nil
167
-}
168
-
169
-func getBindMap(container *Container) (map[string]BindMap, error) {
170
-	var (
171
-		// Create the requested bind mounts
172
-		binds = make(map[string]BindMap)
173
-		// Define illegal container destinations
174
-		illegalDsts = []string{"/", "."}
175
-	)
176
-
177
-	for _, bind := range container.hostConfig.Binds {
178
-		// FIXME: factorize bind parsing in parseBind
179
-		var (
180
-			src, dst, mode string
181
-			arr            = strings.Split(bind, ":")
182
-		)
183
-
184
-		if len(arr) == 2 {
185
-			src = arr[0]
186
-			dst = arr[1]
187
-			mode = "rw"
188
-		} else if len(arr) == 3 {
189
-			src = arr[0]
190
-			dst = arr[1]
191
-			mode = arr[2]
192
-		} else {
193
-			return nil, fmt.Errorf("Invalid bind specification: %s", bind)
194
-		}
195
-
196
-		// Bail if trying to mount to an illegal destination
197
-		for _, illegal := range illegalDsts {
198
-			if dst == illegal {
199
-				return nil, fmt.Errorf("Illegal bind destination: %s", dst)
200
-			}
201
-		}
202
-
203
-		bindMap := BindMap{
204
-			SrcPath: src,
205
-			DstPath: dst,
206
-			Mode:    mode,
207
-		}
208
-		binds[filepath.Clean(dst)] = bindMap
209
-	}
210
-	return binds, nil
211
-}
212
-
213
-func createVolumes(container *Container) error {
214
-	binds, err := getBindMap(container)
215
-	if err != nil {
216
-		return err
217
-	}
218
-
219
-	volumesDriver := container.runtime.volumes.Driver()
220
-	// Create the requested volumes if they don't exist
221
-	for volPath := range container.Config.Volumes {
222
-		volPath = filepath.Clean(volPath)
223
-		volIsDir := true
224
-		// Skip existing volumes
225
-		if _, exists := container.Volumes[volPath]; exists {
226
-			continue
227
-		}
228
-		var srcPath string
229
-		var isBindMount bool
230
-		srcRW := false
231
-		// If an external bind is defined for this volume, use that as a source
232
-		if bindMap, exists := binds[volPath]; exists {
233
-			isBindMount = true
234
-			srcPath = bindMap.SrcPath
235
-			if strings.ToLower(bindMap.Mode) == "rw" {
236
-				srcRW = true
237
-			}
238
-			if stat, err := os.Stat(bindMap.SrcPath); err != nil {
239
-				return err
240
-			} else {
241
-				volIsDir = stat.IsDir()
242
-			}
243
-			// Otherwise create an directory in $ROOT/volumes/ and use that
244
-		} else {
245
-
246
-			// Do not pass a container as the parameter for the volume creation.
247
-			// The graph driver using the container's information ( Image ) to
248
-			// create the parent.
249
-			c, err := container.runtime.volumes.Create(nil, "", "", "", "", nil, nil)
250
-			if err != nil {
251
-				return err
252
-			}
253
-			srcPath, err = volumesDriver.Get(c.ID)
254
-			if err != nil {
255
-				return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
256
-			}
257
-			srcRW = true // RW by default
258
-		}
259
-
260
-		if p, err := filepath.EvalSymlinks(srcPath); err != nil {
261
-			return err
262
-		} else {
263
-			srcPath = p
264
-		}
265
-
266
-		container.Volumes[volPath] = srcPath
267
-		container.VolumesRW[volPath] = srcRW
268
-
269
-		// Create the mountpoint
270
-		volPath = filepath.Join(container.basefs, volPath)
271
-		rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.basefs)
272
-		if err != nil {
273
-			return err
274
-		}
275
-
276
-		if _, err := os.Stat(rootVolPath); err != nil {
277
-			if os.IsNotExist(err) {
278
-				if volIsDir {
279
-					if err := os.MkdirAll(rootVolPath, 0755); err != nil {
280
-						return err
281
-					}
282
-				} else {
283
-					if err := os.MkdirAll(filepath.Dir(rootVolPath), 0755); err != nil {
284
-						return err
285
-					}
286
-					if f, err := os.OpenFile(rootVolPath, os.O_CREATE, 0755); err != nil {
287
-						return err
288
-					} else {
289
-						f.Close()
290
-					}
291
-				}
292
-			}
293
-		}
294
-
295
-		// Do not copy or change permissions if we are mounting from the host
296
-		if srcRW && !isBindMount {
297
-			volList, err := ioutil.ReadDir(rootVolPath)
298
-			if err != nil {
299
-				return err
300
-			}
301
-			if len(volList) > 0 {
302
-				srcList, err := ioutil.ReadDir(srcPath)
303
-				if err != nil {
304
-					return err
305
-				}
306
-				if len(srcList) == 0 {
307
-					// If the source volume is empty copy files from the root into the volume
308
-					if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
309
-						return err
310
-					}
311
-
312
-					var stat syscall.Stat_t
313
-					if err := syscall.Stat(rootVolPath, &stat); err != nil {
314
-						return err
315
-					}
316
-					var srcStat syscall.Stat_t
317
-					if err := syscall.Stat(srcPath, &srcStat); err != nil {
318
-						return err
319
-					}
320
-					// Change the source volume's ownership if it differs from the root
321
-					// files that were just copied
322
-					if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
323
-						if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
324
-							return err
325
-						}
326
-					}
327
-				}
328
-			}
329
-		}
330
-	}
331
-	return nil
332
-}