vendor: github.com/docker/docker v28.0.0-rc.2

full diff: https://github.com/docker/docker/compare/v28.0.0-rc.1...v28.0.0-rc.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2025-02-14 19:39:59 +01:00
parent ef4e9fea83
commit 461bd9e5d1
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
95 changed files with 776 additions and 488 deletions

2
go.mod
View File

@ -19,7 +19,7 @@ require (
github.com/distribution/reference v0.6.0
github.com/docker/cli v28.0.0-rc.1+incompatible
github.com/docker/cli-docs-tool v0.9.0
github.com/docker/docker v28.0.0-rc.1+incompatible
github.com/docker/docker v28.0.0-rc.2+incompatible
github.com/docker/go-units v0.5.0
github.com/gofrs/flock v0.12.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510

4
go.sum
View File

@ -129,8 +129,8 @@ github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3T
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.0.0-rc.1+incompatible h1:xUbdsVxJIFvyZ+958MzyyIT7VuHO4Ecao9hKhl7kGUc=
github.com/docker/docker v28.0.0-rc.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v28.0.0-rc.2+incompatible h1:p+Ri+C0mmbPkhYVD9Sxnp/TnNnZoQWEj/EwOC465Uq4=
github.com/docker/docker v28.0.0-rc.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=

View File

@ -7,7 +7,6 @@ import (
"github.com/docker/buildx/util/progress"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types/image"
dockerclient "github.com/docker/docker/client"
)
@ -53,7 +52,7 @@ func (c *Client) LoadImage(ctx context.Context, name string, status progress.Wri
w.mu.Unlock()
}
resp, err := dapi.ImageLoad(ctx, pr, image.LoadOptions{})
resp, err := dapi.ImageLoad(ctx, pr)
defer close(done)
if err != nil {
handleErr(err)

View File

@ -2,7 +2,9 @@
# This file lists all contributors to the repository.
# See hack/generate-authors.sh to make modifications.
7sunarni <710720732@qq.com>
Aanand Prasad <aanand.prasad@gmail.com>
Aarni Koskela <akx@iki.fi>
Aaron Davidson <aaron@databricks.com>
Aaron Feng <aaron.feng@gmail.com>
Aaron Hnatiw <aaron@griddio.com>
@ -11,6 +13,7 @@ Aaron L. Xu <liker.xu@foxmail.com>
Aaron Lehmann <alehmann@netflix.com>
Aaron Welch <welch@packet.net>
Aaron Yoshitake <airandfingers@gmail.com>
Abdur Rehman <abdur_rehman@mentor.com>
Abel Muiño <amuino@gmail.com>
Abhijeet Kasurde <akasurde@redhat.com>
Abhinandan Prativadi <aprativadi@gmail.com>
@ -24,9 +27,11 @@ Adam Avilla <aavilla@yp.com>
Adam Dobrawy <naczelnik@jawnosc.tk>
Adam Eijdenberg <adam.eijdenberg@gmail.com>
Adam Kunk <adam.kunk@tiaa-cref.org>
Adam Lamers <adam.lamers@wmsdev.pl>
Adam Miller <admiller@redhat.com>
Adam Mills <adam@armills.info>
Adam Pointer <adam.pointer@skybettingandgaming.com>
Adam Simon <adamsimon85100@gmail.com>
Adam Singer <financeCoding@gmail.com>
Adam Thornton <adam.thornton@maryville.com>
Adam Walz <adam@adamwalz.net>
@ -119,6 +124,7 @@ amangoel <amangoel@gmail.com>
Amen Belayneh <amenbelayneh@gmail.com>
Ameya Gawde <agawde@mirantis.com>
Amir Goldstein <amir73il@aquasec.com>
AmirBuddy <badinlu.amirhossein@gmail.com>
Amit Bakshi <ambakshi@gmail.com>
Amit Krishnan <amit.krishnan@oracle.com>
Amit Shukla <amit.shukla@docker.com>
@ -168,6 +174,7 @@ Andrey Kolomentsev <andrey.kolomentsev@docker.com>
Andrey Petrov <andrey.petrov@shazow.net>
Andrey Stolbovsky <andrey.stolbovsky@gmail.com>
André Martins <aanm90@gmail.com>
Andrés Maldonado <maldonado@codelutin.com>
Andy Chambers <anchambers@paypal.com>
andy diller <dillera@gmail.com>
Andy Goldstein <agoldste@redhat.com>
@ -219,6 +226,7 @@ Artur Meyster <arthurfbi@yahoo.com>
Arun Gupta <arun.gupta@gmail.com>
Asad Saeeduddin <masaeedu@gmail.com>
Asbjørn Enge <asbjorn@hanafjedle.net>
Ashly Mathew <ashly.mathew@sap.com>
Austin Vazquez <macedonv@amazon.com>
averagehuman <averagehuman@users.noreply.github.com>
Avi Das <andas222@gmail.com>
@ -345,6 +353,7 @@ Chance Zibolski <chance.zibolski@gmail.com>
Chander Govindarajan <chandergovind@gmail.com>
Chanhun Jeong <keyolk@gmail.com>
Chao Wang <wangchao.fnst@cn.fujitsu.com>
Charity Kathure <ckathure@microsoft.com>
Charles Chan <charleswhchan@users.noreply.github.com>
Charles Hooper <charles.hooper@dotcloud.com>
Charles Law <claw@conduce.com>
@ -480,6 +489,7 @@ Daniel Farrell <dfarrell@redhat.com>
Daniel Garcia <daniel@danielgarcia.info>
Daniel Gasienica <daniel@gasienica.ch>
Daniel Grunwell <mwgrunny@gmail.com>
Daniel Guns <danbguns@gmail.com>
Daniel Helfand <helfand.4@gmail.com>
Daniel Hiltgen <daniel.hiltgen@docker.com>
Daniel J Walsh <dwalsh@redhat.com>
@ -763,6 +773,7 @@ Frank Macreery <frank@macreery.com>
Frank Rosquin <frank.rosquin+github@gmail.com>
Frank Villaro-Dixon <frank.villarodixon@merkle.com>
Frank Yang <yyb196@gmail.com>
François Scala <github@arcenik.net>
Fred Lifton <fred.lifton@docker.com>
Frederick F. Kautz IV <fkautz@redhat.com>
Frederico F. de Oliveira <FreddieOliveira@users.noreply.github.com>
@ -798,6 +809,7 @@ GennadySpb <lipenkov@gmail.com>
Geoff Levand <geoff@infradead.org>
Geoffrey Bachelet <grosfrais@gmail.com>
Geon Kim <geon0250@gmail.com>
George Adams <georgeadams1995@gmail.com>
George Kontridze <george@bugsnag.com>
George Ma <mayangang@outlook.com>
George MacRorie <gmacr31@gmail.com>
@ -826,6 +838,7 @@ Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
Gosuke Miyashita <gosukenator@gmail.com>
Gou Rao <gou@portworx.com>
Govinda Fichtner <govinda.fichtner@googlemail.com>
Grace Choi <grace.54109@gmail.com>
Grant Millar <rid@cylo.io>
Grant Reaber <grant.reaber@gmail.com>
Graydon Hoare <graydon@pobox.com>
@ -966,6 +979,7 @@ James Nugent <james@jen20.com>
James Sanders <james3sanders@gmail.com>
James Turnbull <james@lovedthanlost.net>
James Watkins-Harvey <jwatkins@progi-media.com>
Jameson Hyde <jameson.hyde@docker.com>
Jamie Hannaford <jamie@limetree.org>
Jamshid Afshar <jafshar@yahoo.com>
Jan Breig <git@pygos.space>
@ -1064,13 +1078,16 @@ Jim Perrin <jperrin@centos.org>
Jimmy Cuadra <jimmy@jimmycuadra.com>
Jimmy Puckett <jimmy.puckett@spinen.com>
Jimmy Song <rootsongjc@gmail.com>
jinjiadu <jinjiadu@aliyun.com>
Jinsoo Park <cellpjs@gmail.com>
Jintao Zhang <zhangjintao9020@gmail.com>
Jiri Appl <jiria@microsoft.com>
Jiri Popelka <jpopelka@redhat.com>
Jiuyue Ma <majiuyue@huawei.com>
Jiří Župka <jzupka@redhat.com>
jjimbo137 <115816493+jjimbo137@users.noreply.github.com>
Joakim Roubert <joakim.roubert@axis.com>
Joan Grau <grautxo.dev@proton.me>
Joao Fernandes <joao.fernandes@docker.com>
Joao Trindade <trindade.joao@gmail.com>
Joe Beda <joe.github@bedafamily.com>
@ -1155,6 +1172,7 @@ Josiah Kiehl <jkiehl@riotgames.com>
José Tomás Albornoz <jojo@eljojo.net>
Joyce Jang <mail@joycejang.com>
JP <jpellerin@leapfrogonline.com>
JSchltggr <jschltggr@gmail.com>
Julian Taylor <jtaylor.debian@googlemail.com>
Julien Barbier <write0@gmail.com>
Julien Bisconti <veggiemonk@users.noreply.github.com>
@ -1289,6 +1307,7 @@ Laura Brehm <laurabrehm@hey.com>
Laura Frank <ljfrank@gmail.com>
Laurent Bernaille <laurent.bernaille@datadoghq.com>
Laurent Erignoux <lerignoux@gmail.com>
Laurent Goderre <laurent.goderre@docker.com>
Laurie Voss <github@seldo.com>
Leandro Motta Barros <lmb@stackedboxes.org>
Leandro Siqueira <leandro.siqueira@gmail.com>
@ -1369,6 +1388,7 @@ Madhan Raj Mookkandy <MadhanRaj.Mookkandy@microsoft.com>
Madhav Puri <madhav.puri@gmail.com>
Madhu Venugopal <mavenugo@gmail.com>
Mageee <fangpuyi@foxmail.com>
maggie44 <64841595+maggie44@users.noreply.github.com>
Mahesh Tiyyagura <tmahesh@gmail.com>
malnick <malnick@gmail..com>
Malte Janduda <mail@janduda.net>
@ -1579,6 +1599,7 @@ Muayyad Alsadi <alsadi@gmail.com>
Muhammad Zohaib Aslam <zohaibse011@gmail.com>
Mustafa Akın <mustafa91@gmail.com>
Muthukumar R <muthur@gmail.com>
Myeongjoon Kim <kimmj8409@gmail.com>
Máximo Cuadros <mcuadros@gmail.com>
Médi-Rémi Hashim <medimatrix@users.noreply.github.com>
Nace Oroz <orkica@gmail.com>
@ -1593,6 +1614,7 @@ Natasha Jarus <linuxmercedes@gmail.com>
Nate Brennand <nate.brennand@clever.com>
Nate Eagleson <nate@nateeag.com>
Nate Jones <nate@endot.org>
Nathan Baulch <nathan.baulch@gmail.com>
Nathan Carlson <carl4403@umn.edu>
Nathan Herald <me@nathanherald.com>
Nathan Hsieh <hsieh.nathan@gmail.com>
@ -1655,6 +1677,7 @@ Nuutti Kotivuori <naked@iki.fi>
nzwsch <hi@nzwsch.com>
O.S. Tezer <ostezer@gmail.com>
objectified <objectified@gmail.com>
Octol1ttle <l1ttleofficial@outlook.com>
Odin Ugedal <odin@ugedal.com>
Oguz Bilgic <fisyonet@gmail.com>
Oh Jinkyun <tintypemolly@gmail.com>
@ -1763,6 +1786,7 @@ Pierre Carrier <pierre@meteor.com>
Pierre Dal-Pra <dalpra.pierre@gmail.com>
Pierre Wacrenier <pierre.wacrenier@gmail.com>
Pierre-Alain RIVIERE <pariviere@ippon.fr>
pinglanlu <pinglanlu@outlook.com>
Piotr Bogdan <ppbogdan@gmail.com>
Piotr Karbowski <piotr.karbowski@protonmail.ch>
Porjo <porjo38@yahoo.com.au>
@ -1790,6 +1814,7 @@ Quentin Tayssier <qtayssier@gmail.com>
r0n22 <cameron.regan@gmail.com>
Rachit Sharma <rachitsharma613@gmail.com>
Radostin Stoyanov <rstoyanov1@gmail.com>
Rafael Fernández López <ereslibre@ereslibre.es>
Rafal Jeczalik <rjeczalik@gmail.com>
Rafe Colton <rafael.colton@gmail.com>
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
@ -1856,7 +1881,7 @@ Robin Speekenbrink <robin@kingsquare.nl>
Robin Thoni <robin@rthoni.com>
robpc <rpcann@gmail.com>
Rodolfo Carvalho <rhcarvalho@gmail.com>
Rodrigo Campos <rodrigo@kinvolk.io>
Rodrigo Campos <rodrigoca@microsoft.com>
Rodrigo Vaz <rodrigo.vaz@gmail.com>
Roel Van Nyen <roel.vannyen@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
@ -1995,6 +2020,7 @@ Sevki Hasirci <s@sevki.org>
Shane Canon <scanon@lbl.gov>
Shane da Silva <shane@dasilva.io>
Shaun Kaasten <shaunk@gmail.com>
Shaun Thompson <shaun.thompson@docker.com>
shaunol <shaunol@gmail.com>
Shawn Landden <shawn@churchofgit.com>
Shawn Siefkas <shawn.siefkas@meredith.com>
@ -2013,6 +2039,7 @@ Shijun Qin <qinshijun16@mails.ucas.ac.cn>
Shishir Mahajan <shishir.mahajan@redhat.com>
Shoubhik Bose <sbose78@gmail.com>
Shourya Sarcar <shourya.sarcar@gmail.com>
Shreenidhi Shedi <shreenidhi.shedi@broadcom.com>
Shu-Wai Chow <shu-wai.chow@seattlechildrens.org>
shuai-z <zs.broccoli@gmail.com>
Shukui Yang <yangshukui@huawei.com>
@ -2100,6 +2127,7 @@ Sébastien Stormacq <sebsto@users.noreply.github.com>
Sören Tempel <soeren+git@soeren-tempel.net>
Tabakhase <mail@tabakhase.com>
Tadej Janež <tadej.j@nez.si>
Tadeusz Dudkiewicz <tadeusz.dudkiewicz@rtbhouse.com>
Takuto Sato <tockn.jp@gmail.com>
tang0th <tang0th@gmx.com>
Tangi Colin <tangicolin@gmail.com>
@ -2107,6 +2135,7 @@ Tatsuki Sugiura <sugi@nemui.org>
Tatsushi Inagaki <e29253@jp.ibm.com>
Taylan Isikdemir <taylani@google.com>
Taylor Jones <monitorjbl@gmail.com>
tcpdumppy <847462026@qq.com>
Ted M. Young <tedyoung@gmail.com>
Tehmasp Chaudhri <tehmasp@gmail.com>
Tejaswini Duggaraju <naduggar@microsoft.com>
@ -2391,6 +2420,7 @@ You-Sheng Yang (楊有勝) <vicamo@gmail.com>
youcai <omegacoleman@gmail.com>
Youcef YEKHLEF <yyekhlef@gmail.com>
Youfu Zhang <zhangyoufu@gmail.com>
YR Chen <stevapple@icloud.com>
Yu Changchun <yuchangchun1@huawei.com>
Yu Chengxia <yuchengxia@huawei.com>
Yu Peng <yu.peng36@zte.com.cn>

View File

@ -2754,12 +2754,24 @@ definitions:
type: "string"
error:
type: "string"
x-nullable: true
description: |-
errors encountered during the operation.
> **Deprecated**: This field is deprecated since API v1.4, and will be omitted in a future API version. Use the information in errorDetail instead.
errorDetail:
$ref: "#/definitions/ErrorDetail"
status:
type: "string"
progress:
type: "string"
x-nullable: true
description: |-
Progress is a pre-formatted presentation of progressDetail.
> **Deprecated**: This field is deprecated since API v1.8, and will be omitted in a future API version. Use the information in progressDetail instead.
progressDetail:
$ref: "#/definitions/ProgressDetail"
aux:
@ -2859,12 +2871,24 @@ definitions:
type: "string"
error:
type: "string"
x-nullable: true
description: |-
errors encountered during the operation.
> **Deprecated**: This field is deprecated since API v1.4, and will be omitted in a future API version. Use the information in errorDetail instead.
errorDetail:
$ref: "#/definitions/ErrorDetail"
status:
type: "string"
progress:
type: "string"
x-nullable: true
description: |-
Progress is a pre-formatted presentation of progressDetail.
> **Deprecated**: This field is deprecated since API v1.8, and will be omitted in a future API version. Use the information in progressDetail instead.
progressDetail:
$ref: "#/definitions/ProgressDetail"
@ -2873,10 +2897,24 @@ definitions:
properties:
error:
type: "string"
x-nullable: true
description: |-
errors encountered during the operation.
> **Deprecated**: This field is deprecated since API v1.4, and will be omitted in a future API version. Use the information in errorDetail instead.
errorDetail:
$ref: "#/definitions/ErrorDetail"
status:
type: "string"
progress:
type: "string"
x-nullable: true
description: |-
Progress is a pre-formatted presentation of progressDetail.
> **Deprecated**: This field is deprecated since API v1.8, and will be omitted in a future API version. Use the information in progressDetail instead.
progressDetail:
$ref: "#/definitions/ProgressDetail"
@ -2908,9 +2946,10 @@ definitions:
example:
message: "Something went wrong."
IdResponse:
IDResponse:
description: "Response to an API call that returns just an Id"
type: "object"
x-go-name: "IDResponse"
required: ["Id"]
properties:
Id:
@ -5070,6 +5109,17 @@ definitions:
ImageID:
description: "The ID of the image that this container was created from"
type: "string"
ImageManifestDescriptor:
$ref: "#/definitions/OCIDescriptor"
x-nullable: true
description: |
OCI descriptor of the platform-specific manifest of the image
the container was created from.
Note: Only available if the daemon provides a multi-platform
image store.
This field is not populated in the `GET /system/df` endpoint.
Command:
description: "Command to run when starting the container"
type: "string"
@ -5326,6 +5376,21 @@ definitions:
type: "string"
example: []
ContainerUpdateResponse:
type: "object"
title: "ContainerUpdateResponse"
x-go-name: "UpdateResponse"
description: |-
Response for a successful container-update.
properties:
Warnings:
type: "array"
description: |-
Warnings encountered when updating the container.
items:
type: "string"
example: ["Published ports are discarded when using host network mode"]
ContainerStatsResponse:
description: |
Statistics sample for a container.
@ -5871,6 +5936,58 @@ definitions:
x-nullable: true
example: 7593984
ContainerTopResponse:
type: "object"
x-go-name: "TopResponse"
title: "ContainerTopResponse"
description: |-
Container "top" response.
properties:
Titles:
description: "The ps column titles"
type: "array"
items:
type: "string"
example:
Titles:
- "UID"
- "PID"
- "PPID"
- "C"
- "STIME"
- "TTY"
- "TIME"
- "CMD"
Processes:
description: |-
Each process running in the container, where each process
is an array of values corresponding to the titles.
type: "array"
items:
type: "array"
items:
type: "string"
example:
Processes:
-
- "root"
- "13642"
- "882"
- "0"
- "17:03"
- "pts/0"
- "00:00:00"
- "/bin/bash"
-
- "root"
- "13735"
- "13642"
- "0"
- "17:06"
- "pts/0"
- "00:00:00"
- "sleep 10"
ContainerWaitResponse:
description: "OK response to ContainerWait operation"
type: "object"
@ -8072,54 +8189,7 @@ paths:
200:
description: "no error"
schema:
type: "object"
title: "ContainerTopResponse"
description: "OK response to ContainerTop operation"
properties:
Titles:
description: "The ps column titles"
type: "array"
items:
type: "string"
Processes:
description: |
Each process running in the container, where each is process
is an array of values corresponding to the titles.
type: "array"
items:
type: "array"
items:
type: "string"
examples:
application/json:
Titles:
- "UID"
- "PID"
- "PPID"
- "C"
- "STIME"
- "TTY"
- "TIME"
- "CMD"
Processes:
-
- "root"
- "13642"
- "882"
- "0"
- "17:03"
- "pts/0"
- "00:00:00"
- "/bin/bash"
-
- "root"
- "13735"
- "13642"
- "0"
- "17:06"
- "pts/0"
- "00:00:00"
- "sleep 10"
$ref: "#/definitions/ContainerTopResponse"
404:
description: "no such container"
schema:
@ -8560,14 +8630,7 @@ paths:
200:
description: "The container has been updated."
schema:
type: "object"
title: "ContainerUpdateResponse"
description: "OK response to ContainerUpdate operation"
properties:
Warnings:
type: "array"
items:
type: "string"
$ref: "#/definitions/ContainerUpdateResponse"
404:
description: "no such container"
schema:
@ -10220,7 +10283,7 @@ paths:
201:
description: "no error"
schema:
$ref: "#/definitions/IdResponse"
$ref: "#/definitions/IDResponse"
404:
description: "no such container"
schema:
@ -10614,7 +10677,7 @@ paths:
201:
description: "no error"
schema:
$ref: "#/definitions/IdResponse"
$ref: "#/definitions/IDResponse"
404:
description: "no such container"
schema:
@ -13094,7 +13157,7 @@ paths:
201:
description: "no error"
schema:
$ref: "#/definitions/IdResponse"
$ref: "#/definitions/IDResponse"
409:
description: "name conflicts with an existing object"
schema:
@ -13301,7 +13364,7 @@ paths:
201:
description: "no error"
schema:
$ref: "#/definitions/IdResponse"
$ref: "#/definitions/IDResponse"
409:
description: "name conflicts with an existing object"
schema:

View File

@ -1,10 +1,10 @@
package types
package common
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// IDResponse Response to an API call that returns just an Id
// swagger:model IdResponse
// swagger:model IDResponse
type IDResponse struct {
// The id of the newly created object.

View File

@ -0,0 +1,7 @@
package container
import "github.com/docker/docker/api/types/common"
// CommitResponse response for the commit API call, containing the ID of the
// image that was produced.
type CommitResponse = common.IDResponse

View File

@ -10,6 +10,16 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ContainerUpdateOKBody OK response to ContainerUpdate operation
//
// Deprecated: use [UpdateResponse]. This alias will be removed in the next release.
type ContainerUpdateOKBody = UpdateResponse
// ContainerTopOKBody OK response to ContainerTop operation
//
// Deprecated: use [TopResponse]. This alias will be removed in the next release.
type ContainerTopOKBody = TopResponse
// PruneReport contains the response for Engine API:
// POST "/containers/prune"
type PruneReport struct {
@ -115,6 +125,7 @@ type Summary struct {
Names []string
Image string
ImageID string
ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"`
Command string
Created int64
Ports []Port
@ -173,5 +184,5 @@ type InspectResponse struct {
Config *Config
NetworkSettings *NetworkSettings
// ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container.
ImageManifestDescriptor *ocispec.Descriptor `json:",omitempty"`
ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"`
}

View File

@ -1,22 +0,0 @@
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
// ContainerTopOKBody OK response to ContainerTop operation
// swagger:model ContainerTopOKBody
type ContainerTopOKBody struct {
// Each process running in the container, where each is process
// is an array of values corresponding to the titles.
//
// Required: true
Processes [][]string `json:"Processes"`
// The ps column titles
// Required: true
Titles []string `json:"Titles"`
}

View File

@ -1,16 +0,0 @@
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
// ContainerUpdateOKBody OK response to ContainerUpdate operation
// swagger:model ContainerUpdateOKBody
type ContainerUpdateOKBody struct {
// warnings
// Required: true
Warnings []string `json:"Warnings"`
}

View File

@ -1,5 +1,13 @@
package container
import "github.com/docker/docker/api/types/common"
// ExecCreateResponse is the response for a successful exec-create request.
// It holds the ID of the exec that was created.
//
// TODO(thaJeztah): make this a distinct type.
type ExecCreateResponse = common.IDResponse
// ExecOptions is a small subset of the Config struct that holds the configuration
// for the exec feature of docker.
type ExecOptions struct {

View File

@ -0,0 +1,18 @@
package container
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// TopResponse ContainerTopResponse
//
// Container "top" response.
// swagger:model TopResponse
type TopResponse struct {
// Each process running in the container, where each process
// is an array of values corresponding to the titles.
Processes [][]string `json:"Processes"`
// The ps column titles
Titles []string `json:"Titles"`
}

View File

@ -0,0 +1,14 @@
package container
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// UpdateResponse ContainerUpdateResponse
//
// Response for a successful container-update.
// swagger:model UpdateResponse
type UpdateResponse struct {
// Warnings encountered when updating the container.
Warnings []string `json:"Warnings"`
}

View File

@ -3,11 +3,17 @@ package types
import (
"context"
"github.com/docker/docker/api/types/common"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/storage"
)
// IDResponse Response to an API call that returns just an Id.
//
// Deprecated: use either [container.CommitResponse] or [container.ExecCreateResponse]. It will be removed in the next release.
type IDResponse = common.IDResponse
// ContainerJSONBase contains response of Engine API GET "/containers/{name:.*}/json"
// for API version 1.18 and older.
//

View File

@ -10,7 +10,7 @@ func (cli *Client) BuildCancel(ctx context.Context, id string) error {
query := url.Values{}
query.Set("id", id)
serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@ -40,15 +40,15 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
}
query.Set("filters", f)
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
report := types.BuildCachePruneReport{}
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return nil, errors.Wrap(err, "error retrieving disk usage")
}

View File

@ -23,6 +23,6 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options
return checkpoints, err
}
err = json.NewDecoder(resp.body).Decode(&checkpoints)
err = json.NewDecoder(resp.Body).Decode(&checkpoints)
return checkpoints, err
}

View File

@ -59,7 +59,6 @@ import (
"github.com/docker/go-connections/sockets"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
)
// DummyHost is a hostname used for local communication.
@ -141,7 +140,7 @@ type Client struct {
// negotiateLock is used to single-flight the version negotiation process
negotiateLock sync.Mutex
tp trace.TracerProvider
traceOpts []otelhttp.Option
// When the client transport is an *http.Transport (default) we need to do some extra things (like closing idle connections).
// Store the original transport as the http.Client transport will be wrapped with tracing libs.
@ -203,6 +202,12 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
client: client,
proto: hostURL.Scheme,
addr: hostURL.Host,
traceOpts: []otelhttp.Option{
otelhttp.WithSpanNameFormatter(func(_ string, req *http.Request) string {
return req.Method + " " + req.URL.Path
}),
},
}
for _, op := range ops {
@ -230,13 +235,7 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
}
}
c.client.Transport = otelhttp.NewTransport(
c.client.Transport,
otelhttp.WithTracerProvider(c.tp),
otelhttp.WithSpanNameFormatter(func(_ string, req *http.Request) string {
return req.Method + " " + req.URL.Path
}),
)
c.client.Transport = otelhttp.NewTransport(c.client.Transport, c.traceOpts...)
return c, nil
}

View File

@ -69,11 +69,11 @@ type HijackDialer interface {
// ContainerAPIClient defines API client methods for the containers
type ContainerAPIClient interface {
ContainerAttach(ctx context.Context, container string, options container.AttachOptions) (types.HijackedResponse, error)
ContainerCommit(ctx context.Context, container string, options container.CommitOptions) (types.IDResponse, error)
ContainerCommit(ctx context.Context, container string, options container.CommitOptions) (container.CommitResponse, error)
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error)
ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (types.HijackedResponse, error)
ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error)
ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (container.ExecCreateResponse, error)
ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error)
ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error
ContainerExecStart(ctx context.Context, execID string, options container.ExecStartOptions) error
@ -93,9 +93,9 @@ type ContainerAPIClient interface {
ContainerStatsOneShot(ctx context.Context, container string) (container.StatsResponseReader, error)
ContainerStart(ctx context.Context, container string, options container.StartOptions) error
ContainerStop(ctx context.Context, container string, options container.StopOptions) error
ContainerTop(ctx context.Context, container string, arguments []string) (container.ContainerTopOKBody, error)
ContainerTop(ctx context.Context, container string, arguments []string) (container.TopResponse, error)
ContainerUnpause(ctx context.Context, container string) error
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error)
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.UpdateResponse, error)
ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error)
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error)
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options container.CopyToContainerOptions) error
@ -113,21 +113,30 @@ type ImageAPIClient interface {
BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
BuildCancel(ctx context.Context, id string) error
ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
ImageHistory(ctx context.Context, image string, opts image.HistoryOptions) ([]image.HistoryResponseItem, error)
ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
// Deprecated: Use [Client.ImageInspect] instead.
// Raw response can be obtained by [ImageInspectWithRawResponse] option.
ImageInspectWithRaw(ctx context.Context, image string) (image.InspectResponse, []byte, error)
ImageInspect(ctx context.Context, image string, _ ...ImageInspectOption) (image.InspectResponse, error)
ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
ImageLoad(ctx context.Context, input io.Reader, opts image.LoadOptions) (image.LoadResponse, error)
ImagePull(ctx context.Context, ref string, options image.PullOptions) (io.ReadCloser, error)
ImagePush(ctx context.Context, ref string, options image.PushOptions) (io.ReadCloser, error)
ImageRemove(ctx context.Context, image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
ImageSave(ctx context.Context, images []string, opts image.SaveOptions) (io.ReadCloser, error)
ImageSearch(ctx context.Context, term string, options registry.SearchOptions) ([]registry.SearchResult, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (image.PruneReport, error)
ImageInspect(ctx context.Context, image string, _ ...ImageInspectOption) (image.InspectResponse, error)
ImageHistory(ctx context.Context, image string, _ ...ImageHistoryOption) ([]image.HistoryResponseItem, error)
ImageLoad(ctx context.Context, input io.Reader, _ ...ImageLoadOption) (image.LoadResponse, error)
ImageSave(ctx context.Context, images []string, _ ...ImageSaveOption) (io.ReadCloser, error)
ImageAPIClientDeprecated
}
// ImageAPIClientDeprecated defines deprecated methods of the ImageAPIClient.
type ImageAPIClientDeprecated interface {
// ImageInspectWithRaw returns the image information and its raw representation.
//
// Deprecated: Use [Client.ImageInspect] instead. Raw response can be obtained using the [ImageInspectWithRawResponse] option.
ImageInspectWithRaw(ctx context.Context, image string) (image.InspectResponse, []byte, error)
}
// NetworkAPIClient defines API client methods for the networks

View File

@ -20,6 +20,6 @@ func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (t
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -24,7 +24,7 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
return swarm.Config{}, nil, err
}
body, err := io.ReadAll(resp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Config{}, nil, err
}

View File

@ -33,6 +33,6 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio
}
var configs []swarm.Config
err = json.NewDecoder(resp.body).Decode(&configs)
err = json.NewDecoder(resp.Body).Decode(&configs)
return configs, err
}

