client: add Filters type

Add a new type to use for building filter predicates for API requests,
replacing "./api/types/filters".Args in the client. Remove the now
unused api/types/filters package.

Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
Cory Snider
2025-10-06 15:18:41 -04:00
parent 778e5bfad3
commit 7ea066c8d1
106 changed files with 380 additions and 853 deletions

View File

@@ -1,24 +0,0 @@
package filters
import "fmt"
// invalidFilter indicates that the provided filter or its value is invalid
type invalidFilter struct {
Filter string
Value []string
}
func (e invalidFilter) Error() string {
msg := "invalid filter"
if e.Filter != "" {
msg += " '" + e.Filter
if e.Value != nil {
msg = fmt.Sprintf("%s=%s", msg, e.Value)
}
msg += "'"
}
return msg
}
// InvalidParameter marks this error as ErrInvalidParameter
func (e invalidFilter) InvalidParameter() {}

View File

@@ -1,65 +0,0 @@
/*
Package filters provides tools for encoding a mapping of keys to a set of
multiple values.
*/
package filters
import (
"encoding/json"
)
// Args stores a mapping of keys to a set of multiple values.
type Args struct {
fields map[string]map[string]bool
}
// KeyValuePair are used to initialize a new Args
type KeyValuePair struct {
Key string
Value string
}
// Arg creates a new KeyValuePair for initializing Args
func Arg(key, value string) KeyValuePair {
return KeyValuePair{Key: key, Value: value}
}
// NewArgs returns a new Args populated with the initial args
func NewArgs(initialArgs ...KeyValuePair) Args {
args := Args{fields: map[string]map[string]bool{}}
for _, arg := range initialArgs {
args.Add(arg.Key, arg.Value)
}
return args
}
// MarshalJSON returns a JSON byte representation of the Args
func (args Args) MarshalJSON() ([]byte, error) {
if len(args.fields) == 0 {
return []byte("{}"), nil
}
return json.Marshal(args.fields)
}
// ToJSON returns the Args as a JSON encoded string
func ToJSON(a Args) (string, error) {
if a.Len() == 0 {
return "", nil
}
buf, err := json.Marshal(a)
return string(buf), err
}
// Add a new value to the set of values
func (args Args) Add(key, value string) {
if _, ok := args.fields[key]; ok {
args.fields[key][value] = true
} else {
args.fields[key] = map[string]bool{value: true}
}
}
// Len returns the number of keys in the mapping
func (args Args) Len() int {
return len(args.fields)
}

View File

