Skip to content

Commit ab41b86

Browse files
zhujian7claude
andauthored
πŸ› Use specific addon template instead of default in CSR functions (#1180)
* Upgrade addon framework Signed-off-by: zhujian <[email protected]> * Use specific addon template instead of default in CSR functions - Pass real ManagedClusterAddOn to GetDesiredAddOnTemplate instead of nil - Enable per-addon template selection using addon.Status.ConfigReferences - Replace utilruntime.HandleError with explicit error returns - Update CSRConfigurationsFunc to return ([]RegistrationConfig, error) - Update CSRSignerFunc to return ([]byte, error) - Add addon parameter to CSR functions for better context - Convert runtime errors to structured logging with cluster/addon context - Update tests to verify error conditions This allows each ManagedClusterAddOn instance to use its specific template configuration rather than falling back to the ClusterManagementAddon default. πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: zhujian <[email protected]> * Fix error assertion logic in registration tests and improve error handling - Fix inverted error assertion logic in TestTemplateCSRConfigurationsFunc and TestTemplateCSRSignFunc - Change tests to properly check if expectedErr is empty vs non-empty - When no error expected, assert err == nil; when error expected, assert err != nil and contains substring - Fix strings.Contains argument order to check if actual error contains expected substring - Add nil template checks with proper error messages in CSRSign and PermissionConfig functions - Improve logging consistency with clusterName/addonName format across CSR functions - Guard against nil pointer access by checking err == nil before calling err.Error() πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: zhujian <[email protected]> --------- Signed-off-by: zhujian <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 01b66a6 commit ab41b86

File tree

10 files changed

+148
-85
lines changed

10 files changed

+148
-85
lines changed

β€Žgo.modβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ require (
3939
k8s.io/kube-aggregator v0.33.4
4040
k8s.io/kubectl v0.33.4
4141
k8s.io/utils v0.0.0-20241210054802-24370beab758
42-
open-cluster-management.io/addon-framework v1.0.1-0.20250811135502-4bae358d84c6
42+
open-cluster-management.io/addon-framework v1.0.1-0.20250910091630-7f19b89a319b
4343
open-cluster-management.io/api v1.0.1-0.20250903073454-c6702adf44cc
4444
open-cluster-management.io/sdk-go v1.0.1-0.20250911065113-bff262df709b
4545
sigs.k8s.io/about-api v0.0.0-20250131010323-518069c31c03

β€Žgo.sumβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ k8s.io/kubectl v0.33.4 h1:nXEI6Vi+oB9hXxoAHyHisXolm/l1qutK3oZQMak4N98=
555555
k8s.io/kubectl v0.33.4/go.mod h1:Xe7P9X4DfILvKmlBsVqUtzktkI56lEj22SJW7cFy6nE=
556556
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
557557
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
558-
open-cluster-management.io/addon-framework v1.0.1-0.20250811135502-4bae358d84c6 h1:l6XQEcd6lsvXw5NrKwd/jW+rqz19NRc/MT1gZ1cfBCw=
559-
open-cluster-management.io/addon-framework v1.0.1-0.20250811135502-4bae358d84c6/go.mod h1:fOPWaRyo6upgHFskcL18Al1kI2Ua9HzrS8uothWEe84=
558+
open-cluster-management.io/addon-framework v1.0.1-0.20250910091630-7f19b89a319b h1:/ZT+G/UyMa20gy2OnX30IByst0Ca3VV0lgyLt1miHjk=
559+
open-cluster-management.io/addon-framework v1.0.1-0.20250910091630-7f19b89a319b/go.mod h1:IrMjmd3dLjJtrP2Aqa0Sf/3lDysJHa4j5lNQQ13NxVs=
560560
open-cluster-management.io/api v1.0.1-0.20250903073454-c6702adf44cc h1:U8O6RhHjp088oWuQsGx6pwwFpOFgWo1gl9qhgIGgDpk=
561561
open-cluster-management.io/api v1.0.1-0.20250903073454-c6702adf44cc/go.mod h1:lEc5Wkc9ON5ym/qAtIqNgrE7NW7IEOCOC611iQMlnKM=
562562
open-cluster-management.io/sdk-go v1.0.1-0.20250911065113-bff262df709b h1:tzgcM+yJJBgMwYYbjfzW4kL8p7bsHnScE5lS/69lksE=

β€Žpkg/addon/templateagent/registration.goβ€Ž

Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
corev1 "k8s.io/api/core/v1"
1717
rbacv1 "k8s.io/api/rbac/v1"
1818
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19-
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2019
"k8s.io/client-go/kubernetes"
2120
"k8s.io/klog/v2"
2221

@@ -86,16 +85,18 @@ func (a *CRDTemplateAgentAddon) GetDesiredAddOnTemplate(addon *addonapiv1alpha1.
8685
return a.getDesiredAddOnTemplateInner(cma.Name, configReferences)
8786
}
8887

89-
func (a *CRDTemplateAgentAddon) TemplateCSRConfigurationsFunc() func(cluster *clusterv1.ManagedCluster) []addonapiv1alpha1.RegistrationConfig {
88+
func (a *CRDTemplateAgentAddon) TemplateCSRConfigurationsFunc() agent.CSRConfigurationsFunc {
9089

91-
return func(cluster *clusterv1.ManagedCluster) []addonapiv1alpha1.RegistrationConfig {
92-
template, err := a.GetDesiredAddOnTemplate(nil, cluster.Name, a.addonName)
90+
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn,
91+
) ([]addonapiv1alpha1.RegistrationConfig, error) {
92+
template, err := a.GetDesiredAddOnTemplate(addon, cluster.Name, a.addonName)
9393
if err != nil {
94-
a.logger.Info("CSRConfigurations failed to get addon template", "addonName", a.addonName, "error", err)
95-
return nil
94+
return nil, fmt.Errorf("CSRConfigurations failed to get addon template for addon %s/%s: %v",
95+
cluster.Name, a.addonName, err)
9696
}
9797
if template == nil {
98-
return nil
98+
return nil, fmt.Errorf("CSRConfigurations failed to get addon template for addon %s/%s, template is nil",
99+
cluster.Name, a.addonName)
99100
}
100101

101102
contain := func(rcs []addonapiv1alpha1.RegistrationConfig, signerName string) bool {
@@ -112,7 +113,11 @@ func (a *CRDTemplateAgentAddon) TemplateCSRConfigurationsFunc() func(cluster *cl
112113
switch registration.Type {
113114
case addonapiv1alpha1.RegistrationTypeKubeClient:
114115
if !contain(registrationConfigs, certificatesv1.KubeAPIServerClientSignerName) {
115-
configs := agent.KubeClientSignerConfigurations(a.addonName, a.agentName)(cluster)
116+
configs, err := agent.KubeClientSignerConfigurations(a.addonName, a.agentName)(cluster, addon)
117+
if err != nil {
118+
return nil, fmt.Errorf("failed to get kube signer config for %s/%s: %v",
119+
cluster.Name, a.addonName, err)
120+
}
116121
registrationConfigs = append(registrationConfigs, configs...)
117122
}
118123

@@ -121,29 +126,34 @@ func (a *CRDTemplateAgentAddon) TemplateCSRConfigurationsFunc() func(cluster *cl
121126
continue
122127
}
123128
if !contain(registrationConfigs, registration.CustomSigner.SignerName) {
124-
configs := CustomSignerConfigurations(
129+
configs, err := CustomSignerConfigurations(
125130
a.addonName, a.agentName, registration.CustomSigner)(cluster)
131+
if err != nil {
132+
return nil, fmt.Errorf("failed to get custom signer config for %s/%s: %v",
133+
cluster.Name, a.addonName, err)
134+
}
126135
registrationConfigs = append(registrationConfigs, configs...)
127136
}
128137

129138
default:
130-
utilruntime.HandleError(fmt.Errorf("unsupported registration type %s", registration.Type))
139+
a.logger.Info("CSRConfigurations unsupported registration type",
140+
"clusterName", cluster.Name, "addonName", a.addonName, "type", registration.Type)
131141
}
132142

133143
}
134144

135-
return registrationConfigs
145+
return registrationConfigs, nil
136146
}
137147
}
138148

139149
// CustomSignerConfigurations returns a func that can generate RegistrationConfig
140150
// for CustomSigner type registration addon
141151
func CustomSignerConfigurations(addonName, agentName string,
142152
customSignerConfig *addonapiv1alpha1.CustomSignerRegistrationConfig,
143-
) func(cluster *clusterv1.ManagedCluster) []addonapiv1alpha1.RegistrationConfig {
144-
return func(cluster *clusterv1.ManagedCluster) []addonapiv1alpha1.RegistrationConfig {
153+
) func(cluster *clusterv1.ManagedCluster) ([]addonapiv1alpha1.RegistrationConfig, error) {
154+
return func(cluster *clusterv1.ManagedCluster) ([]addonapiv1alpha1.RegistrationConfig, error) {
145155
if customSignerConfig == nil {
146-
utilruntime.HandleError(fmt.Errorf("custome signer is nil"))
156+
return nil, fmt.Errorf("custom signer config is nil")
147157
}
148158
config := addonapiv1alpha1.RegistrationConfig{
149159
SignerName: customSignerConfig.SignerName,
@@ -157,7 +167,7 @@ func CustomSignerConfigurations(addonName, agentName string,
157167
config.Subject = *customSignerConfig.Subject
158168
}
159169

160-
return []addonapiv1alpha1.RegistrationConfig{config}
170+
return []addonapiv1alpha1.RegistrationConfig{config}, nil
161171
}
162172
}
163173

@@ -168,10 +178,13 @@ func (a *CRDTemplateAgentAddon) TemplateCSRApproveCheckFunc() agent.CSRApproveFu
168178

169179
template, err := a.GetDesiredAddOnTemplate(addon, cluster.Name, a.addonName)
170180
if err != nil {
171-
a.logger.Info("CSRApproveCheck failed to get addon template", "addonName", a.addonName, "error", err)
181+
a.logger.Info("CSRApproveCheck failed to get addon template",
182+
"clusterName", cluster.Name, "addonName", a.addonName, "error", err)
172183
return false
173184
}
174185
if template == nil {
186+
a.logger.Info("CSRApproveCheck failed to get addon template, template is nil",
187+
"clusterName", cluster.Name, "addonName", a.addonName)
175188
return false
176189
}
177190

@@ -192,7 +205,8 @@ func (a *CRDTemplateAgentAddon) TemplateCSRApproveCheckFunc() agent.CSRApproveFu
192205
}
193206

194207
default:
195-
utilruntime.HandleError(fmt.Errorf("unsupported registration type %s", registration.Type))
208+
a.logger.Info("CSRApproveCheck unsupported registration type",
209+
"clusterName", cluster.Name, "addonName", a.addonName, "type", registration.Type)
196210
}
197211

198212
}
@@ -232,21 +246,16 @@ func CustomerSignerCSRApprover(logger klog.Logger, agentName string) agent.CSRAp
232246

233247
func (a *CRDTemplateAgentAddon) TemplateCSRSignFunc() agent.CSRSignerFunc {
234248

235-
return func(csr *certificatesv1.CertificateSigningRequest) []byte {
236-
// TODO: consider to change the agent.CSRSignerFun to accept parameter addon
237-
getClusterName := func(userName string) string {
238-
return csr.Labels[clusterv1.ClusterNameLabelKey]
239-
}
240-
241-
clusterName := getClusterName(csr.Spec.Username)
242-
template, err := a.GetDesiredAddOnTemplate(nil, clusterName, a.addonName)
249+
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn,
250+
csr *certificatesv1.CertificateSigningRequest) ([]byte, error) {
251+
template, err := a.GetDesiredAddOnTemplate(addon, cluster.Name, a.addonName)
243252
if err != nil {
244-
utilruntime.HandleError(fmt.Errorf("failed to get template for addon %s in cluster %s: %v",
245-
a.addonName, clusterName, err))
246-
return nil
253+
return nil, fmt.Errorf("CSRSign failed to get template for addon %s/%s: %v",
254+
cluster.Name, a.addonName, err)
247255
}
248256
if template == nil {
249-
return nil
257+
return nil, fmt.Errorf("CSRSign failed to get addon template for addon %s/%s, template is nil",
258+
cluster.Name, a.addonName)
250259
}
251260

252261
for _, registration := range template.Spec.Registration {
@@ -259,31 +268,33 @@ func (a *CRDTemplateAgentAddon) TemplateCSRSignFunc() agent.CSRSignerFunc {
259268
continue
260269
}
261270
if csr.Spec.SignerName == registration.CustomSigner.SignerName {
262-
return CustomSignerWithExpiry(a.hubKubeClient, registration.CustomSigner, 24*time.Hour)(csr)
271+
return CustomSignerWithExpiry(a.hubKubeClient, registration.CustomSigner, 24*time.Hour)(cluster, addon, csr)
263272
}
264273

265274
default:
266-
utilruntime.HandleError(fmt.Errorf("unsupported registration type %s", registration.Type))
275+
a.logger.Info("CSRSign unsupported registration type",
276+
"clusterName", cluster.Name, "addonName", a.addonName, "type", registration.Type)
267277
}
268278

269279
}
270280

271-
return nil
281+
return nil, nil
272282
}
273283
}
274284

275285
func CustomSignerWithExpiry(
276286
kubeclient kubernetes.Interface,
277287
customSignerConfig *addonapiv1alpha1.CustomSignerRegistrationConfig,
278-
duration time.Duration) agent.CSRSignerFunc {
279-
return func(csr *certificatesv1.CertificateSigningRequest) []byte {
288+
duration time.Duration,
289+
) agent.CSRSignerFunc {
290+
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn,
291+
csr *certificatesv1.CertificateSigningRequest) ([]byte, error) {
280292
if customSignerConfig == nil {
281-
utilruntime.HandleError(fmt.Errorf("custome signer is nil"))
282-
return nil
293+
return nil, fmt.Errorf("custom signer config is nil")
283294
}
284295

285296
if csr.Spec.SignerName != customSignerConfig.SignerName {
286-
return nil
297+
return nil, nil
287298
}
288299

289300
secretNamespace := AddonManagerNamespace()
@@ -293,18 +304,16 @@ func CustomSignerWithExpiry(
293304
caSecret, err := kubeclient.CoreV1().Secrets(secretNamespace).Get(
294305
context.TODO(), customSignerConfig.SigningCA.Name, metav1.GetOptions{})
295306
if err != nil {
296-
utilruntime.HandleError(fmt.Errorf("get custome signer ca %s/%s failed, %v",
297-
secretNamespace, customSignerConfig.SigningCA.Name, err))
298-
return nil
307+
return nil, fmt.Errorf("get custom signer ca %s/%s failed: %w",
308+
secretNamespace, customSignerConfig.SigningCA.Name, err)
299309
}
300310

301311
caData, caKey, err := extractCAdata(caSecret.Data[corev1.TLSCertKey], caSecret.Data[corev1.TLSPrivateKeyKey])
302312
if err != nil {
303-
utilruntime.HandleError(fmt.Errorf("get ca %s/%s data failed, %v",
304-
secretNamespace, customSignerConfig.SigningCA.Name, err))
305-
return nil
313+
return nil, fmt.Errorf("get ca %s/%s data failed: %w",
314+
secretNamespace, customSignerConfig.SigningCA.Name, err)
306315
}
307-
return utils.DefaultSignerWithExpiry(caKey, caData, duration)(csr)
316+
return utils.DefaultSignerWithExpiry(caKey, caData, duration)(cluster, addon, csr)
308317
}
309318
}
310319

@@ -348,10 +357,12 @@ func (a *CRDTemplateAgentAddon) TemplatePermissionConfigFunc() agent.PermissionC
348357
return func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn) error {
349358
template, err := a.GetDesiredAddOnTemplate(addon, cluster.Name, a.addonName)
350359
if err != nil {
351-
return err
360+
return fmt.Errorf("PermissionConfig failed to get addon template for addon %s/%s: %v",
361+
cluster.Name, a.addonName, err)
352362
}
353363
if template == nil {
354-
return nil
364+
return fmt.Errorf("PermissionConfig failed to get addon template for addon %s/%s, template is nil",
365+
cluster.Name, a.addonName)
355366
}
356367

357368
for _, registration := range template.Spec.Registration {
@@ -371,7 +382,8 @@ func (a *CRDTemplateAgentAddon) TemplatePermissionConfigFunc() agent.PermissionC
371382
continue
372383

373384
default:
374-
utilruntime.HandleError(fmt.Errorf("unsupported registration type %s", registration.Type))
385+
a.logger.Info("PermissionConfig unsupported registration type",
386+
"clusterName", cluster.Name, "addonName", a.addonName, "type", registration.Type)
375387
}
376388

377389
}

β€Žpkg/addon/templateagent/registration_test.goβ€Ž

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ func TestTemplateCSRConfigurationsFunc(t *testing.T) {
3737
addon *addonapiv1alpha1.ManagedClusterAddOn
3838
template *addonapiv1alpha1.AddOnTemplate
3939
expectedConfigs []addonapiv1alpha1.RegistrationConfig
40+
expectedErr string
4041
}{
4142
{
4243
name: "empty",
4344
cluster: NewFakeManagedCluster("cluster1"),
4445
addon: NewFakeTemplateManagedClusterAddon("addon1", "cluster1", "", ""),
4546
template: NewFakeAddonTemplate("template1", []addonapiv1alpha1.RegistrationSpec{}),
4647
expectedConfigs: []addonapiv1alpha1.RegistrationConfig{},
48+
expectedErr: "CSRConfigurations failed to get addon template for addon cluster1/addon1, template is nil",
4749
},
4850
{
4951
name: "kubeclient",
@@ -138,7 +140,19 @@ func TestTemplateCSRConfigurationsFunc(t *testing.T) {
138140

139141
agent := NewCRDTemplateAgentAddon(ctx, c.addon.Name, nil, addonClient, addonInformerFactory, nil, nil)
140142
f := agent.TemplateCSRConfigurationsFunc()
141-
registrationConfigs := f(c.cluster)
143+
registrationConfigs, err := f(c.cluster, c.addon)
144+
if c.expectedErr == "" {
145+
if err != nil {
146+
t.Fatalf("case: %s, expected no error but got: %v", c.name, err)
147+
}
148+
} else {
149+
if err == nil {
150+
t.Fatalf("case: %s, expected error but got none", c.name)
151+
}
152+
if !strings.Contains(err.Error(), c.expectedErr) {
153+
t.Fatalf("case: %s, expected error containing %q but got: %v", c.name, c.expectedErr, err)
154+
}
155+
}
142156
if !equality.Semantic.DeepEqual(registrationConfigs, c.expectedConfigs) {
143157
t.Errorf("expected registrationConfigs %v, but got %v", c.expectedConfigs, registrationConfigs)
144158
}
@@ -275,6 +289,7 @@ func TestTemplateCSRSignFunc(t *testing.T) {
275289
casecret *corev1.Secret
276290
csr *certificatesv1.CertificateSigningRequest
277291
expectedCert []byte
292+
expectedErr string
278293
}{
279294
{
280295
name: "kubeclient",
@@ -344,6 +359,7 @@ func TestTemplateCSRSignFunc(t *testing.T) {
344359
},
345360
},
346361
expectedCert: nil,
362+
expectedErr: `get custom signer ca open-cluster-management-hub/name1 failed: secrets "name1" not found`,
347363
},
348364
{
349365
name: "customsigner with ca secret",
@@ -383,6 +399,7 @@ func TestTemplateCSRSignFunc(t *testing.T) {
383399
},
384400
},
385401
expectedCert: nil,
402+
expectedErr: "failed to sign csr: PEM block type must be CERTIFICATE REQUEST",
386403
},
387404
}
388405
for _, c := range cases {
@@ -404,7 +421,19 @@ func TestTemplateCSRSignFunc(t *testing.T) {
404421

405422
agent := NewCRDTemplateAgentAddon(ctx, c.addon.Name, hubKubeClient, addonClient, addonInformerFactory, nil, nil)
406423
f := agent.TemplateCSRSignFunc()
407-
cert := f(c.csr)
424+
cert, err := f(c.cluster, c.addon, c.csr)
425+
if c.expectedErr == "" {
426+
if err != nil {
427+
t.Fatalf("case: %s, expected no error but got: %v", c.name, err)
428+
}
429+
} else {
430+
if err == nil {
431+
t.Fatalf("case: %s, expected error but got none", c.name)
432+
}
433+
if !strings.Contains(err.Error(), c.expectedErr) {
434+
t.Fatalf("case: %s, expected error containing %q but got: %v", c.name, c.expectedErr, err)
435+
}
436+
}
408437
if !bytes.Equal(cert, c.expectedCert) {
409438
t.Errorf("expected cert %v, but got %v", c.expectedCert, cert)
410439
}

β€Žtest/integration/addon/suite_test.goβ€Ž

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,16 @@ func (t *testAddon) GetAgentAddonOptions() agent.AgentAddonOptions {
157157

158158
if len(t.registrations) > 0 {
159159
option.Registration = &agent.RegistrationOption{
160-
CSRConfigurations: func(cluster *clusterv1.ManagedCluster) []addonapiv1alpha1.RegistrationConfig {
161-
return t.registrations[cluster.Name]
160+
CSRConfigurations: func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn,
161+
) ([]addonapiv1alpha1.RegistrationConfig, error) {
162+
return t.registrations[cluster.Name], nil
162163
},
163-
CSRApproveCheck: func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, csr *certificatesv1.CertificateSigningRequest) bool {
164+
CSRApproveCheck: func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn,
165+
csr *certificatesv1.CertificateSigningRequest) bool {
164166
return t.approveCSR
165167
},
166-
CSRSign: func(csr *certificatesv1.CertificateSigningRequest) []byte {
167-
return t.cert
168+
CSRSign: func(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, csr *certificatesv1.CertificateSigningRequest) ([]byte, error) {
169+
return t.cert, nil
168170
},
169171
}
170172
}

β€Žvendor/modules.txtβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1729,7 +1729,7 @@ k8s.io/utils/path
17291729
k8s.io/utils/pointer
17301730
k8s.io/utils/ptr
17311731
k8s.io/utils/trace
1732-
# open-cluster-management.io/addon-framework v1.0.1-0.20250811135502-4bae358d84c6
1732+
# open-cluster-management.io/addon-framework v1.0.1-0.20250910091630-7f19b89a319b
17331733
## explicit; go 1.24.0
17341734
open-cluster-management.io/addon-framework/pkg/addonfactory
17351735
open-cluster-management.io/addon-framework/pkg/addonmanager

0 commit comments

Comments
Β (0)