Compare commits

..

134 Commits

Author SHA1 Message Date
Sebastiaan van Stijn
f417435e5f Merge pull request #47348 from rumpl/25.0_backport-history-config
[25.0 backport]  c8d: Use the same logic to get the present images
2024-02-06 19:43:34 +01:00
Djordje Lukic
acd023d42b c8d: Use the same logic to get the present images
Inspect and history used two different ways to find the present images.
This made history fail in some cases where image inspect would work (if
a configuration of a manifest wasn't found in the content store).

With this change we now use the same logic for both inspect and history.

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2024-02-06 17:17:51 +01:00
Sebastiaan van Stijn
7a075cacf9 Merge pull request #47344 from thaJeztah/25.0_backport_seccomp_updates
[25.0 backport] profiles/seccomp: add syscalls for kernel v5.17 - v6.6, match containerd's profile
2024-02-06 16:46:41 +01:00
Sebastiaan van Stijn
aff7177ee7 Merge pull request #47337 from vvoland/cache-fix-older-windows-25
[25.0 backport] image/cache: Ignore Build and Revision on Windows
2024-02-06 16:18:02 +01:00
Sebastiaan van Stijn
ed7c26339e seccomp: add futex_wake syscall (kernel v6.7, libseccomp v2.5.5)
Add this syscall to match the profile in containerd

containerd: a6e52c74fa
libseccomp: 53267af3fb
kernel: 9f6c532f59

    futex: Add sys_futex_wake()

    To complement sys_futex_waitv() add sys_futex_wake(). This syscall
    implements what was previously known as FUTEX_WAKE_BITSET except it
    uses 'unsigned long' for the bitmask and takes FUTEX2 flags.

    The 'unsigned long' allows FUTEX2_SIZE_U64 on 64bit platforms.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit d69729e053)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:59 +01:00
Sebastiaan van Stijn
74e3b4fb2e seccomp: add futex_wait syscall (kernel v6.7, libseccomp v2.5.5)
Add this syscall to match the profile in containerd

containerd: a6e52c74fa
libseccomp: 53267af3fb
kernel: cb8c4312af

    futex: Add sys_futex_wait()

    To complement sys_futex_waitv()/wake(), add sys_futex_wait(). This
    syscall implements what was previously known as FUTEX_WAIT_BITSET
    except it uses 'unsigned long' for the value and bitmask arguments,
    takes timespec and clockid_t arguments for the absolute timeout and
    uses FUTEX2 flags.

    The 'unsigned long' allows FUTEX2_SIZE_U64 on 64bit platforms.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 10d344d176)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:59 +01:00
Sebastiaan van Stijn
4cc0416534 seccomp: add futex_requeue syscall (kernel v6.7, libseccomp v2.5.5)
Add this syscall to match the profile in containerd

containerd: a6e52c74fa
libseccomp: 53267af3fb
kernel: 0f4b5f9722

    futex: Add sys_futex_requeue()

    Finish off the 'simple' futex2 syscall group by adding
    sys_futex_requeue(). Unlike sys_futex_{wait,wake}() its arguments are
    too numerous to fit into a regular syscall. As such, use struct
    futex_waitv to pass the 'source' and 'destination' futexes to the
    syscall.

    This syscall implements what was previously known as FUTEX_CMP_REQUEUE
    and uses {val, uaddr, flags} for source and {uaddr, flags} for
    destination.

    This design explicitly allows requeueing between different types of
    futex by having a different flags word per uaddr.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit df57a080b6)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:59 +01:00
Sebastiaan van Stijn
f9f9e7ff9a seccomp: add map_shadow_stack syscall (kernel v6.6, libseccomp v2.5.5)
Add this syscall to match the profile in containerd

containerd: a6e52c74fa
libseccomp: 53267af3fb
kernel: c35559f94e

    x86/shstk: Introduce map_shadow_stack syscall

    When operating with shadow stacks enabled, the kernel will automatically
    allocate shadow stacks for new threads, however in some cases userspace
    will need additional shadow stacks. The main example of this is the
    ucontext family of functions, which require userspace allocating and
    pivoting to userspace managed stacks.

    Unlike most other user memory permissions, shadow stacks need to be
    provisioned with special data in order to be useful. They need to be setup
    with a restore token so that userspace can pivot to them via the RSTORSSP
    instruction. But, the security design of shadow stacks is that they
    should not be written to except in limited circumstances. This presents a
    problem for userspace, as to how userspace can provision this special
    data, without allowing for the shadow stack to be generally writable.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 8826f402f9)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:59 +01:00
Sebastiaan van Stijn
5fb4eb941d seccomp: add fchmodat2 syscall (kernel v6.6, libseccomp v2.5.5)
Add this syscall to match the profile in containerd

containerd: a6e52c74fa
libseccomp: 53267af3fb
kernel: 09da082b07

    fs: Add fchmodat2()

    On the userspace side fchmodat(3) is implemented as a wrapper
    function which implements the POSIX-specified interface. This
    interface differs from the underlying kernel system call, which does not
    have a flags argument. Most implementations require procfs [1][2].

    There doesn't appear to be a good userspace workaround for this issue
    but the implementation in the kernel is pretty straight-forward.

    The new fchmodat2() syscall allows to pass the AT_SYMLINK_NOFOLLOW flag,
    unlike existing fchmodat.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 6f242f1a28)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:59 +01:00
Sebastiaan van Stijn
67e9aa6d4d seccomp: add cachestat syscall (kernel v6.5, libseccomp v2.5.5)
Add this syscall to match the profile in containerd

containerd: a6e52c74fa
libseccomp: 53267af3fb
kernel: cf264e1329

    NAME
        cachestat - query the page cache statistics of a file.

    SYNOPSIS
        #include <sys/mman.h>

        struct cachestat_range {
            __u64 off;
            __u64 len;
        };

        struct cachestat {
            __u64 nr_cache;
            __u64 nr_dirty;
            __u64 nr_writeback;
            __u64 nr_evicted;
            __u64 nr_recently_evicted;
        };

        int cachestat(unsigned int fd, struct cachestat_range *cstat_range,
            struct cachestat *cstat, unsigned int flags);

    DESCRIPTION
        cachestat() queries the number of cached pages, number of dirty
        pages, number of pages marked for writeback, number of evicted
        pages, number of recently evicted pages, in the bytes range given by
        `off` and `len`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 4d0d5ee10d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:58 +01:00
Sebastiaan van Stijn
61b82be580 seccomp: add set_mempolicy_home_node syscall (kernel v5.17, libseccomp v2.5.4)
This syscall is gated by CAP_SYS_NICE, matching the profile in containerd.

containerd: a6e52c74fa
libseccomp: d83cb7ac25
kernel: c6018b4b25

    mm/mempolicy: add set_mempolicy_home_node syscall
    This syscall can be used to set a home node for the MPOL_BIND and
    MPOL_PREFERRED_MANY memory policy.  Users should use this syscall after
    setting up a memory policy for the specified range as shown below.

      mbind(p, nr_pages * page_size, MPOL_BIND, new_nodes->maskp,
            new_nodes->size + 1, 0);
      sys_set_mempolicy_home_node((unsigned long)p, nr_pages * page_size,
                    home_node, 0);

    The syscall allows specifying a home node/preferred node from which
    kernel will fulfill memory allocation requests first.
    ...

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 1251982cf7)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 15:25:56 +01:00
Paweł Gronowski
0227d95f99 image/cache: Use Platform from ocispec
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 2c01d53d96)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-06 14:29:54 +01:00
Paweł Gronowski
fa9c5c55e1 image/cache: Ignore Build and Revision on Windows
The compatibility depends on whether `hyperv` or `process` container
isolation is used.
This fixes cache not being used when building images based on older
Windows versions on a newer Windows host.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 91ea04089b)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-06 13:13:37 +01:00
Sebastiaan van Stijn
df96d8d0bd Merge pull request #47334 from thaJeztah/25.0_backport_rootlesskit_binary_2.0.1
[25.0 backport] Dockerfile: update RootlessKit to v2.0.1
2024-02-06 13:00:20 +01:00
Akihiro Suda
1652559be4 Dockerfile: update RootlessKit to v2.0.1
https://github.com/rootless-containers/rootlesskit/releases/tag/v2.0.1

Fix issue 47327 (`rootless lxc-user-nic: /etc/resolv.conf missing ip`)

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
(cherry picked from commit 7f1b700227)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 09:09:01 +01:00
Sebastiaan van Stijn
ab29279200 Merge pull request #47294 from vvoland/fix-save-manifests-25
[25.0 backport] image/save: Fix untagged images not present in index.json
2024-02-05 19:59:57 +01:00
Paweł Gronowski
147b5388dd integration/save: Add tests checking OCI archive output
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 2ef0b53e51)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-05 14:28:02 +01:00
Sebastiaan van Stijn
60103717bc Merge pull request #47316 from thaJeztah/25.0_backport_update_dev_cli_compose
[25.0 backport] Dockerfile: update docker-cli to v25.0.2, docker compose v2.24.5
2024-02-05 11:09:34 +01:00
Sebastiaan van Stijn
45dede440e Merge pull request #47323 from thaJeztah/25.0_backport_plugin-install-digest
[25.0 backport] plugins: Fix panic when fetching by digest
2024-02-05 10:42:20 +01:00
Laura Brehm
ba4a2dab16 plugins: fix panic installing from repo w/ digest
Only print the tag when the received reference has a tag, if
we can't cast the received tag to a `reference.Tagged` then
skip printing the tag as it's likely a digest.

Fixes panic when trying to install a plugin from a reference
with a digest such as
`vieux/sshfs@sha256:1d3c3e42c12138da5ef7873b97f7f32cf99fb6edde75fa4f0bcf9ed277855811`

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-05 09:40:57 +01:00
Laura Brehm
51133117fb tests: add plugin install test w/ digest
Adds a test case for installing a plugin from a remote in the form
of `plugin-content-trust@sha256:d98f2f8061...`, which is currently
causing the daemon to panic, as we found while running the CLI e2e
tests:

```
docker plugin install registry:5000/plugin-content-trust@sha256:d98f2f806144bf4ba62d4ecaf78fec2f2fe350df5a001f6e3b491c393326aedb
```

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-05 09:40:54 +01:00
Sebastiaan van Stijn
341a7978a5 Merge pull request #47313 from thaJeztah/25.0_backport_libc8d_fix_startup_data_race
[25.0 backport] libcontainerd/supervisor: fix data race
2024-02-03 14:37:57 +01:00
Sebastiaan van Stijn
10e3bfd0ac Merge pull request #47220 from thaJeztah/25.0_backport_more_gocompat
[25.0 backport] add more //go:build directives to prevent downgrading to go1.16 language
2024-02-03 14:36:55 +01:00
Sebastiaan van Stijn
269a0d8feb Dockerfile: update docker compose to v2.24.5
Update the version of compose used in CI to the latest version.

- full diff: https://github.com/docker/compose/compare/v2.24.3...v2.24.5
- release notes: https://github.com/docker/compose/releases/tag/v2.24.5

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 10d6f5213a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 13:54:14 +01:00
Sebastiaan van Stijn
876b1d1dcd Dockerfile: update dev-shell version of the cli to v25.0.2
Update the docker CLI that's available for debugging in the dev-shell
to the v25 release.

full diff: https://github.com/docker/cli/compare/v25.0.1...v25.0.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 9c92c07acf)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 13:54:13 +01:00
Sebastiaan van Stijn
0bcd64689b Dockerfile: update docker compose to v2.24.3
Update the version of compose used in CI to the latest version.

- full diff: https://github.com/docker/compose/compare/v2.24.2...v2.24.3
- release notes: https://github.com/docker/compose/releases/tag/v2.24.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 388ba9a69c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 13:54:13 +01:00
Sebastiaan van Stijn
8d454710cd Dockerfile: update dev-shell version of the cli to v25.0.1
Update the docker CLI that's available for debugging in the dev-shell
to the v25 release.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 3eb1527fdb)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 13:54:13 +01:00
Sebastiaan van Stijn
6cf694fe70 Merge pull request #47243 from corhere/backport-25.0/fix-journald-logs-systemd-255
[25.0 backport] logger/journald: fix tailing logs with systemd 255
2024-02-03 13:29:42 +01:00
Cory Snider
c12bbf549b libcontainerd/supervisor: fix data race
The monitorDaemon() goroutine calls startContainerd() then blocks on
<-daemonWaitCh to wait for it to exit. The startContainerd() function
would (re)initialize the daemonWaitCh so a restarted containerd could be
waited on. This implementation was race-free because startContainerd()
would synchronously initialize the daemonWaitCh before returning. When
the call to start the managed containerd process was moved into the
waiter goroutine, the code to initialize the daemonWaitCh struct field
was also moved into the goroutine. This introduced a race condition.

Move the daemonWaitCh initialization to guarantee that it happens before
the startContainerd() call returns.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit dd20bf4862)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-03 11:40:54 +01:00
Sebastiaan van Stijn
1ae115175c Merge pull request #47311 from akerouanton/25.0-libnet-bridge-mtu-ignore-einval
[25.0 backport] libnet: bridge: ignore EINVAL when configuring bridge MTU
2024-02-03 11:36:47 +01:00
Sebastiaan van Stijn
a7f9907f5f Merge pull request #47310 from akerouanton/25.0-revert-automatically-enable-ipv6
[25.0 backport] Revert "daemon: automatically set network EnableIPv6 if needed"
2024-02-03 11:31:11 +01:00
Cory Snider
9150d0115e d/logger/journald: quit waiting when logger closes
If a reader has caught up to the logger and is waiting for the next
message, it should stop waiting when the logger is closed. Otherwise
the reader will unnecessarily wait the full closedDrainTimeout for no
log messages to arrive.

This case was overlooked when the journald reader was recently
overhauled to be compatible with systemd 255, and the reader tests only
failed when a logical race happened to settle in such a way to exercise
the bugged code path. It was only after implicit flushing on close was
added to the journald test harness that the Follow tests would
repeatably fail due to this bug. (No new regression tests are needed.)

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 987fe37ed1)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-02 19:10:41 -05:00
Cory Snider
9af7c8ec0a d/logger/journald: sync logger on close in tests
The journald reader test harness injects an artificial asynchronous
delay into the logging pipeline: a logged message won't be written to
the journal until at least 150ms after the Log() call returns. If a test
returns while log messages are still in flight to be written, the logs
may attempt to be written after the TempDir has been cleaned up, leading
to spurious errors.

The logger read tests which interleave writing and reading have to
include explicit synchronization points to work reliably with this delay
in place. On the other hand, tests should not be required to sync the
logger explicitly before returning. Override the Close() method in the
test harness wrapper to wait for in-flight logs to be flushed to disk.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit d53b7d7e46)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-02 19:10:41 -05:00
Cory Snider
3344c502da d/logger/loggertest: improve TestConcurrent
- Check the return value when logging messages
- Log the stream (stdout/stderr) and list of messages that were not read
- Wait until the logger is closed before returning early (panic/fatal)

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 39c5c16521)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-02 19:10:41 -05:00
Cory Snider
6c9fafdda7 d/logger/journald: log journal-remote cmd output
Writing the systemd-journal-remote command output directly to os.Stdout
and os.Stderr makes it nearly impossible to tell which test case the
output is related to when the tests are not run in verbose mode. Extend
the journald sender fake to redirect output to the test log so they
interleave with the rest of the test output.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 5792bf7ab3)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-02 19:10:41 -05:00
Cory Snider
f8a8cdaf9e d/logger/journald: fix data race in test harness
The Go race detector was detecting a data race when running the
TestLogRead/Follow/Concurrent test against the journald logging driver.
The race was in the test harness, specifically syncLogger. The waitOn
field would be reassigned each time a log entry is sent to the journal,
which is not concurrency-safe. Make it concurrency-safe using the same
patterns that are used in the log follower implementation to synchronize
with the logger.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 982e777d49)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-02-02 19:10:41 -05:00
Albin Kerouanton
7a659049b8 libnet: bridge: ignore EINVAL when configuring bridge MTU
Since 964ab7158c, we explicitly set the bridge MTU if it was specified.
Unfortunately, kernel <v4.17 have a check preventing us to manually set
the MTU to anything greater than 1500 if no links is attached to the
bridge, which is how we do things -- create the bridge, set its MTU and
later on, attach veths to it.

Relevant kernel commit: 804b854d37

As we still have to support CentOS/RHEL 7 (and their old v3.10 kernels)
for a few more months, we need to ignore EINVAL if the MTU is > 1500
(but <= 65535).

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
(cherry picked from commit 89470a7114)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-02-02 19:51:11 +01:00
Albin Kerouanton
0ccf1c2a93 api/t/network: ValidateIPAM: ignore v6 subnet when IPv6 is disabled
Commit 4f47013feb introduced a new validation step to make sure no
IPv6 subnet is configured on a network which has EnableIPv6=false.

Commit 5d5eeac310 then removed that validation step and automatically
enabled IPv6 for networks with a v6 subnet. But this specific commit
was reverted in c59e93a67b and now the error introduced by 4f47013feb
is re-introduced.

But it turns out some users expect a network created with an IPv6
subnet and EnableIPv6=false to actually have no IPv6 connectivity.
This restores that behavior.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
(cherry picked from commit e37172c613)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-02-02 19:37:27 +01:00
Albin Kerouanton
28c1a8bc2b Revert "daemon: automatically set network EnableIPv6 if needed"
This reverts commit 5d5eeac310.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
(cherry picked from commit c59e93a67b)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-02-02 19:37:27 +01:00
Sebastiaan van Stijn
5b5a58b2cd Merge pull request #47304 from akerouanton/25.0-duplicate_mac_addrs2
[25.0 backport] Only restore a configured MAC addr on restart.
2024-02-02 19:04:09 +01:00
Sebastiaan van Stijn
282891f70c Merge pull request #47303 from akerouanton/25.0-backport-internal-bridge-firewalld
[25.0 backport] Add internal n/w bridge to firewalld docker zone
2024-02-02 19:02:57 +01:00
Rob Murray
bbe6f09afc No inspect 'Config.MacAddress' unless configured.
Do not set 'Config.MacAddress' in inspect output unless the MAC address
is configured.

Also, make sure it is filled in for a configured address on the default
network before the container is started (by translating the network name
from 'default' to 'config' so that the address lookup works).

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 8c64b85fb9)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-02-02 09:10:04 +01:00
Rob Murray
5b13a38144 Only restore a configured MAC addr on restart.
The API's EndpointConfig struct has a MacAddress field that's used for
both the configured address, and the current address (which may be generated).

A configured address must be restored when a container is restarted, but a
generated address must not.

The previous attempt to differentiate between the two, without adding a field
to the API's EndpointConfig that would show up in 'inspect' output, was a
field in the daemon's version of EndpointSettings, MACOperational. It did
not work, MACOperational was set to true when a configured address was
used. So, while it ensured addresses were regenerated, it failed to preserve
a configured address.

So, this change removes that code, and adds DesiredMacAddress to the wrapped
version of EndpointSettings, where it is persisted but does not appear in
'inspect' results. Its value is copied from MacAddress (the API field) when
a container is created.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit dae33031e0)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-02-02 09:10:04 +01:00
Rob Murray
990e95dcf0 Add internal n/w bridge to firewalld docker zone
Containers attached to an 'internal' bridge network are unable to
communicate when the host is running firewalld.

Non-internal bridges are added to a trusted 'docker' firewalld zone, but
internal bridges were not.

DOCKER-ISOLATION iptables rules are still configured for an internal
network, they block traffic to/from addresses outside the network's subnet.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 2cc627932a)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-02-02 08:38:44 +01:00
Sebastiaan van Stijn
a140d0d95f Merge pull request #47201 from thaJeztah/25.0_backport_swarm_rotate_key_flake
[25.0 backport] De-flake TestSwarmClusterRotateUnlockKey... again... maybe?
2024-02-02 00:13:42 +01:00
Sebastiaan van Stijn
91a8312fb7 Merge pull request #47295 from vvoland/api-build-version-25
[25.0 backport] api: Document `version` in `/build`
2024-02-01 21:07:57 +01:00
Sebastiaan van Stijn
cf03e96354 Merge pull request #47298 from thaJeztah/25.0_backport_rm_dash_rf
[25.0 backport] Assert temp output directory is not an empty string
2024-02-01 19:13:50 +01:00
Paweł Gronowski
c48b67160d api: Document version in /build
It was introduced in API v1.38 but wasn't documented.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 0c3b8ccda7)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-01 17:00:31 +01:00
Paweł Gronowski
225e043196 c8d/save: Handle digested reference same as ID
When saving an image treat `image@sha256:abcdef...` the same as
`abcdef...`, this makes it:

