Skip to content

Commit 6e98159

Browse files
authored
actionConfigGetter: allow custom mapping from object to rest.Config (#317)
Signed-off-by: Joe Lanford <joe.lanford@gmail.com>
1 parent cfc667c commit 6e98159

File tree

12 files changed

+203
-180
lines changed

12 files changed

+203
-180
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module github.com/operator-framework/helm-operator-plugins
22

33
go 1.21
44

5-
toolchain go1.21.8
5+
toolchain go1.21.9
66

77
require (
88
github.com/blang/semver/v4 v4.0.0

pkg/client/actionclient.go

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

1919
import (
2020
"bytes"
21+
"context"
2122
"encoding/json"
2223
"errors"
2324
"fmt"
@@ -40,13 +41,13 @@ import (
4041
)
4142

4243
type ActionClientGetter interface {
43-
ActionClientFor(obj client.Object) (ActionInterface, error)
44+
ActionClientFor(ctx context.Context, obj client.Object) (ActionInterface, error)
4445
}
4546

46-
type ActionClientGetterFunc func(obj client.Object) (ActionInterface, error)
47+
type ActionClientGetterFunc func(ctx context.Context, obj client.Object) (ActionInterface, error)
4748

48-
func (acgf ActionClientGetterFunc) ActionClientFor(obj client.Object) (ActionInterface, error) {
49-
return acgf(obj)
49+
func (acgf ActionClientGetterFunc) ActionClientFor(ctx context.Context, obj client.Object) (ActionInterface, error) {
50+
return acgf(ctx, obj)
5051
}
5152

5253
type ActionInterface interface {
@@ -140,8 +141,8 @@ type actionClientGetter struct {
140141

141142
var _ ActionClientGetter = &actionClientGetter{}
142143

143-
func (hcg *actionClientGetter) ActionClientFor(obj client.Object) (ActionInterface, error) {
144-
actionConfig, err := hcg.acg.ActionConfigFor(obj)
144+
func (hcg *actionClientGetter) ActionClientFor(ctx context.Context, obj client.Object) (ActionInterface, error) {
145+
actionConfig, err := hcg.acg.ActionConfigFor(ctx, obj)
145146
if err != nil {
146147
return nil, err
147148
}

pkg/client/actionclient_test.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"strconv"
2525
"time"
2626

27-
"github.com/go-logr/logr"
2827
. "github.com/onsi/ginkgo/v2"
2928
. "github.com/onsi/gomega"
3029
"helm.sh/helm/v3/pkg/action"
@@ -45,6 +44,8 @@ import (
4544
apitypes "k8s.io/apimachinery/pkg/types"
4645
"k8s.io/apimachinery/pkg/util/rand"
4746
"k8s.io/cli-runtime/pkg/resource"
47+
"k8s.io/client-go/discovery"
48+
"k8s.io/client-go/discovery/cached/memory"
4849
"k8s.io/client-go/rest"
4950
"k8s.io/utils/ptr"
5051
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -71,7 +72,7 @@ var _ = Describe("ActionClient", func() {
7172
})
7273
var _ = Describe("NewActionClientGetter", func() {
7374
It("should return a valid ActionConfigGetter", func() {
74-
actionConfigGetter, err := NewActionConfigGetter(cfg, rm, logr.Discard())
75+
actionConfigGetter, err := NewActionConfigGetter(cfg, rm)
7576
Expect(err).ShouldNot(HaveOccurred())
7677
acg, err := NewActionClientGetter(actionConfigGetter)
7778
Expect(err).ToNot(HaveOccurred())
@@ -88,9 +89,12 @@ var _ = Describe("ActionClient", func() {
8889
)
8990
BeforeEach(func() {
9091
var err error
91-
actionConfigGetter, err = NewActionConfigGetter(cfg, rm, logr.Discard())
92+
actionConfigGetter, err = NewActionConfigGetter(cfg, rm)
9293
Expect(err).ShouldNot(HaveOccurred())
93-
cli = kube.New(newRESTClientGetter(cfg, rm, ""))
94+
dc, err := discovery.NewDiscoveryClientForConfig(cfg)
95+
Expect(err).ShouldNot(HaveOccurred())
96+
cdc := memory.NewMemCacheClient(dc)
97+
cli = kube.New(newRESTClientGetter(cfg, rm, cdc, ""))
9498
Expect(err).ShouldNot(HaveOccurred())
9599
obj = testutil.BuildTestCR(gvk)
96100
})
@@ -110,7 +114,7 @@ var _ = Describe("ActionClient", func() {
110114
Expect(err).ToNot(HaveOccurred())
111115
Expect(acg).NotTo(BeNil())
112116

113-
ac, err := acg.ActionClientFor(obj)
117+
ac, err := acg.ActionClientFor(context.Background(), obj)
114118
Expect(err).ToNot(HaveOccurred())
115119
Expect(ac).NotTo(BeNil())
116120

@@ -131,7 +135,7 @@ var _ = Describe("ActionClient", func() {
131135
Expect(err).ToNot(HaveOccurred())
132136
Expect(acg).NotTo(BeNil())
133137

134-
ac, err := acg.ActionClientFor(obj)
138+
ac, err := acg.ActionClientFor(context.Background(), obj)
135139
Expect(err).ToNot(HaveOccurred())
136140
Expect(ac).NotTo(BeNil())
137141

@@ -152,7 +156,7 @@ var _ = Describe("ActionClient", func() {
152156
Expect(err).ToNot(HaveOccurred())
153157
Expect(acg).NotTo(BeNil())
154158

155-
ac, err := acg.ActionClientFor(obj)
159+
ac, err := acg.ActionClientFor(context.Background(), obj)
156160
Expect(err).ToNot(HaveOccurred())
157161
Expect(ac).NotTo(BeNil())
158162

@@ -173,7 +177,7 @@ var _ = Describe("ActionClient", func() {
173177
Expect(err).ToNot(HaveOccurred())
174178
Expect(acg).NotTo(BeNil())
175179

176-
ac, err := acg.ActionClientFor(obj)
180+
ac, err := acg.ActionClientFor(context.Background(), obj)
177181
Expect(err).ToNot(HaveOccurred())
178182
Expect(ac).NotTo(BeNil())
179183

@@ -194,7 +198,7 @@ var _ = Describe("ActionClient", func() {
194198
Expect(err).ToNot(HaveOccurred())
195199
Expect(acg).NotTo(BeNil())
196200

197-
ac, err := acg.ActionClientFor(obj)
201+
ac, err := acg.ActionClientFor(context.Background(), obj)
198202
Expect(err).ToNot(HaveOccurred())
199203
Expect(ac).NotTo(BeNil())
200204

@@ -226,7 +230,7 @@ var _ = Describe("ActionClient", func() {
226230
Expect(err).ToNot(HaveOccurred())
227231
Expect(acg).NotTo(BeNil())
228232

229-
ac, err := acg.ActionClientFor(obj)
233+
ac, err := acg.ActionClientFor(context.Background(), obj)
230234
Expect(err).ToNot(HaveOccurred())
231235
Expect(ac).NotTo(BeNil())
232236

@@ -254,7 +258,7 @@ var _ = Describe("ActionClient", func() {
254258
Expect(err).ToNot(HaveOccurred())
255259
Expect(acg).NotTo(BeNil())
256260

257-
ac, err := acg.ActionClientFor(obj)
261+
ac, err := acg.ActionClientFor(context.Background(), obj)
258262
Expect(err).ToNot(HaveOccurred())
259263

260264
_, err = ac.Install(obj.GetName(), obj.GetNamespace(), &chrt, chartutil.Values{})
@@ -291,11 +295,11 @@ var _ = Describe("ActionClient", func() {
291295
expectedObj := &unstructured.Unstructured{}
292296
expectedObj.SetGroupVersionKind(gvk)
293297
var actualObj client.Object
294-
f := ActionClientGetterFunc(func(obj client.Object) (ActionInterface, error) {
298+
f := ActionClientGetterFunc(func(_ context.Context, obj client.Object) (ActionInterface, error) {
295299
actualObj = obj
296300
return nil, nil
297301
})
298-
_, _ = f.ActionClientFor(expectedObj)
302+
_, _ = f.ActionClientFor(context.Background(), expectedObj)
299303
Expect(actualObj.GetObjectKind().GroupVersionKind()).To(Equal(gvk))
300304
})
301305
})
@@ -306,11 +310,11 @@ var _ = Describe("ActionClient", func() {
306310
obj = testutil.BuildTestCR(gvk)
307311
})
308312
It("should return a valid ActionClient", func() {
309-
actionConfGetter, err := NewActionConfigGetter(cfg, rm, logr.Discard())
313+
actionConfGetter, err := NewActionConfigGetter(cfg, rm)
310314
Expect(err).ShouldNot(HaveOccurred())
311315
acg, err := NewActionClientGetter(actionConfGetter)
312316
Expect(err).ToNot(HaveOccurred())
313-
ac, err := acg.ActionClientFor(obj)
317+
ac, err := acg.ActionClientFor(context.Background(), obj)
314318
Expect(err).ToNot(HaveOccurred())
315319
Expect(ac).NotTo(BeNil())
316320
})
@@ -326,11 +330,11 @@ var _ = Describe("ActionClient", func() {
326330
BeforeEach(func() {
327331
obj = testutil.BuildTestCR(gvk)
328332

329-
actionConfigGetter, err := NewActionConfigGetter(cfg, rm, logr.Discard())
333+
actionConfigGetter, err := NewActionConfigGetter(cfg, rm)
330334
Expect(err).ShouldNot(HaveOccurred())
331335
acg, err := NewActionClientGetter(actionConfigGetter)
332336
Expect(err).ToNot(HaveOccurred())
333-
ac, err = acg.ActionClientFor(obj)
337+
ac, err = acg.ActionClientFor(context.Background(), obj)
334338
Expect(err).ToNot(HaveOccurred())
335339

336340
cl, err = client.New(cfg, client.Options{})

pkg/client/actionconfig.go

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,38 +28,28 @@ import (
2828
corev1 "k8s.io/api/core/v1"
2929
"k8s.io/apimachinery/pkg/api/meta"
3030
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31-
"k8s.io/client-go/kubernetes"
31+
"k8s.io/client-go/discovery"
32+
"k8s.io/client-go/discovery/cached/memory"
3233
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
3334
"k8s.io/client-go/rest"
3435
"sigs.k8s.io/controller-runtime/pkg/client"
3536
)
3637

3738
type ActionConfigGetter interface {
38-
ActionConfigFor(obj client.Object) (*action.Configuration, error)
39+
ActionConfigFor(ctx context.Context, obj client.Object) (*action.Configuration, error)
3940
}
4041

41-
func NewActionConfigGetter(cfg *rest.Config, rm meta.RESTMapper, log logr.Logger, opts ...ActionConfigGetterOption) (ActionConfigGetter, error) {
42-
rcg := newRESTClientGetter(cfg, rm, "")
43-
// Setup the debug log function that Helm will use
44-
debugLog := func(format string, v ...interface{}) {
45-
if log.GetSink() != nil {
46-
log.V(1).Info(fmt.Sprintf(format, v...))
47-
}
48-
}
49-
50-
kc := kube.New(rcg)
51-
kc.Log = debugLog
52-
53-
kcs, err := kc.Factory.KubernetesClientSet()
42+
func NewActionConfigGetter(baseRestConfig *rest.Config, rm meta.RESTMapper, opts ...ActionConfigGetterOption) (ActionConfigGetter, error) {
43+
dc, err := discovery.NewDiscoveryClientForConfig(baseRestConfig)
5444
if err != nil {
55-
return nil, fmt.Errorf("creating kubernetes client set: %w", err)
45+
return nil, fmt.Errorf("create discovery client: %v", err)
5646
}
47+
cdc := memory.NewMemCacheClient(dc)
5748

5849
acg := &actionConfigGetter{
59-
kubeClient: kc,
60-
kubeClientSet: kcs,
61-
debugLog: debugLog,
62-
restClientGetter: rcg.restClientGetter,
50+
baseRestConfig: baseRestConfig,
51+
restMapper: rm,
52+
discoveryClient: cdc,
6353
}
6454
for _, o := range opts {
6555
o(acg)
@@ -70,6 +60,11 @@ func NewActionConfigGetter(cfg *rest.Config, rm meta.RESTMapper, log logr.Logger
7060
if acg.objectToStorageNamespace == nil {
7161
acg.objectToStorageNamespace = getObjectNamespace
7262
}
63+
if acg.objectToRestConfig == nil {
64+
acg.objectToRestConfig = func(_ context.Context, _ client.Object, baseRestConfig *rest.Config) (*rest.Config, error) {
65+
return rest.CopyConfig(baseRestConfig), nil
66+
}
67+
}
7368
return acg, nil
7469
}
7570

@@ -97,28 +92,56 @@ func DisableStorageOwnerRefInjection(v bool) ActionConfigGetterOption {
9792
}
9893
}
9994

95+
func RestConfigMapper(f func(context.Context, client.Object, *rest.Config) (*rest.Config, error)) ActionConfigGetterOption {
96+
return func(getter *actionConfigGetter) {
97+
getter.objectToRestConfig = f
98+
}
99+
}
100+
100101
func getObjectNamespace(obj client.Object) (string, error) {
101102
return obj.GetNamespace(), nil
102103
}
103104

104105
type actionConfigGetter struct {
105-
kubeClient *kube.Client
106-
kubeClientSet kubernetes.Interface
107-
debugLog func(string, ...interface{})
108-
restClientGetter *restClientGetter
106+
baseRestConfig *rest.Config
107+
restMapper meta.RESTMapper
108+
discoveryClient discovery.CachedDiscoveryInterface
109109

110110
objectToClientNamespace ObjectToStringMapper
111111
objectToStorageNamespace ObjectToStringMapper
112+
objectToRestConfig func(context.Context, client.Object, *rest.Config) (*rest.Config, error)
112113
disableStorageOwnerRefInjection bool
113114
}
114115

115-
func (acg *actionConfigGetter) ActionConfigFor(obj client.Object) (*action.Configuration, error) {
116+
func (acg *actionConfigGetter) ActionConfigFor(ctx context.Context, obj client.Object) (*action.Configuration, error) {
116117
storageNs, err := acg.objectToStorageNamespace(obj)
117118
if err != nil {
118-
return nil, fmt.Errorf("get storage namespace from object: %v", err)
119+
return nil, fmt.Errorf("get storage namespace for object: %v", err)
120+
}
121+
122+
restConfig, err := acg.objectToRestConfig(ctx, obj, acg.baseRestConfig)
123+
if err != nil {
124+
return nil, fmt.Errorf("get rest config for object: %v", err)
125+
}
126+
127+
clientNamespace, err := acg.objectToClientNamespace(obj)
128+
if err != nil {
129+
return nil, fmt.Errorf("get client namespace for object: %v", err)
119130
}
120131

121-
secretClient := acg.kubeClientSet.CoreV1().Secrets(storageNs)
132+
rcg := newRESTClientGetter(restConfig, acg.restMapper, acg.discoveryClient, clientNamespace)
133+
kc := kube.New(rcg)
134+
kc.Namespace = clientNamespace
135+
136+
kcs, err := kc.Factory.KubernetesClientSet()
137+
if err != nil {
138+
return nil, fmt.Errorf("create kubernetes clientset: %v", err)
139+
}
140+
141+
// Setup the debug log function that Helm will use
142+
debugLog := getDebugLogger(ctx)
143+
144+
secretClient := kcs.CoreV1().Secrets(storageNs)
122145
if !acg.disableStorageOwnerRefInjection {
123146
ownerRef := metav1.NewControllerRef(obj, obj.GetObjectKind().GroupVersionKind())
124147
secretClient = &ownerRefSecretClient{
@@ -127,27 +150,29 @@ func (acg *actionConfigGetter) ActionConfigFor(obj client.Object) (*action.Confi
127150
}
128151
}
129152
d := driver.NewSecrets(secretClient)
130-
131-
// Also, use the debug log for the storage driver
132-
d.Log = acg.debugLog
153+
d.Log = debugLog
133154

134155
// Initialize the storage backend
135156
s := storage.Init(d)
136157

137-
kubeClient := *acg.kubeClient
138-
kubeClient.Namespace, err = acg.objectToClientNamespace(obj)
139-
if err != nil {
140-
return nil, fmt.Errorf("get client namespace from object: %v", err)
141-
}
142-
143158
return &action.Configuration{
144-
RESTClientGetter: acg.restClientGetter.ForNamespace(kubeClient.Namespace),
159+
RESTClientGetter: rcg,
145160
Releases: s,
146-
KubeClient: &kubeClient,
147-
Log: acg.debugLog,
161+
KubeClient: kc,
162+
Log: debugLog,
148163
}, nil
149164
}
150165

166+
func getDebugLogger(ctx context.Context) func(format string, v ...interface{}) {
167+
logger, err := logr.FromContext(ctx)
168+
if err != nil {
169+
return func(format string, v ...interface{}) {}
170+
}
171+
return func(format string, v ...interface{}) {
172+
logger.V(1).Info(fmt.Sprintf(format, v...))
173+
}
174+
}
175+
151176
var _ v1.SecretInterface = &ownerRefSecretClient{}
152177

153178
type ownerRefSecretClient struct {

0 commit comments

Comments
 (0)