41 Commits

Author SHA1 Message Date
Sebastiaan van Stijn
04ab3d562c client: don't downgrade when failing to negotiate
Historically, the client would downgrade to API v1.24 when failing
to negotiate as this was the API version from before API-version
negotiation was introduced.

Given that those daemons are EOL and those API versions no longer
supported, we should not fall back to an older API version, and
just continue using the latest / current version.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-27 13:52:27 +01:00
Sebastiaan van Stijn
189942570a client: enable API-version negotiation by default
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-27 13:52:27 +01:00
Sebastiaan van Stijn
89bd3150e1 client: client.ping(): use fresh request for HEAD -> GET
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-27 12:05:25 +01:00
Sebastiaan van Stijn
4e2e2cde7e client: simplify logic for manual vs auto API versions
When manually setting the API version to use, automatic API version
negotiation should no longer be performed. Instead of keeping track
of these options individually, we can mark negotiation to have happend
if either the version was set manually, or if API version negotiation
took place.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-14 20:30:49 +01:00
Sebastiaan van Stijn
d9ee22d1ab Merge pull request #51530 from thaJeztah/allow_renegotiate
client: client.Ping: allow ForceNegotiate with manual override
2025-11-14 20:07:27 +01:00
Sebastiaan van Stijn
6857132911 client: client.Ping: allow ForceNegotiate with manual override
While a manual overridden version shouldn't perform automatic version
negotiation, the "ForceNegotiate" option could still be used to (re)
negotiate a version. This allows a client to be configured with an
initial API version, then triggered to perform API-version negotiation.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-14 17:41:56 +01:00
Sebastiaan van Stijn
53764de815 client: make WithAPIVersion, WithAPIVersionFromEnv order-independent
Environment-variables are expected to override config / defaults, so
make sure that the DOCKER_API_VERSION env-var always takes priority.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-14 13:54:32 +01:00
Sebastiaan van Stijn
83ad5c92f7 client: Client.ping() fix duplicate ping
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-14 13:54:27 +01:00
Sebastiaan van Stijn
dae3650dcc client: rename/deprecate WithVersion, WithVersionFromEnv
Add WithAPIVersion and WithAPIVersionFromEnv to be more clear on
the intent, and to align with other related options and fields.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-11-12 22:39:05 +01:00
Sebastiaan van Stijn
edbf321ce6 client: remove NegotiateAPIVersion, NegotiateAPIVersionPing
Remove these methods in favor of adding negotiation options to the
Ping method.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-27 19:27:48 +01:00
Sebastiaan van Stijn
8dc5d1e64d api/types: move Ping and swarm.Status to client
The API does not produce these as a response; the fields in the Ping
struct, including the Swarm status are propagated from headers returned
by the /_ping endpoint.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-22 11:05:08 +02:00
Sebastiaan van Stijn
d69fde4c60 client: Client.Ping: improve error handling and fallback
The Ping function first tries to do a HEAD request, but the parsePingResponse
was written with the assumption that a Body could be present in the response
that may include errors returned by the API server.

HEAD responses don't include a body, so there's no response to handle, and
no errors to return by the API, other than a HTTP status code.

This patch:

- Rewrites `parsePingResponse` to a `newPingResponse`, removing the error-
  handling for the response-body. It's also simplified, because a non-nil
  response is guaranteed to have a non-nil Header (but it may not have
  any of the headers set that are used for the Ping).
- Rewrites the `Client.Ping` to only return a Ping-response from the HEAD
  request if no error was returned (i.e., we connected with the API) and
  a successful status-code, otherwise it will fallback to a GET request,
  which allows (for non "OK" (200) status-codes) returning errors from
  the daemon (for example, if the daemon is in an unhealthy state).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-08-12 23:58:40 +02:00
Sebastiaan van Stijn
80294ddb60 client: make checkResponseErr a regular function
It was implemented as a method on Client, but the receiver was not used;
make it a regular function to prevent passing around the Client where
not needed.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-08-12 21:49:24 +02:00
Derek McGowan
afd6487b2e Create github.com/moby/moby/api module
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-07-21 09:30:05 -07:00
Sebastiaan van Stijn
4856e8ffad client: remove // import comments
These comments were added to enforce using the correct import path for
our packages ("github.com/docker/docker", not "github.com/moby/moby").
However, when working in go module mode (not GOPATH / vendor), they have
no effect, so their impact is limited.