- Not export the digested tag as the image name
- Not try to export all tags from the image repository

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 5e13f54f57)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-01 16:48:36 +01:00
Paweł Gronowski
78174d2e74 image/save: Fix untagged images not present in index.json
Saving an image via digested reference, ID or truncated ID doesn't store
the image reference in the archive. This also causes the save code to
not add the image's manifest to the index.json.
This commit explicitly adds the untagged manifests to the index.json if
no tagged manifests were added.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit d131f00fff)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-02-01 16:48:34 +01:00
Sebastiaan van Stijn
622e66684a Merge pull request #47296 from dvdksn/25.0_backport_api_docs_broken_links
[25.0 backport] docs: remove dead links from api verison history
2024-02-01 16:09:01 +01:00
voloder
85f4e6151a Assert temp output directory is not an empty string
Signed-off-by: voloder <110066198+voloder@users.noreply.github.com>
(cherry picked from commit c655b7dc78)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 16:04:29 +01:00
Sebastiaan van Stijn
3e358447f5 Merge pull request #47291 from thaJeztah/25.0_backport_update_actions
[25.0 backport] gha: update actions to account for node 16 deprecation
2024-02-01 15:49:06 +01:00
David Karlsson
dd4de8f388 docs: remove dead links from api verison history
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
(cherry picked from commit 7f94acb6ab)
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-02-01 15:02:46 +01:00
CrazyMax
f5ef4e76b3 ci: update to docker/bake-action@v4
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
(cherry picked from commit a2026ee442)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:42 +01:00
CrazyMax
6c5e5271c1 ci: update to codecov/codecov-action@v4
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
(cherry picked from commit 5a3c463a37)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:42 +01:00
CrazyMax
693fca6199 ci: update to actions/download-artifact@v4 and actions/upload-artifact@v4
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
(cherry picked from commit 9babc02283)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:42 +01:00
CrazyMax
49487e996a ci: update to actions/cache@v3
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
(cherry picked from commit a83557d747)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:41 +01:00
Sebastiaan van Stijn
0358f31dc2 gha: update to crazy-max/ghaction-github-runtime@v3
- Node 20 as default runtime (requires Actions Runner v2.308.0 or later)
- full diff: https://github.com/crazy-max/ghaction-github-runtime/compare/v2.2.0...v3.0.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 3a8191225a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:13 +01:00
Sebastiaan van Stijn
081cffb3fa gha: update to docker/login-action@v3
- Node 20 as default runtime (requires Actions Runner v2.308.0 or later)
- full diff https://github.com/docker/login-action/compare/v2.2.0...v3.0.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 08251978a8)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:13 +01:00
Sebastiaan van Stijn
9de19554c7 gha: update to docker/setup-qemu-action@v3
- Node 20 as default runtime (requires Actions Runner v2.308.0 or later)
- full diff https://github.com/docker/setup-qemu-action/compare/v2.2.0...v3.0.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 5d396e0533)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:13 +01:00
Sebastiaan van Stijn
2a80b8a7b2 gha: update to docker/bake-action@v4
- Node 20 as default runtime (requires Actions Runner v2.308.0 or later)
- full diff https://github.com/docker/bake-action/compare/v2.3.0...v4.1.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 4a1839ef1d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:13 +01:00
Sebastiaan van Stijn
61ffecfa3b gha: update to docker/setup-buildx-action@v3
- Node 20 as default runtime (requires Actions Runner v2.308.0 or later)
- full diff: https://github.com/docker/setup-buildx-action/compare/v2.10.0...v3.0.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit b7fd571b0a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:13 +01:00
Sebastiaan van Stijn
02cd8dec03 gha: update to docker/metadata-action@v5
- Node 20 as default runtime (requires Actions Runner v2.308.0 or later)
- full diff: https://github.com/docker/metadata-action/compare/v4.6.0...v5.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 00a2626b56)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:12 +01:00
Sebastiaan van Stijn
1d7df5ecc0 gha: update to actions/setup-go@v5
- full diff: https://github.com/actions/setup-go/compare/v3.5.0...v5.0.0

v5

In scope of this release, we change Nodejs runtime from node16 to node20.
Moreover, we update some dependencies to the latest versions.

Besides, this release contains such changes as:

- Fix hosted tool cache usage on windows
- Improve documentation regarding dependencies caching

V4

The V4 edition of the action offers:

- Enabled caching by default
- The action will try to enable caching unless the cache input is explicitly
  set to false.

Please see "Caching dependency files and build outputs" for more information:
https://github.com/actions/setup-go#caching-dependency-files-and-build-outputs

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit e27a785f43)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:12 +01:00
Sebastiaan van Stijn
4e68a265ed gha: update to actions/github-script@v7
- full diff: https://github.com/actions/github-script/compare/v6.4.1...v7.0.1

breaking changes: https://github.com/actions/github-script?tab=readme-ov-file#v7

> Version 7 of this action updated the runtime to Node 20
> https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-javascript-actions
>
> All scripts are now run with Node 20 instead of Node 16 and are affected
> by any breaking changes between Node 16 and 20
>
> The previews input now only applies to GraphQL API calls as REST API previews
> are no longer necessary
> https://github.blog/changelog/2021-10-14-rest-api-preview-promotions/.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit fb53ee6ba3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:12 +01:00
Sebastiaan van Stijn
e437f890ba gha: update to actions/checkout@v4
Release notes:

- https://github.com/actions/checkout/compare/v3.6.0...v4.1.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 0ffddc6bb8)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-01 12:33:09 +01:00
Sebastiaan van Stijn
5a0015f72c Merge pull request #47225 from s4ke/bump-swarmkit-generic-resources#25.0
[25.0 backport] Fix HasResource inverted boolean error - vendor swarmkit v2.0.0-20240125134710-dcda100a8261
2024-02-01 04:20:24 +01:00
Sebastiaan van Stijn
5babfee371 Merge pull request #47222 from vvoland/pkg-pools-close-noop-25
[25.0 backport] pkg/ioutils: Make subsequent Close attempts noop
2024-02-01 04:19:12 +01:00
Sebastiaan van Stijn
fce6e0ca9b Merge pull request from GHSA-xw73-rw38-6vjc
[25.0 backport] image/cache: Restrict cache candidates to locally built images
2024-02-01 01:12:24 +01:00
Sebastiaan van Stijn
d838e68300 Merge pull request #47269 from thaJeztah/25.0_backport_bump_runc_binary_1.1.12
[25.0 backport] update runc binary to v1.1.12
2024-02-01 00:05:10 +01:00
Sebastiaan van Stijn
fa0d4159c7 Merge pull request #47280 from thaJeztah/25.0_backport_bump_containerd_binary_1.7.13
[25.0 backport] update containerd binary to v1.7.13
2024-01-31 23:53:46 +01:00
Sebastiaan van Stijn
06e22dce46 Merge pull request #47275 from vvoland/vendor-bk-0.12.5-25
[25.0 backport] vendor: github.com/moby/buildkit v0.12.5
2024-01-31 22:47:49 +01:00
Sebastiaan van Stijn
b73ee94289 Merge pull request #47274 from thaJeztah/25.0_backport_bump_runc_1.1.12
[25.0 backport] vendor: github.com/opencontainers/runc v1.1.12
2024-01-31 22:46:35 +01:00
Sebastiaan van Stijn
fd6a419ad5 update containerd binary to v1.7.13
Update the containerd binary that's used in CI

- full diff: https://github.com/containerd/containerd/compare/v1.7.12...v1.7.13
- release notes: https://github.com/containerd/containerd/releases/tag/v1.7.13

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 835cdcac95)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-31 22:03:56 +01:00
Paweł Gronowski
13ce91825f vendor: github.com/moby/buildkit v0.12.5
full diff: https://github.com/moby/buildkit/compare/v0.12.4...v0.12.5

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-31 21:24:39 +01:00
Sebastiaan van Stijn
4b63c47c1e vendor: github.com/opencontainers/runc v1.1.12
- release notes: https://github.com/opencontainers/runc/releases/tag/v1.1.12
- full diff: https://github.com/opencontainers/runc/compare/v1.1.11...v1.1.12

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit b20dccba5e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-31 21:19:02 +01:00
Sebastiaan van Stijn
4edb71bb83 update runc binary to v1.1.12
Update the runc binary that's used in CI and for the static packages, which
includes a fix for [CVE-2024-21626].

- release notes: https://github.com/opencontainers/runc/releases/tag/v1.1.12
- full diff: https://github.com/opencontainers/runc/compare/v1.1.11...v1.1.12

[CVE-2024-21626]: https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 44bf407d4d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-31 21:06:10 +01:00
Sebastiaan van Stijn
667bc3f803 Merge pull request #47265 from vvoland/ci-fix-makeps1-templatefail-25
[25.0 backport] hack/make.ps1: Fix go list pattern
2024-01-31 21:01:57 +01:00
Paweł Gronowski
1b47bfac02 hack/make.ps1: Fix go list pattern
The double quotes inside a single quoted string don't need to be
escaped.
Looks like different Powershell versions are treating this differently
and it started failing unexpectedly without any changes on our side.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit ecb217cf69)
2024-01-31 19:55:37 +01:00
Cory Snider
f2d0d87c46 logger/journald: drop errDrainDone sentinel
errDrainDone is a sentinel error which is never supposed to escape the
package. Consequently, it needs to be filtered out of returns all over
the place, adding boilerplate. Forgetting to filter out these errors
would be a logic bug which the compiler would not help us catch. Replace
it with boolean multi-valued returns as they can't be accidentally
ignored or propagated.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 905477c8ae)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-01-29 11:28:34 -05:00
Cory Snider
6ac38cdbeb logger/journald: wait no longer than the deadline
While it doesn't really matter if the reader waits for an extra
arbitrary period beyond an arbitrary hardcoded timeout, it's also
trivial and cheap to implement, and nice to have.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit d70fe8803c)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-01-29 11:28:34 -05:00
Cory Snider
d7bf237e29 logger/journald: use deadline for drain timeout
The journald reader uses a timer to set an upper bound on how long to
wait for the final log message of a stopped container. However, the
timer channel is only received from in non-blocking select statements!
There isn't enough benefit of using a timer to offset the cost of having
to manage the timer resource. Setting a deadline and comparing the
current time is just as effective, without having to manage the
lifecycle of any runtime resources.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit e94ec8068d)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-01-29 11:28:33 -05:00
Cory Snider
f41b342cbe l/journald: make tests compatible with systemd 255
Synthesize a boot ID for journal entries fed into
systemd-journal-remote, as required by systemd 255.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 71bfffdad1)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-01-29 11:28:33 -05:00
Cory Snider
f413ba6fdb daemon/logger/loggertest: expand log-follow tests
Following logs with a non-negative tail when the container log is empty
is broken on the journald driver when used with systemd 255. Add tests
which cover this edge case to our loggertest suite.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 931568032a)
Signed-off-by: Cory Snider <csnider@mirantis.com>
2024-01-29 11:28:33 -05:00
Martin Braun
c2ef38f790 vendor swarmkit v2.0.0-20240125134710-dcda100a8261
Signed-off-by: Martin Braun <braun@neuroforge.de>
2024-01-25 16:28:59 +01:00
Paweł Gronowski
d5eebf9e19 builder/windows: Don't set ArgsEscaped for RUN cache probe
Previously this was done indirectly - the `compare` function didn't
check the `ArgsEscaped`.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 96d461d27e)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-25 16:07:14 +01:00
Paweł Gronowski
f3f5327b48 image/cache: Check image platform
Make sure the cache candidate platform matches the requested.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 877ebbe038)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-25 16:07:13 +01:00
Paweł Gronowski
05a370f52f image/cache: Restrict cache candidates to locally built images
Restrict cache candidates only to images that were built locally.
This doesn't affect builds using `--cache-from`.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 96ac22768a)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-25 16:07:11 +01:00
Paweł Gronowski
be7b60ef05 daemon/imageStore: Mark images built locally
Store additional image property which makes it possible to distinguish
if image was built locally.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit c6156dc51b)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-25 16:07:10 +01:00
Paweł Gronowski
6d05b9b65b image/cache: Compare all config fields
Add checks for some image config fields that were missing.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 537348763f)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-25 16:07:08 +01:00
Paweł Gronowski
c01bbbddeb pkg/ioutils: Make subsequent Close attempts noop
Turn subsequent `Close` calls into a no-op and produce a warning with an
optional stack trace (if debug mode is enabled).

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 585d74bad1)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-25 15:15:01 +01:00
Sebastiaan van Stijn
32635850ed add more //go:build directives to prevent downgrading to go1.16 language
This is a follow-up to 2cf230951f, adding
more directives to adjust for some new code added since:

Before this patch:

    make -C ./internal/gocompat/
    GO111MODULE=off go generate .
    GO111MODULE=on go mod tidy
    GO111MODULE=on go test -v

    # github.com/docker/docker/internal/sliceutil
    internal/sliceutil/sliceutil.go:3:12: type parameter requires go1.18 or later (-lang was set to go1.16; check go.mod)
    internal/sliceutil/sliceutil.go:3:14: predeclared comparable requires go1.18 or later (-lang was set to go1.16; check go.mod)
    internal/sliceutil/sliceutil.go:4:19: invalid map key type T (missing comparable constraint)

    # github.com/docker/docker/libnetwork
    libnetwork/endpoint.go:252:17: implicit function instantiation requires go1.18 or later (-lang was set to go1.16; check go.mod)

    # github.com/docker/docker/daemon
    daemon/container_operations.go:682:9: implicit function instantiation requires go1.18 or later (-lang was set to go1.16; check go.mod)
    daemon/inspect.go:42:18: implicit function instantiation requires go1.18 or later (-lang was set to go1.16; check go.mod)

With this patch:

    make -C ./internal/gocompat/
    GO111MODULE=off go generate .
    GO111MODULE=on go mod tidy
    GO111MODULE=on go test -v
    === RUN   TestModuleCompatibllity
        main_test.go:321: all packages have the correct go version specified through //go:build
    --- PASS: TestModuleCompatibllity (0.00s)
    PASS
    ok  	gocompat	0.031s
    make: Leaving directory '/go/src/github.com/docker/docker/internal/gocompat'

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit bd4ff31775)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-25 14:57:05 +01:00
Brian Goff
2cf1c762f8 De-flake TestSwarmClusterRotateUnlockKey... again... maybe?
This hopefully makes the test less flakey (or removes any flake that
would be caused by the test itself).

1. Adds tail of cluster daemon logs when there is a test failure so we
   can more easily see what may be happening
2. Scans the daemon logs to check if the key is rotated before
   restarting the daemon. This is a little hacky but a little better
   than assuming it is done after a hard-coded 3 seconds.
3. Cleans up the `node ls` check such that it uses a poll function

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit fbdc02534a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-24 10:06:10 +01:00
Sebastiaan van Stijn
71fa3ab079 Merge pull request #47196 from akerouanton/25.0-fix-multiple-rename-error
[25.0] daemon: rename: don't reload endpoint from datastore
2024-01-23 23:56:39 +01:00
Albin Kerouanton
5295e88ceb daemon: rename: don't reload endpoint from datastore
Commit 8b7af1d0f added some code to update the DNSNames of all
endpoints attached to a sandbox by loading a new instance of each
affected endpoints from the datastore through a call to
`Network.EndpointByID()`.

This method then calls `Network.getEndpointFromStore()`, that in
turn calls `store.GetObject()`, which then calls `cache.get()`,
which calls `o.CopyTo(kvObject)`. This effectively creates a fresh
new instance of an Endpoint. However, endpoints are already kept in
memory by Sandbox, meaning we now have two in-memory instances of
the same Endpoint.

As it turns out, libnetwork is built around the idea that no two objects
representing the same thing should leave in-memory, otherwise breaking
mutex locking and optimistic locking (as both instances will have a drifting
version tracking ID -- dbIndex in libnetwork parliance).

In this specific case, this bug materializes by container rename failing
when applied a second time for a given container. An integration test is
added to make sure this won't happen again.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
(cherry picked from commit 80c44b4b2e)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-01-23 22:53:43 +01:00
Paweł Gronowski
6eef840b8a Merge pull request #47191 from vvoland/volume-cifs-resolve-optout-25
[25.0 backport] volume/local: Make host resolution backwards compatible
2024-01-23 19:13:39 +01:00
Sebastiaan van Stijn
e2ab4718c8 Merge pull request #47182 from akerouanton/25.0-fix-aliases-on-default-bridge
[25.0] daemon: only add short cid to aliases for custom networks
2024-01-23 18:28:58 +01:00
Paweł Gronowski
3de920a0b1 volume/local: Fix cifs url containing spaces
Unescapes the URL to avoid passing an URL encoded address to the kernel.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 250886741b)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-23 17:46:23 +01:00
Paweł Gronowski
a445aa95e5 volume/local: Add tests for parsing nfs/cifs mounts
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit f4beb130b0)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-23 17:46:18 +01:00
Paweł Gronowski
cb77e48229 volume/local: Break early if addr was specified
I made a mistake in the last commit - after resolving the IP from the
passed `addr` for CIFS it would still resolve the `device` part.

Apply only one name resolution

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit df43311f3d)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-23 17:45:09 +01:00
Albin Kerouanton
e8801fbe26 daemon: only add short cid to aliases for custom networks
Prior to 7a9b680a, the container short ID was added to the network
aliases only for custom networks. However, this logic wasn't preserved
in 6a2542d and now the cid is always added to the list of network
aliases.

This commit reintroduces the old logic.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
(cherry picked from commit 9f37672ca8)
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-01-23 17:09:11 +01:00
Sebastiaan van Stijn
613b6a12c1 Merge pull request #47192 from thaJeztah/25.0_backport_fix_gateway_ip
[25.0 backport] fix "host-gateway-ip" label not set for builder workers
2024-01-23 17:05:02 +01:00
Sebastiaan van Stijn
1b6738369f Merge pull request #47189 from vvoland/c8d-prefer-default-platform-snapshot-25
[25.0 release] c8d/snapshot: Create any platform if not specified
2024-01-23 16:17:16 +01:00
Sebastiaan van Stijn
b8cc2e8c66 fix "host-gateway-ip" label not set for builder workers
Commit 21e50b89c9 added a label on the buildkit
worker to advertise the host-gateway-ip. This option can be either set by the
user in the daemon config, or otherwise defaults to the gateway-ip.

If no value is set by the user, discovery of the gateway-ip happens when
initializing the network-controller (`NewDaemon`, `daemon.restore()`).

However d222bf097c changed how we handle the
daemon config. As a result, the `cli.Config` used when initializing the
builder only holds configuration information form the daemon config
(user-specified or defaults), but is not updated with information set
by `NewDaemon`.

This patch adds an accessor on the daemon to get the current daemon config.
An alternative could be to return the config by `NewDaemon` (which should
likely be a _copy_ of the config).

Before this patch:

    docker buildx inspect default
    Name:   default
    Driver: docker

    Nodes:
    Name:      default
    Endpoint:  default
    Status:    running
    Buildkit:  v0.12.4+3b6880d2a00f
    Platforms: linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
    Labels:
     org.mobyproject.buildkit.worker.moby.host-gateway-ip: <nil>

After this patch:

    docker buildx inspect default
    Name:   default
    Driver: docker

    Nodes:
    Name:      default
    Endpoint:  default
    Status:    running
    Buildkit:  v0.12.4+3b6880d2a00f
    Platforms: linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
    Labels:
     org.mobyproject.buildkit.worker.moby.host-gateway-ip: 172.18.0.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 00c9785e2e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-23 15:59:09 +01:00
Paweł Gronowski
fcccfeb811 c8d/snapshot: Create any platform if not specified
With containerd snapshotters enabled `docker run` currently fails when
creating a container from an image that doesn't have the default host
platform without an explicit `--platform` selection:

```
$ docker run image:amd64
Unable to find image 'asdf:amd64' locally
docker: Error response from daemon: pull access denied for asdf, repository does not exist or may require 'docker login'.
See 'docker run --help'.
```

This is confusing and the graphdriver behavior is much better here,
because it runs whatever platform the image has, but prints a warning:

```
$ docker run image:amd64
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
```

This commits changes the containerd snapshotter behavior to be the same
as the graphdriver. This doesn't affect container creation when platform
is specified explicitly.

```
$ docker run --rm --platform linux/arm64 asdf:amd64
Unable to find image 'asdf:amd64' locally
docker: Error response from daemon: pull access denied for asdf, repository does not exist or may require 'docker login'.
See 'docker run --help'.
```

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit e438db19d56bef55f9676af9db46cc04caa6330b)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-23 15:05:54 +01:00
Sebastiaan van Stijn
f8eaa14a18 pkg/platforms: internalize in daemon/containerd
This matcher was only used internally in the containerd implementation of
the image store. Un-export it, and make it a local utility in that package
to prevent external use.

This package was introduced in 1616a09b61
(v24.0), and there are no known external consumers of this package, so there
should be no need to deprecate / alias the old location.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 94b4765363)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-23 15:05:50 +01:00
Paweł Gronowski
ac76925ff2 volume/local: Make host resolution backwards compatible
Commit 8ae94cafa5 added a DNS resolution
of the `device` part of the volume option.

The previous way to resolve the passed hostname was to use `addr`
option, which was handled by the same code path as the `nfs` mount type.

The issue is that `addr` is also an SMB module option handled by kernel
and passing a hostname as `addr` produces an invalid argument error.

To fix that, restore the old behavior to handle `addr` the same way as
before, and only perform the new DNS resolution of `device` if there is
no `addr` passed.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 0d51cf9db8)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-23 15:01:44 +01:00
Akihiro Suda
c7a1d928c0 Merge pull request #47180 from thaJeztah/25.0_backport_update_compose
[25.0 backport] Dockerfile: update docker compose to v2.24.2
2024-01-23 22:08:15 +09:00
Sebastiaan van Stijn
2672baefd7 Merge pull request #47178 from thaJeztah/25.0_backport_richer_xattr_errors
[25.0 backport] pkg/system: return even richer xattr errors
2024-01-23 10:56:46 +01:00
Sebastiaan van Stijn
ff15b49b47 Dockerfile: update docker compose to v2.24.2
Update the version of compose used in CI to the latest version.

