Skip to content

Commit 49a6424

Browse files
author
Aaron
committed
Add DeleteCollection to the client Interface.
1 parent 6443f37 commit 49a6424

File tree

6 files changed

+133
-1
lines changed

6 files changed

+133
-1
lines changed

pkg/client/client.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ func (c *client) List(ctx context.Context, obj runtime.Object, opts ...ListOptio
139139
return c.typedClient.List(ctx, obj, opts...)
140140
}
141141

142+
// DeleteCollection implements client.Client
143+
func (c *client) DeleteCollection(ctx context.Context, obj runtime.Object, opts ...DeleteCollectionOptionFunc) error {
144+
_, ok := obj.(*unstructured.UnstructuredList)
145+
if ok {
146+
return c.unstructuredClient.DeleteCollection(ctx, obj, opts...)
147+
}
148+
return c.typedClient.DeleteCollection(ctx, obj, opts...)
149+
}
150+
142151
// Status implements client.StatusClient
143152
func (c *client) Status() StatusWriter {
144153
return &statusWriter{client: c}

pkg/client/client_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,37 @@ var _ = Describe("Client", func() {
18461846
Expect(lo.Namespace).To(Equal("test"))
18471847
})
18481848
})
1849+
1850+
Describe("DeleteCollectionOptions", func() {
1851+
It("should be created from ListOptions", func() {
1852+
labels := map[string]string{"foo": "bar"}
1853+
dco := &client.DeleteCollectionOptions{}
1854+
client.FromListOptionsFunc(client.MatchingLabels(labels))(dco)
1855+
Expect(dco).NotTo(BeNil())
1856+
Expect(dco.LabelSelector.String()).To(Equal("foo=bar"))
1857+
Expect(dco.AsDeleteOptions()).To(Equal(&metav1.DeleteOptions{}))
1858+
})
1859+
It("should be created from DeleteOptions", func() {
1860+
dco := &client.DeleteCollectionOptions{}
1861+
client.FromDeleteOptionsFunc(client.GracePeriodSeconds(1))(dco)
1862+
gp := int64(1)
1863+
Expect(dco.GracePeriodSeconds).To(Equal(&gp))
1864+
Expect(dco.AsListOptions()).To(Equal(&metav1.ListOptions{}))
1865+
})
1866+
It("should merge multiple options together", func() {
1867+
gp := int64(1)
1868+
labels := map[string]string{"foo": "bar"}
1869+
1870+
dco := &client.DeleteCollectionOptions{}
1871+
dco.ApplyOptions([]client.DeleteCollectionOptionFunc{
1872+
client.FromListOptionsFunc(client.MatchingLabels(labels)),
1873+
client.FromDeleteOptionsFunc(client.GracePeriodSeconds(1)),
1874+
})
1875+
1876+
Expect(dco.GracePeriodSeconds).To(Equal(&gp))
1877+
Expect(dco.LabelSelector.String()).To(Equal("foo=bar"))
1878+
})
1879+
})
18491880
})
18501881

18511882
var _ = Describe("DelegatingReader", func() {

pkg/client/example_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"os"
2323

2424
corev1 "k8s.io/api/core/v1"
25-
"k8s.io/apimachinery/pkg/apis/meta/v1"
25+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2727
"k8s.io/apimachinery/pkg/runtime/schema"
2828
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -196,3 +196,19 @@ func ExampleClient_delete() {
196196
})
197197
_ = c.Delete(context.Background(), u)
198198
}
199+
200+
// This example shows how to use the client with typed and unstrucurted objects to delete collections of objects.
201+
func ExampleClient_deleteCollection() {
202+
// Using a typed object.
203+
pod := &corev1.PodList{}
204+
// c is a created client.
205+
_ = c.DeleteCollection(context.Background(), pod)
206+
207+
u := &unstructured.UnstructuredList{}
208+
u.SetGroupVersionKind(schema.GroupVersionKind{
209+
Group: "apps",
210+
Kind: "DeploymentList",
211+
Version: "v1",
212+
})
213+
_ = c.DeleteCollection(context.Background(), u)
214+
}

pkg/client/interfaces.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ type Writer interface {
6565
// Update updates the given obj in the Kubernetes cluster. obj must be a
6666
// struct pointer so that obj can be updated with the content returned by the Server.
6767
Update(ctx context.Context, obj runtime.Object) error
68+
69+
DeleteCollection(ctx context.Context, obj runtime.Object, opts ...DeleteCollectionOptionFunc) error
6870
}
6971

