Skip to content

Commit e96f830

Browse files
authored
Merge pull request #341 from rajathagasthya/listoptions-310
✨ Add Limit and Continue functional list options for client
2 parents 0fa2e7c + b5dfbb5 commit e96f830

File tree

2 files changed

+173
-1
lines changed

2 files changed

+173
-1
lines changed

pkg/client/client_test.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,89 @@ var _ = Describe("Client", func() {
19041904
close(done)
19051905
}, serverSideTimeoutSeconds)
19061906

1907+
It("should filter results using limit and continue options", func() {
1908+
1909+
makeDeployment := func(suffix string) *appsv1.Deployment {
1910+
return &appsv1.Deployment{
1911+
ObjectMeta: metav1.ObjectMeta{
1912+
Name: fmt.Sprintf("deployment-%s", suffix),
1913+
},
1914+
Spec: appsv1.DeploymentSpec{
1915+
Selector: &metav1.LabelSelector{
1916+
MatchLabels: map[string]string{"foo": "bar"},
1917+
},
1918+
Template: corev1.PodTemplateSpec{
1919+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
1920+
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}},
1921+
},
1922+
},
1923+
}
1924+
}
1925+
1926+
By("creating 4 deployments")
1927+
dep1 := makeDeployment("1")
1928+
dep1, err := clientset.AppsV1().Deployments(ns).Create(dep1)
1929+
Expect(err).NotTo(HaveOccurred())
1930+
defer deleteDeployment(dep1, ns)
1931+
1932+
dep2 := makeDeployment("2")
1933+
dep2, err = clientset.AppsV1().Deployments(ns).Create(dep2)
1934+
Expect(err).NotTo(HaveOccurred())
1935+
defer deleteDeployment(dep2, ns)
1936+
1937+
dep3 := makeDeployment("3")
1938+
dep3, err = clientset.AppsV1().Deployments(ns).Create(dep3)
1939+
Expect(err).NotTo(HaveOccurred())
1940+
defer deleteDeployment(dep3, ns)
1941+
1942+
dep4 := makeDeployment("4")
1943+
dep4, err = clientset.AppsV1().Deployments(ns).Create(dep4)
1944+
Expect(err).NotTo(HaveOccurred())
1945+
defer deleteDeployment(dep4, ns)
1946+
1947+
cl, err := client.New(cfg, client.Options{})
1948+
Expect(err).NotTo(HaveOccurred())
1949+
1950+
By("listing 1 deployment when limit=1 is used")
1951+
deps := &appsv1.DeploymentList{}
1952+
err = cl.List(context.Background(), deps,
1953+
client.Limit(1),
1954+
)
1955+
Expect(err).NotTo(HaveOccurred())
1956+
1957+
Expect(deps.Items).To(HaveLen(1))
1958+
Expect(deps.Continue).NotTo(BeEmpty())
1959+
Expect(deps.Items[0].Name).To(Equal(dep1.Name))
1960+
1961+
continueToken := deps.Continue
1962+
1963+
By("listing the next deployment when previous continuation token is used and limit=1")
1964+
deps = &appsv1.DeploymentList{}
1965+
err = cl.List(context.Background(), deps,
1966+
client.Limit(1),
1967+
client.Continue(continueToken),
1968+
)
1969+
Expect(err).NotTo(HaveOccurred())
1970+
1971+
Expect(deps.Items).To(HaveLen(1))
1972+
Expect(deps.Continue).NotTo(BeEmpty())
1973+
Expect(deps.Items[0].Name).To(Equal(dep2.Name))
1974+
1975+
continueToken = deps.Continue
1976+
1977+
By("listing the 2 remaining deployments when previous continuation token is used without a limit")
1978+
deps = &appsv1.DeploymentList{}
1979+
err = cl.List(context.Background(), deps,
1980+
client.Continue(continueToken),
1981+
)
1982+
Expect(err).NotTo(HaveOccurred())
1983+
1984+
Expect(deps.Items).To(HaveLen(2))
1985+
Expect(deps.Continue).To(BeEmpty())
1986+
Expect(deps.Items[0].Name).To(Equal(dep3.Name))
1987+
Expect(deps.Items[1].Name).To(Equal(dep4.Name))
1988+
}, serverSideTimeoutSeconds)
1989+
19071990
PIt("should fail if the object doesn't have meta", func() {
19081991

19091992
})
@@ -2309,11 +2392,15 @@ var _ = Describe("Client", func() {
23092392
client.MatchingField("field1", "bar"),
23102393
client.InNamespace("test-namespace"),
23112394
client.MatchingLabels{"foo": "bar"},
2395+
client.Limit(1),
2396+
client.Continue("foo"),
23122397
})
23132398
mlo := lo.AsListOptions()
23142399
Expect(mlo).NotTo(BeNil())
23152400
Expect(mlo.LabelSelector).To(Equal("foo=bar"))
23162401
Expect(mlo.FieldSelector).To(Equal("field1=bar"))
2402+
Expect(mlo.Limit).To(Equal(int64(1)))
2403+
Expect(mlo.Continue).To(Equal("foo"))
23172404
})
23182405