- full diff: docker/compose@v2.24.1...v2.24.2
- release notes: https://github.com/docker/compose/releases/tag/v2.24.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 05d952b246)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-23 10:25:49 +01:00
Cory Snider
c0573b133f pkg/system: return even richer xattr errors
The names of extended attributes are not completely freeform. Attributes
are namespaced, and the kernel enforces (among other things) that only
attributes whose names are prefixed with a valid namespace are
permitted. The name of the attribute therefore needs to be known in
order to diagnose issues with lsetxattr. Include the name of the
extended attribute in the errors returned from the Lsetxattr and
Lgetxattr so users and us can more easily troubleshoot xattr-related
issues. Include the name in a separate rich-error field to provide code
handling the error enough information to determine whether or not the
failure can be ignored.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 43bf65c174)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-23 09:27:49 +01:00
Sebastiaan van Stijn
c7466c0b52 Merge pull request #47170 from thaJeztah/25.0_backport_remove_deprecated_api_docs
[25.0 backport] docs: remove documentation for deprecated API versions (v1.23 and before)
2024-01-22 21:45:09 +01:00
Sebastiaan van Stijn
dde33d0dfe Merge pull request #47172 from thaJeztah/25.0_backport_fix-bad-http-code
[25.0 backport] daemon: return an InvalidParameter error when ep settings are wrong
2024-01-22 21:44:38 +01:00
Sebastiaan van Stijn
39fedb254b Merge pull request #47169 from thaJeztah/25.0_backport_test_fixes
[25.0 backport] backport test-fixes
2024-01-22 21:20:37 +01:00
Sebastiaan van Stijn
f0f5fc974a Merge pull request #47171 from thaJeztah/25.0_backport_47146-duplicate_mac_addrs
[25.0 backport] Remove generated MAC addresses on restart.
2024-01-22 20:53:52 +01:00
Albin Kerouanton
7c185a1e40 daemon: return an InvalidParameter error when ep settings are wrong
Since v25.0 (commit ff50388), we validate endpoint settings when
containers are created, instead of doing so when containers are started.
However, a container created prior to that release would still trigger
validation error at start-time. In such case, the API returns a 500
status code because the Go error isn't wrapped into an InvalidParameter
error. This is now fixed.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
(cherry picked from commit fcc651972e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 20:50:10 +01:00
Rob Murray
2b036fb1da Remove generated MAC addresses on restart.
The MAC address of a running container was stored in the same place as
the configured address for a container.

When starting a stopped container, a generated address was treated as a
configured address. If that generated address (based on an IPAM-assigned
IP address) had been reused, the containers ended up with duplicate MAC
addresses.

So, remember whether the MAC address was explicitly configured, and
clear it if not.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit cd53b7380c)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:51:54 +01:00
Sebastiaan van Stijn
1f24da70d8 docs/api: remove version matrices from swagger files
These tables linked to deprecated API versions, and an up-to-date version of
the matrix is already included at https://docs.docker.com/engine/api/#api-version-matrix

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 521123944a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:44:48 +01:00
Sebastiaan van Stijn
358fecb566 docs: remove documentation for deprecated API versions < v1.23
These versions are deprecated in v25.0.0, and disabled by default,
see 08e4e88482.

Users that need to refer to documentation for older API versions,
can use archived versions of the documentation on GitHub:

- API v1.23 and before: https://github.com/moby/moby/tree/v25.0.0/docs/api
- API v1.17 and before: https://github.com/moby/moby/tree/v1.9.1/docs/reference/api

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit d54be2ee6d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:44:48 +01:00
Sebastiaan van Stijn
f030b25770 Dockerfile: update docker compose to v2.24.1
Update the version of compose used in CI to the latest version.

- full diff: https://github.com/docker/compose/compare/v2.24.0...v2.24.1
- release notes: https://github.com/docker/compose/releases/tag/v2.24.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 307fe9c716)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:41:15 +01:00
Sebastiaan van Stijn
e07aed0f77 Dockerfile: update dev-shell version of the cli to v25.0.0
Update the docker CLI that's available for debugging in the dev-shell
to the v25 release.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit dfced4b557)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:41:15 +01:00
Sebastiaan van Stijn
cdf3611cff integration-cli: TestInspectAPIMultipleNetworks: use current version
This test was added in f301c5765a to test
inspect output for API > v1.21, however, it was pinned to API v1.21,
which is now deprecated.

Remove the fixed version, as the intent was to test "current" API versions
(API v1.21 and up),

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit a0466ca8e1)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:40:57 +01:00
Sebastiaan van Stijn
05267e9e8c integration-cli: TestInspectAPIBridgeNetworkSettings121: use current version
This test was added in f301c5765a to test
inspect output for API > v1.21, however, it was pinned to API v1.21,
which is now deprecated.

Remove the fixed version, as the intent was to test "current" API versions
(API v1.21 and up),

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 13a384a6fa)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:40:56 +01:00
Sebastiaan van Stijn
e5edf62bca integration-cli: TestPutContainerArchiveErrSymlinkInVolumeToReadOnlyRootfs: use current API
This test was added in 75f6929b44, but pinned
to the API version that was current at the time (v1.20), which is now
deprecated.

Update the test to use the current API version.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 52e3fff828)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-22 19:40:42 +01:00
Sebastiaan van Stijn
e14d121d49 Merge pull request #47163 from vvoland/25-fix-swarm-startinterval-25
[25.0 backport] daemon/cluster/executer: Add missing `StartInterval`
2024-01-22 18:39:43 +01:00
Paweł Gronowski
e0acf1cd70 daemon/cluster/executer: Add missing StartInterval
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 6100190e5c)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-22 15:23:27 +01:00
Sebastiaan van Stijn
c2847b2eb2 Merge pull request #47136 from thaJeztah/25.0_backport_git-url-regex
[25.0 backport] Fix isGitURL regular expression
2024-01-22 15:14:04 +01:00
Sebastiaan van Stijn
0894f7fe69 Merge pull request #47161 from vvoland/save-fix-oci-diffids-25
[25.0 backport] image/save: Fix layers order in OCI manifest
2024-01-22 15:05:20 +01:00
Sebastiaan van Stijn
d25aa32c21 Merge pull request #47135 from thaJeztah/25.0_backport_allow-container-ip-outside-subpool
[25.0 backport] libnetwork: loosen container IPAM validation
2024-01-22 14:05:17 +01:00
Paweł Gronowski
1e335cfa74 image/save: Fix layers order in OCI manifest
Order the layers in OCI manifest by their actual apply order. This is
required by the OCI image spec.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 17fd6562bf)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-22 13:53:02 +01:00
Paweł Gronowski
4d287e9267 image/save: Change layers type to DiffID
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 4979605212)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-01-22 13:52:57 +01:00
David Dooling
0240f5675b Fix isGitURL regular expression
Escape period (.) so regular expression does not match any character before "git".

Signed-off-by: David Dooling <david.dooling@docker.com>
(cherry picked from commit 768146b1b0)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-20 12:19:07 +01:00
Cory Snider
13964248f1 libnetwork: loosen container IPAM validation
Permit container network attachments to set any static IP address within
the network's IPAM master pool, including when a subpool is configured.
Users have come to depend on being able to statically assign container
IP addresses which are guaranteed not to collide with automatically-
assigned container addresses.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 058b30023f)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-20 11:33:04 +01:00
1649 changed files with 35231 additions and 102158 deletions

View File

@@ -3,19 +3,11 @@
"build": {
"context": "..",
"dockerfile": "../Dockerfile",
"target": "devcontainer"
"target": "dev"
},
"workspaceFolder": "/go/src/github.com/docker/docker",
"workspaceMount": "source=${localWorkspaceFolder},target=/go/src/github.com/docker/docker,type=bind,consistency=cached",
"remoteUser": "root",
"runArgs": ["--privileged"],
"customizations": {
"vscode": {
"extensions": [
"golang.go"
]
}
}
"runArgs": ["--privileged"]
}

View File

@@ -22,12 +22,9 @@ Please provide the following information:
**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog.
It must be placed inside the below triple backticks section:
pull request for inclusion in the changelog:
-->
```markdown changelog
```
**- A picture of a cute animal (not mandatory but encouraged)**

View File

@@ -12,9 +12,9 @@ on:
default: "graphdriver"
env:
GO_VERSION: "1.21.9"
GO_VERSION: "1.21.6"
GOTESTLIST_VERSION: v0.3.1
TESTSTAT_VERSION: v0.1.25
TESTSTAT_VERSION: v0.1.3
ITG_CLI_MATRIX_SIZE: 6
DOCKER_EXPERIMENTAL: 1
DOCKER_GRAPHDRIVER: ${{ inputs.storage == 'snapshotter' && 'overlayfs' || 'overlay2' }}
@@ -62,7 +62,6 @@ jobs:
directory: ./bundles
env_vars: RUNNER_OS
flags: unit
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
-
name: Upload reports
if: always()
@@ -70,7 +69,6 @@ jobs:
with:
name: test-reports-unit-${{ inputs.storage }}
path: /tmp/reports/*
retention-days: 1
unit-report:
runs-on: ubuntu-20.04
@@ -98,7 +96,7 @@ jobs:
-
name: Create summary
run: |
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
docker-py:
runs-on: ubuntu-20.04
@@ -151,7 +149,6 @@ jobs:
with:
name: test-reports-docker-py-${{ inputs.storage }}
path: /tmp/reports/*
retention-days: 1
integration-flaky:
runs-on: ubuntu-20.04
@@ -260,7 +257,6 @@ jobs:
directory: ./bundles/test-integration
env_vars: RUNNER_OS
flags: integration,${{ matrix.mode }}
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
-
name: Test daemon logs
if: always()
@@ -273,7 +269,6 @@ jobs:
with:
name: test-reports-integration-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
path: /tmp/reports/*
retention-days: 1
integration-report:
runs-on: ubuntu-20.04
@@ -302,7 +297,7 @@ jobs:
-
name: Create summary
run: |
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
integration-cli-prepare:
runs-on: ubuntu-20.04
@@ -400,7 +395,6 @@ jobs:
directory: ./bundles/test-integration
env_vars: RUNNER_OS
flags: integration-cli
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
-
name: Test daemon logs
if: always()
@@ -413,7 +407,6 @@ jobs:
with:
name: test-reports-integration-cli-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
path: /tmp/reports/*
retention-days: 1
integration-cli-report:
runs-on: ubuntu-20.04
@@ -442,4 +435,4 @@ jobs:
-
name: Create summary
run: |
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY

View File

@@ -19,9 +19,9 @@ on:
default: false
env:
GO_VERSION: "1.21.10"
GO_VERSION: "1.21.6"
GOTESTLIST_VERSION: v0.3.1
TESTSTAT_VERSION: v0.1.25
TESTSTAT_VERSION: v0.1.3
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
WINDOWS_BASE_TAG_2019: ltsc2019
WINDOWS_BASE_TAG_2022: ltsc2022
@@ -182,7 +182,6 @@ jobs:
directory: bundles
env_vars: RUNNER_OS
flags: unit
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
-
name: Upload reports
if: always()
@@ -190,7 +189,6 @@ jobs:
with:
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
retention-days: 1
unit-test-report:
runs-on: ubuntu-latest
@@ -216,7 +214,7 @@ jobs:
-
name: Create summary
run: |
find /tmp/artifacts -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
integration-test-prepare:
runs-on: ubuntu-latest
@@ -457,7 +455,6 @@ jobs:
directory: bundles
env_vars: RUNNER_OS
flags: integration,${{ matrix.runtime }}
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
-
name: Docker info
run: |
@@ -509,7 +506,6 @@ jobs:
with:
name: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-${{ env.TESTREPORTS_NAME }}
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
retention-days: 1
integration-test-report:
runs-on: ubuntu-latest
@@ -548,4 +544,4 @@ jobs:
-
name: Create summary
run: |
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY

View File

@@ -13,7 +13,7 @@ on:
pull_request:
env:
GO_VERSION: "1.21.10"
GO_VERSION: "1.21.6"
DESTDIR: ./build
jobs:
@@ -50,9 +50,6 @@ jobs:
timeout-minutes: 120
needs:
- build
env:
TEST_IMAGE_BUILD: "0"
TEST_IMAGE_ID: "buildkit-tests"
strategy:
fail-fast: false
matrix:
@@ -118,14 +115,6 @@ jobs:
sudo service docker restart
docker version
docker info
-
name: Build test image
uses: docker/bake-action@v4
with:
workdir: ./buildkit
targets: integration-tests
set: |
*.output=type=docker,name=${{ env.TEST_IMAGE_ID }}
-
name: Test
run: |

View File

@@ -51,6 +51,14 @@ jobs:
name: Check artifacts
run: |
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
-
name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
path: ${{ env.DESTDIR }}
if-no-files-found: error
retention-days: 7
prepare-cross:
runs-on: ubuntu-latest
@@ -111,3 +119,11 @@ jobs:
name: Check artifacts
run: |
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
-
name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: cross-${{ env.PLATFORM_PAIR }}
path: ${{ env.DESTDIR }}
if-no-files-found: error
retention-days: 7

View File

@@ -13,9 +13,7 @@ on:
pull_request:
env:
GO_VERSION: "1.21.10"
GIT_PAGER: "cat"
PAGER: "cat"
GO_VERSION: "1.21.6"
jobs:
validate-dco:
@@ -59,7 +57,6 @@ jobs:
- build-dev
- validate-dco
uses: ./.github/workflows/.test.yml
secrets: inherit
strategy:
fail-fast: false
matrix:

View File

@@ -1,62 +0,0 @@
name: validate-pr
on:
pull_request:
types: [opened, edited, labeled, unlabeled]
jobs:
check-area-label:
runs-on: ubuntu-20.04
steps:
- name: Missing `area/` label
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') && !contains(join(github.event.pull_request.labels.*.name, ','), 'area/')
run: |
echo "::error::Every PR with an 'impact/*' label should also have an 'area/*' label"
exit 1
- name: OK
run: exit 0
check-changelog:
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/')
runs-on: ubuntu-20.04
env:
PR_BODY: |
${{ github.event.pull_request.body }}
steps:
- name: Check changelog description
run: |
# Extract the `markdown changelog` note code block
block=$(echo -n "$PR_BODY" | tr -d '\r' | awk '/^```markdown changelog$/{flag=1;next}/^```$/{flag=0}flag')
# Strip empty lines
desc=$(echo "$block" | awk NF)
if [ -z "$desc" ]; then
echo "::error::Changelog section is empty. Please provide a description for the changelog."
exit 1
fi
len=$(echo -n "$desc" | wc -c)
if [[ $len -le 6 ]]; then
echo "::error::Description looks too short: $desc"
exit 1
fi
echo "This PR will be included in the release notes with the following note:"
echo "$desc"
check-pr-branch:
runs-on: ubuntu-20.04
env:
PR_TITLE: ${{ github.event.pull_request.title }}
steps:
# Backports or PR that target a release branch directly should mention the target branch in the title, for example:
# [X.Y backport] Some change that needs backporting to X.Y
# [X.Y] Change directly targeting the X.Y branch
- name: Get branch from PR title
id: title_branch
run: echo "$PR_TITLE" | sed -n 's/^\[\([0-9]*\.[0-9]*\)[^]]*\].*/branch=\1/p' >> $GITHUB_OUTPUT
- name: Check release branch
if: github.event.pull_request.base.ref != steps.title_branch.outputs.branch && !(github.event.pull_request.base.ref == 'master' && steps.title_branch.outputs.branch == '')
run: echo "::error::PR title suggests targetting the ${{ steps.title_branch.outputs.branch }} branch, but is opened against ${{ github.event.pull_request.base.ref }}" && exit 1

View File

@@ -22,7 +22,6 @@ jobs:
needs:
- test-prepare
uses: ./.github/workflows/.windows.yml
secrets: inherit
strategy:
fail-fast: false
matrix:

View File

@@ -25,7 +25,6 @@ jobs:
needs:
- test-prepare
uses: ./.github/workflows/.windows.yml
secrets: inherit
strategy:
fail-fast: false
matrix:

View File

@@ -1,7 +1,6 @@
linters:
enable:
- depguard
- dupword # Checks for duplicate words in the source code.
- goimports
- gosec
- gosimple
@@ -26,11 +25,6 @@ linters:
- docs
linters-settings:
dupword:
ignore:
- "true" # some tests use this as expected output
- "false" # some tests use this as expected output
- "root" # for tests using "ls" output with files owned by "root:root"
importas:
# Do not allow unaliased imports of aliased packages.
no-unaliased: true

View File

@@ -1,19 +1,19 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.10
ARG GO_VERSION=1.21.6
ARG BASE_DEBIAN_DISTRO="bookworm"
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
ARG XX_VERSION=1.4.0
ARG XX_VERSION=1.2.1
ARG VPNKIT_VERSION=0.5.0
ARG DOCKERCLI_REPOSITORY="https://github.com/docker/cli.git"
ARG DOCKERCLI_VERSION=v26.0.0
ARG DOCKERCLI_VERSION=v25.0.2
# cli version used for integration-cli tests
ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git"
ARG DOCKERCLI_INTEGRATION_VERSION=v17.06.2-ce
ARG BUILDX_VERSION=0.13.1
ARG COMPOSE_VERSION=v2.25.0
ARG BUILDX_VERSION=0.12.1
ARG COMPOSE_VERSION=v2.24.5
ARG SYSTEMD="false"
ARG DOCKER_STATIC=1
@@ -198,7 +198,7 @@ RUN git init . && git remote add origin "https://github.com/containerd/container
# When updating the binary version you may also need to update the vendor
# version to pick up bug fixes or new APIs, however, usually the Go packages
# are built from a commit from the master branch.
ARG CONTAINERD_VERSION=v1.7.15
ARG CONTAINERD_VERSION=v1.7.13
RUN git fetch -q --depth 1 origin "${CONTAINERD_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
FROM base AS containerd-build
@@ -245,18 +245,12 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
&& /build/gotestsum --version
FROM base AS shfmt
ARG SHFMT_VERSION=v3.8.0
ARG SHFMT_VERSION=v3.6.0
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
GOBIN=/build/ GO111MODULE=on go install "mvdan.cc/sh/v3/cmd/shfmt@${SHFMT_VERSION}" \
&& /build/shfmt --version
FROM base AS gopls
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
GOBIN=/build/ GO111MODULE=on go install "golang.org/x/tools/gopls@latest" \
&& /build/gopls version
FROM base AS dockercli
WORKDIR /go/src/github.com/docker/cli
ARG DOCKERCLI_REPOSITORY
@@ -358,7 +352,7 @@ FROM base AS rootlesskit-src
WORKDIR /usr/src/rootlesskit
RUN git init . && git remote add origin "https://github.com/rootless-containers/rootlesskit.git"
# When updating, also update vendor.mod and hack/dockerfile/install/rootlesskit.installer accordingly.
ARG ROOTLESSKIT_VERSION=v2.0.2
ARG ROOTLESSKIT_VERSION=v2.0.1
RUN git fetch -q --depth 1 origin "${ROOTLESSKIT_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
FROM base AS rootlesskit-build
@@ -661,11 +655,6 @@ RUN <<EOT
docker-proxy --version
EOT
# devcontainer is a stage used by .devcontainer/devcontainer.json
FROM dev-base AS devcontainer
COPY --link . .
COPY --link --from=gopls /build/ /usr/local/bin/
# usage:
# > make shell
# > SYSTEMD=true make shell

View File

@@ -5,7 +5,7 @@
# This represents the bare minimum required to build and test Docker.
ARG GO_VERSION=1.21.10
ARG GO_VERSION=1.21.6
ARG BASE_DEBIAN_DISTRO="bookworm"
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"

View File

@@ -161,10 +161,10 @@ FROM ${WINDOWS_BASE_IMAGE}:${WINDOWS_BASE_IMAGE_TAG}
# Use PowerShell as the default shell
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ARG GO_VERSION=1.21.10
ARG GO_VERSION=1.21.6
ARG GOTESTSUM_VERSION=v1.8.2
ARG GOWINRES_VERSION=v0.3.1
ARG CONTAINERD_VERSION=v1.7.15
ARG CONTAINERD_VERSION=v1.7.13
# Environment variable notes:
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.

View File

@@ -16,9 +16,6 @@ export VALIDATE_REPO
export VALIDATE_BRANCH
export VALIDATE_ORIGIN_BRANCH
export PAGER
export GIT_PAGER
# env vars passed through directly to Docker's build scripts
# to allow things like `make KEEPBUNDLE=1 binary` easily
# `project/PACKAGERS.md` have some limited documentation of some of these
@@ -80,8 +77,6 @@ DOCKER_ENVS := \
-e DEFAULT_PRODUCT_LICENSE \
-e PRODUCT \
-e PACKAGER_NAME \
-e PAGER \
-e GIT_PAGER \
-e OTEL_EXPORTER_OTLP_ENDPOINT \
-e OTEL_EXPORTER_OTLP_PROTOCOL \
-e OTEL_SERVICE_NAME
@@ -255,10 +250,9 @@ swagger-docs: ## preview the API documentation
.PHONY: generate-files
generate-files:
$(eval $@_TMP_OUT := $(shell mktemp -d -t moby-output.XXXXXXXXXX))
@if [ -z "$($@_TMP_OUT)" ]; then \
echo "Temp dir is not set"; \
exit 1; \
fi
ifeq ($($@_TMP_OUT),)
$(error Could not create temp directory.)
endif
$(BUILD_CMD) --target "update" \
--output "type=local,dest=$($@_TMP_OUT)" \
--file "./hack/dockerfiles/generate-files.Dockerfile" .

