Merge pull request #6680 from thaJeztah/bump_modules
vendor: github.com/moby/moby/client v0.2.1
This commit is contained in:
@ -120,8 +120,8 @@ func TestNewAPIClientFromFlagsWithCustomHeadersFromEnv(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
|
||||
const customVersion = "v3.3.3"
|
||||
const expectedVersion = "3.3.3"
|
||||
const customVersion = "v3.3"
|
||||
const expectedVersion = "3.3"
|
||||
t.Setenv("DOCKER_API_VERSION", customVersion)
|
||||
t.Setenv("DOCKER_HOST", ":2375")
|
||||
|
||||
|
||||
@ -134,7 +134,7 @@ func (ep *Endpoint) ClientOpts() ([]client.Opt, error) {
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, client.WithVersionFromEnv(), client.WithAPIVersionNegotiation())
|
||||
result = append(result, client.WithAPIVersionFromEnv())
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.19
|
||||
github.com/moby/go-archive v0.1.0
|
||||
github.com/moby/moby/api v1.52.0
|
||||
github.com/moby/moby/client v0.1.0
|
||||
github.com/moby/moby/client v0.2.1
|
||||
github.com/moby/patternmatcher v0.6.0
|
||||
github.com/moby/swarmkit/v2 v2.1.1
|
||||
github.com/moby/sys/atomicwriter v0.1.0
|
||||
|
||||
@ -115,8 +115,8 @@ github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ
|
||||
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
||||
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
|
||||
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
|
||||
github.com/moby/moby/client v0.1.0 h1:nt+hn6O9cyJQqq5UWnFGqsZRTS/JirUqzPjEl0Bdc/8=
|
||||
github.com/moby/moby/client v0.1.0/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
|
||||
github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k=
|
||||
github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/swarmkit/v2 v2.1.1 h1:yvTJ8MMCc3f0qTA44J6R59EZ5yZawdYopkpuLk4+ICU=
|
||||
|
||||
17
vendor/github.com/moby/moby/client/README.md
generated
vendored
17
vendor/github.com/moby/moby/client/README.md
generated
vendored
@ -23,19 +23,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
// Create a new client that handles common environment variables
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer apiClient.Close()
|
||||
|
||||
containers, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{All: true})
|
||||
// List all containers (both stopped and running).
|
||||
result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
|
||||
All: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, ctr := range containers {
|
||||
fmt.Printf("%s %s (status: %s)\n", ctr.ID, ctr.Image, ctr.Status)
|
||||
// Print each container's ID, status and the image it was created from.
|
||||
fmt.Printf("%s %-22s %s\n", "ID", "STATUS", "IMAGE")
|
||||
for _, ctr := range result.Items {
|
||||
fmt.Printf("%s %-22s %s\n", ctr.ID, ctr.Status, ctr.Image)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
82
vendor/github.com/moby/moby/client/client.go
generated
vendored
82
vendor/github.com/moby/moby/client/client.go
generated
vendored
@ -8,10 +8,8 @@ https://docs.docker.com/reference/api/engine/
|
||||
|
||||
You use the library by constructing a client object using [New]
|
||||
and calling methods on it. The client can be configured from environment
|
||||
variables by passing the [FromEnv] option, and the [WithAPIVersionNegotiation]
|
||||
option to allow downgrading the API version used when connecting with an older
|
||||
daemon version. Other options cen be configured manually by passing any of
|
||||
the available [Opt] options.
|
||||
variables by passing the [FromEnv] option. Other options can be configured
|
||||
manually by passing any of the available [Opt] options.
|
||||
|
||||
For example, to list running containers (the equivalent of "docker ps"):
|
||||
|
||||
@ -30,7 +28,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||
// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
|
||||
// API-version negotiation to allow downgrading the API version
|
||||
// when connecting with an older daemon version.
|
||||
apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
apiClient, err := client.New(client.FromEnv)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -103,18 +101,16 @@ import (
|
||||
const DummyHost = "api.moby.localhost"
|
||||
|
||||
// MaxAPIVersion is the highest REST API version supported by the client.
|
||||
// If API-version negotiation is enabled (see [WithAPIVersionNegotiation],
|
||||
// [Client.NegotiateAPIVersion]), the client may downgrade its API version.
|
||||
// Similarly, the [WithVersion] and [WithVersionFromEnv] allow overriding
|
||||
// the version.
|
||||
// If API-version negotiation is enabled, the client may downgrade its API version.
|
||||
// Similarly, the [WithAPIVersion] and [WithAPIVersionFromEnv] options allow
|
||||
// overriding the version and disable API-version negotiation.
|
||||
//
|
||||
// This version may be lower than the version of the api library module used.
|
||||
const MaxAPIVersion = "1.52"
|
||||
|
||||
// fallbackAPIVersion is the version to fall back to if API-version negotiation
|
||||
// fails. API versions below this version are not supported by the client,
|
||||
// and not considered when negotiating.
|
||||
const fallbackAPIVersion = "1.44"
|
||||
// MinAPIVersion is the minimum API version supported by the client. API versions
|
||||
// below this version are not considered when performing API-version negotiation.
|
||||
const MinAPIVersion = "1.44"
|
||||
|
||||
// Ensure that Client always implements APIClient.
|
||||
var _ APIClient = &Client{}
|
||||
@ -174,8 +170,13 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
|
||||
// It takes an optional list of [Opt] functional arguments, which are applied in
|
||||
// the order they're provided, which allows modifying the defaults when creating
|
||||
// the client. For example, the following initializes a client that configures
|
||||
// itself with values from environment variables ([FromEnv]), and has automatic
|
||||
// API version negotiation enabled ([WithAPIVersionNegotiation]).
|
||||
// itself with values from environment variables ([FromEnv]).
|
||||
//
|
||||
// By default, the client automatically negotiates the API version to use when
|
||||
// making requests. API version negotiation is performed on the first request;
|
||||
// subsequent requests do not re-negotiate. Use [WithAPIVersion] or
|
||||
// [WithAPIVersionFromEnv] to configure the client with a fixed API version
|
||||
// and disable API version negotiation.
|
||||
//
|
||||
// cli, err := client.New(
|
||||
// client.FromEnv,
|
||||
@ -213,6 +214,12 @@ func New(ops ...Opt) (*Client, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.envAPIVersion != "" {
|
||||
c.setAPIVersion(cfg.envAPIVersion)
|
||||
} else if cfg.manualAPIVersion != "" {
|
||||
c.setAPIVersion(cfg.manualAPIVersion)
|
||||
}
|
||||
|
||||
if tr, ok := c.client.Transport.(*http.Transport); ok {
|
||||
// Store the base transport before we wrap it in tracing libs below
|
||||
// This is used, as an example, to close idle connections when the client is closed
|
||||
@ -278,7 +285,7 @@ func (cli *Client) Close() error {
|
||||
// be negotiated when making the actual requests, and for which cases
|
||||
// we cannot do the negotiation lazily.
|
||||
func (cli *Client) checkVersion(ctx context.Context) error {
|
||||
if cli.manualOverride || !cli.negotiateVersion || cli.negotiated.Load() {
|
||||
if cli.negotiated.Load() {
|
||||
return nil
|
||||
}
|
||||
_, err := cli.Ping(ctx, PingOptions{
|
||||
@ -306,36 +313,47 @@ func (cli *Client) ClientVersion() string {
|
||||
}
|
||||
|
||||
// negotiateAPIVersion updates the version to match the API version from
|
||||
// the ping response. It falls back to the lowest version supported if the
|
||||
// API version is empty, or returns an error if the API version is lower than
|
||||
// the lowest supported API version, in which case the version is not modified.
|
||||
// the ping response.
|
||||
//
|
||||
// It returns an error if version is invalid, or lower than the minimum
|
||||
// supported API version in which case the client's API version is not
|
||||
// updated, and negotiation is not marked as completed.
|
||||
func (cli *Client) negotiateAPIVersion(pingVersion string) error {
|
||||
pingVersion = strings.TrimPrefix(pingVersion, "v")
|
||||
if pingVersion == "" {
|
||||
// TODO(thaJeztah): consider returning an error on empty value or not falling back; see https://github.com/moby/moby/pull/51119#discussion_r2413148487
|
||||
pingVersion = fallbackAPIVersion
|
||||
} else if versions.LessThan(pingVersion, fallbackAPIVersion) {
|
||||
return cerrdefs.ErrInvalidArgument.WithMessage(fmt.Sprintf("API version %s is not supported by this client: the minimum supported API version is %s", pingVersion, fallbackAPIVersion))
|
||||
var err error
|
||||
pingVersion, err = parseAPIVersion(pingVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if versions.LessThan(pingVersion, MinAPIVersion) {
|
||||
return cerrdefs.ErrInvalidArgument.WithMessage(fmt.Sprintf("API version %s is not supported by this client: the minimum supported API version is %s", pingVersion, MinAPIVersion))
|
||||
}
|
||||
|
||||
// if the client is not initialized with a version, start with the latest supported version
|
||||
if cli.version == "" {
|
||||
cli.version = MaxAPIVersion
|
||||
negotiatedVersion := cli.version
|
||||
if negotiatedVersion == "" {
|
||||
negotiatedVersion = MaxAPIVersion
|
||||
}
|
||||
|
||||
// if server version is lower than the client version, downgrade
|
||||
if versions.LessThan(pingVersion, cli.version) {
|
||||
cli.version = pingVersion
|
||||
if versions.LessThan(pingVersion, negotiatedVersion) {
|
||||
negotiatedVersion = pingVersion
|
||||
}
|
||||
|
||||
// Store the results, so that automatic API version negotiation (if enabled)
|
||||
// won't be performed on the next request.
|
||||
if cli.negotiateVersion {
|
||||
cli.negotiated.Store(true)
|
||||
}
|
||||
cli.setAPIVersion(negotiatedVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
// setAPIVersion sets the client's API version and marks API version negotiation
|
||||
// as completed, so that automatic API version negotiation (if enabled) won't
|
||||
// be performed on the next request.
|
||||
func (cli *Client) setAPIVersion(version string) {
|
||||
cli.version = version
|
||||
cli.negotiated.Store(true)
|
||||
}
|
||||
|
||||
// DaemonHost returns the host address used by the client
|
||||
func (cli *Client) DaemonHost() string {
|
||||
return cli.host
|
||||
|
||||
@ -38,14 +38,22 @@ type clientConfig struct {
|
||||
userAgent *string
|
||||
// custom HTTP headers configured by users.
|
||||
customHTTPHeaders map[string]string
|
||||
// manualOverride is set to true when the version was set by users.
|
||||
manualOverride bool
|
||||
|
||||
// negotiateVersion indicates if the client should automatically negotiate
|
||||
// the API version to use when making requests. API version negotiation is
|
||||
// performed on the first request, after which negotiated is set to "true"
|
||||
// so that subsequent requests do not re-negotiate.
|
||||
negotiateVersion bool
|
||||
// manualAPIVersion contains the API version set by users. This field
|
||||
// will only be non-empty if a valid-formed version was set through
|
||||
// [WithAPIVersion].
|
||||
//
|
||||
// If both manualAPIVersion and envAPIVersion are set, manualAPIVersion
|
||||
// takes precedence. Either field disables API-version negotiation.
|
||||
manualAPIVersion string
|
||||
|
||||
// envAPIVersion contains the API version set by users. This field
|
||||
// will only be non-empty if a valid-formed version was set through
|
||||
// [WithAPIVersionFromEnv].
|
||||
//
|
||||
// If both manualAPIVersion and envAPIVersion are set, manualAPIVersion
|
||||
// takes precedence. Either field disables API-version negotiation.
|
||||
envAPIVersion string
|
||||
|
||||
// traceOpts is a list of options to configure the tracing span.
|
||||
traceOpts []otelhttp.Option
|
||||
@ -56,7 +64,7 @@ type Opt func(*clientConfig) error
|
||||
|
||||
// FromEnv configures the client with values from environment variables. It
|
||||
// is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv],
|
||||
// and [WithVersionFromEnv] options.
|
||||
// and [WithAPIVersionFromEnv] options.
|
||||
//
|
||||
// FromEnv uses the following environment variables:
|
||||
//
|
||||
@ -71,7 +79,7 @@ func FromEnv(c *clientConfig) error {
|
||||
ops := []Opt{
|
||||
WithTLSClientConfigFromEnv(),
|
||||
WithHostFromEnv(),
|
||||
WithVersionFromEnv(),
|
||||
WithAPIVersionFromEnv(),
|
||||
}
|
||||
for _, op := range ops {
|
||||
if err := op(c); err != nil {
|
||||
@ -241,18 +249,59 @@ func WithTLSClientConfigFromEnv() Opt {
|
||||
}
|
||||
}
|
||||
|
||||
// WithVersion overrides the client version with the specified one. If an empty
|
||||
// version is provided, the value is ignored to allow version negotiation
|
||||
// (see [WithAPIVersionNegotiation]).
|
||||
// WithAPIVersion overrides the client's API version with the specified one,
|
||||
// and disables API version negotiation. If an empty version is provided,
|
||||
// this option is ignored to allow version negotiation. The given version
|
||||
// should be formatted "<major>.<minor>" (for example, "1.52"). It returns
|
||||
// an error if the given value not in the correct format.
|
||||
//
|
||||
// WithVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version is in the correct format and
|
||||
// lower than the maximum supported version as defined by [MaxAPIVersion].
|
||||
func WithVersion(version string) Opt {
|
||||
// WithAPIVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version lower than the maximum supported
|
||||
// version as defined by [MaxAPIVersion].
|
||||
//
|
||||
// [WithAPIVersionFromEnv] takes precedence if [WithAPIVersion] and
|
||||
// [WithAPIVersionFromEnv] are both set.
|
||||
func WithAPIVersion(version string) Opt {
|
||||
return func(c *clientConfig) error {
|
||||
if v := strings.TrimPrefix(version, "v"); v != "" {
|
||||
c.version = v
|
||||
c.manualOverride = true
|
||||
version = strings.TrimSpace(version)
|
||||
if val := strings.TrimPrefix(version, "v"); val != "" {
|
||||
ver, err := parseAPIVersion(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid API version (%s): %w", version, err)
|
||||
}
|
||||
c.manualAPIVersion = ver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithVersion overrides the client version with the specified one.
|
||||
//
|
||||
// Deprecated: use [WithAPIVersion] instead.
|
||||
func WithVersion(version string) Opt {
|
||||
return WithAPIVersion(version)
|
||||
}
|
||||
|
||||
// WithAPIVersionFromEnv overrides the client version with the version specified in
|
||||
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
|
||||
// If DOCKER_API_VERSION is not set, or set to an empty value, the version
|
||||
// is not modified.
|
||||
//
|
||||
// WithAPIVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version lower than the maximum supported
|
||||
// version as defined by [MaxAPIVersion].
|
||||
//
|
||||
// [WithAPIVersionFromEnv] takes precedence if [WithAPIVersion] and
|
||||
// [WithAPIVersionFromEnv] are both set.
|
||||
func WithAPIVersionFromEnv() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
version := strings.TrimSpace(os.Getenv(EnvOverrideAPIVersion))
|
||||
if val := strings.TrimPrefix(version, "v"); val != "" {
|
||||
ver, err := parseAPIVersion(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid API version (%s): %w", version, err)
|
||||
}
|
||||
c.envAPIVersion = ver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -260,25 +309,21 @@ func WithVersion(version string) Opt {
|
||||
|
||||
// WithVersionFromEnv overrides the client version with the version specified in
|
||||
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
|
||||
// If DOCKER_API_VERSION is not set, or set to an empty value, the version
|
||||
// is not modified.
|
||||
//
|
||||
// WithVersion does not validate if the client supports the given version,
|
||||
// and callers should verify if the version is in the correct format and
|
||||
// lower than the maximum supported version as defined by [MaxAPIVersion].
|
||||
// Deprecated: use [WithAPIVersionFromEnv] instead.
|
||||
func WithVersionFromEnv() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c)
|
||||
}
|
||||
return WithAPIVersionFromEnv()
|
||||
}
|
||||
|
||||
// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
|
||||
// With this option enabled, the client automatically negotiates the API version
|
||||
// to use when making requests. API version negotiation is performed on the first
|
||||
// request; subsequent requests do not re-negotiate.
|
||||
//
|
||||
// Deprecated: API-version negotiation is now enabled by default. Use [WithAPIVersion]
|
||||
// or [WithAPIVersionFromEnv] to disable API version negotiation.
|
||||
func WithAPIVersionNegotiation() Opt {
|
||||
return func(c *clientConfig) error {
|
||||
c.negotiateVersion = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/moby/moby/client/envvars.go
generated
vendored
2
vendor/github.com/moby/moby/client/envvars.go
generated
vendored
@ -13,7 +13,7 @@ const (
|
||||
// be used to override the API version to use. Value must be
|
||||
// formatted as MAJOR.MINOR, for example, "1.19".
|
||||
//
|
||||
// This env-var is read by [FromEnv] and [WithVersionFromEnv] and when set to a
|
||||
// This env-var is read by [FromEnv] and [WithAPIVersionFromEnv] and when set to a
|
||||
// non-empty value, takes precedence over API version negotiation.
|
||||
//
|
||||
// This environment variable should be used for debugging purposes only, as
|
||||
|
||||
33
vendor/github.com/moby/moby/client/ping.go
generated
vendored
33
vendor/github.com/moby/moby/client/ping.go
generated
vendored
@ -20,7 +20,7 @@ type PingOptions struct {
|
||||
//
|
||||
// If a manual override is in place, either through the "DOCKER_API_VERSION"
|
||||
// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
|
||||
// with a fixed version ([WithVersion]), no negotiation is performed.
|
||||
// with a fixed version ([WithAPIVersion]), no negotiation is performed.
|
||||
//
|
||||
// If the API server's ping response does not contain an API version, or if the
|
||||
// client did not get a successful ping response, it assumes it is connected with
|
||||
@ -29,9 +29,8 @@ type PingOptions struct {
|
||||
NegotiateAPIVersion bool
|
||||
|
||||
// ForceNegotiate forces the client to re-negotiate the API version, even if
|
||||
// API-version negotiation already happened. This option cannot be
|
||||
// used if the client is configured with a fixed version using (using
|
||||
// [WithVersion] or [WithVersionFromEnv]).
|
||||
// API-version negotiation already happened or it the client is configured
|
||||
// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
|
||||
//
|
||||
// This option has no effect if NegotiateAPIVersion is not set.
|
||||
ForceNegotiate bool
|
||||
@ -72,10 +71,12 @@ type SwarmStatus struct {
|
||||
// for other non-success status codes, failing to connect to the API, or failing
|
||||
// to parse the API response.
|
||||
func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
|
||||
if cli.manualOverride {
|
||||
if !options.NegotiateAPIVersion {
|
||||
// No API version negotiation needed; just return ping response.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
if !options.NegotiateAPIVersion && !cli.negotiateVersion {
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
return cli.ping(ctx)
|
||||
}
|
||||
|
||||
@ -85,10 +86,19 @@ func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, e
|
||||
|
||||
ping, err := cli.ping(ctx)
|
||||
if err != nil {
|
||||
return cli.ping(ctx)
|
||||
return ping, err
|
||||
}
|
||||
|
||||
if cli.negotiated.Load() && !options.ForceNegotiate {
|
||||
// API version was already negotiated or manually set.
|
||||
//
|
||||
// We check cli.negotiated again under lock, to account for race
|
||||
// conditions with the check at the start of this function.
|
||||
return ping, nil
|
||||
}
|
||||
|
||||
if ping.APIVersion == "" {
|
||||
cli.setAPIVersion(MaxAPIVersion)
|
||||
return ping, nil
|
||||
}
|
||||
|
||||
@ -112,10 +122,15 @@ func (cli *Client) ping(ctx context.Context) (PingResult, error) {
|
||||
// response-body to get error details from.
|
||||
return newPingResult(resp), nil
|
||||
}
|
||||
// close to allow reusing connection.
|
||||
ensureReaderClosed(resp)
|
||||
|
||||
// HEAD failed or returned a non-OK status; fallback to GET.
|
||||
req.Method = http.MethodGet
|
||||
resp, err = cli.doRequest(req)
|
||||
req2, err := cli.buildRequest(ctx, http.MethodGet, path.Join(cli.basePath, "/_ping"), nil, nil)
|
||||
if err != nil {
|
||||
return PingResult{}, err
|
||||
}
|
||||
resp, err = cli.doRequest(req2)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
// Failed to connect.
|
||||
|
||||
84
vendor/github.com/moby/moby/client/request.go
generated
vendored
84
vendor/github.com/moby/moby/client/request.go
generated
vendored
@ -67,31 +67,22 @@ func (cli *Client) delete(ctx context.Context, path string, query url.Values, he
|
||||
// prepareJSONRequest encodes the given body to JSON and returns it as an [io.Reader], and sets the Content-Type
|
||||
// header. If body is nil, or a nil-interface, a "nil" body is returned without
|
||||
// error.
|
||||
//
|
||||
// TODO(thaJeztah): should this return an error if a different Content-Type is already set?
|
||||
// TODO(thaJeztah): is "nil" the appropriate approach for an empty body, or should we use [http.NoBody] (or similar)?
|
||||
func prepareJSONRequest(body any, headers http.Header) (io.Reader, http.Header, error) {
|
||||
if body == nil {
|
||||
return nil, headers, nil
|
||||
}
|
||||
// encoding/json encodes a nil pointer as the JSON document `null`,
|
||||
// irrespective of whether the type implements json.Marshaler or encoding.TextMarshaler.
|
||||
// That is almost certainly not what the caller intended as the request body.
|
||||
//
|
||||
// TODO(thaJeztah): consider moving this to jsonEncode, which would also allow returning an (empty) reader instead of nil.
|
||||
if reflect.TypeOf(body).Kind() == reflect.Ptr && reflect.ValueOf(body).IsNil() {
|
||||
return nil, headers, nil
|
||||
}
|
||||
|
||||
jsonBody, err := jsonEncode(body)
|
||||
if err != nil {
|
||||
return nil, headers, err
|
||||
}
|
||||
if jsonBody == nil || jsonBody == http.NoBody {
|
||||
// no content-type is set on empty requests.
|
||||
return jsonBody, headers, nil
|
||||
}
|
||||
|
||||
hdr := http.Header{}
|
||||
if headers != nil {
|
||||
hdr = headers.Clone()
|
||||
}
|
||||
|
||||
// TODO(thaJeztah): should this return an error if a different Content-Type is already set?
|
||||
hdr.Set("Content-Type", "application/json")
|
||||
return jsonBody, hdr, nil
|
||||
}
|
||||
@ -110,9 +101,6 @@ func (cli *Client) buildRequest(ctx context.Context, method, path string, body i
|
||||
req.Host = DummyHost
|
||||
}
|
||||
|
||||
if body != nil && req.Header.Get("Content-Type") == "" {
|
||||
req.Header.Set("Content-Type", "text/plain")
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
@ -248,7 +236,11 @@ func checkResponseErr(serverResp *http.Response) (retErr error) {
|
||||
if statusMsg == "" {
|
||||
statusMsg = http.StatusText(serverResp.StatusCode)
|
||||
}
|
||||
if serverResp.Body != nil {
|
||||
var reqMethod string
|
||||
if serverResp.Request != nil {
|
||||
reqMethod = serverResp.Request.Method
|
||||
}
|
||||
if serverResp.Body != nil && reqMethod != http.MethodHead {
|
||||
bodyMax := 1 * 1024 * 1024 // 1 MiB
|
||||
bodyR := &io.LimitedReader{
|
||||
R: serverResp.Body,
|
||||
@ -333,25 +325,49 @@ func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Requ
|
||||
}
|
||||
|
||||
func jsonEncode(data any) (io.Reader, error) {
|
||||
var params bytes.Buffer
|
||||
if data != nil {
|
||||
if err := json.NewEncoder(¶ms).Encode(data); err != nil {
|
||||
return nil, err
|
||||
switch x := data.(type) {
|
||||
case nil:
|
||||
return http.NoBody, nil
|
||||
case io.Reader:
|
||||
// http.NoBody or other readers
|
||||
return x, nil
|
||||
case json.RawMessage:
|
||||
if len(x) == 0 {
|
||||
return http.NoBody, nil
|
||||
}
|
||||
return bytes.NewReader(x), nil
|
||||
}
|
||||
return ¶ms, nil
|
||||
|
||||
// encoding/json encodes a nil pointer as the JSON document `null`,
|
||||
// irrespective of whether the type implements json.Marshaler or encoding.TextMarshaler.
|
||||
// That is almost certainly not what the caller intended as the request body.
|
||||
if v := reflect.ValueOf(data); v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return http.NoBody, nil
|
||||
}
|
||||
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.NewReader(b), 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
|
||||
// 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()
|
||||
if response == nil || response.Body == nil {
|
||||
return
|
||||
}
|
||||
if response.ContentLength == 0 || (response.Request != nil && response.Request.Method == http.MethodHead) {
|
||||
// No need to drain head requests or zero-length responses.
|
||||
_ = response.Body.Close()
|
||||
return
|
||||
}
|
||||
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
|
||||
// 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()
|
||||
}
|
||||
|
||||
56
vendor/github.com/moby/moby/client/service_create.go
generated
vendored
56
vendor/github.com/moby/moby/client/service_create.go
generated
vendored
@ -59,16 +59,18 @@ func (cli *Client) ServiceCreate(ctx context.Context, options ServiceCreateOptio
|
||||
options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
case options.Spec.TaskTemplate.PluginSpec != nil:
|
||||
if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
|
||||
options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,35 +95,33 @@ func (cli *Client) ServiceCreate(ctx context.Context, options ServiceCreateOptio
|
||||
}
|
||||
|
||||
func resolveContainerSpecImage(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string {
|
||||
var warning string
|
||||
if img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.ContainerSpec.Image, encodedAuth); err != nil {
|
||||
warning = digestWarning(taskSpec.ContainerSpec.Image)
|
||||
} else {
|
||||
taskSpec.ContainerSpec.Image = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.ContainerSpec.Image, encodedAuth)
|
||||
if err != nil {
|
||||
return digestWarning(taskSpec.ContainerSpec.Image)
|
||||
}
|
||||
return warning
|
||||
taskSpec.ContainerSpec.Image = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func resolvePluginSpecRemote(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string {
|
||||
var warning string
|
||||
if img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.PluginSpec.Remote, encodedAuth); err != nil {
|
||||
warning = digestWarning(taskSpec.PluginSpec.Remote)
|
||||
} else {
|
||||
taskSpec.PluginSpec.Remote = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.PluginSpec.Remote, encodedAuth)
|
||||
if err != nil {
|
||||
return digestWarning(taskSpec.PluginSpec.Remote)
|
||||
}
|
||||
return warning
|
||||
taskSpec.PluginSpec.Remote = img
|
||||
if len(imgPlatforms) > 0 {
|
||||
if taskSpec.Placement == nil {
|
||||
taskSpec.Placement = &swarm.Placement{}
|
||||
}
|
||||
taskSpec.Placement.Platforms = imgPlatforms
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) {
|
||||
|
||||
10
vendor/github.com/moby/moby/client/service_update.go
generated
vendored
10
vendor/github.com/moby/moby/client/service_update.go
generated
vendored
@ -82,16 +82,18 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, options
|
||||
options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
case options.Spec.TaskTemplate.PluginSpec != nil:
|
||||
if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
|
||||
options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg
|
||||
}
|
||||
if options.QueryRegistry {
|
||||
resolveWarning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth)
|
||||
warnings = append(warnings, resolveWarning)
|
||||
if warning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
42
vendor/github.com/moby/moby/client/utils.go
generated
vendored
42
vendor/github.com/moby/moby/client/utils.go
generated
vendored
@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -32,6 +33,47 @@ func trimID(objType, id string) (string, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// parseAPIVersion checks v to be a well-formed ("<major>.<minor>")
|
||||
// API version. It returns an error if the value is empty or does not
|
||||
// have the correct format, but does not validate if the API version is
|
||||
// within the supported range ([MinAPIVersion] <= v <= [MaxAPIVersion]).
|
||||
//
|
||||
// It returns version after normalizing, or an error if validation failed.
|
||||
func parseAPIVersion(version string) (string, error) {
|
||||
if strings.TrimPrefix(strings.TrimSpace(version), "v") == "" {
|
||||
return "", cerrdefs.ErrInvalidArgument.WithMessage("value is empty")
|
||||
}
|
||||
major, minor, err := parseMajorMinor(version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%d.%d", major, minor), nil
|
||||
}
|
||||
|
||||
// parseMajorMinor is a helper for parseAPIVersion.
|
||||
func parseMajorMinor(v string) (major, minor int, _ error) {
|
||||
if strings.HasPrefix(v, "v") {
|
||||
return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("must be formatted <major>.<minor>")
|
||||
}
|
||||
if strings.TrimSpace(v) == "" {
|
||||
return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("value is empty")
|
||||
}
|
||||
|
||||
majVer, minVer, ok := strings.Cut(v, ".")
|
||||
if !ok {
|
||||
return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("must be formatted <major>.<minor>")
|
||||
}
|
||||
major, err := strconv.Atoi(majVer)
|
||||
if err != nil {
|
||||
return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("invalid major version: must be formatted <major>.<minor>")
|
||||
}
|
||||
minor, err = strconv.Atoi(minVer)
|
||||
if err != nil {
|
||||
return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("invalid minor version: must be formatted <major>.<minor>")
|
||||
}
|
||||
return major, minor, nil
|
||||
}
|
||||
|
||||
// encodePlatforms marshals the given platform(s) to JSON format, to
|
||||
// be used for query-parameters for filtering / selecting platforms.
|
||||
func encodePlatforms(platform ...ocispec.Platform) ([]string, error) {
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -189,7 +189,7 @@ github.com/moby/moby/api/types/storage
|
||||
github.com/moby/moby/api/types/swarm
|
||||
github.com/moby/moby/api/types/system
|
||||
github.com/moby/moby/api/types/volume
|
||||
# github.com/moby/moby/client v0.1.0
|
||||
# github.com/moby/moby/client v0.2.1
|
||||
## explicit; go 1.24.0
|
||||
github.com/moby/moby/client
|
||||
github.com/moby/moby/client/internal
|
||||
|
||||
Reference in New Issue
Block a user