Skip to content

Commit 29b72d4

Browse files
committed
Support lease filters
Signed-off-by: Derek McGowan <[email protected]>
1 parent 00a99c0 commit 29b72d4

File tree

4 files changed

+183
-5
lines changed

4 files changed

+183
-5
lines changed

metadata/adaptors.go

+18
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/containerd/containerd/content"
2424
"github.com/containerd/containerd/filters"
2525
"github.com/containerd/containerd/images"
26+
"github.com/containerd/containerd/leases"
2627
)
2728

2829
func adaptImage(o interface{}) filters.Adaptor {
@@ -119,6 +120,23 @@ func adaptContentStatus(status content.Status) filters.Adaptor {
119120
})
120121
}
121122

123+
func adaptLease(lease leases.Lease) filters.Adaptor {
124+
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
125+
if len(fieldpath) == 0 {
126+
return "", false
127+
}
128+
129+
switch fieldpath[0] {
130+
case "id":
131+
return lease.ID, len(lease.ID) > 0
132+
case "labels":
133+
return checkMap(fieldpath[1:], lease.Labels)
134+
}
135+
136+
return "", false
137+
})
138+
}
139+
122140
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
123141
if len(m) == 0 {
124142
return "", false

metadata/content_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,16 @@ func TestContentLeased(t *testing.T) {
109109

110110
func createLease(ctx context.Context, db *DB, name string) (context.Context, func() error, error) {
111111
if err := db.Update(func(tx *bolt.Tx) error {
112-
_, err := NewLeaseManager(tx).Create(ctx, name, nil)
112+
_, err := NewLeaseManager(tx).Create(ctx, leases.WithID(name))
113113
return err
114114
}); err != nil {
115115
return nil, nil, err
116116
}
117117
return leases.WithLease(ctx, name), func() error {
118118
return db.Update(func(tx *bolt.Tx) error {
119-
return NewLeaseManager(tx).Delete(ctx, name)
119+
return NewLeaseManager(tx).Delete(ctx, leases.Lease{
120+
ID: name,
121+
})
120122
})
121123
}, nil
122124
}
@@ -126,7 +128,7 @@ func checkContentLeased(ctx context.Context, db *DB, dgst digest.Digest) error {
126128
if !ok {
127129
return errors.New("no namespace in context")
128130
}
129-
lease, ok := leases.Lease(ctx)
131+
lease, ok := leases.FromContext(ctx)
130132
if !ok {
131133
return errors.New("no lease in context")
132134
}

metadata/leases.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/boltdb/bolt"
2424
"github.com/containerd/containerd/errdefs"
25+
"github.com/containerd/containerd/filters"
2526
"github.com/containerd/containerd/leases"
2627
"github.com/containerd/containerd/metadata/boltutil"
2728
"github.com/containerd/containerd/namespaces"
@@ -110,12 +111,17 @@ func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease) error {
110111
}
111112

112113
// List lists all active leases
113-
func (lm *LeaseManager) List(ctx context.Context, filter ...string) ([]leases.Lease, error) {
114+
func (lm *LeaseManager) List(ctx context.Context, fs ...string) ([]leases.Lease, error) {
114115
namespace, err := namespaces.NamespaceRequired(ctx)
115116
if err != nil {
116117
return nil, err
117118
}
118119

120+
filter, err := filters.ParseAll(fs...)
121+
if err != nil {
122+
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
123+
}
124+
119125
var ll []leases.Lease
120126

121127
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
@@ -146,7 +152,9 @@ func (lm *LeaseManager) List(ctx context.Context, filter ...string) ([]leases.Le
146152
}
147153
l.Labels = labels
148154

149-
ll = append(ll, l)
155+
if filter.Match(adaptLease(l)) {
156+
ll = append(ll, l)
157+
}
150158

151159
return nil
152160
}); err != nil {

metadata/leases_test.go

+150
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,153 @@ func TestLeases(t *testing.T) {
107107
t.Fatalf("Expected no leases, found %d: %v", len(listed), listed)
108108
}
109109
}
110+
111+
func TestLeasesList(t *testing.T) {
112+
ctx, db, cancel := testEnv(t)
113+
defer cancel()
114+
115+
testset := [][]leases.Opt{
116+
{
117+
leases.WithID("lease1"),
118+
leases.WithLabels(map[string]string{
119+
"label1": "value1",
120+
"label3": "other",
121+
}),
122+
},
123+
{
124+
leases.WithID("lease2"),
125+
leases.WithLabels(map[string]string{
126+
"label1": "value1",
127+
"label2": "",
128+
"label3": "other",
129+
}),
130+
},
131+
{
132+
leases.WithID("lease3"),
133+
leases.WithLabels(map[string]string{
134+
"label1": "value2",
135+
"label2": "something",
136+
}),
137+
},
138+
}
139+
140+
// Insert all
141+
for _, opts := range testset {
142+
if err := db.Update(func(tx *bolt.Tx) error {
143+
lm := NewLeaseManager(tx)
144+
_, err := lm.Create(ctx, opts...)
145+
return err
146+
}); err != nil {
147+
t.Fatal(err)
148+
}
149+
}
150+
151+
for _, testcase := range []struct {
152+
name string
153+
filters []string
154+
expected []string
155+
}{
156+
{
157+
name: "All",
158+
filters: []string{},
159+
expected: []string{"lease1", "lease2", "lease3"},
160+
},
161+
{
162+
name: "ID",
163+
filters: []string{"id==lease1"},
164+
expected: []string{"lease1"},
165+
},
166+
{
167+
name: "IDx2",
168+
filters: []string{"id==lease1", "id==lease2"},
169+
expected: []string{"lease1", "lease2"},
170+
},
171+
{
172+
name: "Label1",
173+
filters: []string{"labels.label1"},
174+
expected: []string{"lease1", "lease2", "lease3"},
175+
},
176+
177+
{
178+
name: "Label1value1",
179+
filters: []string{"labels.label1==value1"},
180+
expected: []string{"lease1", "lease2"},
181+
},
182+
{
183+
name: "Label1value2",
184+
filters: []string{"labels.label1==value2"},
185+
expected: []string{"lease3"},
186+
},
187+
{
188+
name: "Label2",
189+
filters: []string{"labels.label2"},
190+
expected: []string{"lease3"},
191+
},
192+
{
193+
name: "Label3",
194+
filters: []string{"labels.label2", "labels.label3"},
195+
expected: []string{"lease1", "lease2", "lease3"},
196+
},
197+
} {
198+
t.Run(testcase.name, func(t *testing.T) {
199+
if err := db.View(func(tx *bolt.Tx) error {
200+
lm := NewLeaseManager(tx)
201+
results, err := lm.List(ctx, testcase.filters...)
202+
if err != nil {
203+
return err
204+
}
205+
206+
if len(results) != len(testcase.expected) {
207+
t.Errorf("length of result does not match expected: %v != %v", len(results), len(testcase.expected))
208+
}
209+
210+
expectedMap := map[string]struct{}{}
211+
for _, expected := range testcase.expected {
212+
expectedMap[expected] = struct{}{}
213+
}
214+
215+
for _, result := range results {
216+
if _, ok := expectedMap[result.ID]; !ok {
217+
t.Errorf("unexpected match: %v", result.ID)
218+
} else {
219+
delete(expectedMap, result.ID)
220+
}
221+
}
222+
if len(expectedMap) > 0 {
223+
for match := range expectedMap {
224+
t.Errorf("missing match: %v", match)
225+
}
226+
}
227+
228+
return nil
229+
}); err != nil {
230+
t.Fatal(err)
231+
}
232+
})
233+
}
234+
235+
// delete everything to test it
236+
for _, opts := range testset {
237+
var lease leases.Lease
238+
for _, opt := range opts {
239+
if err := opt(&lease); err != nil {
240+
t.Fatal(err)
241+
}
242+
}
243+
244+
if err := db.Update(func(tx *bolt.Tx) error {
245+
lm := NewLeaseManager(tx)
246+
return lm.Delete(ctx, lease)
247+
}); err != nil {
248+
t.Fatal(err)
249+
}
250+
251+
// try it again, get nil
252+
if err := db.Update(func(tx *bolt.Tx) error {
253+
lm := NewLeaseManager(tx)
254+
return lm.Delete(ctx, lease)
255+
}); err != nil {
256+
t.Fatalf("unexpected error %v", err)
257+
}
258+
}
259+
}

0 commit comments

Comments
 (0)