Skip to content

Commit

Permalink
feature: support images filter flag
Browse files Browse the repository at this point in the history
Signed-off-by: zhangyue <[email protected]>
  • Loading branch information
zhangyue committed Nov 5, 2018
1 parent 9bf53d1 commit 2139681
Show file tree
Hide file tree
Showing 17 changed files with 259 additions and 35 deletions.
37 changes: 37 additions & 0 deletions apis/filters/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package filters
import (
"encoding/json"
"errors"
"path"
"strings"
)

Expand Down Expand Up @@ -36,6 +37,12 @@ func NewArgs(initialArgs ...KeyValuePair) Args {
return args
}

// Contains returns true if the key exists in the mapping
func (args Args) Contains(field string) bool {
_, ok := args.fields[field]
return ok
}

// Get returns the list of values associated with the key
func (args Args) Get(key string) []string {
values := args.fields[key]
Expand Down Expand Up @@ -150,3 +157,33 @@ func FromParam(p string) (Args, error) {
}
return args, nil
}

// FromFilterOpts parse key=value to Args string from cli opts
func FromFilterOpts(filter []string) (Args, error) {
filterArgs := NewArgs()

for _, f := range filter {
var err error
filterArgs, err = ParseFlag(f, filterArgs)
if err != nil {
return filterArgs, err
}
}
return filterArgs, nil
}

// Validate compared the set of accepted keys against the keys in the mapping.
// An error is returned if any mapping keys are not in the accepted set.
func (args Args) Validate(accepted map[string]bool) error {
for name := range args.fields {
if !accepted[name] {
return errors.New("invalid filter " + name)
}
}
return nil
}

// FamiliarMatch decide the ref match the pattern or not
func FamiliarMatch(pattern string, ref string) (bool, error) {
return path.Match(pattern, ref)
}
27 changes: 27 additions & 0 deletions apis/filters/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,30 @@ func TestFromParam(t *testing.T) {
}
}
}

func TestFromFilterOpts(t *testing.T) {
filterOpts := []string{
"reference=img1",
"since=img2",
"before=img3",
"reference=img3",
}

args, err := FromFilterOpts(filterOpts)
if err != nil {
t.Fatal(err)
}

images := args.Get("reference")
if len(images) != 2 {
t.Fatal("Expected two values of reference key, but got one.")
}

if !args.Contains("since") {
t.Fatal("Excepted get since key, but got none.")
}

if !args.Contains("before") {
t.Fatal("Excepted get before key, but got none.")
}
}
10 changes: 7 additions & 3 deletions apis/server/image_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"time"

"github.com/alibaba/pouch/apis/filters"
"github.com/alibaba/pouch/apis/metrics"
"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/daemon/mgr"
Expand Down Expand Up @@ -75,9 +76,12 @@ func (s *Server) getImage(ctx context.Context, rw http.ResponseWriter, req *http
}

