Skip to content

Commit 79b5481

Browse files
authored
Merge pull request #2903 from dlipovetsky/remove-warninghandleroptions
⚠️ Remove options.WarningHandler
2 parents 9516c0f + 4a356a8 commit 79b5481

File tree

3 files changed

+50
-65
lines changed

3 files changed

+50
-65
lines changed

pkg/client/client.go

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,28 +50,10 @@ type Options struct {
5050
// Cache, if provided, is used to read objects from the cache.
5151
Cache *CacheOptions
5252

53-
// WarningHandler is used to configure the warning handler responsible for
54-
// surfacing and handling warnings messages sent by the API server.
55-
WarningHandler WarningHandlerOptions
56-
5753
// DryRun instructs the client to only perform dry run requests.
5854
DryRun *bool
5955
}
6056

61-
// WarningHandlerOptions are options for configuring a
62-
// warning handler for the client which is responsible
63-
// for surfacing API Server warnings.
64-
type WarningHandlerOptions struct {
65-
// SuppressWarnings decides if the warnings from the
66-
// API server are suppressed or surfaced in the client.
67-
SuppressWarnings bool
68-
// AllowDuplicateLogs does not deduplicate the to-be
69-
// logged surfaced warnings messages. See
70-
// log.WarningHandlerOptions for considerations
71-
// regarding deduplication
72-
AllowDuplicateLogs bool
73-
}
74-
7557
// CacheOptions are options for creating a cache-backed client.
7658
type CacheOptions struct {
7759
// Reader is a cache-backed reader that will be used to read objects from the cache.
@@ -91,6 +73,12 @@ type NewClientFunc func(config *rest.Config, options Options) (Client, error)
9173

9274
// New returns a new Client using the provided config and Options.
9375
//
76+
// By default, the client surfaces warnings returned by the server. To
77+
// suppress warnings, set config.WarningHandler = rest.NoWarnings{}. To
78+
// define custom behavior, implement the rest.WarningHandler interface.
79+
// See [sigs.k8s.io/controller-runtime/pkg/log.KubeAPIWarningLogger] for
80+
// an example.
81+
//
9482
// The client's read behavior is determined by Options.Cache.
9583
// If either Options.Cache or Options.Cache.Reader is nil,
9684
// the client reads directly from the API server.
@@ -124,15 +112,14 @@ func newClient(config *rest.Config, options Options) (*client, error) {
124112
config.UserAgent = rest.DefaultKubernetesUserAgent()
125113
}
126114

127-
// By default, we de-duplicate and surface warnings.
128-
config.WarningHandler = log.NewKubeAPIWarningLogger(
129-
log.Log.WithName("KubeAPIWarningLogger"),
130-
log.KubeAPIWarningLoggerOptions{
131-
Deduplicate: !options.WarningHandler.AllowDuplicateLogs,
132-
},
133-
)
134-
if options.WarningHandler.SuppressWarnings {
135-
config.WarningHandler = rest.NoWarnings{}
115+
if config.WarningHandler == nil {
116+
// By default, we de-duplicate and surface warnings.
117+
config.WarningHandler = log.NewKubeAPIWarningLogger(
118+
log.Log.WithName("KubeAPIWarningLogger"),
119+
log.KubeAPIWarningLoggerOptions{
120+
Deduplicate: true,
121+
},
122+
)
136123
}
137124

138125
// Use the rest HTTP client for the provided config if unset

pkg/client/client_test.go

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package client_test
1818

1919
import (
2020
"bufio"
21+
"bytes"
2122
"context"
2223
"encoding/json"
2324
"errors"
@@ -43,6 +44,7 @@ import (
4344
"k8s.io/apimachinery/pkg/runtime/schema"
4445
"k8s.io/apimachinery/pkg/types"
4546
kscheme "k8s.io/client-go/kubernetes/scheme"
47+
"k8s.io/client-go/rest"
4648
"k8s.io/utils/ptr"
4749

4850
"sigs.k8s.io/controller-runtime/examples/crd/pkg"
@@ -229,15 +231,19 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC
229231
})
230232

231233
Describe("WarningHandler", func() {
232-
It("should log warnings when warning suppression is disabled", func() {
234+
It("should log warnings with config.WarningHandler, if one is defined", func() {
233235
cache := &fakeReader{}
234-
cl, err := client.New(cfg, client.Options{
235-
WarningHandler: client.WarningHandlerOptions{SuppressWarnings: false}, Cache: &client.CacheOptions{Reader: cache, DisableFor: []client.Object{&corev1.Namespace{}}},
236-
})
236+
237+
testCfg := rest.CopyConfig(cfg)
238+
239+
var testLog bytes.Buffer
240+
testCfg.WarningHandler = rest.NewWarningWriter(&testLog, rest.WarningWriterOptions{})
241+
242+
cl, err := client.New(testCfg, client.Options{Cache: &client.CacheOptions{Reader: cache, DisableFor: []client.Object{&corev1.Namespace{}}}})
237243
Expect(err).NotTo(HaveOccurred())
238244
Expect(cl).NotTo(BeNil())
239245

240-
tns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ws-disabled"}}
246+
tns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "wh-defined"}}
241247
tns, err = clientset.CoreV1().Namespaces().Create(ctx, tns, metav1.CreateOptions{})
242248
Expect(err).NotTo(HaveOccurred())
243249
Expect(tns).NotTo(BeNil())
@@ -257,45 +263,17 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC
257263
Expect(err).NotTo(HaveOccurred())
258264
Expect(cl).NotTo(BeNil())
259265

260-
scanner := bufio.NewScanner(&log)
261-
for scanner.Scan() {
262-
line := scanner.Text()
266+
scannerTestLog := bufio.NewScanner(&testLog)
267+
for scannerTestLog.Scan() {
268+
line := scannerTestLog.Text()
263269
if strings.Contains(
264270
line,
265271
"unknown field \"status\"",
266272
) {
267273
return
268274
}
269275
}
270-
defer Fail("expected to find one API server warning in the client log")
271-
})
272-
273-
It("should not log warnings when warning suppression is enabled", func() {
274-
cache := &fakeReader{}
275-
cl, err := client.New(cfg, client.Options{
276-
WarningHandler: client.WarningHandlerOptions{SuppressWarnings: true}, Cache: &client.CacheOptions{Reader: cache, DisableFor: []client.Object{&corev1.Namespace{}}},
277-
})
278-
Expect(err).NotTo(HaveOccurred())
279-
Expect(cl).NotTo(BeNil())
280-
281-
tns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ws-enabled"}}
282-
tns, err = clientset.CoreV1().Namespaces().Create(ctx, tns, metav1.CreateOptions{})
283-
Expect(err).NotTo(HaveOccurred())
284-
Expect(tns).NotTo(BeNil())
285-
286-
toCreate := &pkg.ChaosPod{
287-
ObjectMeta: metav1.ObjectMeta{
288-
Name: "example",
289-
Namespace: tns.Name,
290-
},
291-
// The ChaosPod CRD does not define Status, so the field is unknown to the API server,
292-
// but field validation is not strict by default, so the API server returns a warning,
293-
// and we need a warning to check whether suppression works.
294-
Status: pkg.ChaosPodStatus{},
295-
}
296-
err = cl.Create(ctx, toCreate)
297-
Expect(err).NotTo(HaveOccurred())
298-
Expect(cl).NotTo(BeNil())
276+
defer Fail("expected to find one API server warning logged the config.WarningHandler")
299277

300278
scanner := bufio.NewScanner(&log)
301279
for scanner.Scan() {
@@ -308,7 +286,6 @@ U5wwSivyi7vmegHKmblOzNVKA5qPO8zWzqBC
308286
break
309287
}
310288
}
311-
deleteNamespace(ctx, tns)
312289
})
313290
})
314291

pkg/client/example_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"k8s.io/apimachinery/pkg/runtime/schema"
3030
"k8s.io/apimachinery/pkg/types"
3131
corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
32+
"k8s.io/client-go/rest"
3233

3334
"sigs.k8s.io/controller-runtime/pkg/client"
3435
"sigs.k8s.io/controller-runtime/pkg/client/config"
@@ -56,6 +57,26 @@ func ExampleNew() {
5657
}
5758
}
5859

60+
func ExampleNew_suppress_warnings() {
61+
cfg := config.GetConfigOrDie()
62+
// Use a rest.WarningHandler that discards warning messages.
63+
cfg.WarningHandler = rest.NoWarnings{}
64+
65+
cl, err := client.New(cfg, client.Options{})
66+
if err != nil {
67+
fmt.Println("failed to create client")
68+
os.Exit(1)
69+
}
70+
71+
podList := &corev1.PodList{}
72+
73+
err = cl.List(context.Background(), podList, client.InNamespace("default"))
74+
if err != nil {
75+
fmt.Printf("failed to list pods in namespace default: %v\n", err)
76+
os.Exit(1)
77+
}
78+
}
79+
5980
// This example shows how to use the client with typed and unstructured objects to retrieve an object.
6081
func ExampleClient_get() {
6182
// Using a typed object.

0 commit comments

Comments
 (0)