@@ -6,11 +6,15 @@ package cilium
6
6
import (
7
7
"context"
8
8
"fmt"
9
+ "time"
9
10
11
+ "github.com/go-logr/logr"
10
12
"github.com/spf13/pflag"
13
+ appsv1 "k8s.io/api/apps/v1"
11
14
corev1 "k8s.io/api/core/v1"
12
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
16
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
17
+ "sigs.k8s.io/cluster-api/controllers/remote"
14
18
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
15
19
ctrl "sigs.k8s.io/controller-runtime"
16
20
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -19,10 +23,12 @@ import (
19
23
commonhandlers "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers"
20
24
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle"
21
25
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables"
26
+ capiutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/utils"
22
27
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/addons"
23
28
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config"
24
29
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options"
25
30
handlersutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/utils"
31
+ "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/wait"
26
32
)
27
33
28
34
type CNIConfig struct {
@@ -221,7 +227,8 @@ func (c *CiliumCNI) apply(
221
227
),
222
228
c .client ,
223
229
helmChart ,
224
- )
230
+ ).
231
+ WithDefaultWaiter ()
225
232
case "" :
226
233
resp .SetStatus (runtimehooksv1 .ResponseStatusFailure )
227
234
resp .SetMessage ("strategy not specified for Cilium CNI addon" )
@@ -231,11 +238,129 @@ func (c *CiliumCNI) apply(
231
238
return
232
239
}
233
240
234
- if err := strategy . Apply (ctx , cluster , targetNamespace , log ); err != nil {
241
+ if err := runApply (ctx , c . client , cluster , strategy , targetNamespace , log ); err != nil {
235
242
resp .SetStatus (runtimehooksv1 .ResponseStatusFailure )
236
243
resp .SetMessage (err .Error ())
237
244
return
238
245
}
239
246
240
247
resp .SetStatus (runtimehooksv1 .ResponseStatusSuccess )
241
248
}
249
+
250
+ func runApply (
251
+ ctx context.Context ,
252
+ client ctrlclient.Client ,
253
+ cluster * clusterv1.Cluster ,
254
+ strategy addons.Applier ,
255
+ targetNamespace string ,
256
+ log logr.Logger ,
257
+ ) error {
258
+ if err := strategy .Apply (ctx , cluster , targetNamespace , log ); err != nil {
259
+ return err
260
+ }
261
+
262
+ // If skip kube-proxy is not set, return early.
263
+ // Otherwise, wait for Cilium to be rolled out and then cleanup kube-proxy if installed.
264
+ if ! capiutils .ShouldSkipKubeProxy (cluster ) {
265
+ return nil
266
+ }
267
+
268
+ log .Info (
269
+ fmt .Sprintf ("Waiting for Cilium to be ready for cluster %s" , ctrlclient .ObjectKeyFromObject (cluster )),
270
+ )
271
+ if err := waitForCiliumToBeReady (ctx , client , cluster ); err != nil {
272
+ return fmt .Errorf ("failed to wait for Cilium to be ready: %w" , err )
273
+ }
274
+
275
+ log .Info (
276
+ fmt .Sprintf ("Cleaning up kube-proxy for cluster %s" , ctrlclient .ObjectKeyFromObject (cluster )),
277
+ )
278
+ if err := cleanupKubeProxy (ctx , client , cluster ); err != nil {
279
+ return fmt .Errorf ("failed to cleanup kube-proxy: %w" , err )
280
+ }
281
+
282
+ return nil
283
+ }
284
+
285
+ const (
286
+ kubeProxyName = "kube-proxy"
287
+ kubeProxyNamespace = "kube-system"
288
+ )
289
+
290
+ func waitForCiliumToBeReady (
291
+ ctx context.Context ,
292
+ c ctrlclient.Client ,
293
+ cluster * clusterv1.Cluster ,
294
+ ) error {
295
+ remoteClient , err := remote .NewClusterClient (
296
+ ctx ,
297
+ "" ,
298
+ c ,
299
+ ctrlclient .ObjectKeyFromObject (cluster ),
300
+ )
301
+ if err != nil {
302
+ return fmt .Errorf ("error creating remote cluster client: %w" , err )
303
+ }
304
+
305
+ ds := & appsv1.DaemonSet {
306
+ ObjectMeta : metav1.ObjectMeta {
307
+ Name : defaultCiliumReleaseName ,
308
+ Namespace : defaultCiliumNamespace ,
309
+ },
310
+ }
311
+ if err := wait .ForObject (
312
+ ctx ,
313
+ wait.ForObjectInput [* appsv1.DaemonSet ]{
314
+ Reader : remoteClient ,
315
+ Target : ds .DeepCopy (),
316
+ Check : func (_ context.Context , obj * appsv1.DaemonSet ) (bool , error ) {
317
+ return obj .Status .NumberAvailable == obj .Status .DesiredNumberScheduled && obj .Status .NumberUnavailable == 0 , nil
318
+ },
319
+ Interval : 1 * time .Second ,
320
+ Timeout : 30 * time .Second ,
321
+ },
322
+ ); err != nil {
323
+ return fmt .Errorf (
324
+ "failed to wait for DaemonSet %s to be Ready: %w" ,
325
+ ctrlclient .ObjectKeyFromObject (ds ),
326
+ err ,
327
+ )
328
+ }
329
+
330
+ return nil
331
+ }
332
+
333
+ // cleanupKubeProxy cleans up kube-proxy DaemonSet and ConfigMap on the remote cluster when kube-proxy is disabled.
334
+ func cleanupKubeProxy (ctx context.Context , c ctrlclient.Client , cluster * clusterv1.Cluster ) error {
335
+ remoteClient , err := remote .NewClusterClient (
336
+ ctx ,
337
+ "" ,
338
+ c ,
339
+ ctrlclient .ObjectKeyFromObject (cluster ),
340
+ )
341
+ if err != nil {
342
+ return fmt .Errorf ("error creating remote cluster client: %w" , err )
343
+ }
344
+
345
+ objs := []ctrlclient.Object {
346
+ & appsv1.DaemonSet {
347
+ ObjectMeta : metav1.ObjectMeta {
348
+ Name : kubeProxyName ,
349
+ Namespace : kubeProxyNamespace ,
350
+ },
351
+ },
352
+ & corev1.ConfigMap {
353
+ ObjectMeta : metav1.ObjectMeta {
354
+ Name : kubeProxyName ,
355
+ Namespace : kubeProxyNamespace ,
356
+ },
357
+ },
358
+ }
359
+ for _ , obj := range objs {
360
+ if err := ctrlclient .IgnoreNotFound (remoteClient .Delete (ctx , obj )); err != nil {
361
+ return fmt .Errorf ("failed to delete %s/%s: %w" , obj .GetNamespace (), obj .GetName (), err )
362
+ }
363
+ }
364
+
365
+ return nil
366
+ }
0 commit comments