github.com/moby/docker@v26.1.3+incompatible/client/ping.go (about) 1 package client // import "github.com/docker/docker/client" 2 3 import ( 4 "context" 5 "net/http" 6 "path" 7 "strings" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/swarm" 11 "github.com/docker/docker/errdefs" 12 ) 13 14 // Ping pings the server and returns the value of the "Docker-Experimental", 15 // "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use 16 // a HEAD request on the endpoint, but falls back to GET if HEAD is not supported 17 // by the daemon. It ignores internal server errors returned by the API, which 18 // may be returned if the daemon is in an unhealthy state, but returns errors 19 // for other non-success status codes, failing to connect to the API, or failing 20 // to parse the API response. 21 func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { 22 var ping types.Ping 23 24 // Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest() 25 // because ping requests are used during API version negotiation, so we want 26 // to hit the non-versioned /_ping endpoint, not /v1.xx/_ping 27 req, err := cli.buildRequest(ctx, http.MethodHead, path.Join(cli.basePath, "/_ping"), nil, nil) 28 if err != nil { 29 return ping, err 30 } 31 serverResp, err := cli.doRequest(req) 32 if err == nil { 33 defer ensureReaderClosed(serverResp) 34 switch serverResp.statusCode { 35 case http.StatusOK, http.StatusInternalServerError: 36 // Server handled the request, so parse the response 37 return parsePingResponse(cli, serverResp) 38 } 39 } else if IsErrConnectionFailed(err) { 40 return ping, err 41 } 42 43 // HEAD failed; fallback to GET. 44 req.Method = http.MethodGet 45 serverResp, err = cli.doRequest(req) 46 defer ensureReaderClosed(serverResp) 47 if err != nil { 48 return ping, err 49 } 50 return parsePingResponse(cli, serverResp) 51 } 52 53 func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) { 54 var ping types.Ping 55 if resp.header == nil { 56 err := cli.checkResponseErr(resp) 57 return ping, errdefs.FromStatusCode(err, resp.statusCode) 58 } 59 ping.APIVersion = resp.header.Get("API-Version") 60 ping.OSType = resp.header.Get("OSType") 61 if resp.header.Get("Docker-Experimental") == "true" { 62 ping.Experimental = true 63 } 64 if bv := resp.header.Get("Builder-Version"); bv != "" { 65 ping.BuilderVersion = types.BuilderVersion(bv) 66 } 67 if si := resp.header.Get("Swarm"); si != "" { 68 state, role, _ := strings.Cut(si, "/") 69 ping.SwarmStatus = &swarm.Status{ 70 NodeState: swarm.LocalNodeState(state), 71 ControlAvailable: role == "manager", 72 } 73 } 74 err := cli.checkResponseErr(resp) 75 return ping, errdefs.FromStatusCode(err, resp.statusCode) 76 }