View File

@ -7,26 +7,25 @@ import (
"net/url"
"github.com/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
)
// ContainerCommit applies changes to a container and creates a new tagged image.
func (cli *Client) ContainerCommit(ctx context.Context, containerID string, options container.CommitOptions) (types.IDResponse, error) {
func (cli *Client) ContainerCommit(ctx context.Context, containerID string, options container.CommitOptions) (container.CommitResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return types.IDResponse{}, err
return container.CommitResponse{}, err
}
var repository, tag string
if options.Reference != "" {
ref, err := reference.ParseNormalizedNamed(options.Reference)
if err != nil {
return types.IDResponse{}, err
return container.CommitResponse{}, err
}
if _, isCanonical := ref.(reference.Canonical); isCanonical {
return types.IDResponse{}, errors.New("refusing to create a tag with a digest reference")
return container.CommitResponse{}, errors.New("refusing to create a tag with a digest reference")
}
ref = reference.TagNameOnly(ref)
@ -49,13 +48,13 @@ func (cli *Client) ContainerCommit(ctx context.Context, containerID string, opti
query.Set("pause", "0")
}
var response types.IDResponse
var response container.CommitResponse
resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -24,12 +24,12 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
query := url.Values{}
query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
response, err := cli.head(ctx, "/containers/"+containerID+"/archive", query, nil)
defer ensureReaderClosed(response)
resp, err := cli.head(ctx, "/containers/"+containerID+"/archive", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.PathStat{}, err
}
return getContainerPathStatFromHeader(response.header)
return getContainerPathStatFromHeader(resp.Header)
}
// CopyToContainer copies content into the container filesystem.
@ -71,7 +71,7 @@ func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath s
query := make(url.Values, 1)
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
response, err := cli.get(ctx, "/containers/"+containerID+"/archive", query, nil)
resp, err := cli.get(ctx, "/containers/"+containerID+"/archive", query, nil)
if err != nil {
return nil, container.PathStat{}, err
}
@ -82,11 +82,11 @@ func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath s
// copy it locally. Along with the stat info about the local destination,
// we have everything we need to handle the multiple possibilities there
// can be when copying a file/dir from one location to another file/dir.
stat, err := getContainerPathStatFromHeader(response.header)
stat, err := getContainerPathStatFromHeader(resp.Header)
if err != nil {
return nil, stat, fmt.Errorf("unable to get resource stat from response: %s", err)
}
return response.body, stat, err
return resp.Body, stat, err
}
func getContainerPathStatFromHeader(header http.Header) (container.PathStat, error) {

View File

@ -79,13 +79,13 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
NetworkingConfig: networkingConfig,
}
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/containers/create", query, body, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(serverResp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -15,14 +15,14 @@ func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]con
return nil, err
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var changes []container.FilesystemChange
err = json.NewDecoder(serverResp.body).Decode(&changes)
err = json.NewDecoder(resp.Body).Decode(&changes)
if err != nil {
return nil, err
}