View File

@@ -2,17 +2,8 @@ package api // import "github.com/docker/docker/api"
// Common constants for daemon and client.
const (
// DefaultVersion of the current REST API.
DefaultVersion = "1.45"
// MinSupportedAPIVersion is the minimum API version that can be supported
// by the API server, specified as "major.minor". Note that the daemon
// may be configured with a different minimum API version, as returned
// in [github.com/docker/docker/api/types.Version.MinAPIVersion].
//
// API requests for API versions lower than the configured version produce
// an error.
MinSupportedAPIVersion = "1.24"
// DefaultVersion of Current REST API
DefaultVersion = "1.44"
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.

View File

@@ -0,0 +1,34 @@
package server
import (
"net/http"
"github.com/docker/docker/api/server/httpstatus"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
"github.com/gorilla/mux"
"google.golang.org/grpc/status"
)
// makeErrorHandler makes an HTTP handler that decodes a Docker error and
// returns it in the response.
func makeErrorHandler(err error) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
statusCode := httpstatus.FromError(err)
vars := mux.Vars(r)
if apiVersionSupportsJSONErrors(vars["version"]) {
response := &types.ErrorResponse{
Message: err.Error(),
}
_ = httputils.WriteJSON(w, statusCode, response)
} else {
http.Error(w, status.Convert(err).Message(), statusCode)
}
}
}
func apiVersionSupportsJSONErrors(version string) bool {
const firstAPIVersionWithJSONErrors = "1.23"
return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors)
}

View File

@@ -12,4 +12,5 @@ import (
// container configuration.
type ContainerDecoder interface {
DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error)
DecodeHostConfig(src io.Reader) (*container.HostConfig, error)
}

View File

