From aff2e29b97cd7cfb9ac81feec8a55d5e529e0015 Mon Sep 17 00:00:00 2001 From: Eric Fried Date: Sun, 18 Aug 2024 10:43:38 -0500 Subject: [PATCH] Add client.WithWatch wrapper In some cases, one can wrap already-extant `client.Client`s to confer extra functionality. For example: ```go cWithFieldOwner := client.WithFieldOwner(cWithoutFieldOwner, "owner") ``` However, it has not heretofore been possible to confer `WithWatch` on an existing client: one could only obtain a `client.WithWatch` via a constructor: ```go cWithWatch, err := client.NewWithWatch(cfg, opts) ``` The resulting client is "frozen" -- i.e. can't be subjected to decorators like `WithFieldOwner` -- because those wrappers return a `client.Client`, which can't `Watch()`! This commit adds a decorator function to allow an existing client to grow `WithWatch` functionality: ```go c, err := client.New(cfg, opts) c = client.WithFieldOwner(c, "owner") // ... chain other decorators ... cWithAllTheThings, err := client.AsWithWatch(c) ``` Notes: - We would have preferred to call the wrapper `WithWatch`, but that name is already taken by the interface. Sad face. - This client is "the end of the line". It can't be further wrapped, unless the wrapper is `WithWatch`-specific. Sad face. - As currently conceived, you can't just do this to any `client.Client` because the `Watch()` implementation relies on internals of the specific `client` (lowercase) implementation in the library. Sad face. --- pkg/client/watch.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/client/watch.go b/pkg/client/watch.go index 181b22a673..8de5d64b4b 100644 --- a/pkg/client/watch.go +++ b/pkg/client/watch.go @@ -18,6 +18,7 @@ package client import ( "context" + "errors" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,6 +36,15 @@ func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) { return &watchingClient{client: client}, nil } +// AsWithWatch wraps an existing client in a WithWatch +func AsWithWatch(c Client) (WithWatch, error) { + cl, ok := c.(*client) + if !ok { + return nil, errors.New("incompatible client type") + } + return &watchingClient{client: cl}, nil +} + type watchingClient struct { *client }