Remove these imports in preparation of migrating our code to become an
actual go module.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-30 15:59:10 +02:00
Sebastiaan van Stijn
3d1e4d9002 api/types: move build-related types to api/types/build
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 09:30:27 +02:00
Sebastiaan van Stijn
72c91e378d client: remove serverResponse and use http.Response directly
Looking in history to learn why this struct existed, shows that this type
was mostly the result of tech-debt accumulating over time;

- originally ([moby@1aa7f13]) most of the request handling was internal;
  the [`call()` function][1] would make a request, read the `response.Body`,
  and return it as a `[]byte` (or an error if one happened).
- some features needed the statuscode, so [moby@a4bcf7e] added an extra
  output variable to return the `response.StatusCode`.
- some new features required streaming, so [moby@fdd8d4b] changed the
  function to return the `response.Body` as a `io.ReadCloser`, instead
  of a `[]byte`.
- some features needed access to the content-type header, so a new
  `clientRequest` method was introduced in [moby@6b2eeaf] to read the
  `Content-Type` header from `response.Headers` and return it as a string.
- of course, `Content-Type` may not be the only header needed, so [moby@0cdc3b7]
  changed the signature to return `response.Headers` as a whole as a
  `http.Header`
- things became a bit unwieldy now, with the function having four (4) output
  variables, so [moby@126529c] chose to refactor this code, introducing a
  `serverResponse` struct to wrap them all, not realizing that all these
  values were effectively deconstructed from the `url.Response`, so now
  re-assembling them into our own "URL response", only preserving a subset
  of the information available.
- now that we had a custom struct, it was possible to add more information
  to it without changing the signature. When there was a need to know the
  URL of the request that initiated the response, [moby@27ef09a] introduced
  a `reqURL` field to hold the `request.URL` which notably also is available
  in `response.Request.URL`.

In short;

- The original implementation tried to (pre-maturely) abstract the underlying
  response to provide a simplified interface.
- While initially not needed, abstracting caused relevant information from
  the response (and request) to be unavailable to callers.
- As a result, we ended up in a situation where we are deconstructing the
  original `url.Response`, only to re-assemble it into our own, custom struct
  (`serverResponsee`) with only a subset of the information preserved.

This patch removes the `serverResponse` struct, instead returning the
`url.Response` as-is, so that all information is preserved, allowing callers
to use the information they need.

There is one follow-up change to consider; commit [moby@589df17] introduced
a `ensureReaderClosed` utility. Before that commit, the response body would
be closed in a more idiomatic way through a [`defer serverResp.body.Close()`][2].
A later change in [docker/engine-api@5dd6452] added an optimization to that
utility, draining the response to allow connections to be reused. While
skipping that utility (and not draining the response) would not be a critical
issue, it may be easy to overlook that utility, and to close the response
body in the "idiomatic" way, resulting in a possible performance regression.

We need to check if that optimization is still relevant or if later changes
in Go itself already take care of this; we should also look if context
cancellation is handled correctly for these. If it's still relevant, we could

- Wrap the the `url.Response` in a custom struct ("drainCloser") to provide
  a `Close()` function handling the draining and closing; this would re-
  introduce a custom type to be returned, so perhaps not what we want.
- Wrap the `url.Response.Body` in the response returned (so, calling)
  `response.Body.Close()` would call the wrapped closer.
- Change the signature of `Client.sendRequest()` (and related) to return
  a `close()` func to handle this; doing so would more strongly encourage
  callers to close the response body.

[1]: 1aa7f1392d/commands.go (L1008-L1027)
[2]: 589df17a1a/api/client/ps.go (L84-L89)
[moby@1aa7f13]: 1aa7f1392d
[moby@a4bcf7e]: a4bcf7e1ac
[moby@fdd8d4b]: fdd8d4b7d9
[moby@6b2eeaf]: 6b2eeaf896
[moby@0cdc3b7]: 0cdc3b7539
[moby@126529c]: 126529c6d0
[moby@27ef09a]: 27ef09a46f
[moby@589df17]: 589df17a1a
[docker/engine-api@5dd6452]: 5dd6452d4d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-11 13:20:27 +01:00
maggie44
76a5ca1d4d Accurately reflect the canonical casing of API-Version and OS-Type headers
Go automatically canonicalises HTTP headers, meaning the string `API-Version` passed as a header has always been returned as `Api-Version`. Similarly, `OSType` is returned as `Ostype`.

