Browse code

runtime.Create receives an image name + Config. The Config includes all required runtime information: command, environment, ports etc.

Solomon Hykes authored on 2013/03/24 04:16:58
Showing 5 changed files
... ...
@@ -803,45 +803,27 @@ func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string)
803 803
 }
804 804
 
805 805
 func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
806
-	cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container")
807
-	fl_user := cmd.String("u", "", "Username or UID")
808
-	fl_detach := cmd.Bool("d", false, "Detached mode: leave the container running in the background")
809
-	fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
810
-	fl_tty := cmd.Bool("t", false, "Allocate a pseudo-tty")
811
-	fl_memory := cmd.Int64("m", 0, "Memory limit (in bytes)")
812
-	var fl_ports ports
813
-
814
-	cmd.Var(&fl_ports, "p", "Map a network port to the container")
815
-	var fl_env ListOpts
816
-	cmd.Var(&fl_env, "e", "Set environment variables")
817
-	if err := cmd.Parse(args); err != nil {
818
-		return nil
806
+	image, config, err := ParseRun(args)
807
+	if err != nil {
808
+		return err
819 809
 	}
820
-	if cmd.NArg() < 2 {
821
-		cmd.Usage()
822
-		return nil
810
+	if image == "" {
811
+		return fmt.Errorf("Image not specified")
812
+	}
813
+	if len(config.Cmd) == 0 {
814
+		return fmt.Errorf("Command not specified")
823 815
 	}
824
-	name := cmd.Arg(0)
825
-	cmdline := cmd.Args()[1:]
826 816
 	// Create new container
827
-	container, err := srv.runtime.Create(cmdline[0], cmdline[1:], name,
828
-		&Config{
829
-			Ports:     fl_ports,
830
-			User:      *fl_user,
831
-			Tty:       *fl_tty,
832
-			OpenStdin: *fl_stdin,
833
-			Memory:    *fl_memory,
834
-			Env:       fl_env,
835
-		})
817
+	container, err := srv.runtime.Create(image, config)
836 818
 	if err != nil {
837 819
 		return errors.New("Error creating container: " + err.Error())
838 820
 	}
839
-	if *fl_stdin {
821
+	if config.OpenStdin {
840 822
 		cmd_stdin, err := container.StdinPipe()
841 823
 		if err != nil {
842 824
 			return err
843 825
 		}
844
-		if !*fl_detach {
826
+		if !config.Detach {
845 827
 			Go(func() error {
846 828
 				_, err := io.Copy(cmd_stdin, stdin)
847 829
 				cmd_stdin.Close()
... ...
@@ -850,7 +832,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
850 850
 		}
851 851
 	}
852 852
 	// Run the container
853
-	if !*fl_detach {
853
+	if !config.Detach {
854 854
 		cmd_stderr, err := container.StderrPipe()
855 855
 		if err != nil {
856 856
 			return err
... ...
@@ -3,6 +3,7 @@ package docker
3 3
 import (
4 4
 	"encoding/json"
5 5
 	"errors"
6
+	"flag"
6 7
 	"fmt"
7 8
 	"github.com/kr/pty"
8 9
 	"io"
... ...
@@ -50,10 +51,42 @@ type Config struct {
50 50
 	User       string
51 51
 	Memory     int64 // Memory limit (in bytes)
52 52
 	MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
53
+	Detach     bool
53 54
 	Ports      []int
54 55
 	Tty        bool // Attach standard streams to a tty, including stdin if it is not closed.
55 56
 	OpenStdin  bool // Open stdin
56 57
 	Env        []string
58
+	Cmd        []string
59
+}
60
+
61
+func ParseRun(args []string) (string, *Config, error) {
62
+	cmd := flag.NewFlagSet("", flag.ContinueOnError)
63
+	cmd.SetOutput(ioutil.Discard)
64
+	fl_user := cmd.String("u", "", "Username or UID")
65
+	fl_detach := cmd.Bool("d", false, "Detached mode: leave the container running in the background")
66
+	fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
67
+	fl_tty := cmd.Bool("t", false, "Allocate a pseudo-tty")
68
+	fl_memory := cmd.Int64("m", 0, "Memory limit (in bytes)")
69
+	var fl_ports ports
70
+
71
+	cmd.Var(&fl_ports, "p", "Map a network port to the container")
72
+	var fl_env ListOpts
73
+	cmd.Var(&fl_env, "e", "Set environment variables")
74
+	if err := cmd.Parse(args); err != nil {
75
+		return "", nil, err
76
+	}
77
+	image := cmd.Arg(0)
78
+	config := &Config{
79
+		Ports:     fl_ports,
80
+		User:      *fl_user,
81
+		Tty:       *fl_tty,
82
+		OpenStdin: *fl_stdin,
83
+		Memory:    *fl_memory,
84
+		Detach:    *fl_detach,
85
+		Env:       fl_env,
86
+		Cmd:       cmd.Args()[1:],
87
+	}
88
+	return image, config, nil
57 89
 }
58 90
 
59 91
 type NetworkSettings struct {
... ...
@@ -20,10 +20,9 @@ func TestCommitRun(t *testing.T) {
20 20
 	}
21 21
 	defer nuke(runtime)
22 22
 	container1, err := runtime.Create(
23
-		"/bin/sh",
24
-		[]string{"-c", "echo hello > /world"},
25 23
 		GetTestImage(runtime).Id,
26 24
 		&Config{
25
+			Cmd:    []string{"/bin/sh", "-c", "echo hello > /world"},
27 26
 			Memory: 33554432,
28 27
 		},
29 28
 	)
... ...
@@ -54,11 +53,10 @@ func TestCommitRun(t *testing.T) {
54 54
 	// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
55 55
 
56 56
 	container2, err := runtime.Create(
57
-		"cat",
58
-		[]string{"/world"},
59 57
 		img.Id,
60 58
 		&Config{
61 59
 			Memory: 33554432,
60
+			Cmd:    []string{"cat", "/world"},
62 61
 		},
63 62
 	)
64 63
 	if err != nil {
... ...
@@ -88,11 +86,10 @@ func TestRun(t *testing.T) {
88 88
 	}
89 89
 	defer nuke(runtime)
90 90
 	container, err := runtime.Create(
91
-		"ls",
92
-		[]string{"-al"},
93 91
 		GetTestImage(runtime).Id,
94 92
 		&Config{
95 93
 			Memory: 33554432,
94
+			Cmd:    []string{"ls", "-al"},
96 95
 		},
97 96
 	)
98 97
 	if err != nil {
... ...
@@ -118,10 +115,10 @@ func TestOutput(t *testing.T) {
118 118
 	}
119 119
 	defer nuke(runtime)
120 120
 	container, err := runtime.Create(
121
-		"echo",
122
-		[]string{"-n", "foobar"},
123 121
 		GetTestImage(runtime).Id,
124
-		&Config{},
122
+		&Config{
123
+			Cmd: []string{"echo", "-n", "foobar"},
124
+		},
125 125
 	)
126 126
 	if err != nil {
127 127
 		t.Fatal(err)
... ...
@@ -142,11 +139,9 @@ func TestKill(t *testing.T) {
142 142
 		t.Fatal(err)
143 143
 	}
144 144
 	defer nuke(runtime)
145
-	container, err := runtime.Create(
146
-		"cat",
147
-		[]string{"/dev/zero"},
148
-		GetTestImage(runtime).Id,
149
-		&Config{},
145
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
146
+		Cmd: []string{"cat", "/dev/zero"},
147
+	},
150 148
 	)
151 149
 	if err != nil {
152 150
 		t.Fatal(err)
... ...
@@ -185,11 +180,9 @@ func TestExitCode(t *testing.T) {
185 185
 	}
186 186
 	defer nuke(runtime)
187 187
 
188
-	trueContainer, err := runtime.Create(
189
-		"/bin/true",
190
-		[]string{""},
191
-		GetTestImage(runtime).Id,
192
-		&Config{},
188
+	trueContainer, err := runtime.Create(GetTestImage(runtime).Id, &Config{
189
+		Cmd: []string{"/bin/true", ""},
190
+	},
193 191
 	)
194 192
 	if err != nil {
195 193
 		t.Fatal(err)
... ...
@@ -199,11 +192,9 @@ func TestExitCode(t *testing.T) {
199 199
 		t.Fatal(err)
200 200
 	}
201 201
 
202
-	falseContainer, err := runtime.Create(
203
-		"/bin/false",
204
-		[]string{""},
205
-		GetTestImage(runtime).Id,
206
-		&Config{},
202
+	falseContainer, err := runtime.Create(GetTestImage(runtime).Id, &Config{
203
+		Cmd: []string{"/bin/false", ""},
204
+	},
207 205
 	)
208 206
 	if err != nil {
209 207
 		t.Fatal(err)
... ...
@@ -228,11 +219,9 @@ func TestRestart(t *testing.T) {
228 228
 		t.Fatal(err)
229 229
 	}
230 230
 	defer nuke(runtime)
231
-	container, err := runtime.Create(
232
-		"echo",
233
-		[]string{"-n", "foobar"},
234
-		GetTestImage(runtime).Id,
235
-		&Config{},
231
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
232
+		Cmd: []string{"echo", "-n", "foobar"},
233
+	},
236 234
 	)
237 235
 	if err != nil {
238 236
 		t.Fatal(err)
... ...
@@ -262,13 +251,11 @@ func TestRestartStdin(t *testing.T) {
262 262
 		t.Fatal(err)
263 263
 	}
264 264
 	defer nuke(runtime)
265
-	container, err := runtime.Create(
266
-		"cat",
267
-		[]string{},
268
-		GetTestImage(runtime).Id,
269
-		&Config{
270
-			OpenStdin: true,
271
-		},
265
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
266
+		Cmd: []string{"cat"},
267
+
268
+		OpenStdin: true,
269
+	},
272 270
 	)
273 271
 	if err != nil {
274 272
 		t.Fatal(err)
... ...
@@ -313,11 +300,9 @@ func TestUser(t *testing.T) {
313 313
 	defer nuke(runtime)
314 314
 
315 315
 	// Default user must be root
316
-	container, err := runtime.Create(
317
-		"id",
318
-		[]string{},
319
-		GetTestImage(runtime).Id,
320
-		&Config{},
316
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
317
+		Cmd: []string{"id"},
318
+	},
321 319
 	)
322 320
 	if err != nil {
323 321
 		t.Fatal(err)
... ...
@@ -332,13 +317,11 @@ func TestUser(t *testing.T) {
332 332
 	}
333 333
 
334 334
 	// Set a username
335
-	container, err = runtime.Create(
336
-		"id",
337
-		[]string{},
338
-		GetTestImage(runtime).Id,
339
-		&Config{
340
-			User: "root",
341
-		},
335
+	container, err = runtime.Create(GetTestImage(runtime).Id, &Config{
336
+		Cmd: []string{"id"},
337
+
338
+		User: "root",
339
+	},
342 340
 	)
343 341
 	if err != nil {
344 342
 		t.Fatal(err)
... ...
@@ -353,13 +336,11 @@ func TestUser(t *testing.T) {
353 353
 	}
354 354
 
355 355
 	// Set a UID
356
-	container, err = runtime.Create(
357
-		"id",
358
-		[]string{},
359
-		GetTestImage(runtime).Id,
360
-		&Config{
361
-			User: "0",
362
-		},
356
+	container, err = runtime.Create(GetTestImage(runtime).Id, &Config{
357
+		Cmd: []string{"id"},
358
+
359
+		User: "0",
360
+	},
363 361
 	)
364 362
 	if err != nil || container.State.ExitCode != 0 {
365 363
 		t.Fatal(err)
... ...
@@ -374,13 +355,11 @@ func TestUser(t *testing.T) {
374 374
 	}
375 375
 
376 376
 	// Set a different user by uid
377
-	container, err = runtime.Create(
378
-		"id",
379
-		[]string{},
380
-		GetTestImage(runtime).Id,
381
-		&Config{
382
-			User: "1",
383
-		},
377
+	container, err = runtime.Create(GetTestImage(runtime).Id, &Config{
378
+		Cmd: []string{"id"},
379
+
380
+		User: "1",
381
+	},
384 382
 	)
385 383
 	if err != nil {
386 384
 		t.Fatal(err)
... ...
@@ -397,13 +376,11 @@ func TestUser(t *testing.T) {
397 397
 	}
398 398
 
399 399
 	// Set a different user by username
400
-	container, err = runtime.Create(
401
-		"id",
402
-		[]string{},
403
-		GetTestImage(runtime).Id,
404
-		&Config{
405
-			User: "daemon",
406
-		},
400
+	container, err = runtime.Create(GetTestImage(runtime).Id, &Config{
401
+		Cmd: []string{"id"},
402
+
403
+		User: "daemon",
404
+	},
407 405
 	)
408 406
 	if err != nil {
409 407
 		t.Fatal(err)
... ...
@@ -425,22 +402,18 @@ func TestMultipleContainers(t *testing.T) {
425 425
 	}
426 426
 	defer nuke(runtime)
427 427
 
428
-	container1, err := runtime.Create(
429
-		"cat",
430
-		[]string{"/dev/zero"},
431
-		GetTestImage(runtime).Id,
432
-		&Config{},
428
+	container1, err := runtime.Create(GetTestImage(runtime).Id, &Config{
429
+		Cmd: []string{"cat", "/dev/zero"},
430
+	},
433 431
 	)
434 432
 	if err != nil {
435 433
 		t.Fatal(err)
436 434
 	}
437 435
 	defer runtime.Destroy(container1)
438 436
 
439
-	container2, err := runtime.Create(
440
-		"cat",
441
-		[]string{"/dev/zero"},
442
-		GetTestImage(runtime).Id,
443
-		&Config{},
437
+	container2, err := runtime.Create(GetTestImage(runtime).Id, &Config{
438
+		Cmd: []string{"cat", "/dev/zero"},
439
+	},
444 440
 	)
445 441
 	if err != nil {
446 442
 		t.Fatal(err)
... ...
@@ -479,13 +452,11 @@ func TestStdin(t *testing.T) {
479 479
 		t.Fatal(err)
480 480
 	}
481 481
 	defer nuke(runtime)
482
-	container, err := runtime.Create(
483
-		"cat",
484
-		[]string{},
485
-		GetTestImage(runtime).Id,
486
-		&Config{
487
-			OpenStdin: true,
488
-		},
482
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
483
+		Cmd: []string{"cat"},
484
+
485
+		OpenStdin: true,
486
+	},
489 487
 	)
490 488
 	if err != nil {
491 489
 		t.Fatal(err)
... ...
@@ -514,13 +485,11 @@ func TestTty(t *testing.T) {
514 514
 		t.Fatal(err)
515 515
 	}
516 516
 	defer nuke(runtime)
517
-	container, err := runtime.Create(
518
-		"cat",
519
-		[]string{},
520
-		GetTestImage(runtime).Id,
521
-		&Config{
522
-			OpenStdin: true,
523
-		},
517
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
518
+		Cmd: []string{"cat"},
519
+
520
+		OpenStdin: true,
521
+	},
524 522
 	)
525 523
 	if err != nil {
526 524
 		t.Fatal(err)
... ...
@@ -549,11 +518,9 @@ func TestEnv(t *testing.T) {
549 549
 		t.Fatal(err)
550 550
 	}
551 551
 	defer nuke(runtime)
552
-	container, err := runtime.Create(
553
-		"/usr/bin/env",
554
-		[]string{},
555
-		GetTestImage(runtime).Id,
556
-		&Config{},
552
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
553
+		Cmd: []string{"/usr/bin/env"},
554
+	},
557 555
 	)
558 556
 	if err != nil {
559 557
 		t.Fatal(err)
... ...
@@ -623,14 +590,12 @@ func TestLXCConfig(t *testing.T) {
623 623
 	memMin := 33554432
624 624
 	memMax := 536870912
625 625
 	mem := memMin + rand.Intn(memMax-memMin)
626
-	container, err := runtime.Create(
627
-		"/bin/true",
628
-		[]string{},
629
-		GetTestImage(runtime).Id,
630
-		&Config{
631
-			Hostname: "foobar",
632
-			Memory:   int64(mem),
633
-		},
626
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
627
+		Cmd: []string{"/bin/true"},
628
+
629
+		Hostname: "foobar",
630
+		Memory:   int64(mem),
631
+	},
634 632
 	)
635 633
 	if err != nil {
636 634
 		t.Fatal(err)
... ...
@@ -651,11 +616,9 @@ func BenchmarkRunSequencial(b *testing.B) {
651 651
 	}
652 652
 	defer nuke(runtime)
653 653
 	for i := 0; i < b.N; i++ {
654
-		container, err := runtime.Create(
655
-			"echo",
656
-			[]string{"-n", "foo"},
657
-			GetTestImage(runtime).Id,
658
-			&Config{},
654
+		container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
655
+			Cmd: []string{"echo", "-n", "foo"},
656
+		},
659 657
 		)
660 658
 		if err != nil {
661 659
 			b.Fatal(err)
... ...
@@ -687,11 +650,9 @@ func BenchmarkRunParallel(b *testing.B) {
687 687
 		complete := make(chan error)
688 688
 		tasks = append(tasks, complete)
689 689
 		go func(i int, complete chan error) {
690
-			container, err := runtime.Create(
691
-				"echo",
692
-				[]string{"-n", "foo"},
693
-				GetTestImage(runtime).Id,
694
-				&Config{},
690
+			container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
691
+				Cmd: []string{"echo", "-n", "foo"},
692
+			},
695 693
 			)
696 694
 			if err != nil {
697 695
 				complete <- err
... ...
@@ -64,7 +64,7 @@ func (runtime *Runtime) containerRoot(id string) string {
64 64
 	return path.Join(runtime.repository, id)
65 65
 }
66 66
 
67
-func (runtime *Runtime) Create(command string, args []string, image string, config *Config) (*Container, error) {
67
+func (runtime *Runtime) Create(image string, config *Config) (*Container, error) {
68 68
 	// Lookup image
69 69
 	img, err := runtime.repositories.LookupImage(image)
70 70
 	if err != nil {
... ...
@@ -72,13 +72,12 @@ func (runtime *Runtime) Create(command string, args []string, image string, conf
72 72
 	}
73 73
 	container := &Container{
74 74
 		// FIXME: we should generate the ID here instead of receiving it as an argument
75
-		Id:      GenerateId(),
76
-		Created: time.Now(),
77
-		Path:    command,
78
-		Args:    args,
79
-		Config:  config,
80
-		Image:   img.Id, // Always use the resolved image id
81
-		//FIXME: store the name under which the image was given, for reference
75
+		Id:              GenerateId(),
76
+		Created:         time.Now(),
77
+		Path:            config.Cmd[0],
78
+		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
79
+		Config:          config,
80
+		Image:           img.Id, // Always use the resolved image id
82 81
 		NetworkSettings: &NetworkSettings{},
83 82
 		// FIXME: do we need to store this in the container?
84 83
 		SysInitPath: sysInitPath,
... ...
@@ -112,11 +112,9 @@ func TestRuntimeCreate(t *testing.T) {
112 112
 	if len(runtime.List()) != 0 {
113 113
 		t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
114 114
 	}
115
-	container, err := runtime.Create(
116
-		"ls",
117
-		[]string{"-al"},
118
-		GetTestImage(runtime).Id,
119
-		&Config{},
115
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
116
+		Cmd: []string{"ls", "-al"},
117
+	},
120 118
 	)
121 119
 	if err != nil {
122 120
 		t.Fatal(err)
... ...
@@ -160,11 +158,9 @@ func TestDestroy(t *testing.T) {
160 160
 		t.Fatal(err)
161 161
 	}
162 162
 	defer nuke(runtime)
163
-	container, err := runtime.Create(
164
-		"ls",
165
-		[]string{"-al"},
166
-		GetTestImage(runtime).Id,
167
-		&Config{},
163
+	container, err := runtime.Create(GetTestImage(runtime).Id, &Config{
164
+		Cmd: []string{"ls", "-al"},
165
+	},
168 166
 	)
169 167
 	if err != nil {
170 168
 		t.Fatal(err)
... ...
@@ -208,33 +204,27 @@ func TestGet(t *testing.T) {
208 208
 		t.Fatal(err)
209 209
 	}
210 210
 	defer nuke(runtime)
211
-	container1, err := runtime.Create(
212
-		"ls",
213
-		[]string{"-al"},
214
-		GetTestImage(runtime).Id,
215
-		&Config{},
211
+	container1, err := runtime.Create(GetTestImage(runtime).Id, &Config{
212
+		Cmd: []string{"ls", "-al"},
213
+	},
216 214
 	)
217 215
 	if err != nil {
218 216
 		t.Fatal(err)
219 217
 	}
220 218
 	defer runtime.Destroy(container1)
221 219
 
222
-	container2, err := runtime.Create(
223
-		"ls",
224
-		[]string{"-al"},
225
-		GetTestImage(runtime).Id,
226
-		&Config{},
220
+	container2, err := runtime.Create(GetTestImage(runtime).Id, &Config{
221
+		Cmd: []string{"ls", "-al"},
222
+	},
227 223
 	)
228 224
 	if err != nil {
229 225
 		t.Fatal(err)
230 226
 	}
231 227
 	defer runtime.Destroy(container2)
232 228
 
233
-	container3, err := runtime.Create(
234
-		"ls",
235
-		[]string{"-al"},
236
-		GetTestImage(runtime).Id,
237
-		&Config{},
229
+	container3, err := runtime.Create(GetTestImage(runtime).Id, &Config{
230
+		Cmd: []string{"ls", "-al"},
231
+	},
238 232
 	)
239 233
 	if err != nil {
240 234
 		t.Fatal(err)
... ...
@@ -274,11 +264,9 @@ func TestRestore(t *testing.T) {
274 274
 	}
275 275
 
276 276
 	// Create a container with one instance of docker
277
-	container1, err := runtime1.Create(
278
-		"ls",
279
-		[]string{"-al"},
280
-		GetTestImage(runtime1).Id,
281
-		&Config{},
277
+	container1, err := runtime1.Create(GetTestImage(runtime1).Id, &Config{
278
+		Cmd: []string{"ls", "-al"},
279
+	},
282 280
 	)
283 281
 	if err != nil {
284 282
 		t.Fatal(err)