@@ -1,62 +0,0 @@
package filters
import (
"encoding/json"
"testing"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestMarshalJSON(t *testing.T) {
a := NewArgs(
Arg("created", "today"),
Arg("image.name", "ubuntu*"),
Arg("image.name", "*untu"),
)
s, err := a.MarshalJSON()
assert.Check(t, err)
const expected = `{"created":{"today":true},"image.name":{"*untu":true,"ubuntu*":true}}`
assert.Check(t, is.Equal(string(s), expected))
}
func TestMarshalJSONWithEmpty(t *testing.T) {
s, err := json.Marshal(NewArgs())
assert.Check(t, err)
const expected = `{}`
assert.Check(t, is.Equal(string(s), expected))
}
func TestToJSON(t *testing.T) {
a := NewArgs(
Arg("created", "today"),
Arg("image.name", "ubuntu*"),
Arg("image.name", "*untu"),
)
s, err := ToJSON(a)
assert.Check(t, err)
const expected = `{"created":{"today":true},"image.name":{"*untu":true,"ubuntu*":true}}`
assert.Check(t, is.Equal(s, expected))
}
func TestAdd(t *testing.T) {
f := NewArgs()
f.Add("status", "running")
v := f.fields["status"]
assert.Check(t, is.DeepEqual(v, []string{"running"}))
f.Add("status", "paused")
v = f.fields["status"]
assert.Check(t, is.Len(v, 2))
assert.Check(t, is.Contains(v, "running"))
assert.Check(t, is.Contains(v, "paused"))
}
func TestLen(t *testing.T) {
f := NewArgs()
assert.Check(t, is.Equal(f.Len(), 0))
f.Add("status", "running")
assert.Check(t, is.Equal(f.Len(), 1))
}

View File

@@ -8,7 +8,6 @@ import (
"strconv"
"github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
)
@@ -18,7 +17,7 @@ type BuildCachePruneOptions struct {
ReservedSpace int64
MaxUsedSpace int64
MinFreeSpace int64
Filters filters.Args
Filters Filters
}
// BuildCachePruneResult holds the result from the BuildCachePrune method.
@@ -49,11 +48,7 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOpti
if opts.MinFreeSpace != 0 {
query.Set("min-free-space", strconv.Itoa(int(opts.MinFreeSpace)))
}
f, err := filters.ToJSON(opts.Filters)
if err != nil {
return BuildCachePruneResult{}, fmt.Errorf("prune could not marshal filters option: %w", err)
}
query.Set("filters", f)
opts.Filters.updateURLValues(query)
resp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/plugin"
@@ -89,7 +88,7 @@ type ContainerAPIClient interface {
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 CopyToContainerOptions) error
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
ContainersPrune(ctx context.Context, pruneFilters Filters) (container.PruneReport, error)
}
type ExecAPIClient interface {
@@ -119,7 +118,7 @@ type ImageAPIClient interface {
ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) ([]image.DeleteResponse, error)
ImageSearch(ctx context.Context, term string, options ImageSearchOptions) ([]registry.SearchResult, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (image.PruneReport, error)
ImagesPrune(ctx context.Context, pruneFilter Filters) (image.PruneReport, error)
ImageInspect(ctx context.Context, image string, _ ...ImageInspectOption) (image.InspectResponse, error)
ImageHistory(ctx context.Context, image string, _ ...ImageHistoryOption) ([]image.HistoryResponseItem, error)
@@ -136,7 +135,7 @@ type NetworkAPIClient interface {
NetworkInspectWithRaw(ctx context.Context, network string, options NetworkInspectOptions) (network.Inspect, []byte, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]network.Summary, error)
NetworkRemove(ctx context.Context, network string) error
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
NetworksPrune(ctx context.Context, pruneFilter Filters) (network.PruneReport, error)
}
// NodeAPIClient defines API client methods for the nodes
@@ -149,7 +148,7 @@ type NodeAPIClient interface {
// PluginAPIClient defines API client methods for the plugins
type PluginAPIClient interface {
PluginList(ctx context.Context, filter filters.Args) (plugin.ListResponse, error)
PluginList(ctx context.Context, filter Filters) (plugin.ListResponse, error)
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error
@@ -201,7 +200,7 @@ type VolumeAPIClient interface {
VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error)
VolumeList(ctx context.Context, options VolumeListOptions) (volume.ListResponse, error)
VolumeRemove(ctx context.Context, volumeID string, force bool) error
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (volume.PruneReport, error)
VolumesPrune(ctx context.Context, pruneFilter Filters) (volume.PruneReport, error)
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
}

View File

@@ -5,22 +5,13 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
// ConfigList returns the list of configs.
func (cli *Client) ConfigList(ctx context.Context, options ConfigListOptions) ([]swarm.Config, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/configs", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -41,10 +40,9 @@ func TestConfigList(t *testing.T) {
},
{
options: ConfigListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
Filters: make(Filters).
Add("label", "label1").
Add("label", "label2"),
},
expectedQueryParams: map[string]string{
"filters": `{"label":{"label1":true,"label2":true}}`,

View File

@@ -7,7 +7,6 @@ import (
"strconv"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
)
// ContainerListOptions holds parameters to list containers with.
@@ -18,7 +17,7 @@ type ContainerListOptions struct {
Since string
Before string
Limit int
Filters filters.Args
Filters Filters
}
// ContainerList returns the list of containers in the docker host.
@@ -45,13 +44,7 @@ func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptio
query.Set("size", "1")
}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/containers/json", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -11,7 +11,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@@ -86,11 +85,10 @@ func TestContainerList(t *testing.T) {
Size: true,
All: true,
Since: "container",
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
filters.Arg("before", "container"),
),
Filters: make(Filters).
Add("label", "label1").
Add("label", "label2").
Add("before", "container"),
})
assert.NilError(t, err)
assert.Check(t, is.Len(containers, 2))

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
)
// ContainersPrune requests the daemon to delete unused data
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return container.PruneReport{}, err
}
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters Filters) (container.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -10,7 +10,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@@ -19,7 +18,7 @@ func TestContainersPruneError(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
assert.NilError(t, err)
_, err = client.ContainersPrune(context.Background(), filters.Args{})
_, err = client.ContainersPrune(context.Background(), Filters{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
}
@@ -27,11 +26,11 @@ func TestContainersPrune(t *testing.T) {
const expectedURL = "/containers/prune"
listCases := []struct {
filters filters.Args
filters Filters
expectedQueryParams map[string]string
}{
{
filters: filters.Args{},
filters: Filters{},
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -39,7 +38,7 @@ func TestContainersPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("dangling", "true")),
filters: make(Filters).Add("dangling", "true"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -47,10 +46,9 @@ func TestContainersPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(
filters.Arg("dangling", "true"),
filters.Arg("until", "2016-12-15T14:00"),
),
filters: make(Filters).
Add("dangling", "true").
Add("until", "2016-12-15T14:00"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -58,7 +56,7 @@ func TestContainersPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("dangling", "false")),
filters: make(Filters).Add("dangling", "false"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -66,11 +64,10 @@ func TestContainersPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(
filters.Arg("dangling", "true"),
filters.Arg("label", "label1=foo"),
filters.Arg("label", "label2!=bar"),
),
filters: make(Filters).
Add("dangling", "true").
Add("label", "label1=foo").
Add("label", "label2!=bar"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",

46
client/filters.go Normal file
View File

@@ -0,0 +1,46 @@
package client
import (
"encoding/json"
"net/url"
)
// Filters describes a predicate for an API request.
//
// Each entry in the map is a filter term.
// Each term is evaluated against the set of values.
// A filter term is satisfied if any one of the values in the set is a match.
// An item matches the filters when all terms are satisfied.
//
// Like all other map types in Go, the zero value is empty and read-only.
type Filters map[string]map[string]bool
// Add appends values to the value-set of term.
//
// The receiver f is returned for chaining.
//
// f := make(Filters).Add("name", "foo", "bar").Add("status", "exited")
func (f Filters) Add(term string, values ...string) Filters {
if _, ok := f[term]; !ok {
f[term] = make(map[string]bool)
}
for _, v := range values {
f[term][v] = true
}
return f
}
// updateURLValues sets the "filters" key in values to the marshalled value of
// f, replacing any existing values. When f is empty, any existing "filters" key
// is removed.
func (f Filters) updateURLValues(values url.Values) {
if len(f) > 0 {
b, err := json.Marshal(f)
if err != nil {
panic(err) // Marshaling builtin types should never fail
}
values.Set("filters", string(b))
} else {
values.Del("filters")
}
}

48
client/filters_test.go Normal file
View File

@@ -0,0 +1,48 @@
package client
import (
"net/url"
"testing"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestFilters(t *testing.T) {
f := make(Filters).Add("foo", "bar", "baz", "bar").
Add("quux", "xyzzy").
Add("quux", "plugh")
f["lol"] = map[string]bool{"abc": true}
f.Add("lol", "def")
assert.Check(t, is.DeepEqual(f, Filters{
"foo": {"bar": true, "baz": true},
"quux": {"xyzzy": true, "plugh": true},
"lol": {"abc": true, "def": true},
}))
}
func TestFilters_UpdateURLValues(t *testing.T) {
v := url.Values{}
Filters(nil).updateURLValues(v)
assert.Check(t, is.DeepEqual(v, url.Values{}))
v = url.Values{"filters": []string{"bogus"}}
Filters(nil).updateURLValues(v)
assert.Check(t, is.DeepEqual(v, url.Values{}))
v = url.Values{}
Filters{}.updateURLValues(v)
assert.Check(t, is.DeepEqual(v, url.Values{}))
v = url.Values{"filters": []string{"bogus"}}
Filters{}.updateURLValues(v)
assert.Check(t, is.DeepEqual(v, url.Values{}))
v = url.Values{}
Filters{"foo": map[string]bool{"bar": true}}.updateURLValues(v)
assert.Check(t, is.DeepEqual(v, url.Values{"filters": []string{`{"foo":{"bar":true}}`}}))
v = url.Values{"filters": []string{"bogus"}}
Filters{"foo": map[string]bool{"bar": true}}.updateURLValues(v)
assert.Check(t, is.DeepEqual(v, url.Values{"filters": []string{`{"foo":{"bar":true}}`}}))
}

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/versions"
)
@@ -30,13 +29,7 @@ func (cli *Client) ImageList(ctx context.Context, options ImageListOptions) ([]i
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return images, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
if options.All {
query.Set("all", "1")
}

View File

@@ -1,7 +1,5 @@
package client
import "github.com/moby/moby/api/types/filters"
// ImageListOptions holds parameters to list images with.
type ImageListOptions struct {
// All controls whether all images in the graph are filtered, or just
@@ -9,7 +7,7 @@ type ImageListOptions struct {
All bool
// Filters is a JSON-encoded set of filter arguments.
Filters filters.Args
Filters Filters
// SharedSize indicates whether the shared size of images should be computed.
SharedSize bool

View File

@@ -12,7 +12,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -55,11 +54,10 @@ func TestImageList(t *testing.T) {
},
{
options: ImageListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
filters.Arg("dangling", "true"),
),
Filters: make(Filters).
Add("label", "label1").
Add("label", "label2").
Add("dangling", "true"),
},
expectedQueryParams: map[string]string{
"all": "",
@@ -69,7 +67,7 @@ func TestImageList(t *testing.T) {
},
{
options: ImageListOptions{
Filters: filters.NewArgs(filters.Arg("dangling", "false")),
Filters: make(Filters).Add("dangling", "false"),
},
expectedQueryParams: map[string]string{
"all": "",

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
)
// ImagesPrune requests the daemon to delete unused data
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return image.PruneReport{}, err
}
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters Filters) (image.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -11,7 +11,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/filters"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@@ -20,7 +19,7 @@ func TestImagesPruneError(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
assert.NilError(t, err)
_, err = client.ImagesPrune(context.Background(), filters.NewArgs())
_, err = client.ImagesPrune(context.Background(), nil)
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
}
@@ -28,11 +27,11 @@ func TestImagesPrune(t *testing.T) {
const expectedURL = "/images/prune"
listCases := []struct {
filters filters.Args
filters Filters
expectedQueryParams map[string]string
}{
{
filters: filters.Args{},
filters: Filters{},
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -40,7 +39,7 @@ func TestImagesPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("dangling", "true")),
filters: make(Filters).Add("dangling", "true"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -48,7 +47,7 @@ func TestImagesPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("dangling", "false")),
filters: make(Filters).Add("dangling", "false"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -56,11 +55,9 @@ func TestImagesPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(
filters.Arg("dangling", "true"),
filters.Arg("label", "label1=foo"),
filters.Arg("label", "label2!=bar"),
),
filters: make(Filters).
Add("dangling", "true").
Add("label", "label1=foo", "label2!=bar"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",

View File

@@ -8,7 +8,6 @@ import (
"strconv"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/registry"
)
@@ -22,13 +21,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSe
query.Set("limit", strconv.Itoa(options.Limit))
}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return results, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
defer ensureReaderClosed(resp)

View File

@@ -2,8 +2,6 @@ package client
import (
"context"
"github.com/moby/moby/api/types/filters"
)
// ImageSearchOptions holds parameters to search images with.
@@ -17,6 +15,6 @@ type ImageSearchOptions struct {
//
// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
PrivilegeFunc func(context.Context) (string, error)
Filters filters.Args
Filters Filters
Limit int
}

View File

@@ -11,7 +11,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/registry"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -133,10 +132,7 @@ func TestImageSearchWithoutErrors(t *testing.T) {
}))
assert.NilError(t, err)
results, err := client.ImageSearch(context.Background(), "some-image", ImageSearchOptions{
Filters: filters.NewArgs(
filters.Arg("is-automated", "true"),
filters.Arg("stars", "3"),
),
Filters: make(Filters).Add("is-automated", "true").Add("stars", "3"),
})
assert.NilError(t, err)
assert.Check(t, is.Len(results, 1))

View File

@@ -5,20 +5,13 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
)
// NetworkList returns the list of networks configured in the docker host.
func (cli *Client) NetworkList(ctx context.Context, options NetworkListOptions) ([]network.Summary, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
var networkResources []network.Summary
resp, err := cli.get(ctx, "/networks", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// NetworkListOptions holds parameters to filter the list of networks with.
type NetworkListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -37,22 +36,21 @@ func TestNetworkList(t *testing.T) {
},
{
options: NetworkListOptions{
Filters: filters.NewArgs(filters.Arg("dangling", "false")),
Filters: make(Filters).Add("dangling", "false"),
},
expectedFilters: `{"dangling":{"false":true}}`,
},
{
options: NetworkListOptions{
Filters: filters.NewArgs(filters.Arg("dangling", "true")),
Filters: make(Filters).Add("dangling", "true"),
},
expectedFilters: `{"dangling":{"true":true}}`,
},
{
options: NetworkListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
Filters: make(Filters).
Add("label", "label1").
Add("label", "label2"),
},
expectedFilters: `{"label":{"label1":true,"label2":true}}`,
},

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
)
// NetworksPrune requests the daemon to delete unused networks
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return network.PruneReport{}, err
}
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters Filters) (network.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -9,7 +9,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -21,7 +20,7 @@ func TestNetworksPruneError(t *testing.T) {
)
assert.NilError(t, err)
_, err = client.NetworksPrune(context.Background(), filters.NewArgs())
_, err = client.NetworksPrune(context.Background(), nil)
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
}
@@ -29,11 +28,11 @@ func TestNetworksPrune(t *testing.T) {
const expectedURL = "/networks/prune"
listCases := []struct {
filters filters.Args
filters Filters
expectedQueryParams map[string]string
}{
{
filters: filters.Args{},
filters: Filters{},
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -41,7 +40,7 @@ func TestNetworksPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("dangling", "true")),
filters: make(Filters).Add("dangling", "true"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -49,7 +48,7 @@ func TestNetworksPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("dangling", "false")),
filters: make(Filters).Add("dangling", "false"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",
@@ -57,11 +56,10 @@ func TestNetworksPrune(t *testing.T) {
},
},
{
filters: filters.NewArgs(
filters.Arg("dangling", "true"),
filters.Arg("label", "label1=foo"),
filters.Arg("label", "label2!=bar"),
),
filters: make(Filters).
Add("dangling", "true").
Add("label", "label1=foo").
Add("label", "label2!=bar"),
expectedQueryParams: map[string]string{
"until": "",
"filter": "",

View File

@@ -5,23 +5,13 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
// NodeList returns the list of nodes.
func (cli *Client) NodeList(ctx context.Context, options NodeListOptions) ([]swarm.Node, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/nodes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -39,10 +38,8 @@ func TestNodeList(t *testing.T) {
},
{
options: NodeListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
Filters: make(Filters).
Add("label", "label1", "label2"),
},
expectedQueryParams: map[string]string{
"filters": `{"label":{"label1":true,"label2":true}}`,

View File

@@ -5,22 +5,15 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
)
// PluginList returns the installed plugins
func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (plugin.ListResponse, error) {
func (cli *Client) PluginList(ctx context.Context, filter Filters) (plugin.ListResponse, error) {
var plugins plugin.ListResponse
query := url.Values{}
if filter.Len() > 0 {
filterJSON, err := filters.ToJSON(filter)
if err != nil {
return plugins, err
}
query.Set("filters", filterJSON)
}
filter.updateURLValues(query)
resp, err := cli.get(ctx, "/plugins", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -20,7 +19,7 @@ func TestPluginListError(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
assert.NilError(t, err)
_, err = client.PluginList(context.Background(), filters.NewArgs())
_, err = client.PluginList(context.Background(), nil)
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
}
@@ -28,11 +27,10 @@ func TestPluginList(t *testing.T) {
const expectedURL = "/plugins"
listCases := []struct {
filters filters.Args
filters Filters
expectedQueryParams map[string]string
}{
{
filters: filters.NewArgs(),
expectedQueryParams: map[string]string{
"all": "",
"filter": "",
@@ -40,7 +38,7 @@ func TestPluginList(t *testing.T) {
},
},
{
filters: filters.NewArgs(filters.Arg("enabled", "true")),
filters: make(Filters).Add("enabled", "true"),
expectedQueryParams: map[string]string{
"all": "",
"filter": "",
@@ -48,10 +46,7 @@ func TestPluginList(t *testing.T) {
},
},
{
filters: filters.NewArgs(
filters.Arg("capability", "volumedriver"),
filters.Arg("capability", "authz"),
),
filters: make(Filters).Add("capability", "volumedriver", "authz"),
expectedQueryParams: map[string]string{
"all": "",
"filter": "",

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
@@ -13,15 +12,7 @@ import (
func (cli *Client) SecretList(ctx context.Context, options SecretListOptions) ([]swarm.Secret, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/secrets", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// SecretListOptions holds parameters to list secrets
type SecretListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -39,10 +38,7 @@ func TestSecretList(t *testing.T) {
},
{
options: SecretListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
Filters: make(Filters).Add("label", "label1", "label2"),
},
expectedQueryParams: map[string]string{
"filters": `{"label":{"label1":true,"label2":true}}`,

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
@@ -13,14 +12,7 @@ import (
func (cli *Client) ServiceList(ctx context.Context, options ServiceListOptions) ([]swarm.Service, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
if options.Status {
query.Set("status", "true")

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -39,10 +38,7 @@ func TestServiceList(t *testing.T) {
},
{
options: ServiceListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
Filters: make(Filters).Add("label", "label1", "label2"),
},
expectedQueryParams: map[string]string{
"filters": `{"label":{"label1":true,"label2":true}}`,

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// ConfigListOptions holds parameters to list configs
type ConfigListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// NodeListOptions holds parameters to list nodes with.
type NodeListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -1,10 +1,8 @@
package client
import "github.com/moby/moby/api/types/filters"
// ServiceListOptions holds parameters to list services with.
type ServiceListOptions struct {
Filters filters.Args
Filters Filters
// Status indicates whether the server should include the service task
// count of running and desired tasks.

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// TaskListOptions holds parameters to list tasks with.
type TaskListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/client/internal"
"github.com/moby/moby/client/internal/timestamp"
)
@@ -17,7 +16,7 @@ import (
type EventsListOptions struct {
Since string
Until string
Filters filters.Args
Filters Filters
}
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
@@ -100,13 +99,7 @@ func buildEventsQueryParams(options EventsListOptions) (url.Values, error) {
query.Set("until", ts)
}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
return query, nil
}

View File

@@ -12,7 +12,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@@ -55,7 +54,7 @@ func TestEventsErrorFromServer(t *testing.T) {
func TestEvents(t *testing.T) {
const expectedURL = "/events"
fltrs := filters.NewArgs(filters.Arg("type", string(events.ContainerEventType)))
fltrs := make(Filters).Add("type", string(events.ContainerEventType))
expectedFiltersJSON := fmt.Sprintf(`{"type":{%q:true}}`, events.ContainerEventType)
eventsCases := []struct {

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
@@ -13,14 +12,7 @@ import (
func (cli *Client) TaskList(ctx context.Context, options TaskListOptions) ([]swarm.Task, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/tasks", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -39,10 +38,7 @@ func TestTaskList(t *testing.T) {
},
{
options: TaskListOptions{
Filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
Filters: make(Filters).Add("label", "label1", "label2"),
},
expectedQueryParams: map[string]string{
"filters": `{"label":{"label1":true,"label2":true}}`,

View File

@@ -3,11 +3,9 @@ package client
import (
"encoding/json"
"fmt"
"net/url"
"strings"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@@ -28,20 +26,6 @@ func trimID(objType, id string) (string, error) {
return id, nil
}
// getFiltersQuery returns a url query with "filters" query term, based on the
// filters provided.
func getFiltersQuery(f filters.Args) (url.Values, error) {
query := url.Values{}
if f.Len() > 0 {
filterJSON, err := filters.ToJSON(f)
if err != nil {
return query, err
}
query.Set("filters", filterJSON)
}
return query, 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) {

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/volume"
)
@@ -13,13 +12,7 @@ import (
func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (volume.ListResponse, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return volume.ListResponse{}, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/volumes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// VolumeListOptions holds parameters to list volumes.
type VolumeListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -10,7 +10,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/volume"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -28,23 +27,19 @@ func TestVolumeList(t *testing.T) {
const expectedURL = "/volumes"
listCases := []struct {
filters filters.Args
filters Filters
expectedFilters string
}{
{
filters: filters.NewArgs(),
expectedFilters: "",
}, {
filters: filters.NewArgs(filters.Arg("dangling", "false")),
filters: make(Filters).Add("dangling", "false"),
expectedFilters: `{"dangling":{"false":true}}`,
}, {
filters: filters.NewArgs(filters.Arg("dangling", "true")),
filters: make(Filters).Add("dangling", "true"),
expectedFilters: `{"dangling":{"true":true}}`,
}, {
filters: filters.NewArgs(
filters.Arg("label", "label1"),
filters.Arg("label", "label2"),
),
filters: make(Filters).Add("label", "label1", "label2"),
expectedFilters: `{"label":{"label1":true,"label2":true}}`,
},
}

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/volume"
)
// VolumesPrune requests the daemon to delete unused data
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return volume.PruneReport{}, err
}
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters Filters) (volume.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -8,7 +8,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"gotest.tools/v3/assert"
@@ -105,7 +104,7 @@ func (d *Daemon) CheckRunningTaskNetworks(ctx context.Context) func(t *testing.T
defer cli.Close()
tasks, err := cli.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(filters.Arg("desired-state", "running")),
Filters: make(client.Filters).Add("desired-state", "running"),
})
assert.NilError(t, err)
@@ -126,7 +125,7 @@ func (d *Daemon) CheckRunningTaskImages(ctx context.Context) func(t *testing.T)
defer cli.Close()
tasks, err := cli.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(filters.Arg("desired-state", "running")),
Filters: make(client.Filters).Add("desired-state", "running"),
})
assert.NilError(t, err)

View File

@@ -17,7 +17,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/client"
"github.com/moby/moby/client/pkg/jsonmessage"
@@ -122,9 +121,9 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
}
}
func buildContainerIdsFilter(buildOutput io.Reader) (filters.Args, error) {
func buildContainerIdsFilter(buildOutput io.Reader) (client.Filters, error) {
const intermediateContainerPrefix = " ---> Running in "
filter := filters.NewArgs()
filter := client.Filters{}
dec := json.NewDecoder(buildOutput)
for {

View File

@@ -10,7 +10,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/pkg/stdcopy"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/swarm"
@@ -76,32 +75,32 @@ func TestConfigList(t *testing.T) {
testCases := []struct {
desc string
filters filters.Args
filters client.Filters
expected []string
}{
{
desc: "test filter by name",
filters: filters.NewArgs(filters.Arg("name", testName0)),
filters: make(client.Filters).Add("name", testName0),
expected: []string{testName0},
},
{
desc: "test filter by id",
filters: filters.NewArgs(filters.Arg("id", config1ID)),
filters: make(client.Filters).Add("id", config1ID),
expected: []string{testName1},
},
{
desc: "test filter by label key only",
filters: filters.NewArgs(filters.Arg("label", "type")),
filters: make(client.Filters).Add("label", "type"),
expected: testNames,
},
{
desc: "test filter by label key=value " + testName0,
filters: filters.NewArgs(filters.Arg("label", "type=test")),
filters: make(client.Filters).Add("label", "type=test"),
expected: []string{testName0},
},
{
desc: "test filter by label key=value " + testName1,
filters: filters.NewArgs(filters.Arg("label", "type=production")),
filters: make(client.Filters).Add("label", "type=production"),
expected: []string{testName1},
},
}

View File

@@ -5,7 +5,6 @@ import (
"strings"
"testing"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/client"
"github.com/moby/moby/client/pkg/jsonmessage"
"github.com/moby/moby/v2/integration/internal/container"
@@ -45,7 +44,7 @@ func TestExportContainerAndImportImage(t *testing.T) {
assert.NilError(t, err)
images, err := apiClient.ImageList(ctx, client.ImageListOptions{
Filters: filters.NewArgs(filters.Arg("reference", reference)),
Filters: make(client.Filters).Add("reference", reference),
})
assert.NilError(t, err)
assert.Check(t, is.Equal(jm.Status, images[0].ID))

View File

@@ -4,7 +4,6 @@ import (
"os"
"testing"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
"gotest.tools/v3/assert"
@@ -44,7 +43,7 @@ func TestLinksContainerNames(t *testing.T) {
container.Run(ctx, t, apiClient, container.WithName(containerB), container.WithLinks(containerA+":"+containerA))
containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", containerA)),
Filters: make(client.Filters).Add("name", containerA),
})
assert.NilError(t, err)
assert.Check(t, is.Equal(1, len(containers)))

View File

@@ -7,7 +7,6 @@ import (
"time"
containertypes "github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
@@ -68,7 +67,7 @@ func TestContainerList_Annotations(t *testing.T) {
containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("id", id)),
Filters: make(client.Filters).Add("id", id),
})
assert.NilError(t, err)
assert.Assert(t, is.Len(containers, 1))
@@ -104,7 +103,7 @@ func TestContainerList_Filter(t *testing.T) {
ctx := testutil.StartSpan(ctx, t)
results, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("since", top)),
Filters: make(client.Filters).Add("since", top),
})
assert.NilError(t, err)
assert.Check(t, is.Contains(containerIDs(results), next))
@@ -114,7 +113,7 @@ func TestContainerList_Filter(t *testing.T) {
ctx := testutil.StartSpan(ctx, t)
results, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("before", top)),
Filters: make(client.Filters).Add("before", top),
})
assert.NilError(t, err)
assert.Check(t, is.Contains(containerIDs(results), prev))
@@ -152,7 +151,7 @@ func pollForHealthStatusSummary(ctx context.Context, apiClient client.APIClient,
return func(log poll.LogT) poll.Result {
containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("id", containerID)),
Filters: make(client.Filters).Add("id", containerID),
})
if err != nil {
return poll.Error(err)

View File

@@ -7,7 +7,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
"github.com/moby/moby/v2/internal/testutil/request"
@@ -43,7 +42,7 @@ func TestPause(t *testing.T) {
messages, errs := apiClient.Events(ctx, client.EventsListOptions{
Since: since,
Until: until,
Filters: filters.NewArgs(filters.Arg(string(events.ContainerEventType), cID)),
Filters: make(client.Filters).Add(string(events.ContainerEventType), cID),
})
assert.Check(t, is.DeepEqual([]events.Action{events.ActionPause, events.ActionUnPause}, getEventActions(t, messages, errs)))
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/client"
testContainer "github.com/moby/moby/v2/integration/internal/container"
"github.com/moby/moby/v2/internal/testutil"
@@ -242,10 +241,7 @@ func TestContainerRestartWithCancelledRequest(t *testing.T) {
// Start listening for events.
messages, errs := apiClient.Events(ctx, client.EventsListOptions{
Filters: filters.NewArgs(
filters.Arg("container", cID),
filters.Arg("event", string(events.ActionRestart)),
),
Filters: make(client.Filters).Add("container", cID).Add("event", string(events.ActionRestart)),
})
// Make restart request, but cancel the request before the container

View File

@@ -8,7 +8,6 @@ import (
"time"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/versions"
"github.com/moby/moby/client"
@@ -43,12 +42,8 @@ func TestImagesFilterMultiReference(t *testing.T) {
assert.NilError(t, err)
}
filter := filters.NewArgs()
filter.Add("reference", repoTags[0])
filter.Add("reference", repoTags[1])
filter.Add("reference", repoTags[2])
options := client.ImageListOptions{
Filters: filter,
Filters: make(client.Filters).Add("reference", repoTags[:3]...),
}
images, err := apiClient.ImageList(ctx, options)
assert.NilError(t, err)
@@ -89,12 +84,11 @@ func TestImagesFilterUntil(t *testing.T) {
assert.NilError(t, err)
laterUntil := laterImage.Created
filter := filters.NewArgs(
filters.Arg("since", imgs[0]),
filters.Arg("until", olderUntil),
filters.Arg("until", laterUntil),
filters.Arg("before", imgs[len(imgs)-1]),
)
filter := make(client.Filters).
Add("since", imgs[0]).
Add("until", olderUntil).
Add("until", laterUntil).
Add("before", imgs[len(imgs)-1])
list, err := apiClient.ImageList(ctx, client.ImageListOptions{Filters: filter})
assert.NilError(t, err)
@@ -125,10 +119,9 @@ func TestImagesFilterBeforeSince(t *testing.T) {
imgs[i] = id.ID
}
filter := filters.NewArgs(
filters.Arg("since", imgs[0]),
filters.Arg("before", imgs[len(imgs)-1]),
)
filter := make(client.Filters).
Add("since", imgs[0]).
Add("before", imgs[len(imgs)-1])
list, err := apiClient.ImageList(ctx, client.ImageListOptions{Filters: filter})
assert.NilError(t, err)
@@ -155,31 +148,31 @@ func TestAPIImagesFilters(t *testing.T) {
testcases := []struct {
name string
filters []filters.KeyValuePair
filters client.Filters
expectedImages int
expectedRepoTags int
}{
{
name: "repository regex",
filters: []filters.KeyValuePair{filters.Arg("reference", "utest*/*")},
filters: make(client.Filters).Add("reference", "utest*/*"),
expectedImages: 1,
expectedRepoTags: 2,
},
{
name: "image name regex",
filters: []filters.KeyValuePair{filters.Arg("reference", "utest*")},
filters: make(client.Filters).Add("reference", "utest*"),
expectedImages: 1,
expectedRepoTags: 1,
},
{
name: "image name without a tag",
filters: []filters.KeyValuePair{filters.Arg("reference", "utest")},
filters: make(client.Filters).Add("reference", "utest"),
expectedImages: 1,
expectedRepoTags: 1,
},
{
name: "registry port regex",
filters: []filters.KeyValuePair{filters.Arg("reference", "*5000*/*")},
filters: make(client.Filters).Add("reference", "*5000*/*"),
expectedImages: 1,
expectedRepoTags: 1,
},
@@ -191,7 +184,7 @@ func TestAPIImagesFilters(t *testing.T) {
ctx := testutil.StartSpan(ctx, t)
images, err := apiClient.ImageList(ctx, client.ImageListOptions{
Filters: filters.NewArgs(tc.filters...),
Filters: tc.filters,
})
assert.Check(t, err)
assert.Assert(t, is.Len(images, tc.expectedImages))

View File

@@ -4,7 +4,6 @@ import (
"strings"
"testing"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
@@ -40,7 +39,7 @@ func TestPruneDontDeleteUsedDangling(t *testing.T) {
container.WithImage(danglingID),
container.WithCmd("sleep", "60"))
pruned, err := apiClient.ImagesPrune(ctx, filters.NewArgs(filters.Arg("dangling", "true")))
pruned, err := apiClient.ImagesPrune(ctx, make(client.Filters).Add("dangling", "true"))
assert.NilError(t, err)
for _, deleted := range pruned.ImagesDeleted {
@@ -88,7 +87,7 @@ func TestPruneLexographicalOrder(t *testing.T) {
cid := container.Create(ctx, t, apiClient, container.WithImage(id))
defer container.Remove(ctx, t, apiClient, cid, client.ContainerRemoveOptions{Force: true})
pruned, err := apiClient.ImagesPrune(ctx, filters.NewArgs(filters.Arg("dangling", "false")))
pruned, err := apiClient.ImagesPrune(ctx, make(client.Filters).Add("dangling", "false"))
assert.NilError(t, err)
assert.Check(t, is.Len(pruned.ImagesDeleted, len(tags)))
@@ -218,7 +217,7 @@ func TestPruneDontDeleteUsedImage(t *testing.T) {
defer container.Remove(ctx, t, apiClient, cid, client.ContainerRemoveOptions{Force: true})
// dangling=false also prunes unused images
pruned, err := apiClient.ImagesPrune(ctx, filters.NewArgs(filters.Arg("dangling", "false")))
pruned, err := apiClient.ImagesPrune(ctx, make(client.Filters).Add("dangling", "false"))
assert.NilError(t, err)
env.check(t, apiClient, pruned)

View File

@@ -6,7 +6,6 @@ import (
"testing"
"time"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/internal/testutil/daemon"
@@ -206,10 +205,9 @@ func GetRunningTasks(ctx context.Context, t *testing.T, c client.ServiceAPIClien
t.Helper()
tasks, err := c.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(
filters.Arg("service", serviceID),
filters.Arg("desired-state", "running"),
),
Filters: make(client.Filters).
Add("service", serviceID).
Add("desired-state", "running"),
})
assert.NilError(t, err)

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"gotest.tools/v3/poll"
@@ -14,9 +13,7 @@ import (
func NoTasksForService(ctx context.Context, apiClient client.ServiceAPIClient, serviceID string) func(log poll.LogT) poll.Result {
return func(log poll.LogT) poll.Result {
tasks, err := apiClient.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(
filters.Arg("service", serviceID),
),
Filters: make(client.Filters).Add("service", serviceID),
})
if err == nil {
if len(tasks) == 0 {
@@ -50,10 +47,8 @@ func NoTasks(ctx context.Context, apiClient client.ServiceAPIClient) func(log po
// RunningTasksCount verifies there are `instances` tasks running for `serviceID`
func RunningTasksCount(ctx context.Context, apiClient client.ServiceAPIClient, serviceID string, instances uint64) func(log poll.LogT) poll.Result {
return func(log poll.LogT) poll.Result {
filter := filters.NewArgs()
filter.Add("service", serviceID)
tasks, err := apiClient.TaskList(ctx, client.TaskListOptions{
Filters: filter,
Filters: make(client.Filters).Add("service", serviceID),
})
var running int
var taskError string
@@ -90,7 +85,7 @@ func RunningTasksCount(ctx context.Context, apiClient client.ServiceAPIClient, s
// completed additionally, while polling, it verifies that the job never
// exceeds MaxConcurrent running tasks
func JobComplete(ctx context.Context, apiClient client.ServiceAPIClient, service swarmtypes.Service) func(log poll.LogT) poll.Result {
filter := filters.NewArgs(filters.Arg("service", service.ID))
filter := make(client.Filters).Add("service", service.ID)
var jobIteration swarmtypes.Version
if service.JobStatus != nil {
@@ -165,7 +160,7 @@ func JobComplete(ctx context.Context, apiClient client.ServiceAPIClient, service
func HasLeader(ctx context.Context, apiClient client.NodeAPIClient) func(log poll.LogT) poll.Result {
return func(log poll.LogT) poll.Result {
nodes, err := apiClient.NodeList(ctx, client.NodeListOptions{
Filters: filters.NewArgs(filters.Arg("role", "manager")),
Filters: make(client.Filters).Add("role", "manager"),
})
if err != nil {
return poll.Error(err)

View File

@@ -5,7 +5,6 @@ import (
"strconv"
"testing"
"github.com/moby/moby/api/types/filters"
networktypes "github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/network"
@@ -166,7 +165,7 @@ func TestInspectNetwork(t *testing.T) {
leaderID := func() string {
ls, err := c1.NodeList(ctx, client.NodeListOptions{
Filters: filters.NewArgs(filters.Arg("role", "manager")),
Filters: make(client.Filters).Add("role", "manager"),
})
assert.NilError(t, err)
for _, node := range ls {

View File

@@ -6,7 +6,6 @@ import (
"net/http"
"testing"
"github.com/moby/moby/api/types/filters"
networktypes "github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/internal/testutil"
@@ -132,7 +131,7 @@ func TestAPINetworkFilter(t *testing.T) {
apiClient := testEnv.APIClient()
networks, err := apiClient.NetworkList(ctx, client.NetworkListOptions{
Filters: filters.NewArgs(filters.Arg("name", networkName)),
Filters: make(client.Filters).Add("name", networkName),
})
assert.NilError(t, err)

View File

@@ -8,7 +8,6 @@ import (
"io"
"testing"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/volume"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
@@ -111,7 +110,7 @@ func TestAuthZPluginV2RejectVolumeRequests(t *testing.T) {
assert.Assert(t, err != nil)
assert.ErrorContains(t, err, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
_, err = c.VolumesPrune(ctx, filters.Args{})
_, err = c.VolumesPrune(ctx, nil)
assert.Assert(t, err != nil)
assert.ErrorContains(t, err, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
}

View File

@@ -10,7 +10,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/pkg/stdcopy"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/swarm"
@@ -73,30 +72,30 @@ func TestSecretList(t *testing.T) {
assert.Check(t, is.DeepEqual(secretNamesFromList(entries), testNames))
testCases := []struct {
filters filters.Args
filters client.Filters
expected []string
}{
// test filter by name `secret ls --filter name=xxx`
{
filters: filters.NewArgs(filters.Arg("name", testName0)),
filters: make(client.Filters).Add("name", testName0),
expected: []string{testName0},
},
// test filter by id `secret ls --filter id=xxx`
{
filters: filters.NewArgs(filters.Arg("id", secret1ID)),
filters: make(client.Filters).Add("id", secret1ID),
expected: []string{testName1},
},
// test filter by label `secret ls --filter label=xxx`
{
filters: filters.NewArgs(filters.Arg("label", "type")),
filters: make(client.Filters).Add("label", "type"),
expected: testNames,
},
{
filters: filters.NewArgs(filters.Arg("label", "type=test")),
filters: make(client.Filters).Add("label", "type=test"),
expected: []string{testName0},
},
{
filters: filters.NewArgs(filters.Arg("label", "type=production")),
filters: make(client.Filters).Add("label", "type=production"),
expected: []string{testName1},
},
}

View File

@@ -9,7 +9,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/network"
@@ -65,7 +64,7 @@ func testServiceCreateInit(ctx context.Context, daemonEnabled bool) func(t *test
func inspectServiceContainer(ctx context.Context, t *testing.T, apiClient client.APIClient, serviceID string) container.InspectResponse {
t.Helper()
containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("label", "com.docker.swarm.service.id="+serviceID)),
Filters: make(client.Filters).Add("label", "com.docker.swarm.service.id="+serviceID),
})
assert.NilError(t, err)
assert.Check(t, is.Len(containers, 1))
@@ -368,7 +367,7 @@ func TestCreateServiceSysctls(t *testing.T) {
// get all tasks of the service, so we can get the container
tasks, err := apiClient.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(filters.Arg("service", serviceID)),
Filters: make(client.Filters).Add("service", serviceID),
})
assert.NilError(t, err)
assert.Check(t, is.Equal(len(tasks), 1))
@@ -438,7 +437,7 @@ func TestCreateServiceCapabilities(t *testing.T) {
// get all tasks of the service, so we can get the container
tasks, err := apiClient.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(filters.Arg("service", serviceID)),
Filters: make(client.Filters).Add("service", serviceID),
})
assert.NilError(t, err)
assert.Check(t, is.Equal(len(tasks), 1))

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"testing"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/swarm"
@@ -54,7 +53,7 @@ func TestServiceListWithStatuses(t *testing.T) {
// bespoke closure right here.
poll.WaitOn(t, func(log poll.LogT) poll.Result {
tasks, err := apiClient.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(filters.Arg("service", id)),
Filters: make(client.Filters).Add("service", id),
})
running := 0

View File

@@ -6,7 +6,6 @@ import (
"strings"
"testing"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/swarm"
@@ -68,7 +67,7 @@ func TestServicePlugin(t *testing.T) {
// test that environment variables are passed from plugin service to plugin instance
service := d1.GetService(ctx, t, id)
tasks := d1.GetServiceTasks(ctx, t, service.Spec.Annotations.Name, filters.Arg("runtime", "plugin"))
tasks := d1.GetServiceTasksWithFilters(ctx, t, service.Spec.Annotations.Name, make(client.Filters).Add("runtime", "plugin"))
if len(tasks) == 0 {
t.Log("No tasks found for plugin service")
t.Fail()

View File

@@ -5,7 +5,6 @@ import (
"testing"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
swarmtypes "github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/network"
@@ -325,10 +324,7 @@ func TestServiceUpdatePidsLimit(t *testing.T) {
func getServiceTaskContainer(ctx context.Context, t *testing.T, cli client.APIClient, serviceID string) container.InspectResponse {
t.Helper()
tasks, err := cli.TaskList(ctx, client.TaskListOptions{
Filters: filters.NewArgs(
filters.Arg("service", serviceID),
filters.Arg("desired-state", "running"),
),
Filters: make(client.Filters).Add("service", serviceID).Add("desired-state", "running"),
})
assert.NilError(t, err)
assert.Assert(t, len(tasks) > 0)

View File

@@ -9,7 +9,6 @@ import (
"time"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/mount"
"github.com/moby/moby/api/types/volume"
"github.com/moby/moby/client"
@@ -33,10 +32,7 @@ func TestEventsExecDie(t *testing.T) {
assert.NilError(t, err)
msg, errs := apiClient.Events(ctx, client.EventsListOptions{
Filters: filters.NewArgs(
filters.Arg("container", cID),
filters.Arg("event", string(events.ActionExecDie)),
),
Filters: make(client.Filters).Add("container", cID).Add("event", string(events.ActionExecDie)),
})
err = apiClient.ContainerExecStart(ctx, id.ID, client.ExecStartOptions{
@@ -108,11 +104,10 @@ func TestEventsVolumeCreate(t *testing.T) {
_, err := apiClient.VolumeCreate(ctx, volume.CreateOptions{Name: volName})
assert.NilError(t, err)
filter := filters.NewArgs(
filters.Arg("type", "volume"),
filters.Arg("event", "create"),
filters.Arg("volume", volName),
)
filter := make(client.Filters).
Add("type", "volume").
Add("event", "create").
Add("volume", volName)
messages, errs := apiClient.Events(ctx, client.EventsListOptions{
Since: since,
Until: request.DaemonUnixTime(ctx, t, apiClient, testEnv),

View File

@@ -10,7 +10,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/volume"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/build"
@@ -271,7 +270,7 @@ func TestVolumePruneAnonymous(t *testing.T) {
assert.NilError(t, err)
// Prune anonymous volumes
pruneReport, err := apiClient.VolumesPrune(ctx, filters.Args{})
pruneReport, err := apiClient.VolumesPrune(ctx, nil)
assert.NilError(t, err)
assert.Check(t, is.Equal(len(pruneReport.VolumesDeleted), 1))
assert.Check(t, is.Equal(pruneReport.VolumesDeleted[0], v.Name))
@@ -283,7 +282,7 @@ func TestVolumePruneAnonymous(t *testing.T) {
_, err = apiClient.VolumeCreate(ctx, volume.CreateOptions{})
assert.NilError(t, err)
pruneReport, err = apiClient.VolumesPrune(ctx, filters.NewArgs(filters.Arg("all", "1")))
pruneReport, err = apiClient.VolumesPrune(ctx, make(client.Filters).Add("all", "1"))
assert.NilError(t, err)
assert.Check(t, is.Equal(len(pruneReport.VolumesDeleted), 2))
@@ -298,7 +297,7 @@ func TestVolumePruneAnonymous(t *testing.T) {
vNamed, err = apiClient.VolumeCreate(ctx, volume.CreateOptions{Name: "test-api141"})
assert.NilError(t, err)
pruneReport, err = clientOld.VolumesPrune(ctx, filters.Args{})
pruneReport, err = clientOld.VolumesPrune(ctx, nil)
assert.NilError(t, err)
assert.Check(t, is.Equal(len(pruneReport.VolumesDeleted), 2))
assert.Check(t, is.Contains(pruneReport.VolumesDeleted, v.Name))
@@ -333,7 +332,7 @@ VOLUME ` + volDest
err = apiClient.ContainerRemove(ctx, id, client.ContainerRemoveOptions{})
assert.NilError(t, err)
pruneReport, err := apiClient.VolumesPrune(ctx, filters.Args{})
pruneReport, err := apiClient.VolumesPrune(ctx, nil)
assert.NilError(t, err)
assert.Assert(t, is.Contains(pruneReport.VolumesDeleted, volumeName))
}

View File

@@ -2,10 +2,11 @@ package daemon
import (
"context"
"maps"
"slices"
"testing"
"time"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
"github.com/moby/moby/client"
"gotest.tools/v3/assert"
@@ -50,17 +51,19 @@ func (d *Daemon) GetService(ctx context.Context, t testing.TB, id string) *swarm
}
// GetServiceTasks returns the swarm tasks for the specified service
func (d *Daemon) GetServiceTasks(ctx context.Context, t testing.TB, service string, additionalFilters ...filters.KeyValuePair) []swarm.Task {
func (d *Daemon) GetServiceTasks(ctx context.Context, t testing.TB, service string) []swarm.Task {
return d.GetServiceTasksWithFilters(ctx, t, service, nil)
}
// GetServiceTasksWithFilters returns the swarm tasks for the specified service with additional filters
func (d *Daemon) GetServiceTasksWithFilters(ctx context.Context, t testing.TB, service string, additionalFilters client.Filters) []swarm.Task {
t.Helper()
cli := d.NewClientT(t)
defer cli.Close()
filterArgs := filters.NewArgs(
filters.Arg("desired-state", "running"),
filters.Arg("service", service),
)
for _, filter := range additionalFilters {
filterArgs.Add(filter.Key, filter.Value)
filterArgs := make(client.Filters).Add("desired-state", "running").Add("service", service)
for term, values := range additionalFilters {
filterArgs.Add(term, slices.Collect(maps.Keys(values))...)
}
options := client.TaskListOptions{

View File

@@ -7,7 +7,6 @@ import (
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"go.opentelemetry.io/otel"
@@ -53,7 +52,7 @@ func unpauseAllContainers(ctx context.Context, t testing.TB, client client.Conta
func getPausedContainers(ctx context.Context, t testing.TB, apiClient client.ContainerAPIClient) []container.Summary {
t.Helper()
containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("status", "paused")),
Filters: make(client.Filters).Add("status", "paused"),
All: true,
})
assert.Check(t, err, "failed to list containers")
@@ -163,7 +162,7 @@ func deleteAllNetworks(ctx context.Context, t testing.TB, c client.NetworkAPICli
func deleteAllPlugins(ctx context.Context, t testing.TB, c client.PluginAPIClient, protectedPlugins map[string]struct{}) {
t.Helper()
plugins, err := c.PluginList(ctx, filters.Args{})
plugins, err := c.PluginList(ctx, nil)
// Docker EE does not allow cluster-wide plugin management.
if cerrdefs.IsNotImplemented(err) {
return

View File

@@ -10,7 +10,6 @@ import (
"testing"
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/system"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/internal/testutil/fixtures/load"
@@ -200,10 +199,9 @@ func (e *Execution) UsingSnapshotter() bool {
func (e *Execution) HasExistingImage(t testing.TB, reference string) bool {
imageList, err := e.APIClient().ImageList(context.Background(), client.ImageListOptions{
All: true,
Filters: filters.NewArgs(
filters.Arg("dangling", "false"),
filters.Arg("reference", reference),
),
Filters: make(client.Filters).
Add("dangling", "false").
Add("reference", reference),
})
assert.NilError(t, err, "failed to list images")

View File

@@ -5,7 +5,6 @@ import (
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/internal/testutil"
@@ -117,7 +116,7 @@ func getExistingImages(ctx context.Context, t testing.TB, testEnv *Execution) []
apiClient := testEnv.APIClient()
imageList, err := apiClient.ImageList(ctx, client.ImageListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("dangling", "false")),
Filters: make(client.Filters).Add("dangling", "false"),
})
assert.NilError(t, err, "failed to list images")
@@ -195,7 +194,7 @@ func ProtectPlugins(ctx context.Context, t testing.TB, testEnv *Execution) {
func getExistingPlugins(ctx context.Context, t testing.TB, testEnv *Execution) []string {
t.Helper()
client := testEnv.APIClient()
pluginList, err := client.PluginList(ctx, filters.Args{})
pluginList, err := client.PluginList(ctx, nil)
// Docker EE does not allow cluster-wide plugin management.
if cerrdefs.IsNotImplemented(err) {
return []string{}

View File

@@ -1,24 +0,0 @@
package filters
import "fmt"
// invalidFilter indicates that the provided filter or its value is invalid
type invalidFilter struct {
Filter string
Value []string
}
func (e invalidFilter) Error() string {
msg := "invalid filter"
if e.Filter != "" {
msg += " '" + e.Filter
if e.Value != nil {
msg = fmt.Sprintf("%s=%s", msg, e.Value)
}
msg += "'"
}
return msg
}
// InvalidParameter marks this error as ErrInvalidParameter
func (e invalidFilter) InvalidParameter() {}

View File

@@ -1,65 +0,0 @@
/*
Package filters provides tools for encoding a mapping of keys to a set of
multiple values.
*/
package filters
import (
"encoding/json"
)
// Args stores a mapping of keys to a set of multiple values.
type Args struct {
fields map[string]map[string]bool
}
// KeyValuePair are used to initialize a new Args
type KeyValuePair struct {
Key string
Value string
}
// Arg creates a new KeyValuePair for initializing Args
func Arg(key, value string) KeyValuePair {
return KeyValuePair{Key: key, Value: value}
}
// NewArgs returns a new Args populated with the initial args
func NewArgs(initialArgs ...KeyValuePair) Args {
args := Args{fields: map[string]map[string]bool{}}
for _, arg := range initialArgs {
args.Add(arg.Key, arg.Value)
}
return args
}
// MarshalJSON returns a JSON byte representation of the Args
func (args Args) MarshalJSON() ([]byte, error) {
if len(args.fields) == 0 {
return []byte("{}"), nil
}
return json.Marshal(args.fields)
}
// ToJSON returns the Args as a JSON encoded string
func ToJSON(a Args) (string, error) {
if a.Len() == 0 {
return "", nil
}
buf, err := json.Marshal(a)
return string(buf), err
}
// Add a new value to the set of values
func (args Args) Add(key, value string) {
if _, ok := args.fields[key]; ok {
args.fields[key][value] = true
} else {
args.fields[key] = map[string]bool{value: true}
}
}
// Len returns the number of keys in the mapping
func (args Args) Len() int {
return len(args.fields)
}

View File

@@ -8,7 +8,6 @@ import (
"strconv"
"github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/versions"
)
@@ -18,7 +17,7 @@ type BuildCachePruneOptions struct {
ReservedSpace int64
MaxUsedSpace int64
MinFreeSpace int64
Filters filters.Args
Filters Filters
}
// BuildCachePruneResult holds the result from the BuildCachePrune method.
@@ -49,11 +48,7 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOpti
if opts.MinFreeSpace != 0 {
query.Set("min-free-space", strconv.Itoa(int(opts.MinFreeSpace)))
}
f, err := filters.ToJSON(opts.Filters)
if err != nil {
return BuildCachePruneResult{}, fmt.Errorf("prune could not marshal filters option: %w", err)
}
query.Set("filters", f)
opts.Filters.updateURLValues(query)
resp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/plugin"
@@ -89,7 +88,7 @@ type ContainerAPIClient interface {
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 CopyToContainerOptions) error
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
ContainersPrune(ctx context.Context, pruneFilters Filters) (container.PruneReport, error)
}
type ExecAPIClient interface {
@@ -119,7 +118,7 @@ type ImageAPIClient interface {
ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) ([]image.DeleteResponse, error)
ImageSearch(ctx context.Context, term string, options ImageSearchOptions) ([]registry.SearchResult, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (image.PruneReport, error)
ImagesPrune(ctx context.Context, pruneFilter Filters) (image.PruneReport, error)
ImageInspect(ctx context.Context, image string, _ ...ImageInspectOption) (image.InspectResponse, error)
ImageHistory(ctx context.Context, image string, _ ...ImageHistoryOption) ([]image.HistoryResponseItem, error)
@@ -136,7 +135,7 @@ type NetworkAPIClient interface {
NetworkInspectWithRaw(ctx context.Context, network string, options NetworkInspectOptions) (network.Inspect, []byte, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]network.Summary, error)
NetworkRemove(ctx context.Context, network string) error
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
NetworksPrune(ctx context.Context, pruneFilter Filters) (network.PruneReport, error)
}
// NodeAPIClient defines API client methods for the nodes
@@ -149,7 +148,7 @@ type NodeAPIClient interface {
// PluginAPIClient defines API client methods for the plugins
type PluginAPIClient interface {
PluginList(ctx context.Context, filter filters.Args) (plugin.ListResponse, error)
PluginList(ctx context.Context, filter Filters) (plugin.ListResponse, error)
PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) error
PluginEnable(ctx context.Context, name string, options PluginEnableOptions) error
PluginDisable(ctx context.Context, name string, options PluginDisableOptions) error
@@ -201,7 +200,7 @@ type VolumeAPIClient interface {
VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error)
VolumeList(ctx context.Context, options VolumeListOptions) (volume.ListResponse, error)
VolumeRemove(ctx context.Context, volumeID string, force bool) error
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (volume.PruneReport, error)
VolumesPrune(ctx context.Context, pruneFilter Filters) (volume.PruneReport, error)
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
}

View File

@@ -5,22 +5,13 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
// ConfigList returns the list of configs.
func (cli *Client) ConfigList(ctx context.Context, options ConfigListOptions) ([]swarm.Config, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/configs", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -7,7 +7,6 @@ import (
"strconv"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
)
// ContainerListOptions holds parameters to list containers with.
@@ -18,7 +17,7 @@ type ContainerListOptions struct {
Since string
Before string
Limit int
Filters filters.Args
Filters Filters
}
// ContainerList returns the list of containers in the docker host.
@@ -45,13 +44,7 @@ func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptio
query.Set("size", "1")
}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/containers/json", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/filters"
)
// ContainersPrune requests the daemon to delete unused data
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return container.PruneReport{}, err
}
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters Filters) (container.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(resp)

46
vendor/github.com/moby/moby/client/filters.go generated vendored Normal file
View File

@@ -0,0 +1,46 @@
package client
import (
"encoding/json"
"net/url"
)
// Filters describes a predicate for an API request.
//
// Each entry in the map is a filter term.
// Each term is evaluated against the set of values.
// A filter term is satisfied if any one of the values in the set is a match.
// An item matches the filters when all terms are satisfied.
//
// Like all other map types in Go, the zero value is empty and read-only.
type Filters map[string]map[string]bool
// Add appends values to the value-set of term.
//
// The receiver f is returned for chaining.
//
// f := make(Filters).Add("name", "foo", "bar").Add("status", "exited")
func (f Filters) Add(term string, values ...string) Filters {
if _, ok := f[term]; !ok {
f[term] = make(map[string]bool)
}
for _, v := range values {
f[term][v] = true
}
return f
}
// updateURLValues sets the "filters" key in values to the marshalled value of
// f, replacing any existing values. When f is empty, any existing "filters" key
// is removed.
func (f Filters) updateURLValues(values url.Values) {
if len(f) > 0 {
b, err := json.Marshal(f)
if err != nil {
panic(err) // Marshaling builtin types should never fail
}
values.Set("filters", string(b))
} else {
values.Del("filters")
}
}

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/versions"
)
@@ -30,13 +29,7 @@ func (cli *Client) ImageList(ctx context.Context, options ImageListOptions) ([]i
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return images, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
if options.All {
query.Set("all", "1")
}

View File

@@ -1,7 +1,5 @@
package client
import "github.com/moby/moby/api/types/filters"
// ImageListOptions holds parameters to list images with.
type ImageListOptions struct {
// All controls whether all images in the graph are filtered, or just
@@ -9,7 +7,7 @@ type ImageListOptions struct {
All bool
// Filters is a JSON-encoded set of filter arguments.
Filters filters.Args
Filters Filters
// SharedSize indicates whether the shared size of images should be computed.
SharedSize bool

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/image"
)
// ImagesPrune requests the daemon to delete unused data
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return image.PruneReport{}, err
}
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters Filters) (image.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -8,7 +8,6 @@ import (
"strconv"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/registry"
)
@@ -22,13 +21,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSe
query.Set("limit", strconv.Itoa(options.Limit))
}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return results, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
defer ensureReaderClosed(resp)

View File

@@ -2,8 +2,6 @@ package client
import (
"context"
"github.com/moby/moby/api/types/filters"
)
// ImageSearchOptions holds parameters to search images with.
@@ -17,6 +15,6 @@ type ImageSearchOptions struct {
//
// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
PrivilegeFunc func(context.Context) (string, error)
Filters filters.Args
Filters Filters
Limit int
}

View File

@@ -5,20 +5,13 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
)
// NetworkList returns the list of networks configured in the docker host.
func (cli *Client) NetworkList(ctx context.Context, options NetworkListOptions) ([]network.Summary, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
var networkResources []network.Summary
resp, err := cli.get(ctx, "/networks", query, nil)
defer ensureReaderClosed(resp)

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// NetworkListOptions holds parameters to filter the list of networks with.
type NetworkListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -4,17 +4,15 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/network"
)
// NetworksPrune requests the daemon to delete unused networks
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return network.PruneReport{}, err
}
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters Filters) (network.PruneReport, error) {
query := url.Values{}
pruneFilters.updateURLValues(query)
resp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(resp)

View File

@@ -5,23 +5,13 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
// NodeList returns the list of nodes.
func (cli *Client) NodeList(ctx context.Context, options NodeListOptions) ([]swarm.Node, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/nodes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -5,22 +5,15 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/plugin"
)
// PluginList returns the installed plugins
func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (plugin.ListResponse, error) {
func (cli *Client) PluginList(ctx context.Context, filter Filters) (plugin.ListResponse, error) {
var plugins plugin.ListResponse
query := url.Values{}
if filter.Len() > 0 {
filterJSON, err := filters.ToJSON(filter)
if err != nil {
return plugins, err
}
query.Set("filters", filterJSON)
}
filter.updateURLValues(query)
resp, err := cli.get(ctx, "/plugins", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
@@ -13,15 +12,7 @@ import (
func (cli *Client) SecretList(ctx context.Context, options SecretListOptions) ([]swarm.Secret, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
resp, err := cli.get(ctx, "/secrets", query, nil)
defer ensureReaderClosed(resp)
if err != nil {

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// SecretListOptions holds parameters to list secrets
type SecretListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -5,7 +5,6 @@ import (
"encoding/json"
"net/url"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/api/types/swarm"
)
@@ -13,14 +12,7 @@ import (
func (cli *Client) ServiceList(ctx context.Context, options ServiceListOptions) ([]swarm.Service, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
if options.Status {
query.Set("status", "true")

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// ConfigListOptions holds parameters to list configs
type ConfigListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// NodeListOptions holds parameters to list nodes with.
type NodeListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -1,10 +1,8 @@
package client
import "github.com/moby/moby/api/types/filters"
// ServiceListOptions holds parameters to list services with.
type ServiceListOptions struct {
Filters filters.Args
Filters Filters
// Status indicates whether the server should include the service task
// count of running and desired tasks.

View File

@@ -1,8 +1,6 @@
package client
import "github.com/moby/moby/api/types/filters"
// TaskListOptions holds parameters to list tasks with.
type TaskListOptions struct {
Filters filters.Args
Filters Filters
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/filters"
"github.com/moby/moby/client/internal"
"github.com/moby/moby/client/internal/timestamp"
)
@@ -17,7 +16,7 @@ import (
type EventsListOptions struct {
Since string
Until string
Filters filters.Args
Filters Filters
}
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
@@ -100,13 +99,7 @@ func buildEventsQueryParams(options EventsListOptions) (url.Values, error) {
query.Set("until", ts)
}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
options.Filters.updateURLValues(query)
return query, nil
}

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