client: remove support for API < v1.22 filter format

The format for filters changed in 93d1dd8036
(docker v1.10 / API v1.22). As part of that implementation, the daemon
would parse the new format, and fall back to parsing the old format if
this failed. This fallback was not based on API version, so any version
of the API released since would continue to accept both the legacy and
curent format.

For the client, the change in format caused a regression when connecting
to an older daemon; a `ToParamWithVersion` utility was introduced in
[docker/engine-api@81388f0] to produce the old format when the client was
connected to a docker v1.9 or older daemon, using an old API version.

Given that any version of docker 1.10 or above would support both formats,
regardless of the API version used, and API v1.22 is no longer supported,
it should be safe to assume we can drop the version-specific format in the
client. Even if the client would be using API v1.22 (or older), the format
would only be necessary for an actual docker v1.9 daemon, which would be
very unlikely, and a daemon that's 9 Years old.

[docker/engine-api@81388f0]: 81388f00dd

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-09-15 21:27:58 +02:00
parent 689decba9a
commit 839e46f97c
15 changed files with 4 additions and 236 deletions

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
)
// ContainerListOptions holds parameters to list containers with.
@@ -47,27 +46,10 @@ func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptio
}
if options.Filters.Len() > 0 {
// 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 nil, err
}
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}

View File

