Browse code

Merge builder.go into runtime.go

Solomon Hykes authored on 2013/09/07 09:33:05
Showing 8 changed files
... ...
@@ -321,7 +321,7 @@ func TestGetContainersJSON(t *testing.T) {
321 321
 
322 322
 	srv := &Server{runtime: runtime}
323 323
 
324
-	container, err := NewBuilder(runtime).Create(&Config{
324
+	container, err := runtime.Create(&Config{
325 325
 		Image: GetTestImage(runtime).ID,
326 326
 		Cmd:   []string{"echo", "test"},
327 327
 	})
... ...
@@ -357,10 +357,8 @@ func TestGetContainersExport(t *testing.T) {
357 357
 
358 358
 	srv := &Server{runtime: runtime}
359 359
 
360
-	builder := NewBuilder(runtime)
361
-
362 360
 	// Create a container and remove a file
363
-	container, err := builder.Create(
361
+	container, err := runtime.Create(
364 362
 		&Config{
365 363
 			Image: GetTestImage(runtime).ID,
366 364
 			Cmd:   []string{"touch", "/test"},
... ...
@@ -409,10 +407,8 @@ func TestGetContainersChanges(t *testing.T) {
409 409
 
410 410
 	srv := &Server{runtime: runtime}
411 411
 
412
-	builder := NewBuilder(runtime)
413
-
414 412
 	// Create a container and remove a file
415
-	container, err := builder.Create(
413
+	container, err := runtime.Create(
416 414
 		&Config{
417 415
 			Image: GetTestImage(runtime).ID,
418 416
 			Cmd:   []string{"/bin/rm", "/etc/passwd"},
... ...
@@ -458,9 +454,7 @@ func TestGetContainersTop(t *testing.T) {
458 458
 
459 459
 	srv := &Server{runtime: runtime}
460 460
 
461
-	builder := NewBuilder(runtime)
462
-
463
-	container, err := builder.Create(
461
+	container, err := runtime.Create(
464 462
 		&Config{
465 463
 			Image:     GetTestImage(runtime).ID,
466 464
 			Cmd:       []string{"/bin/sh", "-c", "cat"},
... ...
@@ -541,10 +535,8 @@ func TestGetContainersByName(t *testing.T) {
541 541
 
542 542
 	srv := &Server{runtime: runtime}
543 543
 
544
-	builder := NewBuilder(runtime)
545
-
546 544
 	// Create a container and remove a file
547
-	container, err := builder.Create(
545
+	container, err := runtime.Create(
548 546
 		&Config{
549 547
 			Image: GetTestImage(runtime).ID,
550 548
 			Cmd:   []string{"echo", "test"},
... ...
@@ -574,10 +566,9 @@ func TestPostCommit(t *testing.T) {
574 574
 
575 575
 	srv := &Server{runtime: runtime}
576 576
 
577
-	builder := NewBuilder(runtime)
578 577
 
579 578
 	// Create a container and remove a file
580
-	container, err := builder.Create(
579
+	container, err := runtime.Create(
581 580
 		&Config{
582 581
 			Image: GetTestImage(runtime).ID,
583 582
 			Cmd:   []string{"touch", "/test"},
... ...
@@ -671,7 +662,7 @@ func TestPostContainersKill(t *testing.T) {
671 671
 
672 672
 	srv := &Server{runtime: runtime}
673 673
 
674
-	container, err := NewBuilder(runtime).Create(
674
+	container, err := runtime.Create(
675 675
 		&Config{
676 676
 			Image:     GetTestImage(runtime).ID,
677 677
 			Cmd:       []string{"/bin/cat"},
... ...
@@ -713,7 +704,7 @@ func TestPostContainersRestart(t *testing.T) {
713 713
 
714 714
 	srv := &Server{runtime: runtime}
715 715
 
716
-	container, err := NewBuilder(runtime).Create(
716
+	container, err := runtime.Create(
717 717
 		&Config{
718 718
 			Image:     GetTestImage(runtime).ID,
719 719
 			Cmd:       []string{"/bin/cat"},
... ...
@@ -767,7 +758,7 @@ func TestPostContainersStart(t *testing.T) {
767 767
 
768 768
 	srv := &Server{runtime: runtime}
769 769
 
770
-	container, err := NewBuilder(runtime).Create(
770
+	container, err := runtime.Create(
771 771
 		&Config{
772 772
 			Image:     GetTestImage(runtime).ID,
773 773
 			Cmd:       []string{"/bin/cat"},
... ...
@@ -817,7 +808,7 @@ func TestPostContainersStop(t *testing.T) {
817 817
 
818 818
 	srv := &Server{runtime: runtime}
819 819
 
820
-	container, err := NewBuilder(runtime).Create(
820
+	container, err := runtime.Create(
821 821
 		&Config{
822 822
 			Image:     GetTestImage(runtime).ID,
823 823
 			Cmd:       []string{"/bin/cat"},
... ...
@@ -864,7 +855,7 @@ func TestPostContainersWait(t *testing.T) {
864 864
 
865 865
 	srv := &Server{runtime: runtime}
866 866
 
867
-	container, err := NewBuilder(runtime).Create(
867
+	container, err := runtime.Create(
868 868
 		&Config{
869 869
 			Image:     GetTestImage(runtime).ID,
870 870
 			Cmd:       []string{"/bin/sleep", "1"},
... ...
@@ -906,7 +897,7 @@ func TestPostContainersAttach(t *testing.T) {
906 906
 
907 907
 	srv := &Server{runtime: runtime}
908 908
 
909
-	container, err := NewBuilder(runtime).Create(
909
+	container, err := runtime.Create(
910 910
 		&Config{
911 911
 			Image:     GetTestImage(runtime).ID,
912 912
 			Cmd:       []string{"/bin/cat"},
... ...
@@ -998,7 +989,7 @@ func TestDeleteContainers(t *testing.T) {
998 998
 
999 999
 	srv := &Server{runtime: runtime}
1000 1000
 
1001
-	container, err := NewBuilder(runtime).Create(&Config{
1001
+	container, err := runtime.Create(&Config{
1002 1002
 		Image: GetTestImage(runtime).ID,
1003 1003
 		Cmd:   []string{"touch", "/test"},
1004 1004
 	})
... ...
@@ -1185,10 +1176,8 @@ func TestPostContainersCopy(t *testing.T) {
1185 1185
 
1186 1186
 	srv := &Server{runtime: runtime}
1187 1187
 
1188
-	builder := NewBuilder(runtime)
1189
-
1190 1188
 	// Create a container and remove a file
1191
-	container, err := builder.Create(
1189
+	container, err := runtime.Create(
1192 1190
 		&Config{
1193 1191
 			Image: GetTestImage(runtime).ID,
1194 1192
 			Cmd:   []string{"touch", "/test.txt"},
1195 1193
deleted file mode 100644
... ...
@@ -1,154 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/utils"
6
-	"os"
7
-	"path"
8
-	"time"
9
-)
10
-
11
-var defaultDns = []string{"8.8.8.8", "8.8.4.4"}
12
-
13
-type Builder struct {
14
-	runtime      *Runtime
15
-	repositories *TagStore
16
-	graph        *Graph
17
-
18
-	config *Config
19
-	image  *Image
20
-}
21
-
22
-func NewBuilder(runtime *Runtime) *Builder {
23
-	return &Builder{
24
-		runtime:      runtime,
25
-		graph:        runtime.graph,
26
-		repositories: runtime.repositories,
27
-	}
28
-}
29
-
30
-func (builder *Builder) Create(config *Config) (*Container, error) {
31
-	// Lookup image
32
-	img, err := builder.repositories.LookupImage(config.Image)
33
-	if err != nil {
34
-		return nil, err
35
-	}
36
-
37
-	if img.Config != nil {
38
-		MergeConfig(config, img.Config)
39
-	}
40
-
41
-	if len(config.Entrypoint) != 0 && config.Cmd == nil {
42
-		config.Cmd = []string{}
43
-	} else if config.Cmd == nil || len(config.Cmd) == 0 {
44
-		return nil, fmt.Errorf("No command specified")
45
-	}
46
-
47
-	// Generate id
48
-	id := GenerateID()
49
-	// Generate default hostname
50
-	// FIXME: the lxc template no longer needs to set a default hostname
51
-	if config.Hostname == "" {
52
-		config.Hostname = id[:12]
53
-	}
54
-
55
-	var args []string
56
-	var entrypoint string
57
-
58
-	if len(config.Entrypoint) != 0 {
59
-		entrypoint = config.Entrypoint[0]
60
-		args = append(config.Entrypoint[1:], config.Cmd...)
61
-	} else {
62
-		entrypoint = config.Cmd[0]
63
-		args = config.Cmd[1:]
64
-	}
65
-
66
-	container := &Container{
67
-		// FIXME: we should generate the ID here instead of receiving it as an argument
68
-		ID:              id,
69
-		Created:         time.Now(),
70
-		Path:            entrypoint,
71
-		Args:            args, //FIXME: de-duplicate from config
72
-		Config:          config,
73
-		Image:           img.ID, // Always use the resolved image id
74
-		NetworkSettings: &NetworkSettings{},
75
-		// FIXME: do we need to store this in the container?
76
-		SysInitPath: sysInitPath,
77
-	}
78
-	container.root = builder.runtime.containerRoot(container.ID)
79
-	// Step 1: create the container directory.
80
-	// This doubles as a barrier to avoid race conditions.
81
-	if err := os.Mkdir(container.root, 0700); err != nil {
82
-		return nil, err
83
-	}
84
-
85
-	resolvConf, err := utils.GetResolvConf()
86
-	if err != nil {
87
-		return nil, err
88
-	}
89
-
90
-	if len(config.Dns) == 0 && len(builder.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
91
-		//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
92
-		builder.runtime.Dns = defaultDns
93
-	}
94
-
95
-	// If custom dns exists, then create a resolv.conf for the container
96
-	if len(config.Dns) > 0 || len(builder.runtime.Dns) > 0 {
97
-		var dns []string
98
-		if len(config.Dns) > 0 {
99
-			dns = config.Dns
100
-		} else {
101
-			dns = builder.runtime.Dns
102
-		}
103
-		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
104
-		f, err := os.Create(container.ResolvConfPath)
105
-		if err != nil {
106
-			return nil, err
107
-		}
108
-		defer f.Close()
109
-		for _, dns := range dns {
110
-			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
111
-				return nil, err
112
-			}
113
-		}
114
-	} else {
115
-		container.ResolvConfPath = "/etc/resolv.conf"
116
-	}
117
-
118
-	// Step 2: save the container json
119
-	if err := container.ToDisk(); err != nil {
120
-		return nil, err
121
-	}
122
-	// Step 3: register the container
123
-	if err := builder.runtime.Register(container); err != nil {
124
-		return nil, err
125
-	}
126
-	return container, nil
127
-}
128
-
129
-// Commit creates a new filesystem image from the current state of a container.
130
-// The image can optionally be tagged into a repository
131
-func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
132
-	// FIXME: freeze the container before copying it to avoid data corruption?
133
-	// FIXME: this shouldn't be in commands.
134
-	if err := container.EnsureMounted(); err != nil {
135
-		return nil, err
136
-	}
137
-
138
-	rwTar, err := container.ExportRw()
139
-	if err != nil {
140
-		return nil, err
141
-	}
142
-	// Create a new image from the container's base layers + a new layer from container changes
143
-	img, err := builder.graph.Create(rwTar, container, comment, author, config)
144
-	if err != nil {
145
-		return nil, err
146
-	}
147
-	// Register the image if needed
148
-	if repository != "" {
149
-		if err := builder.repositories.Set(repository, tag, img.ID, true); err != nil {
150
-			return img, err
151
-		}
152
-	}
153
-	return img, nil
154
-}
... ...
@@ -23,7 +23,6 @@ type BuildFile interface {
23 23
 
24 24
 type buildFile struct {
25 25
 	runtime *Runtime
26
-	builder *Builder
27 26
 	srv     *Server
28 27
 
29 28
 	image        string
... ...
@@ -337,7 +336,7 @@ func (b *buildFile) CmdAdd(args string) error {
337 337
 
338 338
 	b.config.Image = b.image
339 339
 	// Create the container and start it
340
-	container, err := b.builder.Create(b.config)
340
+	container, err := b.runtime.Create(b.config)
341 341
 	if err != nil {
342 342
 		return err
343 343
 	}
... ...
@@ -372,7 +371,7 @@ func (b *buildFile) run() (string, error) {
372 372
 	b.config.Image = b.image
373 373
 
374 374
 	// Create the container and start it
375
-	c, err := b.builder.Create(b.config)
375
+	c, err := b.runtime.Create(b.config)
376 376
 	if err != nil {
377 377
 		return "", err
378 378
 	}
... ...
@@ -428,7 +427,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
428 428
 			}
429 429
 		}
430 430
 
431
-		container, err := b.builder.Create(b.config)
431
+		container, err := b.runtime.Create(b.config)
432 432
 		if err != nil {
433 433
 			return err
434 434
 		}
... ...
@@ -450,7 +449,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
450 450
 	autoConfig := *b.config
451 451
 	autoConfig.Cmd = autoCmd
452 452
 	// Commit the container
453
-	image, err := b.builder.Commit(container, "", "", "", b.maintainer, &autoConfig)
453
+	image, err := b.runtime.Commit(container, "", "", "", b.maintainer, &autoConfig)
454 454
 	if err != nil {
455 455
 		return err
456 456
 	}
... ...
@@ -524,7 +523,6 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
524 524
 
525 525
 func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache bool) BuildFile {
526 526
 	return &buildFile{
527
-		builder:       NewBuilder(srv.runtime),
528 527
 		runtime:       srv.runtime,
529 528
 		srv:           srv,
530 529
 		config:        &Config{},
... ...
@@ -18,7 +18,7 @@ import (
18 18
 func TestIDFormat(t *testing.T) {
19 19
 	runtime := mkRuntime(t)
20 20
 	defer nuke(runtime)
21
-	container1, err := NewBuilder(runtime).Create(
21
+	container1, err := runtime.Create(
22 22
 		&Config{
23 23
 			Image: GetTestImage(runtime).ID,
24 24
 			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
... ...
@@ -388,7 +388,7 @@ func TestRun(t *testing.T) {
388 388
 func TestOutput(t *testing.T) {
389 389
 	runtime := mkRuntime(t)
390 390
 	defer nuke(runtime)
391
-	container, err := NewBuilder(runtime).Create(
391
+	container, err := runtime.Create(
392 392
 		&Config{
393 393
 			Image: GetTestImage(runtime).ID,
394 394
 			Cmd:   []string{"echo", "-n", "foobar"},
... ...
@@ -411,7 +411,7 @@ func TestKillDifferentUser(t *testing.T) {
411 411
 	runtime := mkRuntime(t)
412 412
 	defer nuke(runtime)
413 413
 
414
-	container, err := NewBuilder(runtime).Create(&Config{
414
+	container, err := runtime.Create(&Config{
415 415
 		Image:     GetTestImage(runtime).ID,
416 416
 		Cmd:       []string{"cat"},
417 417
 		OpenStdin: true,
... ...
@@ -471,7 +471,7 @@ func TestCreateVolume(t *testing.T) {
471 471
 	if err != nil {
472 472
 		t.Fatal(err)
473 473
 	}
474
-	c, err := NewBuilder(runtime).Create(config)
474
+	c, err := runtime.Create(config)
475 475
 	if err != nil {
476 476
 		t.Fatal(err)
477 477
 	}
... ...
@@ -486,7 +486,7 @@ func TestCreateVolume(t *testing.T) {
486 486
 func TestKill(t *testing.T) {
487 487
 	runtime := mkRuntime(t)
488 488
 	defer nuke(runtime)
489
-	container, err := NewBuilder(runtime).Create(&Config{
489
+	container, err := runtime.Create(&Config{
490 490
 		Image: GetTestImage(runtime).ID,
491 491
 		Cmd:   []string{"sleep", "2"},
492 492
 	},
... ...
@@ -530,9 +530,7 @@ func TestExitCode(t *testing.T) {
530 530
 	runtime := mkRuntime(t)
531 531
 	defer nuke(runtime)
532 532
 
533
-	builder := NewBuilder(runtime)
534
-
535
-	trueContainer, err := builder.Create(&Config{
533
+	trueContainer, err := runtime.Create(&Config{
536 534
 		Image: GetTestImage(runtime).ID,
537 535
 		Cmd:   []string{"/bin/true", ""},
538 536
 	})
... ...
@@ -547,7 +545,7 @@ func TestExitCode(t *testing.T) {
547 547
 		t.Errorf("Unexpected exit code %d (expected 0)", trueContainer.State.ExitCode)
548 548
 	}
549 549
 
550
-	falseContainer, err := builder.Create(&Config{
550
+	falseContainer, err := runtime.Create(&Config{
551 551
 		Image: GetTestImage(runtime).ID,
552 552
 		Cmd:   []string{"/bin/false", ""},
553 553
 	})
... ...
@@ -566,7 +564,7 @@ func TestExitCode(t *testing.T) {
566 566
 func TestRestart(t *testing.T) {
567 567
 	runtime := mkRuntime(t)
568 568
 	defer nuke(runtime)
569
-	container, err := NewBuilder(runtime).Create(&Config{
569
+	container, err := runtime.Create(&Config{
570 570
 		Image: GetTestImage(runtime).ID,
571 571
 		Cmd:   []string{"echo", "-n", "foobar"},
572 572
 	},
... ...
@@ -596,7 +594,7 @@ func TestRestart(t *testing.T) {
596 596
 func TestRestartStdin(t *testing.T) {
597 597
 	runtime := mkRuntime(t)
598 598
 	defer nuke(runtime)
599
-	container, err := NewBuilder(runtime).Create(&Config{
599
+	container, err := runtime.Create(&Config{
600 600
 		Image: GetTestImage(runtime).ID,
601 601
 		Cmd:   []string{"cat"},
602 602
 
... ...
@@ -673,10 +671,8 @@ func TestUser(t *testing.T) {
673 673
 	runtime := mkRuntime(t)
674 674
 	defer nuke(runtime)
675 675
 
676
-	builder := NewBuilder(runtime)
677
-
678 676
 	// Default user must be root
679
-	container, err := builder.Create(&Config{
677
+	container, err := runtime.Create(&Config{
680 678
 		Image: GetTestImage(runtime).ID,
681 679
 		Cmd:   []string{"id"},
682 680
 	},
... ...
@@ -694,7 +690,7 @@ func TestUser(t *testing.T) {
694 694
 	}
695 695
 
696 696
 	// Set a username
697
-	container, err = builder.Create(&Config{
697
+	container, err = runtime.Create(&Config{
698 698
 		Image: GetTestImage(runtime).ID,
699 699
 		Cmd:   []string{"id"},
700 700
 
... ...
@@ -714,7 +710,7 @@ func TestUser(t *testing.T) {
714 714
 	}
715 715
 
716 716
 	// Set a UID
717
-	container, err = builder.Create(&Config{
717
+	container, err = runtime.Create(&Config{
718 718
 		Image: GetTestImage(runtime).ID,
719 719
 		Cmd:   []string{"id"},
720 720
 
... ...
@@ -734,7 +730,7 @@ func TestUser(t *testing.T) {
734 734
 	}
735 735
 
736 736
 	// Set a different user by uid
737
-	container, err = builder.Create(&Config{
737
+	container, err = runtime.Create(&Config{
738 738
 		Image: GetTestImage(runtime).ID,
739 739
 		Cmd:   []string{"id"},
740 740
 
... ...
@@ -756,7 +752,7 @@ func TestUser(t *testing.T) {
756 756
 	}
757 757
 
758 758
 	// Set a different user by username
759
-	container, err = builder.Create(&Config{
759
+	container, err = runtime.Create(&Config{
760 760
 		Image: GetTestImage(runtime).ID,
761 761
 		Cmd:   []string{"id"},
762 762
 
... ...
@@ -776,7 +772,7 @@ func TestUser(t *testing.T) {
776 776
 	}
777 777
 
778 778
 	// Test an wrong username
779
-	container, err = builder.Create(&Config{
779
+	container, err = runtime.Create(&Config{
780 780
 		Image: GetTestImage(runtime).ID,
781 781
 		Cmd:   []string{"id"},
782 782
 
... ...
@@ -797,9 +793,7 @@ func TestMultipleContainers(t *testing.T) {
797 797
 	runtime := mkRuntime(t)
798 798
 	defer nuke(runtime)
799 799
 
800
-	builder := NewBuilder(runtime)
801
-
802
-	container1, err := builder.Create(&Config{
800
+	container1, err := runtime.Create(&Config{
803 801
 		Image: GetTestImage(runtime).ID,
804 802
 		Cmd:   []string{"sleep", "2"},
805 803
 	},
... ...
@@ -809,7 +803,7 @@ func TestMultipleContainers(t *testing.T) {
809 809
 	}
810 810
 	defer runtime.Destroy(container1)
811 811
 
812
-	container2, err := builder.Create(&Config{
812
+	container2, err := runtime.Create(&Config{
813 813
 		Image: GetTestImage(runtime).ID,
814 814
 		Cmd:   []string{"sleep", "2"},
815 815
 	},
... ...
@@ -853,7 +847,7 @@ func TestMultipleContainers(t *testing.T) {
853 853
 func TestStdin(t *testing.T) {
854 854
 	runtime := mkRuntime(t)
855 855
 	defer nuke(runtime)
856
-	container, err := NewBuilder(runtime).Create(&Config{
856
+	container, err := runtime.Create(&Config{
857 857
 		Image: GetTestImage(runtime).ID,
858 858
 		Cmd:   []string{"cat"},
859 859
 
... ...
@@ -898,7 +892,7 @@ func TestStdin(t *testing.T) {
898 898
 func TestTty(t *testing.T) {
899 899
 	runtime := mkRuntime(t)
900 900
 	defer nuke(runtime)
901
-	container, err := NewBuilder(runtime).Create(&Config{
901
+	container, err := runtime.Create(&Config{
902 902
 		Image: GetTestImage(runtime).ID,
903 903
 		Cmd:   []string{"cat"},
904 904
 
... ...
@@ -943,7 +937,7 @@ func TestTty(t *testing.T) {
943 943
 func TestEnv(t *testing.T) {
944 944
 	runtime := mkRuntime(t)
945 945
 	defer nuke(runtime)
946
-	container, err := NewBuilder(runtime).Create(&Config{
946
+	container, err := runtime.Create(&Config{
947 947
 		Image: GetTestImage(runtime).ID,
948 948
 		Cmd:   []string{"env"},
949 949
 	},
... ...
@@ -992,7 +986,7 @@ func TestEnv(t *testing.T) {
992 992
 func TestEntrypoint(t *testing.T) {
993 993
 	runtime := mkRuntime(t)
994 994
 	defer nuke(runtime)
995
-	container, err := NewBuilder(runtime).Create(
995
+	container, err := runtime.Create(
996 996
 		&Config{
997 997
 			Image:      GetTestImage(runtime).ID,
998 998
 			Entrypoint: []string{"/bin/echo"},
... ...
@@ -1015,7 +1009,7 @@ func TestEntrypoint(t *testing.T) {
1015 1015
 func TestEntrypointNoCmd(t *testing.T) {
1016 1016
 	runtime := mkRuntime(t)
1017 1017
 	defer nuke(runtime)
1018
-	container, err := NewBuilder(runtime).Create(
1018
+	container, err := runtime.Create(
1019 1019
 		&Config{
1020 1020
 			Image:      GetTestImage(runtime).ID,
1021 1021
 			Entrypoint: []string{"/bin/echo", "foobar"},
... ...
@@ -1066,7 +1060,7 @@ func TestLXCConfig(t *testing.T) {
1066 1066
 	cpuMin := 100
1067 1067
 	cpuMax := 10000
1068 1068
 	cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
1069
-	container, err := NewBuilder(runtime).Create(&Config{
1069
+	container, err := runtime.Create(&Config{
1070 1070
 		Image: GetTestImage(runtime).ID,
1071 1071
 		Cmd:   []string{"/bin/true"},
1072 1072
 
... ...
@@ -1090,7 +1084,7 @@ func TestLXCConfig(t *testing.T) {
1090 1090
 func TestCustomLxcConfig(t *testing.T) {
1091 1091
 	runtime := mkRuntime(t)
1092 1092
 	defer nuke(runtime)
1093
-	container, err := NewBuilder(runtime).Create(&Config{
1093
+	container, err := runtime.Create(&Config{
1094 1094
 		Image: GetTestImage(runtime).ID,
1095 1095
 		Cmd:   []string{"/bin/true"},
1096 1096
 
... ...
@@ -1121,7 +1115,7 @@ func BenchmarkRunSequencial(b *testing.B) {
1121 1121
 	runtime := mkRuntime(b)
1122 1122
 	defer nuke(runtime)
1123 1123
 	for i := 0; i < b.N; i++ {
1124
-		container, err := NewBuilder(runtime).Create(&Config{
1124
+		container, err := runtime.Create(&Config{
1125 1125
 			Image: GetTestImage(runtime).ID,
1126 1126
 			Cmd:   []string{"echo", "-n", "foo"},
1127 1127
 		},
... ...
@@ -1153,7 +1147,7 @@ func BenchmarkRunParallel(b *testing.B) {
1153 1153
 		complete := make(chan error)
1154 1154
 		tasks = append(tasks, complete)
1155 1155
 		go func(i int, complete chan error) {
1156
-			container, err := NewBuilder(runtime).Create(&Config{
1156
+			container, err := runtime.Create(&Config{
1157 1157
 				Image: GetTestImage(runtime).ID,
1158 1158
 				Cmd:   []string{"echo", "-n", "foo"},
1159 1159
 			},
... ...
@@ -1229,7 +1223,7 @@ func TestBindMounts(t *testing.T) {
1229 1229
 func TestVolumesFromReadonlyMount(t *testing.T) {
1230 1230
 	runtime := mkRuntime(t)
1231 1231
 	defer nuke(runtime)
1232
-	container, err := NewBuilder(runtime).Create(
1232
+	container, err := runtime.Create(
1233 1233
 		&Config{
1234 1234
 			Image:   GetTestImage(runtime).ID,
1235 1235
 			Cmd:     []string{"/bin/echo", "-n", "foobar"},
... ...
@@ -1248,7 +1242,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
1248 1248
 		t.Fail()
1249 1249
 	}
1250 1250
 
1251
-	container2, err := NewBuilder(runtime).Create(
1251
+	container2, err := runtime.Create(
1252 1252
 		&Config{
1253 1253
 			Image:       GetTestImage(runtime).ID,
1254 1254
 			Cmd:         []string{"/bin/echo", "-n", "foobar"},
... ...
@@ -1284,7 +1278,7 @@ func TestRestartWithVolumes(t *testing.T) {
1284 1284
 	runtime := mkRuntime(t)
1285 1285
 	defer nuke(runtime)
1286 1286
 
1287
-	container, err := NewBuilder(runtime).Create(&Config{
1287
+	container, err := runtime.Create(&Config{
1288 1288
 		Image:   GetTestImage(runtime).ID,
1289 1289
 		Cmd:     []string{"echo", "-n", "foobar"},
1290 1290
 		Volumes: map[string]struct{}{"/test": {}},
... ...
@@ -1327,7 +1321,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
1327 1327
 	runtime := mkRuntime(t)
1328 1328
 	defer nuke(runtime)
1329 1329
 
1330
-	container, err := NewBuilder(runtime).Create(&Config{
1330
+	container, err := runtime.Create(&Config{
1331 1331
 		Image:   GetTestImage(runtime).ID,
1332 1332
 		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
1333 1333
 		Volumes: map[string]struct{}{"/test": {}},
... ...
@@ -1354,7 +1348,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
1354 1354
 		t.Fail()
1355 1355
 	}
1356 1356
 
1357
-	container2, err := NewBuilder(runtime).Create(
1357
+	container2, err := runtime.Create(
1358 1358
 		&Config{
1359 1359
 			Image:       GetTestImage(runtime).ID,
1360 1360
 			Cmd:         []string{"cat", "/test/foo"},
... ...
@@ -1395,7 +1389,7 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
1395 1395
 	if err != nil {
1396 1396
 		t.Fatal(err)
1397 1397
 	}
1398
-	c, err := NewBuilder(runtime).Create(config)
1398
+	c, err := runtime.Create(config)
1399 1399
 	if err != nil {
1400 1400
 		t.Fatal(err)
1401 1401
 	}
... ...
@@ -14,6 +14,8 @@ import (
14 14
 	"strings"
15 15
 )
16 16
 
17
+var defaultDns = []string{"8.8.8.8", "8.8.4.4"}
18
+
17 19
 type Capabilities struct {
18 20
 	MemoryLimit            bool
19 21
 	SwapLimit              bool
... ...
@@ -233,6 +235,7 @@ func (runtime *Runtime) restore() error {
233 233
 	return nil
234 234
 }
235 235
 
236
+// FIXME: comment please
236 237
 func (runtime *Runtime) UpdateCapabilities(quiet bool) {
237 238
 	if cgroupMemoryMountpoint, err := utils.FindCgroupMountpoint("memory"); err != nil {
238 239
 		if !quiet {
... ...
@@ -260,6 +263,133 @@ func (runtime *Runtime) UpdateCapabilities(quiet bool) {
260 260
 	}
261 261
 }
262 262
 
263
+// Create creates a new container from the given configuration.
264
+func (runtime *Runtime) Create(config *Config) (*Container, error) {
265
+	// Lookup image
266
+	img, err := runtime.repositories.LookupImage(config.Image)
267
+	if err != nil {
268
+		return nil, err
269
+	}
270
+
271
+	if img.Config != nil {
272
+		MergeConfig(config, img.Config)
273
+	}
274
+
275
+	if len(config.Entrypoint) != 0 && config.Cmd == nil {
276
+		config.Cmd = []string{}
277
+	} else if config.Cmd == nil || len(config.Cmd) == 0 {
278
+		return nil, fmt.Errorf("No command specified")
279
+	}
280
+
281
+	// Generate id
282
+	id := GenerateID()
283
+	// Generate default hostname
284
+	// FIXME: the lxc template no longer needs to set a default hostname
285
+	if config.Hostname == "" {
286
+		config.Hostname = id[:12]
287
+	}
288
+
289
+	var args []string
290
+	var entrypoint string
291
+
292
+	if len(config.Entrypoint) != 0 {
293
+		entrypoint = config.Entrypoint[0]
294
+		args = append(config.Entrypoint[1:], config.Cmd...)
295
+	} else {
296
+		entrypoint = config.Cmd[0]
297
+		args = config.Cmd[1:]
298
+	}
299
+
300
+	container := &Container{
301
+		// FIXME: we should generate the ID here instead of receiving it as an argument
302
+		ID:              id,
303
+		Created:         time.Now(),
304
+		Path:            entrypoint,
305
+		Args:            args, //FIXME: de-duplicate from config
306
+		Config:          config,
307
+		Image:           img.ID, // Always use the resolved image id
308
+		NetworkSettings: &NetworkSettings{},
309
+		// FIXME: do we need to store this in the container?
310
+		SysInitPath: sysInitPath,
311
+	}
312
+	container.root = runtime.containerRoot(container.ID)
313
+	// Step 1: create the container directory.
314
+	// This doubles as a barrier to avoid race conditions.
315
+	if err := os.Mkdir(container.root, 0700); err != nil {
316
+		return nil, err
317
+	}
318
+
319
+	resolvConf, err := utils.GetResolvConf()
320
+	if err != nil {
321
+		return nil, err
322
+	}
323
+
324
+	if len(config.Dns) == 0 && len(runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
325
+		//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
326
+		runtime.Dns = defaultDns
327
+	}
328
+
329
+	// If custom dns exists, then create a resolv.conf for the container
330
+	if len(config.Dns) > 0 || len(runtime.Dns) > 0 {
331
+		var dns []string
332
+		if len(config.Dns) > 0 {
333
+			dns = config.Dns
334
+		} else {
335
+			dns = runtime.Dns
336
+		}
337
+		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
338
+		f, err := os.Create(container.ResolvConfPath)
339
+		if err != nil {
340
+			return nil, err
341
+		}
342
+		defer f.Close()
343
+		for _, dns := range dns {
344
+			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
345
+				return nil, err
346
+			}
347
+		}
348
+	} else {
349
+		container.ResolvConfPath = "/etc/resolv.conf"
350
+	}
351
+
352
+	// Step 2: save the container json
353
+	if err := container.ToDisk(); err != nil {
354
+		return nil, err
355
+	}
356
+	// Step 3: register the container
357
+	if err := runtime.Register(container); err != nil {
358
+		return nil, err
359
+	}
360
+	return container, nil
361
+}
362
+
363
+// Commit creates a new filesystem image from the current state of a container.
364
+// The image can optionally be tagged into a repository
365
+func (runtime *Runtime) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
366
+	// FIXME: freeze the container before copying it to avoid data corruption?
367
+	// FIXME: this shouldn't be in commands.
368
+	if err := container.EnsureMounted(); err != nil {
369
+		return nil, err
370
+	}
371
+
372
+	rwTar, err := container.ExportRw()
373
+	if err != nil {
374
+		return nil, err
375
+	}
376
+	// Create a new image from the container's base layers + a new layer from container changes
377
+	img, err := runtime.graph.Create(rwTar, container, comment, author, config)
378
+	if err != nil {
379
+		return nil, err
380
+	}
381
+	// Register the image if needed
382
+	if repository != "" {
383
+		if err := runtime.repositories.Set(repository, tag, img.ID, true); err != nil {
384
+			return img, err
385
+		}
386
+	}
387
+	return img, nil
388
+}
389
+
263 390
 // FIXME: harmonize with NewGraph()
264 391
 func NewRuntime(flGraphPath string, autoRestart bool, dns []string) (*Runtime, error) {
265 392
 	runtime, err := NewRuntimeFromDirectory(flGraphPath, autoRestart)
... ...
@@ -347,3 +477,4 @@ func (history *History) Add(container *Container) {
347 347
 	*history = append(*history, container)
348 348
 	sort.Sort(history)
349 349
 }
350
+
... ...
@@ -144,9 +144,7 @@ func TestRuntimeCreate(t *testing.T) {
144 144
 		t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
145 145
 	}
146 146
 
147
-	builder := NewBuilder(runtime)
148
-
149
-	container, err := builder.Create(&Config{
147
+	container, err := runtime.Create(&Config{
150 148
 		Image: GetTestImage(runtime).ID,
151 149
 		Cmd:   []string{"ls", "-al"},
152 150
 	},
... ...
@@ -187,7 +185,7 @@ func TestRuntimeCreate(t *testing.T) {
187 187
 	}
188 188
 
189 189
 	// Make sure crete with bad parameters returns an error
190
-	_, err = builder.Create(
190
+	_, err = runtime.Create(
191 191
 		&Config{
192 192
 			Image: GetTestImage(runtime).ID,
193 193
 		},
... ...
@@ -196,7 +194,7 @@ func TestRuntimeCreate(t *testing.T) {
196 196
 		t.Fatal("Builder.Create should throw an error when Cmd is missing")
197 197
 	}
198 198
 
199
-	_, err = builder.Create(
199
+	_, err = runtime.Create(
200 200
 		&Config{
201 201
 			Image: GetTestImage(runtime).ID,
202 202
 			Cmd:   []string{},
... ...
@@ -210,7 +208,7 @@ func TestRuntimeCreate(t *testing.T) {
210 210
 func TestDestroy(t *testing.T) {
211 211
 	runtime := mkRuntime(t)
212 212
 	defer nuke(runtime)
213
-	container, err := NewBuilder(runtime).Create(&Config{
213
+	container, err := runtime.Create(&Config{
214 214
 		Image: GetTestImage(runtime).ID,
215 215
 		Cmd:   []string{"ls", "-al"},
216 216
 	},
... ...
@@ -296,7 +294,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container,
296 296
 			t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
297 297
 		}
298 298
 		t.Log("Trying port", strPort)
299
-		container, err = NewBuilder(runtime).Create(&Config{
299
+		container, err = runtime.Create(&Config{
300 300
 			Image:     GetTestImage(runtime).ID,
301 301
 			Cmd:       []string{"sh", "-c", cmd},
302 302
 			PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
... ...
@@ -139,8 +139,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
139 139
 		return "", err
140 140
 	}
141 141
 
142
-	b := NewBuilder(srv.runtime)
143
-	c, err := b.Create(config)
142
+	c, err := srv.runtime.Create(config)
144 143
 	if err != nil {
145 144
 		return "", err
146 145
 	}
... ...
@@ -149,7 +148,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
149 149
 		return "", err
150 150
 	}
151 151
 	// FIXME: Handle custom repo, tag comment, author
152
-	img, err = b.Commit(c, "", "", img.Comment, img.Author, nil)
152
+	img, err = srv.runtime.Commit(c, "", "", img.Comment, img.Author, nil)
153 153
 	if err != nil {
154 154
 		return "", err
155 155
 	}
... ...
@@ -400,7 +399,7 @@ func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, conf
400 400
 	if container == nil {
401 401
 		return "", fmt.Errorf("No such container: %s", name)
402 402
 	}
403
-	img, err := NewBuilder(srv.runtime).Commit(container, repo, tag, comment, author, config)
403
+	img, err := srv.runtime.Commit(container, repo, tag, comment, author, config)
404 404
 	if err != nil {
405 405
 		return "", err
406 406
 	}
... ...
@@ -904,8 +903,7 @@ func (srv *Server) ContainerCreate(config *Config) (string, error) {
904 904
 	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
905 905
 		config.MemorySwap = -1
906 906
 	}
907
-	b := NewBuilder(srv.runtime)
908
-	container, err := b.Create(config)
907
+	container, err := srv.runtime.Create(config)
909 908
 	if err != nil {
910 909
 		if srv.runtime.graph.IsNotExist(err) {
911 910
 
... ...
@@ -101,7 +101,7 @@ func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, *HostConf
101 101
 	if config.Image == "_" {
102 102
 		config.Image = GetTestImage(r).ID
103 103
 	}
104
-	c, err := NewBuilder(r).Create(config)
104
+	c, err := r.Create(config)
105 105
 	if err != nil {
106 106
 		return nil, nil, err
107 107
 	}