@@ -2,6 +2,7 @@ package addontemplate
2
2
3
3
import (
4
4
"context"
5
+ "reflect"
5
6
"time"
6
7
7
8
"github.com/openshift/library-go/pkg/controller/factory"
@@ -14,6 +15,7 @@ import (
14
15
"k8s.io/client-go/kubernetes"
15
16
"k8s.io/client-go/rest"
16
17
"k8s.io/client-go/tools/cache"
18
+ "k8s.io/client-go/util/workqueue"
17
19
"k8s.io/klog/v2"
18
20
19
21
"open-cluster-management.io/addon-framework/pkg/addonfactory"
@@ -52,6 +54,7 @@ type addonTemplateController struct {
52
54
workInformers workv1informers.SharedInformerFactory
53
55
runControllerFunc runController
54
56
eventRecorder events.Recorder
57
+ queue workqueue.TypedRateLimitingInterface [any ]
55
58
}
56
59
57
60
type runController func (ctx context.Context , addonName string ) error
@@ -69,6 +72,9 @@ func NewAddonTemplateController(
69
72
recorder events.Recorder ,
70
73
runController ... runController ,
71
74
) factory.Controller {
75
+ controllerName := "addon-template-controller"
76
+ syncCtx := factory .NewSyncContext (controllerName , recorder )
77
+
72
78
c := & addonTemplateController {
73
79
kubeConfig : hubKubeconfig ,
74
80
kubeClient : hubKubeClient ,
@@ -82,6 +88,7 @@ func NewAddonTemplateController(
82
88
dynamicInformers : dynamicInformers ,
83
89
workInformers : workInformers ,
84
90
eventRecorder : recorder ,
91
+ queue : syncCtx .Queue (),
85
92
}
86
93
87
94
if len (runController ) > 0 {
@@ -90,39 +97,78 @@ func NewAddonTemplateController(
90
97
// easy to mock in unit tests
91
98
c .runControllerFunc = c .runController
92
99
}
93
- return factory .New ().
100
+
101
+ controller := factory .New ().
102
+ WithSyncContext (syncCtx ).
94
103
WithInformersQueueKeysFunc (
95
104
queue .QueueKeyByMetaNamespaceName ,
96
105
addonInformers .Addon ().V1alpha1 ().ClusterManagementAddOns ().Informer ()).
97
- WithFilteredEventsInformersQueueKeysFunc (
98
- queue .QueueKeyByMetaName ,
99
- func (obj interface {}) bool {
100
- mca , ok := obj .(* addonv1alpha1.ManagedClusterAddOn )
101
- if ! ok {
102
- return false
103
- }
104
-
105
- // Only process ManagedClusterAddOns that reference AddOnTemplates
106
- for _ , configRef := range mca .Status .ConfigReferences {
107
- if configRef .ConfigGroupResource .Group == "addon.open-cluster-management.io" &&
108
- configRef .ConfigGroupResource .Resource == "addontemplates" {
109
- return true
110
- }
111
- }
112
- return false
113
- },
114
- addonInformers .Addon ().V1alpha1 ().ManagedClusterAddOns ().Informer ()).
115
106
WithBareInformers (
107
+ addonInformers .Addon ().V1alpha1 ().ManagedClusterAddOns ().Informer (),
116
108
// do not need to queue, just make sure the controller reconciles after the addonTemplate cache is synced
117
109
// otherwise, there will be "xx-addon-template" not found" errors in the log as the controller uses the
118
110
// addonTemplate lister to get the template object
119
111
addonInformers .Addon ().V1alpha1 ().AddOnTemplates ().Informer ()).
120
112
WithSync (c .sync ).
121
113
ToController ("addon-template-controller" , recorder )
114
+
115
+ // Add custom event handler for ManagedClusterAddon to filter configReference changes
116
+ _ , err := addonInformers .Addon ().V1alpha1 ().ManagedClusterAddOns ().Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
117
+ UpdateFunc : func (oldObj , newObj interface {}) {
118
+ // Only handle configReference updates for AddOnTemplates
119
+ oldMCA , ok := oldObj .(* addonv1alpha1.ManagedClusterAddOn )
120
+ if ! ok {
121
+ return
122
+ }
123
+ newMCA , ok := newObj .(* addonv1alpha1.ManagedClusterAddOn )
124
+ if ! ok {
125
+ return
126
+ }
127
+
128
+ // Extract AddOnTemplate configReferences from both old and new
129
+ oldTemplateRefs := extractAddOnTemplateConfigRefs (oldMCA )
130
+ newTemplateRefs := extractAddOnTemplateConfigRefs (newMCA )
131
+
132
+ // Only process if AddOnTemplate configReferences changed
133
+ if ! reflect .DeepEqual (oldTemplateRefs , newTemplateRefs ) {
134
+ // Queue the addon name to trigger reconciliation
135
+ c .queue .Add (newMCA .Name )
136
+ }
137
+ },
138
+ DeleteFunc : func (obj interface {}) {
139
+ mca , ok := obj .(* addonv1alpha1.ManagedClusterAddOn )
140
+ if ! ok {
141
+ return
142
+ }
143
+
144
+ // Only process template-based addons
145
+ templateRefs := extractAddOnTemplateConfigRefs (mca )
146
+ if len (templateRefs ) > 0 {
147
+ c .queue .Add (mca .Name )
148
+ }
149
+ },
150
+ })
151
+ if err != nil {
152
+ utilruntime .HandleError (err )
153
+ }
154
+
155
+ return controller
156
+ }
157
+
158
+ // extractAddOnTemplateConfigRefs extracts only AddOnTemplate configReferences
159
+ func extractAddOnTemplateConfigRefs (mca * addonv1alpha1.ManagedClusterAddOn ) []addonv1alpha1.ConfigReference {
160
+ var templateRefs []addonv1alpha1.ConfigReference
161
+ for _ , configRef := range mca .Status .ConfigReferences {
162
+ if configRef .ConfigGroupResource .Group == "addon.open-cluster-management.io" &&
163
+ configRef .ConfigGroupResource .Resource == "addontemplates" {
164
+ templateRefs = append (templateRefs , configRef )
165
+ }
166
+ }
167
+ return templateRefs
122
168
}
123
169
124
170
func (c * addonTemplateController ) stopUnusedManagers (
125
- ctx context.Context , syncCtx factory.SyncContext , addOnName string ) error {
171
+ ctx context.Context , _ factory.SyncContext , addOnName string ) error {
126
172
logger := klog .FromContext (ctx )
127
173
128
174
// Check if all managed cluster addon instances are deleted before stopping the manager
0 commit comments