This commit updates the documentation to reflect this behaviour and modifies the codebase to ensure that input strings are aligned with their canonical output values.

Signed-off-by: maggie44 <64841595+maggie44@users.noreply.github.com>
2024-12-08 22:23:57 +00:00
Sebastiaan van Stijn
901b90593d client: NegotiateAPIVersion: do not ignore (connection) errors from Ping
NegotiateAPIVersion was ignoring errors returned by Ping. The intent here
was to handle API responses from a daemon that may be in an unhealthy state,
however this case is already handled by Ping itself.

Ping only returns an error when either failing to connect to the API (daemon
not running or permissions errors), or when failing to parse the API response.

Neither of those should be ignored in this code, or considered a successful
"ping", so update the code to return

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-23 14:31:55 +01:00
Sebastiaan van Stijn
4cc796ab93 client: Client.buildRequest: use http.NewRequestWithContext
Attach the context to the request while we're creating it, instead of
creating the context first, and adding the context later.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-08-09 20:30:25 +02:00
Sebastiaan van Stijn
58dc0fcd1e client: Client.Ping: re-use request when falling back to GET
Re-use the request, and change the method to GET instead of building
a new request "from scratch".

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-08-09 20:30:25 +02:00
Sebastiaan van Stijn
19cd5ff164 client: use strings.Cut()
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-12-21 11:09:01 +01:00
Sebastiaan van Stijn
1e645fb70f client: Ping(): add handling for swarm status headers
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-03-25 23:57:58 +01:00
Daniel Helfand
4d249ae1f3 remove extra space in code comment in ping.go
Signed-off-by: Daniel Helfand <helfand.4@gmail.com>
2020-01-20 00:04:53 -05:00
Sebastiaan van Stijn
dabc7cdb56 client: use constants for http methods
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-10-13 17:30:21 +02:00
Ian Campbell
8c8457b0f2 client: do not fallback to GET if HEAD on _ping fail to connect
When we see an `ECONNREFUSED` (or equivalent) from an attempted `HEAD` on the
`/_ping` endpoint there is no point in trying again with `GET` since the server
is not responding/available at all.

Once vendored into the cli this will partially mitigate https://github.com/docker/cli/issues/1739
("Docker commands take 1 minute to timeout if context endpoint is unreachable")
by cutting the effective timeout in half.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-05-13 13:48:17 +01:00
Sebastiaan van Stijn
9c846b2fcc Client: always call ensureReaderClosed
Unlike a plain `net/http/client.Do()`, requests made through client/request
use the `sendRequest` function, which parses the server response, and may
convert non-transport errors into errors (through `cli.checkResponseErr()`).

This means that we cannot assume that no reader was opened if an error is
returned.

This patch changes various locations where `ensureReaderClosed` was only
called in the non-error situation, and uses a `defer` to make sure it's
always called.

`ensureReaderClosed` itself already checks if the response's body was set,
so in situations where the error was due to a transport error, calling
`ensureReaderClosed` should be a no-op.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-03-18 15:26:21 +01:00
Sebastiaan van Stijn
2a9c987e5a Move httputils error helpers to errdefs package
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-03-16 00:42:23 +01:00
Sebastiaan van Stijn
38e6d474af client: return rich / errdefs errors
this patch makes the client return errors matching
the errdefs interface.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-03-16 00:40:39 +01:00
Sebastiaan van Stijn
7e7e100be0 Add HEAD support for /_ping endpoint
Monitoring systems and load balancers are usually configured to use HEAD
requests for health monitoring. The /_ping endpoint currently does not
support this type of request, which means that those systems have fallback
to GET requests.

This patch adds support for HEAD requests on the /_ping endpoint.