View File

@ -11,10 +11,10 @@ import (
)
// ContainerExecCreate creates a new exec configuration to run an exec process.
func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string, options container.ExecOptions) (types.IDResponse, error) {
func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string, options container.ExecOptions) (container.ExecCreateResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return types.IDResponse{}, err
return container.ExecCreateResponse{}, err
}
// Make sure we negotiated (if the client is configured to do so),
@ -23,11 +23,11 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string,
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return types.IDResponse{}, err
return container.ExecCreateResponse{}, err
}
if err := cli.NewVersionError(ctx, "1.25", "env"); len(options.Env) != 0 && err != nil {
return types.IDResponse{}, err
return container.ExecCreateResponse{}, err
}
if versions.LessThan(cli.ClientVersion(), "1.42") {
options.ConsoleSize = nil
@ -36,11 +36,11 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string,
resp, err := cli.post(ctx, "/containers/"+containerID+"/exec", nil, options, nil)
defer ensureReaderClosed(resp)
if err != nil {
return types.IDResponse{}, err
return container.ExecCreateResponse{}, err
}
var response types.IDResponse
err = json.NewDecoder(resp.body).Decode(&response)
var response container.ExecCreateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}
@ -75,7 +75,7 @@ func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (con
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@ -15,10 +15,10 @@ func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.
return nil, err
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil)
resp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil)
if err != nil {
return nil, err
}
return serverResp.body, nil
return resp.Body, nil
}