func (s *Server) listImages(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
filters := req.FormValue("filters")
filter, err := filters.FromParam(req.FormValue("filters"))
if err != nil {
return err
}

imageList, err := s.ImageMgr.ListImages(ctx, filters)
imageList, err := s.ImageMgr.ListImages(ctx, filter)
if err != nil {
logrus.Errorf("failed to list images: %v", err)
return err
Expand All @@ -91,7 +95,7 @@ func (s *Server) searchImages(ctx context.Context, rw http.ResponseWriter, req *

searchResultItem, err := s.ImageMgr.SearchImages(ctx, searchPattern, registry)
if err != nil {
logrus.Errorf("failed to search images from resgitry: %v", err)
logrus.Errorf("failed to search images from registry: %v", err)
return err
}
return EncodeResponse(rw, http.StatusOK, searchResultItem)
Expand Down
2 changes: 0 additions & 2 deletions apis/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,6 @@ paths:
A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
- `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
- `dangling=true`
- `label=key` or `label="key=value"` of an image label
- `reference`=(`<image-name>[:<tag>]`)
- `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
type: "string"
Expand Down
12 changes: 3 additions & 9 deletions cli/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,9 @@ func (e *EventsCommand) runEvents() error {
ctx := context.Background()
apiClient := e.cli.Client()

eventFilterArgs := filters.NewArgs()

// TODO: parse params
for _, f := range e.filter {
var err error
eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
if err != nil {
return err
}
eventFilterArgs, err := filters.FromFilterOpts(e.filter)
if err != nil {
return err
}

responseBody, err := apiClient.Events(ctx, e.since, e.until, eventFilterArgs)
Expand Down
13 changes: 10 additions & 3 deletions cli/image_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"context"
"fmt"

"github.com/alibaba/pouch/apis/filters"
"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/pkg/reference"
"github.com/alibaba/pouch/pkg/utils"

digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -38,6 +39,7 @@ type ImagesCommand struct {
flagQuiet bool
flagDigest bool
flagNoTrunc bool
flagFilter []string
}

// Init initialize images command.
Expand All @@ -63,17 +65,22 @@ func (i *ImagesCommand) addFlags() {
flagSet.BoolVarP(&i.flagQuiet, "quiet", "q", false, "Only show image numeric ID")
flagSet.BoolVar(&i.flagDigest, "digest", false, "Show images with digest")
flagSet.BoolVar(&i.flagNoTrunc, "no-trunc", false, "Do not truncate output")
flagSet.StringSliceVarP(&i.flagFilter, "filter", "f", []string{}, "Filter output based on conditions provided")
}

// runImages is the entry of images container command.
func (i *ImagesCommand) runImages(args []string) error {
ctx := context.Background()
apiClient := i.cli.Client()

imageList, err := apiClient.ImageList(ctx)
imageFilterArgs, err := filters.FromFilterOpts(i.flagFilter)
if err != nil {
return fmt.Errorf("failed to get image list: %v", err)
return err
}

imageList, err := apiClient.ImageList(ctx, imageFilterArgs)
if err != nil {
return fmt.Errorf("failed to get image list: %v", err)
}

if i.flagQuiet {
Expand Down
18 changes: 15 additions & 3 deletions client/image_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@ package client

import (
"context"
"net/url"

"github.com/alibaba/pouch/apis/filters"
"github.com/alibaba/pouch/apis/types"
)

// ImageList requests daemon to list all images
func (client *APIClient) ImageList(ctx context.Context) ([]types.ImageInfo, error) {
resp, err := client.get(ctx, "/images/json", nil, nil)
func (client *APIClient) ImageList(ctx context.Context, filter filters.Args) ([]types.ImageInfo, error) {
query := url.Values{}

if filter.Len() > 0 {
filtersJSON, err := filters.ToParam(filter)
if err != nil {
return nil, err
}

query.Set("filters", filtersJSON)
}

resp, err := client.get(ctx, "/images/json", query, nil)
if err != nil {
return nil, err
}
Expand All @@ -19,5 +32,4 @@ func (client *APIClient) ImageList(ctx context.Context) ([]types.ImageInfo, erro
ensureCloseReader(resp)

return imageList, err

}
5 changes: 3 additions & 2 deletions client/image_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import (

"github.com/alibaba/pouch/apis/types"

"github.com/alibaba/pouch/apis/filters"
"github.com/stretchr/testify/assert"
)

func TestImageListServerError(t *testing.T) {
client := &APIClient{
HTTPCli: newMockClient(errorMockResponse(http.StatusInternalServerError, "Server error")),
}
_, err := client.ImageList(context.Background())
_, err := client.ImageList(context.Background(), filters.NewArgs())
if err == nil || !strings.Contains(err.Error(), "Server error") {
t.Fatalf("expected a Server Error, got %v", err)
}
Expand Down Expand Up @@ -62,7 +63,7 @@ func TestImageList(t *testing.T) {
HTTPCli: httpClient,
}

image, err := client.ImageList(context.Background())
image, err := client.ImageList(context.Background(), filters.NewArgs())
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type ContainerAPIClient interface {

// ImageAPIClient defines methods of Image client.
type ImageAPIClient interface {
ImageList(ctx context.Context) ([]types.ImageInfo, error)
ImageList(ctx context.Context, filters filters.Args) ([]types.ImageInfo, error)
ImageInspect(ctx context.Context, name string) (types.ImageInfo, error)
ImagePull(ctx context.Context, name, tag, encodedAuth string) (io.ReadCloser, error)
ImageRemove(ctx context.Context, name string, force bool) error
Expand Down
3 changes: 2 additions & 1 deletion cri/v1alpha1/cri.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
goruntime "runtime"
"time"

"github.com/alibaba/pouch/apis/filters"
apitypes "github.com/alibaba/pouch/apis/types"
anno "github.com/alibaba/pouch/cri/annotations"
cni "github.com/alibaba/pouch/cri/ocicni"
Expand Down Expand Up @@ -1023,7 +1024,7 @@ func (c *CriManager) Status(ctx context.Context, r *runtime.StatusRequest) (*run
// ListImages lists existing images.
func (c *CriManager) ListImages(ctx context.Context, r *runtime.ListImagesRequest) (*runtime.ListImagesResponse, error) {
// TODO: handle image list filters.
imageList, err := c.ImageMgr.ListImages(ctx, "")
imageList, err := c.ImageMgr.ListImages(ctx, filters.NewArgs())
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion cri/v1alpha2/cri.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"strconv"
"time"

"github.com/alibaba/pouch/apis/filters"
apitypes "github.com/alibaba/pouch/apis/types"
anno "github.com/alibaba/pouch/cri/annotations"
runtime "github.com/alibaba/pouch/cri/apis/v1alpha2"
Expand Down Expand Up @@ -1307,7 +1308,7 @@ func (c *CriManager) ListImages(ctx context.Context, r *runtime.ListImagesReques
}(time.Now())

// TODO: handle image list filters.
imageList, err := c.ImageMgr.ListImages(ctx, "")
imageList, err := c.ImageMgr.ListImages(ctx, filters.NewArgs())
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 2139681

Please sign in to comment.