@@ -6,7 +6,6 @@ import (
"net/http"
"runtime"
"github.com/docker/docker/api"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types/versions"
)
@@ -14,40 +13,19 @@ import (
// VersionMiddleware is a middleware that
// validates the client and server versions.
type VersionMiddleware struct {
serverVersion string
// defaultAPIVersion is the default API version provided by the API server,
// specified as "major.minor". It is usually configured to the latest API
// version [github.com/docker/docker/api.DefaultVersion].
//
// API requests for API versions greater than this version are rejected by
// the server and produce a [versionUnsupportedError].
defaultAPIVersion string
// minAPIVersion is the minimum API version provided by the API server,
// specified as "major.minor".
//
// API requests for API versions lower than this version are rejected by
// the server and produce a [versionUnsupportedError].
minAPIVersion string
serverVersion string
defaultVersion string
minVersion string
}
// NewVersionMiddleware creates a VersionMiddleware with the given versions.
func NewVersionMiddleware(serverVersion, defaultAPIVersion, minAPIVersion string) (*VersionMiddleware, error) {
if versions.LessThan(defaultAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(defaultAPIVersion, api.DefaultVersion) {
return nil, fmt.Errorf("invalid default API version (%s): must be between %s and %s", defaultAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
// NewVersionMiddleware creates a new VersionMiddleware
// with the default versions.
func NewVersionMiddleware(s, d, m string) VersionMiddleware {
return VersionMiddleware{
serverVersion: s,
defaultVersion: d,
minVersion: m,
}
if versions.LessThan(minAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(minAPIVersion, api.DefaultVersion) {
return nil, fmt.Errorf("invalid minimum API version (%s): must be between %s and %s", minAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
}
if versions.GreaterThan(minAPIVersion, defaultAPIVersion) {
return nil, fmt.Errorf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", minAPIVersion, defaultAPIVersion)
}
return &VersionMiddleware{
serverVersion: serverVersion,
defaultAPIVersion: defaultAPIVersion,
minAPIVersion: minAPIVersion,
}, nil
}
type versionUnsupportedError struct {
@@ -67,18 +45,18 @@ func (e versionUnsupportedError) InvalidParameter() {}
func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
w.Header().Set("Server", fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS))
w.Header().Set("API-Version", v.defaultAPIVersion)
w.Header().Set("API-Version", v.defaultVersion)
w.Header().Set("OSType", runtime.GOOS)
apiVersion := vars["version"]
if apiVersion == "" {
apiVersion = v.defaultAPIVersion
apiVersion = v.defaultVersion
}
if versions.LessThan(apiVersion, v.minAPIVersion) {
return versionUnsupportedError{version: apiVersion, minVersion: v.minAPIVersion}
if versions.LessThan(apiVersion, v.minVersion) {
return versionUnsupportedError{version: apiVersion, minVersion: v.minVersion}
}
if versions.GreaterThan(apiVersion, v.defaultAPIVersion) {
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultAPIVersion}
if versions.GreaterThan(apiVersion, v.defaultVersion) {
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultVersion}
}
ctx = context.WithValue(ctx, httputils.APIVersionKey{}, apiVersion)
return handler(ctx, w, r, vars)

View File

@@ -2,82 +2,27 @@ package middleware // import "github.com/docker/docker/api/server/middleware"
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"runtime"
"testing"
"github.com/docker/docker/api"
"github.com/docker/docker/api/server/httputils"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestNewVersionMiddlewareValidation(t *testing.T) {
tests := []struct {
doc, defaultVersion, minVersion, expectedErr string
}{
{
doc: "defaults",
defaultVersion: api.DefaultVersion,
minVersion: api.MinSupportedAPIVersion,
},
{
doc: "invalid default lower than min",
defaultVersion: api.MinSupportedAPIVersion,
minVersion: api.DefaultVersion,
expectedErr: fmt.Sprintf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", api.DefaultVersion, api.MinSupportedAPIVersion),
},
{
doc: "invalid default too low",
defaultVersion: "0.1",
minVersion: api.MinSupportedAPIVersion,
expectedErr: fmt.Sprintf("invalid default API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
},
{
doc: "invalid default too high",
defaultVersion: "9999.9999",
minVersion: api.DefaultVersion,
expectedErr: fmt.Sprintf("invalid default API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
},
{
doc: "invalid minimum too low",
defaultVersion: api.MinSupportedAPIVersion,
minVersion: "0.1",
expectedErr: fmt.Sprintf("invalid minimum API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
},
{
doc: "invalid minimum too high",
defaultVersion: api.DefaultVersion,
minVersion: "9999.9999",
expectedErr: fmt.Sprintf("invalid minimum API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
},
}
for _, tc := range tests {
tc := tc
t.Run(tc.doc, func(t *testing.T) {
_, err := NewVersionMiddleware("1.2.3", tc.defaultVersion, tc.minVersion)
if tc.expectedErr == "" {
assert.Check(t, err)
} else {
assert.Check(t, is.Error(err, tc.expectedErr))
}
})
}
}
func TestVersionMiddlewareVersion(t *testing.T) {
expectedVersion := "<not set>"
defaultVersion := "1.10.0"
minVersion := "1.2.0"
expectedVersion := defaultVersion
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v := httputils.VersionFromContext(ctx)
assert.Check(t, is.Equal(expectedVersion, v))
return nil
}
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
assert.NilError(t, err)
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
h := m.WrapHandler(handler)
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
@@ -90,19 +35,19 @@ func TestVersionMiddlewareVersion(t *testing.T) {
errString string
}{
{
expectedVersion: api.DefaultVersion,
expectedVersion: "1.10.0",
},
{
reqVersion: api.MinSupportedAPIVersion,
expectedVersion: api.MinSupportedAPIVersion,
reqVersion: "1.9.0",
expectedVersion: "1.9.0",
},
{
reqVersion: "0.1",
errString: fmt.Sprintf("client version 0.1 is too old. Minimum supported API version is %s, please upgrade your client to a newer version", api.MinSupportedAPIVersion),
errString: "client version 0.1 is too old. Minimum supported API version is 1.2.0, please upgrade your client to a newer version",
},
{
reqVersion: "9999.9999",
errString: fmt.Sprintf("client version 9999.9999 is too new. Maximum supported API version is %s", api.DefaultVersion),
errString: "client version 9999.9999 is too new. Maximum supported API version is 1.10.0",
},
}
@@ -126,8 +71,9 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
return nil
}
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
assert.NilError(t, err)
defaultVersion := "1.10.0"
minVersion := "1.2.0"
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
h := m.WrapHandler(handler)
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
@@ -135,12 +81,12 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
ctx := context.Background()
vars := map[string]string{"version": "0.1"}
err = h(ctx, resp, req, vars)
err := h(ctx, resp, req, vars)
assert.Check(t, is.ErrorContains(err, ""))
hdr := resp.Result().Header
assert.Check(t, is.Contains(hdr.Get("Server"), "Docker/1.2.3"))
assert.Check(t, is.Contains(hdr.Get("Server"), "Docker/"+defaultVersion))
assert.Check(t, is.Contains(hdr.Get("Server"), runtime.GOOS))
assert.Check(t, is.Equal(hdr.Get("API-Version"), api.DefaultVersion))
assert.Check(t, is.Equal(hdr.Get("API-Version"), defaultVersion))
assert.Check(t, is.Equal(hdr.Get("OSType"), runtime.GOOS))
}

View File

@@ -42,7 +42,6 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
SuppressOutput: httputils.BoolValue(r, "q"),
NoCache: httputils.BoolValue(r, "nocache"),
ForceRemove: httputils.BoolValue(r, "forcerm"),
PullParent: httputils.BoolValue(r, "pull"),
MemorySwap: httputils.Int64ValueOrZero(r, "memswap"),
Memory: httputils.Int64ValueOrZero(r, "memory"),
CPUShares: httputils.Int64ValueOrZero(r, "cpushares"),
@@ -67,14 +66,17 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
return nil, invalidParam{errors.New("security options are not supported on " + runtime.GOOS)}
}
if httputils.BoolValue(r, "forcerm") {
version := httputils.VersionFromContext(ctx)
if httputils.BoolValue(r, "forcerm") && versions.GreaterThanOrEqualTo(version, "1.12") {
options.Remove = true
} else if r.FormValue("rm") == "" {
} else if r.FormValue("rm") == "" && versions.GreaterThanOrEqualTo(version, "1.12") {
options.Remove = true
} else {
options.Remove = httputils.BoolValue(r, "rm")
}
version := httputils.VersionFromContext(ctx)
if httputils.BoolValue(r, "pull") && versions.GreaterThanOrEqualTo(version, "1.16") {
options.PullParent = true
}
if versions.GreaterThanOrEqualTo(version, "1.32") {
options.Platform = r.FormValue("platform")
}

View File

@@ -24,6 +24,7 @@ type execBackend interface {
// copyBackend includes functions to implement to provide container copy functionality.
type copyBackend interface {
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
ContainerCopy(name string, res string) (io.ReadCloser, error)
ContainerExport(ctx context.Context, name string, out io.Writer) error
ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error
ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
@@ -38,7 +39,7 @@ type stateBackend interface {
ContainerResize(name string, height, width int) error
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
ContainerRm(name string, config *backend.ContainerRmConfig) error
ContainerStart(ctx context.Context, name string, checkpoint string, checkpointDir string) error
ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStop(ctx context.Context, name string, options container.StopOptions) error
ContainerUnpause(name string) error
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)

View File

@@ -56,6 +56,7 @@ func (r *containerRouter) initRoutes() {
router.NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait),
router.NewPostRoute("/containers/{name:.*}/resize", r.postContainersResize),
router.NewPostRoute("/containers/{name:.*}/attach", r.postContainersAttach),
router.NewPostRoute("/containers/{name:.*}/copy", r.postContainersCopy), // Deprecated since 1.8 (API v1.20), errors out since 1.12 (API v1.24)
router.NewPostRoute("/containers/{name:.*}/exec", r.postContainerExecCreate),
router.NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
router.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),

View File

@@ -39,6 +39,13 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
return err
}
// TODO: remove pause arg, and always pause in backend
pause := httputils.BoolValue(r, "pause")
version := httputils.VersionFromContext(ctx)
if r.FormValue("pause") == "" && versions.GreaterThanOrEqualTo(version, "1.13") {
pause = true
}
config, _, _, err := s.decoder.DecodeConfig(r.Body)
if err != nil && !errors.Is(err, io.EOF) { // Do not fail if body is empty.
return err
@@ -50,7 +57,7 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
}
imgID, err := s.backend.CreateImageFromContainer(ctx, r.Form.Get("container"), &backend.CreateImageConfig{
Pause: httputils.BoolValueOrDefault(r, "pause", true), // TODO(dnephin): remove pause arg, and always pause in backend
Pause: pause,
Tag: ref,
Author: r.Form.Get("author"),
Comment: r.Form.Get("comment"),
@@ -111,11 +118,14 @@ func (s *containerRouter) getContainersStats(ctx context.Context, w http.Respons
oneShot = httputils.BoolValueOrDefault(r, "one-shot", false)
}
return s.backend.ContainerStats(ctx, vars["name"], &backend.ContainerStatsConfig{
config := &backend.ContainerStatsConfig{
Stream: stream,
OneShot: oneShot,
OutStream: w,
})
Version: httputils.VersionFromContext(ctx),
}
return s.backend.ContainerStats(ctx, vars["name"], config)
}
func (s *containerRouter) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -168,6 +178,14 @@ func (s *containerRouter) getContainersExport(ctx context.Context, w http.Respon
return s.backend.ContainerExport(ctx, vars["name"], w)
}
type bodyOnStartError struct{}
func (bodyOnStartError) Error() string {
return "starting container with non-empty request body was deprecated since API v1.22 and removed in v1.24"
}
func (bodyOnStartError) InvalidParameter() {}
func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
// If contentLength is -1, we can assumed chunked encoding
// or more technically that the length is unknown
@@ -175,17 +193,33 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
// net/http otherwise seems to swallow any headers related to chunked encoding
// including r.TransferEncoding
// allow a nil body for backwards compatibility
//
version := httputils.VersionFromContext(ctx)
var hostConfig *container.HostConfig
// A non-nil json object is at least 7 characters.
if r.ContentLength > 7 || r.ContentLength == -1 {
return errdefs.InvalidParameter(errors.New("starting container with non-empty request body was deprecated since API v1.22 and removed in v1.24"))
if versions.GreaterThanOrEqualTo(version, "1.24") {
return bodyOnStartError{}
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
c, err := s.decoder.DecodeHostConfig(r.Body)
if err != nil {
return err
}
hostConfig = c
}
if err := httputils.ParseForm(r); err != nil {
return err
}
if err := s.backend.ContainerStart(ctx, vars["name"], r.Form.Get("checkpoint"), r.Form.Get("checkpoint-dir")); err != nil {
checkpoint := r.Form.Get("checkpoint")
checkpointDir := r.Form.Get("checkpoint-dir")
if err := s.backend.ContainerStart(ctx, vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
return err
}
@@ -221,14 +255,25 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
return nil
}
func (s *containerRouter) postContainersKill(_ context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}
name := vars["name"]
if err := s.backend.ContainerKill(name, r.Form.Get("signal")); err != nil {
return errors.Wrapf(err, "cannot kill container: %s", name)
var isStopped bool
if errdefs.IsConflict(err) {
isStopped = true
}
// Return error that's not caused because the container is stopped.
// Return error if the container is not running and the api is >= 1.20
// to keep backwards compatibility.
version := httputils.VersionFromContext(ctx)
if versions.GreaterThanOrEqualTo(version, "1.20") || !isStopped {
return errors.Wrapf(err, "Cannot kill container: %s", name)
}
}
w.WriteHeader(http.StatusNoContent)
@@ -467,6 +512,7 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
version := httputils.VersionFromContext(ctx)
adjustCPUShares := versions.LessThan(version, "1.19")
// When using API 1.24 and under, the client is responsible for removing the container
if versions.LessThan(version, "1.25") {
@@ -556,27 +602,17 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
hostConfig.Annotations = nil
}
defaultReadOnlyNonRecursive := false
if versions.LessThan(version, "1.44") {
if config.Healthcheck != nil {
// StartInterval was added in API 1.44
config.Healthcheck.StartInterval = 0
}
// Set ReadOnlyNonRecursive to true because it was added in API 1.44
// Before that all read-only mounts were non-recursive.
// Keep that behavior for clients on older APIs.
defaultReadOnlyNonRecursive = true
for _, m := range hostConfig.Mounts {
if m.Type == mount.TypeBind {
if m.BindOptions != nil && m.BindOptions.ReadOnlyForceRecursive {
// NOTE: that technically this is a breaking change for older
// API versions, and we should ignore the new field.
// However, this option may be incorrectly set by a client with
// the expectation that the failing to apply recursive read-only
// is enforced, so we decided to produce an error instead,
// instead of silently ignoring.
if m.BindOptions != nil {
// Ignore ReadOnlyNonRecursive because it was added in API 1.44.
m.BindOptions.ReadOnlyNonRecursive = false
if m.BindOptions.ReadOnlyForceRecursive {
return errdefs.InvalidParameter(errors.New("BindOptions.ReadOnlyForceRecursive needs API v1.44 or newer"))
}
}
@@ -592,14 +628,6 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
}
if versions.LessThan(version, "1.45") {
for _, m := range hostConfig.Mounts {
if m.VolumeOptions != nil && m.VolumeOptions.Subpath != "" {
return errdefs.InvalidParameter(errors.New("VolumeOptions.Subpath needs API v1.45 or newer"))
}
}
}
var warnings []string
if warn, err := handleMACAddressBC(config, hostConfig, networkingConfig, version); err != nil {
return err
@@ -616,12 +644,12 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
}
ccr, err := s.backend.ContainerCreate(ctx, backend.ContainerCreateConfig{
Name: name,
Config: config,
HostConfig: hostConfig,
NetworkingConfig: networkingConfig,
Platform: platform,
DefaultReadOnlyNonRecursive: defaultReadOnlyNonRecursive,
Name: name,
Config: config,
HostConfig: hostConfig,
NetworkingConfig: networkingConfig,
AdjustCPUShares: adjustCPUShares,
Platform: platform,
})
if err != nil {
return err
@@ -634,73 +662,42 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
// networkingConfig to set the endpoint-specific MACAddress field introduced in API v1.44. It returns a warning message
// or an error if the container-wide field was specified for API >= v1.44.
func handleMACAddressBC(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, version string) (string, error) {
if config.MacAddress == "" { //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
return "", nil
}
deprecatedMacAddress := config.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
// For older versions of the API, migrate the container-wide MAC address to EndpointsConfig.
if versions.LessThan(version, "1.44") {
if deprecatedMacAddress == "" {
// If a MAC address is supplied in EndpointsConfig, discard it because the old API
// would have ignored it.
for _, ep := range networkingConfig.EndpointsConfig {
ep.MacAddress = ""
// The container-wide MacAddress parameter is deprecated and should now be specified in EndpointsConfig.
if hostConfig.NetworkMode.IsDefault() || hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
nwName := hostConfig.NetworkMode.NetworkName()
if _, ok := networkingConfig.EndpointsConfig[nwName]; !ok {
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{}
}
return "", nil
// Overwrite the config: either the endpoint's MacAddress was set by the user on API < v1.44, which
// must be ignored, or migrate the top-level MacAddress to the endpoint's config.
networkingConfig.EndpointsConfig[nwName].MacAddress = deprecatedMacAddress
}
if !hostConfig.NetworkMode.IsDefault() && !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
return "", runconfig.ErrConflictContainerNetworkAndMac
}
// There cannot be more than one entry in EndpointsConfig with API < 1.44.
// If there's no EndpointsConfig, create a place to store the configured address. It is
// safe to use NetworkMode as the network name, whether it's a name or id/short-id, as
// it will be normalised later and there is no other EndpointSettings object that might
// refer to this network/endpoint.
if len(networkingConfig.EndpointsConfig) == 0 {
nwName := hostConfig.NetworkMode.NetworkName()
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{}
}
// There's exactly one network in EndpointsConfig, either from the API or just-created.
// Migrate the container-wide setting to it.
// No need to check for a match between NetworkMode and the names/ids in EndpointsConfig,
// the old version of the API would have applied the address to this network anyway.
for _, ep := range networkingConfig.EndpointsConfig {
ep.MacAddress = deprecatedMacAddress
}
return "", nil
}
// The container-wide MacAddress parameter is deprecated and should now be specified in EndpointsConfig.
if deprecatedMacAddress == "" {
return "", nil
}
var warning string
if hostConfig.NetworkMode.IsDefault() || hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
nwName := hostConfig.NetworkMode.NetworkName()
// If there's no endpoint config, create a place to store the configured address.
if len(networkingConfig.EndpointsConfig) == 0 {
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{
MacAddress: deprecatedMacAddress,
}
} else {
// There is existing endpoint config - if it's not indexed by NetworkMode.Name(), we
// can't tell which network the container-wide settings was intended for. NetworkMode,
// the keys in EndpointsConfig and the NetworkID in EndpointsConfig may mix network
// name/id/short-id. It's not safe to create EndpointsConfig under the NetworkMode
// name to store the container-wide MAC address, because that may result in two sets
// of EndpointsConfig for the same network and one set will be discarded later. So,
// reject the request ...
ep, ok := networkingConfig.EndpointsConfig[nwName]
if !ok {
return "", errdefs.InvalidParameter(errors.New("if a container-wide MAC address is supplied, HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks"))
}
// ep is the endpoint that needs the container-wide MAC address; migrate the address
// to it, or bail out if there's a mismatch.
if ep.MacAddress == "" {
ep.MacAddress = deprecatedMacAddress
} else if ep.MacAddress != deprecatedMacAddress {
return "", errdefs.InvalidParameter(errors.New("the container-wide MAC address must match the endpoint-specific MAC address for the main network, or be left empty"))
}
if _, ok := networkingConfig.EndpointsConfig[nwName]; !ok {
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{}
}
ep := networkingConfig.EndpointsConfig[nwName]
if ep.MacAddress == "" {
ep.MacAddress = deprecatedMacAddress
} else if ep.MacAddress != deprecatedMacAddress {
return "", errdefs.InvalidParameter(errors.New("the container-wide MAC address should match the endpoint-specific MAC address for the main network or should be left empty"))
}
}
warning = "The container-wide MacAddress field is now deprecated. It should be specified in EndpointsConfig instead."

View File

@@ -1,160 +0,0 @@
package container
import (
"testing"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestHandleMACAddressBC(t *testing.T) {
testcases := []struct {
name string
apiVersion string
ctrWideMAC string
networkMode container.NetworkMode
epConfig map[string]*network.EndpointSettings
expEpWithCtrWideMAC string
expEpWithNoMAC string
expCtrWideMAC string
expWarning string
expError string
}{
{
name: "old api ctr-wide mac mix id and name",
apiVersion: "1.43",
ctrWideMAC: "11:22:33:44:55:66",
networkMode: "aNetId",
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
expEpWithCtrWideMAC: "aNetName",
expCtrWideMAC: "11:22:33:44:55:66",
},
{
name: "old api clear ep mac",
apiVersion: "1.43",
networkMode: "aNetId",
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "11:22:33:44:55:66"}},
expEpWithNoMAC: "aNetName",
},
{
name: "old api no-network ctr-wide mac",
apiVersion: "1.43",
networkMode: "none",
ctrWideMAC: "11:22:33:44:55:66",
expError: "conflicting options: mac-address and the network mode",
expCtrWideMAC: "11:22:33:44:55:66",
},
{
name: "old api create ep",
apiVersion: "1.43",
networkMode: "aNetId",
ctrWideMAC: "11:22:33:44:55:66",
epConfig: map[string]*network.EndpointSettings{},
expEpWithCtrWideMAC: "aNetId",
expCtrWideMAC: "11:22:33:44:55:66",
},
{
name: "old api migrate ctr-wide mac",
apiVersion: "1.43",
ctrWideMAC: "11:22:33:44:55:66",
networkMode: "aNetName",
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
expEpWithCtrWideMAC: "aNetName",
expCtrWideMAC: "11:22:33:44:55:66",
},
{
name: "new api no macs",
apiVersion: "1.44",
networkMode: "aNetId",
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
},
{
name: "new api ep specific mac",
apiVersion: "1.44",
networkMode: "aNetName",
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "11:22:33:44:55:66"}},
},
{
name: "new api migrate ctr-wide mac to new ep",
apiVersion: "1.44",
ctrWideMAC: "11:22:33:44:55:66",
networkMode: "aNetName",
epConfig: map[string]*network.EndpointSettings{},
expEpWithCtrWideMAC: "aNetName",
expWarning: "The container-wide MacAddress field is now deprecated",
expCtrWideMAC: "",
},
{
name: "new api migrate ctr-wide mac to existing ep",
apiVersion: "1.44",
ctrWideMAC: "11:22:33:44:55:66",
networkMode: "aNetName",
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
expEpWithCtrWideMAC: "aNetName",
expWarning: "The container-wide MacAddress field is now deprecated",
expCtrWideMAC: "",
},
{
name: "new api mode vs name mismatch",
apiVersion: "1.44",
ctrWideMAC: "11:22:33:44:55:66",
networkMode: "aNetId",
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
expError: "if a container-wide MAC address is supplied, HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks",
expCtrWideMAC: "11:22:33:44:55:66",
},
{
name: "new api mac mismatch",
apiVersion: "1.44",
ctrWideMAC: "11:22:33:44:55:66",
networkMode: "aNetName",
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "00:11:22:33:44:55"}},
expError: "the container-wide MAC address must match the endpoint-specific MAC address",
expCtrWideMAC: "11:22:33:44:55:66",
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
cfg := &container.Config{
MacAddress: tc.ctrWideMAC, //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
}
hostCfg := &container.HostConfig{
NetworkMode: tc.networkMode,
}
epConfig := make(map[string]*network.EndpointSettings, len(tc.epConfig))
for k, v := range tc.epConfig {
v := v
epConfig[k] = v
}
netCfg := &network.NetworkingConfig{
EndpointsConfig: epConfig,
}
warning, err := handleMACAddressBC(cfg, hostCfg, netCfg, tc.apiVersion)
if tc.expError == "" {
assert.Check(t, err)
} else {
assert.Check(t, is.ErrorContains(err, tc.expError))
}
if tc.expWarning == "" {
assert.Check(t, is.Equal(warning, ""))
} else {
assert.Check(t, is.Contains(warning, tc.expWarning))
}
if tc.expEpWithCtrWideMAC != "" {
got := netCfg.EndpointsConfig[tc.expEpWithCtrWideMAC].MacAddress
assert.Check(t, is.Equal(got, tc.ctrWideMAC))
}
if tc.expEpWithNoMAC != "" {
got := netCfg.EndpointsConfig[tc.expEpWithNoMAC].MacAddress
assert.Check(t, is.Equal(got, ""))
}
gotCtrWideMAC := cfg.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
assert.Check(t, is.Equal(gotCtrWideMAC, tc.expCtrWideMAC))
})
}
}

View File

@@ -11,10 +11,49 @@ import (
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
gddohttputil "github.com/golang/gddo/httputil"
)
// setContainerPathStatHeader encodes the stat to JSON, base64 encode, and place in a header.
type pathError struct{}
func (pathError) Error() string {
return "Path cannot be empty"
}
func (pathError) InvalidParameter() {}
// postContainersCopy is deprecated in favor of getContainersArchive.
//
// Deprecated since 1.8 (API v1.20), errors out since 1.12 (API v1.24)
func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
version := httputils.VersionFromContext(ctx)
if versions.GreaterThanOrEqualTo(version, "1.24") {
w.WriteHeader(http.StatusNotFound)
return nil
}
cfg := types.CopyConfig{}
if err := httputils.ReadJSON(r, &cfg); err != nil {
return err
}
if cfg.Resource == "" {
return pathError{}
}
data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
if err != nil {
return err
}
defer data.Close()
w.Header().Set("Content-Type", "application/x-tar")
_, err = io.Copy(w, data)
return err
}
// // Encode the stat to JSON, base64 encode, and place in a header.
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
statJSON, err := json.Marshal(stat)
if err != nil {

View File

@@ -71,6 +71,15 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
return err
}
version := httputils.VersionFromContext(ctx)
if versions.LessThan(version, "1.22") {
// API versions before 1.22 did not enforce application/json content-type.
// Allow older clients to work by patching the content-type.
if r.Header.Get("Content-Type") != "application/json" {
r.Header.Set("Content-Type", "application/json")
}
}
var (
execName = vars["name"]
stdin, inStream io.ReadCloser
@@ -87,8 +96,6 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
}
if execStartCheck.ConsoleSize != nil {
version := httputils.VersionFromContext(ctx)
// Not supported before 1.42
if versions.LessThan(version, "1.42") {
execStartCheck.ConsoleSize = nil

View File

@@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"net/http"
"os"
"github.com/distribution/reference"
"github.com/docker/distribution"
@@ -13,7 +12,6 @@ import (
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types/registry"
distributionpkg "github.com/docker/docker/distribution"
"github.com/docker/docker/errdefs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@@ -26,10 +24,10 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
w.Header().Set("Content-Type", "application/json")
imgName := vars["name"]
image := vars["name"]
// TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors?
ref, err := reference.ParseAnyReference(imgName)
ref, err := reference.ParseAnyReference(image)
if err != nil {
return errdefs.InvalidParameter(err)
}
@@ -39,7 +37,7 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
// full image ID
return errors.Errorf("no manifest found for full image ID")
}
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", imgName))
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image))
}
// For a search it is not an error if no auth was given. Ignore invalid
@@ -155,9 +153,6 @@ func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distrib
}
}
case *schema1.SignedManifest:
if os.Getenv("DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE") == "" {
return registry.DistributionInspect{}, distributionpkg.DeprecatedSchema1ImageError(namedRef)
}
platform := ocispec.Platform{
Architecture: mnfstObj.Architecture,
OS: "linux",

View File

@@ -21,7 +21,7 @@ type grpcRouter struct {
// NewRouter initializes a new grpc http router
func NewRouter(backends ...Backend) router.Router {
unary := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptor(), grpcerrors.UnaryServerInterceptor))
stream := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(otelgrpc.StreamServerInterceptor(), grpcerrors.StreamServerInterceptor)) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
stream := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(otelgrpc.StreamServerInterceptor(), grpcerrors.StreamServerInterceptor))
r := &grpcRouter{
h2Server: &http2.Server{},
@@ -46,7 +46,7 @@ func (gr *grpcRouter) initRoutes() {
}
func unaryInterceptor() grpc.UnaryServerInterceptor {
withTrace := otelgrpc.UnaryServerInterceptor() //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
withTrace := otelgrpc.UnaryServerInterceptor()
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// This method is used by the clients to send their traces to buildkit so they can be included

View File

@@ -6,7 +6,6 @@ import (
"github.com/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/registry"
@@ -25,8 +24,8 @@ type Backend interface {
type imageBackend interface {
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]image.DeleteResponse, error)
ImageHistory(ctx context.Context, imageName string) ([]*image.HistoryResponseItem, error)
Images(ctx context.Context, opts image.ListOptions) ([]*image.Summary, error)
GetImage(ctx context.Context, refOrID string, options backend.GetImageOpts) (*dockerimage.Image, error)
Images(ctx context.Context, opts types.ImageListOptions) ([]*image.Summary, error)
GetImage(ctx context.Context, refOrID string, options image.GetImageOpts) (*dockerimage.Image, error)
TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
}

View File

@@ -15,9 +15,8 @@ import (
"github.com/docker/docker/api"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/filters"
imagetypes "github.com/docker/docker/api/types/image"
opts "github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/builder/remotecontext"
@@ -73,9 +72,9 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
// Special case: "pull -a" may send an image name with a
// trailing :. This is ugly, but let's not break API
// compatibility.
imgName := strings.TrimSuffix(img, ":")
image := strings.TrimSuffix(img, ":")
ref, err := reference.ParseNormalizedNamed(imgName)
ref, err := reference.ParseNormalizedNamed(image)
if err != nil {
return errdefs.InvalidParameter(err)
}
@@ -190,7 +189,7 @@ func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter
var ref reference.Named
// Tag is empty only in case PushOptions.All is true.
// Tag is empty only in case ImagePushOptions.All is true.
if tag != "" {
r, err := httputils.RepoTagReference(img, tag)
if err != nil {
@@ -286,7 +285,7 @@ func (ir *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter,
}
func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
img, err := ir.backend.GetImage(ctx, vars["name"], backend.GetImageOpts{Details: true})
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{Details: true})
if err != nil {
return err
}
@@ -299,16 +298,6 @@ func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWrite
version := httputils.VersionFromContext(ctx)
if versions.LessThan(version, "1.44") {
imageInspect.VirtualSize = imageInspect.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
if imageInspect.Created == "" {
// backwards compatibility for Created not existing returning "0001-01-01T00:00:00Z"
// https://github.com/moby/moby/issues/47368
imageInspect.Created = time.Time{}.Format(time.RFC3339Nano)
}
}
if versions.GreaterThanOrEqualTo(version, "1.45") {
imageInspect.Container = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
imageInspect.ContainerConfig = nil //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
}
return httputils.WriteJSON(w, http.StatusOK, imageInspect)
}
@@ -364,7 +353,7 @@ func (ir *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, er
Data: img.Details.Metadata,
},
RootFS: rootFSToAPIType(img.RootFS),
Metadata: imagetypes.Metadata{
Metadata: opts.Metadata{
LastTagTime: img.Details.LastUpdated,
},
}, nil
@@ -406,7 +395,7 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
sharedSize = httputils.BoolValue(r, "shared-size")
}
images, err := ir.backend.Images(ctx, imagetypes.ListOptions{
images, err := ir.backend.Images(ctx, types.ImageListOptions{
All: httputils.BoolValue(r, "all"),
Filters: imageFilters,
SharedSize: sharedSize,
@@ -463,7 +452,7 @@ func (ir *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
return errdefs.InvalidParameter(errors.New("refusing to create an ambiguous tag using digest algorithm as name"))
}
img, err := ir.backend.GetImage(ctx, vars["name"], backend.GetImageOpts{})
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{})
if err != nil {
return errdefs.NotFound(err)
}

View File

@@ -213,10 +213,6 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
return libnetwork.NetworkNameError(create.Name)
}
// For a Swarm-scoped network, this call to backend.CreateNetwork is used to
// validate the configuration. The network will not be created but, if the
// configuration is valid, ManagerRedirectError will be returned and handled
// below.
nw, err := n.backend.CreateNetwork(create)
if err != nil {
if _, ok := err.(libnetwork.ManagerRedirectError); !ok {

View File

@@ -10,7 +10,6 @@ import (
"github.com/docker/docker/api/server/middleware"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/api/server/router/debug"
"github.com/docker/docker/api/types"
"github.com/docker/docker/dockerversion"
"github.com/gorilla/mux"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
@@ -58,13 +57,19 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) ht
if statusCode >= 500 {
log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
}
_ = httputils.WriteJSON(w, statusCode, &types.ErrorResponse{
Message: err.Error(),
})
makeErrorHandler(err)(w, r)
}
}), operation).ServeHTTP
}
type pageNotFoundError struct{}
func (pageNotFoundError) Error() string {
return "page not found"
}
func (pageNotFoundError) NotFound() {}
// CreateMux returns a new mux with all the routers registered.
func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
m := mux.NewRouter()
@@ -86,12 +91,7 @@ func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
m.Path("/debug" + r.Path()).Handler(f)
}
notFoundHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = httputils.WriteJSON(w, http.StatusNotFound, &types.ErrorResponse{
Message: "page not found",
})
})
notFoundHandler := makeErrorHandler(pageNotFoundError{})
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
m.NotFoundHandler = notFoundHandler
m.MethodNotAllowedHandler = notFoundHandler

View File

@@ -15,11 +15,8 @@ import (
func TestMiddlewares(t *testing.T) {
srv := &Server{}
m, err := middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinSupportedAPIVersion)
if err != nil {
t.Fatal(err)
}
srv.UseMiddleware(*m)
const apiMinVersion = "1.12"
srv.UseMiddleware(middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, apiMinVersion))
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
resp := httptest.NewRecorder()

View File

@@ -19,10 +19,10 @@ produces:
consumes:
- "application/json"
- "text/plain"
basePath: "/v1.45"
basePath: "/v1.44"
info:
title: "Docker Engine API"
version: "1.45"
version: "1.44"
x-logo:
url: "https://docs.docker.com/assets/images/logo-docker-main.png"
description: |
@@ -55,8 +55,8 @@ info:
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
is returned.
If you omit the version-prefix, the current version of the API (v1.45) is used.
For example, calling `/info` is the same as calling `/v1.45/info`. Using the
If you omit the version-prefix, the current version of the API (v1.44) is used.
For example, calling `/info` is the same as calling `/v1.44/info`. Using the
API without a version-prefix is deprecated and will be removed in a future release.
Engine releases in the near future should support this version of the API,
@@ -391,11 +391,7 @@ definitions:
ReadOnlyNonRecursive:
description: |
Make the mount non-recursively read-only, but still leave the mount recursive
(unless NonRecursive is set to `true` in conjunction).
Addded in v1.44, before that version all read-only mounts were
non-recursive by default. To match the previous behaviour this
will default to `true` for clients on versions prior to v1.44.
(unless NonRecursive is set to true in conjunction).
type: "boolean"
default: false
ReadOnlyForceRecursive:
@@ -427,10 +423,6 @@ definitions:
type: "object"
additionalProperties:
type: "string"
Subpath:
description: "Source path inside the volume. Must be relative without any back traversals."
type: "string"
example: "dir-inside-volume/subdirectory"
TmpfsOptions:
description: "Optional configuration for the `tmpfs` type."
type: "object"
@@ -1751,12 +1743,8 @@ definitions:
description: |
Date and time at which the image was created, formatted in
[RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds.
This information is only available if present in the image,
and omitted otherwise.
type: "string"
format: "dateTime"
x-nullable: true
x-nullable: false
example: "2022-02-04T21:20:12.497794809Z"
Container:
description: |
@@ -8774,7 +8762,8 @@ paths:
<p><br /></p>
> **Deprecated**: This field is deprecated and will always be "false".
> **Deprecated**: This field is deprecated and will always
> be "false" in future.
type: "boolean"
example: false
name:
@@ -8817,8 +8806,13 @@ paths:
description: |
A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
- `is-automated=(true|false)` (deprecated, see below)
- `is-official=(true|false)`
- `stars=<number>` Matches images that has at least 'number' stars.
The `is-automated` filter is deprecated. The `is_automated` field has
been deprecated by Docker Hub's search API. Consequently, searching
for `is-automated=true` will yield no results.
type: "string"
tags: ["Image"]
/images/prune:

View File

@@ -13,12 +13,12 @@ import (
// ContainerCreateConfig is the parameter set to ContainerCreate()
type ContainerCreateConfig struct {
Name string
Config *container.Config
HostConfig *container.HostConfig
NetworkingConfig *network.NetworkingConfig
Platform *ocispec.Platform
DefaultReadOnlyNonRecursive bool
Name string
Config *container.Config
HostConfig *container.HostConfig
NetworkingConfig *network.NetworkingConfig
Platform *ocispec.Platform
AdjustCPUShares bool
}
// ContainerRmConfig holds arguments for the container remove
@@ -90,6 +90,7 @@ type ContainerStatsConfig struct {
Stream bool
OneShot bool
OutStream io.Writer
Version string
}
// ExecInspect holds information about a running process started
@@ -129,13 +130,6 @@ type CreateImageConfig struct {
Changes []string
}
// GetImageOpts holds parameters to retrieve image information
// from the backend.
type GetImageOpts struct {
Platform *ocispec.Platform
Details bool
}
// CommitConfig is the configuration for creating an image as part of a build.
type CommitConfig struct {
Author string

View File

@@ -157,12 +157,42 @@ type ImageBuildResponse struct {
OSType string
}
// ImageCreateOptions holds information to create images.
type ImageCreateOptions struct {
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
}
// ImageImportSource holds source information for ImageImport
type ImageImportSource struct {
Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
}
// ImageImportOptions holds information to import images from the client host.
type ImageImportOptions struct {
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
Message string // Message is the message to tag the image with
Changes []string // Changes are the raw changes to apply to this image
Platform string // Platform is the target platform of the image
}
// ImageListOptions holds parameters to list images with.
type ImageListOptions struct {
// All controls whether all images in the graph are filtered, or just
// the heads.
All bool
// Filters is a JSON-encoded set of filter arguments.
Filters filters.Args
// SharedSize indicates whether the shared size of images should be computed.
SharedSize bool
// ContainerCount indicates whether container count should be computed.
ContainerCount bool
}
// ImageLoadResponse returns information to the client about a load process.
type ImageLoadResponse struct {
// Body must be closed to avoid a resource leak
@@ -170,6 +200,14 @@ type ImageLoadResponse struct {
JSON bool
}
// ImagePullOptions holds information to pull images.
type ImagePullOptions struct {
All bool
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
PrivilegeFunc RequestPrivilegeFunc
Platform string
}
// RequestPrivilegeFunc is a function interface that
// clients can supply to retry operations after
// getting an authorization error.
@@ -178,6 +216,15 @@ type ImageLoadResponse struct {
// if the privilege request fails.
type RequestPrivilegeFunc func() (string, error)
// ImagePushOptions holds information to push images.
type ImagePushOptions ImagePullOptions
// ImageRemoveOptions holds parameters to remove images.
type ImageRemoveOptions struct {
Force bool
PruneChildren bool
}
// ImageSearchOptions holds parameters to search images with.
type ImageSearchOptions struct {
RegistryAuth string

View File

@@ -5,8 +5,8 @@ import (
"time"
"github.com/docker/docker/api/types/strslice"
dockerspec "github.com/docker/docker/image/spec/specs-go/v1"
"github.com/docker/go-connections/nat"
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
)
// MinimumDuration puts a minimum on user configured duration.

View File

@@ -1,57 +1,9 @@
package image
import "github.com/docker/docker/api/types/filters"
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
// ImportOptions holds information to import images from the client host.
type ImportOptions struct {
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
Message string // Message is the message to tag the image with
Changes []string // Changes are the raw changes to apply to this image
Platform string // Platform is the target platform of the image
}
// CreateOptions holds information to create images.
type CreateOptions struct {
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
}
// PullOptions holds information to pull images.
type PullOptions struct {
All bool
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
// PrivilegeFunc is a function that clients can supply to retry operations
// after getting an authorization error. This function returns the registry
// authentication header value in base64 encoded format, or an error if the
// privilege request fails.
//
// Also see [github.com/docker/docker/api/types.RequestPrivilegeFunc].
PrivilegeFunc func() (string, error)
Platform string
}
// PushOptions holds information to push images.
type PushOptions PullOptions
// ListOptions holds parameters to list images with.
type ListOptions struct {
// All controls whether all images in the graph are filtered, or just
// the heads.
All bool
// Filters is a JSON-encoded set of filter arguments.
Filters filters.Args
// SharedSize indicates whether the shared size of images should be computed.
SharedSize bool
// ContainerCount indicates whether container count should be computed.
ContainerCount bool
}
// RemoveOptions holds parameters to remove images.
type RemoveOptions struct {
Force bool
PruneChildren bool
// GetImageOpts holds parameters to inspect an image.
type GetImageOpts struct {
Platform *ocispec.Platform
Details bool
}

View File

@@ -96,7 +96,6 @@ type BindOptions struct {
type VolumeOptions struct {
NoCopy bool `json:",omitempty"`
Labels map[string]string `json:",omitempty"`
Subpath string `json:",omitempty"`
DriverConfig *Driver `json:",omitempty"`
}

View File

@@ -94,7 +94,7 @@ type SearchResult struct {
Name string `json:"name"`
// IsAutomated indicates whether the result is automated.
//
// Deprecated: the "is_automated" field is deprecated and will always be "false".
// Deprecated: the "is_automated" field is deprecated and will always be "false" in the future.
IsAutomated bool `json:"is_automated"`
// Description is a textual description of the repository
Description string `json:"description"`

View File

@@ -72,17 +72,14 @@ type ImageInspect struct {
// Created is the date and time at which the image was created, formatted in
// RFC 3339 nano-seconds (time.RFC3339Nano).
//
// This information is only available if present in the image,
// and omitted otherwise.
Created string `json:",omitempty"`
Created string
// Container is the ID of the container that was used to create the image.
//
// Depending on how the image was created, this field may be empty.
//
// Deprecated: this field is omitted in API v1.45, but kept for backward compatibility.
Container string `json:",omitempty"`
Container string
// ContainerConfig is an optional field containing the configuration of the
// container that was last committed when creating the image.
@@ -91,7 +88,7 @@ type ImageInspect struct {
// and it is not in active use anymore.
//
// Deprecated: this field is omitted in API v1.45, but kept for backward compatibility.
ContainerConfig *container.Config `json:",omitempty"`
ContainerConfig *container.Config
// DockerVersion is the version of Docker that was used to build the image.
//

View File

@@ -1,35 +1,138 @@
package types
import (
"github.com/docker/docker/api/types/checkpoint"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
)
// ImageImportOptions holds information to import images from the client host.
// CheckpointCreateOptions holds parameters to create a checkpoint from a container.
//
// Deprecated: use [image.ImportOptions].
type ImageImportOptions = image.ImportOptions
// Deprecated: use [checkpoint.CreateOptions].
type CheckpointCreateOptions = checkpoint.CreateOptions
// ImageCreateOptions holds information to create images.
// CheckpointListOptions holds parameters to list checkpoints for a container
//
// Deprecated: use [image.CreateOptions].
type ImageCreateOptions = image.CreateOptions
// Deprecated: use [checkpoint.ListOptions].
type CheckpointListOptions = checkpoint.ListOptions
// ImagePullOptions holds information to pull images.
// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container
//
// Deprecated: use [image.PullOptions].
type ImagePullOptions = image.PullOptions
// Deprecated: use [checkpoint.DeleteOptions].
type CheckpointDeleteOptions = checkpoint.DeleteOptions
// ImagePushOptions holds information to push images.
// Checkpoint represents the details of a checkpoint when listing endpoints.
//
// Deprecated: use [image.PushOptions].
type ImagePushOptions = image.PushOptions
// Deprecated: use [checkpoint.Summary].
type Checkpoint = checkpoint.Summary
// ImageListOptions holds parameters to list images with.
// Info contains response of Engine API:
// GET "/info"
//
// Deprecated: use [image.ListOptions].
type ImageListOptions = image.ListOptions
// Deprecated: use [system.Info].
type Info = system.Info
// ImageRemoveOptions holds parameters to remove images.
// Commit holds the Git-commit (SHA1) that a binary was built from, as reported
// in the version-string of external tools, such as containerd, or runC.
//
// Deprecated: use [image.RemoveOptions].
type ImageRemoveOptions = image.RemoveOptions
// Deprecated: use [system.Commit].
type Commit = system.Commit
// PluginsInfo is a temp struct holding Plugins name
// registered with docker daemon. It is used by [system.Info] struct
//
// Deprecated: use [system.PluginsInfo].
type PluginsInfo = system.PluginsInfo
// NetworkAddressPool is a temp struct used by [system.Info] struct.
//
// Deprecated: use [system.NetworkAddressPool].
type NetworkAddressPool = system.NetworkAddressPool
// Runtime describes an OCI runtime.
//
// Deprecated: use [system.Runtime].
type Runtime = system.Runtime
// SecurityOpt contains the name and options of a security option.
//
// Deprecated: use [system.SecurityOpt].
type SecurityOpt = system.SecurityOpt
// KeyValue holds a key/value pair.
//
// Deprecated: use [system.KeyValue].
type KeyValue = system.KeyValue
// ImageDeleteResponseItem image delete response item.
//
// Deprecated: use [image.DeleteResponse].
type ImageDeleteResponseItem = image.DeleteResponse
// ImageSummary image summary.
//
// Deprecated: use [image.Summary].
type ImageSummary = image.Summary
// ImageMetadata contains engine-local data about the image.
//
// Deprecated: use [image.Metadata].
type ImageMetadata = image.Metadata
// ServiceCreateResponse contains the information returned to a client
// on the creation of a new service.
//
// Deprecated: use [swarm.ServiceCreateResponse].
type ServiceCreateResponse = swarm.ServiceCreateResponse
// ServiceUpdateResponse service update response.
//
// Deprecated: use [swarm.ServiceUpdateResponse].
type ServiceUpdateResponse = swarm.ServiceUpdateResponse
// ContainerStartOptions holds parameters to start containers.
//
// Deprecated: use [container.StartOptions].
type ContainerStartOptions = container.StartOptions
// ResizeOptions holds parameters to resize a TTY.
// It can be used to resize container TTYs and
// exec process TTYs too.
//
// Deprecated: use [container.ResizeOptions].
type ResizeOptions = container.ResizeOptions
// ContainerAttachOptions holds parameters to attach to a container.
//
// Deprecated: use [container.AttachOptions].
type ContainerAttachOptions = container.AttachOptions
// ContainerCommitOptions holds parameters to commit changes into a container.
//
// Deprecated: use [container.CommitOptions].
type ContainerCommitOptions = container.CommitOptions
// ContainerListOptions holds parameters to list containers with.
//
// Deprecated: use [container.ListOptions].
type ContainerListOptions = container.ListOptions
// ContainerLogsOptions holds parameters to filter logs with.
//
// Deprecated: use [container.LogsOptions].
type ContainerLogsOptions = container.LogsOptions
// ContainerRemoveOptions holds parameters to remove containers.
//
// Deprecated: use [container.RemoveOptions].
type ContainerRemoveOptions = container.RemoveOptions
// DecodeSecurityOptions decodes a security options string slice to a type safe
// [system.SecurityOpt].
//
// Deprecated: use [system.DecodeSecurityOptions].
func DecodeSecurityOptions(opts []string) ([]system.SecurityOpt, error) {
return system.DecodeSecurityOptions(opts)
}

View File

@@ -0,0 +1,14 @@
# Legacy API type versions
This package includes types for legacy API versions. The stable version of the API types live in `api/types/*.go`.
Consider moving a type here when you need to keep backwards compatibility in the API. This legacy types are organized by the latest API version they appear in. For instance, types in the `v1p19` package are valid for API versions below or equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, since the versions below that will use the legacy types in `v1p19`.
## Package name conventions
The package name convention is to use `v` as a prefix for the version number and `p`(patch) as a separator. We use this nomenclature due to a few restrictions in the Go package name convention:
1. We cannot use `.` because it's interpreted by the language, think of `v1.20.CallFunction`.
2. We cannot use `_` because golint complains about it. The code is actually valid, but it looks probably more weird: `v1_20.CallFunction`.
For instance, if you want to modify a type that was available in the version `1.21` of the API but it will have different fields in the version `1.22`, you want to create a new package under `api/types/versions/v1p21`.

View File

@@ -0,0 +1,35 @@
// Package v1p19 provides specific API types for the API version 1, patch 19.
package v1p19 // import "github.com/docker/docker/api/types/versions/v1p19"
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions/v1p20"
"github.com/docker/go-connections/nat"
)
// ContainerJSON is a backcompatibility struct for APIs prior to 1.20.
// Note this is not used by the Windows daemon.
type ContainerJSON struct {
*types.ContainerJSONBase
Volumes map[string]string
VolumesRW map[string]bool
Config *ContainerConfig
NetworkSettings *v1p20.NetworkSettings
}
// ContainerConfig is a backcompatibility struct for APIs prior to 1.20.
type ContainerConfig struct {
*container.Config
MacAddress string
NetworkDisabled bool
ExposedPorts map[nat.Port]struct{}
// backward compatibility, they now live in HostConfig
VolumeDriver string
Memory int64
MemorySwap int64
CPUShares int64 `json:"CpuShares"`
CPUSet string `json:"Cpuset"`
}

View File

@@ -0,0 +1,40 @@
// Package v1p20 provides specific API types for the API version 1, patch 20.
package v1p20 // import "github.com/docker/docker/api/types/versions/v1p20"
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
)
// ContainerJSON is a backcompatibility struct for the API 1.20
type ContainerJSON struct {
*types.ContainerJSONBase
Mounts []types.MountPoint
Config *ContainerConfig
NetworkSettings *NetworkSettings
}
// ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20
type ContainerConfig struct {
*container.Config
MacAddress string
NetworkDisabled bool
ExposedPorts map[nat.Port]struct{}
// backward compatibility, they now live in HostConfig
VolumeDriver string
}
// StatsJSON is a backcompatibility struct used in Stats for APIs prior to 1.21
type StatsJSON struct {
types.Stats
Network types.NetworkStats `json:"network,omitempty"`
}
// NetworkSettings is a backward compatible struct for APIs prior to 1.21
type NetworkSettings struct {
types.NetworkSettingsBase
types.DefaultNetworkSettings
}

View File

@@ -238,13 +238,13 @@ type TopologyRequirement struct {
// If requisite is specified, all topologies in preferred list MUST
// also be present in the list of requisite topologies.
//
// If the SP is unable to make the provisioned volume available
// If the SP is unable to to make the provisioned volume available
// from any of the preferred topologies, the SP MAY choose a topology
// from the list of requisite topologies.
// If the list of requisite topologies is not specified, then the SP
// MAY choose from the list of all possible topologies.
// If the list of requisite topologies is specified and the SP is
// unable to make the provisioned volume available from any of the
// unable to to make the provisioned volume available from any of the
// requisite topologies it MUST fail the CreateVolume call.
//
// Example 1:
@@ -254,7 +254,7 @@ type TopologyRequirement struct {
// {"region": "R1", "zone": "Z3"}
// preferred =
// {"region": "R1", "zone": "Z3"}
// then the SP SHOULD first attempt to make the provisioned volume
// then the the SP SHOULD first attempt to make the provisioned volume
// available from "zone" "Z3" in the "region" "R1" and fall back to
// "zone" "Z2" in the "region" "R1" if that is not possible.
//
@@ -268,7 +268,7 @@ type TopologyRequirement struct {
// preferred =
// {"region": "R1", "zone": "Z4"},
// {"region": "R1", "zone": "Z2"}
// then the SP SHOULD first attempt to make the provisioned volume
// then the the SP SHOULD first attempt to make the provisioned volume
// accessible from "zone" "Z4" in the "region" "R1" and fall back to
// "zone" "Z2" in the "region" "R1" if that is not possible. If that
// is not possible, the SP may choose between either the "zone"
@@ -287,7 +287,7 @@ type TopologyRequirement struct {
// preferred =
// {"region": "R1", "zone": "Z5"},
// {"region": "R1", "zone": "Z3"}
// then the SP SHOULD first attempt to make the provisioned volume
// then the the SP SHOULD first attempt to make the provisioned volume
// accessible from the combination of the two "zones" "Z5" and "Z3" in
// the "region" "R1". If that's not possible, it should fall back to
// a combination of "Z5" and other possibilities from the list of

View File

@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"path"
"strconv"
"strings"
"sync"
"time"
@@ -35,15 +34,14 @@ import (
pkgprogress "github.com/docker/docker/pkg/progress"
"github.com/docker/docker/reference"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb/sourceresolver"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/source"
"github.com/moby/buildkit/source/containerimage"
srctypes "github.com/moby/buildkit/source/types"
"github.com/moby/buildkit/sourcepolicy"
policy "github.com/moby/buildkit/sourcepolicy/pb"
spb "github.com/moby/buildkit/sourcepolicy/pb"
"github.com/moby/buildkit/util/flightcontrol"
"github.com/moby/buildkit/util/imageutil"
@@ -82,77 +80,9 @@ func NewSource(opt SourceOpt) (*Source, error) {
return &Source{SourceOpt: opt}, nil
}
// Schemes returns a list of SourceOp identifier schemes that this source
// should match.
func (is *Source) Schemes() []string {
return []string{srctypes.DockerImageScheme}
}
// Identifier constructs an Identifier from the given scheme, ref, and attrs,
// all of which come from a SourceOp.
func (is *Source) Identifier(scheme, ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) {
return is.registryIdentifier(ref, attrs, platform)
}
// Copied from github.com/moby/buildkit/source/containerimage/source.go
func (is *Source) registryIdentifier(ref string, attrs map[string]string, platform *pb.Platform) (source.Identifier, error) {
id, err := containerimage.NewImageIdentifier(ref)
if err != nil {
return nil, err
}
if platform != nil {
id.Platform = &ocispec.Platform{
OS: platform.OS,
Architecture: platform.Architecture,
Variant: platform.Variant,
OSVersion: platform.OSVersion,
}
if platform.OSFeatures != nil {
id.Platform.OSFeatures = append([]string{}, platform.OSFeatures...)
}
}
for k, v := range attrs {
switch k {
case pb.AttrImageResolveMode:
rm, err := resolver.ParseImageResolveMode(v)
if err != nil {
return nil, err
}
id.ResolveMode = rm
case pb.AttrImageRecordType:
rt, err := parseImageRecordType(v)
if err != nil {
return nil, err
}
id.RecordType = rt
case pb.AttrImageLayerLimit:
l, err := strconv.Atoi(v)
if err != nil {
return nil, errors.Wrapf(err, "invalid layer limit %s", v)
}
if l <= 0 {
return nil, errors.Errorf("invalid layer limit %s", v)
}
id.LayerLimit = &l
}
}
return id, nil
}
func parseImageRecordType(v string) (client.UsageRecordType, error) {
switch client.UsageRecordType(v) {
case "", client.UsageRecordTypeRegular:
return client.UsageRecordTypeRegular, nil
case client.UsageRecordTypeInternal:
return client.UsageRecordTypeInternal, nil
case client.UsageRecordTypeFrontend:
return client.UsageRecordTypeFrontend, nil
default:
return "", errors.Errorf("invalid record type %s", v)
}
// ID returns image scheme identifier
func (is *Source) ID() string {
return srctypes.DockerImageScheme
}
func (is *Source) resolveLocal(refStr string) (*image.Image, error) {
@@ -177,7 +107,7 @@ type resolveRemoteResult struct {
dt []byte
}
func (is *Source) resolveRemote(ctx context.Context, ref string, platform *ocispec.Platform, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) {
func (is *Source) resolveRemote(ctx context.Context, ref string, platform *ocispec.Platform, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) {
p := platforms.DefaultSpec()
if platform != nil {
p = *platform
@@ -186,36 +116,34 @@ func (is *Source) resolveRemote(ctx context.Context, ref string, platform *ocisp
key := "getconfig::" + ref + "::" + platforms.Format(p)
res, err := is.g.Do(ctx, key, func(ctx context.Context) (*resolveRemoteResult, error) {
res := resolver.DefaultPool.GetResolver(is.RegistryHosts, ref, "pull", sm, g)
dgst, dt, err := imageutil.Config(ctx, ref, res, is.ContentStore, is.LeaseManager, platform)
ref, dgst, dt, err := imageutil.Config(ctx, ref, res, is.ContentStore, is.LeaseManager, platform, []*policy.Policy{})
if err != nil {
return nil, err
}
return &resolveRemoteResult{ref: ref, dgst: dgst, dt: dt}, nil
})
if err != nil {
return "", nil, err
return ref, "", nil, err
}
return res.dgst, res.dt, nil
return res.ref, res.dgst, res.dt, nil
}
// ResolveImageConfig returns image config for an image
func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) {
if opt.ImageOpt == nil {
return "", nil, fmt.Errorf("can only resolve an image: %v, opt: %v", ref, opt)
}
func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) {
ref, err := applySourcePolicies(ctx, ref, opt.SourcePolicies)
if err != nil {
return "", nil, err
return "", "", nil, err
}
resolveMode, err := resolver.ParseImageResolveMode(opt.ImageOpt.ResolveMode)
resolveMode, err := source.ParseImageResolveMode(opt.ResolveMode)
if err != nil {
return "", nil, err
return ref, "", nil, err
}
switch resolveMode {
case resolver.ResolveModeForcePull:
return is.resolveRemote(ctx, ref, opt.Platform, sm, g)
case source.ResolveModeForcePull:
ref, dgst, dt, err := is.resolveRemote(ctx, ref, opt.Platform, sm, g)
// TODO: pull should fallback to local in case of failure to allow offline behavior
// the fallback doesn't work currently
return ref, dgst, dt, err
/*
if err == nil {
return dgst, dt, err
@@ -225,10 +153,10 @@ func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt source
return "", dt, err
*/
case resolver.ResolveModeDefault:
case source.ResolveModeDefault:
// default == prefer local, but in the future could be smarter
fallthrough
case resolver.ResolveModePreferLocal:
case source.ResolveModePreferLocal:
img, err := is.resolveLocal(ref)
if err == nil {
if opt.Platform != nil && !platformMatches(img, opt.Platform) {
@@ -237,19 +165,19 @@ func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt source
path.Join(img.OS, img.Architecture, img.Variant),
)
} else {
return "", img.RawJSON(), err
return ref, "", img.RawJSON(), err
}
}
// fallback to remote
return is.resolveRemote(ctx, ref, opt.Platform, sm, g)
}
// should never happen
return "", nil, fmt.Errorf("builder cannot resolve image %s: invalid mode %q", ref, opt.ImageOpt.ResolveMode)
return ref, "", nil, fmt.Errorf("builder cannot resolve image %s: invalid mode %q", ref, opt.ResolveMode)
}
// Resolve returns access to pulling for an identifier
func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session.Manager, vtx solver.Vertex) (source.SourceInstance, error) {
imageIdentifier, ok := id.(*containerimage.ImageIdentifier)
imageIdentifier, ok := id.(*source.ImageIdentifier)
if !ok {
return nil, errors.Errorf("invalid image identifier %v", id)
}
@@ -273,7 +201,7 @@ type puller struct {
is *Source
resolveLocalOnce sync.Once
g flightcontrol.Group[struct{}]
src *containerimage.ImageIdentifier
src *source.ImageIdentifier
desc ocispec.Descriptor
ref string
config []byte
@@ -325,7 +253,7 @@ func (p *puller) resolveLocal() {
}
}
if p.src.ResolveMode == resolver.ResolveModeDefault || p.src.ResolveMode == resolver.ResolveModePreferLocal {
if p.src.ResolveMode == source.ResolveModeDefault || p.src.ResolveMode == source.ResolveModePreferLocal {
ref := p.src.Reference.String()
img, err := p.is.resolveLocal(ref)
if err == nil {
@@ -374,17 +302,12 @@ func (p *puller) resolve(ctx context.Context, g session.Group) error {
if err != nil {
return struct{}{}, err
}
_, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), sourceresolver.Opt{
Platform: &p.platform,
ImageOpt: &sourceresolver.ResolveImageOpt{
ResolveMode: p.src.ResolveMode.String(),
},
}, p.sm, g)
newRef, _, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), llb.ResolveImageConfigOpt{Platform: &p.platform, ResolveMode: p.src.ResolveMode.String()}, p.sm, g)
if err != nil {
return struct{}{}, err
}
p.ref = ref.String()
p.ref = newRef
p.config = dt
}
return struct{}{}, nil
@@ -943,8 +866,12 @@ func applySourcePolicies(ctx context.Context, str string, spls []*spb.Policy) (s
if err != nil {
return "", errors.WithStack(err)
}
op := &pb.SourceOp{
Identifier: srctypes.DockerImageScheme + "://" + ref.String(),
op := &pb.Op{
Op: &pb.Op_Source{
Source: &pb.SourceOp{
Identifier: srctypes.DockerImageScheme + "://" + ref.String(),
},
},
}
mut, err := sourcepolicy.NewEngine(spls).Evaluate(ctx, op)
@@ -957,9 +884,9 @@ func applySourcePolicies(ctx context.Context, str string, spls []*spb.Policy) (s
t string
ok bool
)
t, newRef, ok := strings.Cut(op.GetIdentifier(), "://")
t, newRef, ok := strings.Cut(op.GetSource().GetIdentifier(), "://")
if !ok {
return "", errors.Errorf("could not parse ref: %s", op.GetIdentifier())
return "", errors.Errorf("could not parse ref: %s", op.GetSource().GetIdentifier())
}
if ok && t != srctypes.DockerImageScheme {
return "", &imageutil.ResolveToNonImageError{Ref: str, Updated: newRef}

View File

@@ -22,9 +22,6 @@ func (s *snapshotter) GetDiffIDs(ctx context.Context, key string) ([]layer.DiffI
}
func (s *snapshotter) EnsureLayer(ctx context.Context, key string) ([]layer.DiffID, error) {
s.layerCreateLocker.Lock(key)
defer s.layerCreateLocker.Unlock(key)
diffIDs, err := s.GetDiffIDs(ctx, key)
if err != nil {
return nil, err

View File

@@ -17,7 +17,6 @@ import (
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/util/leaseutil"
"github.com/moby/locker"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
bolt "go.etcd.io/bbolt"
@@ -52,11 +51,10 @@ type checksumCalculator interface {
type snapshotter struct {
opt Opt
refs map[string]layer.Layer
db *bolt.DB
mu sync.Mutex
reg graphIDRegistrar
layerCreateLocker *locker.Locker
refs map[string]layer.Layer
db *bolt.DB
mu sync.Mutex
reg graphIDRegistrar
}
// NewSnapshotter creates a new snapshotter
@@ -73,11 +71,10 @@ func NewSnapshotter(opt Opt, prevLM leases.Manager, ns string) (snapshot.Snapsho
}
s := &snapshotter{
opt: opt,
db: db,
refs: map[string]layer.Layer{},
reg: reg,
layerCreateLocker: locker.New(),
opt: opt,
db: db,
refs: map[string]layer.Layer{},
reg: reg,
}
slm := newLeaseManager(s, prevLM)

View File

@@ -389,10 +389,9 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
}
req := &controlapi.SolveRequest{
Ref: id,
Exporters: []*controlapi.Exporter{
&controlapi.Exporter{Type: exporterName, Attrs: exporterAttrs},
},
Ref: id,
Exporter: exporterName,
ExporterAttrs: exporterAttrs,
Frontend: "dockerfile.v0",
FrontendAttrs: frontendAttrs,
Session: opt.Options.SessionID,

View File

@@ -67,11 +67,11 @@ func newController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control
}
func getTraceExporter(ctx context.Context) trace.SpanExporter {
span, _, err := detect.Exporter()
exp, err := detect.Exporter()
if err != nil {
log.G(ctx).WithError(err).Error("Failed to detect trace exporter for buildkit controller")
}
return span
return exp
}
func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt) (*control.Controller, error) {
@@ -105,8 +105,7 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
wo, err := containerd.NewWorkerOpt(opt.Root, opt.ContainerdAddress, opt.Snapshotter, opt.ContainerdNamespace,
opt.Rootless, map[string]string{
label.Snapshotter: opt.Snapshotter,
}, dns, nc, opt.ApparmorProfile, false, nil, "", nil, ctd.WithTimeout(60*time.Second),
)
}, dns, nc, opt.ApparmorProfile, false, nil, "", ctd.WithTimeout(60*time.Second))
if err != nil {
return nil, err
}
@@ -303,11 +302,9 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
}
exp, err := mobyexporter.New(mobyexporter.Opt{
ImageStore: dist.ImageStore,
ContentStore: store,
Differ: differ,
ImageTagger: opt.ImageTagger,
LeaseManager: lm,
ImageStore: dist.ImageStore,
Differ: differ,
ImageTagger: opt.ImageTagger,
})
if err != nil {
return nil, err

View File

@@ -16,7 +16,6 @@ import (
"github.com/moby/buildkit/executor"
"github.com/moby/buildkit/executor/oci"
"github.com/moby/buildkit/executor/resources"
resourcestypes "github.com/moby/buildkit/executor/resources/types"
"github.com/moby/buildkit/executor/runcexecutor"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/solver/pb"
@@ -57,16 +56,9 @@ func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfi
return nil, err
}
runcCmds := []string{"runc"}
// TODO: FIXME: testing env var, replace with something better or remove in a major version or two
if runcOverride := os.Getenv("DOCKER_BUILDKIT_RUNC_COMMAND"); runcOverride != "" {
runcCmds = []string{runcOverride}
}
return runcexecutor.New(runcexecutor.Opt{
Root: filepath.Join(root, "executor"),
CommandCandidates: runcCmds,
CommandCandidates: []string{"runc"},
DefaultCgroupParent: cgroupParent,
Rootless: rootless,
NoPivot: os.Getenv("DOCKER_RAMDISK") != "",
@@ -136,8 +128,8 @@ func (iface *lnInterface) init(c *libnetwork.Controller, n *libnetwork.Network)
}
// TODO(neersighted): Unstub Sample(), and collect data from the libnetwork Endpoint.
func (iface *lnInterface) Sample() (*resourcestypes.NetworkSample, error) {
return &resourcestypes.NetworkSample{}, nil
func (iface *lnInterface) Sample() (*network.Sample, error) {
return &network.Sample{}, nil
}
func (iface *lnInterface) Set(s *specs.Spec) error {

View File

@@ -1,27 +1,24 @@
package mobyexporter
import (
"bytes"
"context"
"encoding/json"
"fmt"
"strings"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/leases"
"github.com/containerd/log"
distref "github.com/distribution/reference"
"github.com/docker/docker/image"
"github.com/docker/docker/internal/compatcontext"
"github.com/docker/docker/layer"
"github.com/moby/buildkit/exporter"
"github.com/moby/buildkit/exporter/containerimage"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/util/leaseutil"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
const (
keyImageName = "name"
)
// Differ can make a moby layer from a snapshot
type Differ interface {
EnsureLayer(ctx context.Context, key string) ([]layer.DiffID, error)
@@ -33,11 +30,9 @@ type ImageTagger interface {
// Opt defines a struct for creating new exporter
type Opt struct {
ImageStore image.Store
Differ Differ
ImageTagger ImageTagger
ContentStore content.Store
LeaseManager leases.Manager
ImageStore image.Store
Differ Differ
ImageTagger ImageTagger
}
type imageExporter struct {
@@ -50,14 +45,13 @@ func New(opt Opt) (exporter.Exporter, error) {
return im, nil
}
func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]string) (exporter.ExporterInstance, error) {
func (e *imageExporter) Resolve(ctx context.Context, opt map[string]string) (exporter.ExporterInstance, error) {
i := &imageExporterInstance{
imageExporter: e,
id: id,
}
for k, v := range opt {
switch exptypes.ImageExporterOptKey(k) {
case exptypes.OptKeyName:
switch k {
case keyImageName:
for _, v := range strings.Split(v, ",") {
ref, err := distref.ParseNormalizedNamed(v)
if err != nil {
@@ -77,15 +71,10 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri
type imageExporterInstance struct {
*imageExporter
id int
targetNames []distref.Named
meta map[string][]byte
}
func (e *imageExporterInstance) ID() int {
return e.id
}
func (e *imageExporterInstance) Name() string {
return "exporting to image"
}
@@ -94,7 +83,7 @@ func (e *imageExporterInstance) Config() *exporter.Config {
return exporter.NewConfig()
}
func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source, inlineCache exptypes.InlineCache, sessionID string) (map[string]string, exporter.DescriptorReference, error) {
func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source, sessionID string) (map[string]string, exporter.DescriptorReference, error) {
if len(inp.Refs) > 1 {
return nil, nil, fmt.Errorf("exporting multiple references to image store is currently unsupported")
}
@@ -114,14 +103,18 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source
case 0:
config = inp.Metadata[exptypes.ExporterImageConfigKey]
case 1:
ps, err := exptypes.ParsePlatforms(inp.Metadata)
if err != nil {
return nil, nil, fmt.Errorf("cannot export image, failed to parse platforms: %w", err)
platformsBytes, ok := inp.Metadata[exptypes.ExporterPlatformsKey]
if !ok {
return nil, nil, fmt.Errorf("cannot export image, missing platforms mapping")
}
if len(ps.Platforms) != len(inp.Refs) {
return nil, nil, errors.Errorf("number of platforms does not match references %d %d", len(ps.Platforms), len(inp.Refs))
var p exptypes.Platforms
if err := json.Unmarshal(platformsBytes, &p); err != nil {
return nil, nil, errors.Wrapf(err, "failed to parse platforms passed to exporter")
}
config = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, ps.Platforms[0].ID)]
if len(p.Platforms) != len(inp.Refs) {
return nil, nil, errors.Errorf("number of platforms does not match references %d %d", len(p.Platforms), len(inp.Refs))
}
config = inp.Metadata[fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, p.Platforms[0].ID)]
}
var diffs []digest.Digest
@@ -164,21 +157,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source
diffs, history = normalizeLayersAndHistory(diffs, history, ref)
var inlineCacheEntry *exptypes.InlineCacheEntry
if inlineCache != nil {
inlineCacheResult, err := inlineCache(ctx)
if err != nil {
return nil, nil, err
}
if inlineCacheResult != nil {
if ref != nil {
inlineCacheEntry, _ = inlineCacheResult.FindRef(ref.ID())
} else {
inlineCacheEntry = inlineCacheResult.Ref
}
}
}
config, err = patchImageConfig(config, diffs, history, inlineCacheEntry)
config, err = patchImageConfig(config, diffs, history, inp.Metadata[exptypes.ExporterInlineCache])
if err != nil {
return nil, nil, err
}
@@ -192,10 +171,8 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source
}
_ = configDone(nil)
var names []string
for _, targetName := range e.targetNames {
names = append(names, targetName.String())
if e.opt.ImageTagger != nil {
if e.opt.ImageTagger != nil {
for _, targetName := range e.targetNames {
tagDone := oneOffProgress(ctx, "naming to "+targetName.String())
if err := e.opt.ImageTagger.TagImage(ctx, image.ID(digest.Digest(id)), targetName); err != nil {
return nil, nil, tagDone(err)
@@ -204,49 +181,8 @@ func (e *imageExporterInstance) Export(ctx context.Context, inp *exporter.Source
}
}
resp := map[string]string{
return map[string]string{
exptypes.ExporterImageConfigDigestKey: configDigest.String(),
exptypes.ExporterImageDigestKey: id.String(),
}
if len(names) > 0 {
resp["image.name"] = strings.Join(names, ",")
}
descRef, err := e.newTempReference(ctx, config)
if err != nil {
return nil, nil, fmt.Errorf("failed to create a temporary descriptor reference: %w", err)
}
return resp, descRef, nil
}
func (e *imageExporterInstance) newTempReference(ctx context.Context, config []byte) (exporter.DescriptorReference, error) {
lm := e.opt.LeaseManager
dgst := digest.FromBytes(config)
leaseCtx, done, err := leaseutil.WithLease(ctx, lm, leaseutil.MakeTemporary)
if err != nil {
return nil, err
}
unlease := func(ctx context.Context) error {
err := done(compatcontext.WithoutCancel(ctx))
if err != nil {
log.G(ctx).WithError(err).Error("failed to delete descriptor reference lease")
}
return err
}
desc := ocispec.Descriptor{
Digest: dgst,
MediaType: "application/vnd.docker.container.image.v1+json",
Size: int64(len(config)),
}
if err := content.WriteBlob(leaseCtx, e.opt.ContentStore, desc.Digest.String(), bytes.NewReader(config), desc); err != nil {
unlease(leaseCtx)
return nil, fmt.Errorf("failed to save temporary image config: %w", err)
}
return containerimage.NewDescriptorReference(desc, unlease), nil
}, nil, nil
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/containerd/containerd/platforms"
"github.com/containerd/log"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/util/progress"
"github.com/moby/buildkit/util/system"
"github.com/opencontainers/go-digest"
@@ -39,7 +38,7 @@ func parseHistoryFromConfig(dt []byte) ([]ocispec.History, error) {
return config.History, nil
}
func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, cache *exptypes.InlineCacheEntry) ([]byte, error) {
func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History, cache []byte) ([]byte, error) {
m := map[string]json.RawMessage{}
if err := json.Unmarshal(dt, &m); err != nil {
return nil, errors.Wrap(err, "failed to parse image config for patch")
@@ -76,7 +75,7 @@ func patchImageConfig(dt []byte, dps []digest.Digest, history []ocispec.History,
}
if cache != nil {
dt, err := json.Marshal(cache.Data)
dt, err := json.Marshal(cache)
if err != nil {
return nil, err
}

View File

@@ -19,7 +19,7 @@ func NewExporterWrapper(exp exporter.Exporter) (exporter.Exporter, error) {
}
// Resolve applies moby specific attributes to the request.
func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, id int, exporterAttrs map[string]string) (exporter.ExporterInstance, error) {
func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, exporterAttrs map[string]string) (exporter.ExporterInstance, error) {
if exporterAttrs == nil {
exporterAttrs = make(map[string]string)
}
@@ -33,5 +33,5 @@ func (e *imageExporterMobyWrapper) Resolve(ctx context.Context, id int, exporter
exporterAttrs[string(exptypes.OptKeyDanglingPrefix)] = "moby-dangling"
}
return e.exp.Resolve(ctx, id, exporterAttrs)
return e.exp.Resolve(ctx, exporterAttrs)
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/log"
imageadapter "github.com/docker/docker/builder/builder-next/adapters/containerimage"
"github.com/docker/docker/builder/builder-next/adapters/containerimage"
mobyexporter "github.com/docker/docker/builder/builder-next/exporter"
distmetadata "github.com/docker/docker/distribution/metadata"
"github.com/docker/docker/distribution/xfer"
@@ -23,7 +23,7 @@ import (
"github.com/moby/buildkit/cache"
cacheconfig "github.com/moby/buildkit/cache/config"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb/sourceresolver"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/executor"
"github.com/moby/buildkit/exporter"
localexporter "github.com/moby/buildkit/exporter/local"
@@ -37,7 +37,6 @@ import (
"github.com/moby/buildkit/solver/llbsolver/ops"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/source"
"github.com/moby/buildkit/source/containerimage"
"github.com/moby/buildkit/source/git"
"github.com/moby/buildkit/source/http"
"github.com/moby/buildkit/source/local"
@@ -76,7 +75,7 @@ type Opt struct {
ContentStore *containerdsnapshot.Store
CacheManager cache.Manager
LeaseManager *leaseutil.Manager
ImageSource *imageadapter.Source
ImageSource *containerimage.Source
DownloadManager *xfer.LayerDownloadManager
V2MetadataService distmetadata.V2MetadataService
Transport nethttp.RoundTripper
@@ -213,49 +212,6 @@ func (w *Worker) LoadRef(ctx context.Context, id string, hidden bool) (cache.Imm
return w.CacheManager().Get(ctx, id, nil, opts...)
}
func (w *Worker) ResolveSourceMetadata(ctx context.Context, op *pb.SourceOp, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (*sourceresolver.MetaResponse, error) {
if opt.SourcePolicies != nil {
return nil, errors.New("source policies can not be set for worker")
}
var platform *pb.Platform
if p := opt.Platform; p != nil {
platform = &pb.Platform{
Architecture: p.Architecture,
OS: p.OS,
Variant: p.Variant,
OSVersion: p.OSVersion,
}
}
id, err := w.SourceManager.Identifier(&pb.Op_Source{Source: op}, platform)
if err != nil {
return nil, err
}
switch idt := id.(type) {
case *containerimage.ImageIdentifier:
if opt.ImageOpt == nil {
opt.ImageOpt = &sourceresolver.ResolveImageOpt{}
}
dgst, config, err := w.ImageSource.ResolveImageConfig(ctx, idt.Reference.String(), opt, sm, g)
if err != nil {
return nil, err
}
return &sourceresolver.MetaResponse{
Op: op,
Image: &sourceresolver.ResolveImageResponse{
Digest: dgst,
Config: config,
},
}, nil
}
return &sourceresolver.MetaResponse{
Op: op,
}, nil
}
// ResolveOp converts a LLB vertex into a LLB operation
func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge, sm *session.Manager) (solver.Op, error) {
if baseOp, ok := v.Sys().(*pb.Op); ok {
@@ -280,7 +236,7 @@ func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge, sm *se
}
// ResolveImageConfig returns image config for an image
func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) {
func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt, sm *session.Manager, g session.Group) (string, digest.Digest, []byte, error) {
return w.ImageSource.ResolveImageConfig(ctx, ref, opt, sm, g)
}
@@ -570,7 +526,3 @@ type emptyProvider struct{}
func (p *emptyProvider) ReaderAt(ctx context.Context, dec ocispec.Descriptor) (content.ReaderAt, error) {
return nil, errors.Errorf("ReaderAt not implemented for empty provider")
}
func (p *emptyProvider) Info(ctx context.Context, d digest.Digest) (content.Info, error) {
return content.Info{}, errors.Errorf("Info not implemented for empty provider")
}

View File

@@ -64,7 +64,7 @@ type ExecBackend interface {
// ContainerRm removes a container specified by `id`.
ContainerRm(name string, config *backend.ContainerRmConfig) error
// ContainerStart starts a new container
ContainerStart(ctx context.Context, containerID string, checkpoint string, checkpointDir string) error
ContainerStart(ctx context.Context, containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
// ContainerWait stops processing until the given container is stopped.
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
}

View File

@@ -72,7 +72,7 @@ func (c *containerManager) Run(ctx context.Context, cID string, stdout, stderr i
}
}()
if err := c.backend.ContainerStart(ctx, cID, "", ""); err != nil {
if err := c.backend.ContainerStart(ctx, cID, nil, "", ""); err != nil {
close(finished)
logCancellationError(cancelErrCh, "error from ContainerStart: "+err.Error())
return err

View File

@@ -459,16 +459,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
return copyDirectory(archiver, srcPath, destPath, options.identity)
}
if options.decompress && archive.IsArchivePath(srcPath) && !source.noDecompress {
f, err := os.Open(srcPath)
if err != nil {
return err
}
defer f.Close()
options := &archive.TarOptions{
IDMap: archiver.IDMapping,
BestEffortXattrs: true,
}
return archiver.Untar(f, destPath, options)
return archiver.UntarPath(srcPath, destPath)
}
destExistsAsDir, err := isExistingDirectory(destPath)

View File

@@ -46,7 +46,7 @@ func (m *MockBackend) CommitBuildStep(ctx context.Context, c backend.CommitConfi
return "", nil
}
func (m *MockBackend) ContainerStart(ctx context.Context, containerID string, checkpoint string, checkpointDir string) error {
func (m *MockBackend) ContainerStart(ctx context.Context, containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error {
return nil
}

View File

@@ -265,22 +265,17 @@ func (cli *Client) Close() error {
// This allows for version-dependent code to use the same version as will
// be negotiated when making the actual requests, and for which cases
// we cannot do the negotiation lazily.
func (cli *Client) checkVersion(ctx context.Context) error {
if !cli.manualOverride && cli.negotiateVersion && !cli.negotiated {
ping, err := cli.Ping(ctx)
if err != nil {
return err
}
cli.negotiateAPIVersionPing(ping)
func (cli *Client) checkVersion(ctx context.Context) {
if cli.negotiateVersion && !cli.negotiated {
cli.NegotiateAPIVersion(ctx)
}
return nil
}
// getAPIPath returns the versioned request path to call the API.
// It appends the query parameters to the path if they are not empty.
func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
var apiPath string
_ = cli.checkVersion(ctx)
cli.checkVersion(ctx)
if cli.version != "" {
v := strings.TrimPrefix(cli.version, "v")
apiPath = path.Join(cli.basePath, "/v"+v, p)
@@ -312,11 +307,7 @@ func (cli *Client) ClientVersion() string {
// added (1.24).
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
if !cli.manualOverride {
ping, err := cli.Ping(ctx)
if err != nil {
// FIXME(thaJeztah): Ping returns an error when failing to connect to the API; we should not swallow the error here, and instead returning it.
return
}
ping, _ := cli.Ping(ctx)
cli.negotiateAPIVersionPing(ping)
}
}

View File

@@ -354,19 +354,6 @@ func TestNegotiateAPVersionOverride(t *testing.T) {
assert.Equal(t, client.ClientVersion(), expected)
}
// TestNegotiateAPVersionConnectionFailure asserts that we do not modify the
// API version when failing to connect.
func TestNegotiateAPVersionConnectionFailure(t *testing.T) {
const expected = "9.99"
client, err := NewClientWithOpts(WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
client.version = expected
client.NegotiateAPIVersion(context.Background())
assert.Equal(t, client.ClientVersion(), expected)
}
func TestNegotiateAPIVersionAutomatic(t *testing.T) {
var pingVersion string
httpClient := newMockClient(func(req *http.Request) (*http.Response, error) {

View File

@@ -28,9 +28,7 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
}
cli.checkVersion(ctx)
if err := cli.NewVersionError(ctx, "1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
return response, err

View File

@@ -113,15 +113,3 @@ func TestContainerCreateAutoRemove(t *testing.T) {
t.Fatal(err)
}
}
// TestContainerCreateConnection verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestContainerCreateConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
_, err = client.ContainerCreate(context.Background(), nil, nil, nil, nil, "")
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}

View File

@@ -18,9 +18,7 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
}
cli.checkVersion(ctx)
if err := cli.NewVersionError(ctx, "1.25", "env"); len(config.Env) != 0 && err != nil {
return response, err

View File

@@ -24,18 +24,6 @@ func TestContainerExecCreateError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestContainerExecCreateConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestContainerExecCreateConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
_, err = client.ContainerExecCreate(context.Background(), "", types.ExecConfig{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestContainerExecCreate(t *testing.T) {
expectedURL := "/containers/container_id/exec"
client := &Client{

View File

@@ -23,9 +23,7 @@ func (cli *Client) ContainerRestart(ctx context.Context, containerID string, opt
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
cli.checkVersion(ctx)
if versions.GreaterThanOrEqualTo(cli.version, "1.42") {
query.Set("signal", options.Signal)
}

View File

@@ -23,18 +23,6 @@ func TestContainerRestartError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestContainerRestartConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestContainerRestartConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
err = client.ContainerRestart(context.Background(), "nothing", container.StopOptions{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestContainerRestart(t *testing.T) {
const expectedURL = "/v1.42/containers/container_id/restart"
client := &Client{

View File

@@ -27,9 +27,7 @@ func (cli *Client) ContainerStop(ctx context.Context, containerID string, option
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
cli.checkVersion(ctx)
if versions.GreaterThanOrEqualTo(cli.version, "1.42") {
query.Set("signal", options.Signal)
}

View File

@@ -23,18 +23,6 @@ func TestContainerStopError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestContainerStopConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestContainerStopConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
err = client.ContainerStop(context.Background(), "nothing", container.StopOptions{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestContainerStop(t *testing.T) {
const expectedURL = "/v1.42/containers/container_id/stop"
client := &Client{

View File

@@ -30,22 +30,19 @@ const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
// synchronize ContainerWait with other calls, such as specifying a
// "next-exit" condition before issuing a ContainerStart request.
func (cli *Client) ContainerWait(ctx context.Context, containerID string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) {
resultC := make(chan container.WaitResponse)
errC := make(chan error, 1)
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
errC <- err
return resultC, errC
}
cli.checkVersion(ctx)
if versions.LessThan(cli.ClientVersion(), "1.30") {
return cli.legacyContainerWait(ctx, containerID)
}
resultC := make(chan container.WaitResponse)
errC := make(chan error, 1)
query := url.Values{}
if condition != "" {
query.Set("condition", string(condition))

View File

@@ -34,23 +34,6 @@ func TestContainerWaitError(t *testing.T) {
}
}
// TestContainerWaitConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestContainerWaitConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
resultC, errC := client.ContainerWait(context.Background(), "nothing", "")
select {
case result := <-resultC:
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
case err := <-errC:
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
}
func TestContainerWait(t *testing.T) {
expectedURL := "/containers/container_id/wait"
client := &Client{

View File

@@ -10,11 +10,11 @@ import (
)
// DistributionInspect returns the image digest with the full manifest.
func (cli *Client) DistributionInspect(ctx context.Context, imageRef, encodedRegistryAuth string) (registry.DistributionInspect, error) {
func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registry.DistributionInspect, error) {
// Contact the registry to retrieve digest and platform information
var distributionInspect registry.DistributionInspect
if imageRef == "" {
return distributionInspect, objectNotFoundError{object: "distribution", id: imageRef}
if image == "" {
return distributionInspect, objectNotFoundError{object: "distribution", id: image}
}
if err := cli.NewVersionError(ctx, "1.30", "distribution inspect"); err != nil {
@@ -28,7 +28,7 @@ func (cli *Client) DistributionInspect(ctx context.Context, imageRef, encodedReg
}
}
resp, err := cli.get(ctx, "/distribution/"+imageRef+"/json", url.Values{}, headers)
resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers)
defer ensureReaderClosed(resp)
if err != nil {
return distributionInspect, err

View File

@@ -11,16 +11,15 @@ import (
// errConnectionFailed implements an error returned when connection failed.
type errConnectionFailed struct {
error
host string
}
// Error returns a string representation of an errConnectionFailed
func (e errConnectionFailed) Error() string {
return e.error.Error()
}
func (e errConnectionFailed) Unwrap() error {
return e.error
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)
}
// IsErrConnectionFailed returns true if the error is caused by connection failed.
@@ -30,13 +29,7 @@ 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 {
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}
return errConnectionFailed{host: host}
}
// IsErrNotFound returns true if the error is a NotFound error, which is returned
@@ -67,9 +60,7 @@ func (cli *Client) NewVersionError(ctx context.Context, APIrequired, feature str
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
cli.checkVersion(ctx)
if cli.version != "" && versions.LessThan(cli.version, APIrequired) {
return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, APIrequired, cli.version)
}

View File

@@ -8,13 +8,13 @@ import (
"strings"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
)
// ImageCreate creates a new image based on the parent options.
// It returns the JSON content in the response body.
func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
ref, err := reference.ParseNormalizedNamed(parentReference)
if err != nil {
return nil, err

View File

@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
@@ -20,7 +20,7 @@ func TestImageCreateError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImageCreate(context.Background(), "reference", image.CreateOptions{})
_, err := client.ImageCreate(context.Background(), "reference", types.ImageCreateOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
@@ -58,7 +58,7 @@ func TestImageCreate(t *testing.T) {
}),
}
createResponse, err := client.ImageCreate(context.Background(), expectedReference, image.CreateOptions{
createResponse, err := client.ImageCreate(context.Background(), expectedReference, types.ImageCreateOptions{
RegistryAuth: expectedRegistryAuth,
})
if err != nil {

View File

@@ -8,12 +8,11 @@ import (
"github.com/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
)
// ImageImport creates a new image based on the source options.
// It returns the JSON content in the response body.
func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
if ref != "" {
// Check if the given image name can be resolved
if _, err := reference.ParseNormalizedNamed(ref); err != nil {

View File

@@ -11,7 +11,6 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -21,7 +20,7 @@ func TestImageImportError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImageImport(context.Background(), types.ImageImportSource{}, "image:tag", image.ImportOptions{})
_, err := client.ImageImport(context.Background(), types.ImageImportSource{}, "image:tag", types.ImageImportOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
@@ -64,7 +63,7 @@ func TestImageImport(t *testing.T) {
importResponse, err := client.ImageImport(context.Background(), types.ImageImportSource{
Source: strings.NewReader("source"),
SourceName: "image_source",
}, "repository_name:imported", image.ImportOptions{
}, "repository_name:imported", types.ImageImportOptions{
Tag: "imported",
Message: "A message",
Changes: []string{"change1", "change2"},

View File

@@ -5,24 +5,22 @@ import (
"encoding/json"
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/versions"
)
// ImageList returns a list of images in the docker host.
func (cli *Client) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) {
var images []image.Summary
func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions) ([]image.Summary, error) {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return images, err
}
cli.checkVersion(ctx)
var images []image.Summary
query := url.Values{}
optionFilters := options.Filters

View File

@@ -11,6 +11,7 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/errdefs"
@@ -23,31 +24,19 @@ func TestImageListError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImageList(context.Background(), image.ListOptions{})
_, err := client.ImageList(context.Background(), types.ImageListOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestImageListConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestImageListConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
_, err = client.ImageList(context.Background(), image.ListOptions{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestImageList(t *testing.T) {
const expectedURL = "/images/json"
listCases := []struct {
options image.ListOptions
options types.ImageListOptions
expectedQueryParams map[string]string
}{
{
options: image.ListOptions{},
options: types.ImageListOptions{},
expectedQueryParams: map[string]string{
"all": "",
"filter": "",
@@ -55,7 +44,7 @@ func TestImageList(t *testing.T) {
},
},
{
options: image.ListOptions{
options: types.ImageListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
@@ -69,7 +58,7 @@ func TestImageList(t *testing.T) {
},
},
{
options: image.ListOptions{
options: types.ImageListOptions{
Filters: filters.NewArgs(filters.Arg("dangling", "false")),
},
expectedQueryParams: map[string]string{
@@ -152,7 +141,7 @@ func TestImageListApiBefore125(t *testing.T) {
version: "1.24",
}
options := image.ListOptions{
options := types.ImageListOptions{
Filters: filters.NewArgs(filters.Arg("reference", "image:tag")),
}
@@ -173,12 +162,12 @@ func TestImageListWithSharedSize(t *testing.T) {
for _, tc := range []struct {
name string
version string
options image.ListOptions
options types.ImageListOptions
sharedSize string // expected value for the shared-size query param, or empty if it should not be set.
}{
{name: "unset after 1.42, no options set", version: "1.42"},
{name: "set after 1.42, if requested", version: "1.42", options: image.ListOptions{SharedSize: true}, sharedSize: "1"},
{name: "unset before 1.42, even if requested", version: "1.41", options: image.ListOptions{SharedSize: true}},
{name: "set after 1.42, if requested", version: "1.42", options: types.ImageListOptions{SharedSize: true}, sharedSize: "1"},
{name: "unset before 1.42, even if requested", version: "1.41", options: types.ImageListOptions{SharedSize: true}},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"strings"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types"
"github.com/docker/docker/errdefs"
)
@@ -19,7 +19,7 @@ import (
// FIXME(vdemeester): there is currently used in a few way in docker/docker
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
func (cli *Client) ImagePull(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error) {
func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.ImagePullOptions) (io.ReadCloser, error) {
ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
return nil, err

View File

@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
@@ -23,7 +23,7 @@ func TestImagePullReferenceParseError(t *testing.T) {
}),
}
// An empty reference is an invalid reference
_, err := client.ImagePull(context.Background(), "", image.PullOptions{})
_, err := client.ImagePull(context.Background(), "", types.ImagePullOptions{})
if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
t.Fatalf("expected an error, got %v", err)
}
@@ -33,7 +33,7 @@ func TestImagePullAnyError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImagePull(context.Background(), "myimage", image.PullOptions{})
_, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
@@ -41,7 +41,7 @@ func TestImagePullStatusUnauthorizedError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
}
_, err := client.ImagePull(context.Background(), "myimage", image.PullOptions{})
_, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsUnauthorized))
}
@@ -52,7 +52,7 @@ func TestImagePullWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
privilegeFunc := func() (string, error) {
return "", fmt.Errorf("Error requesting privilege")
}
_, err := client.ImagePull(context.Background(), "myimage", image.PullOptions{
_, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{
PrivilegeFunc: privilegeFunc,
})
if err == nil || err.Error() != "Error requesting privilege" {
@@ -67,7 +67,7 @@ func TestImagePullWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T)
privilegeFunc := func() (string, error) {
return "a-auth-header", nil
}
_, err := client.ImagePull(context.Background(), "myimage", image.PullOptions{
_, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{
PrivilegeFunc: privilegeFunc,
})
assert.Check(t, is.ErrorType(err, errdefs.IsUnauthorized))
@@ -108,7 +108,7 @@ func TestImagePullWithPrivilegedFuncNoError(t *testing.T) {
privilegeFunc := func() (string, error) {
return "IAmValid", nil
}
resp, err := client.ImagePull(context.Background(), "myimage", image.PullOptions{
resp, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{
RegistryAuth: "NotValid",
PrivilegeFunc: privilegeFunc,
})
@@ -179,7 +179,7 @@ func TestImagePullWithoutErrors(t *testing.T) {
}, nil
}),
}
resp, err := client.ImagePull(context.Background(), pullCase.reference, image.PullOptions{
resp, err := client.ImagePull(context.Background(), pullCase.reference, types.ImagePullOptions{
All: pullCase.all,
})
if err != nil {

View File

@@ -8,7 +8,7 @@ import (
"net/url"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
)
@@ -17,7 +17,7 @@ import (
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// It's up to the caller to handle the io.ReadCloser and close it properly.
func (cli *Client) ImagePush(ctx context.Context, image string, options image.PushOptions) (io.ReadCloser, error) {
func (cli *Client) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) {
ref, err := reference.ParseNormalizedNamed(image)
if err != nil {
return nil, err

View File

@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
@@ -23,12 +23,12 @@ func TestImagePushReferenceError(t *testing.T) {
}),
}
// An empty reference is an invalid reference
_, err := client.ImagePush(context.Background(), "", image.PushOptions{})
_, err := client.ImagePush(context.Background(), "", types.ImagePushOptions{})
if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
t.Fatalf("expected an error, got %v", err)
}
// An canonical reference cannot be pushed
_, err = client.ImagePush(context.Background(), "repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", image.PushOptions{})
_, err = client.ImagePush(context.Background(), "repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", types.ImagePushOptions{})
if err == nil || err.Error() != "cannot push a digest reference" {
t.Fatalf("expected an error, got %v", err)
}
@@ -38,7 +38,7 @@ func TestImagePushAnyError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImagePush(context.Background(), "myimage", image.PushOptions{})
_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
@@ -46,7 +46,7 @@ func TestImagePushStatusUnauthorizedError(t *testing.T) {
client := &Client{
client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
}
_, err := client.ImagePush(context.Background(), "myimage", image.PushOptions{})
_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsUnauthorized))
}
@@ -57,7 +57,7 @@ func TestImagePushWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
privilegeFunc := func() (string, error) {
return "", fmt.Errorf("Error requesting privilege")
}
_, err := client.ImagePush(context.Background(), "myimage", image.PushOptions{
_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{
PrivilegeFunc: privilegeFunc,
})
if err == nil || err.Error() != "Error requesting privilege" {
@@ -72,7 +72,7 @@ func TestImagePushWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T)
privilegeFunc := func() (string, error) {
return "a-auth-header", nil
}
_, err := client.ImagePush(context.Background(), "myimage", image.PushOptions{
_, err := client.ImagePush(context.Background(), "myimage", types.ImagePushOptions{
PrivilegeFunc: privilegeFunc,
})
assert.Check(t, is.ErrorType(err, errdefs.IsUnauthorized))
@@ -109,7 +109,7 @@ func TestImagePushWithPrivilegedFuncNoError(t *testing.T) {
privilegeFunc := func() (string, error) {
return "IAmValid", nil
}
resp, err := client.ImagePush(context.Background(), "myimage:tag", image.PushOptions{
resp, err := client.ImagePush(context.Background(), "myimage:tag", types.ImagePushOptions{
RegistryAuth: "NotValid",
PrivilegeFunc: privilegeFunc,
})
@@ -179,7 +179,7 @@ func TestImagePushWithoutErrors(t *testing.T) {
}, nil
}),
}
resp, err := client.ImagePush(context.Background(), tc.reference, image.PushOptions{
resp, err := client.ImagePush(context.Background(), tc.reference, types.ImagePushOptions{
All: tc.all,
})
if err != nil {

View File

@@ -5,11 +5,12 @@ import (
"encoding/json"
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
)
// ImageRemove removes an image from the docker host.
func (cli *Client) ImageRemove(ctx context.Context, imageID string, options image.RemoveOptions) ([]image.DeleteResponse, error) {
func (cli *Client) ImageRemove(ctx context.Context, imageID string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error) {
query := url.Values{}
if options.Force {

View File

@@ -10,6 +10,7 @@ import (
"strings"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
@@ -21,7 +22,7 @@ func TestImageRemoveError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImageRemove(context.Background(), "image_id", image.RemoveOptions{})
_, err := client.ImageRemove(context.Background(), "image_id", types.ImageRemoveOptions{})
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
@@ -30,7 +31,7 @@ func TestImageRemoveImageNotFound(t *testing.T) {
client: newMockClient(errorMock(http.StatusNotFound, "no such image: unknown")),
}
_, err := client.ImageRemove(context.Background(), "unknown", image.RemoveOptions{})
_, err := client.ImageRemove(context.Background(), "unknown", types.ImageRemoveOptions{})
assert.Check(t, is.ErrorContains(err, "no such image: unknown"))
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
}
@@ -92,7 +93,7 @@ func TestImageRemove(t *testing.T) {
}, nil
}),
}
imageDeletes, err := client.ImageRemove(context.Background(), "image_id", image.RemoveOptions{
imageDeletes, err := client.ImageRemove(context.Background(), "image_id", types.ImageRemoveOptions{
Force: removeCase.force,
PruneChildren: removeCase.pruneChildren,
})

View File

@@ -90,15 +90,15 @@ type ImageAPIClient interface {
ImageBuild(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error)
BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
BuildCancel(ctx context.Context, id string) error
ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error)
ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error)
ImageInspectWithRaw(ctx context.Context, image string) (types.ImageInspect, []byte, error)
ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
ImageList(ctx context.Context, options types.ImageListOptions) ([]image.Summary, error)
ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error)
ImagePull(ctx context.Context, ref string, options image.PullOptions) (io.ReadCloser, error)
ImagePush(ctx context.Context, ref string, options image.PushOptions) (io.ReadCloser, error)
ImageRemove(ctx context.Context, image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error)
ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error)
ImageRemove(ctx context.Context, image string, options types.ImageRemoveOptions) ([]image.DeleteResponse, error)
ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error)
ImageSave(ctx context.Context, images []string) (io.ReadCloser, error)
ImageTag(ctx context.Context, image, ref string) error

View File

@@ -10,16 +10,12 @@ import (
// NetworkCreate creates a new network in the docker host.
func (cli *Client) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) {
var response types.NetworkCreateResponse
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
}
cli.checkVersion(ctx)
networkCreateRequest := types.NetworkCreateRequest{
NetworkCreate: options,
@@ -29,6 +25,7 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options types
networkCreateRequest.CheckDuplicate = true //nolint:staticcheck // ignore SA1019: CheckDuplicate is deprecated since API v1.44.
}
var response types.NetworkCreateResponse
serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
defer ensureReaderClosed(serverResp)
if err != nil {

View File

@@ -25,18 +25,6 @@ func TestNetworkCreateError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestNetworkCreateConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestNetworkCreateConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
_, err = client.NetworkCreate(context.Background(), "mynetwork", types.NetworkCreate{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestNetworkCreate(t *testing.T) {
expectedURL := "/networks/create"

View File

@@ -14,10 +14,7 @@ import (
// Ping pings the server and returns the value of the "Docker-Experimental",
// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use
// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported
// by the daemon. It ignores internal server errors returned by the API, which
// may be returned if the daemon is in an unhealthy state, but returns errors
// for other non-success status codes, failing to connect to the API, or failing
// to parse the API response.
// by the daemon.
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
var ping types.Ping

View File

@@ -53,12 +53,18 @@ func TestPingFail(t *testing.T) {
func TestPingWithError(t *testing.T) {
client := &Client{
client: newMockClient(func(req *http.Request) (*http.Response, error) {
return nil, errors.New("some connection error")
resp := &http.Response{StatusCode: http.StatusInternalServerError}
resp.Header = http.Header{}
resp.Header.Set("API-Version", "awesome")
resp.Header.Set("Docker-Experimental", "true")
resp.Header.Set("Swarm", "active/manager")
resp.Body = io.NopCloser(strings.NewReader("some error with the server"))
return resp, errors.New("some error")
}),
}
ping, err := client.Ping(context.Background())
assert.Check(t, is.ErrorContains(err, "some connection error"))
assert.Check(t, is.ErrorContains(err, "some error"))
assert.Check(t, is.Equal(false, ping.Experimental))
assert.Check(t, is.Equal("", ping.APIVersion))
var si *swarm.Status

View File

@@ -134,18 +134,17 @@ 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, errConnectionFailed{fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)}
return serverResp, 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, errConnectionFailed{errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")}
return serverResp, 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
@@ -157,13 +156,12 @@ 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, errConnectionFailed{errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)}
return serverResp, 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)
}
@@ -192,7 +190,7 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
}
}
return serverResp, errConnectionFailed{errors.Wrap(err, "error during connect")}
return serverResp, errors.Wrap(err, "error during connect")
}
if resp != nil {

View File

@@ -25,9 +25,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
}
cli.checkVersion(ctx)
// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container
if service.TaskTemplate.ContainerSpec == nil && (service.TaskTemplate.Runtime == "" || service.TaskTemplate.Runtime == swarm.RuntimeContainer) {

View File

@@ -28,18 +28,6 @@ func TestServiceCreateError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestServiceCreateConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestServiceCreateConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
_, err = client.ServiceCreate(context.Background(), swarm.ServiceSpec{}, types.ServiceCreateOptions{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestServiceCreate(t *testing.T) {
expectedURL := "/services/create"
client := &Client{

View File

@@ -16,18 +16,18 @@ import (
// It should be the value as set *before* the update. You can find this value in the Meta field
// of swarm.Service, which can be found using ServiceInspectWithRaw.
func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error) {
response := swarm.ServiceUpdateResponse{}
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
}
cli.checkVersion(ctx)
var (
query = url.Values{}
response = swarm.ServiceUpdateResponse{}
)
query := url.Values{}
if options.RegistryAuthFrom != "" {
query.Set("registryAuthFrom", options.RegistryAuthFrom)
}

View File

@@ -25,18 +25,6 @@ func TestServiceUpdateError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestServiceUpdateConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestServiceUpdateConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
_, err = client.ServiceUpdate(context.Background(), "service_id", swarm.Version{}, swarm.ServiceSpec{}, types.ServiceUpdateOptions{})
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestServiceUpdate(t *testing.T) {
expectedURL := "/services/service_id/update"

View File

@@ -16,9 +16,7 @@ func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
cli.checkVersion(ctx)
if versions.GreaterThanOrEqualTo(cli.version, "1.25") {
query.Set("force", "1")
}

View File

@@ -23,18 +23,6 @@ func TestVolumeRemoveError(t *testing.T) {
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
}
// TestVolumeRemoveConnectionError verifies that connection errors occurring
// during API-version negotiation are not shadowed by API-version errors.
//
// Regression test for https://github.com/docker/cli/issues/4890
func TestVolumeRemoveConnectionError(t *testing.T) {
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
assert.NilError(t, err)
err = client.VolumeRemove(context.Background(), "volume_id", false)
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
}
func TestVolumeRemove(t *testing.T) {
expectedURL := "/volumes/volume_id"

View File

@@ -15,7 +15,7 @@ import (
)
var (
testBuf = []byte("Buffalo1 buffalo2 Buffalo3 buffalo4 buffalo5 buffalo6 Buffalo7 buffalo8")
testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
testBufSize = len(testBuf)
)

Some files were not shown because too many files have changed in this diff Show More