View File

@ -17,14 +17,14 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (co
return container.InspectResponse{}, err
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.InspectResponse{}, err
}
var response container.InspectResponse
err = json.NewDecoder(serverResp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}
@ -39,13 +39,13 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri
if getSize {
query.Set("size", "1")
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.InspectResponse{}, nil, err
}
body, err := io.ReadAll(serverResp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return container.InspectResponse{}, nil, err
}

View File

@ -51,6 +51,6 @@ func (cli *Client) ContainerList(ctx context.Context, options container.ListOpti
}
var containers []container.Summary
err = json.NewDecoder(resp.body).Decode(&containers)
err = json.NewDecoder(resp.Body).Decode(&containers)
return containers, err
}

View File

@ -81,5 +81,5 @@ func (cli *Client) ContainerLogs(ctx context.Context, containerID string, option
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}

View File

@ -20,14 +20,14 @@ func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Arg
return container.PruneReport{}, err
}
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.PruneReport{}, err
}
var report container.PruneReport
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return container.PruneReport{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}

View File

@ -27,8 +27,8 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea
}
return container.StatsResponseReader{
Body: resp.body,
OSType: getDockerOS(resp.header.Get("Server")),
Body: resp.Body,
OSType: getDockerOS(resp.Header.Get("Server")),
}, nil
}
@ -50,7 +50,7 @@ func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string
}
return container.StatsResponseReader{
Body: resp.body,
OSType: getDockerOS(resp.header.Get("Server")),
Body: resp.Body,
OSType: getDockerOS(resp.Header.Get("Server")),
}, nil
}

View File

@ -10,10 +10,10 @@ import (
)
// ContainerTop shows process information from within a container.
func (cli *Client) ContainerTop(ctx context.Context, containerID string, arguments []string) (container.ContainerTopOKBody, error) {
func (cli *Client) ContainerTop(ctx context.Context, containerID string, arguments []string) (container.TopResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.ContainerTopOKBody{}, err
return container.TopResponse{}, err
}
query := url.Values{}
@ -24,10 +24,10 @@ func (cli *Client) ContainerTop(ctx context.Context, containerID string, argumen
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.ContainerTopOKBody{}, err
return container.TopResponse{}, err
}
var response container.ContainerTopOKBody
err = json.NewDecoder(resp.body).Decode(&response)
var response container.TopResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -8,19 +8,19 @@ import (
)
// ContainerUpdate updates the resources of a container.
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) {
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.UpdateResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.ContainerUpdateOKBody{}, err
return container.UpdateResponse{}, err
}
serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.ContainerUpdateOKBody{}, err
return container.UpdateResponse{}, err
}
var response container.ContainerUpdateOKBody
err = json.NewDecoder(serverResp.body).Decode(&response)
var response container.UpdateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -67,9 +67,8 @@ func (cli *Client) ContainerWait(ctx context.Context, containerID string, condit
go func() {
defer ensureReaderClosed(resp)
body := resp.body
responseText := bytes.NewBuffer(nil)
stream := io.TeeReader(body, responseText)
stream := io.TeeReader(resp.Body, responseText)
var res container.WaitResponse
if err := json.NewDecoder(stream).Decode(&res); err != nil {
@ -111,7 +110,7 @@ func (cli *Client) legacyContainerWait(ctx context.Context, containerID string)
defer ensureReaderClosed(resp)
var res container.WaitResponse
if err := json.NewDecoder(resp.body).Decode(&res); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
errC <- err
return
}

View File

@ -19,14 +19,14 @@ func (cli *Client) DiskUsage(ctx context.Context, options types.DiskUsageOptions
}
}
serverResp, err := cli.get(ctx, "/system/df", query, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/system/df", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return types.DiskUsage{}, err
}
var du types.DiskUsage
if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
return types.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return du, nil

View File

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

View File

@ -36,9 +36,9 @@ func (cli *Client) Events(ctx context.Context, options events.ListOptions) (<-ch
errs <- err
return
}
defer resp.body.Close()
defer resp.Body.Close()
decoder := json.NewDecoder(resp.body)
decoder := json.NewDecoder(resp.Body)
close(started)
for {

View File

@ -33,14 +33,14 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
headers.Set("Content-Type", "application/x-tar")
serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
resp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
if err != nil {
return types.ImageBuildResponse{}, err
}
return types.ImageBuildResponse{
Body: serverResp.body,
OSType: getDockerOS(serverResp.header.Get("Server")),
Body: resp.Body,
OSType: getDockerOS(resp.Header.Get("Server")),
}, nil
}

View File

@ -30,10 +30,10 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}
func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/images/create", query, nil, http.Header{
registry.AuthHeader: {registryAuth},
})

