cmd/ctr, service/containers: implement container filter

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day
2017-06-21 15:29:58 -07:00
parent 3332042ab6
commit 396d89e423
16 changed files with 409 additions and 189 deletions

View File

@@ -2,11 +2,13 @@ package metadata
import (
"context"
"strings"
"time"
"github.com/boltdb/bolt"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/filters"
"github.com/containerd/containerd/identifiers"
"github.com/containerd/containerd/namespaces"
"github.com/gogo/protobuf/proto"
@@ -43,16 +45,22 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
return container, nil
}
func (s *containerStore) List(ctx context.Context, filter string) ([]containers.Container, error) {
func (s *containerStore) List(ctx context.Context, fs ...filters.Filter) ([]containers.Container, error) {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
}
var (
m []containers.Container
bkt = getContainersBucket(s.tx, namespace)
m []containers.Container
filter = filters.Filter(filters.Any(fs))
bkt = getContainersBucket(s.tx, namespace)
)
if len(fs) == 0 {
filter = filters.Always
}
if bkt == nil {
return m, nil
}
@@ -66,7 +74,10 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
if err := readContainer(&container, cbkt); err != nil {
return errors.Wrap(err, "failed to read container")
}
m = append(m, container)
if filter.Match(adaptContainer(container)) {
m = append(m, container)
}
return nil
}); err != nil {
return nil, err
@@ -75,6 +86,46 @@ func (s *containerStore) List(ctx context.Context, filter string) ([]containers.
return m, nil
}
func adaptContainer(o interface{}) filters.Adaptor {
obj := o.(containers.Container)
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
if len(fieldpath) == 0 {
return "", false
}
switch fieldpath[0] {
case "id":
return obj.ID, len(obj.ID) > 0
case "runtime":
if len(fieldpath) <= 1 {
return "", false
}
switch fieldpath[1] {
case "name":
return obj.Runtime.Name, len(obj.Runtime.Name) > 0
default:
return "", false
}
case "image":
return obj.Image, len(obj.Image) > 0
case "labels":
return checkMap(fieldpath[1:], obj.Labels)
}
return "", false
})
}
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
if len(m) == 0 {
return "", false
}
value, ok := m[strings.Join(fieldpath, ".")]
return value, ok
}
func (s *containerStore) Create(ctx context.Context, container containers.Container) (containers.Container, error) {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
@@ -268,14 +319,22 @@ func writeContainer(container *containers.Container, bkt *bolt.Bucket) error {
return err
}
}
lbkt, err := bkt.CreateBucket(bucketKeyLabels)
if err != nil {
return err
}
for k, v := range container.Labels {
if v == "" {
delete(container.Labels, k) // remove since we don't actually set it
continue
}
if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
return err
}
}
return nil
}

View File

@@ -136,7 +136,7 @@ func (s *namespaceStore) namespaceEmpty(ctx context.Context, namespace string) (
}
containerStore := NewContainerStore(s.tx)
containers, err := containerStore.List(ctx, "")
containers, err := containerStore.List(ctx)
if err != nil {
return false, err
}