Compare commits

..

52 Commits

Author SHA1 Message Date
f4ffd2511c Merge pull request #273 from andrewhsu/v
[17.10] bump version to 17.10.0-ce
2017-10-17 11:51:33 -07:00
ec6b6de1c8 Merge pull request #272 from andrewhsu/c
[17.10] update changelog for 17.10.0-ce
2017-10-17 11:51:16 -07:00
8bac3f632b update changelog for 17.10.0-ce
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-17 11:02:49 -07:00
646a76c31b bump version to 17.10.0-ce
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-13 14:37:20 -07:00
af94197a36 Merge pull request #268 from andrewhsu/v
[17.10] bump version to 17.10.0-ce-rc2
2017-10-11 17:38:08 -07:00
2f11502622 Merge pull request #269 from andrewhsu/cl
[17.10] update changelog for 17.10.0-ce-rc2
2017-10-11 17:37:59 -07:00
24ee573f35 Merge pull request #270 from andrewhsu/sk
[17.10] re-vndr swarmkit to 1d2bc2e
2017-10-11 17:37:36 -07:00
4d73e16a14 update changelog for 17.10.0-ce-rc2
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 16:28:26 -07:00
1311aaf76e Merge pull request #271 from andrewhsu/d
[17.10] backport doc fixes and shell completion script fixes
2017-10-11 16:10:39 -07:00
6f56735237 Merge pull request #266 from johnstep/windows-manifest-lists
[17.10] Backport version fix for Windows manifest lists
2017-10-11 16:08:09 -07:00
e274827392 Merge pull request #267 from seemethere/cherry_pick_cli_607
[17.10] Mutate image references where needed for trusted pulls
2017-10-11 16:03:47 -07:00
e7f51b183f Fix markdown link in service-create reference docs
Markdown nested in a HTML table doesn't work, so changing
the link to a plain HTML link.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 6b6511f191)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:32:32 -07:00
792e8f9a82 Fix dockerd reference heading levels
Commit ddadd3db49 changed
the heading levels of various sections, but as a result,
the "daemon configuration file" section (and other sections)
changed from a H2 to a H4, therefore no longer showing
up in the page's TOC / navigation bar.

This patch changes the heading level to a H3 for
sections that should show up in the page navigation.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit aca0421eb8)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:31:37 -07:00
8b13940b3b Update rmi.md
Signed-off-by: Daniel Goosen <daniel.goosen@surveysampling.com>
(cherry picked from commit 9004495541)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:30:49 -07:00
550052ebae Add bash completion for secret create --driver
Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit 1d7a31f87e)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:29:15 -07:00
b0596beda5 Add bash completion for stack deploy --resolve-image
Also adds minimal documentation for this flag.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit 9559b9b7a8)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:28:15 -07:00
6fc2c6b8c5 Update deprecation for synchronous service updates
- The default was not changed in 17.09 but will be in 17.10
- `service scale` and `service rollback` are also affected.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit 20d9ceca78)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:26:34 -07:00
f26232e8f6 Update bash completion for synchronous docker service commands
The default value for
`docker service create|update|scale|rollback --detach|-d` changed from
`true` to `false`.
This updates bash completion to complete just `--detach|-d`.

Signed-off-by: Harald Albers <github@albersweb.de>
(cherry picked from commit 60bfaba6fb)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 15:26:34 -07:00
018b6401f5 re-vndr swarmkit to 1d2bc2e
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 14:27:34 -07:00
56bd88c226 bump version to 17.10.0-ce-rc2
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-11 10:55:10 -07:00
fc8971da3b Merge pull request #265 from andrewhsu/olay
[17.10] Fallback to use naive diff driver if enable CONFIG_OVERLAY_FS_REDIREC…
2017-10-11 10:49:01 -07:00
9f566ba32b Update e2e test for image pull to check stdout
Also add TEST_DEBUG env variable for debugging E2E tests.
And change icmd environment helpers to fit the CmdOp interface os they
can be passed to 'icmd.RunCmd()'

Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit b11c11ea74)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
785d4378ad Refactor runPull to remove second GetImageReferencesAndAuth
Fix unit tests to catch the regression.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit e548861481)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
e9a538eda6 factor out rigging for pushing unsigned busybox image
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
(cherry picked from commit 7dda6fc3c9)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
cdee6d83f4 update image pull tests
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
(cherry picked from commit 46f3d8bb7f)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
c76d10969f get e2e working with notary service
Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit ade675d36c)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
02f6ddc6ae trust: update references when pulling
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
(cherry picked from commit 067fff8b03)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
125ffb8b1b update e2e tests for content trust tests
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
(cherry picked from commit 6e3bafd06b)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-11 10:47:45 -07:00
9c61899f29 Merge pull request #264 from andrewhsu/v
[17.10] re-vndr libnetwork to 6c51292 and swarmkit to 872861d
2017-10-11 10:46:00 -07:00
76922d8690 Stop filtering Windows manifest lists by version
Signed-off-by: John Stephens <johnstep@docker.com>
(cherry picked from commit 8ed8f4a71d7e1a936fa077b4348b7375c81746a6)

Conflicts:
	components/engine/distribution/pull_v2_windows.go

Signed-off-by: John Stephens <johnstep@docker.com>
2017-10-10 21:42:19 -07:00
f437cf754f Add support for Windows version filtering on pull
Update logic to choose manifest from manifest list to check
for os version on Windows. Separate the logic for windows
and unix to keep unix logic the same.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
(cherry picked from commit 38aef56e1fcb8ea318df98c89cf002267b88a136)
Signed-off-by: John Stephens <johnstep@docker.com>
2017-10-10 21:10:00 -07:00
2adb51e303 Fallback to use naive diff driver if enable CONFIG_OVERLAY_FS_REDIRECT_DIR
When use overlay2 as the graphdriver and the kernel enable
`CONFIG_OVERLAY_FS_REDIRECT_DIR=y`, rename a dir in lower layer
will has a xattr to redirct its dir to source dir. This make the
image layer unportable. This patch fallback to use naive diff driver
when kernel enable CONFIG_OVERLAY_FS_REDIRECT_DIR

Signed-off-by: Lei Jitang <leijitang@huawei.com>
(cherry picked from commit 49c3a7c4bac2877265ef8c4eaf210159560f08b4)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-10 20:56:55 -07:00
a761ee3d4d Modifying swarm integration test
Signed-off-by: Abhinandan Prativadi <abhi@docker.com>
(cherry picked from commit 7e6b2165ef58e68ad4eafd457e8de89dd4c2c6b1)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-10 18:59:32 -07:00
e1484d2ff8 re-vndr swarmkit to 872861d
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-10 17:50:47 -07:00
d82f9fe3f3 re-vndr libnetwork to 6c51292
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-10-10 17:19:58 -07:00
73ecdcee10 Merge pull request #263 from seemethere/change_ubuntu_trusty_package_mirror
Switches ubuntu trusty mirror to one that works
2017-10-10 10:24:53 -07:00
c8e9afef61 Switches ubuntu trusty mirror to one that works
Was getting 404's with the old one, consider this one temporary until
canonical fixes their stuff.

Related:
https://bugs.launchpad.net/cloud-images/+bug/1711735

Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
(cherry picked from commit 8e177368d0a30614a7ba615f3c2f2ede1e21ff8e)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-10 10:22:06 -07:00
d866876d86 Merge pull request #259 from andrewhsu/v
[17.10] bump version to 17.10.0-ce-rc1
2017-10-04 14:11:32 -07:00
8ab000a5f4 Merge pull request #256 from vieux/17.10-changelog
[17.10] add 17.10 changelog
2017-10-04 14:08:52 -07:00
c8ede6fcc6 Merge pull request #260 from seemethere/fix_tests_for_1710_release
[17.10] Fix tests for 17.10 release
2017-10-04 14:07:13 -07:00
0d46b8e710 [integration-cli] fix s390x flaky test
s390x node-1 has kernel 4.6.0, kernel.CompareKernelVersion()
returns 0 if the kernels are equal, so include that.

Full logic for CompareKernelVersion() is
a > b ret 1,
a == b ret 0,
a < b ret -1

Signed-off-by: Christopher Jones <tophj@linux.vnet.ibm.com>
(cherry picked from commit aa5ea652c8864f014e1fa480d7e504f0d742c170)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-04 13:11:31 -07:00
58f592c0d9 Add note to test changes for rmi
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-10-04 10:43:27 -07:00
e58d3abea8 Switch from using lstat to stat in docker cp test. Use the first 12 characters of the ID for the stats test substring.
Signed-off-by: Corbin <corbin.coleman@docker.com>
2017-10-03 14:02:17 -07:00
4f818dd6f7 Add detach flag for scale tests
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-30 13:23:18 -07:00
d73806305a Changes error check form NotNil to IsNil
rmi -f always returns a 0 exit code so these tests needed to be changed
accordingly.

Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
(cherry picked from commit 5d1587e61e)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-30 13:23:18 -07:00
4e81e4fa4e Blacklist tests, will be rewritten later on
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-30 13:23:18 -07:00
8a6c4c93b6 Merge pull request #261 from seemethere/ensure_channel
[17.10] ensure channel is allocated
2017-09-30 09:36:10 -07:00
7b99808cac cli/command/container: ensure channel is allocated
Signed-off-by: Stephen J Day <stephen.day@docker.com>
(cherry picked from commit e78772af4d)
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
2017-09-29 18:14:51 -07:00
fab4b40e38 bump version to 17.10.0-ce-rc1
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-29 16:12:03 -07:00
079f5eb5e5 removed deprecation line
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-29 15:56:26 -07:00
db0a220cda update punctuation and spacing
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2017-09-29 15:47:47 -07:00
71bb1e8c44 add 17.10 changelog
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
2017-09-29 15:47:47 -07:00
2145 changed files with 33148 additions and 132200 deletions

View File

