Signed-off-by: Lei Jitang <leijitang@huawei.com>
Lei Jitang authored on 2015/10/19 22:17:37... | ... |
@@ -112,8 +112,13 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF |
112 | 112 |
return errors.New("Please specify only one -H") |
113 | 113 |
} |
114 | 114 |
|
115 |
+ defaultHost := opts.DefaultTCPHost |
|
116 |
+ if clientFlags.Common.TLSOptions != nil { |
|
117 |
+ defaultHost = opts.DefaultTLSHost |
|
118 |
+ } |
|
119 |
+ |
|
115 | 120 |
var e error |
116 |
- if hosts[0], e = opts.ParseHost(hosts[0]); e != nil { |
|
121 |
+ if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil { |
|
117 | 122 |
return e |
118 | 123 |
} |
119 | 124 |
|
... | ... |
@@ -210,6 +210,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { |
210 | 210 |
} |
211 | 211 |
serverConfig = setPlatformServerConfig(serverConfig, cli.Config) |
212 | 212 |
|
213 |
+ defaultHost := opts.DefaultHost |
|
213 | 214 |
if commonFlags.TLSOptions != nil { |
214 | 215 |
if !commonFlags.TLSOptions.InsecureSkipVerify { |
215 | 216 |
// server requires and verifies client's certificate |
... | ... |
@@ -220,6 +221,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { |
220 | 220 |
logrus.Fatal(err) |
221 | 221 |
} |
222 | 222 |
serverConfig.TLSConfig = tlsConfig |
223 |
+ defaultHost = opts.DefaultTLSHost |
|
223 | 224 |
} |
224 | 225 |
|
225 | 226 |
if len(commonFlags.Hosts) == 0 { |
... | ... |
@@ -227,7 +229,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { |
227 | 227 |
} |
228 | 228 |
for i := 0; i < len(commonFlags.Hosts); i++ { |
229 | 229 |
var err error |
230 |
- if commonFlags.Hosts[i], err = opts.ParseHost(commonFlags.Hosts[i]); err != nil { |
|
230 |
+ if commonFlags.Hosts[i], err = opts.ParseHost(defaultHost, commonFlags.Hosts[i]); err != nil { |
|
231 | 231 |
logrus.Fatalf("error parsing -H %s : %v", commonFlags.Hosts[i], err) |
232 | 232 |
} |
233 | 233 |
} |
... | ... |
@@ -1723,3 +1723,37 @@ func (s *DockerDaemonSuite) TestDaemonStartWithoutHost(c *check.C) { |
1723 | 1723 |
}() |
1724 | 1724 |
c.Assert(s.d.Start(), check.IsNil) |
1725 | 1725 |
} |
1726 |
+ |
|
1727 |
+func (s *DockerDaemonSuite) TestDaemonStartWithDefalutTlsHost(c *check.C) { |
|
1728 |
+ s.d.useDefaultTLSHost = true |
|
1729 |
+ defer func() { |
|
1730 |
+ s.d.useDefaultTLSHost = false |
|
1731 |
+ }() |
|
1732 |
+ if err := s.d.Start( |
|
1733 |
+ "--tlsverify", |
|
1734 |
+ "--tlscacert", "fixtures/https/ca.pem", |
|
1735 |
+ "--tlscert", "fixtures/https/server-cert.pem", |
|
1736 |
+ "--tlskey", "fixtures/https/server-key.pem"); err != nil { |
|
1737 |
+ c.Fatalf("Could not start daemon: %v", err) |
|
1738 |
+ } |
|
1739 |
+ |
|
1740 |
+ // The client with --tlsverify should also use default host localhost:2376 |
|
1741 |
+ tmpHost := os.Getenv("DOCKER_HOST") |
|
1742 |
+ defer func() { |
|
1743 |
+ os.Setenv("DOCKER_HOST", tmpHost) |
|
1744 |
+ }() |
|
1745 |
+ |
|
1746 |
+ os.Setenv("DOCKER_HOST", "") |
|
1747 |
+ |
|
1748 |
+ out, _ := dockerCmd( |
|
1749 |
+ c, |
|
1750 |
+ "--tlsverify", |
|
1751 |
+ "--tlscacert", "fixtures/https/ca.pem", |
|
1752 |
+ "--tlscert", "fixtures/https/client-cert.pem", |
|
1753 |
+ "--tlskey", "fixtures/https/client-key.pem", |
|
1754 |
+ "version", |
|
1755 |
+ ) |
|
1756 |
+ if !strings.Contains(out, "Server") { |
|
1757 |
+ c.Fatalf("docker version should return information of server side") |
|
1758 |
+ } |
|
1759 |
+} |
... | ... |
@@ -26,7 +26,9 @@ import ( |
26 | 26 |
"github.com/docker/docker/pkg/httputils" |
27 | 27 |
"github.com/docker/docker/pkg/integration" |
28 | 28 |
"github.com/docker/docker/pkg/ioutils" |
29 |
+ "github.com/docker/docker/pkg/sockets" |
|
29 | 30 |
"github.com/docker/docker/pkg/stringutils" |
31 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
30 | 32 |
"github.com/go-check/check" |
31 | 33 |
) |
32 | 34 |
|
... | ... |
@@ -37,19 +39,26 @@ type Daemon struct { |
37 | 37 |
Command string |
38 | 38 |
GlobalFlags []string |
39 | 39 |
|
40 |
- id string |
|
41 |
- c *check.C |
|
42 |
- logFile *os.File |
|
43 |
- folder string |
|
44 |
- root string |
|
45 |
- stdin io.WriteCloser |
|
46 |
- stdout, stderr io.ReadCloser |
|
47 |
- cmd *exec.Cmd |
|
48 |
- storageDriver string |
|
49 |
- execDriver string |
|
50 |
- wait chan error |
|
51 |
- userlandProxy bool |
|
52 |
- useDefaultHost bool |
|
40 |
+ id string |
|
41 |
+ c *check.C |
|
42 |
+ logFile *os.File |
|
43 |
+ folder string |
|
44 |
+ root string |
|
45 |
+ stdin io.WriteCloser |
|
46 |
+ stdout, stderr io.ReadCloser |
|
47 |
+ cmd *exec.Cmd |
|
48 |
+ storageDriver string |
|
49 |
+ execDriver string |
|
50 |
+ wait chan error |
|
51 |
+ userlandProxy bool |
|
52 |
+ useDefaultHost bool |
|
53 |
+ useDefaultTLSHost bool |
|
54 |
+} |
|
55 |
+ |
|
56 |
+type clientConfig struct { |
|
57 |
+ transport *http.Transport |
|
58 |
+ scheme string |
|
59 |
+ addr string |
|
53 | 60 |
} |
54 | 61 |
|
55 | 62 |
// NewDaemon returns a Daemon instance to be used for testing. |
... | ... |
@@ -86,6 +95,50 @@ func NewDaemon(c *check.C) *Daemon { |
86 | 86 |
} |
87 | 87 |
} |
88 | 88 |
|
89 |
+func (d *Daemon) getClientConfig() (*clientConfig, error) { |
|
90 |
+ var ( |
|
91 |
+ transport *http.Transport |
|
92 |
+ scheme string |
|
93 |
+ addr string |
|
94 |
+ proto string |
|
95 |
+ ) |
|
96 |
+ if d.useDefaultTLSHost { |
|
97 |
+ option := &tlsconfig.Options{ |
|
98 |
+ CAFile: "fixtures/https/ca.pem", |
|
99 |
+ CertFile: "fixtures/https/client-cert.pem", |
|
100 |
+ KeyFile: "fixtures/https/client-key.pem", |
|
101 |
+ } |
|
102 |
+ tlsConfig, err := tlsconfig.Client(*option) |
|
103 |
+ if err != nil { |
|
104 |
+ return nil, err |
|
105 |
+ } |
|
106 |
+ transport = &http.Transport{ |
|
107 |
+ TLSClientConfig: tlsConfig, |
|
108 |
+ } |
|
109 |
+ addr = fmt.Sprintf("%s:%d", opts.DefaultHTTPHost, opts.DefaultTLSHTTPPort) |
|
110 |
+ scheme = "https" |
|
111 |
+ proto = "tcp" |
|
112 |
+ } else if d.useDefaultHost { |
|
113 |
+ addr = opts.DefaultUnixSocket |
|
114 |
+ proto = "unix" |
|
115 |
+ scheme = "http" |
|
116 |
+ transport = &http.Transport{} |
|
117 |
+ } else { |
|
118 |
+ addr = filepath.Join(d.folder, "docker.sock") |
|
119 |
+ proto = "unix" |
|
120 |
+ scheme = "http" |
|
121 |
+ transport = &http.Transport{} |
|
122 |
+ } |
|
123 |
+ |
|
124 |
+ sockets.ConfigureTCPTransport(transport, proto, addr) |
|
125 |
+ |
|
126 |
+ return &clientConfig{ |
|
127 |
+ transport: transport, |
|
128 |
+ scheme: scheme, |
|
129 |
+ addr: addr, |
|
130 |
+ }, nil |
|
131 |
+} |
|
132 |
+ |
|
89 | 133 |
// Start will start the daemon and return once it is ready to receive requests. |
90 | 134 |
// You can specify additional daemon flags. |
91 | 135 |
func (d *Daemon) Start(arg ...string) error { |
... | ... |
@@ -98,7 +151,7 @@ func (d *Daemon) Start(arg ...string) error { |
98 | 98 |
"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder), |
99 | 99 |
fmt.Sprintf("--userland-proxy=%t", d.userlandProxy), |
100 | 100 |
) |
101 |
- if !d.useDefaultHost { |
|
101 |
+ if !(d.useDefaultHost || d.useDefaultTLSHost) { |
|
102 | 102 |
args = append(args, []string{"--host", d.sock()}...) |
103 | 103 |
} |
104 | 104 |
if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" { |
... | ... |
@@ -160,25 +213,19 @@ func (d *Daemon) Start(arg ...string) error { |
160 | 160 |
case <-time.After(2 * time.Second): |
161 | 161 |
return fmt.Errorf("[%s] timeout: daemon does not respond", d.id) |
162 | 162 |
case <-tick: |
163 |
- var ( |
|
164 |
- c net.Conn |
|
165 |
- err error |
|
166 |
- ) |
|
167 |
- if d.useDefaultHost { |
|
168 |
- c, err = net.Dial("unix", "/var/run/docker.sock") |
|
169 |
- } else { |
|
170 |
- c, err = net.Dial("unix", filepath.Join(d.folder, "docker.sock")) |
|
171 |
- } |
|
163 |
+ clientConfig, err := d.getClientConfig() |
|
172 | 164 |
if err != nil { |
173 |
- continue |
|
165 |
+ return err |
|
174 | 166 |
} |
175 | 167 |
|
176 |
- client := httputil.NewClientConn(c, nil) |
|
177 |
- defer client.Close() |
|
168 |
+ client := &http.Client{ |
|
169 |
+ Transport: clientConfig.transport, |
|
170 |
+ } |
|
178 | 171 |
|
179 | 172 |
req, err := http.NewRequest("GET", "/_ping", nil) |
180 | 173 |
d.c.Assert(err, check.IsNil, check.Commentf("[%s] could not create new request", d.id)) |
181 |
- |
|
174 |
+ req.URL.Host = clientConfig.addr |
|
175 |
+ req.URL.Scheme = clientConfig.scheme |
|
182 | 176 |
resp, err := client.Do(req) |
183 | 177 |
if err != nil { |
184 | 178 |
continue |
... | ... |
@@ -289,34 +336,28 @@ func (d *Daemon) Restart(arg ...string) error { |
289 | 289 |
func (d *Daemon) queryRootDir() (string, error) { |
290 | 290 |
// update daemon root by asking /info endpoint (to support user |
291 | 291 |
// namespaced daemon with root remapped uid.gid directory) |
292 |
- var ( |
|
293 |
- conn net.Conn |
|
294 |
- err error |
|
295 |
- ) |
|
296 |
- if d.useDefaultHost { |
|
297 |
- conn, err = net.Dial("unix", "/var/run/docker.sock") |
|
298 |
- } else { |
|
299 |
- conn, err = net.Dial("unix", filepath.Join(d.folder, "docker.sock")) |
|
300 |
- } |
|
292 |
+ clientConfig, err := d.getClientConfig() |
|
301 | 293 |
if err != nil { |
302 | 294 |
return "", err |
303 | 295 |
} |
304 |
- client := httputil.NewClientConn(conn, nil) |
|
296 |
+ |
|
297 |
+ client := &http.Client{ |
|
298 |
+ Transport: clientConfig.transport, |
|
299 |
+ } |
|
305 | 300 |
|
306 | 301 |
req, err := http.NewRequest("GET", "/info", nil) |
307 | 302 |
if err != nil { |
308 |
- client.Close() |
|
309 | 303 |
return "", err |
310 | 304 |
} |
311 | 305 |
req.Header.Set("Content-Type", "application/json") |
306 |
+ req.URL.Host = clientConfig.addr |
|
307 |
+ req.URL.Scheme = clientConfig.scheme |
|
312 | 308 |
|
313 | 309 |
resp, err := client.Do(req) |
314 | 310 |
if err != nil { |
315 |
- client.Close() |
|
316 | 311 |
return "", err |
317 | 312 |
} |
318 | 313 |
body := ioutils.NewReadCloserWrapper(resp.Body, func() error { |
319 |
- defer client.Close() |
|
320 | 314 |
return resp.Body.Close() |
321 | 315 |
}) |
322 | 316 |
|
... | ... |
@@ -16,7 +16,7 @@ var ( |
16 | 16 |
alphaRegexp = regexp.MustCompile(`[a-zA-Z]`) |
17 | 17 |
domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`) |
18 | 18 |
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. docker daemon -H tcp://:8080 |
19 |
- DefaultHTTPHost = "127.0.0.1" |
|
19 |
+ DefaultHTTPHost = "localhost" |
|
20 | 20 |
|
21 | 21 |
// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp:// |
22 | 22 |
// TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter |
... | ... |
@@ -342,7 +342,7 @@ func ValidateLabel(val string) (string, error) { |
342 | 342 |
|
343 | 343 |
// ValidateHost validates that the specified string is a valid host and returns it. |
344 | 344 |
func ValidateHost(val string) (string, error) { |
345 |
- _, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val) |
|
345 |
+ _, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, "", val) |
|
346 | 346 |
if err != nil { |
347 | 347 |
return val, err |
348 | 348 |
} |
... | ... |
@@ -352,8 +352,8 @@ func ValidateHost(val string) (string, error) { |
352 | 352 |
} |
353 | 353 |
|
354 | 354 |
// ParseHost and set defaults for a Daemon host string |
355 |
-func ParseHost(val string) (string, error) { |
|
356 |
- host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val) |
|
355 |
+func ParseHost(defaultHost, val string) (string, error) { |
|
356 |
+ host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, defaultHost, val) |
|
357 | 357 |
if err != nil { |
358 | 358 |
return val, err |
359 | 359 |
} |
... | ... |
@@ -445,9 +445,9 @@ func TestParseHost(t *testing.T) { |
445 | 445 |
"fd://": "fd://", |
446 | 446 |
"fd://something": "fd://something", |
447 | 447 |
"tcp://host:": "tcp://host:2375", |
448 |
- "tcp://": "tcp://127.0.0.1:2375", |
|
449 |
- "tcp://:2375": "tcp://127.0.0.1:2375", // default ip address |
|
450 |
- "tcp://:2376": "tcp://127.0.0.1:2376", // default ip address |
|
448 |
+ "tcp://": "tcp://localhost:2375", |
|
449 |
+ "tcp://:2375": "tcp://localhost:2375", // default ip address |
|
450 |
+ "tcp://:2376": "tcp://localhost:2376", // default ip address |
|
451 | 451 |
"tcp://0.0.0.0:8080": "tcp://0.0.0.0:8080", |
452 | 452 |
"tcp://192.168.0.0:12000": "tcp://192.168.0.0:12000", |
453 | 453 |
"tcp://192.168:8080": "tcp://192.168:8080", |
... | ... |
@@ -458,12 +458,12 @@ func TestParseHost(t *testing.T) { |
458 | 458 |
} |
459 | 459 |
|
460 | 460 |
for value, errorMessage := range invalid { |
461 |
- if _, err := ParseHost(value); err == nil || err.Error() != errorMessage { |
|
461 |
+ if _, err := ParseHost(defaultHTTPHost, value); err == nil || err.Error() != errorMessage { |
|
462 | 462 |
t.Fatalf("Expected an error for %v with [%v], got [%v]", value, errorMessage, err) |
463 | 463 |
} |
464 | 464 |
} |
465 | 465 |
for value, expected := range valid { |
466 |
- if actual, err := ParseHost(value); err != nil || actual != expected { |
|
466 |
+ if actual, err := ParseHost(defaultHTTPHost, value); err != nil || actual != expected { |
|
467 | 467 |
t.Fatalf("Expected for %v [%v], got [%v, %v]", value, expected, actual, err) |
468 | 468 |
} |
469 | 469 |
} |
... | ... |
@@ -17,9 +17,12 @@ import ( |
17 | 17 |
// Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr |
18 | 18 |
// defaultUnixAddr must be a absolute file path (no `unix://` prefix) |
19 | 19 |
// defaultTCPAddr must be the full `tcp://host:port` form |
20 |
-func ParseDockerDaemonHost(defaultTCPAddr, defaultUnixAddr, addr string) (string, error) { |
|
20 |
+func ParseDockerDaemonHost(defaultTCPAddr, defaultTLSHost, defaultUnixAddr, defaultAddr, addr string) (string, error) { |
|
21 | 21 |
addr = strings.TrimSpace(addr) |
22 | 22 |
if addr == "" { |
23 |
+ if defaultAddr == defaultTLSHost { |
|
24 |
+ return defaultTLSHost, nil |
|
25 |
+ } |
|
23 | 26 |
if runtime.GOOS != "windows" { |
24 | 27 |
return fmt.Sprintf("unix://%s", defaultUnixAddr), nil |
25 | 28 |
} |
... | ... |
@@ -9,9 +9,10 @@ import ( |
9 | 9 |
|
10 | 10 |
func TestParseDockerDaemonHost(t *testing.T) { |
11 | 11 |
var ( |
12 |
- defaultHTTPHost = "tcp://127.0.0.1:2376" |
|
13 |
- defaultUnix = "/var/run/docker.sock" |
|
14 |
- defaultHOST = "unix:///var/run/docker.sock" |
|
12 |
+ defaultHTTPHost = "tcp://localhost:2375" |
|
13 |
+ defaultHTTPSHost = "tcp://localhost:2376" |
|
14 |
+ defaultUnix = "/var/run/docker.sock" |
|
15 |
+ defaultHOST = "unix:///var/run/docker.sock" |
|
15 | 16 |
) |
16 | 17 |
if runtime.GOOS == "windows" { |
17 | 18 |
defaultHOST = defaultHTTPHost |
... | ... |
@@ -28,37 +29,37 @@ func TestParseDockerDaemonHost(t *testing.T) { |
28 | 28 |
"fd": "Invalid bind address format: fd", |
29 | 29 |
} |
30 | 30 |
valids := map[string]string{ |
31 |
- "0.0.0.1:": "tcp://0.0.0.1:2376", |
|
31 |
+ "0.0.0.1:": "tcp://0.0.0.1:2375", |
|
32 | 32 |
"0.0.0.1:5555": "tcp://0.0.0.1:5555", |
33 | 33 |
"0.0.0.1:5555/path": "tcp://0.0.0.1:5555/path", |
34 |
- "[::1]:": "tcp://[::1]:2376", |
|
34 |
+ "[::1]:": "tcp://[::1]:2375", |
|
35 | 35 |
"[::1]:5555/path": "tcp://[::1]:5555/path", |
36 |
- "[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2376", |
|
36 |
+ "[0:0:0:0:0:0:0:1]:": "tcp://[0:0:0:0:0:0:0:1]:2375", |
|
37 | 37 |
"[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path", |
38 |
- ":6666": "tcp://127.0.0.1:6666", |
|
39 |
- ":6666/path": "tcp://127.0.0.1:6666/path", |
|
38 |
+ ":6666": "tcp://localhost:6666", |
|
39 |
+ ":6666/path": "tcp://localhost:6666/path", |
|
40 | 40 |
"": defaultHOST, |
41 | 41 |
" ": defaultHOST, |
42 | 42 |
" ": defaultHOST, |
43 | 43 |
"tcp://": defaultHTTPHost, |
44 |
- "tcp://:7777": "tcp://127.0.0.1:7777", |
|
45 |
- "tcp://:7777/path": "tcp://127.0.0.1:7777/path", |
|
46 |
- " tcp://:7777/path ": "tcp://127.0.0.1:7777/path", |
|
44 |
+ "tcp://:7777": "tcp://localhost:7777", |
|
45 |
+ "tcp://:7777/path": "tcp://localhost:7777/path", |
|
46 |
+ " tcp://:7777/path ": "tcp://localhost:7777/path", |
|
47 | 47 |
"unix:///run/docker.sock": "unix:///run/docker.sock", |
48 | 48 |
"unix://": "unix:///var/run/docker.sock", |
49 | 49 |
"fd://": "fd://", |
50 | 50 |
"fd://something": "fd://something", |
51 |
- "localhost:": "tcp://localhost:2376", |
|
51 |
+ "localhost:": "tcp://localhost:2375", |
|
52 | 52 |
"localhost:5555": "tcp://localhost:5555", |
53 | 53 |
"localhost:5555/path": "tcp://localhost:5555/path", |
54 | 54 |
} |
55 | 55 |
for invalidAddr, expectedError := range invalids { |
56 |
- if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultUnix, invalidAddr); err == nil || err.Error() != expectedError { |
|
56 |
+ if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", invalidAddr); err == nil || err.Error() != expectedError { |
|
57 | 57 |
t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr) |
58 | 58 |
} |
59 | 59 |
} |
60 | 60 |
for validAddr, expectedAddr := range valids { |
61 |
- if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultUnix, validAddr); err != nil || addr != expectedAddr { |
|
61 |
+ if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", validAddr); err != nil || addr != expectedAddr { |
|
62 | 62 |
t.Errorf("%v -> expected %v, got (%v) addr (%v)", validAddr, expectedAddr, err, addr) |
63 | 63 |
} |
64 | 64 |
} |