mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add reference filter and deprecated filter param…
… for `docker images`. This deprecates the `filter` param for the `/images` endpoint and make a new filter called `reference` to replace it. It does change the CLI side (still possible to do `docker images busybox:musl`) but changes the cli code to use the filter instead (so that `docker images --filter busybox:musl` and `docker images busybox:musl` act the same). Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
90d10203a4
commit
820b809e70
10 changed files with 53 additions and 56 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/backend"
|
"github.com/docker/docker/api/types/backend"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
@ -25,7 +26,7 @@ type containerBackend interface {
|
||||||
type imageBackend interface {
|
type imageBackend interface {
|
||||||
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error)
|
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error)
|
||||||
ImageHistory(imageName string) ([]*types.ImageHistory, error)
|
ImageHistory(imageName string) ([]*types.ImageHistory, error)
|
||||||
Images(filterArgs string, filter string, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error)
|
Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error)
|
||||||
LookupImage(name string) (*types.ImageInspect, error)
|
LookupImage(name string) (*types.ImageInspect, error)
|
||||||
TagImage(imageName, repository, tag string) error
|
TagImage(imageName, repository, tag string) error
|
||||||
ImagesPrune(config *types.ImagesPruneConfig) (*types.ImagesPruneReport, error)
|
ImagesPrune(config *types.ImagesPruneConfig) (*types.ImagesPruneReport, error)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/backend"
|
"github.com/docker/docker/api/types/backend"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
|
@ -247,8 +248,18 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: The filter parameter could just be a match filter
|
imageFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||||
images, err := s.backend.Images(r.Form.Get("filters"), r.Form.Get("filter"), httputils.BoolValue(r, "all"), false)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
version := httputils.VersionFromContext(ctx)
|
||||||
|
filterParam := r.Form.Get("filter")
|
||||||
|
if versions.LessThan(version, "1.28") && filterParam != "" {
|
||||||
|
imageFilters.Add("reference", filterParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
images, err := s.backend.Images(imageFilters, httputils.BoolValue(r, "all"), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,6 @@ type ImageImportOptions struct {
|
||||||
|
|
||||||
// ImageListOptions holds parameters to filter the list of images with.
|
// ImageListOptions holds parameters to filter the list of images with.
|
||||||
type ImageListOptions struct {
|
type ImageListOptions struct {
|
||||||
MatchName string
|
|
||||||
All bool
|
All bool
|
||||||
Filters filters.Args
|
Filters filters.Args
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,14 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
func runImages(dockerCli *command.DockerCli, opts imagesOptions) error {
|
func runImages(dockerCli *command.DockerCli, opts imagesOptions) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
filters := opts.filter.Value()
|
||||||
|
if opts.matchName != "" {
|
||||||
|
filters.Add("reference", opts.matchName)
|
||||||
|
}
|
||||||
|
|
||||||
options := types.ImageListOptions{
|
options := types.ImageListOptions{
|
||||||
MatchName: opts.matchName,
|
|
||||||
All: opts.all,
|
All: opts.all,
|
||||||
Filters: opts.filter.Value(),
|
Filters: filters,
|
||||||
}
|
}
|
||||||
|
|
||||||
images, err := dockerCli.Client().ImageList(ctx, options)
|
images, err := dockerCli.Client().ImageList(ctx, options)
|
||||||
|
|
|
@ -21,10 +21,6 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions
|
||||||
}
|
}
|
||||||
query.Set("filters", filterJSON)
|
query.Set("filters", filterJSON)
|
||||||
}
|
}
|
||||||
if options.MatchName != "" {
|
|
||||||
// FIXME rename this parameter, to not be confused with the filters flag
|
|
||||||
query.Set("filter", options.MatchName)
|
|
||||||
}
|
|
||||||
if options.All {
|
if options.All {
|
||||||
query.Set("all", "1")
|
query.Set("all", "1")
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,17 +48,6 @@ func TestImageList(t *testing.T) {
|
||||||
"filters": "",
|
"filters": "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
options: types.ImageListOptions{
|
|
||||||
All: true,
|
|
||||||
MatchName: "image_name",
|
|
||||||
},
|
|
||||||
expectedQueryParams: map[string]string{
|
|
||||||
"all": "1",
|
|
||||||
"filter": "image_name",
|
|
||||||
"filters": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
options: types.ImageListOptions{
|
options: types.ImageListOptions{
|
||||||
Filters: filters,
|
Filters: filters,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/distribution/digest"
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/pkg/directory"
|
"github.com/docker/docker/pkg/directory"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
|
@ -44,7 +45,7 @@ func (daemon *Daemon) SystemDiskUsage() (*types.DiskUsage, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all top images with extra attributes
|
// Get all top images with extra attributes
|
||||||
allImages, err := daemon.Images("", "", false, true)
|
allImages, err := daemon.Images(filters.NewArgs(), false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve image list: %v", err)
|
return nil, fmt.Errorf("failed to retrieve image list: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,17 @@ package daemon
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var acceptedImageFilterTags = map[string]bool{
|
var acceptedImageFilterTags = map[string]bool{
|
||||||
|
@ -22,6 +21,7 @@ var acceptedImageFilterTags = map[string]bool{
|
||||||
"label": true,
|
"label": true,
|
||||||
"before": true,
|
"before": true,
|
||||||
"since": true,
|
"since": true,
|
||||||
|
"reference": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// byCreated is a temporary type used to sort a list of images by creation
|
// byCreated is a temporary type used to sort a list of images by creation
|
||||||
|
@ -42,17 +42,13 @@ func (daemon *Daemon) Map() map[image.ID]*image.Image {
|
||||||
// filter is a shell glob string applied to repository names. The argument
|
// filter is a shell glob string applied to repository names. The argument
|
||||||
// named all controls whether all images in the graph are filtered, or just
|
// named all controls whether all images in the graph are filtered, or just
|
||||||
// the heads.
|
// the heads.
|
||||||
func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) {
|
func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) {
|
||||||
var (
|
var (
|
||||||
allImages map[image.ID]*image.Image
|
allImages map[image.ID]*image.Image
|
||||||
err error
|
err error
|
||||||
danglingOnly = false
|
danglingOnly = false
|
||||||
)
|
)
|
||||||
|
|
||||||
imageFilters, err := filters.FromParam(filterArgs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := imageFilters.Validate(acceptedImageFilterTags); err != nil {
|
if err := imageFilters.Validate(acceptedImageFilterTags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -93,16 +89,6 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs
|
||||||
var allLayers map[layer.ChainID]layer.Layer
|
var allLayers map[layer.ChainID]layer.Layer
|
||||||
var allContainers []*container.Container
|
var allContainers []*container.Container
|
||||||
|
|
||||||
var filterTagged bool
|
|
||||||
if filter != "" {
|
|
||||||
filterRef, err := reference.ParseNamed(filter)
|
|
||||||
if err == nil { // parse error means wildcard repo
|
|
||||||
if _, ok := filterRef.(reference.NamedTagged); ok {
|
|
||||||
filterTagged = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for id, img := range allImages {
|
for id, img := range allImages {
|
||||||
if beforeFilter != nil {
|
if beforeFilter != nil {
|
||||||
if img.Created.Equal(beforeFilter.Created) || img.Created.After(beforeFilter.Created) {
|
if img.Created.Equal(beforeFilter.Created) || img.Created.After(beforeFilter.Created) {
|
||||||
|
@ -145,12 +131,16 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs
|
||||||
newImage := newImage(img, size)
|
newImage := newImage(img, size)
|
||||||
|
|
||||||
for _, ref := range daemon.referenceStore.References(id.Digest()) {
|
for _, ref := range daemon.referenceStore.References(id.Digest()) {
|
||||||
if filter != "" { // filter by tag/repo name
|
if imageFilters.Include("reference") {
|
||||||
if filterTagged { // filter by tag, require full ref match
|
var found bool
|
||||||
if ref.String() != filter {
|
var matchErr error
|
||||||
continue
|
for _, pattern := range imageFilters.Get("reference") {
|
||||||
|
found, matchErr = reference.Match(pattern, ref)
|
||||||
|
if matchErr != nil {
|
||||||
|
return nil, matchErr
|
||||||
}
|
}
|
||||||
} else if matched, err := path.Match(filter, ref.Name()); !matched || err != nil { // name only match, FIXME: docs say exact
|
}
|
||||||
|
if !found {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +158,7 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs
|
||||||
//dangling=false case, so dangling image is not needed
|
//dangling=false case, so dangling image is not needed
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if filter != "" { // skip images with no references if filtering by tag
|
if imageFilters.Include("reference") { // skip images with no references if filtering by reference
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newImage.RepoDigests = []string{"<none>@<none>"}
|
newImage.RepoDigests = []string{"<none>@<none>"}
|
||||||
|
|
|
@ -20,23 +20,29 @@ The following list of features are deprecated in Engine.
|
||||||
To learn more about Docker Engine's deprecation policy,
|
To learn more about Docker Engine's deprecation policy,
|
||||||
see [Feature Deprecation Policy](https://docs.docker.com/engine/#feature-deprecation-policy).
|
see [Feature Deprecation Policy](https://docs.docker.com/engine/#feature-deprecation-policy).
|
||||||
|
|
||||||
|
## `filter` param for `/images/json` endpoint
|
||||||
|
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
|
||||||
|
|
||||||
|
**Target For Removal In Release: v1.16**
|
||||||
|
|
||||||
|
The `filter` param to filter the list of image by reference (name or name:tag) is now implemented as a regular filter, named `reference`.
|
||||||
|
|
||||||
### `repository:shortid` image references
|
### `repository:shortid` image references
|
||||||
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/)**
|
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
|
||||||
|
|
||||||
**Target For Removal In Release: v1.16**
|
**Target For Removal In Release: v1.16**
|
||||||
|
|
||||||
`repository:shortid` syntax for referencing images is very little used, collides with with tag references can be confused with digest references.
|
`repository:shortid` syntax for referencing images is very little used, collides with with tag references can be confused with digest references.
|
||||||
|
|
||||||
### `docker daemon` subcommand
|
### `docker daemon` subcommand
|
||||||
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/)**
|
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
|
||||||
|
|
||||||
**Target For Removal In Release: v1.16**
|
**Target For Removal In Release: v1.16**
|
||||||
|
|
||||||
The daemon is moved to a separate binary (`dockerd`), and should be used instead.
|
The daemon is moved to a separate binary (`dockerd`), and should be used instead.
|
||||||
|
|
||||||
### Duplicate keys with conflicting values in engine labels
|
### Duplicate keys with conflicting values in engine labels
|
||||||
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/)**
|
**Deprecated In Release: [v1.13](https://github.com/docker/docker/releases/tag/v1.13.0)**
|
||||||
|
|
||||||
**Target For Removal In Release: v1.16**
|
**Target For Removal In Release: v1.16**
|
||||||
|
|
||||||
|
|
|
@ -1733,7 +1733,7 @@ references on the command line.
|
||||||
- `label=key` or `label="key=value"` of an image label
|
- `label=key` or `label="key=value"` of an image label
|
||||||
- `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
|
- `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
|
||||||
- `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
|
- `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
|
||||||
- **filter** - only return images with the specified name
|
- `reference`=(`<image-name>[:<tag>]`)
|
||||||
|
|
||||||
### Build image from a Dockerfile
|
### Build image from a Dockerfile
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue