Browse Source

Merge pull request #16940 from coolljt0725/default_tls_host

Make default tls host work
Tibor Vass 9 years ago
parent
commit
6a7c38a57d

+ 6 - 1
api/client/cli.go

@@ -112,8 +112,13 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF
 			return errors.New("Please specify only one -H")
 		}
 
+		defaultHost := opts.DefaultTCPHost
+		if clientFlags.Common.TLSOptions != nil {
+			defaultHost = opts.DefaultTLSHost
+		}
+
 		var e error
-		if hosts[0], e = opts.ParseHost(hosts[0]); e != nil {
+		if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil {
 			return e
 		}
 

+ 3 - 1
docker/daemon.go

@@ -210,6 +210,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
 	}
 	serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
 
+	defaultHost := opts.DefaultHost
 	if commonFlags.TLSOptions != nil {
 		if !commonFlags.TLSOptions.InsecureSkipVerify {
 			// server requires and verifies client's certificate
@@ -220,6 +221,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
 			logrus.Fatal(err)
 		}
 		serverConfig.TLSConfig = tlsConfig
+		defaultHost = opts.DefaultTLSHost
 	}
 
 	if len(commonFlags.Hosts) == 0 {
@@ -227,7 +229,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
 	}
 	for i := 0; i < len(commonFlags.Hosts); i++ {
 		var err error
-		if commonFlags.Hosts[i], err = opts.ParseHost(commonFlags.Hosts[i]); err != nil {
+		if commonFlags.Hosts[i], err = opts.ParseHost(defaultHost, commonFlags.Hosts[i]); err != nil {
 			logrus.Fatalf("error parsing -H %s : %v", commonFlags.Hosts[i], err)
 		}
 	}

+ 34 - 0
integration-cli/docker_cli_daemon_test.go

@@ -1750,3 +1750,37 @@ func (s *DockerDaemonSuite) TestDaemonStartWithoutHost(c *check.C) {
 	}()
 	c.Assert(s.d.Start(), check.IsNil)
 }
+
+func (s *DockerDaemonSuite) TestDaemonStartWithDefalutTlsHost(c *check.C) {
+	s.d.useDefaultTLSHost = true
+	defer func() {
+		s.d.useDefaultTLSHost = false
+	}()
+	if err := s.d.Start(
+		"--tlsverify",
+		"--tlscacert", "fixtures/https/ca.pem",
+		"--tlscert", "fixtures/https/server-cert.pem",
+		"--tlskey", "fixtures/https/server-key.pem"); err != nil {
+		c.Fatalf("Could not start daemon: %v", err)
+	}
+
+	// The client with --tlsverify should also use default host localhost:2376
+	tmpHost := os.Getenv("DOCKER_HOST")
+	defer func() {
+		os.Setenv("DOCKER_HOST", tmpHost)
+	}()
+
+	os.Setenv("DOCKER_HOST", "")
+
+	out, _ := dockerCmd(
+		c,
+		"--tlsverify",
+		"--tlscacert", "fixtures/https/ca.pem",
+		"--tlscert", "fixtures/https/client-cert.pem",
+		"--tlskey", "fixtures/https/client-key.pem",
+		"version",
+	)
+	if !strings.Contains(out, "Server") {
+		c.Fatalf("docker version should return information of server side")
+	}
+}

+ 81 - 40
integration-cli/docker_utils.go

@@ -26,7 +26,9 @@ import (
 	"github.com/docker/docker/pkg/httputils"
 	"github.com/docker/docker/pkg/integration"
 	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/docker/pkg/sockets"
 	"github.com/docker/docker/pkg/stringutils"
+	"github.com/docker/docker/pkg/tlsconfig"
 	"github.com/go-check/check"
 )
 
