22 Commits

Author SHA1 Message Date
Paweł Gronowski
1cc2ab16ce client/container_copy: Wrap options and result struct
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-10-29 14:34:19 +01:00
Sebastiaan van Stijn
4d20b6fe56 api/types/container: move container options to client
Move the option-types to the client and in some cases create a
copy for the backend. These types are used to construct query-
args, and not marshaled to JSON, and can be replaced with functional
options in the client.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-09-04 20:09:55 +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
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
Sebastiaan van Stijn
329b2a26f3 client: normalize and validate empty ID / name arguments to fail early
In situations where an empty ID was passed, the client would construct an
invalid API endpoint URL, which either resulted in the "not found" handler
being hit (resulting in a "page not found" error), or even the wrong endpoint
being hit if the client follows redirects.

For example, `/containers/<empty id>/json` (inspect) redirects to `/containers/json`
(docker ps))

Given that empty IDs should never be expected (especially if they're part of
the API URL path), we can validate these and return early.

Its worth noting that a few methods already had an error in place; those
methods were related to the situation mentioned above, where (e.g.) an
"inspect" would redirect to a "list" endpoint. The existing errors, for
convenience, mimicked a "not found" error; this patch changes such errors
to an "Invalid Parameter" instead, which is more correct, but it could be
a breaking change for some edge cases where users parsed the output;

    git grep 'objectNotFoundError{'
    client/config_inspect.go:        return swarm.Config{}, nil, objectNotFoundError{object: "config", id: id}
    client/container_inspect.go:     return container.InspectResponse{}, nil, objectNotFoundError{object: "container", id: containerID}
    client/container_inspect.go:     return container.InspectResponse{}, objectNotFoundError{object: "container", id: containerID}
    client/distribution_inspect.go:  return distributionInspect, objectNotFoundError{object: "distribution", id: imageRef}
    client/image_inspect.go:         return image.InspectResponse{}, nil, objectNotFoundError{object: "image", id: imageID}
    client/network_inspect.go:       return network.Inspect{}, nil, objectNotFoundError{object: "network", id: networkID}
    client/node_inspect.go:          return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID}
    client/plugin_inspect.go:        return nil, nil, objectNotFoundError{object: "plugin", id: name}
    client/secret_inspect.go:        return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id}
    client/service_inspect.go:       return swarm.Service{}, nil, objectNotFoundError{object: "service", id: serviceID}
    client/task_inspect.go:          return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID}
    client/volume_inspect.go:        return volume.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID}

Two such errors are still left, as "ID or name" would probably be confusing,
but perhaps we can use a more generic error to include those as well (e.g.
"invalid <object> reference: value is empty");

    client/distribution_inspect.go:  return distributionInspect, objectNotFoundError{object: "distribution", id: imageRef}
    client/image_inspect.go:         return image.InspectResponse{}, nil, objectNotFoundError{object: "image", id: imageID}

Before this patch:

    docker container start ""
    Error response from daemon: page not found
    Error: failed to start containers:

    docker container start " "
    Error response from daemon: No such container:
    Error: failed to start containers:

With this patch:

    docker container start ""
    invalid container name or ID: value is empty
    Error: failed to start containers:

    docker container start " "
    invalid container name or ID: value is empty
    Error: failed to start containers:

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-03 11:21:51 +01:00
Sebastiaan van Stijn
fd1d8f323b api/types: move CopyToContainerOptions to api/types/container
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-06-10 10:20:47 +02:00
Sebastiaan van Stijn
47d7c9e31d api/types: move ContainerPathStat to api/types/container
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-06-10 10:20:45 +02:00
Sebastiaan van Stijn
013d648888 client: CopyToContainer(), CopyFromContainer(): remove status-code handling
This was added in 93c3e6c91e, at which time only
some basic handling of non-succesful status codes was present;
93c3e6c91e/api/client/utils.go (L112-L121)

Given that since 38e6d474af non-successful status-
codes are already handled, and a 204 ("no content") status should not be an error,
this special case should no longer be needed.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-04-19 08:28:20 +02:00
Sebastiaan van Stijn
45067cda33 client: remove wrapResponseError()
The wrapResponseError() utility converted some specific errors, but in
doing so, could hide the actual error message returned by the daemon.
In addition, starting with 38e6d474af,
HTTP status codes were already mapped to their corresponding errdefs
types on the client-side, making this conversion redundant.

This patch removes the wrapResponseError() utility; it's worth noting
that some error-messages will change slightly (as they now return the
error as returned by the daemon), but may cointain more details as
before, and in some cases prevents hiding the actual error.