@@ -43,13 +43,6 @@ func (cli *Client) ImageList(ctx context.Context, options ImageListOptions) ([]i
if err != nil {
return images, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
if options.All {

View File

@@ -7,7 +7,6 @@ import (
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/versions"
)
// NetworkList returns the list of networks configured in the docker host.
@@ -18,14 +17,6 @@ func (cli *Client) NetworkList(ctx context.Context, options NetworkListOptions)
if err != nil {
return nil, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
var networkResources []network.Summary

View File

@@ -7,7 +7,6 @@ import (
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/versions"
)
// PluginList returns the installed plugins
@@ -20,13 +19,6 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (plugin.
if err != nil {
return plugins, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return plugins, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/plugins", query, nil)

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/client/internal/timestamp"
)
@@ -31,17 +30,7 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha
go func() {
defer close(errs)
// 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 {
close(started)
errs <- err
return
}
query, err := buildEventsQueryParams(cli.version, options)
query, err := buildEventsQueryParams(options)
if err != nil {
close(started)
errs <- err
@@ -85,7 +74,7 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha
return messages, errs
}
func buildEventsQueryParams(cliVersion string, options EventsListOptions) (url.Values, error) {
func buildEventsQueryParams(options EventsListOptions) (url.Values, error) {
query := url.Values{}
ref := time.Now()
@@ -110,13 +99,6 @@ func buildEventsQueryParams(cliVersion string, options EventsListOptions) (url.V
if err != nil {
return nil, err
}
if cliVersion != "" && versions.LessThan(cliVersion, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}

View File

@@ -81,41 +81,3 @@ func encodePlatform(platform *ocispec.Platform) (string, error) {
}
return string(p), nil
}
// encodeLegacyFilters encodes Args in the legacy format as used in API v1.21 and older.
// where values are a list of strings, instead of a set.
//
// Don't use in any new code; use [filters.ToJSON]] instead.
func encodeLegacyFilters(currentFormat string) (string, error) {
// The Args.fields field is not exported, but used to marshal JSON,
// so we'll marshal to the new format, then unmarshal to get the
// fields, and marshal again.
//
// This is far from optimal, but this code is only used for deprecated
// API versions, so should not be hit commonly.
var argsFields map[string]map[string]bool
err := json.Unmarshal([]byte(currentFormat), &argsFields)
if err != nil {
return "", err
}
buf, err := json.Marshal(convertArgsToSlice(argsFields))
if err != nil {
return "", err
}
return string(buf), nil
}
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
m := map[string][]string{}
for k, v := range f {
values := []string{}
for kk := range v {
if v[kk] {
values = append(values, kk)
}
}
m[k] = values
}
return m
}

View File

@@ -3,7 +3,6 @@ package client
import (
"testing"
"github.com/moby/moby/api/types/filters"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -56,22 +55,3 @@ func TestEncodePlatforms(t *testing.T) {
})
}
}
func TestEncodeLegacyFilters(t *testing.T) {
a := filters.NewArgs(
filters.Arg("created", "today"),
filters.Arg("image.name", "ubuntu*"),
filters.Arg("image.name", "*untu"),
)
currentFormat, err := filters.ToJSON(a)
assert.NilError(t, err)
// encode in the API v1.21 (and older) format
str1, err := encodeLegacyFilters(currentFormat)
assert.Check(t, err)
if str1 != `{"created":["today"],"image.name":["*untu","ubuntu*"]}` &&
str1 != `{"created":["today"],"image.name":["ubuntu*","*untu"]}` {
t.Errorf("incorrectly marshaled the filters: %s", str1)
}
}

View File

@@ -6,7 +6,6 @@ import (
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/api/types/volume"
)
@@ -19,13 +18,6 @@ func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (v
if err != nil {
return volume.ListResponse{}, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return volume.ListResponse{}, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/volumes", query, nil)

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
)
// ContainerListOptions holds parameters to list containers with.
@@ -47,27 +46,10 @@ func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptio
}
if options.Filters.Len() > 0 {
// 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 nil, err
}
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}

View File

@@ -43,13 +43,6 @@ func (cli *Client) ImageList(ctx context.Context, options ImageListOptions) ([]i
if err != nil {
return images, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
if options.All {

View File

@@ -7,7 +7,6 @@ import (
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/versions"
)
// NetworkList returns the list of networks configured in the docker host.
@@ -18,14 +17,6 @@ func (cli *Client) NetworkList(ctx context.Context, options NetworkListOptions)
if err != nil {
return nil, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
var networkResources []network.Summary

View File

@@ -7,7 +7,6 @@ import (
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/versions"
)
// PluginList returns the installed plugins
@@ -20,13 +19,6 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (plugin.
if err != nil {
return plugins, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return plugins, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/plugins", query, nil)

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/client/internal/timestamp"
)
@@ -31,17 +30,7 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha
go func() {
defer close(errs)
// 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 {
close(started)
errs <- err
return
}
query, err := buildEventsQueryParams(cli.version, options)
query, err := buildEventsQueryParams(options)
if err != nil {
close(started)
errs <- err
@@ -85,7 +74,7 @@ func (cli *Client) Events(ctx context.Context, options EventsListOptions) (<-cha
return messages, errs
}
func buildEventsQueryParams(cliVersion string, options EventsListOptions) (url.Values, error) {
func buildEventsQueryParams(options EventsListOptions) (url.Values, error) {
query := url.Values{}
ref := time.Now()
@@ -110,13 +99,6 @@ func buildEventsQueryParams(cliVersion string, options EventsListOptions) (url.V
if err != nil {
return nil, err
}
if cliVersion != "" && versions.LessThan(cliVersion, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return nil, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}

View File

@@ -81,41 +81,3 @@ func encodePlatform(platform *ocispec.Platform) (string, error) {
}
return string(p), nil
}
// encodeLegacyFilters encodes Args in the legacy format as used in API v1.21 and older.
// where values are a list of strings, instead of a set.
//
// Don't use in any new code; use [filters.ToJSON]] instead.
func encodeLegacyFilters(currentFormat string) (string, error) {
// The Args.fields field is not exported, but used to marshal JSON,
// so we'll marshal to the new format, then unmarshal to get the
// fields, and marshal again.
//
// This is far from optimal, but this code is only used for deprecated
// API versions, so should not be hit commonly.
var argsFields map[string]map[string]bool
err := json.Unmarshal([]byte(currentFormat), &argsFields)
if err != nil {
return "", err
}
buf, err := json.Marshal(convertArgsToSlice(argsFields))
if err != nil {
return "", err
}
return string(buf), nil
}
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
m := map[string][]string{}
for k, v := range f {
values := []string{}
for kk := range v {
if v[kk] {
values = append(values, kk)
}
}
m[k] = values
}
return m
}

View File

@@ -6,7 +6,6 @@ import (
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/api/types/volume"
)
@@ -19,13 +18,6 @@ func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (v
if err != nil {
return volume.ListResponse{}, err
}
if cli.version != "" && versions.LessThan(cli.version, "1.22") {
legacyFormat, err := encodeLegacyFilters(filterJSON)
if err != nil {
return volume.ListResponse{}, err
}
filterJSON = legacyFormat
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/volumes", query, nil)