7072
// StatusClient knows how to create a client which can update status subresource
@@ -323,3 +325,36 @@ func UseListOptions(newOpts *ListOptions) ListOptionFunc {
323325
*opts = *newOpts
324326
}
325327
}
328+
329+
// DeleteCollectionOptions contains options for delete collection requests. It's a collection of
330+
// Both metav1.DeletOptions and metav1.ListOptions
331+
type DeleteCollectionOptions struct {
332+
DeleteOptions
333+
ListOptions
334+
}
335+
336+
// ApplyOptions executes the given DeleteCollectionOptionFuncs and returns the mutated
337+
// DeleteOptions.
338+
func (o *DeleteCollectionOptions) ApplyOptions(optFuncs []DeleteCollectionOptionFunc) *DeleteCollectionOptions {
339+
for _, optFunc := range optFuncs {
340+
optFunc(o)
341+
}
342+
return o
343+
}
344+
345+
// DeleteCollectionOptionFunc is a function that mutates a DeleteOptions struct. It implements
346+
// the functional options pattern. See
347+
// https://github.com/tmrts/go-patterns/blob/master/idiom/functional-options.md.
348+
type DeleteCollectionOptionFunc func(*DeleteCollectionOptions)
349+
350+
func FromListOptionsFunc(newFunc ListOptionFunc) DeleteCollectionOptionFunc {
351+
return func(opts *DeleteCollectionOptions) {
352+
newFunc(&opts.ListOptions)
353+
}
354+
}
355+
356+
func FromDeleteOptionsFunc(newFunc DeleteOptionFunc) DeleteCollectionOptionFunc {
357+
return func(opts *DeleteCollectionOptions) {
358+
newFunc(&opts.DeleteOptions)
359+
}
360+
}

pkg/client/typed_client.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,25 @@ func (c *typedClient) List(ctx context.Context, obj runtime.Object, opts ...List
109109
Into(obj)
110110
}
111111

112+
func (c *typedClient) DeleteCollection(ctx context.Context, obj runtime.Object, opts ...DeleteCollectionOptionFunc) error {
113+
r, err := c.cache.getResource(obj)
114+
if err != nil {
115+
return err
116+
}
117+
118+
dcOpts := DeleteCollectionOptions{}
119+
dcOpts.ApplyOptions(opts)
120+
121+
return r.Delete().
122+
NamespaceIfScoped(dcOpts.Namespace, r.isNamespaced()).
123+
Resource(r.resource()).
124+
VersionedParams(dcOpts.AsListOptions(), c.paramCodec).
125+
Body(dcOpts.AsDeleteOptions()).
126+
Context(ctx).
127+
Do().
128+
Error()
129+
}
130+
112131
// UpdateStatus used by StatusWriter to write status.
113132
func (c *typedClient) UpdateStatus(ctx context.Context, obj runtime.Object) error {
114133
o, err := c.cache.getObjMeta(obj)

pkg/client/unstructured_client.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,28 @@ func (uc *unstructuredClient) List(_ context.Context, obj runtime.Object, opts .
131131
return nil
132132
}
133133

134+
func (uc *unstructuredClient) DeleteCollection(_ context.Context, obj runtime.Object, opts ...DeleteCollectionOptionFunc) error {
135+
u, ok := obj.(*unstructured.UnstructuredList)
136+
if !ok {
137+
return fmt.Errorf("unstructured client did not understand object: %T", obj)
138+
}
139+
gvk := u.GroupVersionKind()
140+
if strings.HasSuffix(gvk.Kind, "List") {
141+
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
142+
}
143+
144+
dcOpts := DeleteCollectionOptions{}
145+
dcOpts.ApplyOptions(opts)
146+
147+
r, err := uc.getResourceInterface(gvk, dcOpts.ListOptions.Namespace)
148+
if err != nil {
149+
return err
150+
}
151+
152+
err = r.DeleteCollection(dcOpts.AsDeleteOptions(), *dcOpts.AsListOptions())
153+
return err
154+
}
155+
134156
func (uc *unstructuredClient) UpdateStatus(_ context.Context, obj runtime.Object) error {
135157
u, ok := obj.(*unstructured.Unstructured)
136158
if !ok {

0 commit comments

Comments
 (0)