Before this change:

    docker container rm nosuchcontainer
    Error: No such container: nosuchcontainer

    docker container cp mycontainer:/no/such/path .
    Error: No such container:path: mycontainer:/no/such/path

    docker container cp ./Dockerfile mycontainer:/no/such/path
    Error: No such container:path: mycontainer:/no/such

    docker image rm nosuchimage
    Error: No such image: nosuchimage

    docker network rm nosuchnetwork
    Error: No such network: nosuchnetwork

    docker volume rm nosuchvolume
    Error: No such volume: nosuchvolume

    docker plugin rm nosuchplugin
    Error: No such plugin: nosuchplugin

    docker checkpoint rm nosuchcontainer nosuchcheckpoint
    Error response from daemon: No such container: nosuchcontainer

    docker checkpoint rm mycontainer nosuchcheckpoint
    Error response from daemon: checkpoint nosuchcheckpoint does not exist for container mycontainer

    docker service rm nosuchservice
    Error: No such service: nosuchservice

    docker node rm nosuchnode
    Error: No such node: nosuchnode

    docker config rm nosuschconfig
    Error: No such config: nosuschconfig

    docker secret rm nosuchsecret
    Error: No such secret: nosuchsecret

After this change:

    docker container rm nosuchcontainer
    Error response from daemon: No such container: nosuchcontainer

    docker container cp mycontainer:/no/such/path .
    Error response from daemon: Could not find the file /no/such/path in container mycontainer

    docker container cp ./Dockerfile mycontainer:/no/such/path
    Error response from daemon: Could not find the file /no/such in container mycontainer

    docker image rm nosuchimage
    Error response from daemon: No such image: nosuchimage:latest

    docker network rm nosuchnetwork
    Error response from daemon: network nosuchnetwork not found

    docker volume rm nosuchvolume
    Error response from daemon: get nosuchvolume: no such volume

    docker plugin rm nosuchplugin
    Error response from daemon: plugin "nosuchplugin" not found

    docker checkpoint rm nosuchcontainer nosuchcheckpoint
    Error response from daemon: No such container: nosuchcontainer

    docker checkpoint rm mycontainer nosuchcheckpoint
    Error response from daemon: checkpoint nosuchcheckpoint does not exist for container mycontainer

    docker service rm nosuchservice
    Error response from daemon: service nosuchservice not found

    docker node rm nosuchnode
    Error response from daemon: node nosuchnode not found

    docker config rm nosuchconfig
    Error response from daemon: config nosuchconfig not found

    docker secret rm nosuchsecret
    Error response from daemon: secret nosuchsecret not found

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-03-20 19:04:52 +01:00
Levi Harrison
8128a9a478 Fix grammar in client function comments
Changes certain words and adds punctuation to the comments of functions in the client package, which end up in the GoDoc documentation. Areas where only periods were needed were ignored to prevent excessive code churn.

Signed-off-by: Levi Harrison <levisamuelharrison@gmail.com>
2021-02-16 10:07:44 -05: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
0cafc84fb2 Use errdefs for handling errors in client
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-03-16 00:42:42 +01: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
Emil Davtyan
44369bdd65 Wrap response errors for container copy methods.
This allows IsErrNotFound and IsErrNotImplemented to work as intended.

Signed-off-by: Emil Davtyan <emil2k@gmail.com>
2018-01-11 13:40:49 +01:00
Yong Tang
e330e7a5ce Update doc for CopyFromContainer
This fix updates doc for CopyFromContainer to explicitly
mention that the content received from the reader is
a TAR archive.

This fix closes 35965.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
2018-01-08 18:29:59 +00:00
Sebastiaan van Stijn
5564fad406 Merge pull request #33467 from bschwind/copy-documentation
Add note to CopyToContainer documentation
2017-06-24 00:19:51 -07:00
Brian Schwind
1c3071e487 Add note to CopyToContainer documentation
Signed-off-by: Brian Schwind <brianmschwind@gmail.com>
2017-06-20 14:49:38 +09: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
Erik Hollensbe
8a7ff5ff74 daemon/archive.go: Fix copy routines to preserve UID.
This changes the long-standing bug of copy operations not preserving the
UID/GID information after the files arrive to the container.

Signed-off-by: Erik Hollensbe <github@hollensbe.org>
2017-04-12 10:33:19 +00:00
Michael Crosby
7c36a1af03 Move engine-api client package
This moves the engine-api client package to `/docker/docker/client`.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-09-07 11:05:58 -07:00