View File

@ -3,33 +3,54 @@ package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/docker/docker/api/types/image"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ImageHistoryWithPlatform sets the platform for the image history operation.
func ImageHistoryWithPlatform(platform ocispec.Platform) ImageHistoryOption {
return imageHistoryOptionFunc(func(opt *imageHistoryOpts) error {
if opt.apiOptions.Platform != nil {
return fmt.Errorf("platform already set to %s", *opt.apiOptions.Platform)
}
opt.apiOptions.Platform = &platform
return nil
})
}
// ImageHistory returns the changes in an image in history format.
func (cli *Client) ImageHistory(ctx context.Context, imageID string, opts image.HistoryOptions) ([]image.HistoryResponseItem, error) {
func (cli *Client) ImageHistory(ctx context.Context, imageID string, historyOpts ...ImageHistoryOption) ([]image.HistoryResponseItem, error) {
query := url.Values{}
if opts.Platform != nil {
var opts imageHistoryOpts
for _, o := range historyOpts {
if err := o.Apply(&opts); err != nil {
return nil, err
}
}
if opts.apiOptions.Platform != nil {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return nil, err
}
p, err := encodePlatform(opts.Platform)
p, err := encodePlatform(opts.apiOptions.Platform)
if err != nil {
return nil, err
}
query.Set("platform", p)
}
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", query, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/images/"+imageID+"/history", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var history []image.HistoryResponseItem
err = json.NewDecoder(serverResp.body).Decode(&history)
err = json.NewDecoder(resp.Body).Decode(&history)
return history, err
}

View File

@ -0,0 +1,19 @@
package client
import (
"github.com/docker/docker/api/types/image"
)
// ImageHistoryOption is a type representing functional options for the image history operation.
type ImageHistoryOption interface {
Apply(*imageHistoryOpts) error
}
type imageHistoryOptionFunc func(opt *imageHistoryOpts) error
func (f imageHistoryOptionFunc) Apply(o *imageHistoryOpts) error {
return f(o)
}
type imageHistoryOpts struct {
apiOptions image.HistoryOptions
}

View File

@ -44,5 +44,5 @@ func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, r
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}

View File

@ -11,49 +11,6 @@ import (
"github.com/docker/docker/api/types/image"
)
// ImageInspectOption is a type representing functional options for the image inspect operation.
type ImageInspectOption interface {
Apply(*imageInspectOpts) error
}
type imageInspectOptionFunc func(opt *imageInspectOpts) error
func (f imageInspectOptionFunc) Apply(o *imageInspectOpts) error {
return f(o)
}
// ImageInspectWithRawResponse instructs the client to additionally store the
// raw inspect response in the provided buffer.
func ImageInspectWithRawResponse(raw *bytes.Buffer) ImageInspectOption {
return imageInspectOptionFunc(func(opts *imageInspectOpts) error {
opts.raw = raw
return nil
})
}
// ImageInspectWithManifests sets manifests API option for the image inspect operation.
// This option is only available for API version 1.48 and up.
// With this option set, the image inspect operation response will have the
// [image.InspectResponse.Manifests] field populated if the server is multi-platform capable.
func ImageInspectWithManifests(manifests bool) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
clientOpts.apiOptions.Manifests = manifests
return nil
})
}
// ImageInspectWithAPIOpts sets the API options for the image inspect operation.
func ImageInspectWithAPIOpts(opts image.InspectOptions) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
clientOpts.apiOptions = opts
return nil
})
}
type imageInspectOpts struct {
raw *bytes.Buffer
apiOptions image.InspectOptions
}
// ImageInspect returns the image information.
func (cli *Client) ImageInspect(ctx context.Context, imageID string, inspectOpts ...ImageInspectOption) (image.InspectResponse, error) {
if imageID == "" {
@ -75,8 +32,8 @@ func (cli *Client) ImageInspect(ctx context.Context, imageID string, inspectOpts
query.Set("manifests", "1")
}
serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", query, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/images/"+imageID+"/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return image.InspectResponse{}, err
}
@ -86,7 +43,7 @@ func (cli *Client) ImageInspect(ctx context.Context, imageID string, inspectOpts
buf = &bytes.Buffer{}
}
if _, err := io.Copy(buf, serverResp.body); err != nil {
if _, err := io.Copy(buf, resp.Body); err != nil {
return image.InspectResponse{}, err
}
@ -97,8 +54,7 @@ func (cli *Client) ImageInspect(ctx context.Context, imageID string, inspectOpts
// ImageInspectWithRaw returns the image information and its raw representation.
//
// Deprecated: Use [Client.ImageInspect] instead.
// Raw response can be obtained by [ImageInspectWithRawResponse] option.
// Deprecated: Use [Client.ImageInspect] instead. Raw response can be obtained using the [ImageInspectWithRawResponse] option.
func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (image.InspectResponse, []byte, error) {
var buf bytes.Buffer
resp, err := cli.ImageInspect(ctx, imageID, ImageInspectWithRawResponse(&buf))

View File

@ -0,0 +1,50 @@
package client
import (
"bytes"
"github.com/docker/docker/api/types/image"
)
// ImageInspectOption is a type representing functional options for the image inspect operation.
type ImageInspectOption interface {
Apply(*imageInspectOpts) error
}
type imageInspectOptionFunc func(opt *imageInspectOpts) error
func (f imageInspectOptionFunc) Apply(o *imageInspectOpts) error {
return f(o)
}
// ImageInspectWithRawResponse instructs the client to additionally store the
// raw inspect response in the provided buffer.
func ImageInspectWithRawResponse(raw *bytes.Buffer) ImageInspectOption {
return imageInspectOptionFunc(func(opts *imageInspectOpts) error {
opts.raw = raw
return nil
})
}
// ImageInspectWithManifests sets manifests API option for the image inspect operation.
// This option is only available for API version 1.48 and up.
// With this option set, the image inspect operation response will have the
// [image.InspectResponse.Manifests] field populated if the server is multi-platform capable.
func ImageInspectWithManifests(manifests bool) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
clientOpts.apiOptions.Manifests = manifests
return nil
})
}
// ImageInspectWithAPIOpts sets the API options for the image inspect operation.
func ImageInspectWithAPIOpts(opts image.InspectOptions) ImageInspectOption {
return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
clientOpts.apiOptions = opts
return nil
})
}
type imageInspectOpts struct {
raw *bytes.Buffer
apiOptions image.InspectOptions
}

View File

@ -56,12 +56,12 @@ func (cli *Client) ImageList(ctx context.Context, options image.ListOptions) ([]
query.Set("manifests", "1")
}
serverResp, err := cli.get(ctx, "/images/json", query, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/images/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return images, err
}
err = json.NewDecoder(serverResp.body).Decode(&images)
err = json.NewDecoder(resp.Body).Decode(&images)
return images, err
}

View File

@ -16,18 +16,25 @@ import (
// Platform is an optional parameter that specifies the platform to load from
// the provided multi-platform image. This is only has effect if the input image
// is a multi-platform image.
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, opts image.LoadOptions) (image.LoadResponse, error) {
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, loadOpts ...ImageLoadOption) (image.LoadResponse, error) {
var opts imageLoadOpts
for _, opt := range loadOpts {
if err := opt.Apply(&opts); err != nil {
return image.LoadResponse{}, err
}
}
query := url.Values{}
query.Set("quiet", "0")
if opts.Quiet {
if opts.apiOptions.Quiet {
query.Set("quiet", "1")
}
if len(opts.Platforms) > 0 {
if len(opts.apiOptions.Platforms) > 0 {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return image.LoadResponse{}, err
}
p, err := encodePlatforms(opts.Platforms...)
p, err := encodePlatforms(opts.apiOptions.Platforms...)
if err != nil {
return image.LoadResponse{}, err
}
@ -41,7 +48,7 @@ func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, opts image.Lo
return image.LoadResponse{}, err
}
return image.LoadResponse{
Body: resp.body,
JSON: resp.header.Get("Content-Type") == "application/json",
Body: resp.Body,
JSON: resp.Header.Get("Content-Type") == "application/json",
}, nil
}

View File

@ -0,0 +1,41 @@
package client
import (
"fmt"
"github.com/docker/docker/api/types/image"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ImageLoadOption is a type representing functional options for the image load operation.
type ImageLoadOption interface {
Apply(*imageLoadOpts) error
}
type imageLoadOptionFunc func(opt *imageLoadOpts) error
func (f imageLoadOptionFunc) Apply(o *imageLoadOpts) error {
return f(o)
}
type imageLoadOpts struct {
apiOptions image.LoadOptions
}
// ImageLoadWithQuiet sets the quiet option for the image load operation.
func ImageLoadWithQuiet(quiet bool) ImageLoadOption {
return imageLoadOptionFunc(func(opt *imageLoadOpts) error {
opt.apiOptions.Quiet = quiet
return nil
})
}
// ImageLoadWithPlatforms sets the platforms to be loaded from the image.
func ImageLoadWithPlatforms(platforms ...ocispec.Platform) ImageLoadOption {
return imageLoadOptionFunc(func(opt *imageLoadOpts) error {
if opt.apiOptions.Platforms != nil {
return fmt.Errorf("platforms already set to %v", opt.apiOptions.Platforms)
}
opt.apiOptions.Platforms = platforms
return nil
})
}

View File

@ -20,14 +20,14 @@ func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (
return image.PruneReport{}, err
}
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return image.PruneReport{}, err
}
var report image.PruneReport
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return image.PruneReport{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}

View File

@ -45,7 +45,7 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options image.P
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}
// getAPITagFromNamedRef returns a tag from the specified reference.