@ -5,107 +5,50 @@ information on the list of deprecated flags and APIs please have a look at
https://docs.docker.com/engine/deprecated/ where target removal dates can also
be found.
**IMPORTANT**: You must stop all containers and plugins **BEFORE** upgrading to Docker CE 17.12.
See related PR: [moby/moby#35812](https://github.com/moby/moby/pull/35812)
## 17.10.0-ce (2017-10-17)
## 17.12.0-ce (2017-12-27)
## Known Issues
* AWS logs batch size calculation [moby/moby#35726](https://github.com/moby/moby/pull/35726)
* Health check no longer uses the container's working directory [moby/moby#35843](https://github.com/moby/moby/issues/35843)
* Errors not returned from client in stack deploy configs [moby/moby#757](https://github.com/docker/cli/pull/757)
* Daemon aborts when project quota fails [moby/moby#35827](https://github.com/moby/moby/pull/35827)
* Docker cannot use memory limit when using systemd options [moby/moby#35123](https://github.com/moby/moby/issues/35123)
IMPORTANT: Starting with this release, `docker service create`, `docker service update`,
`docker service scale` and `docker service rollback` use non-detached mode as default,
use `--detach` to keep the old behaviour.
### Builder
- Fix build cache hash for broken symlink [moby/moby#34271](https://github.com/moby/moby/pull/34271)
- Fix long stream sync [moby/moby#35404](https://github.com/moby/moby/pull/35404)
- Fix dockerfile parser failing silently on long tokens [moby/moby#35429](https://github.com/moby/moby/pull/35429)
* Reset uid/gid to 0 in uploaded build context to share build cache with other clients [docker/cli#513](https://github.com/docker/cli/pull/513)
+ Add support for `ADD` urls without any sub path [moby/moby#34217](https://github.com/moby/moby/pull/34217)
### Client
* Remove secret/config duplication in cli/compose [docker/cli#671](https://github.com/docker/cli/pull/671)
* Add `--local` flag to `docker trust sign` [docker/cli#575](https://github.com/docker/cli/pull/575)
* Add `docker trust inspect` [docker/cli#694](https://github.com/docker/cli/pull/694)
+ Add `name` field to secrets and configs to allow interpolation in Compose files [docker/cli#668](https://github.com/docker/cli/pull/668)
+ Add `--isolation` for setting swarm service isolation mode [docker/cli#426](https://github.com/docker/cli/pull/426)
* Remove deprecated "daemon" subcommand [docker/cli#689](https://github.com/docker/cli/pull/689)
- Fix behaviour of `rmi -f` with unexpected errors [docker/cli#654](https://github.com/docker/cli/pull/654)
* Integrated Generic resource in service create [docker/cli#429](https://github.com/docker/cli/pull/429)
- Fix external networks in stacks [docker/cli#743](https://github.com/docker/cli/pull/743)
* Remove support for referencing images by image shortid [docker/cli#753](https://github.com/docker/cli/pull/753) and [moby/moby#35790](https://github.com/moby/moby/pull/35790)
* Use commit-sha instead of tag for containerd [moby/moby#35770](https://github.com/moby/moby/pull/35770)
### Documentation
* Update API version history for 1.35 [moby/moby#35724](https://github.com/moby/moby/pull/35724)
### Logging
* Logentries driver line-only=true []byte output fix [moby/moby#35612](https://github.com/moby/moby/pull/35612)
* Logentries line-only logopt fix to maintain backwards compatibility [moby/moby#35628](https://github.com/moby/moby/pull/35628)
+ Add `--until` flag for docker logs [moby/moby#32914](https://github.com/moby/moby/pull/32914)
+ Add gelf log driver plugin to Windows build [moby/moby#35073](https://github.com/moby/moby/pull/35073)
* Set timeout on splunk batch send [moby/moby#35496](https://github.com/moby/moby/pull/35496)
* Update Graylog2/go-gelf [moby/moby#35765](https://github.com/moby/moby/pull/35765)
* Move output of `docker stack rm` to stdout [docker/cli#491](https://github.com/docker/cli/pull/491)
* Use natural sort secrets and configs in cli [docker/cli#307](https://github.com/docker/cli/pull/307)
* Use non-detached mode as default for `docker service` commands [docker/cli#525](https://github.com/docker/cli/pull/525)
* Set APIVersion on the client, even when Ping fails [docker/cli#546](https://github.com/docker/cli/pull/546)
- Fix loader error with different build syntax in `docker stack deploy` [docker/cli#544](https://github.com/docker/cli/pull/544)
* Change the default output format for `docker container stats` to show `CONTAINER ID` and `NAME` [docker/cli#565](https://github.com/docker/cli/pull/565)
+ Add `--no-trunc` flag to `docker container stats` [docker/cli#565](https://github.com/docker/cli/pull/565)
+ Add experimental `docker trust`: `view`, `revoke`, `sign` subcommands [docker/cli#472](https://github.com/docker/cli/pull/472)
- Various doc and shell completion fixes [docker/cli#610](https://github.com/docker/cli/pull/610) [docker/cli#611](https://github.com/docker/cli/pull/611) [docker/cli#618](https://github.com/docker/cli/pull/618) [docker/cli#580](https://github.com/docker/cli/pull/580) [docker/cli#598](https://github.com/docker/cli/pull/698) [docker/cli#603](https://github.com/docker/cli/pull/603)
### Networking
* Move load balancer sandbox creation/deletion into libnetwork [moby/moby#35422](https://github.com/moby/moby/pull/35422)
* Only chown network files within container metadata [moby/moby#34224](https://github.com/moby/moby/pull/34224)
* Restore error type in FindNetwork [moby/moby#35634](https://github.com/moby/moby/pull/35634)
- Fix consumes MIME type for NetworkConnect [moby/moby#35542](https://github.com/moby/moby/pull/35542)
+ Added support for persisting Windows network driver specific options [moby/moby#35563](https://github.com/moby/moby/pull/35563)
- Fix timeout on netlink sockets and watchmiss leak [moby/moby#35677](https://github.com/moby/moby/pull/35677)
+ New daemon config for networking diagnosis [moby/moby#35677](https://github.com/moby/moby/pull/35677)
- Clean up node management logic [docker/libnetwork#2036](https://github.com/docker/libnetwork/pull/2036)
- Allocate VIPs when endpoints are restored [docker/swarmkit#2474](https://github.com/docker/swarmkit/pull/2474)
* Enabling ILB/ELB on windows using per-node, per-network LB endpoint [moby/moby#34674](https://github.com/moby/moby/pull/34674)
* Overlay fix for transient IP reuse [docker/libnetwork#1935](https://github.com/docker/libnetwork/pull/1935)
* Serializing bitseq alloc [docker/libnetwork#1788](https://github.com/docker/libnetwork/pull/1788)
- Disable hostname lookup on chain exists check [docker/libnetwork#1974](https://github.com/docker/libnetwork/pull/1974)
### Runtime
* Update to containerd v1.0.0 [moby/moby#35707](https://github.com/moby/moby/pull/35707)
* Have VFS graphdriver use accelerated in-kernel copy [moby/moby#35537](https://github.com/moby/moby/pull/35537)
* Introduce `workingdir` option for docker exec [moby/moby#35661](https://github.com/moby/moby/pull/35661)
* Bump Go to 1.9.2 [moby/moby#33892](https://github.com/moby/moby/pull/33892) [docker/cli#716](https://github.com/docker/cli/pull/716)
* `/dev` should not be readonly with `--readonly` flag [moby/moby#35344](https://github.com/moby/moby/pull/35344)
+ Add custom build-time Graphdrivers priority list [moby/moby#35522](https://github.com/moby/moby/pull/35522)
* LCOW: CLI changes to add platform flag - pull, run, create and build [docker/cli#474](https://github.com/docker/cli/pull/474)
* Fix width/height on Windoes for `docker exec` [moby/moby#35631](https://github.com/moby/moby/pull/35631)
* Detect overlay2 support on pre-4.0 kernels [moby/moby#35527](https://github.com/moby/moby/pull/35527)
* Devicemapper: remove container rootfs mountPath after umount [moby/moby#34573](https://github.com/moby/moby/pull/34573)
* Disallow overlay/overlay2 on top of NFS [moby/moby#35483](https://github.com/moby/moby/pull/35483)
- Fix potential panic during plugin set. [moby/moby#35632](https://github.com/moby/moby/pull/35632)
- Fix some issues with locking on the container [moby/moby#35501](https://github.com/moby/moby/pull/35501)
- Fixup some issues with plugin refcounting [moby/moby#35265](https://github.com/moby/moby/pull/35265)
+ Add missing lock in ProcessEvent [moby/moby#35516](https://github.com/moby/moby/pull/35516)
+ Add vfs quota support [moby/moby#35231](https://github.com/moby/moby/pull/35231)
* Skip empty directories on prior graphdriver detection [moby/moby#35528](https://github.com/moby/moby/pull/35528)
* Skip xfs quota tests when running in user namespace [moby/moby#35526](https://github.com/moby/moby/pull/35526)
+ Added SubSecondPrecision to config option. [moby/moby#35529](https://github.com/moby/moby/pull/35529)
* Update fsnotify to fix deadlock in removing watch [moby/moby#35453](https://github.com/moby/moby/pull/35453)
- Fix "duplicate mount point" when `--tmpfs /dev/shm` is used [moby/moby#35467](https://github.com/moby/moby/pull/35467)
- Fix honoring tmpfs-size for user `/dev/shm` mount [moby/moby#35316](https://github.com/moby/moby/pull/35316)
- Fix EBUSY errors under overlayfs and v4.13+ kernels [moby/moby#34948](https://github.com/moby/moby/pull/34948)
* Container: protect health monitor channel [moby/moby#35482](https://github.com/moby/moby/pull/35482)
* Container: protect the health status with mutex [moby/moby#35517](https://github.com/moby/moby/pull/35517)
* Container: update real-time resources [moby/moby#33731](https://github.com/moby/moby/pull/33731)
* Create labels when volume exists only remotely [moby/moby#34896](https://github.com/moby/moby/pull/34896)
- Fix leaking container/exec state [moby/moby#35484](https://github.com/moby/moby/pull/35484)
* Disallow using legacy (v1) registries [moby/moby#35751](https://github.com/moby/moby/pull/35751) and [docker/cli#747](https://github.com/docker/cli/pull/747)
- Windows: Fix case insensitive filename matching against builder cache [moby/moby#35793](https://github.com/moby/moby/pull/35793)
- Fix race conditions around process handling and error checks [moby/moby#35809](https://github.com/moby/moby/pull/35809)
* Ensure containers are stopped on daemon startup [moby/moby#35805](https://github.com/moby/moby/pull/35805)
* Follow containerd namespace conventions [moby/moby#35812](https://github.com/moby/moby/pull/35812)
* LCOW: Add UVM debugability by grabbing logs before tear-down [moby/moby#34846](https://github.com/moby/moby/pull/34846)
* LCOW: Prepare work for bind mounts [moby/moby#34258](https://github.com/moby/moby/pull/34258)
* LCOW: Support for docker cp, ADD/COPY on build [moby/moby#34252](https://github.com/moby/moby/pull/34252)
* LCOW: VHDX boot to readonly [moby/moby#34754](https://github.com/moby/moby/pull/34754)
* Volume: evaluate symlinks before relabeling mount source [moby/moby#34792](https://github.com/moby/moby/pull/34792)
- Fixing docker cp to allow new target file name in a host symlinked directory [moby/moby#31993](https://github.com/moby/moby/pull/31993)
+ Add support for Windows version filtering on pull [moby/moby#35090](https://github.com/moby/moby/pull/35090)
### Swarm Mode
### Swarm mode
+ Added support for swarm service isolation mode [moby/moby#34424](https://github.com/moby/moby/pull/34424)
- Fix task clean up for tasks that are complete [docker/swarmkit#2477](https://github.com/docker/swarmkit/pull/2477)
### Packaging
+ Add Packaging for Fedora 27 [docker/docker-ce-packaging#59](https://github.com/docker/docker-ce-packaging/pull/59)
* Change default versioning scheme to 0.0.0-dev unless specified for packaging [docker/docker-ce-packaging#67](https://github.com/docker/docker-ce-packaging/pull/67)
* Pass Version to engine static builds [docker/docker-ce-packaging#70](https://github.com/docker/docker-ce-packaging/pull/70)
+ Added support for aarch64 on Debian (stretch/jessie) and Ubuntu Zesty or newer [docker/docker-ce-packaging#35](https://github.com/docker/docker-ce-packaging/pull/35)
* Produce an error if `docker swarm init --force-new-cluster` is executed on worker nodes [moby/moby#34881](https://github.com/moby/moby/pull/34881)
+ Add support for `.Node.Hostname` templating in swarm services [moby/moby#34686](https://github.com/moby/moby/pull/34686)
* Increase gRPC request timeout to 20 seconds for sending snapshots [docker/swarmkit#2391](https://github.com/docker/swarmkit/pull/2391)
- Do not filter nodes if logdriver is set to `none` [docker/swarmkit#2396](https://github.com/docker/swarmkit/pull/2396)
+ Adding ipam options to ipam driver requests [docker/swarmkit#2324](https://github.com/docker/swarmkit/pull/2324)

View File

@ -1,7 +1,7 @@
CLI_DIR:=$(CURDIR)/components/cli
ENGINE_DIR:=$(CURDIR)/components/engine
PACKAGING_DIR:=$(CURDIR)/components/packaging
MOBY_COMPONENTS_SHA=ab7c118272b02d8672dc0255561d0c4015979780
MOBY_COMPONENTS_SHA=f79265f1412af0a68aadd11e1d2f374446f3681b
MOBY_COMPONENTS_URL=https://raw.githubusercontent.com/shykes/moby-extras/$(MOBY_COMPONENTS_SHA)/cmd/moby-components
MOBY_COMPONENTS=.helpers/moby-components-$(MOBY_COMPONENTS_SHA)
VERSION=$(shell cat VERSION)

View File

@ -1 +1 @@
17.12.0-ce
17.10.0-ce

View File

@ -1,9 +1,9 @@
# GitHub code owners
# Github code owners
# See https://github.com/blog/2392-introducing-code-owners
cli/command/stack/** @dnephin @vdemeester
cli/compose/** @dnephin @vdemeester
contrib/completion/bash/** @albers
contrib/completion/zsh/** @sdurrheimer
docs/** @mistyhacks @vdemeester @thaJeztah
docs/** @mstanleyjones @vdemeester @thaJeztah
scripts/** @dnephin

View File

@ -103,7 +103,7 @@
[people.cpuguy83]
Name = "Brian Goff"
Email = "cpuguy83@gmail.com"
GitHub = "cpuguy83"
Github = "cpuguy83"
[people.crosbymichael]
Name = "Michael Crosby"
@ -133,7 +133,7 @@
[people.misty]
Name = "Misty Stanley-Jones"
Email = "misty@docker.com"
GitHub = "mistyhacks"
GitHub = "mstanleyjones"
[people.mlaventure]
Name = "Kenfe-Mickaël Laventure"

View File

@ -1 +1 @@
17.12.0-ce
17.10.0-ce

View File

@ -17,7 +17,6 @@ func SetupRootCommand(rootCmd *cobra.Command) {
cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
cobra.AddTemplateFunc("useLine", UseLine)
rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.SetHelpTemplate(helpTemplate)
@ -26,7 +25,6 @@ func SetupRootCommand(rootCmd *cobra.Command) {
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
rootCmd.PersistentFlags().Lookup("help").Hidden = true
}
// FlagErrorFunc prints an error message which matches the format of the
@ -99,19 +97,9 @@ func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
return cmds
}
// UseLine returns the usage line for a command. This implementation is different
// from the default Command.UseLine in that it does not add a `[flags]` to the
// end of the line.
func UseLine(cmd *cobra.Command) string {
if cmd.HasParent() {
return cmd.Parent().CommandPath() + " " + cmd.Use
}
return cmd.Use
}
var usageTemplate = `Usage:
{{- if not .HasSubCommands}} {{ useLine . }}{{end}}
{{- if not .HasSubCommands}} {{.UseLine}}{{end}}
{{- if .HasSubCommands}} {{ .CommandPath}} COMMAND{{end}}
{{ .Short | trim }}

View File

@ -9,11 +9,11 @@ import (
// NewCheckpointCommand returns the `checkpoint` subcommand (only in experimental)
func NewCheckpointCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "checkpoint",
Short: "Manage checkpoints",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"experimental": "", "version": "1.25"},
Use: "checkpoint",
Short: "Manage checkpoints",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"experimental": "", "version": "1.25"},
}
cmd.AddCommand(
newCreateCommand(dockerCli),

View File

@ -18,11 +18,11 @@ import (
"github.com/docker/docker/client"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/docker/notary"
notaryclient "github.com/docker/notary/client"
"github.com/docker/notary/passphrase"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/theupdateframework/notary"
notaryclient "github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/passphrase"
"golang.org/x/net/context"
)
@ -207,8 +207,7 @@ func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile.
return client.NewClient(host, verStr, httpClient, customHeaders)
}
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (string, error) {
var host string
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (host string, err error) {
switch len(hosts) {
case 0:
host = os.Getenv("DOCKER_HOST")
@ -218,7 +217,8 @@ func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (string, error
return "", errors.New("Please specify only one -H")
}
return dopts.ParseHost(tlsOptions != nil, host)
host, err = dopts.ParseHost(tlsOptions != nil, host)
return
}
func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, error) {

View File

@ -8,13 +8,14 @@ import (
)
// NewConfigCommand returns a cobra command for `config` subcommands
func NewConfigCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewConfigCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "Manage Docker configs",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.30"},
Use: "config",
Short: "Manage Docker configs",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.30"},
}
cmd.AddCommand(
newConfigListCommand(dockerCli),

View File

@ -12,15 +12,12 @@ import (
type fakeClient struct {
client.Client
inspectFunc func(string) (types.ContainerJSON, error)
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error)
createContainerFunc func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error)
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
infoFunc func() (types.Info, error)
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
inspectFunc func(string) (types.ContainerJSON, error)
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error)
createContainerFunc func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error)
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
infoFunc func() (types.Info, error)
}
func (f *fakeClient) ContainerInspect(_ context.Context, containerID string) (types.ContainerJSON, error) {
@ -74,24 +71,3 @@ func (f *fakeClient) Info(_ context.Context) (types.Info, error) {
}
return types.Info{}, nil
}
func (f *fakeClient) ContainerStatPath(_ context.Context, container, path string) (types.ContainerPathStat, error) {
if f.containerStatPathFunc != nil {
return f.containerStatPathFunc(container, path)
}
return types.ContainerPathStat{}, nil
}
func (f *fakeClient) CopyFromContainer(_ context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
if f.containerCopyFromFunc != nil {
return f.containerCopyFromFunc(container, srcPath)
}
return nil, types.ContainerPathStat{}, nil
}
func (f *fakeClient) ContainerLogs(_ context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error) {
if f.logFunc != nil {
return f.logFunc(container, options)
}
return nil, nil
}

View File

@ -7,7 +7,8 @@ import (
)
// NewContainerCommand returns a cobra command for `container` subcommands
func NewContainerCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewContainerCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "container",
Short: "Manage containers",

View File

@ -22,7 +22,7 @@ type commitOptions struct {
}
// NewCommitCommand creates a new cobra.Command for `docker commit`
func NewCommitCommand(dockerCli command.Cli) *cobra.Command {
func NewCommitCommand(dockerCli *command.DockerCli) *cobra.Command {
var options commitOptions
cmd := &cobra.Command{
@ -51,7 +51,7 @@ func NewCommitCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runCommit(dockerCli command.Cli, options *commitOptions) error {
func runCommit(dockerCli *command.DockerCli, options *commitOptions) error {
ctx := context.Background()
name := options.container

View File

@ -26,21 +26,17 @@ type copyOptions struct {
type copyDirection int
const (
fromContainer copyDirection = 1 << iota
fromContainer copyDirection = (1 << iota)
toContainer
acrossContainers = fromContainer | toContainer
)
type cpConfig struct {
followLink bool
copyUIDGID bool
sourcePath string
destPath string
container string
}
// NewCopyCommand creates a new `docker cp` command
func NewCopyCommand(dockerCli command.Cli) *cobra.Command {
func NewCopyCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts copyOptions
cmd := &cobra.Command{
@ -69,57 +65,58 @@ func NewCopyCommand(dockerCli command.Cli) *cobra.Command {
}
flags := cmd.Flags()
flags.BoolVarP(&opts.followLink, "follow-link", "L", false, "Always follow symbol link in SRC_PATH")
flags.BoolVarP(&opts.copyUIDGID, "archive", "a", false, "Archive mode (copy all uid/gid information)")
return cmd
}
func runCopy(dockerCli command.Cli, opts copyOptions) error {
func runCopy(dockerCli *command.DockerCli, opts copyOptions) error {
srcContainer, srcPath := splitCpArg(opts.source)
destContainer, destPath := splitCpArg(opts.destination)
copyConfig := cpConfig{
followLink: opts.followLink,
copyUIDGID: opts.copyUIDGID,
sourcePath: srcPath,
destPath: destPath,
}
dstContainer, dstPath := splitCpArg(opts.destination)
var direction copyDirection
if srcContainer != "" {
direction |= fromContainer
copyConfig.container = srcContainer
}
if destContainer != "" {
if dstContainer != "" {
direction |= toContainer
copyConfig.container = destContainer
}
cpParam := &cpConfig{
followLink: opts.followLink,
}
ctx := context.Background()
switch direction {
case fromContainer:
return copyFromContainer(ctx, dockerCli, copyConfig)
return copyFromContainer(ctx, dockerCli, srcContainer, srcPath, dstPath, cpParam)
case toContainer:
return copyToContainer(ctx, dockerCli, copyConfig)
return copyToContainer(ctx, dockerCli, srcPath, dstContainer, dstPath, cpParam, opts.copyUIDGID)
case acrossContainers:
// Copying between containers isn't supported.
return errors.New("copying between containers is not supported")
default:
// User didn't specify any container.
return errors.New("must specify at least one container source")
}
}
func statContainerPath(ctx context.Context, dockerCli *command.DockerCli, containerName, path string) (types.ContainerPathStat, error) {
return dockerCli.Client().ContainerStatPath(ctx, containerName, path)
}
func resolveLocalPath(localPath string) (absPath string, err error) {
if absPath, err = filepath.Abs(localPath); err != nil {
return
}
return archive.PreserveTrailingDotOrSeparator(absPath, localPath, filepath.Separator), nil
}
func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpConfig) (err error) {
dstPath := copyConfig.destPath
srcPath := copyConfig.sourcePath
func copyFromContainer(ctx context.Context, dockerCli *command.DockerCli, srcContainer, srcPath, dstPath string, cpParam *cpConfig) (err error) {
if dstPath != "-" {
// Get an absolute destination path.
dstPath, err = resolveLocalPath(dstPath)
@ -128,11 +125,10 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
}
}
client := dockerCli.Client()
// if client requests to follow symbol link, then must decide target file to be copied
var rebaseName string
if copyConfig.followLink {
srcStat, err := client.ContainerStatPath(ctx, copyConfig.container, srcPath)
if cpParam.followLink {
srcStat, err := statContainerPath(ctx, dockerCli, srcContainer, srcPath)
// If the destination is a symbolic link, we should follow it.
if err == nil && srcStat.Mode&os.ModeSymlink != 0 {
@ -149,17 +145,20 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
}
content, stat, err := client.CopyFromContainer(ctx, copyConfig.container, srcPath)
content, stat, err := dockerCli.Client().CopyFromContainer(ctx, srcContainer, srcPath)
if err != nil {
return err
}
defer content.Close()
if dstPath == "-" {
_, err = io.Copy(dockerCli.Out(), content)
// Send the response to STDOUT.
_, err = io.Copy(os.Stdout, content)
return err
}
// Prepare source copy info.
srcInfo := archive.CopyInfo{
Path: srcPath,
Exists: true,
@ -172,17 +171,13 @@ func copyFromContainer(ctx context.Context, dockerCli command.Cli, copyConfig cp
_, srcBase := archive.SplitPathDirEntry(srcInfo.Path)
preArchive = archive.RebaseArchiveEntries(content, srcBase, srcInfo.RebaseName)
}
// See comments in the implementation of `archive.CopyTo` for exactly what
// goes into deciding how and whether the source archive needs to be
// altered for the correct copy behavior.
return archive.CopyTo(preArchive, srcInfo, dstPath)
}
// In order to get the copy behavior right, we need to know information
// about both the source and destination. The API is a simple tar
// archive/extract API but we can use the stat info header about the
// destination to be more informed about exactly what the destination is.
func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpConfig) (err error) {
srcPath := copyConfig.sourcePath
dstPath := copyConfig.destPath
func copyToContainer(ctx context.Context, dockerCli *command.DockerCli, srcPath, dstContainer, dstPath string, cpParam *cpConfig, copyUIDGID bool) (err error) {
if srcPath != "-" {
// Get an absolute source path.
srcPath, err = resolveLocalPath(srcPath)
@ -191,10 +186,14 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
}
}
client := dockerCli.Client()
// In order to get the copy behavior right, we need to know information
// about both the source and destination. The API is a simple tar
// archive/extract API but we can use the stat info header about the
// destination to be more informed about exactly what the destination is.
// Prepare destination copy info by stat-ing the container path.
dstInfo := archive.CopyInfo{Path: dstPath}
dstStat, err := client.ContainerStatPath(ctx, copyConfig.container, dstPath)
dstStat, err := statContainerPath(ctx, dockerCli, dstContainer, dstPath)
// If the destination is a symbolic link, we should evaluate it.
if err == nil && dstStat.Mode&os.ModeSymlink != 0 {
@ -206,7 +205,7 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
}
dstInfo.Path = linkTarget
dstStat, err = client.ContainerStatPath(ctx, copyConfig.container, linkTarget)
dstStat, err = statContainerPath(ctx, dockerCli, dstContainer, linkTarget)
}
// Ignore any error and assume that the parent directory of the destination
@ -225,14 +224,15 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
)
if srcPath == "-" {
// Use STDIN.
content = os.Stdin
resolvedDstPath = dstInfo.Path
if !dstInfo.IsDir {
return errors.Errorf("destination \"%s:%s\" must be a directory", copyConfig.container, dstPath)
return errors.Errorf("destination \"%s:%s\" must be a directory", dstContainer, dstPath)
}
} else {
// Prepare source copy info.
srcInfo, err := archive.CopyInfoSourcePath(srcPath, copyConfig.followLink)
srcInfo, err := archive.CopyInfoSourcePath(srcPath, cpParam.followLink)
if err != nil {
return err
}
@ -267,9 +267,10 @@ func copyToContainer(ctx context.Context, dockerCli command.Cli, copyConfig cpCo
options := types.CopyToContainerOptions{
AllowOverwriteDirWithFile: false,
CopyUIDGID: copyConfig.copyUIDGID,
CopyUIDGID: copyUIDGID,
}
return client.CopyToContainer(ctx, copyConfig.container, resolvedDstPath, content, options)
return dockerCli.Client().CopyToContainer(ctx, dstContainer, resolvedDstPath, content, options)
}
// We use `:` as a delimiter between CONTAINER and PATH, but `:` could also be

View File

@ -1,160 +0,0 @@
package container
import (
"io"
"io/ioutil"
"runtime"
"strings"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRunCopyWithInvalidArguments(t *testing.T) {
var testcases = []struct {
doc string
options copyOptions
expectedErr string
}{
{
doc: "copy between container",
options: copyOptions{
source: "first:/path",
destination: "second:/path",
},
expectedErr: "copying between containers is not supported",
},
{
doc: "copy without a container",
options: copyOptions{
source: "./source",
destination: "./dest",
},
expectedErr: "must specify at least one container source",
},
}
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
err := runCopy(test.NewFakeCli(nil), testcase.options)
assert.EqualError(t, err, testcase.expectedErr)
})
}
}
func TestRunCopyFromContainerToStdout(t *testing.T) {
tarContent := "the tar content"
fakeClient := &fakeClient{
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
assert.Equal(t, "container", container)
return ioutil.NopCloser(strings.NewReader(tarContent)), types.ContainerPathStat{}, nil
},
}
options := copyOptions{source: "container:/path", destination: "-"}
cli := test.NewFakeCli(fakeClient)
err := runCopy(cli, options)
require.NoError(t, err)
assert.Equal(t, tarContent, cli.OutBuffer().String())
assert.Equal(t, "", cli.ErrBuffer().String())
}
func TestRunCopyFromContainerToFilesystem(t *testing.T) {
destDir := fs.NewDir(t, "cp-test",
fs.WithFile("file1", "content\n"))
defer destDir.Remove()
fakeClient := &fakeClient{
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
assert.Equal(t, "container", container)
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
return readCloser, types.ContainerPathStat{}, err
},
}
options := copyOptions{source: "container:/path", destination: destDir.Path()}
cli := test.NewFakeCli(fakeClient)
err := runCopy(cli, options)
require.NoError(t, err)
assert.Equal(t, "", cli.OutBuffer().String())
assert.Equal(t, "", cli.ErrBuffer().String())
content, err := ioutil.ReadFile(destDir.Join("file1"))
require.NoError(t, err)
assert.Equal(t, "content\n", string(content))
}
func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.T) {
destDir := fs.NewDir(t, "cp-test",
fs.WithFile("file1", "content\n"))
defer destDir.Remove()
fakeClient := &fakeClient{
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
assert.Equal(t, "container", container)
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
return readCloser, types.ContainerPathStat{}, err
},
}
options := copyOptions{
source: "container:/path",
destination: destDir.Join("missing", "foo"),
}
cli := test.NewFakeCli(fakeClient)
err := runCopy(cli, options)
testutil.ErrorContains(t, err, destDir.Join("missing"))
}
func TestSplitCpArg(t *testing.T) {
var testcases = []struct {
doc string
path string
os string
expectedContainer string
expectedPath string
}{
{
doc: "absolute path with colon",
os: "linux",
path: "/abs/path:withcolon",
expectedPath: "/abs/path:withcolon",
},
{
doc: "relative path with colon",
path: "./relative:path",
expectedPath: "./relative:path",
},
{
doc: "absolute path with drive",
os: "windows",
path: `d:\abs\path`,
expectedPath: `d:\abs\path`,
},
{
doc: "no separator",
path: "relative/path",
expectedPath: "relative/path",
},
{
doc: "with separator",
path: "container:/opt/foo",
expectedPath: "/opt/foo",
expectedContainer: "container",
},
}
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
skip.IfCondition(t, testcase.os != "" && testcase.os != runtime.GOOS)
container, path := splitCpArg(testcase.path)
assert.Equal(t, testcase.expectedContainer, container)
assert.Equal(t, testcase.expectedPath, path)
})
}
}

View File

@ -21,8 +21,7 @@ import (
)
type createOptions struct {
name string
platform string
name string
}
// NewCreateCommand creates a new cobra.Command for `docker create`
@ -52,7 +51,6 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
// with hostname
flags.Bool("help", false, "Print usage")
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags)
copts = addFlags(flags)
return cmd
@ -64,7 +62,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions,
reportError(dockerCli.Err(), "create", err.Error(), true)
return cli.StatusError{StatusCode: 125}
}
response, err := createContainer(context.Background(), dockerCli, containerConfig, opts.name, opts.platform)
response, err := createContainer(context.Background(), dockerCli, containerConfig, opts.name)
if err != nil {
return err
}
@ -72,7 +70,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions,
return nil
}
func pullImage(ctx context.Context, dockerCli command.Cli, image string, platform string, out io.Writer) error {
func pullImage(ctx context.Context, dockerCli command.Cli, image string, out io.Writer) error {
ref, err := reference.ParseNormalizedNamed(image)
if err != nil {
return err
@ -92,7 +90,6 @@ func pullImage(ctx context.Context, dockerCli command.Cli, image string, platfor
options := types.ImageCreateOptions{
RegistryAuth: encodedAuth,
Platform: platform,
}
responseBody, err := dockerCli.Client().ImageCreate(ctx, image, options)
@ -158,7 +155,7 @@ func newCIDFile(path string) (*cidFile, error) {
return &cidFile{path: path, file: f}, nil
}
func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig *containerConfig, name string, platform string) (*container.ContainerCreateCreatedBody, error) {
func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig *containerConfig, name string) (*container.ContainerCreateCreatedBody, error) {
config := containerConfig.Config
hostConfig := containerConfig.HostConfig
networkingConfig := containerConfig.NetworkingConfig
@ -197,11 +194,11 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
//if image not found try to pull it
if err != nil {
if apiclient.IsErrNotFound(err) && namedRef != nil {
if apiclient.IsErrImageNotFound(err) && namedRef != nil {
fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
// we don't want to write to stdout anything apart from container.ID
if err := pullImage(ctx, dockerCli, config.Image, platform, stderr); err != nil {
if err := pullImage(ctx, dockerCli, config.Image, stderr); err != nil {
return nil, err
}
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {

View File

@ -5,7 +5,6 @@ import (
"io"
"io/ioutil"
"os"
"runtime"
"strings"
"testing"
@ -107,7 +106,7 @@ func TestCreateContainerPullsImageIfMissing(t *testing.T) {
},
HostConfig: &container.HostConfig{},
}
body, err := createContainer(context.Background(), cli, config, "name", runtime.GOOS)
body, err := createContainer(context.Background(), cli, config, "name")
require.NoError(t, err)
expected := container.ContainerCreateCreatedBody{ID: containerID}
assert.Equal(t, expected, *body)

View File

@ -14,7 +14,7 @@ type diffOptions struct {
}
// NewDiffCommand creates a new cobra.Command for `docker diff`
func NewDiffCommand(dockerCli command.Cli) *cobra.Command {
func NewDiffCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts diffOptions
return &cobra.Command{
@ -28,7 +28,7 @@ func NewDiffCommand(dockerCli command.Cli) *cobra.Command {
}
}
func runDiff(dockerCli command.Cli, opts *diffOptions) error {
func runDiff(dockerCli *command.DockerCli, opts *diffOptions) error {
if opts.container == "" {
return errors.New("Container name cannot be empty")
}

View File

@ -24,7 +24,6 @@ type execOptions struct {
user string
privileged bool
env opts.ListOpts
workdir string
container string
command []string
}
@ -59,8 +58,6 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
flags.BoolVarP(&options.privileged, "privileged", "", false, "Give extended privileges to the command")
flags.VarP(&options.env, "env", "e", "Set environment variables")
flags.SetAnnotation("env", "version", []string{"1.25"})
flags.StringVarP(&options.workdir, "workdir", "w", "", "Working directory inside the container")
flags.SetAnnotation("workdir", "version", []string{"1.35"})
return cmd
}
@ -125,10 +122,7 @@ func interactiveExec(ctx context.Context, dockerCli command.Cli, execConfig *typ
}
client := dockerCli.Client()
execStartCheck := types.ExecStartCheck{
Tty: execConfig.Tty,
}
resp, err := client.ContainerExecAttach(ctx, execID, execStartCheck)
resp, err := client.ContainerExecAttach(ctx, execID, *execConfig)
if err != nil {
return err
}
@ -193,7 +187,6 @@ func parseExec(opts execOptions, configFile *configfile.ConfigFile) *types.ExecC
Cmd: opts.command,
Detach: opts.detach,
Env: opts.env.GetAll(),
WorkingDir: opts.workdir,
}
// If -d is not set, attach to everything by default

View File

@ -16,7 +16,7 @@ type exportOptions struct {
}
// NewExportCommand creates a new `docker export` command
func NewExportCommand(dockerCli command.Cli) *cobra.Command {
func NewExportCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts exportOptions
cmd := &cobra.Command{
@ -36,7 +36,7 @@ func NewExportCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runExport(dockerCli command.Cli, opts exportOptions) error {
func runExport(dockerCli *command.DockerCli, opts exportOptions) error {
if opts.output == "" && dockerCli.Out().IsTerminal() {
return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
}

View File

@ -15,7 +15,7 @@ type inspectOptions struct {
}
// newInspectCommand creates a new cobra.Command for `docker container inspect`
func newInspectCommand(dockerCli command.Cli) *cobra.Command {
func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts inspectOptions
cmd := &cobra.Command{
@ -35,7 +35,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runInspect(dockerCli command.Cli, opts inspectOptions) error {
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
client := dockerCli.Client()
ctx := context.Background()

View File

@ -18,7 +18,7 @@ type killOptions struct {
}
// NewKillCommand creates a new cobra.Command for `docker kill`
func NewKillCommand(dockerCli command.Cli) *cobra.Command {
func NewKillCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts killOptions
cmd := &cobra.Command{
@ -36,7 +36,7 @@ func NewKillCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runKill(dockerCli command.Cli, opts *killOptions) error {
func runKill(dockerCli *command.DockerCli, opts *killOptions) error {
var errs []string
ctx := context.Background()
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, container string) error {

View File

@ -25,7 +25,7 @@ type psOptions struct {
}
// NewPsCommand creates a new cobra.Command for `docker ps`
func NewPsCommand(dockerCli command.Cli) *cobra.Command {
func NewPsCommand(dockerCli *command.DockerCli) *cobra.Command {
options := psOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
@ -51,7 +51,7 @@ func NewPsCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func newListCommand(dockerCli command.Cli) *cobra.Command {
func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := *NewPsCommand(dockerCli)
cmd.Aliases = []string{"ps", "list"}
cmd.Use = "ls [OPTIONS]"
@ -109,7 +109,7 @@ func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, er
return options, nil
}
func runPs(dockerCli command.Cli, options *psOptions) error {
func runPs(dockerCli *command.DockerCli, options *psOptions) error {
ctx := context.Background()
listOptions, err := buildContainerListOptions(options)

View File

@ -14,7 +14,6 @@ import (
type logsOptions struct {
follow bool
since string
until string
timestamps bool
details bool
tail string
@ -23,7 +22,7 @@ type logsOptions struct {
}
// NewLogsCommand creates a new cobra.Command for `docker logs`
func NewLogsCommand(dockerCli command.Cli) *cobra.Command {
func NewLogsCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts logsOptions
cmd := &cobra.Command{
@ -39,22 +38,19 @@ func NewLogsCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output")
flags.StringVar(&opts.since, "since", "", "Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)")
flags.StringVar(&opts.until, "until", "", "Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)")
flags.SetAnnotation("until", "version", []string{"1.35"})
flags.BoolVarP(&opts.timestamps, "timestamps", "t", false, "Show timestamps")
flags.BoolVar(&opts.details, "details", false, "Show extra details provided to logs")
flags.StringVar(&opts.tail, "tail", "all", "Number of lines to show from the end of the logs")
return cmd
}
func runLogs(dockerCli command.Cli, opts *logsOptions) error {
func runLogs(dockerCli *command.DockerCli, opts *logsOptions) error {
ctx := context.Background()
options := types.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
Since: opts.since,
Until: opts.until,
Timestamps: opts.timestamps,
Follow: opts.follow,
Tail: opts.tail,

View File

@ -1,62 +0,0 @@
package container
import (
"io"
"io/ioutil"
"strings"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert"
)
var logFn = func(expectedOut string) func(string, types.ContainerLogsOptions) (io.ReadCloser, error) {
return func(container string, opts types.ContainerLogsOptions) (io.ReadCloser, error) {
return ioutil.NopCloser(strings.NewReader(expectedOut)), nil
}
}
func TestRunLogs(t *testing.T) {
inspectFn := func(containerID string) (types.ContainerJSON, error) {
return types.ContainerJSON{
Config: &container.Config{Tty: true},
ContainerJSONBase: &types.ContainerJSONBase{State: &types.ContainerState{Running: false}},
}, nil
}
var testcases = []struct {
doc string
options *logsOptions
client fakeClient
expectedError string
expectedOut string
expectedErr string
}{
{
doc: "successful logs",
expectedOut: "foo",
options: &logsOptions{},
client: fakeClient{logFunc: logFn("foo"), inspectFunc: inspectFn},
},
}
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
cli := test.NewFakeCli(&testcase.client)
err := runLogs(cli, testcase.options)
if testcase.expectedError != "" {
testutil.ErrorContains(t, err, testcase.expectedError)
} else {
if !assert.NoError(t, err) {
return
}
}
assert.Equal(t, testcase.expectedOut, cli.OutBuffer().String())
assert.Equal(t, testcase.expectedErr, cli.ErrBuffer().String())
})
}
}

View File

@ -45,7 +45,10 @@ func TestValidateAttach(t *testing.T) {
// nolint: unparam
func parseRun(args []string) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
flags, copts := setupRunFlags()
flags := pflag.NewFlagSet("run", pflag.ContinueOnError)
flags.SetOutput(ioutil.Discard)
flags.Usage = nil
copts := addFlags(flags)
if err := flags.Parse(args); err != nil {
return nil, nil, nil, err
}
@ -57,14 +60,6 @@ func parseRun(args []string) (*container.Config, *container.HostConfig, *network
return containerConfig.Config, containerConfig.HostConfig, containerConfig.NetworkingConfig, err
}
func setupRunFlags() (*pflag.FlagSet, *containerOptions) {
flags := pflag.NewFlagSet("run", pflag.ContinueOnError)
flags.SetOutput(ioutil.Discard)
flags.Usage = nil
copts := addFlags(flags)
return flags, copts
}
func parseMustError(t *testing.T, args string) {
_, _, _, err := parseRun(strings.Split(args+" ubuntu bash", " "))
assert.Error(t, err, args)
@ -232,21 +227,20 @@ func TestParseWithMacAddress(t *testing.T) {
}
}
func TestRunFlagsParseWithMemory(t *testing.T) {
flags, _ := setupRunFlags()
args := []string{"--memory=invalid", "img", "cmd"}
err := flags.Parse(args)
testutil.ErrorContains(t, err, `invalid argument "invalid" for "-m, --memory" flag`)
func TestParseWithMemory(t *testing.T) {
invalidMemory := "--memory=invalid"
_, _, _, err := parseRun([]string{invalidMemory, "img", "cmd"})
testutil.ErrorContains(t, err, invalidMemory)
_, hostconfig := mustParse(t, "--memory=1G")
assert.Equal(t, int64(1073741824), hostconfig.Memory)
}
func TestParseWithMemorySwap(t *testing.T) {
flags, _ := setupRunFlags()
args := []string{"--memory-swap=invalid", "img", "cmd"}
err := flags.Parse(args)
testutil.ErrorContains(t, err, `invalid argument "invalid" for "--memory-swap" flag`)
invalidMemory := "--memory-swap=invalid"
_, _, _, err := parseRun([]string{invalidMemory, "img", "cmd"})
testutil.ErrorContains(t, err, invalidMemory)
_, hostconfig := mustParse(t, "--memory-swap=1G")
assert.Equal(t, int64(1073741824), hostconfig.MemorySwap)
@ -371,10 +365,7 @@ func TestParseDevice(t *testing.T) {
func TestParseModes(t *testing.T) {
// pid ko
flags, copts := setupRunFlags()
args := []string{"--pid=container:", "img", "cmd"}
require.NoError(t, flags.Parse(args))
_, err := parse(flags, copts)
_, _, _, err := parseRun([]string{"--pid=container:", "img", "cmd"})
testutil.ErrorContains(t, err, "--pid: invalid PID mode")
// pid ok
@ -394,18 +385,14 @@ func TestParseModes(t *testing.T) {
if !hostconfig.UTSMode.Valid() {
t.Fatalf("Expected a valid UTSMode, got %v", hostconfig.UTSMode)
}
}
func TestRunFlagsParseShmSize(t *testing.T) {
// shm-size ko
flags, _ := setupRunFlags()
args := []string{"--shm-size=a128m", "img", "cmd"}
expectedErr := `invalid argument "a128m" for "--shm-size" flag: invalid size: 'a128m'`
err := flags.Parse(args)
expectedErr := `invalid argument "a128m" for --shm-size=a128m: invalid size: 'a128m'`
_, _, _, err = parseRun([]string{"--shm-size=a128m", "img", "cmd"})
testutil.ErrorContains(t, err, expectedErr)
// shm-size ok
_, hostconfig, _, err := parseRun([]string{"--shm-size=128m", "img", "cmd"})
_, hostconfig, _, err = parseRun([]string{"--shm-size=128m", "img", "cmd"})
require.NoError(t, err)
if hostconfig.ShmSize != 134217728 {
t.Fatalf("Expected a valid ShmSize, got %d", hostconfig.ShmSize)

View File

@ -16,7 +16,7 @@ type pauseOptions struct {
}
// NewPauseCommand creates a new cobra.Command for `docker pause`
func NewPauseCommand(dockerCli command.Cli) *cobra.Command {
func NewPauseCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts pauseOptions
return &cobra.Command{
@ -30,7 +30,7 @@ func NewPauseCommand(dockerCli command.Cli) *cobra.Command {
}
}
func runPause(dockerCli command.Cli, opts *pauseOptions) error {
func runPause(dockerCli *command.DockerCli, opts *pauseOptions) error {
ctx := context.Background()
var errs []string

View File

@ -19,7 +19,7 @@ type portOptions struct {
}
// NewPortCommand creates a new cobra.Command for `docker port`
func NewPortCommand(dockerCli command.Cli) *cobra.Command {
func NewPortCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts portOptions
cmd := &cobra.Command{
@ -37,7 +37,7 @@ func NewPortCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runPort(dockerCli command.Cli, opts *portOptions) error {
func runPort(dockerCli *command.DockerCli, opts *portOptions) error {
ctx := context.Background()
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container)

View File

@ -35,7 +35,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.25"},
Tags: map[string]string{"version": "1.25"},
}
flags := cmd.Flags()
@ -52,12 +52,12 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint6
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return 0, "", nil
return
}
report, err := dockerCli.Client().ContainersPrune(context.Background(), pruneFilters)
if err != nil {
return 0, "", err
return
}
if len(report.ContainersDeleted) > 0 {
@ -68,7 +68,7 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint6
spaceReclaimed = report.SpaceReclaimed
}
return spaceReclaimed, output, nil
return
}
// RunPrune calls the Container Prune API

View File

@ -17,7 +17,7 @@ type renameOptions struct {
}
// NewRenameCommand creates a new cobra.Command for `docker rename`
func NewRenameCommand(dockerCli command.Cli) *cobra.Command {
func NewRenameCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts renameOptions
cmd := &cobra.Command{
@ -33,7 +33,7 @@ func NewRenameCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runRename(dockerCli command.Cli, opts *renameOptions) error {
func runRename(dockerCli *command.DockerCli, opts *renameOptions) error {
ctx := context.Background()
oldName := strings.TrimSpace(opts.oldName)

View File

@ -20,7 +20,7 @@ type restartOptions struct {
}
// NewRestartCommand creates a new cobra.Command for `docker restart`
func NewRestartCommand(dockerCli command.Cli) *cobra.Command {
func NewRestartCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts restartOptions
cmd := &cobra.Command{
@ -39,7 +39,7 @@ func NewRestartCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runRestart(dockerCli command.Cli, opts *restartOptions) error {
func runRestart(dockerCli *command.DockerCli, opts *restartOptions) error {
ctx := context.Background()
var errs []string
var timeout *time.Duration

View File

@ -21,7 +21,7 @@ type rmOptions struct {
}
// NewRmCommand creates a new cobra.Command for `docker rm`
func NewRmCommand(dockerCli command.Cli) *cobra.Command {
func NewRmCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts rmOptions
cmd := &cobra.Command{
@ -41,7 +41,7 @@ func NewRmCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runRm(dockerCli command.Cli, opts *rmOptions) error {
func runRm(dockerCli *command.DockerCli, opts *rmOptions) error {
ctx := context.Background()
var errs []string

View File

@ -29,11 +29,10 @@ type runOptions struct {
sigProxy bool
name string
detachKeys string
platform string
}
// NewRunCommand create a new `docker run` command
func NewRunCommand(dockerCli command.Cli) *cobra.Command {
func NewRunCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts runOptions
var copts *containerOptions
@ -63,7 +62,6 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
// with hostname
flags.Bool("help", false, "Print usage")
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags)
copts = addFlags(flags)
return cmd
@ -98,7 +96,7 @@ func isLocalhost(ip string) bool {
return localhostIPRegexp.MatchString(ip)
}
func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copts *containerOptions) error {
func runRun(dockerCli *command.DockerCli, flags *pflag.FlagSet, ropts *runOptions, copts *containerOptions) error {
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), copts.env.GetAll())
newEnv := []string{}
for k, v := range proxyConfig {
@ -119,7 +117,7 @@ func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copt
}
// nolint: gocyclo
func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptions, containerConfig *containerConfig) error {
func runContainer(dockerCli *command.DockerCli, opts *runOptions, copts *containerOptions, containerConfig *containerConfig) error {
config := containerConfig.Config
hostConfig := containerConfig.HostConfig
stdout, stderr := dockerCli.Out(), dockerCli.Err()
@ -162,7 +160,7 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
ctx, cancelFun := context.WithCancel(context.Background())
createResponse, err := createContainer(ctx, dockerCli, containerConfig, opts.name, opts.platform)
createResponse, err := createContainer(ctx, dockerCli, containerConfig, opts.name)
if err != nil {
reportError(stderr, cmdPath, err.Error(), true)
return runStartContainerErr(err)

View File

@ -27,7 +27,7 @@ type startOptions struct {
}
// NewStartCommand creates a new cobra.Command for `docker start`
func NewStartCommand(dockerCli command.Cli) *cobra.Command {
func NewStartCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts startOptions
cmd := &cobra.Command{
@ -53,7 +53,7 @@ func NewStartCommand(dockerCli command.Cli) *cobra.Command {
}
// nolint: gocyclo
func runStart(dockerCli command.Cli, opts *startOptions) error {
func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
ctx, cancelFun := context.WithCancel(context.Background())
if opts.attach || opts.openStdin {
@ -181,7 +181,7 @@ func runStart(dockerCli command.Cli, opts *startOptions) error {
return nil
}
func startContainersWithoutAttachments(ctx context.Context, dockerCli command.Cli, containers []string) error {
func startContainersWithoutAttachments(ctx context.Context, dockerCli *command.DockerCli, containers []string) error {
var failedContainers []string
for _, container := range containers {
if err := dockerCli.Client().ContainerStart(ctx, container, types.ContainerStartOptions{}); err != nil {

View File

@ -27,7 +27,7 @@ type statsOptions struct {
}
// NewStatsCommand creates a new cobra.Command for `docker stats`
func NewStatsCommand(dockerCli command.Cli) *cobra.Command {
func NewStatsCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts statsOptions
cmd := &cobra.Command{
@ -51,7 +51,7 @@ func NewStatsCommand(dockerCli command.Cli) *cobra.Command {
// runStats displays a live stream of resource usage statistics for one or more containers.
// This shows real-time information on CPU usage, memory usage, and network I/O.
// nolint: gocyclo
func runStats(dockerCli command.Cli, opts *statsOptions) error {
func runStats(dockerCli *command.DockerCli, opts *statsOptions) error {
showAll := len(opts.containers) == 0
closeChan := make(chan error)

View File

@ -200,8 +200,7 @@ func calculateCPUPercentWindows(v *types.StatsJSON) float64 {
return 0.00
}
func calculateBlockIO(blkio types.BlkioStats) (uint64, uint64) {
var blkRead, blkWrite uint64
func calculateBlockIO(blkio types.BlkioStats) (blkRead uint64, blkWrite uint64) {
for _, bioEntry := range blkio.IoServiceBytesRecursive {
switch strings.ToLower(bioEntry.Op) {
case "read":
@ -210,7 +209,7 @@ func calculateBlockIO(blkio types.BlkioStats) (uint64, uint64) {
blkWrite = blkWrite + bioEntry.Value
}
}
return blkRead, blkWrite
return
}
func calculateNetwork(network map[string]types.NetworkStats) (float64, float64) {

View File

@ -20,7 +20,7 @@ type stopOptions struct {
}
// NewStopCommand creates a new cobra.Command for `docker stop`
func NewStopCommand(dockerCli command.Cli) *cobra.Command {
func NewStopCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts stopOptions
cmd := &cobra.Command{
@ -39,7 +39,7 @@ func NewStopCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runStop(dockerCli command.Cli, opts *stopOptions) error {
func runStop(dockerCli *command.DockerCli, opts *stopOptions) error {
ctx := context.Background()
var timeout *time.Duration

View File

@ -18,7 +18,7 @@ type topOptions struct {
}
// NewTopCommand creates a new cobra.Command for `docker top`
func NewTopCommand(dockerCli command.Cli) *cobra.Command {
func NewTopCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts topOptions
cmd := &cobra.Command{
@ -38,7 +38,7 @@ func NewTopCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runTop(dockerCli command.Cli, opts *topOptions) error {
func runTop(dockerCli *command.DockerCli, opts *topOptions) error {
ctx := context.Background()
procList, err := dockerCli.Client().ContainerTop(ctx, opts.container, opts.args)

View File

@ -16,7 +16,7 @@ type unpauseOptions struct {
}
// NewUnpauseCommand creates a new cobra.Command for `docker unpause`
func NewUnpauseCommand(dockerCli command.Cli) *cobra.Command {
func NewUnpauseCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts unpauseOptions
cmd := &cobra.Command{
@ -31,7 +31,7 @@ func NewUnpauseCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runUnpause(dockerCli command.Cli, opts *unpauseOptions) error {
func runUnpause(dockerCli *command.DockerCli, opts *unpauseOptions) error {
ctx := context.Background()
var errs []string

View File

@ -35,7 +35,7 @@ type updateOptions struct {
}
// NewUpdateCommand creates a new cobra.Command for `docker update`
func NewUpdateCommand(dockerCli command.Cli) *cobra.Command {
func NewUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
var options updateOptions
cmd := &cobra.Command{
@ -72,7 +72,7 @@ func NewUpdateCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runUpdate(dockerCli command.Cli, options *updateOptions) error {
func runUpdate(dockerCli *command.DockerCli, options *updateOptions) error {
var err error
if options.nFlag == 0 {

View File

@ -13,7 +13,7 @@ import (
"golang.org/x/net/context"
)
func waitExitOrRemoved(ctx context.Context, dockerCli command.Cli, containerID string, waitRemove bool) <-chan int {
func waitExitOrRemoved(ctx context.Context, dockerCli *command.DockerCli, containerID string, waitRemove bool) <-chan int {
if len(containerID) == 0 {
// containerID can never be empty
panic("Internal Error: waitExitOrRemoved needs a containerID as parameter")
@ -47,7 +47,7 @@ func waitExitOrRemoved(ctx context.Context, dockerCli command.Cli, containerID s
return statusC
}
func legacyWaitExitOrRemoved(ctx context.Context, dockerCli command.Cli, containerID string, waitRemove bool) <-chan int {
func legacyWaitExitOrRemoved(ctx context.Context, dockerCli *command.DockerCli, containerID string, waitRemove bool) <-chan int {
var removeErr error
statusChan := make(chan int)
exitCode := 125

View File

@ -16,7 +16,7 @@ type waitOptions struct {
}
// NewWaitCommand creates a new cobra.Command for `docker wait`
func NewWaitCommand(dockerCli command.Cli) *cobra.Command {
func NewWaitCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts waitOptions
cmd := &cobra.Command{
@ -32,7 +32,7 @@ func NewWaitCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runWait(dockerCli command.Cli, opts *waitOptions) error {
func runWait(dockerCli *command.DockerCli, opts *waitOptions) error {
ctx := context.Background()
var errs []string

View File

@ -10,6 +10,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/go-units"
)
@ -164,7 +165,7 @@ func (c *containerContext) Image() string {
func (c *containerContext) Command() string {
command := c.c.Command
if c.trunc {
command = Ellipsis(command, 20)
command = stringutils.Ellipsis(command, 20)
}
return strconv.Quote(command)
}
@ -226,7 +227,7 @@ func (c *containerContext) Mounts() string {
name = m.Name
}
if c.trunc {
name = Ellipsis(name, 15)
name = stringutils.Ellipsis(name, 15)
}
mounts = append(mounts, name)
}

View File

@ -66,7 +66,7 @@ func TestContainerPsContext(t *testing.T) {
Source: "/a/path",
},
},
}, true, "this-is-a-long…", ctx.Mounts},
}, true, "this-is-a-lo...", ctx.Mounts},
{types.Container{
Mounts: []types.MountPoint{
{

View File

@ -118,11 +118,11 @@ func (ctx *DiskUsageContext) Write() (err error) {
return err
}
func (ctx *DiskUsageContext) verboseWrite() error {
func (ctx *DiskUsageContext) verboseWrite() (err error) {
// First images
tmpl, err := ctx.startSubsection(defaultDiskUsageImageTableFormat)
if err != nil {
return err
return
}
ctx.Output.Write([]byte("Images space usage:\n\n"))
@ -141,14 +141,14 @@ func (ctx *DiskUsageContext) verboseWrite() error {
}
}
err := ctx.contextFormat(tmpl, &imageContext{
err = ctx.contextFormat(tmpl, &imageContext{
repo: repo,
tag: tag,
trunc: true,
i: *i,
})
if err != nil {
return err
return
}
}
ctx.postFormat(tmpl, newImageContext())
@ -157,14 +157,17 @@ func (ctx *DiskUsageContext) verboseWrite() error {
ctx.Output.Write([]byte("\nContainers space usage:\n\n"))
tmpl, err = ctx.startSubsection(defaultDiskUsageContainerTableFormat)
if err != nil {
return err
return
}
for _, c := range ctx.Containers {
// Don't display the virtual size
c.SizeRootFs = 0
err := ctx.contextFormat(tmpl, &containerContext{trunc: true, c: *c})
err = ctx.contextFormat(tmpl, &containerContext{
trunc: true,
c: *c,
})
if err != nil {
return err
return
}
}
ctx.postFormat(tmpl, newContainerContext())
@ -173,18 +176,21 @@ func (ctx *DiskUsageContext) verboseWrite() error {
ctx.Output.Write([]byte("\nLocal Volumes space usage:\n\n"))
tmpl, err = ctx.startSubsection(defaultDiskUsageVolumeTableFormat)
if err != nil {
return err
return
}
for _, v := range ctx.Volumes {
if err := ctx.contextFormat(tmpl, &volumeContext{v: *v}); err != nil {
return err
err = ctx.contextFormat(tmpl, &volumeContext{
v: *v,
})
if err != nil {
return
}
}
ctx.postFormat(tmpl, newVolumeContext())
// And build cache
fmt.Fprintf(ctx.Output, "\nBuild cache usage: %s\n\n", units.HumanSize(float64(ctx.BuilderSize)))
return nil
return
}
type diskUsageImagesContext struct {

View File

@ -1,61 +0,0 @@
package formatter
import (
"unicode/utf8"
"golang.org/x/text/width"
)
// charWidth returns the number of horizontal positions a character occupies,
// and is used to account for wide characters when displaying strings.
//
// In a broad sense, wide characters include East Asian Wide, East Asian Full-width,
// (when not in East Asian context) see http://unicode.org/reports/tr11/.
func charWidth(r rune) int {
switch width.LookupRune(r).Kind() {
case width.EastAsianWide, width.EastAsianFullwidth:
return 2
default:
return 1
}
}
// Ellipsis truncates a string to fit within maxDisplayWidth, and appends ellipsis (…).
// For maxDisplayWidth of 1 and lower, no ellipsis is appended.
// For maxDisplayWidth of 1, first char of string will return even if its width > 1.
func Ellipsis(s string, maxDisplayWidth int) string {
if maxDisplayWidth <= 0 {
return ""
}
rs := []rune(s)
if maxDisplayWidth == 1 {
return string(rs[0])
}
byteLen := len(s)
if byteLen == utf8.RuneCountInString(s) {
if byteLen <= maxDisplayWidth {
return s
}
return string(rs[:maxDisplayWidth-1]) + "…"
}
var (
display []int
displayWidth int
)
for _, r := range rs {
cw := charWidth(r)
displayWidth += cw
display = append(display, displayWidth)
}
if displayWidth <= maxDisplayWidth {
return s
}
for i := range display {
if display[i] <= maxDisplayWidth-1 && display[i+1] > maxDisplayWidth-1 {
return string(rs[:i+1]) + "…"
}
}
return s
}

View File

@ -1,30 +0,0 @@
package formatter
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestEllipsis(t *testing.T) {
var testcases = []struct {
source string
width int
expected string
}{
{source: "t🐳ststring", width: 0, expected: ""},
{source: "t🐳ststring", width: 1, expected: "t"},
{source: "t🐳ststring", width: 2, expected: "t…"},
{source: "t🐳ststring", width: 6, expected: "t🐳st…"},
{source: "t🐳ststring", width: 20, expected: "t🐳ststring"},
{source: "你好世界teststring", width: 0, expected: ""},
{source: "你好世界teststring", width: 1, expected: "你"},
{source: "你好世界teststring", width: 3, expected: "你…"},
{source: "你好世界teststring", width: 6, expected: "你好…"},
{source: "你好世界teststring", width: 20, expected: "你好世界teststring"},
}
for _, testcase := range testcases {
assert.Equal(t, testcase.expected, Ellipsis(testcase.source, testcase.width))
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
units "github.com/docker/go-units"
)
@ -92,7 +93,7 @@ func (c *historyContext) CreatedSince() string {
func (c *historyContext) CreatedBy() string {
createdBy := strings.Replace(c.h.CreatedBy, "\t", " ", -1)
if c.trunc {
return Ellipsis(createdBy, 45)
return stringutils.Ellipsis(createdBy, 45)
}
return createdBy
}

View File

@ -10,6 +10,7 @@ import (
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/stretchr/testify/assert"
)
@ -95,7 +96,7 @@ func TestHistoryContext_CreatedBy(t *testing.T) {
historyContext{
h: image.HistoryResponseItem{CreatedBy: withTabs},
trunc: true,
}, Ellipsis(expected, 45), ctx.CreatedBy,
}, stringutils.Ellipsis(expected, 45), ctx.CreatedBy,
},
}
@ -190,7 +191,7 @@ imageID3 24 hours ago /bin/bash ls
imageID4 24 hours ago /bin/bash grep 183MB Hi
`
expectedTrunc := `IMAGE CREATED CREATED BY SIZE COMMENT
imageID1 24 hours ago /bin/bash ls && npm i && npm run test && kar… 183MB Hi
imageID1 24 hours ago /bin/bash ls && npm i && npm run test && k... 183MB Hi
imageID2 24 hours ago /bin/bash echo 183MB Hi
imageID3 24 hours ago /bin/bash ls 183MB Hi
imageID4 24 hours ago /bin/bash grep 183MB Hi

View File

@ -5,6 +5,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
)
const (
@ -79,7 +80,7 @@ func (c *pluginContext) Description() string {
desc := strings.Replace(c.p.Config.Description, "\n", "", -1)
desc = strings.Replace(desc, "\r", "", -1)
if c.trunc {
desc = Ellipsis(desc, 45)
desc = stringutils.Ellipsis(desc, 45)
}
return desc

View File

@ -5,6 +5,7 @@ import (
"strings"
registry "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/stringutils"
)
const (
@ -72,7 +73,7 @@ func (c *searchContext) Description() string {
desc := strings.Replace(c.s.Description, "\n", " ", -1)
desc = strings.Replace(desc, "\r", " ", -1)
if c.trunc {
desc = Ellipsis(desc, 45)
desc = stringutils.Ellipsis(desc, 45)
}
return desc
}

View File

@ -7,6 +7,7 @@ import (
"testing"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/stringutils"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
@ -78,7 +79,7 @@ func TestSearchContextDescription(t *testing.T) {
{searchContext{
s: registrytypes.SearchResult{Description: longDescription},
trunc: true,
}, Ellipsis(longDescription, 45), ctx.Description},
}, stringutils.Ellipsis(longDescription, 45), ctx.Description},
{searchContext{
s: registrytypes.SearchResult{Description: descriptionWReturns},
trunc: false,
@ -86,7 +87,7 @@ func TestSearchContextDescription(t *testing.T) {
{searchContext{
s: registrytypes.SearchResult{Description: descriptionWReturns},
trunc: true,
}, Ellipsis(longDescription, 45), ctx.Description},
}, stringutils.Ellipsis(longDescription, 45), ctx.Description},
}
for _, c := range cases {

View File

@ -64,7 +64,6 @@ type buildOptions struct {
target string
imageIDFile string
stream bool
platform string
}
// dockerfileFromStdin returns true when the user specified that the Dockerfile
@ -136,7 +135,6 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file")
command.AddTrustVerificationFlags(flags)
command.AddPlatformFlag(flags, &options.platform)
flags.BoolVar(&options.squash, "squash", false, "Squash newly built layers into a single new layer")
flags.SetAnnotation("squash", "experimental", nil)
@ -307,8 +305,8 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
progressOutput = &lastProgressOutput{output: progressOutput}
}
// if up to this point nothing has set the context then we must have another
// way for sending it(streaming) and set the context to the Dockerfile
// if up to this point nothing has set the context then we must have have
// another way for sending it(streaming) and set the context to the Dockerfile
if dockerfileCtx != nil && buildCtx == nil {
buildCtx = dockerfileCtx
}
@ -376,7 +374,6 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
ExtraHosts: options.extraHosts.GetAll(),
Target: options.target,
RemoteContext: remote,
Platform: options.platform,
}
if s != nil {

View File

@ -128,18 +128,18 @@ func getBuildSharedKey(dir string) (string, error) {
return hex.EncodeToString(s[:]), nil
}
func tryNodeIdentifier() string {
out := cliconfig.Dir() // return config dir as default on permission error
func tryNodeIdentifier() (out string) {
out = cliconfig.Dir() // return config dir as default on permission error
if err := os.MkdirAll(cliconfig.Dir(), 0700); err == nil {
sessionFile := filepath.Join(cliconfig.Dir(), ".buildNodeID")
if _, err := os.Lstat(sessionFile); err != nil {
if os.IsNotExist(err) { // create a new file with stored randomness
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return out
return
}
if err := ioutil.WriteFile(sessionFile, []byte(hex.EncodeToString(b)), 0600); err != nil {
return out
return
}
}
}
@ -149,5 +149,5 @@ func tryNodeIdentifier() string {
return string(dt)
}
}
return out
return
}

View File

@ -37,7 +37,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
return nil
},
Annotations: map[string]string{"version": "1.25"},
Tags: map[string]string{"version": "1.25"},
}
flags := cmd.Flags()
@ -65,12 +65,12 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint6
warning = allImageWarning
}
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return 0, "", nil
return
}
report, err := dockerCli.Client().ImagesPrune(context.Background(), pruneFilters)
if err != nil {
return 0, "", err
return
}
if len(report.ImagesDeleted) > 0 {
@ -85,7 +85,7 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint6
spaceReclaimed = report.SpaceReclaimed
}
return spaceReclaimed, output, nil
return
}
// RunPrune calls the Image Prune API

View File

@ -14,9 +14,8 @@ import (
)
type pullOptions struct {
remote string
all bool
platform string
remote string
all bool
}
// NewPullCommand creates a new `docker pull` command
@ -36,8 +35,6 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.BoolVarP(&opts.all, "all-tags", "a", false, "Download all tagged images in the repository")
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags)
return cmd
@ -66,9 +63,9 @@ func runPull(cli command.Cli, opts pullOptions) error {
// Check if reference has a digest
_, isCanonical := distributionRef.(reference.Canonical)
if command.IsTrusted() && !isCanonical {
err = trustedPull(ctx, cli, imgRefAndAuth, opts.platform)
err = trustedPull(ctx, cli, imgRefAndAuth)
} else {
err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts.all, opts.platform)
err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts.all)
}
if err != nil {
if strings.Contains(err.Error(), "when fetching 'plugin'") {

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
apiclient "github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -57,13 +56,9 @@ func runRemove(dockerCli command.Cli, opts removeOptions, images []string) error
}
var errs []string
var fatalErr = false
for _, img := range images {
dels, err := client.ImageRemove(ctx, img, options)
if err != nil {
if !apiclient.IsErrNotFound(err) {
fatalErr = true
}
errs = append(errs, err.Error())
} else {
for _, del := range dels {
@ -78,7 +73,7 @@ func runRemove(dockerCli command.Cli, opts removeOptions, images []string) error
if len(errs) > 0 {
msg := strings.Join(errs, "\n")
if !opts.force || fatalErr {
if !opts.force {
return errors.New(msg)
}
fmt.Fprintf(dockerCli.Err(), msg)

View File

@ -13,18 +13,6 @@ import (
"github.com/stretchr/testify/assert"
)
type notFound struct {
imageID string
}
func (n notFound) Error() string {
return fmt.Sprintf("Error: No such image: %s", n.imageID)
}
func (n notFound) NotFound() bool {
return true
}
func TestNewRemoveCommandAlias(t *testing.T) {
cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}))
assert.True(t, cmd.HasAlias("rmi"))
@ -43,15 +31,6 @@ func TestNewRemoveCommandErrors(t *testing.T) {
name: "wrong args",
expectedError: "requires at least 1 argument.",
},
{
name: "ImageRemove fail with force option",
args: []string{"-f", "image1"},
expectedError: "error removing image",
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Equal(t, "image1", image)
return []types.ImageDeleteResponseItem{}, errors.Errorf("error removing image")
},
},
{
name: "ImageRemove fail",
args: []string{"arg1"},
@ -64,14 +43,12 @@ func TestNewRemoveCommandErrors(t *testing.T) {
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cmd := NewRemoveCommand(test.NewFakeCli(&fakeClient{
imageRemoveFunc: tc.imageRemoveFunc,
}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
})
cmd := NewRemoveCommand(test.NewFakeCli(&fakeClient{
imageRemoveFunc: tc.imageRemoveFunc,
}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -80,7 +57,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
name string
args []string
imageRemoveFunc func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error)
expectedStderr string
expectedErrMsg string
}{
{
name: "Image Deleted",
@ -91,16 +68,14 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
},
},
{
name: "Image not found with force option",
name: "Image Deleted with force option",
args: []string{"-f", "image1"},
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Equal(t, "image1", image)
assert.Equal(t, true, options.Force)
return []types.ImageDeleteResponseItem{}, notFound{"image1"}
return []types.ImageDeleteResponseItem{}, errors.Errorf("error removing image")
},
expectedStderr: "Error: No such image: image1",
expectedErrMsg: "error removing image",
},
{
name: "Image Untagged",
args: []string{"image1"},
@ -121,14 +96,14 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{imageRemoveFunc: tc.imageRemoveFunc})
cmd := NewRemoveCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.NoError(t, cmd.Execute())
assert.Equal(t, tc.expectedStderr, cli.ErrBuffer().String())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("remove-command-success.%s.golden", tc.name))
})
cli := test.NewFakeCli(&fakeClient{imageRemoveFunc: tc.imageRemoveFunc})
cmd := NewRemoveCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.NoError(t, cmd.Execute())
if tc.expectedErrMsg != "" {
assert.Equal(t, tc.expectedErrMsg, cli.ErrBuffer().String())
}
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("remove-command-success.%s.golden", tc.name))
}
}

View File

@ -14,11 +14,11 @@ import (
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry"
"github.com/docker/notary/client"
"github.com/docker/notary/tuf/data"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/tuf/data"
"golang.org/x/net/context"
)
@ -84,7 +84,7 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
if err := jsonmessage.DisplayJSONMessagesToStream(in, streams.Out(), nil); err != nil {
return err
}
fmt.Fprintln(streams.Err(), "No tag specified, skipping trust metadata push")
fmt.Fprintln(streams.Out(), "No tag specified, skipping trust metadata push")
return nil
}
@ -97,14 +97,16 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
}
if target == nil {
return errors.Errorf("no targets found, please provide a specific tag in order to sign it")
fmt.Fprintln(streams.Out(), "No targets found, please provide a specific tag in order to sign it")
return nil
}
fmt.Fprintln(streams.Out(), "Signing and pushing trust metadata")
repo, err := trust.GetNotaryRepository(streams.In(), streams.Out(), command.UserAgent(), repoInfo, &authConfig, "push", "pull")
if err != nil {
return errors.Wrap(err, "error establishing connection to trust repository")
fmt.Fprintf(streams.Out(), "Error establishing connection to notary repository: %s\n", err)
return err
}
// get the latest repository metadata so we can figure out which roles to sign
@ -144,11 +146,11 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
}
if err != nil {
err = errors.Wrapf(err, "failed to sign %s:%s", repoInfo.Name.Name(), tag)
fmt.Fprintf(streams.Out(), "Failed to sign %q:%s - %s\n", repoInfo.Name.Name(), tag, err.Error())
return trust.NotaryError(repoInfo.Name.Name(), err)
}
fmt.Fprintf(streams.Out(), "Successfully signed %s:%s\n", repoInfo.Name.Name(), tag)
fmt.Fprintf(streams.Out(), "Successfully signed %q:%s\n", repoInfo.Name.Name(), tag)
return nil
}
@ -180,7 +182,7 @@ func imagePushPrivileged(ctx context.Context, cli command.Cli, authConfig types.
}
// trustedPull handles content trust pulling of an image
func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, platform string) error {
func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) error {
refs, err := getTrustedPullTargets(cli, imgRefAndAuth)
if err != nil {
return err
@ -202,7 +204,7 @@ func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.Image
if err != nil {
return err
}
if err := imagePullPrivileged(ctx, cli, updatedImgRefAndAuth, false, platform); err != nil {
if err := imagePullPrivileged(ctx, cli, updatedImgRefAndAuth, false); err != nil {
return err
}
@ -221,7 +223,8 @@ func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.Image
func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) ([]target, error) {
notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPullOnly)
if err != nil {
return nil, errors.Wrap(err, "error establishing connection to trust repository")
fmt.Fprintf(cli.Out(), "Error establishing connection to trust repository: %s\n", err)
return nil, err
}
ref := imgRefAndAuth.Reference()
@ -236,7 +239,7 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
for _, tgt := range targets {
t, err := convertTarget(tgt.Target)
if err != nil {
fmt.Fprintf(cli.Err(), "Skipping target for %q\n", reference.FamiliarName(ref))
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
continue
}
// Only list tags in the top level targets role or the releases delegation role - ignore
@ -262,13 +265,13 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
return nil, trust.NotaryError(ref.Name(), errors.Errorf("No trust data for %s", tagged.Tag()))
}
logrus.Debugf("retrieving target for %s role", t.Role)
logrus.Debugf("retrieving target for %s role\n", t.Role)
r, err := convertTarget(t.Target)
return []target{r}, err
}
// imagePullPrivileged pulls the image and displays it to the output
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, all bool, platform string) error {
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, all bool) error {
ref := reference.FamiliarString(imgRefAndAuth.Reference())
encodedAuth, err := command.EncodeAuthToBase64(*imgRefAndAuth.AuthConfig())
@ -280,8 +283,8 @@ func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth tru
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
All: all,
Platform: platform,
}
responseBody, err := cli.Client().ImagePull(ctx, ref, options)
if err != nil {
return err
@ -311,7 +314,8 @@ func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedT
notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull")
if err != nil {
return nil, errors.Wrap(err, "error establishing connection to trust repository")
fmt.Fprintf(cli.Out(), "Error establishing connection to trust repository: %s\n", err)
return nil, err
}
t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
@ -328,6 +332,7 @@ func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedT
return nil, err
}
return reference.WithDigest(reference.TrimNamed(ref), r.digest)
}
@ -350,7 +355,7 @@ func TagTrusted(ctx context.Context, cli command.Cli, trustedRef reference.Canon
familiarRef := reference.FamiliarString(ref)
trustedFamiliarRef := reference.FamiliarString(trustedRef)
fmt.Fprintf(cli.Err(), "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
fmt.Fprintf(cli.Out(), "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef)
}

View File

@ -8,11 +8,11 @@ import (
"github.com/docker/cli/cli/trust"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/registry"
"github.com/docker/notary/client"
"github.com/docker/notary/passphrase"
"github.com/docker/notary/trustpinning"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/trustpinning"
)
func unsetENV() {

View File

@ -33,7 +33,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
}
return nil
},
Annotations: map[string]string{"version": "1.25"},
Tags: map[string]string{"version": "1.25"},
}
flags := cmd.Flags()
@ -50,12 +50,12 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (output string, err e
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
return "", nil
return
}
report, err := dockerCli.Client().NetworksPrune(context.Background(), pruneFilters)
if err != nil {
return "", err
return
}
if len(report.NetworksDeleted) > 0 {
@ -65,7 +65,7 @@ func runPrune(dockerCli command.Cli, options pruneOptions) (output string, err e
}
}
return output, nil
return
}
// RunPrune calls the Network Prune API

View File

@ -14,11 +14,11 @@ import (
// NewNodeCommand returns a cobra command for `node` subcommands
func NewNodeCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Manage Swarm nodes",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.24"},
Use: "node",
Short: "Manage Swarm nodes",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.24"},
}
cmd.AddCommand(
newDemoteCommand(dockerCli),

View File

@ -7,13 +7,14 @@ import (
)
// NewPluginCommand returns a cobra command for `plugin` subcommands
func NewPluginCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewPluginCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "plugin",
Short: "Manage plugins",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.25"},
Use: "plugin",
Short: "Manage plugins",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.25"},
}
cmd.AddCommand(

View File

@ -63,7 +63,7 @@ type pluginCreateOptions struct {
compress bool
}
func newCreateCommand(dockerCli command.Cli) *cobra.Command {
func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
options := pluginCreateOptions{}
cmd := &cobra.Command{
@ -84,7 +84,7 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runCreate(dockerCli command.Cli, options pluginCreateOptions) error {
func runCreate(dockerCli *command.DockerCli, options pluginCreateOptions) error {
var (
createCtx io.ReadCloser
err error

View File

@ -10,7 +10,7 @@ import (
"golang.org/x/net/context"
)
func newDisableCommand(dockerCli command.Cli) *cobra.Command {
func newDisableCommand(dockerCli *command.DockerCli) *cobra.Command {
var force bool
cmd := &cobra.Command{
@ -27,7 +27,7 @@ func newDisableCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runDisable(dockerCli command.Cli, name string, force bool) error {
func runDisable(dockerCli *command.DockerCli, name string, force bool) error {
if err := dockerCli.Client().PluginDisable(context.Background(), name, types.PluginDisableOptions{Force: force}); err != nil {
return err
}

View File

@ -16,7 +16,7 @@ type enableOpts struct {
name string
}
func newEnableCommand(dockerCli command.Cli) *cobra.Command {
func newEnableCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts enableOpts
cmd := &cobra.Command{
@ -34,7 +34,7 @@ func newEnableCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runEnable(dockerCli command.Cli, opts *enableOpts) error {
func runEnable(dockerCli *command.DockerCli, opts *enableOpts) error {
name := opts.name
if opts.timeout < 0 {
return errors.Errorf("negative timeout %d is invalid", opts.timeout)

View File

@ -13,7 +13,7 @@ type inspectOptions struct {
format string
}
func newInspectCommand(dockerCli command.Cli) *cobra.Command {
func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts inspectOptions
cmd := &cobra.Command{
@ -31,7 +31,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runInspect(dockerCli command.Cli, opts inspectOptions) error {
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
client := dockerCli.Client()
ctx := context.Background()
getRef := func(ref string) (interface{}, []byte, error) {

View File

@ -31,7 +31,7 @@ func loadPullFlags(opts *pluginOptions, flags *pflag.FlagSet) {
command.AddTrustVerificationFlags(flags)
}
func newInstallCommand(dockerCli command.Cli) *cobra.Command {
func newInstallCommand(dockerCli *command.DockerCli) *cobra.Command {
var options pluginOptions
cmd := &cobra.Command{
Use: "install [OPTIONS] PLUGIN [KEY=VALUE...]",
@ -57,12 +57,12 @@ type pluginRegistryService struct {
registry.Service
}
func (s pluginRegistryService) ResolveRepository(name reference.Named) (*registry.RepositoryInfo, error) {
repoInfo, err := s.Service.ResolveRepository(name)
func (s pluginRegistryService) ResolveRepository(name reference.Named) (repoInfo *registry.RepositoryInfo, err error) {
repoInfo, err = s.Service.ResolveRepository(name)
if repoInfo != nil {
repoInfo.Class = "plugin"
}
return repoInfo, err
return
}
func newRegistryService() (registry.Service, error) {
@ -73,7 +73,7 @@ func newRegistryService() (registry.Service, error) {
return pluginRegistryService{Service: svc}, nil
}
func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOptions, cmdName string) (types.PluginInstallOptions, error) {
func buildPullConfig(ctx context.Context, dockerCli *command.DockerCli, opts pluginOptions, cmdName string) (types.PluginInstallOptions, error) {
// Names with both tag and digest will be treated by the daemon
// as a pull by digest with a local name for the tag
// (if no local name is provided).
@ -130,7 +130,7 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
return options, nil
}
func runInstall(dockerCli command.Cli, opts pluginOptions) error {
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
var localName string
if opts.localName != "" {
aref, err := reference.ParseNormalizedNamed(opts.localName)
@ -163,7 +163,7 @@ func runInstall(dockerCli command.Cli, opts pluginOptions) error {
return nil
}
func acceptPrivileges(dockerCli command.Cli, name string) func(privileges types.PluginPrivileges) (bool, error) {
func acceptPrivileges(dockerCli *command.DockerCli, name string) func(privileges types.PluginPrivileges) (bool, error) {
return func(privileges types.PluginPrivileges) (bool, error) {
fmt.Fprintf(dockerCli.Out(), "Plugin %q is requesting the following privileges:\n", name)
for _, privilege := range privileges {

View File

@ -16,7 +16,7 @@ type listOptions struct {
filter opts.FilterOpt
}
func newListCommand(dockerCli command.Cli) *cobra.Command {
func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
options := listOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
@ -39,7 +39,7 @@ func newListCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runList(dockerCli command.Cli, options listOptions) error {
func runList(dockerCli *command.DockerCli, options listOptions) error {
plugins, err := dockerCli.Client().PluginList(context.Background(), options.filter.Value())
if err != nil {
return err

View File

@ -16,7 +16,7 @@ type rmOptions struct {
plugins []string
}
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts rmOptions
cmd := &cobra.Command{
@ -35,7 +35,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runRemove(dockerCli command.Cli, opts *rmOptions) error {
func runRemove(dockerCli *command.DockerCli, opts *rmOptions) error {
ctx := context.Background()
var errs cli.Errors

View File

@ -8,7 +8,7 @@ import (
"github.com/spf13/cobra"
)
func newSetCommand(dockerCli command.Cli) *cobra.Command {
func newSetCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "set PLUGIN KEY=VALUE [KEY=VALUE...]",
Short: "Change settings for a plugin",

View File

@ -13,7 +13,7 @@ import (
"github.com/spf13/cobra"
)
func newUpgradeCommand(dockerCli command.Cli) *cobra.Command {
func newUpgradeCommand(dockerCli *command.DockerCli) *cobra.Command {
var options pluginOptions
cmd := &cobra.Command{
Use: "upgrade [OPTIONS] PLUGIN [REMOTE]",
@ -26,7 +26,7 @@ func newUpgradeCommand(dockerCli command.Cli) *cobra.Command {
}
return runUpgrade(dockerCli, options)
},
Annotations: map[string]string{"version": "1.26"},
Tags: map[string]string{"version": "1.26"},
}
flags := cmd.Flags()
@ -35,7 +35,7 @@ func newUpgradeCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runUpgrade(dockerCli command.Cli, opts pluginOptions) error {
func runUpgrade(dockerCli *command.DockerCli, opts pluginOptions) error {
ctx := context.Background()
p, _, err := dockerCli.Client().PluginInspectWithRaw(ctx, opts.localName)
if err != nil {

View File

@ -8,13 +8,14 @@ import (
)
// NewSecretCommand returns a cobra command for `secret` subcommands
func NewSecretCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewSecretCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "secret",
Short: "Manage Docker secrets",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.25"},
Use: "secret",
Short: "Manage Docker secrets",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.25"},
}
cmd.AddCommand(
newSecretListCommand(dockerCli),

View File

@ -14,7 +14,6 @@ type fakeClient struct {
serviceInspectWithRawFunc func(ctx context.Context, serviceID string, options types.ServiceInspectOptions) (swarm.Service, []byte, error)
serviceUpdateFunc func(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error)
serviceListFunc func(context.Context, types.ServiceListOptions) ([]swarm.Service, error)
taskListFunc func(context.Context, types.TaskListOptions) ([]swarm.Task, error)
infoFunc func(ctx context.Context) (types.Info, error)
}
@ -23,9 +22,6 @@ func (f *fakeClient) NodeList(ctx context.Context, options types.NodeListOptions
}
func (f *fakeClient) TaskList(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
if f.taskListFunc != nil {
return f.taskListFunc(ctx, options)
}
return nil, nil
}

View File

@ -8,13 +8,14 @@ import (
)
// NewServiceCommand returns a cobra command for `service` subcommands
func NewServiceCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewServiceCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "service",
Short: "Manage services",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.24"},
Use: "service",
Short: "Manage services",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.24"},
}
cmd.AddCommand(
newCreateCommand(dockerCli),

View File

@ -5,7 +5,6 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
cliopts "github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
"github.com/spf13/cobra"
@ -59,9 +58,6 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
flags.Var(&opts.hosts, flagHost, "Set one or more custom host-to-IP mappings (host:ip)")
flags.SetAnnotation(flagHost, "version", []string{"1.25"})
flags.Var(cliopts.NewListOptsRef(&opts.resources.resGenericResources, ValidateSingleGenericResource), "generic-resource", "User defined resources")
flags.SetAnnotation(flagHostAdd, "version", []string{"1.32"})
flags.SetInterspersed(false)
return cmd
}

View File

@ -1,105 +0,0 @@
package service
import (
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/docker/docker/api/types/swarm"
swarmapi "github.com/docker/swarmkit/api"
"github.com/docker/swarmkit/api/genericresource"
)
// GenericResource is a concept that a user can use to advertise user-defined
// resources on a node and thus better place services based on these resources.
// E.g: NVIDIA GPUs, Intel FPGAs, ...
// See https://github.com/docker/swarmkit/blob/master/design/generic_resources.md
// ValidateSingleGenericResource validates that a single entry in the
// generic resource list is valid.
// i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't
func ValidateSingleGenericResource(val string) (string, error) {
if strings.Count(val, "=") < 1 {
return "", fmt.Errorf("invalid generic-resource format `%s` expected `name=value`", val)
}
return val, nil
}
// ParseGenericResources parses an array of Generic resourceResources
// Requesting Named Generic Resources for a service is not supported this
// is filtered here.
func ParseGenericResources(value []string) ([]swarm.GenericResource, error) {
if len(value) == 0 {
return nil, nil
}
resources, err := genericresource.Parse(value)
if err != nil {
return nil, errors.Wrapf(err, "invalid generic resource specification")
}
swarmResources := genericResourcesFromGRPC(resources)
for _, res := range swarmResources {
if res.NamedResourceSpec != nil {
return nil, fmt.Errorf("invalid generic-resource request `%s=%s`, Named Generic Resources is not supported for service create or update", res.NamedResourceSpec.Kind, res.NamedResourceSpec.Value)
}
}
return swarmResources, nil
}
// genericResourcesFromGRPC converts a GRPC GenericResource to a GenericResource
func genericResourcesFromGRPC(genericRes []*swarmapi.GenericResource) []swarm.GenericResource {
var generic []swarm.GenericResource
for _, res := range genericRes {
var current swarm.GenericResource
switch r := res.Resource.(type) {
case *swarmapi.GenericResource_DiscreteResourceSpec:
current.DiscreteResourceSpec = &swarm.DiscreteGenericResource{
Kind: r.DiscreteResourceSpec.Kind,
Value: r.DiscreteResourceSpec.Value,
}
case *swarmapi.GenericResource_NamedResourceSpec:
current.NamedResourceSpec = &swarm.NamedGenericResource{
Kind: r.NamedResourceSpec.Kind,
Value: r.NamedResourceSpec.Value,
}
}
generic = append(generic, current)
}
return generic
}
func buildGenericResourceMap(genericRes []swarm.GenericResource) (map[string]swarm.GenericResource, error) {
m := make(map[string]swarm.GenericResource)
for _, res := range genericRes {
if res.DiscreteResourceSpec == nil {
return nil, fmt.Errorf("invalid generic-resource `%+v` for service task", res)
}
_, ok := m[res.DiscreteResourceSpec.Kind]
if ok {
return nil, fmt.Errorf("duplicate generic-resource `%+v` for service task", res.DiscreteResourceSpec.Kind)
}
m[res.DiscreteResourceSpec.Kind] = res
}
return m, nil
}
func buildGenericResourceList(genericRes map[string]swarm.GenericResource) []swarm.GenericResource {
var l []swarm.GenericResource
for _, res := range genericRes {
l = append(l, res)
}
return l
}

View File

@ -1,22 +0,0 @@
package service
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidateSingleGenericResource(t *testing.T) {
incorrect := []string{"foo", "fooo-bar"}
correct := []string{"foo=bar", "bar=1", "foo=barbar"}
for _, v := range incorrect {
_, err := ValidateSingleGenericResource(v)
assert.Error(t, err)
}
for _, v := range correct {
_, err := ValidateSingleGenericResource(v)
assert.NoError(t, err)
}
}

View File

@ -54,7 +54,7 @@ func runInspect(dockerCli command.Cli, opts inspectOptions) error {
getRef := func(ref string) (interface{}, []byte, error) {
// Service inspect shows defaults values in empty fields.
service, _, err := client.ServiceInspectWithRaw(ctx, ref, types.ServiceInspectOptions{InsertDefaults: true})
if err == nil || !apiclient.IsErrNotFound(err) {
if err == nil || !apiclient.IsErrServiceNotFound(err) {
return service, nil, err
}
return nil, nil, errors.Errorf("Error: no such service: %s", ref)
@ -62,7 +62,7 @@ func runInspect(dockerCli command.Cli, opts inspectOptions) error {
getNetwork := func(ref string) (interface{}, []byte, error) {
network, _, err := client.NetworkInspectWithRaw(ctx, ref, types.NetworkInspectOptions{Scope: "swarm"})
if err == nil || !apiclient.IsErrNotFound(err) {
if err == nil || !apiclient.IsErrNetworkNotFound(err) {
return network, nil, err
}
return nil, nil, errors.Errorf("Error: no such network: %s", ref)

View File

@ -37,7 +37,7 @@ type logsOptions struct {
target string
}
func newLogsCommand(dockerCli command.Cli) *cobra.Command {
func newLogsCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts logsOptions
cmd := &cobra.Command{
@ -48,7 +48,7 @@ func newLogsCommand(dockerCli command.Cli) *cobra.Command {
opts.target = args[0]
return runLogs(dockerCli, &opts)
},
Annotations: map[string]string{"version": "1.29"},
Tags: map[string]string{"version": "1.29"},
}
flags := cmd.Flags()
@ -68,7 +68,7 @@ func newLogsCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runLogs(dockerCli command.Cli, opts *logsOptions) error {
func runLogs(dockerCli *command.DockerCli, opts *logsOptions) error {
ctx := context.Background()
options := types.ContainerLogsOptions{
@ -97,12 +97,12 @@ func runLogs(dockerCli command.Cli, opts *logsOptions) error {
service, _, err := cli.ServiceInspectWithRaw(ctx, opts.target, types.ServiceInspectOptions{})
if err != nil {
// if it's any error other than service not found, it's Real
if !client.IsErrNotFound(err) {
if !client.IsErrServiceNotFound(err) {
return err
}
task, _, err := cli.TaskInspectWithRaw(ctx, opts.target)
if err != nil {
if client.IsErrNotFound(err) {
if client.IsErrTaskNotFound(err) {
// if the task isn't found, rewrite the error to be clear
// that we looked for services AND tasks and found none
err = fmt.Errorf("no such task or service: %v", opts.target)

View File

@ -222,30 +222,23 @@ func (opts updateOptions) rollbackConfig(flags *pflag.FlagSet) *swarm.UpdateConf
}
type resourceOptions struct {
limitCPU opts.NanoCPUs
limitMemBytes opts.MemBytes
resCPU opts.NanoCPUs
resMemBytes opts.MemBytes
resGenericResources []string
limitCPU opts.NanoCPUs
limitMemBytes opts.MemBytes
resCPU opts.NanoCPUs
resMemBytes opts.MemBytes
}
func (r *resourceOptions) ToResourceRequirements() (*swarm.ResourceRequirements, error) {
generic, err := ParseGenericResources(r.resGenericResources)
if err != nil {
return nil, err
}
func (r *resourceOptions) ToResourceRequirements() *swarm.ResourceRequirements {
return &swarm.ResourceRequirements{
Limits: &swarm.Resources{
NanoCPUs: r.limitCPU.Value(),
MemoryBytes: r.limitMemBytes.Value(),
},
Reservations: &swarm.Resources{
NanoCPUs: r.resCPU.Value(),
MemoryBytes: r.resMemBytes.Value(),
GenericResources: generic,
NanoCPUs: r.resCPU.Value(),
MemoryBytes: r.resMemBytes.Value(),
},
}, nil
}
}
type restartPolicyOptions struct {
@ -361,7 +354,7 @@ func convertNetworks(ctx context.Context, apiClient client.NetworkAPIClient, net
if err != nil {
return nil, err
}
netAttach = append(netAttach, swarm.NetworkAttachmentConfig{
netAttach = append(netAttach, swarm.NetworkAttachmentConfig{ // nolint: gosimple
Target: net.Target,
Aliases: net.Aliases,
DriverOpts: net.DriverOpts,
@ -512,8 +505,6 @@ type serviceOptions struct {
healthcheck healthCheckOptions
secrets opts.SecretOpt
configs opts.ConfigOpt
isolation string
}
func newServiceOptions() *serviceOptions {
@ -595,11 +586,6 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
return service, err
}
resources, err := options.resources.ToResourceRequirements()
if err != nil {
return service, err
}
service = swarm.ServiceSpec{
Annotations: swarm.Annotations{
Name: options.name,
@ -628,10 +614,9 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
Hosts: convertExtraHostsToSwarmHosts(options.hosts.GetAll()),
StopGracePeriod: options.ToStopGracePeriod(flags),
Healthcheck: healthConfig,
Isolation: container.Isolation(options.isolation),
},
Networks: networks,
Resources: resources,
Resources: options.resources.ToResourceRequirements(),
RestartPolicy: options.restartPolicy.ToRestartPolicy(flags),
Placement: &swarm.Placement{
Constraints: options.constraints.GetAll(),
@ -799,8 +784,6 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValu
flags.StringVar(&opts.stopSignal, flagStopSignal, "", "Signal to stop the container")
flags.SetAnnotation(flagStopSignal, "version", []string{"1.28"})
flags.StringVar(&opts.isolation, flagIsolation, "", "Service container isolation mode")
flags.SetAnnotation(flagIsolation, "version", []string{"1.35"})
}
const (
@ -830,8 +813,6 @@ const (
flagEnvFile = "env-file"
flagEnvRemove = "env-rm"
flagEnvAdd = "env-add"
flagGenericResourcesRemove = "generic-resource-rm"
flagGenericResourcesAdd = "generic-resource-add"
flagGroup = "group"
flagGroupAdd = "group-add"
flagGroupRemove = "group-rm"
@ -898,5 +879,4 @@ const (
flagConfig = "config"
flagConfigAdd = "config-add"
flagConfigRemove = "config-rm"
flagIsolation = "isolation"
)

View File

@ -85,41 +85,3 @@ func TestHealthCheckOptionsToHealthConfigConflict(t *testing.T) {
_, err := opt.toHealthConfig()
assert.EqualError(t, err, "--no-healthcheck conflicts with --health-* options")
}
func TestResourceOptionsToResourceRequirements(t *testing.T) {
incorrectOptions := []resourceOptions{
{
resGenericResources: []string{"foo=bar", "foo=1"},
},
{
resGenericResources: []string{"foo=bar", "foo=baz"},
},
{
resGenericResources: []string{"foo=bar"},
},
{
resGenericResources: []string{"foo=1", "foo=2"},
},
}
for _, opt := range incorrectOptions {
_, err := opt.ToResourceRequirements()
assert.Error(t, err)
}
correctOptions := []resourceOptions{
{
resGenericResources: []string{"foo=1"},
},
{
resGenericResources: []string{"foo=1", "bar=2"},
},
}
for _, opt := range correctOptions {
r, err := opt.ToResourceRequirements()
assert.NoError(t, err)
assert.Len(t, r.Reservations.GenericResources, len(opt.resGenericResources))
}
}

View File

@ -69,9 +69,6 @@ func runPS(dockerCli command.Cli, options psOptions) error {
if len(format) == 0 {
format = task.DefaultFormat(dockerCli.ConfigFile(), options.quiet)
}
if options.quiet {
options.noTrunc = true
}
if err := task.Print(ctx, dockerCli, tasks, idresolver.New(client, options.noResolve), !options.noTrunc, options.quiet, format); err != nil {
return err
}

View File

@ -90,22 +90,6 @@ func TestRunPSWarnsOnNotFound(t *testing.T) {
assert.EqualError(t, err, "no such service: bar")
}
func TestRunPSQuiet(t *testing.T) {
client := &fakeClient{
serviceListFunc: func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
return []swarm.Service{{ID: "foo"}}, nil
},
taskListFunc: func(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error) {
return []swarm.Task{{ID: "sxabyp0obqokwekpun4rjo0b3"}}, nil
},
}
cli := test.NewFakeCli(client)
err := runPS(cli, psOptions{services: []string{"foo"}, quiet: true, filter: opts.NewFilterOpt()})
require.NoError(t, err)
assert.Equal(t, "sxabyp0obqokwekpun4rjo0b3\n", cli.OutBuffer().String())
}
func TestUpdateNodeFilter(t *testing.T) {
selfNodeID := "foofoo"
filter := filters.NewArgs()

View File

@ -21,7 +21,7 @@ func newRollbackCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runRollback(dockerCli, options, args[0])
},
Annotations: map[string]string{"version": "1.31"},
Tags: map[string]string{"version": "1.31"},
}
flags := cmd.Flags()

View File

@ -8,10 +8,10 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/registry"
"github.com/docker/notary/tuf/data"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/theupdateframework/notary/tuf/data"
"golang.org/x/net/context"
)

View File

@ -92,15 +92,9 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
flags.SetAnnotation(flagDNSOptionAdd, "version", []string{"1.25"})
flags.Var(&options.dnsSearch, flagDNSSearchAdd, "Add or update a custom DNS search domain")
flags.SetAnnotation(flagDNSSearchAdd, "version", []string{"1.25"})
flags.Var(&options.hosts, flagHostAdd, "Add a custom host-to-IP mapping (host:ip)")
flags.Var(&options.hosts, flagHostAdd, "Add or update a custom host-to-IP mapping (host:ip)")
flags.SetAnnotation(flagHostAdd, "version", []string{"1.25"})
// Add needs parsing, Remove only needs the key
flags.Var(newListOptsVar(), flagGenericResourcesRemove, "Remove a Generic resource")
flags.SetAnnotation(flagHostAdd, "version", []string{"1.32"})
flags.Var(newListOptsVarWithValidator(ValidateSingleGenericResource), flagGenericResourcesAdd, "Add a Generic resource")
flags.SetAnnotation(flagHostAdd, "version", []string{"1.32"})
return cmd
}
@ -108,10 +102,6 @@ func newListOptsVar() *opts.ListOpts {
return opts.NewListOptsRef(&[]string{}, nil)
}
func newListOptsVarWithValidator(validator opts.ValidatorFctType) *opts.ListOpts {
return opts.NewListOptsRef(&[]string{}, validator)
}
// nolint: gocyclo
func runUpdate(dockerCli command.Cli, flags *pflag.FlagSet, options *serviceOptions, serviceID string) error {
apiClient := dockerCli.Client()
@ -279,14 +269,6 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
}
}
updateIsolation := func(flag string, field *container.Isolation) error {
if flags.Changed(flag) {
val, _ := flags.GetString(flag)
*field = container.Isolation(val)
}
return nil
}
cspec := spec.TaskTemplate.ContainerSpec
task := &spec.TaskTemplate
@ -306,9 +288,6 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
updateString(flagWorkdir, &cspec.Dir)
updateString(flagUser, &cspec.User)
updateString(flagHostname, &cspec.Hostname)
if err := updateIsolation(flagIsolation, &cspec.Isolation); err != nil {
return err
}
if err := updateMounts(flags, &cspec.Mounts); err != nil {
return err
}
@ -324,14 +303,6 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
updateInt64Value(flagReserveMemory, &task.Resources.Reservations.MemoryBytes)
}
if err := addGenericResources(flags, task); err != nil {
return err
}
if err := removeGenericResources(flags, task); err != nil {
return err
}
updateDurationOpt(flagStopGracePeriod, &cspec.StopGracePeriod)
if anyChanged(flags, flagRestartCondition, flagRestartDelay, flagRestartMaxAttempts, flagRestartWindow) {
@ -488,72 +459,6 @@ func anyChanged(flags *pflag.FlagSet, fields ...string) bool {
return false
}
func addGenericResources(flags *pflag.FlagSet, spec *swarm.TaskSpec) error {
if !flags.Changed(flagGenericResourcesAdd) {
return nil
}
if spec.Resources == nil {
spec.Resources = &swarm.ResourceRequirements{}
}
if spec.Resources.Reservations == nil {
spec.Resources.Reservations = &swarm.Resources{}
}
values := flags.Lookup(flagGenericResourcesAdd).Value.(*opts.ListOpts).GetAll()
generic, err := ParseGenericResources(values)
if err != nil {
return err
}
m, err := buildGenericResourceMap(spec.Resources.Reservations.GenericResources)
if err != nil {
return err
}
for _, toAddRes := range generic {
m[toAddRes.DiscreteResourceSpec.Kind] = toAddRes
}
spec.Resources.Reservations.GenericResources = buildGenericResourceList(m)
return nil
}
func removeGenericResources(flags *pflag.FlagSet, spec *swarm.TaskSpec) error {
// Can only be Discrete Resources
if !flags.Changed(flagGenericResourcesRemove) {
return nil
}
if spec.Resources == nil {
spec.Resources = &swarm.ResourceRequirements{}
}
if spec.Resources.Reservations == nil {
spec.Resources.Reservations = &swarm.Resources{}
}
values := flags.Lookup(flagGenericResourcesRemove).Value.(*opts.ListOpts).GetAll()
m, err := buildGenericResourceMap(spec.Resources.Reservations.GenericResources)
if err != nil {
return err
}
for _, toRemoveRes := range values {
if _, ok := m[toRemoveRes]; !ok {
return fmt.Errorf("could not find generic-resource `%s` to remove it", toRemoveRes)
}
delete(m, toRemoveRes)
}
spec.Resources.Reservations.GenericResources = buildGenericResourceList(m)
return nil
}
func updatePlacementConstraints(flags *pflag.FlagSet, placement *swarm.Placement) {
if flags.Changed(flagConstraintAdd) {
values := flags.Lookup(flagConstraintAdd).Value.(*opts.ListOpts).GetAll()
@ -963,10 +868,6 @@ func updateReplicas(flags *pflag.FlagSet, serviceMode *swarm.ServiceMode) error
return nil
}
// updateHosts performs a diff between existing host entries, entries to be
// removed, and entries to be added. Host entries preserve the order in which they
// were added, as the specification mentions that in case multiple entries for a
// host exist, the first entry should be used (by default).
func updateHosts(flags *pflag.FlagSet, hosts *[]string) error {
// Combine existing Hosts (in swarmkit format) with the host to add (convert to swarmkit format)
if flags.Changed(flagHostAdd) {
@ -1001,6 +902,9 @@ func updateHosts(flags *pflag.FlagSet, hosts *[]string) error {
}
}
// Sort so that result is predictable.
sort.Strings(newHosts)
*hosts = newHosts
return nil
}

View File

@ -6,7 +6,6 @@ import (
"testing"
"time"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
@ -166,7 +165,7 @@ func TestUpdateDNSConfig(t *testing.T) {
// IPv6
flags.Set("dns-add", "2001:db8:abc8::1")
// Invalid dns record
testutil.ErrorContains(t, flags.Set("dns-add", "x.y.z.w"), "x.y.z.w is not an ip address")
assert.EqualError(t, flags.Set("dns-add", "x.y.z.w"), "x.y.z.w is not an ip address")
// domains with duplicates
flags.Set("dns-search-add", "example.com")
@ -174,7 +173,7 @@ func TestUpdateDNSConfig(t *testing.T) {
flags.Set("dns-search-add", "example.org")
flags.Set("dns-search-rm", "example.org")
// Invalid dns search domain
testutil.ErrorContains(t, flags.Set("dns-search-add", "example$com"), "example$com is not a valid domain")
assert.EqualError(t, flags.Set("dns-search-add", "example$com"), "example$com is not a valid domain")
flags.Set("dns-option-add", "ndots:9")
flags.Set("dns-option-rm", "timeout:3")
@ -363,26 +362,15 @@ func TestUpdateHosts(t *testing.T) {
// just hostname should work as well
flags.Set("host-rm", "example.net")
// bad format error
testutil.ErrorContains(t, flags.Set("host-add", "$example.com$"), `bad format for add-host: "$example.com$"`)
assert.EqualError(t, flags.Set("host-add", "$example.com$"), `bad format for add-host: "$example.com$"`)
hosts := []string{"1.2.3.4 example.com", "4.3.2.1 example.org", "2001:db8:abc8::1 example.net"}
expected := []string{"1.2.3.4 example.com", "4.3.2.1 example.org", "2001:db8:abc8::1 ipv6.net"}
err := updateHosts(flags, &hosts)
assert.NoError(t, err)
assert.Equal(t, expected, hosts)
}
func TestUpdateHostsPreservesOrder(t *testing.T) {
flags := newUpdateCommand(nil).Flags()
flags.Set("host-add", "foobar:127.0.0.2")
flags.Set("host-add", "foobar:127.0.0.1")
flags.Set("host-add", "foobar:127.0.0.3")
hosts := []string{}
err := updateHosts(flags, &hosts)
assert.NoError(t, err)
assert.Equal(t, []string{"127.0.0.2 foobar", "127.0.0.1 foobar", "127.0.0.3 foobar"}, hosts)
updateHosts(flags, &hosts)
require.Len(t, hosts, 3)
assert.Equal(t, "1.2.3.4 example.com", hosts[0])
assert.Equal(t, "2001:db8:abc8::1 ipv6.net", hosts[1])
assert.Equal(t, "4.3.2.1 example.org", hosts[2])
}
func TestUpdatePortsRmWithProtocol(t *testing.T) {
@ -518,71 +506,3 @@ func TestUpdateStopSignal(t *testing.T) {
updateService(nil, nil, flags, spec)
assert.Equal(t, "SIGWINCH", cspec.StopSignal)
}
func TestUpdateIsolationValid(t *testing.T) {
flags := newUpdateCommand(nil).Flags()
err := flags.Set("isolation", "process")
require.NoError(t, err)
spec := swarm.ServiceSpec{
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{},
},
}
err = updateService(context.Background(), nil, flags, &spec)
require.NoError(t, err)
assert.Equal(t, container.IsolationProcess, spec.TaskTemplate.ContainerSpec.Isolation)
}
func TestUpdateIsolationInvalid(t *testing.T) {
// validation depends on daemon os / version so validation should be done on the daemon side
flags := newUpdateCommand(nil).Flags()
err := flags.Set("isolation", "test")
require.NoError(t, err)
spec := swarm.ServiceSpec{
TaskTemplate: swarm.TaskSpec{
ContainerSpec: &swarm.ContainerSpec{},
},
}
err = updateService(context.Background(), nil, flags, &spec)
require.NoError(t, err)
assert.Equal(t, container.Isolation("test"), spec.TaskTemplate.ContainerSpec.Isolation)
}
func TestAddGenericResources(t *testing.T) {
task := &swarm.TaskSpec{}
flags := newUpdateCommand(nil).Flags()
assert.Nil(t, addGenericResources(flags, task))
flags.Set(flagGenericResourcesAdd, "foo=1")
assert.NoError(t, addGenericResources(flags, task))
assert.Len(t, task.Resources.Reservations.GenericResources, 1)
// Checks that foo isn't added a 2nd time
flags = newUpdateCommand(nil).Flags()
flags.Set(flagGenericResourcesAdd, "bar=1")
assert.NoError(t, addGenericResources(flags, task))
assert.Len(t, task.Resources.Reservations.GenericResources, 2)
}
func TestRemoveGenericResources(t *testing.T) {
task := &swarm.TaskSpec{}
flags := newUpdateCommand(nil).Flags()
assert.Nil(t, removeGenericResources(flags, task))
flags.Set(flagGenericResourcesRemove, "foo")
assert.Error(t, removeGenericResources(flags, task))
flags = newUpdateCommand(nil).Flags()
flags.Set(flagGenericResourcesAdd, "foo=1")
addGenericResources(flags, task)
flags = newUpdateCommand(nil).Flags()
flags.Set(flagGenericResourcesAdd, "bar=1")
addGenericResources(flags, task)
flags = newUpdateCommand(nil).Flags()
flags.Set(flagGenericResourcesRemove, "foo")
assert.NoError(t, removeGenericResources(flags, task))
assert.Len(t, task.Resources.Reservations.GenericResources, 1)
}

View File

@ -7,13 +7,14 @@ import (
)
// NewStackCommand returns a cobra command for `stack` subcommands
func NewStackCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewStackCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "stack",
Short: "Manage Docker stacks",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.25"},
Use: "stack",
Short: "Manage Docker stacks",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.25"},
}
cmd.AddCommand(
newDeployCommand(dockerCli),
@ -30,6 +31,6 @@ func NewTopLevelDeployCommand(dockerCli command.Cli) *cobra.Command {
cmd := newDeployCommand(dockerCli)
// Remove the aliases at the top level
cmd.Aliases = []string{}
cmd.Annotations = map[string]string{"experimental": "", "version": "1.25"}
cmd.Tags = map[string]string{"experimental": "", "version": "1.25"}
return cmd
}

View File

@ -222,9 +222,8 @@ func createSecrets(
if err := client.SecretUpdate(ctx, secret.ID, secret.Meta.Version, secretSpec); err != nil {
return errors.Wrapf(err, "failed to update secret %s", secretSpec.Name)
}
case apiclient.IsErrNotFound(err):
case apiclient.IsErrSecretNotFound(err):
// secret does not exist, then we create a new one.
fmt.Fprintf(dockerCli.Out(), "Creating secret %s\n", secretSpec.Name)
if _, err := client.SecretCreate(ctx, secretSpec); err != nil {
return errors.Wrapf(err, "failed to create secret %s", secretSpec.Name)
}
@ -250,9 +249,8 @@ func createConfigs(
if err := client.ConfigUpdate(ctx, config.ID, config.Meta.Version, configSpec); err != nil {
errors.Wrapf(err, "failed to update config %s", configSpec.Name)
}
case apiclient.IsErrNotFound(err):
case apiclient.IsErrConfigNotFound(err):
// config does not exist, then we create a new one.
fmt.Fprintf(dockerCli.Out(), "Creating config %s\n", configSpec.Name)
if _, err := client.ConfigCreate(ctx, configSpec); err != nil {
errors.Wrapf(err, "failed to create config %s", configSpec.Name)
}

View File

@ -36,7 +36,7 @@ func newCACommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runCA(dockerCli, cmd.Flags(), opts)
},
Annotations: map[string]string{"version": "1.30"},
Tags: map[string]string{"version": "1.30"},
}
flags := cmd.Flags()

View File

@ -8,13 +8,14 @@ import (
)
// NewSwarmCommand returns a cobra command for `swarm` subcommands
// nolint: interfacer
func NewSwarmCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "swarm",
Short: "Manage Swarm",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Annotations: map[string]string{"version": "1.24"},
Use: "swarm",
Short: "Manage Swarm",
Args: cli.NoArgs,
RunE: command.ShowHelp(dockerCli.Err()),
Tags: map[string]string{"version": "1.24"},
}
cmd.AddCommand(
newInitCommand(dockerCli),

View File

@ -8,7 +8,6 @@ Flags:
--cert-expiry duration Validity period for node certificates (ns|us|ms|s|m|h) (default 2160h0m0s)
--dispatcher-heartbeat duration Dispatcher heartbeat period (ns|us|ms|s|m|h) (default 5s)
--external-ca external-ca Specifications of one or more certificate signing endpoints
-h, --help help for update
--max-snapshots uint Number of additional Raft snapshots to retain
--snapshot-interval uint Number of log entries between Raft snapshots (default 10000)
--task-history-limit int Task history retention limit (default 5)

View File

@ -7,7 +7,8 @@ import (
)
// NewSystemCommand returns a cobra command for `system` subcommands
func NewSystemCommand(dockerCli command.Cli) *cobra.Command {
// nolint: interfacer
func NewSystemCommand(dockerCli *command.DockerCli) *cobra.Command {
cmd := &cobra.Command{
Use: "system",
Short: "Manage Docker",

View File

@ -16,7 +16,7 @@ type diskUsageOptions struct {
}
// newDiskUsageCommand creates a new cobra.Command for `docker df`
func newDiskUsageCommand(dockerCli command.Cli) *cobra.Command {
func newDiskUsageCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts diskUsageOptions
cmd := &cobra.Command{
@ -26,7 +26,7 @@ func newDiskUsageCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runDiskUsage(dockerCli, opts)
},
Annotations: map[string]string{"version": "1.25"},
Tags: map[string]string{"version": "1.25"},
}
flags := cmd.Flags()
@ -37,7 +37,7 @@ func newDiskUsageCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runDiskUsage(dockerCli command.Cli, opts diskUsageOptions) error {
func runDiskUsage(dockerCli *command.DockerCli, opts diskUsageOptions) error {
if opts.verbose && len(opts.format) != 0 {
return errors.New("the verbose and the format options conflict")
}

View File

@ -27,7 +27,7 @@ type eventsOptions struct {
}
// NewEventsCommand creates a new cobra.Command for `docker events`
func NewEventsCommand(dockerCli command.Cli) *cobra.Command {
func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command {
options := eventsOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
@ -48,7 +48,7 @@ func NewEventsCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runEvents(dockerCli command.Cli, options *eventsOptions) error {
func runEvents(dockerCli *command.DockerCli, options *eventsOptions) error {
tmpl, err := makeTemplate(options.format)
if err != nil {
return cli.StatusError{

View File

@ -22,7 +22,7 @@ type infoOptions struct {
}
// NewInfoCommand creates a new cobra.Command for `docker info`
func NewInfoCommand(dockerCli command.Cli) *cobra.Command {
func NewInfoCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts infoOptions
cmd := &cobra.Command{
@ -41,7 +41,7 @@ func NewInfoCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runInfo(dockerCli command.Cli, opts *infoOptions) error {
func runInfo(dockerCli *command.DockerCli, opts *infoOptions) error {
ctx := context.Background()
info, err := dockerCli.Client().Info(ctx)
if err != nil {
@ -357,7 +357,7 @@ func getBackingFs(info types.Info) string {
return ""
}
func formatInfo(dockerCli command.Cli, info types.Info, format string) error {
func formatInfo(dockerCli *command.DockerCli, info types.Info, format string) error {
tmpl, err := templates.Parse(format)
if err != nil {
return cli.StatusError{StatusCode: 64,

View File

@ -37,7 +37,7 @@ func newPruneCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runPrune(dockerCli, options)
},
Annotations: map[string]string{"version": "1.25"},
Tags: map[string]string{"version": "1.25"},
}
flags := cmd.Flags()

View File

@ -1,52 +1,34 @@
package system
import (
"fmt"
"runtime"
"sort"
"text/template"
"time"
"golang.org/x/net/context"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/templates"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)
var versionTemplate = `{{with .Client -}}
Client:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
Version: {{.Version}}
API version: {{.APIVersion}}{{if ne .APIVersion .DefaultAPIVersion}} (downgraded from {{.DefaultAPIVersion}}){{end}}
Go version: {{.GoVersion}}
Git commit: {{.GitCommit}}
Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}
{{- end}}
var versionTemplate = `Client:
Version: {{.Client.Version}}
API version: {{.Client.APIVersion}}{{if ne .Client.APIVersion .Client.DefaultAPIVersion}} (downgraded from {{.Client.DefaultAPIVersion}}){{end}}
Go version: {{.Client.GoVersion}}
Git commit: {{.Client.GitCommit}}
Built: {{.Client.BuildTime}}
OS/Arch: {{.Client.Os}}/{{.Client.Arch}}{{if .ServerOK}}
{{- if .ServerOK}}{{with .Server}}
Server:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
{{- range $component := .Components}}
{{$component.Name}}:
{{- if eq $component.Name "Engine" }}
Version: {{.Version}}
API version: {{index .Details "ApiVersion"}} (minimum version {{index .Details "MinAPIVersion"}})
Go version: {{index .Details "GoVersion"}}
Git commit: {{index .Details "GitCommit"}}
Built: {{index .Details "BuildTime"}}
OS/Arch: {{index .Details "Os"}}/{{index .Details "Arch"}}
Experimental: {{index .Details "Experimental"}}
{{- else }}
Version: {{$component.Version}}
{{- $detailsOrder := getDetailsOrder $component}}
{{- range $key := $detailsOrder}}
{{$key}}: {{index $component.Details $key}}
{{- end}}
{{- end}}
{{- end}}
{{- end}}{{end}}`
Server:
Version: {{.Server.Version}}
API version: {{.Server.APIVersion}} (minimum version {{.Server.MinAPIVersion}})
Go version: {{.Server.GoVersion}}
Git commit: {{.Server.GitCommit}}
Built: {{.Server.BuildTime}}
OS/Arch: {{.Server.Os}}/{{.Server.Arch}}
Experimental: {{.Server.Experimental}}{{end}}`
type versionOptions struct {
format string
@ -59,8 +41,6 @@ type versionInfo struct {
}
type clientVersion struct {
Platform struct{ Name string } `json:",omitempty"`
Version string
APIVersion string `json:"ApiVersion"`
DefaultAPIVersion string `json:"DefaultAPIVersion,omitempty"`
@ -97,27 +77,15 @@ func NewVersionCommand(dockerCli *command.DockerCli) *cobra.Command {
return cmd
}
func reformatDate(buildTime string) string {
t, errTime := time.Parse(time.RFC3339Nano, buildTime)
if errTime == nil {
return t.Format(time.ANSIC)
}
return buildTime
}
func runVersion(dockerCli *command.DockerCli, opts *versionOptions) error {
ctx := context.Background()
templateFormat := versionTemplate
tmpl := templates.New("version")
if opts.format != "" {
templateFormat = opts.format
} else {
tmpl = tmpl.Funcs(template.FuncMap{"getDetailsOrder": getDetailsOrder})
}
var err error
tmpl, err = tmpl.Parse(templateFormat)
tmpl, err := templates.Parse(templateFormat)
if err != nil {
return cli.StatusError{StatusCode: 64,
Status: "Template parsing error: " + err.Error()}
@ -135,41 +103,22 @@ func runVersion(dockerCli *command.DockerCli, opts *versionOptions) error {
Arch: runtime.GOARCH,
},
}
vd.Client.Platform.Name = cli.PlatformName
serverVersion, err := dockerCli.Client().ServerVersion(ctx)
if err == nil {
vd.Server = &serverVersion
}
// first we need to make BuildTime more human friendly
vd.Client.BuildTime = reformatDate(vd.Client.BuildTime)
t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime)
if errTime == nil {
vd.Client.BuildTime = t.Format(time.ANSIC)
}
sv, err := dockerCli.Client().ServerVersion(ctx)
if err == nil {
vd.Server = &sv
foundEngine := false
for _, component := range sv.Components {
if component.Name == "Engine" {
foundEngine = true
buildTime, ok := component.Details["BuildTime"]
if ok {
component.Details["BuildTime"] = reformatDate(buildTime)
}
break
}
}
if !foundEngine {
vd.Server.Components = append(vd.Server.Components, types.ComponentVersion{
Name: "Engine",
Version: sv.Version,
Details: map[string]string{
"ApiVersion": sv.APIVersion,
"MinAPIVersion": sv.MinAPIVersion,
"GitCommit": sv.GitCommit,
"GoVersion": sv.GoVersion,
"Os": sv.Os,
"Arch": sv.Arch,
"BuildTime": reformatDate(vd.Server.BuildTime),
"Experimental": fmt.Sprintf("%t", sv.Experimental),
},
})
if vd.ServerOK() {
t, errTime = time.Parse(time.RFC3339Nano, vd.Server.BuildTime)
if errTime == nil {
vd.Server.BuildTime = t.Format(time.ANSIC)
}
}
@ -179,12 +128,3 @@ func runVersion(dockerCli *command.DockerCli, opts *versionOptions) error {
dockerCli.Out().Write([]byte{'\n'})
return err
}
func getDetailsOrder(v types.ComponentVersion) []string {
out := make([]string, 0, len(v.Details))
for k := range v.Details {
out = append(out, k)
}
sort.Strings(out)
return out
}

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