Browse code

API: Provide the HostConfig during "run".

Currently, the HostConfig is only passed from the CLI to Docker only
when issuing a docker create, but not when doing a docker run.

In the near future, in order to allocate ports at creation time rather
than start time, we will need to have the HostConfig readily available
at container creation.

This PR makes the client always pass the HostConfig when creating a
container (regardless of whether it's for a run or create).

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>

Andrea Luzzardi authored on 2014/09/26 06:23:59
Showing 7 changed files
... ...
@@ -2027,12 +2027,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
2027 2027
 		containerValues.Set("name", name)
2028 2028
 	}
2029 2029
 
2030
-	var data interface{}
2031
-	if hostConfig != nil {
2032
-		data = runconfig.MergeConfigs(config, hostConfig)
2033
-	} else {
2034
-		data = config
2035
-	}
2030
+	mergedConfig := runconfig.MergeConfigs(config, hostConfig)
2036 2031
 
2037 2032
 	var containerIDFile *cidFile
2038 2033
 	if cidfile != "" {
... ...
@@ -2044,7 +2039,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
2044 2044
 	}
2045 2045
 
2046 2046
 	//create the container
2047
-	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), data, false)
2047
+	stream, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false)
2048 2048
 	//if image not found try to pull it
2049 2049
 	if statusCode == 404 {
2050 2050
 		fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image)
... ...
@@ -2053,7 +2048,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
2053 2053
 			return nil, err
2054 2054
 		}
2055 2055
 		// Retry
2056
-		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), data, false); err != nil {
2056
+		if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, false); err != nil {
2057 2057
 			return nil, err
2058 2058
 		}
2059 2059
 	} else if err != nil {
... ...
@@ -2155,7 +2150,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
2155 2155
 		sigProxy = false
2156 2156
 	}
2157 2157
 
2158
-	runResult, err := cli.createContainer(config, nil, hostConfig.ContainerIDFile, *flName)
2158
+	runResult, err := cli.createContainer(config, hostConfig, hostConfig.ContainerIDFile, *flName)
2159 2159
 	if err != nil {
2160 2160
 		return err
2161 2161
 	}
... ...
@@ -173,7 +173,7 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowDecomp
173 173
 		return nil
174 174
 	}
175 175
 
176
-	container, _, err := b.Daemon.Create(b.Config, "")
176
+	container, _, err := b.Daemon.Create(b.Config, nil, "")
177 177
 	if err != nil {
178 178
 		return err
179 179
 	}
... ...
@@ -442,7 +442,7 @@ func (b *Builder) create() (*daemon.Container, error) {
442 442
 	config := *b.Config
443 443
 
444 444
 	// Create the container
445
-	c, warnings, err := b.Daemon.Create(b.Config, "")
445
+	c, warnings, err := b.Daemon.Create(b.Config, nil, "")
446 446
 	if err != nil {
447 447
 		return nil, err
448 448
 	}
... ...
@@ -26,7 +26,16 @@ func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status {
26 26
 		job.Errorf("Your kernel does not support swap limit capabilities. Limitation discarded.\n")
27 27
 		config.MemorySwap = -1
28 28
 	}
29
-	container, buildWarnings, err := daemon.Create(config, name)
29
+
30
+	var hostConfig *runconfig.HostConfig
31
+	if job.EnvExists("HostConfig") {
32
+		hostConfig = runconfig.ContainerHostConfigFromJob(job)
33
+	} else {
34
+		// Older versions of the API don't provide a HostConfig.
35
+		hostConfig = nil
36
+	}
37
+
38
+	container, buildWarnings, err := daemon.Create(config, hostConfig, name)
30 39
 	if err != nil {
31 40
 		if daemon.Graph().IsNotExist(err) {
32 41
 			_, tag := parsers.ParseRepositoryTag(config.Image)
... ...
@@ -51,18 +60,11 @@ func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status {
51 51
 		job.Errorf("%s\n", warning)
52 52
 	}
53 53
 
54
-	if job.EnvExists("HostConfig") {
55
-		hostConfig := runconfig.ContainerHostConfigFromJob(job)
56
-		if err := daemon.setHostConfig(container, hostConfig); err != nil {
57
-			return job.Error(err)
58
-		}
59
-	}
60
-
61 54
 	return engine.StatusOK
62 55
 }
63 56
 
64 57
 // Create creates a new container from the given configuration with a given name.
65
-func (daemon *Daemon) Create(config *runconfig.Config, name string) (*Container, []string, error) {
58
+func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (*Container, []string, error) {
66 59
 	var (
67 60
 		container *Container
68 61
 		warnings  []string
... ...
@@ -84,6 +86,11 @@ func (daemon *Daemon) Create(config *runconfig.Config, name string) (*Container,
84 84
 	if err := daemon.createRootfs(container, img); err != nil {
85 85
 		return nil, nil, err
86 86
 	}
87
+	if hostConfig != nil {
88
+		if err := daemon.setHostConfig(container, hostConfig); err != nil {
89
+			return nil, nil, err
90
+		}
91
+	}
87 92
 	if err := container.ToDisk(); err != nil {
88 93
 		return nil, nil, err
89 94
 	}
... ...
@@ -27,6 +27,8 @@ func (daemon *Daemon) ContainerStart(job *engine.Job) engine.Status {
27 27
 	}
28 28
 
29 29
 	// If no environment was set, then no hostconfig was passed.
30
+	// This is kept for backward compatibility - hostconfig should be passed when
31
+	// creating a container, not during start.
30 32
 	if len(job.Environ()) > 0 {
31 33
 		hostConfig := runconfig.ContainerHostConfigFromJob(job)
32 34
 		if err := daemon.setHostConfig(container, hostConfig); err != nil {
... ...
@@ -18,6 +18,7 @@ func TestRestartStdin(t *testing.T) {
18 18
 
19 19
 		OpenStdin: true,
20 20
 	},
21
+		&runconfig.HostConfig{},
21 22
 		"",
22 23
 	)
23 24
 	if err != nil {
... ...
@@ -94,6 +95,7 @@ func TestStdin(t *testing.T) {
94 94
 
95 95
 		OpenStdin: true,
96 96
 	},
97
+		&runconfig.HostConfig{},
97 98
 		"",
98 99
 	)
99 100
 	if err != nil {
... ...
@@ -139,6 +141,7 @@ func TestTty(t *testing.T) {
139 139
 
140 140
 		OpenStdin: true,
141 141
 	},
142
+		&runconfig.HostConfig{},
142 143
 		"",
143 144
 	)
144 145
 	if err != nil {
... ...
@@ -183,6 +186,7 @@ func BenchmarkRunSequential(b *testing.B) {
183 183
 			Image: GetTestImage(daemon).ID,
184 184
 			Cmd:   []string{"echo", "-n", "foo"},
185 185
 		},
186
+			&runconfig.HostConfig{},
186 187
 			"",
187 188
 		)
188 189
 		if err != nil {
... ...
@@ -216,6 +220,7 @@ func BenchmarkRunParallel(b *testing.B) {
216 216
 				Image: GetTestImage(daemon).ID,
217 217
 				Cmd:   []string{"echo", "-n", "foo"},
218 218
 			},
219
+				&runconfig.HostConfig{},
219 220
 				"",
220 221
 			)
221 222
 			if err != nil {
... ...
@@ -266,6 +266,7 @@ func TestDaemonCreate(t *testing.T) {
266 266
 		Image: GetTestImage(daemon).ID,
267 267
 		Cmd:   []string{"ls", "-al"},
268 268
 	},
269
+		&runconfig.HostConfig{},
269 270
 		"",
270 271
 	)
271 272
 	if err != nil {
... ...
@@ -309,14 +310,15 @@ func TestDaemonCreate(t *testing.T) {
309 309
 			Image: GetTestImage(daemon).ID,
310 310
 			Cmd:   []string{"ls", "-al"},
311 311
 		},
312
+		&runconfig.HostConfig{},
312 313
 		"conflictname",
313 314
 	)
314
-	if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: []string{"ls", "-al"}}, testContainer.Name); err == nil || !strings.Contains(err.Error(), utils.TruncateID(testContainer.ID)) {
315
+	if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: []string{"ls", "-al"}}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), utils.TruncateID(testContainer.ID)) {
315 316
 		t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %s", err.Error())
316 317
 	}
317 318
 
318 319
 	// Make sure create with bad parameters returns an error
319
-	if _, _, err = daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID}, ""); err == nil {
320
+	if _, _, err = daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID}, &runconfig.HostConfig{}, ""); err == nil {
320 321
 		t.Fatal("Builder.Create should throw an error when Cmd is missing")
321 322
 	}
