@@ -25,6 +25,7 @@ import (
25
25
"github.com/go-logr/logr"
26
26
"k8s.io/apimachinery/pkg/api/errors"
27
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28
29
"k8s.io/apimachinery/pkg/runtime/schema"
29
30
"k8s.io/apimachinery/pkg/util/runtime"
30
31
"k8s.io/apimachinery/pkg/util/wait"
@@ -37,94 +38,80 @@ import (
37
38
"kusionstack.io/kube-utils/multicluster/metrics"
38
39
)
39
40
40
- type ClusterManagementType string
41
-
42
- const (
43
- OpenClusterManagement ClusterManagementType = "OpenClusterManagement"
44
- TestCluterManagement ClusterManagementType = "TestCluterManagement"
45
- )
41
+ type ClusterProvider interface {
42
+ Init ( config * rest. Config ) // Init is used to initialize the cluster provider, config is the kubeconfig for the fed cluster
43
+ GetClusterMangementGVR () schema. GroupVersionResource // The GVR will be used to watch cluster management resource
44
+ GetClusterName ( obj * unstructured. Unstructured ) string // Get cluster name from cluster management resource, cluster name is used to identify the cluster
45
+ GetClusterConfig ( obj * unstructured. Unstructured ) * rest. Config // Get kubeconfig from cluster management resource
46
+ }
46
47
47
48
type Controller struct {
48
- config * rest.Config
49
- clusterManagementType ClusterManagementType
50
- clusterManagementGVR schema.GroupVersionResource
49
+ config * rest.Config
50
+ clusterProvider ClusterProvider
51
51
52
- client dynamic.Interface // client to get cluster info
52
+ client dynamic.Interface // Client to get cluster info
53
53
informerFactory dynamicinformer.DynamicSharedInformerFactory
54
54
informer cache.SharedIndexInformer
55
55
workqueue workqueue.RateLimitingInterface
56
56
57
- mutex sync.Mutex
58
- syncedNum int // number of synced cluster
59
- syncedCh chan struct {}
57
+ mutex sync.RWMutex
58
+ syncedNum int // Number of synced cluster
59
+ syncedCh chan struct {} // Channel to notify all synced clusters have been processed
60
60
61
- addUpdateHandler func (string ) error // when cluster is added or updated, this handler will be called
62
- deleteHandler func (string ) // when cluster is deleted, this handler will be called
63
- log logr.Logger
61
+ addUpdateHandler func (string ) error // When cluster is added or updated, this handler will be invoked
62
+ deleteHandler func (string ) // When cluster is deleted, this handler will be invoked
64
63
65
- // for test
66
- restConfigForCluster func (cluster string ) * rest.Config
64
+ clusterNameToNamespacedKey map [string ]string
65
+ namespacedKeyToObj map [string ]* unstructured.Unstructured
66
+ log logr.Logger
67
67
}
68
68
69
69
type ControllerConfig struct {
70
- Config * rest.Config // config for cluster management
71
- ClusterManagementType ClusterManagementType
72
- ClusterManagementGVR * schema.GroupVersionResource
73
- ResyncPeriod time.Duration // resync period for cluster management
74
- Log logr.Logger
75
-
76
- // for test
77
- RestConfigForCluster func (cluster string ) * rest.Config
70
+ Config * rest.Config // Kubeconfig for the fed cluster
71
+ ClusterProvider ClusterProvider
72
+ ResyncPeriod time.Duration // Resync period for cluster management
73
+ Log logr.Logger
78
74
}
79
75
80
76
// NewController creates a new Controller which will process events about cluster.
81
77
func NewController (cfg * ControllerConfig ) (* Controller , error ) {
82
- var clusterManagementGVR schema.GroupVersionResource
83
- switch cfg .ClusterManagementType {
84
- case OpenClusterManagement :
85
- if cfg .ClusterManagementGVR == nil {
86
- return nil , fmt .Errorf ("ClusterManagementGVR must be set when use %s" , cfg .ClusterManagementType )
87
- }
88
- clusterManagementGVR = * cfg .ClusterManagementGVR
89
- case TestCluterManagement :
90
- if cfg .ClusterManagementGVR == nil || cfg .RestConfigForCluster == nil {
91
- return nil , fmt .Errorf ("ClusterManagementGVR and RestConfigForCluster must be set when use %s" , cfg .ClusterManagementType )
92
- }
93
- clusterManagementGVR = * cfg .ClusterManagementGVR
94
- default :
95
- return nil , fmt .Errorf ("not support cluster management type: %v" , cfg .ClusterManagementType )
96
- }
97
-
98
78
client , err := dynamic .NewForConfig (cfg .Config )
99
79
if err != nil {
100
80
return nil , err
101
81
}
82
+ if cfg .ClusterProvider == nil {
83
+ return nil , fmt .Errorf ("ClusterProvider is required" )
84
+ }
85
+
102
86
informerFactory := dynamicinformer .NewDynamicSharedInformerFactory (client , cfg .ResyncPeriod )
103
- informer := informerFactory .ForResource (clusterManagementGVR ).Informer ()
87
+ informer := informerFactory .ForResource (cfg . ClusterProvider . GetClusterMangementGVR () ).Informer ()
104
88
105
89
return & Controller {
106
- config : cfg .Config ,
107
- client : client ,
108
- informerFactory : informerFactory ,
109
- clusterManagementType : cfg .ClusterManagementType ,
110
- clusterManagementGVR : clusterManagementGVR ,
111
- informer : informer ,
112
- workqueue : workqueue .NewNamedRateLimitingQueue (workqueue .DefaultControllerRateLimiter (), clusterManagementGVR .Resource ),
113
- syncedCh : make (chan struct {}),
114
- log : cfg .Log ,
115
-
116
- restConfigForCluster : cfg .RestConfigForCluster ,
90
+ config : cfg .Config ,
91
+ clusterProvider : cfg .ClusterProvider ,
92
+
93
+ client : client ,
94
+ informerFactory : informerFactory ,
95
+ informer : informer ,
96
+ workqueue : workqueue .NewNamedRateLimitingQueue (workqueue .DefaultControllerRateLimiter (), cfg .ClusterProvider .GetClusterMangementGVR ().Resource ),
97
+ syncedCh : make (chan struct {}),
98
+
99
+ clusterNameToNamespacedKey : make (map [string ]string ), // Get namespaced key by cluster name
100
+ namespacedKeyToObj : make (map [string ]* unstructured.Unstructured ), // Get cluster management resource by namespaced key
101
+ log : cfg .Log ,
117
102
}, nil
118
103
}
119
104
120
- // AddEventHandler adds handler for events about cluster.
105
+ // AddEventHandler adds handlers which will be invoked.
106
+ // When cluster is added or updated, addUpdateHandler will be invoked.
107
+ // When cluster is deleted, deleteHandler will be invoked.
121
108
func (c * Controller ) AddEventHandler (addUpdateHandler func (string ) error , deleteHandler func (string )) {
122
109
c .informer .AddEventHandler (cache.ResourceEventHandlerFuncs {
123
- AddFunc : c .enqueueClusterExtension ,
110
+ AddFunc : c .enqueueClusterEvent ,
124
111
UpdateFunc : func (old , new interface {}) {
125
- c .enqueueClusterExtension (new )
112
+ c .enqueueClusterEvent (new )
126
113
},
127
- DeleteFunc : c .enqueueClusterExtension ,
114
+ DeleteFunc : c .enqueueClusterEvent ,
128
115
})
129
116
130
117
c .addUpdateHandler = addUpdateHandler
@@ -135,6 +122,8 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
135
122
defer runtime .HandleCrash ()
136
123
defer c .workqueue .ShutDown ()
137
124
125
+ c .clusterProvider .Init (c .config )
126
+
138
127
c .informerFactory .Start (stopCh )
139
128
140
129
// Wait for the caches to be synced before starting workers
@@ -164,10 +153,9 @@ func (c *Controller) WaitForSynced(ctx context.Context) bool {
164
153
}
165
154
}
166
155
167
- func (c * Controller ) enqueueClusterExtension (obj interface {}) {
168
- var key string
169
- var err error
170
- if key , err = cache .MetaNamespaceKeyFunc (obj ); err != nil {
156
+ func (c * Controller ) enqueueClusterEvent (obj interface {}) {
157
+ key , err := cache .MetaNamespaceKeyFunc (obj )
158
+ if err != nil {
171
159
c .log .Error (err , "failed to get enqueue key" )
172
160
return
173
161
}
@@ -205,11 +193,9 @@ func (c *Controller) processNextWorkItem() bool {
205
193
206
194
if err := c .eventHandler (key ); err != nil {
207
195
c .workqueue .AddRateLimited (key )
208
- metrics .NewControllerEventCountMetrics (key , "failed" ).Inc ()
209
196
return err
210
197
}
211
198
212
- metrics .NewControllerEventCountMetrics (key , "ok" ).Inc ()
213
199
c .workqueue .Forget (obj )
214
200
return nil
215
201
}(obj )
@@ -228,35 +214,60 @@ func (c *Controller) eventHandler(key string) error {
228
214
return nil
229
215
}
230
216
231
- _ , err = c .client .Resource (c .clusterManagementGVR ).Namespace (namespace ).Get (context .Background (), name , metav1.GetOptions {})
217
+ obj , err : = c .client .Resource (c .clusterProvider . GetClusterMangementGVR () ).Namespace (namespace ).Get (context .Background (), name , metav1.GetOptions {})
232
218
if err != nil {
233
219
if errors .IsNotFound (err ) {
234
- c .deleteHandler (name )
220
+ c .mutex .Lock ()
221
+ defer c .mutex .Unlock ()
222
+
223
+ oldObj , ok := c .namespacedKeyToObj [key ]
224
+ if ! ok {
225
+ return nil
226
+ }
227
+ delete (c .namespacedKeyToObj , key )
228
+
229
+ clusterName := c .clusterProvider .GetClusterName (oldObj )
230
+ delete (c .clusterNameToNamespacedKey , clusterName )
231
+
232
+ metrics .NewClusterEventCountMetrics (key , "delete" , "true" ).Inc ()
233
+ c .deleteHandler (clusterName )
235
234
return nil
236
235
}
236
+ metrics .NewClusterEventCountMetrics (key , "delete" , "false" ).Inc ()
237
237
c .log .Error (err , "failed to get resource" , "key" , key )
238
238
return err
239
239
}
240
240
241
- err = c .addUpdateHandler (name )
241
+ c .mutex .Lock ()
242
+ c .namespacedKeyToObj [key ] = obj
243
+ clusterName := c .clusterProvider .GetClusterName (obj )
244
+ c .clusterNameToNamespacedKey [clusterName ] = key
245
+ c .mutex .Unlock ()
246
+
247
+ err = c .addUpdateHandler (clusterName )
242
248
if err != nil {
249
+ metrics .NewClusterEventCountMetrics (key , "add-update" , "false" ).Inc ()
243
250
c .log .Error (err , "failed to add or update cluster" , "key" , key )
244
251
return err
245
252
}
246
253
254
+ metrics .NewClusterEventCountMetrics (key , "add-update" , "true" ).Inc ()
247
255
return nil
248
256
}
249
257
250
258
// RestConfigForCluster returns the rest config for the mangered cluster.
251
- func (c * Controller ) RestConfigForCluster (cluster string ) * rest.Config {
252
- switch c .clusterManagementType {
253
- case OpenClusterManagement :
254
- clusterConfig := * c .config
255
- clusterConfig .Host = fmt .Sprintf ("%s/apis/%s/%s/%s/%s/proxy" , clusterConfig .Host , c .clusterManagementGVR .Group , c .clusterManagementGVR .Version , c .clusterManagementGVR .Resource , cluster )
256
- return & clusterConfig
257
- case TestCluterManagement :
258
- return c .restConfigForCluster (cluster )
259
- default :
259
+ func (c * Controller ) RestConfigForCluster (clusterName string ) * rest.Config {
260
+ c .mutex .RLock ()
261
+ defer c .mutex .RUnlock ()
262
+
263
+ namespacedKey , ok := c .clusterNameToNamespacedKey [clusterName ]
264
+ if ! ok {
265
+ return nil
266
+ }
267
+
268
+ obj , ok := c .namespacedKeyToObj [namespacedKey ]
269
+ if ! ok {
260
270
return nil
261
271
}
272
+ return c .clusterProvider .GetClusterConfig (obj )
262
273
}
0 commit comments