Skip to content

Commit e690724

Browse files
committed
client: negotiate api version before handling version-specific code
We try to perform API-version negotiation as lazy as possible (and only execute when we are about to make an API request). However, some code requires API-version dependent handling (to set options, or remove options based on the version of the API we're using). Currently this code depended on the caller code to perform API negotiation (or to configure the API version) first, which may not happen, and because of that we may be missing options (or set options that are not supported on older API versions). This patch: - splits the code that triggered API-version negotiation to a separate Client.checkVersion() function. - updates NewVersionError to accept a context - updates NewVersionError to perform API-version negotiation (if enabled) - updates various Client functions to manually trigger API-version negotiation Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent 7cfb81b commit e690724

31 files changed

Lines changed: 126 additions & 38 deletions

client/build_prune.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313

1414
// BuildCachePrune requests the daemon to delete unused cache data
1515
func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
16-
if err := cli.NewVersionError("1.31", "build prune"); err != nil {
16+
if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
1717
return nil, err
1818
}
1919

client/client.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,21 @@ func (cli *Client) Close() error {
254254
return nil
255255
}
256256

257+
// checkVersion manually triggers API version negotiation (if configured).
258+
// This allows for version-dependent code to use the same version as will
259+
// be negotiated when making the actual requests, and for which cases
260+
// we cannot do the negotiation lazily.
261+
func (cli *Client) checkVersion(ctx context.Context) {
262+
if cli.negotiateVersion && !cli.negotiated {
263+
cli.NegotiateAPIVersion(ctx)
264+
}
265+
}
266+
257267
// getAPIPath returns the versioned request path to call the API.
258268
// It appends the query parameters to the path if they are not empty.
259269
func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
260270
var apiPath string
261-
if cli.negotiateVersion && !cli.negotiated {
262-
cli.NegotiateAPIVersion(ctx)
263-
}
271+
cli.checkVersion(ctx)
264272
if cli.version != "" {
265273
v := strings.TrimPrefix(cli.version, "v")
266274
apiPath = path.Join(cli.basePath, "/v"+v, p)

client/config_create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
// ConfigCreate creates a new config.
1212
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
1313
var response types.ConfigCreateResponse
14-
if err := cli.NewVersionError("1.30", "config create"); err != nil {
14+
if err := cli.NewVersionError(ctx, "1.30", "config create"); err != nil {
1515
return response, err
1616
}
1717
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)

client/config_inspect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
1414
if id == "" {
1515
return swarm.Config{}, nil, objectNotFoundError{object: "config", id: id}
1616
}
17-
if err := cli.NewVersionError("1.30", "config inspect"); err != nil {
17+
if err := cli.NewVersionError(ctx, "1.30", "config inspect"); err != nil {
1818
return swarm.Config{}, nil, err
1919
}
2020
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)

client/config_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
// ConfigList returns the list of configs.
1414
func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
15-
if err := cli.NewVersionError("1.30", "config list"); err != nil {
15+
if err := cli.NewVersionError(ctx, "1.30", "config list"); err != nil {
1616
return nil, err
1717
}
1818
query := url.Values{}

client/config_remove.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "context"
44

55
// ConfigRemove removes a config.
66
func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
7-
if err := cli.NewVersionError("1.30", "config remove"); err != nil {
7+
if err := cli.NewVersionError(ctx, "1.30", "config remove"); err != nil {
88
return err
99
}
1010
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)

client/config_update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
// ConfigUpdate attempts to update a config
1111
func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error {
12-
if err := cli.NewVersionError("1.30", "config update"); err != nil {
12+
if err := cli.NewVersionError(ctx, "1.30", "config update"); err != nil {
1313
return err
1414
}
1515
query := url.Values{}

client/container_create.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ type configWrapper struct {
2323
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error) {
2424
var response container.CreateResponse
2525

26-
if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
26+
// Make sure we negotiated (if the client is configured to do so),
27+
// as code below contains API-version specific handling of options.
28+
//
29+
// Normally, version-negotiation (if enabled) would not happen until
30+
// the API request is made.
31+
cli.checkVersion(ctx)
32+
33+
if err := cli.NewVersionError(ctx, "1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
2734
return response, err
2835
}
29-
if err := cli.NewVersionError("1.41", "specify container image platform"); platform != nil && err != nil {
36+
if err := cli.NewVersionError(ctx, "1.41", "specify container image platform"); platform != nil && err != nil {
3037
return response, err
3138
}
32-
if err := cli.NewVersionError("1.44", "specify health-check start interval"); config != nil && config.Healthcheck != nil && config.Healthcheck.StartInterval != 0 && err != nil {
39+
if err := cli.NewVersionError(ctx, "1.44", "specify health-check start interval"); config != nil && config.Healthcheck != nil && config.Healthcheck.StartInterval != 0 && err != nil {
3340
return response, err
3441
}
3542

client/container_exec.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ import (
1313
func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) {
1414
var response types.IDResponse
1515

16-
if err := cli.NewVersionError("1.25", "env"); len(config.Env) != 0 && err != nil {
16+
// Make sure we negotiated (if the client is configured to do so),
17+
// as code below contains API-version specific handling of options.
18+
//
19+
// Normally, version-negotiation (if enabled) would not happen until
20+
// the API request is made.
21+
cli.checkVersion(ctx)
22+
23+
if err := cli.NewVersionError(ctx, "1.25", "env"); len(config.Env) != 0 && err != nil {
1724
return response, err
1825
}
1926
if versions.LessThan(cli.ClientVersion(), "1.42") {

client/container_prune.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) {
1414
var report types.ContainersPruneReport
1515

16-
if err := cli.NewVersionError("1.25", "container prune"); err != nil {
16+
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
1717
return report, err
1818
}
1919

0 commit comments

Comments
 (0)