Although optional, this patch also returns `Content-Type` and `Content-Length`
headers in case of a HEAD request; Refering to RFC 7231, section 4.3.2:

    The HEAD method is identical to GET except that the server MUST NOT
    send a message body in the response (i.e., the response terminates at
    the end of the header section).  The server SHOULD send the same
    header fields in response to a HEAD request as it would have sent if
    the request had been a GET, except that the payload header fields
    (Section 3.3) MAY be omitted.  This method can be used for obtaining
    metadata about the selected representation without transferring the
    representation data and is often used for testing hypertext links for
    validity, accessibility, and recent modification.

    A payload within a HEAD request message has no defined semantics;
    sending a payload body on a HEAD request might cause some existing
    implementations to reject the request.

    The response to a HEAD request is cacheable; a cache MAY use it to
    satisfy subsequent HEAD requests unless otherwise indicated by the
    Cache-Control header field (Section 5.2 of [RFC7234]).  A HEAD
    response might also have an effect on previously cached responses to
    GET; see Section 4.3.5 of [RFC7234].

With this patch applied, either `GET` or `HEAD` requests work; the only
difference is that the body is empty in case of a `HEAD` request;

    curl -i --unix-socket /var/run/docker.sock http://localhost/_ping
    HTTP/1.1 200 OK
    Api-Version: 1.40
    Cache-Control: no-cache, no-store, must-revalidate
    Docker-Experimental: false
    Ostype: linux
    Pragma: no-cache
    Server: Docker/dev (linux)
    Date: Mon, 14 Jan 2019 12:35:16 GMT
    Content-Length: 2
    Content-Type: text/plain; charset=utf-8

    OK

    curl --head -i --unix-socket /var/run/docker.sock http://localhost/_ping
    HTTP/1.1 200 OK
    Api-Version: 1.40
    Cache-Control: no-cache, no-store, must-revalidate
    Content-Length: 0
    Content-Type: text/plain; charset=utf-8
    Docker-Experimental: false
    Ostype: linux
    Pragma: no-cache
    Server: Docker/dev (linux)
    Date: Mon, 14 Jan 2019 12:34:15 GMT

The client is also updated to use `HEAD` by default, but fallback to `GET`
if the daemon does not support this method.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-01-31 18:18:24 +01:00
Anda Xu
2be17666b4 add optional fields in daemon.json to enable buildkit
Signed-off-by: Anda Xu <anda.xu@docker.com>
2018-08-19 14:58:23 -07:00
Kir Kolyshkin
7d62e40f7e Switch from x/net/context -> context
Since Go 1.7, context is a standard package. Since Go 1.9, everything
that is provided by "x/net/context" is a couple of type aliases to
types in "context".

Many vendored packages still use x/net/context, so vendor entry remains
for now.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2018-04-23 13:52:44 -07:00
Daniel Nephin
4f0d95fa6e Add canonical import comment
Signed-off-by: Daniel Nephin <dnephin@docker.com>
2018-02-05 16:51:57 -05:00
Daniel Nephin
81bb9978ab Cleanup client not found errors.
And fix remove calls to return a notFound error

Signed-off-by: Daniel Nephin <dnephin@docker.com>
2017-09-11 19:53:18 -04:00
Tonis Tiigi
823e88d4c4 Fix requests for docker host ending with slash
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2017-08-11 10:47:02 -07:00
Brian Goff
27ef09a46f Set ping version even on error
In some cases a server may return an error on the ping response but
still provide version details. The client should use these values when
available.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2017-06-29 12:42:14 -04:00
Aaron Lehmann
44c9ccc069 client: Use string concatenation instead of Sprintf
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2017-06-02 14:01:57 +02:00
Boaz Shuster
7199522ea2 Hide command options that are related to Windows
Signed-off-by: Boaz Shuster <ripcurld.github@gmail.com>
2017-03-12 08:47:17 +02:00
allencloud
7c3657065c change minor mistake of spelling
Signed-off-by: allencloud <allen.sun@daocloud.io>
2016-12-20 21:05:19 +08:00
Victor Vieux
e98e4a7111 always add but hide experimental cmds and flags
Signed-off-by: Victor Vieux <vieux@docker.com>

update cobra and use Tags

Signed-off-by: Victor Vieux <vieux@docker.com>

allow client to talk to an older server

Signed-off-by: Victor Vieux <vieux@docker.com>
2016-11-08 04:55:27 -08:00
Kenfe-Mickael Laventure
7781a1bf0f Make experimental a runtime flag
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
2016-10-24 15:20:01 -07:00