23192406
It("should be populated by MatchingLabels", func() {
@@ -2343,6 +2430,58 @@ var _ = Describe("Client", func() {
23432430
do = &client.ListOptions{}
23442431
Expect(do.AsListOptions()).To(Equal(&metav1.ListOptions{}))
23452432
})
2433+
2434+
It("should be populated by Limit", func() {
2435+
lo := &client.ListOptions{}
2436+
client.Limit(1).ApplyToList(lo)
2437+
Expect(lo).NotTo(BeNil())
2438+
Expect(lo.Limit).To(Equal(int64(1)))
2439+
})
2440+
2441+
It("should ignore Limit when converted to metav1.ListOptions and watch is true", func() {
2442+
lo := &client.ListOptions{
2443+
Raw: &metav1.ListOptions{Watch: true},
2444+
}
2445+
lo.ApplyOptions([]client.ListOption{
2446+
client.Limit(1),
2447+
})
2448+
mlo := lo.AsListOptions()
2449+
Expect(mlo).NotTo(BeNil())
2450+
Expect(mlo.Limit).To(BeZero())
2451+
})
2452+
2453+
It("should be populated by Continue", func() {
2454+
lo := &client.ListOptions{}
2455+
client.Continue("foo").ApplyToList(lo)
2456+
Expect(lo).NotTo(BeNil())
2457+
Expect(lo.Continue).To(Equal("foo"))
2458+
})
2459+
2460+
It("should ignore Continue token when converted to metav1.ListOptions and watch is true", func() {
2461+
lo := &client.ListOptions{
2462+
Raw: &metav1.ListOptions{Watch: true},
2463+
}
2464+
lo.ApplyOptions([]client.ListOption{
2465+
client.Continue("foo"),
2466+
})
2467+
mlo := lo.AsListOptions()
2468+
Expect(mlo).NotTo(BeNil())
2469+
Expect(mlo.Continue).To(BeEmpty())
2470+
})
2471+
2472+
It("should ignore both Limit and Continue token when converted to metav1.ListOptions and watch is true", func() {
2473+
lo := &client.ListOptions{
2474+
Raw: &metav1.ListOptions{Watch: true},
2475+
}
2476+
lo.ApplyOptions([]client.ListOption{
2477+
client.Limit(1),
2478+
client.Continue("foo"),
2479+
})
2480+
mlo := lo.AsListOptions()
2481+
Expect(mlo).NotTo(BeNil())
2482+
Expect(mlo.Limit).To(BeZero())
2483+
Expect(mlo.Continue).To(BeEmpty())
2484+
})
23462485
})
23472486

23482487
Describe("UpdateOptions", func() {

pkg/client/options.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,20 @@ type ListOptions struct {
303303
// non-namespaced objects, or to list across all namespaces.
304304
Namespace string
305305

306+
// Limit specifies the maximum number of results to return from the server. The server may
307+
// not support this field on all resource types, but if it does and more results remain it
308+
// will set the continue field on the returned list object. This field is not supported if watch
309+
// is true in the Raw ListOptions.
310+
Limit int64
311+
// Continue is a token returned by the server that lets a client retrieve chunks of results
312+
// from the server by specifying limit. The server may reject requests for continuation tokens
313+
// it does not recognize and will return a 410 error if the token can no longer be used because
314+
// it has expired. This field is not supported if watch is true in the Raw ListOptions.
315+
Continue string
316+
306317
// Raw represents raw ListOptions, as passed to the API server. Note
307318
// that these may not be respected by all implementations of interface,
308-
// and the LabelSelector and FieldSelector fields are ignored.
319+
// and the LabelSelector, FieldSelector, Limit and Continue fields are ignored.
309320
Raw *metav1.ListOptions
310321
}
311322

@@ -342,6 +353,10 @@ func (o *ListOptions) AsListOptions() *metav1.ListOptions {
342353
if o.FieldSelector != nil {
343354
o.Raw.FieldSelector = o.FieldSelector.String()
344355
}
356+
if !o.Raw.Watch {
357+
o.Raw.Limit = o.Limit
358+
o.Raw.Continue = o.Continue
359+
}
345360
return o.Raw
346361
}
347362

@@ -430,6 +445,24 @@ func (n InNamespace) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
430445
n.ApplyToList(&opts.ListOptions)
431446
}
432447

448+
// Limit specifies the maximum number of results to return from the server.
449+
// Limit does not implement DeleteAllOfOption interface because the server
450+
// does not support setting it for deletecollection operations.
451+
type Limit int64
452+
453+
func (l Limit) ApplyToList(opts *ListOptions) {
454+
opts.Limit = int64(l)
455+
}
456+
457+
// Continue sets a continuation token to retrieve chunks of results when using limit.
458+
// Continue does not implement DeleteAllOfOption interface because the server
459+
// does not support setting it for deletecollection operations.
460+
type Continue string
461+
462+
func (c Continue) ApplyToList(opts *ListOptions) {
463+
opts.Continue = string(c)
464+
}
465+
433466
// }}}
434467

435468
// {{{ Update Options

0 commit comments

Comments
 (0)