Support lease filters
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
00a99c0472
commit
29b72d4ff0
@ -23,6 +23,7 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/filters"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
)
|
||||
|
||||
func adaptImage(o interface{}) filters.Adaptor {
|
||||
@ -119,6 +120,23 @@ func adaptContentStatus(status content.Status) filters.Adaptor {
|
||||
})
|
||||
}
|
||||
|
||||
func adaptLease(lease leases.Lease) filters.Adaptor {
|
||||
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
|
||||
if len(fieldpath) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
switch fieldpath[0] {
|
||||
case "id":
|
||||
return lease.ID, len(lease.ID) > 0
|
||||
case "labels":
|
||||
return checkMap(fieldpath[1:], lease.Labels)
|
||||
}
|
||||
|
||||
return "", false
|
||||
})
|
||||
}
|
||||
|
||||
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
|
||||
if len(m) == 0 {
|
||||
return "", false
|
||||
|
@ -109,14 +109,16 @@ func TestContentLeased(t *testing.T) {
|
||||
|
||||
func createLease(ctx context.Context, db *DB, name string) (context.Context, func() error, error) {
|
||||
if err := db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := NewLeaseManager(tx).Create(ctx, name, nil)
|
||||
_, err := NewLeaseManager(tx).Create(ctx, leases.WithID(name))
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return leases.WithLease(ctx, name), func() error {
|
||||
return db.Update(func(tx *bolt.Tx) error {
|
||||
return NewLeaseManager(tx).Delete(ctx, name)
|
||||
return NewLeaseManager(tx).Delete(ctx, leases.Lease{
|
||||
ID: name,
|
||||
})
|
||||
})
|
||||
}, nil
|
||||
}
|
||||
@ -126,7 +128,7 @@ func checkContentLeased(ctx context.Context, db *DB, dgst digest.Digest) error {
|
||||
if !ok {
|
||||
return errors.New("no namespace in context")
|
||||
}
|
||||
lease, ok := leases.Lease(ctx)
|
||||
lease, ok := leases.FromContext(ctx)
|
||||
if !ok {
|
||||
return errors.New("no lease in context")
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/filters"
|
||||
"github.com/containerd/containerd/leases"
|
||||
"github.com/containerd/containerd/metadata/boltutil"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
@ -110,12 +111,17 @@ func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease) error {
|
||||
}
|
||||
|
||||
// List lists all active leases
|
||||
func (lm *LeaseManager) List(ctx context.Context, filter ...string) ([]leases.Lease, error) {
|
||||
func (lm *LeaseManager) List(ctx context.Context, fs ...string) ([]leases.Lease, error) {
|
||||
namespace, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter, err := filters.ParseAll(fs...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
var ll []leases.Lease
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
@ -146,7 +152,9 @@ func (lm *LeaseManager) List(ctx context.Context, filter ...string) ([]leases.Le
|
||||
}
|
||||
l.Labels = labels
|
||||
|
||||
ll = append(ll, l)
|
||||
if filter.Match(adaptLease(l)) {
|
||||
ll = append(ll, l)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
@ -107,3 +107,153 @@ func TestLeases(t *testing.T) {
|
||||
t.Fatalf("Expected no leases, found %d: %v", len(listed), listed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLeasesList(t *testing.T) {
|
||||
ctx, db, cancel := testEnv(t)
|
||||
defer cancel()
|
||||
|
||||
testset := [][]leases.Opt{
|
||||
{
|
||||
leases.WithID("lease1"),
|
||||
leases.WithLabels(map[string]string{
|
||||
"label1": "value1",
|
||||
"label3": "other",
|
||||
}),
|
||||
},
|
||||
{
|
||||
leases.WithID("lease2"),
|
||||
leases.WithLabels(map[string]string{
|
||||
"label1": "value1",
|
||||
"label2": "",
|
||||
"label3": "other",
|
||||
}),
|
||||
},
|
||||
{
|
||||
leases.WithID("lease3"),
|
||||
leases.WithLabels(map[string]string{
|
||||
"label1": "value2",
|
||||
"label2": "something",
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
// Insert all
|
||||
for _, opts := range testset {
|
||||
if err := db.Update(func(tx *bolt.Tx) error {
|
||||
lm := NewLeaseManager(tx)
|
||||
_, err := lm.Create(ctx, opts...)
|
||||
return err
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, testcase := range []struct {
|
||||
name string
|
||||
filters []string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "All",
|
||||
filters: []string{},
|
||||
expected: []string{"lease1", "lease2", "lease3"},
|
||||
},
|
||||
{
|
||||
name: "ID",
|
||||
filters: []string{"id==lease1"},
|
||||
expected: []string{"lease1"},
|
||||
},
|
||||
{
|
||||
name: "IDx2",
|
||||
filters: []string{"id==lease1", "id==lease2"},
|
||||
expected: []string{"lease1", "lease2"},
|
||||
},
|
||||
{
|
||||
name: "Label1",
|
||||
filters: []string{"labels.label1"},
|
||||
expected: []string{"lease1", "lease2", "lease3"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "Label1value1",
|
||||
filters: []string{"labels.label1==value1"},
|
||||
expected: []string{"lease1", "lease2"},
|
||||
},
|
||||
{
|
||||
name: "Label1value2",
|
||||
filters: []string{"labels.label1==value2"},
|
||||
expected: []string{"lease3"},
|
||||
},
|
||||
{
|
||||
name: "Label2",
|
||||
filters: []string{"labels.label2"},
|
||||
expected: []string{"lease3"},
|
||||
},
|
||||
{
|
||||
name: "Label3",
|
||||
filters: []string{"labels.label2", "labels.label3"},
|
||||
expected: []string{"lease1", "lease2", "lease3"},
|
||||
},
|
||||
} {
|
||||
t.Run(testcase.name, func(t *testing.T) {
|
||||
if err := db.View(func(tx *bolt.Tx) error {
|
||||
lm := NewLeaseManager(tx)
|
||||
results, err := lm.List(ctx, testcase.filters...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(results) != len(testcase.expected) {
|
||||
t.Errorf("length of result does not match expected: %v != %v", len(results), len(testcase.expected))
|
||||
}
|
||||
|
||||
expectedMap := map[string]struct{}{}
|
||||
for _, expected := range testcase.expected {
|
||||
expectedMap[expected] = struct{}{}
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
if _, ok := expectedMap[result.ID]; !ok {
|
||||
t.Errorf("unexpected match: %v", result.ID)
|
||||
} else {
|
||||
delete(expectedMap, result.ID)
|
||||
}
|
||||
}
|
||||
if len(expectedMap) > 0 {
|
||||
for match := range expectedMap {
|
||||
t.Errorf("missing match: %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// delete everything to test it
|
||||
for _, opts := range testset {
|
||||
var lease leases.Lease
|
||||
for _, opt := range opts {
|
||||
if err := opt(&lease); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.Update(func(tx *bolt.Tx) error {
|
||||
lm := NewLeaseManager(tx)
|
||||
return lm.Delete(ctx, lease)
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// try it again, get nil
|
||||
if err := db.Update(func(tx *bolt.Tx) error {
|
||||
lm := NewLeaseManager(tx)
|
||||
return lm.Delete(ctx, lease)
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user