Selaa lähdekoodia

client: doRequest: make sure we return a connection-error

This function has various errors that are returned when failing to make a
connection (due to permission issues, TLS mis-configuration, or failing to
resolve the TCP address).

The errConnectionFailed error is currently used as a special case when
processing Ping responses. The current code did not consistently treat
connection errors, and because of that could either absorb the error,
or process the empty response.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 1 vuosi sitten
vanhempi
commit
913478b428
2 muutettua tiedostoa jossa 20 lisäystä ja 11 poistoa
  1. 14 7
      client/errors.go
  2. 6 4
      client/request.go

+ 14 - 7
client/errors.go

@@ -11,15 +11,16 @@ import (
 
 // errConnectionFailed implements an error returned when connection failed.
 type errConnectionFailed struct {
-	host string
+	error
 }
 
 // Error returns a string representation of an errConnectionFailed
-func (err errConnectionFailed) Error() string {
-	if err.host == "" {
-		return "Cannot connect to the Docker daemon. Is the docker daemon running on this host?"
-	}
-	return fmt.Sprintf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", err.host)
+func (e errConnectionFailed) Error() string {
+	return e.error.Error()
+}
+
+func (e errConnectionFailed) Unwrap() error {
+	return e.error
 }
 
 // IsErrConnectionFailed returns true if the error is caused by connection failed.
@@ -29,7 +30,13 @@ func IsErrConnectionFailed(err error) bool {
 
 // ErrorConnectionFailed returns an error with host in the error message when connection to docker daemon failed.
 func ErrorConnectionFailed(host string) error {
-	return errConnectionFailed{host: host}
+	var err error
+	if host == "" {
+		err = fmt.Errorf("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
+	} else {
+		err = fmt.Errorf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", host)
+	}
+	return errConnectionFailed{error: err}
 }
 
 // IsErrNotFound returns true if the error is a NotFound error, which is returned

+ 6 - 4
client/request.go

@@ -134,17 +134,18 @@ func (cli *Client) sendRequest(ctx context.Context, method, path string, query u
 	return resp, errdefs.FromStatusCode(err, resp.statusCode)
 }
 
+// FIXME(thaJeztah): Should this actually return a serverResp when a connection error occurred?
 func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
 	serverResp := serverResponse{statusCode: -1, reqURL: req.URL}
 
 	resp, err := cli.client.Do(req)
 	if err != nil {
 		if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
-			return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
+			return serverResp, errConnectionFailed{fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)}
 		}
 
 		if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
-			return serverResp, errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")
+			return serverResp, errConnectionFailed{errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")}
 		}
 
 		// Don't decorate context sentinel errors; users may be comparing to
@@ -156,12 +157,13 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
 		if uErr, ok := err.(*url.Error); ok {
 			if nErr, ok := uErr.Err.(*net.OpError); ok {
 				if os.IsPermission(nErr.Err) {
-					return serverResp, errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)
+					return serverResp, errConnectionFailed{errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)}
 				}
 			}
 		}
 
 		if nErr, ok := err.(net.Error); ok {
+			// FIXME(thaJeztah): any net.Error should be considered a connection error (but we should include the original error)?
 			if nErr.Timeout() {
 				return serverResp, ErrorConnectionFailed(cli.host)
 			}
@@ -190,7 +192,7 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
 			}
 		}
 
-		return serverResp, errors.Wrap(err, "error during connect")
+		return serverResp, errConnectionFailed{errors.Wrap(err, "error during connect")}
 	}
 
 	if resp != nil {