View File

@ -63,10 +63,10 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options image.Pu
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}
func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (serverResponse, error) {
func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/images/"+imageID+"/push", query, nil, http.Header{
registry.AuthHeader: {registryAuth},
})

View File

@ -19,13 +19,13 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options imag
query.Set("noprune", "1")
}
var dels []image.DeleteResponse
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return dels, err
return nil, err
}
err = json.NewDecoder(resp.body).Decode(&dels)
var dels []image.DeleteResponse
err = json.NewDecoder(resp.Body).Decode(&dels)
return dels, err
}

View File

@ -4,22 +4,29 @@ import (
"context"
"io"
"net/url"
"github.com/docker/docker/api/types/image"
)
// ImageSave retrieves one or more images from the docker host as an io.ReadCloser.
// It's up to the caller to store the images and close the stream.
func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, opts image.SaveOptions) (io.ReadCloser, error) {
//
// Platforms is an optional parameter that specifies the platforms to save from the image.
// This is only has effect if the input image is a multi-platform image.
func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts ...ImageSaveOption) (io.ReadCloser, error) {
var opts imageSaveOpts
for _, opt := range saveOpts {
if err := opt.Apply(&opts); err != nil {
return nil, err
}
}
query := url.Values{
"names": imageIDs,
}
if len(opts.Platforms) > 0 {
if len(opts.apiOptions.Platforms) > 0 {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return nil, err
}
p, err := encodePlatforms(opts.Platforms...)
p, err := encodePlatforms(opts.apiOptions.Platforms...)
if err != nil {
return nil, err
}
@ -30,5 +37,5 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, opts image.
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}

View File

@ -0,0 +1,33 @@
package client
import (
"fmt"
"github.com/docker/docker/api/types/image"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
type ImageSaveOption interface {
Apply(*imageSaveOpts) error
}
type imageSaveOptionFunc func(opt *imageSaveOpts) error
func (f imageSaveOptionFunc) Apply(o *imageSaveOpts) error {
return f(o)
}
// ImageSaveWithPlatforms sets the platforms to be saved from the image.
func ImageSaveWithPlatforms(platforms ...ocispec.Platform) ImageSaveOption {
return imageSaveOptionFunc(func(opt *imageSaveOpts) error {
if opt.apiOptions.Platforms != nil {
return fmt.Errorf("platforms already set to %v", opt.apiOptions.Platforms)
}
opt.apiOptions.Platforms = platforms
return nil
})
}
type imageSaveOpts struct {
apiOptions image.SaveOptions
}

View File

@ -43,11 +43,11 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options registr
return results, err
}
err = json.NewDecoder(resp.body).Decode(&results)
err = json.NewDecoder(resp.Body).Decode(&results)
return results, err
}
func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
return cli.get(ctx, "/images/search", query, http.Header{
registry.AuthHeader: {registryAuth},
})

View File

@ -12,13 +12,13 @@ import (
// Info returns information about the docker server.
func (cli *Client) Info(ctx context.Context) (system.Info, error) {
var info system.Info
serverResp, err := cli.get(ctx, "/info", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/info", url.Values{}, nil)
defer ensureReaderClosed(resp)
if err != nil {
return info, err
}
if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return info, fmt.Errorf("Error reading remote info: %v", err)
}

View File

@ -19,6 +19,6 @@ func (cli *Client) RegistryLogin(ctx context.Context, auth registry.AuthConfig)
}
var response registry.AuthenticateOKBody
err = json.NewDecoder(resp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -10,15 +10,13 @@ import (
// NetworkCreate creates a new network in the docker host.
func (cli *Client) NetworkCreate(ctx context.Context, name string, options network.CreateOptions) (network.CreateResponse, error) {
var response network.CreateResponse
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
return network.CreateResponse{}, err
}
networkCreateRequest := network.CreateRequest{
@ -30,12 +28,13 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options netwo
networkCreateRequest.CheckDuplicate = &enabled //nolint:staticcheck // ignore SA1019: CheckDuplicate is deprecated since API v1.44.
}
serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
return network.CreateResponse{}, err
}
err = json.NewDecoder(serverResp.body).Decode(&response)
var response network.CreateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -36,7 +36,7 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string,
return network.Inspect{}, nil, err
}
raw, err := io.ReadAll(resp.body)
raw, err := io.ReadAll(resp.Body)
if err != nil {
return network.Inspect{}, nil, err
}

View File

@ -27,6 +27,6 @@ func (cli *Client) NetworkList(ctx context.Context, options network.ListOptions)
if err != nil {
return networkResources, err
}
err = json.NewDecoder(resp.body).Decode(&networkResources)
err = json.NewDecoder(resp.Body).Decode(&networkResources)
return networkResources, err
}

View File

@ -20,14 +20,14 @@ func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args)
return network.PruneReport{}, err
}
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.PruneReport{}, err
}
var report network.PruneReport
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return network.PruneReport{}, fmt.Errorf("Error retrieving network prune report: %v", err)
}

View File

@ -15,13 +15,13 @@ func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm
if err != nil {
return swarm.Node{}, nil, err
}
serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Node{}, nil, err
}
body, err := io.ReadAll(serverResp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Node{}, nil, err
}

View File

@ -30,6 +30,6 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions)
}
var nodes []swarm.Node
err = json.NewDecoder(resp.body).Decode(&nodes)
err = json.NewDecoder(resp.Body).Decode(&nodes)
return nodes, err
}

View File

@ -12,6 +12,7 @@ import (
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
)
@ -227,8 +228,13 @@ func WithAPIVersionNegotiation() Opt {
// WithTraceProvider sets the trace provider for the client.
// If this is not set then the global trace provider will be used.
func WithTraceProvider(provider trace.TracerProvider) Opt {
return WithTraceOptions(otelhttp.WithTracerProvider(provider))
}
// WithTraceOptions sets tracing span options for the client.
func WithTraceOptions(opts ...otelhttp.Option) Opt {
return func(c *Client) error {
c.tp = provider
c.traceOpts = append(c.traceOpts, opts...)
return nil
}
}

View File

@ -8,7 +8,6 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/errdefs"
)
// Ping pings the server and returns the value of the "Docker-Experimental",
@ -28,49 +27,54 @@ func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
if err != nil {
return ping, err
}
serverResp, err := cli.doRequest(req)
if err == nil {
defer ensureReaderClosed(serverResp)
switch serverResp.statusCode {
resp, err := cli.doRequest(req)
if err != nil {
if IsErrConnectionFailed(err) {
return ping, err
}
// We managed to connect, but got some error; continue and try GET request.
} else {
defer ensureReaderClosed(resp)
switch resp.StatusCode {
case http.StatusOK, http.StatusInternalServerError:
// Server handled the request, so parse the response
return parsePingResponse(cli, serverResp)
return parsePingResponse(cli, resp)
}
} else if IsErrConnectionFailed(err) {
return ping, err
}
// HEAD failed; fallback to GET.
req.Method = http.MethodGet
serverResp, err = cli.doRequest(req)
defer ensureReaderClosed(serverResp)
resp, err = cli.doRequest(req)
defer ensureReaderClosed(resp)
if err != nil {
return ping, err
}
return parsePingResponse(cli, serverResp)
return parsePingResponse(cli, resp)
}
func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
var ping types.Ping
if resp.header == nil {
err := cli.checkResponseErr(resp)
return ping, errdefs.FromStatusCode(err, resp.statusCode)
func parsePingResponse(cli *Client, resp *http.Response) (types.Ping, error) {
if resp == nil {
return types.Ping{}, nil
}
ping.APIVersion = resp.header.Get("Api-Version")
ping.OSType = resp.header.Get("Ostype")
if resp.header.Get("Docker-Experimental") == "true" {
var ping types.Ping
if resp.Header == nil {
return ping, cli.checkResponseErr(resp)
}
ping.APIVersion = resp.Header.Get("Api-Version")
ping.OSType = resp.Header.Get("Ostype")
if resp.Header.Get("Docker-Experimental") == "true" {
ping.Experimental = true
}
if bv := resp.header.Get("Builder-Version"); bv != "" {
if bv := resp.Header.Get("Builder-Version"); bv != "" {
ping.BuilderVersion = types.BuilderVersion(bv)
}
if si := resp.header.Get("Swarm"); si != "" {
if si := resp.Header.Get("Swarm"); si != "" {
state, role, _ := strings.Cut(si, "/")
ping.SwarmStatus = &swarm.Status{
NodeState: swarm.LocalNodeState(state),
ControlAvailable: role == "manager",
}
}
err := cli.checkResponseErr(resp)
return ping, errdefs.FromStatusCode(err, resp.statusCode)
return ping, cli.checkResponseErr(resp)
}

View File

@ -21,7 +21,7 @@ func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*type
return nil, nil, err
}
body, err := io.ReadAll(resp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}

View File

@ -35,13 +35,13 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
return nil, err
}
name = resp.header.Get("Docker-Plugin-Name")
name = resp.Header.Get("Docker-Plugin-Name")
pr, pw := io.Pipe()
go func() { // todo: the client should probably be designed more around the actual api
_, err := io.Copy(pw, resp.body)
_, err := io.Copy(pw, resp.Body)
if err != nil {
pw.CloseWithError(err)
_ = pw.CloseWithError(err)
return
}
defer func() {
@ -52,29 +52,29 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
}()
if len(options.Args) > 0 {
if err := cli.PluginSet(ctx, name, options.Args); err != nil {
pw.CloseWithError(err)
_ = pw.CloseWithError(err)
return
}
}
if options.Disabled {
pw.Close()
_ = pw.Close()
return
}
enableErr := cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
pw.CloseWithError(enableErr)
_ = pw.CloseWithError(enableErr)
}()
return pr, nil
}
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
return cli.get(ctx, "/plugins/privileges", query, http.Header{
registry.AuthHeader: {registryAuth},
})
}
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) {
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/plugins/pull", query, privileges, http.Header{
registry.AuthHeader: {registryAuth},
})
@ -98,7 +98,7 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values,
}
var privileges types.PluginPrivileges
if err := json.NewDecoder(resp.body).Decode(&privileges); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&privileges); err != nil {
ensureReaderClosed(resp)
return nil, err
}

