Skip to content

Commit 913478b

Browse files
committed
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 <[email protected]>
1 parent 901b905 commit 913478b

2 files changed

Lines changed: 20 additions & 11 deletions

File tree

client/errors.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ import (
1111

1212
// errConnectionFailed implements an error returned when connection failed.
1313
type errConnectionFailed struct {
14-
host string
14+
error
1515
}
1616

1717
// Error returns a string representation of an errConnectionFailed
18-
func (err errConnectionFailed) Error() string {
19-
if err.host == "" {
20-
return "Cannot connect to the Docker daemon. Is the docker daemon running on this host?"
21-
}
22-
return fmt.Sprintf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", err.host)
18+
func (e errConnectionFailed) Error() string {
19+
return e.error.Error()
20+
}
21+
22+
func (e errConnectionFailed) Unwrap() error {
23+
return e.error
2324
}
2425

2526
// IsErrConnectionFailed returns true if the error is caused by connection failed.
@@ -29,7 +30,13 @@ func IsErrConnectionFailed(err error) bool {
2930

3031
// ErrorConnectionFailed returns an error with host in the error message when connection to docker daemon failed.
3132
func ErrorConnectionFailed(host string) error {
32-
return errConnectionFailed{host: host}
33+
var err error
34+
if host == "" {
35+
err = fmt.Errorf("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
36+
} else {
37+
err = fmt.Errorf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", host)
38+
}
39+
return errConnectionFailed{error: err}
3340
}
3441

3542
// IsErrNotFound returns true if the error is a NotFound error, which is returned

client/request.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,18 @@ func (cli *Client) sendRequest(ctx context.Context, method, path string, query u
134134
return resp, errdefs.FromStatusCode(err, resp.statusCode)
135135
}
136136

137+
// FIXME(thaJeztah): Should this actually return a serverResp when a connection error occurred?
137138
func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
138139
serverResp := serverResponse{statusCode: -1, reqURL: req.URL}
139140

140141
resp, err := cli.client.Do(req)
141142
if err != nil {
142143
if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
143-
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
144+
return serverResp, errConnectionFailed{fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)}
144145
}
145146

146147
if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
147-
return serverResp, errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")
148+
return serverResp, errConnectionFailed{errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")}
148149
}
149150

150151
// Don't decorate context sentinel errors; users may be comparing to
@@ -156,12 +157,13 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
156157
if uErr, ok := err.(*url.Error); ok {
157158
if nErr, ok := uErr.Err.(*net.OpError); ok {
158159
if os.IsPermission(nErr.Err) {
159-
return serverResp, errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)
160+
return serverResp, errConnectionFailed{errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)}
160161
}
161162
}
162163
}
163164

164165
if nErr, ok := err.(net.Error); ok {
166+
// FIXME(thaJeztah): any net.Error should be considered a connection error (but we should include the original error)?
165167
if nErr.Timeout() {
166168
return serverResp, ErrorConnectionFailed(cli.host)
167169
}
@@ -190,7 +192,7 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
190192
}
191193
}
192194

193-
return serverResp, errors.Wrap(err, "error during connect")
195+
return serverResp, errConnectionFailed{errors.Wrap(err, "error during connect")}
194196
}
195197

196198
if resp != nil {

0 commit comments

Comments
 (0)