@@ -37,19 +39,26 @@ type Daemon struct {
 	Command     string
 	GlobalFlags []string
 
-	id             string
-	c              *check.C
-	logFile        *os.File
-	folder         string
-	root           string
-	stdin          io.WriteCloser
-	stdout, stderr io.ReadCloser
-	cmd            *exec.Cmd
-	storageDriver  string
-	execDriver     string
-	wait           chan error
-	userlandProxy  bool
-	useDefaultHost bool
+	id                string
+	c                 *check.C
+	logFile           *os.File
+	folder            string
+	root              string
+	stdin             io.WriteCloser
+	stdout, stderr    io.ReadCloser
+	cmd               *exec.Cmd
+	storageDriver     string
+	execDriver        string
+	wait              chan error
+	userlandProxy     bool
+	useDefaultHost    bool
+	useDefaultTLSHost bool
+}
+
+type clientConfig struct {
+	transport *http.Transport
+	scheme    string
+	addr      string
 }
 
 // NewDaemon returns a Daemon instance to be used for testing.
@@ -86,6 +95,50 @@ func NewDaemon(c *check.C) *Daemon {
 	}
 }
 
+func (d *Daemon) getClientConfig() (*clientConfig, error) {
+	var (
+		transport *http.Transport
+		scheme    string
+		addr      string
+		proto     string
+	)
+	if d.useDefaultTLSHost {
+		option := &tlsconfig.Options{
+			CAFile:   "fixtures/https/ca.pem",
+			CertFile: "fixtures/https/client-cert.pem",
+			KeyFile:  "fixtures/https/client-key.pem",
+		}
+		tlsConfig, err := tlsconfig.Client(*option)
+		if err != nil {
+			return nil, err
+		}
+		transport = &http.Transport{
+			TLSClientConfig: tlsConfig,
+		}
+		addr = fmt.Sprintf("%s:%d", opts.DefaultHTTPHost, opts.DefaultTLSHTTPPort)
+		scheme = "https"
+		proto = "tcp"
+	} else if d.useDefaultHost {
+		addr = opts.DefaultUnixSocket
+		proto = "unix"
+		scheme = "http"
+		transport = &http.Transport{}
+	} else {
+		addr = filepath.Join(d.folder, "docker.sock")
+		proto = "unix"
+		scheme = "http"
+		transport = &http.Transport{}
+	}
+
+	sockets.ConfigureTCPTransport(transport, proto, addr)
+
+	return &clientConfig{
+		transport: transport,
+		scheme:    scheme,
+		addr:      addr,
+	}, nil
+}
+
 // Start will start the daemon and return once it is ready to receive requests.
 // You can specify additional daemon flags.
 func (d *Daemon) Start(arg ...string) error {
@@ -98,7 +151,7 @@ func (d *Daemon) Start(arg ...string) error {
 		"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder),
 		fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
 	)
-	if !d.useDefaultHost {
+	if !(d.useDefaultHost || d.useDefaultTLSHost) {
 		args = append(args, []string{"--host", d.sock()}...)
 	}
 	if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" {
@@ -160,25 +213,19 @@ func (d *Daemon) Start(arg ...string) error {
 		case <-time.After(2 * time.Second):
 			return fmt.Errorf("[%s] timeout: daemon does not respond", d.id)
 		case <-tick:
-			var (
-				c   net.Conn
-				err error
-			)
-			if d.useDefaultHost {
-				c, err = net.Dial("unix", "/var/run/docker.sock")
-			} else {
-				c, err = net.Dial("unix", filepath.Join(d.folder, "docker.sock"))
-			}
+			clientConfig, err := d.getClientConfig()
 			if err != nil {
-				continue
+				return err
 			}
 
-			client := httputil.NewClientConn(c, nil)
-			defer client.Close()
+			client := &http.Client{
+				Transport: clientConfig.transport,
+			}
 
 			req, err := http.NewRequest("GET", "/_ping", nil)
 			d.c.Assert(err, check.IsNil, check.Commentf("[%s] could not create new request", d.id))
-
+			req.URL.Host = clientConfig.addr
+			req.URL.Scheme = clientConfig.scheme
 			resp, err := client.Do(req)
 			if err != nil {
 				continue
@@ -289,34 +336,28 @@ func (d *Daemon) Restart(arg ...string) error {
 func (d *Daemon) queryRootDir() (string, error) {
 	// update daemon root by asking /info endpoint (to support user
 	// namespaced daemon with root remapped uid.gid directory)
-	var (
-		conn net.Conn
-		err  error
-	)
-	if d.useDefaultHost {
-		conn, err = net.Dial("unix", "/var/run/docker.sock")
-	} else {
-		conn, err = net.Dial("unix", filepath.Join(d.folder, "docker.sock"))
-	}
+	clientConfig, err := d.getClientConfig()
 	if err != nil {
 		return "", err
 	}
-	client := httputil.NewClientConn(conn, nil)
+
+	client := &http.Client{
+		Transport: clientConfig.transport,
+	}
 
 	req, err := http.NewRequest("GET", "/info", nil)
 	if err != nil {
-		client.Close()
 		return "", err
 	}
 	req.Header.Set("Content-Type", "application/json")
+	req.URL.Host = clientConfig.addr
+	req.URL.Scheme = clientConfig.scheme
 
 	resp, err := client.Do(req)
 	if err != nil {
-		client.Close()
 		return "", err
 	}
 	body := ioutils.NewReadCloserWrapper(resp.Body, func() error {
-		defer client.Close()
 		return resp.Body.Close()
 	})
 

+ 4 - 4
opts/opts.go

@@ -16,7 +16,7 @@ var (
 	alphaRegexp  = regexp.MustCompile(`[a-zA-Z]`)
 	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*$`)
 	// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. docker daemon -H tcp://:8080
-	DefaultHTTPHost = "127.0.0.1"
+	DefaultHTTPHost = "localhost"
 
 	// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp://
 	// TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter
@@ -342,7 +342,7 @@ func ValidateLabel(val string) (string, error) {
 
 // ValidateHost validates that the specified string is a valid host and returns it.
 func ValidateHost(val string) (string, error) {
-	_, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val)
+	_, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, "", val)
 	if err != nil {
 		return val, err
 	}
@@ -352,8 +352,8 @@ func ValidateHost(val string) (string, error) {
 }
 
 // ParseHost and set defaults for a Daemon host string
-func ParseHost(val string) (string, error) {
-	host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val)
+func ParseHost(defaultHost, val string) (string, error) {
+	host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, defaultHost, val)
 	if err != nil {
 		return val, err
 	}

+ 5 - 5
opts/opts_test.go

@@ -445,9 +445,9 @@ func TestParseHost(t *testing.T) {
 		"fd://":                    "fd://",
 		"fd://something":           "fd://something",
 		"tcp://host:":              "tcp://host:2375",
-		"tcp://":                   "tcp://127.0.0.1:2375",
-		"tcp://:2375":              "tcp://127.0.0.1:2375", // default ip address
-		"tcp://:2376":              "tcp://127.0.0.1:2376", // default ip address
+		"tcp://":                   "tcp://localhost:2375",
+		"tcp://:2375":              "tcp://localhost:2375", // default ip address
+		"tcp://:2376":              "tcp://localhost:2376", // default ip address
 		"tcp://0.0.0.0:8080":       "tcp://0.0.0.0:8080",
 		"tcp://192.168.0.0:12000":  "tcp://192.168.0.0:12000",
 		"tcp://192.168:8080":       "tcp://192.168:8080",
@@ -458,12 +458,12 @@ func TestParseHost(t *testing.T) {
 	}
 
 	for value, errorMessage := range invalid {
-		if _, err := ParseHost(value); err == nil || err.Error() != errorMessage {
+		if _, err := ParseHost(defaultHTTPHost, value); err == nil || err.Error() != errorMessage {
 			t.Fatalf("Expected an error for %v with [%v], got [%v]", value, errorMessage, err)
 		}
 	}
 	for value, expected := range valid {
-		if actual, err := ParseHost(value); err != nil || actual != expected {
+		if actual, err := ParseHost(defaultHTTPHost, value); err != nil || actual != expected {
 			t.Fatalf("Expected for %v [%v], got [%v, %v]", value, expected, actual, err)
 		}
 	}

+ 4 - 1
pkg/parsers/parsers.go

@@ -17,9 +17,12 @@ import (
 // Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr
 // defaultUnixAddr must be a absolute file path (no `unix://` prefix)
 // defaultTCPAddr must be the full `tcp://host:port` form
-func ParseDockerDaemonHost(defaultTCPAddr, defaultUnixAddr, addr string) (string, error) {
+func ParseDockerDaemonHost(defaultTCPAddr, defaultTLSHost, defaultUnixAddr, defaultAddr, addr string) (string, error) {
 	addr = strings.TrimSpace(addr)
 	if addr == "" {
+		if defaultAddr == defaultTLSHost {
+			return defaultTLSHost, nil
+		}
 		if runtime.GOOS != "windows" {
 			return fmt.Sprintf("unix://%s", defaultUnixAddr), nil
 		}

+ 15 - 14
pkg/parsers/parsers_test.go

@@ -9,9 +9,10 @@ import (
 
 func TestParseDockerDaemonHost(t *testing.T) {
 	var (
-		defaultHTTPHost = "tcp://127.0.0.1:2376"
-		defaultUnix     = "/var/run/docker.sock"
-		defaultHOST     = "unix:///var/run/docker.sock"
+		defaultHTTPHost  = "tcp://localhost:2375"
+		defaultHTTPSHost = "tcp://localhost:2376"
+		defaultUnix      = "/var/run/docker.sock"
+		defaultHOST      = "unix:///var/run/docker.sock"
 	)
 	if runtime.GOOS == "windows" {
 		defaultHOST = defaultHTTPHost
@@ -28,37 +29,37 @@ func TestParseDockerDaemonHost(t *testing.T) {
 		"fd":   "Invalid bind address format: fd",
 	}
 	valids := map[string]string{
-		"0.0.0.1:":                    "tcp://0.0.0.1:2376",
+		"0.0.0.1:":                    "tcp://0.0.0.1:2375",
 		"0.0.0.1:5555":                "tcp://0.0.0.1:5555",
 		"0.0.0.1:5555/path":           "tcp://0.0.0.1:5555/path",
-		"[::1]:":                      "tcp://[::1]:2376",
+		"[::1]:":                      "tcp://[::1]:2375",
 		"[::1]:5555/path":             "tcp://[::1]:5555/path",
-		"[0:0:0:0:0:0:0:1]:":          "tcp://[0:0:0:0:0:0:0:1]:2376",
+		"[0:0:0:0:0:0:0:1]:":          "tcp://[0:0:0:0:0:0:0:1]:2375",
 		"[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path",
-		":6666":                   "tcp://127.0.0.1:6666",
-		":6666/path":              "tcp://127.0.0.1:6666/path",
+		":6666":                   "tcp://localhost:6666",
+		":6666/path":              "tcp://localhost:6666/path",
 		"":                        defaultHOST,
 		" ":                       defaultHOST,
 		"  ":                      defaultHOST,
 		"tcp://":                  defaultHTTPHost,
-		"tcp://:7777":             "tcp://127.0.0.1:7777",
-		"tcp://:7777/path":        "tcp://127.0.0.1:7777/path",
-		" tcp://:7777/path ":      "tcp://127.0.0.1:7777/path",
+		"tcp://:7777":             "tcp://localhost:7777",
+		"tcp://:7777/path":        "tcp://localhost:7777/path",
+		" tcp://:7777/path ":      "tcp://localhost:7777/path",
 		"unix:///run/docker.sock": "unix:///run/docker.sock",
 		"unix://":                 "unix:///var/run/docker.sock",
 		"fd://":                   "fd://",
 		"fd://something":          "fd://something",
-		"localhost:":              "tcp://localhost:2376",
+		"localhost:":              "tcp://localhost:2375",
 		"localhost:5555":          "tcp://localhost:5555",
 		"localhost:5555/path":     "tcp://localhost:5555/path",
 	}
 	for invalidAddr, expectedError := range invalids {
-		if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultUnix, invalidAddr); err == nil || err.Error() != expectedError {
+		if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", invalidAddr); err == nil || err.Error() != expectedError {
 			t.Errorf("tcp %v address expected error %v return, got %s and addr %v", invalidAddr, expectedError, err, addr)
 		}
 	}
 	for validAddr, expectedAddr := range valids {
-		if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultUnix, validAddr); err != nil || addr != expectedAddr {
+		if addr, err := ParseDockerDaemonHost(defaultHTTPHost, defaultHTTPSHost, defaultUnix, "", validAddr); err != nil || addr != expectedAddr {
 			t.Errorf("%v -> expected %v, got (%v) addr (%v)", validAddr, expectedAddr, err, addr)
 		}
 	}