View File

@ -28,6 +28,6 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.P
return plugins, err
}
err = json.NewDecoder(resp.body).Decode(&plugins)
err = json.NewDecoder(resp.Body).Decode(&plugins)
return plugins, err
}

View File

@ -20,5 +20,5 @@ func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth str
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}

View File

@ -37,10 +37,10 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) {
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, http.Header{
registry.AuthHeader: {registryAuth},
})

View File

@ -19,47 +19,39 @@ import (
"github.com/pkg/errors"
)
// serverResponse is a wrapper for http API responses.
type serverResponse struct {
body io.ReadCloser
header http.Header
statusCode int
reqURL *url.URL
}
// head sends an http request to the docker API using the method HEAD.
func (cli *Client) head(ctx context.Context, path string, query url.Values, headers http.Header) (serverResponse, error) {
func (cli *Client) head(ctx context.Context, path string, query url.Values, headers http.Header) (*http.Response, error) {
return cli.sendRequest(ctx, http.MethodHead, path, query, nil, headers)
}
// get sends an http request to the docker API using the method GET with a specific Go context.
func (cli *Client) get(ctx context.Context, path string, query url.Values, headers http.Header) (serverResponse, error) {
func (cli *Client) get(ctx context.Context, path string, query url.Values, headers http.Header) (*http.Response, error) {
return cli.sendRequest(ctx, http.MethodGet, path, query, nil, headers)
}
// post sends an http request to the docker API using the method POST with a specific Go context.
func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers http.Header) (serverResponse, error) {
func (cli *Client) post(ctx context.Context, path string, query url.Values, obj interface{}, headers http.Header) (*http.Response, error) {
body, headers, err := encodeBody(obj, headers)
if err != nil {
return serverResponse{}, err
return nil, err
}
return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers)
}
func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (*http.Response, error) {
return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers)
}
func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers http.Header) (serverResponse, error) {
func (cli *Client) put(ctx context.Context, path string, query url.Values, obj interface{}, headers http.Header) (*http.Response, error) {
body, headers, err := encodeBody(obj, headers)
if err != nil {
return serverResponse{}, err
return nil, err
}
return cli.putRaw(ctx, path, query, body, headers)
}
// putRaw sends an http request to the docker API using the method PUT.
func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (*http.Response, error) {
// PUT requests are expected to always have a body (apparently)
// so explicitly pass an empty body to sendRequest to signal that
// it should set the Content-Type header if not already present.
@ -70,7 +62,7 @@ func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, bo
}
// delete sends an http request to the docker API using the method DELETE.
func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers http.Header) (serverResponse, error) {
func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers http.Header) (*http.Response, error) {
return cli.sendRequest(ctx, http.MethodDelete, path, query, nil, headers)
}
@ -116,42 +108,40 @@ func (cli *Client) buildRequest(ctx context.Context, method, path string, body i
return req, nil
}
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers http.Header) (serverResponse, error) {
func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers http.Header) (*http.Response, error) {
req, err := cli.buildRequest(ctx, method, cli.getAPIPath(ctx, path, query), body, headers)
if err != nil {
return serverResponse{}, err
return nil, err
}
resp, err := cli.doRequest(req)
switch {
case errors.Is(err, context.Canceled):
return serverResponse{}, errdefs.Cancelled(err)
return nil, errdefs.Cancelled(err)
case errors.Is(err, context.DeadlineExceeded):
return serverResponse{}, errdefs.Deadline(err)
return nil, errdefs.Deadline(err)
case err == nil:
err = cli.checkResponseErr(resp)
return resp, cli.checkResponseErr(resp)
default:
return resp, err
}
return resp, errdefs.FromStatusCode(err, resp.statusCode)
}
// FIXME(thaJeztah): Should this actually return a serverResp when a connection error occurred?
func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
serverResp := serverResponse{statusCode: -1, reqURL: req.URL}
func (cli *Client) doRequest(req *http.Request) (*http.Response, error) {
resp, err := cli.client.Do(req)
if err != nil {
if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
return serverResp, errConnectionFailed{fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)}
return nil, errConnectionFailed{fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)}
}
if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") {
return serverResp, errConnectionFailed{errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")}
return nil, errConnectionFailed{errors.Wrap(err, "the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings")}
}
// Don't decorate context sentinel errors; users may be comparing to
// them directly.
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return serverResp, err
return nil, err
}
var uErr *url.Error
@ -159,7 +149,7 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
var nErr *net.OpError
if errors.As(uErr.Err, &nErr) {
if os.IsPermission(nErr.Err) {
return serverResp, errConnectionFailed{errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)}
return nil, errConnectionFailed{errors.Wrapf(err, "permission denied while trying to connect to the Docker daemon socket at %v", cli.host)}
}
}
}
@ -168,10 +158,10 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
if errors.As(err, &nErr) {
// FIXME(thaJeztah): any net.Error should be considered a connection error (but we should include the original error)?
if nErr.Timeout() {
return serverResp, connectionFailed(cli.host)
return nil, connectionFailed(cli.host)
}
if strings.Contains(nErr.Error(), "connection refused") || strings.Contains(nErr.Error(), "dial unix") {
return serverResp, connectionFailed(cli.host)
return nil, connectionFailed(cli.host)
}
}
@ -195,28 +185,37 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) {
}
}
return serverResp, errConnectionFailed{errors.Wrap(err, "error during connect")}
return nil, errConnectionFailed{errors.Wrap(err, "error during connect")}
}
if resp != nil {
serverResp.statusCode = resp.StatusCode
serverResp.body = resp.Body
serverResp.header = resp.Header
}
return serverResp, nil
return resp, nil
}
func (cli *Client) checkResponseErr(serverResp serverResponse) error {
if serverResp.statusCode >= 200 && serverResp.statusCode < 400 {
func (cli *Client) checkResponseErr(serverResp *http.Response) (retErr error) {
if serverResp == nil {
return nil
}
if serverResp.StatusCode >= 200 && serverResp.StatusCode < 400 {
return nil
}
defer func() {
retErr = errdefs.FromStatusCode(retErr, serverResp.StatusCode)
}()
var body []byte
var err error
if serverResp.body != nil {
var reqURL string
if serverResp.Request != nil {
reqURL = serverResp.Request.URL.String()
}
statusMsg := serverResp.Status
if statusMsg == "" {
statusMsg = http.StatusText(serverResp.StatusCode)
}
if serverResp.Body != nil {
bodyMax := 1 * 1024 * 1024 // 1 MiB
bodyR := &io.LimitedReader{
R: serverResp.body,
R: serverResp.Body,
N: int64(bodyMax),
}
body, err = io.ReadAll(bodyR)
@ -224,15 +223,21 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
return err
}
if bodyR.N == 0 {
return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), bodyMax, serverResp.reqURL)
if reqURL != "" {
return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", statusMsg, bodyMax, reqURL)
}
return fmt.Errorf("request returned %s with a message (> %d bytes); check if the server supports the requested API version", statusMsg, bodyMax)
}
}
if len(body) == 0 {
return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL)
if reqURL != "" {
return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", statusMsg, reqURL)
}
return fmt.Errorf("request returned %s; check if the server supports the requested API version", statusMsg)
}
var daemonErr error
if serverResp.header.Get("Content-Type") == "application/json" && (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) {
if serverResp.Header.Get("Content-Type") == "application/json" && (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) {
var errorResponse types.ErrorResponse
if err := json.Unmarshal(body, &errorResponse); err != nil {
return errors.Wrap(err, "Error reading JSON")
@ -255,8 +260,8 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error {
//
// TODO(thaJeztah): consider adding a log.Debug to allow clients to debug the actual response when enabling debug logging.
daemonErr = fmt.Errorf(`API returned a %d (%s) but provided no error-message`,
serverResp.statusCode,
http.StatusText(serverResp.statusCode),
serverResp.StatusCode,
http.StatusText(serverResp.StatusCode),
)
} else {
daemonErr = errors.New(strings.TrimSpace(errorResponse.Message))
@ -305,10 +310,16 @@ func encodeData(data interface{}) (*bytes.Buffer, error) {
return params, nil
}
func ensureReaderClosed(response serverResponse) {
if response.body != nil {
func ensureReaderClosed(response *http.Response) {
if response != nil && response.Body != nil {
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
_, _ = io.CopyN(io.Discard, response.body, 512)
_ = response.body.Close()
// see https://github.com/google/go-github/pull/317/files#r57536827
//
// TODO(thaJeztah): see if this optimization is still needed, or already implemented in stdlib,
// and check if context-cancellation should handle this as well. If still needed, consider
// wrapping response.Body, or returning a "closer()" from [Client.sendRequest] and related
// methods.
_, _ = io.CopyN(io.Discard, response.Body, 512)
_ = response.Body.Close()
}
}

View File

@ -10,16 +10,16 @@ import (
// SecretCreate creates a new secret.
func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error) {
var response types.SecretCreateResponse
if err := cli.NewVersionError(ctx, "1.25", "secret create"); err != nil {
return response, err
return types.SecretCreateResponse{}, err
}
resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
return types.SecretCreateResponse{}, err
}
err = json.NewDecoder(resp.body).Decode(&response)
var response types.SecretCreateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -24,7 +24,7 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
return swarm.Secret{}, nil, err
}
body, err := io.ReadAll(resp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Secret{}, nil, err
}

View File

@ -33,6 +33,6 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio
}
var secrets []swarm.Secret
err = json.NewDecoder(resp.body).Decode(&secrets)
err = json.NewDecoder(resp.Body).Decode(&secrets)
return secrets, err
}

View File

@ -73,7 +73,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
if resolveWarning != "" {
response.Warnings = append(response.Warnings, resolveWarning)
}

View File

@ -21,13 +21,13 @@ func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string,
query := url.Values{}
query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults))
serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Service{}, nil, err
}
body, err := io.ReadAll(serverResp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Service{}, nil, err
}