322 323
 
... ...
@@ -325,6 +327,7 @@ func TestDaemonCreate(t *testing.T) {
325 325
 			Image: GetTestImage(daemon).ID,
326 326
 			Cmd:   []string{},
327 327
 		},
328
+		&runconfig.HostConfig{},
328 329
 		"",
329 330
 	); err == nil {
330 331
 		t.Fatal("Builder.Create should throw an error when Cmd is empty")
... ...
@@ -335,7 +338,7 @@ func TestDaemonCreate(t *testing.T) {
335 335
 		Cmd:       []string{"/bin/ls"},
336 336
 		PortSpecs: []string{"80"},
337 337
 	}
338
-	container, _, err = daemon.Create(config, "")
338
+	container, _, err = daemon.Create(config, &runconfig.HostConfig{}, "")
339 339
 
340 340
 	_, err = daemon.Commit(container, "testrepo", "testtag", "", "", true, config)
341 341
 	if err != nil {
... ...
@@ -348,6 +351,7 @@ func TestDaemonCreate(t *testing.T) {
348 348
 		Cmd:       []string{"ls", "-al"},
349 349
 		PortSpecs: []string{"80:8000"},
350 350
 	},
351
+		&runconfig.HostConfig{},
351 352
 		"",
352 353
 	)
353 354
 	if err != nil {
... ...
@@ -365,7 +369,9 @@ func TestDestroy(t *testing.T) {
365 365
 	container, _, err := daemon.Create(&runconfig.Config{
366 366
 		Image: GetTestImage(daemon).ID,
367 367
 		Cmd:   []string{"ls", "-al"},
368
-	}, "")
368
+	},
369
+		&runconfig.HostConfig{},
370
+		"")
369 371
 	if err != nil {
370 372
 		t.Fatal(err)
371 373
 	}
... ...
@@ -857,7 +863,9 @@ func TestDestroyWithInitLayer(t *testing.T) {
857 857
 	container, _, err := daemon.Create(&runconfig.Config{
858 858
 		Image: GetTestImage(daemon).ID,
859 859
 		Cmd:   []string{"ls", "-al"},
860
-	}, "")
860
+	},
861
+		&runconfig.HostConfig{},
862
+		"")
861 863
 
862 864
 	if err != nil {
863 865
 		t.Fatal(err)
... ...
@@ -263,7 +263,7 @@ func mkContainer(r *daemon.Daemon, args []string, t *testing.T) (*daemon.Contain
263 263
 	if config.Image == "_" {
264 264
 		config.Image = GetTestImage(r).ID
265 265
 	}
266
-	c, _, err := r.Create(config, "")
266
+	c, _, err := r.Create(config, nil, "")
267 267
 	if err != nil {
268 268
 		return nil, nil, err
269 269
 	}