View File

@ -34,6 +34,6 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt
}
var services []swarm.Service
err = json.NewDecoder(resp.body).Decode(&services)
err = json.NewDecoder(resp.Body).Decode(&services)
return services, err
}

View File

@ -53,5 +53,5 @@ func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options co
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}

View File

@ -80,8 +80,8 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
return swarm.ServiceUpdateResponse{}, err
}
response := swarm.ServiceUpdateResponse{}
err = json.NewDecoder(resp.body).Decode(&response)
var response swarm.ServiceUpdateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
if resolveWarning != "" {
response.Warnings = append(response.Warnings, resolveWarning)
}

View File

@ -9,13 +9,13 @@ import (
// SwarmGetUnlockKey retrieves the swarm's unlock key.
func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) {
serverResp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return types.SwarmUnlockKeyResponse{}, err
}
var response types.SwarmUnlockKeyResponse
err = json.NewDecoder(serverResp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -9,13 +9,13 @@ import (
// SwarmInit initializes the swarm.
func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) {
serverResp, err := cli.post(ctx, "/swarm/init", nil, req, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/swarm/init", nil, req, nil)
defer ensureReaderClosed(resp)
if err != nil {
return "", err
}
var response string
err = json.NewDecoder(serverResp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -9,13 +9,13 @@ import (
// SwarmInspect inspects the swarm.
func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) {
serverResp, err := cli.get(ctx, "/swarm", nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/swarm", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Swarm{}, err
}
var response swarm.Swarm
err = json.NewDecoder(serverResp.body).Decode(&response)
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@ -8,7 +8,7 @@ import (
// SwarmUnlock unlocks locked swarm.
func (cli *Client) SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error {
serverResp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil)
ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil)
ensureReaderClosed(resp)
return err
}

View File

@ -16,13 +16,13 @@ func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm
return swarm.Task{}, nil, err
}
serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Task{}, nil, err
}
body, err := io.ReadAll(serverResp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Task{}, nil, err
}

View File

@ -30,6 +30,6 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions)
}
var tasks []swarm.Task
err = json.NewDecoder(resp.body).Decode(&tasks)
err = json.NewDecoder(resp.Body).Decode(&tasks)
return tasks, err
}

View File

@ -47,5 +47,5 @@ func (cli *Client) TaskLogs(ctx context.Context, taskID string, options containe
if err != nil {
return nil, err
}
return resp.body, nil
return resp.Body, nil
}

View File

@ -16,6 +16,6 @@ func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) {
}
var server types.Version
err = json.NewDecoder(resp.body).Decode(&server)
err = json.NewDecoder(resp.Body).Decode(&server)
return server, err
}

View File

@ -9,12 +9,13 @@ import (
// VolumeCreate creates a volume in the docker host.
func (cli *Client) VolumeCreate(ctx context.Context, options volume.CreateOptions) (volume.Volume, error) {
var vol volume.Volume
resp, err := cli.post(ctx, "/volumes/create", nil, options, nil)
defer ensureReaderClosed(resp)
if err != nil {
return vol, err
}
err = json.NewDecoder(resp.body).Decode(&vol)
return volume.Volume{}, err
}
var vol volume.Volume
err = json.NewDecoder(resp.Body).Decode(&vol)
return vol, err
}

View File

@ -22,17 +22,18 @@ func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (v
return volume.Volume{}, nil, err
}
var vol volume.Volume
resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return vol, nil, err
return volume.Volume{}, nil, err
}
body, err := io.ReadAll(resp.body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return vol, nil, err
return volume.Volume{}, nil, err
}
var vol volume.Volume
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&vol)
return vol, body, err

View File

@ -11,23 +11,23 @@ import (
// VolumeList returns the volumes configured in the docker host.
func (cli *Client) VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) {
var volumes volume.ListResponse
query := url.Values{}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
if err != nil {
return volumes, err
return volume.ListResponse{}, err
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/volumes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return volumes, err
return volume.ListResponse{}, err
}
err = json.NewDecoder(resp.body).Decode(&volumes)
var volumes volume.ListResponse
err = json.NewDecoder(resp.Body).Decode(&volumes)
return volumes, err
}

View File

@ -20,14 +20,14 @@ func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args)
return volume.PruneReport{}, err
}
serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
resp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return volume.PruneReport{}, err
}
var report volume.PruneReport
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return volume.PruneReport{}, fmt.Errorf("Error retrieving volume prune report: %v", err)
}

View File

@ -1,11 +1,11 @@
package archive
import (
"bytes"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"syscall"
"unsafe"
@ -143,7 +143,7 @@ func (w *walker) walk(path string, i1, i2 os.FileInfo) (err error) {
ni1 := names1[ix1]
ni2 := names2[ix2]
switch bytes.Compare([]byte(ni1.name), []byte(ni2.name)) {
switch strings.Compare(ni1.name, ni2.name) {
case -1: // ni1 < ni2 -- advance ni1
// we will not encounter ni1 in names2
names = append(names, ni1.name)

View File

@ -56,7 +56,6 @@ func (p *JSONProgress) String() string {
width = p.width()
pbBox string
numbersBox string
timeLeftBox string
)
if p.Current <= 0 && p.Total <= 0 {
return ""
@ -104,14 +103,14 @@ func (p *JSONProgress) String() string {
}
}
// Show approximation of remaining time if there's enough width.
var timeLeftBox string
if width > 50 {
if p.Current > 0 && p.Start > 0 && percentage < 50 {
fromStart := p.now().Sub(time.Unix(p.Start, 0))
perEntry := fromStart / time.Duration(p.Current)
left := time.Duration(p.Total-p.Current) * perEntry
left = (left / time.Second) * time.Second
if width > 50 {
timeLeftBox = " " + left.String()
timeLeftBox = " " + left.Round(time.Second).String()
}
}
return pbBox + numbersBox + timeLeftBox
@ -146,12 +145,20 @@ type JSONMessage struct {
Stream string `json:"stream,omitempty"`
Status string `json:"status,omitempty"`
Progress *JSONProgress `json:"progressDetail,omitempty"`
ProgressMessage string `json:"progress,omitempty"` // deprecated
// ProgressMessage is a pre-formatted presentation of [Progress].
//
// Deprecated: this field is deprecated since docker v0.7.1 / API v1.8. Use the information in [Progress] instead. This field will be omitted in a future release.
ProgressMessage string `json:"progress,omitempty"`
ID string `json:"id,omitempty"`
From string `json:"from,omitempty"`
Time int64 `json:"time,omitempty"`
TimeNano int64 `json:"timeNano,omitempty"`
Error *JSONError `json:"errorDetail,omitempty"`
// ErrorMessage contains errors encountered during the operation.
//
// Deprecated: this field is deprecated since docker v0.6.0 / API v1.4. Use [Error.Message] instead. This field will be omitted in a future release.
ErrorMessage string `json:"error,omitempty"` // deprecated
// Aux contains out-of-band data, such as digests for push signing and image id after building.
Aux *json.RawMessage `json:"aux,omitempty"`

3
vendor/modules.txt vendored
View File

@ -283,12 +283,13 @@ github.com/docker/distribution/registry/client/transport
github.com/docker/distribution/registry/storage/cache
github.com/docker/distribution/registry/storage/cache/memory
github.com/docker/distribution/uuid
# github.com/docker/docker v28.0.0-rc.1+incompatible
# github.com/docker/docker v28.0.0-rc.2+incompatible
## explicit
github.com/docker/docker/api
github.com/docker/docker/api/types
github.com/docker/docker/api/types/blkiodev
github.com/docker/docker/api/types/checkpoint
github.com/docker/docker/api/types/common
github.com/docker/docker/api/types/container
github.com/docker/docker/api/types/events
github.com/docker/docker/api/types/filters