github.com/cilium/cilium@v1.16.2/operator/cmd/root.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package cmd 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "log/slog" 11 "os" 12 "path/filepath" 13 "sync" 14 "sync/atomic" 15 "time" 16 17 "github.com/cilium/hive/cell" 18 "github.com/sirupsen/logrus" 19 "github.com/spf13/cobra" 20 "github.com/spf13/viper" 21 "google.golang.org/grpc" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/apimachinery/pkg/util/rand" 24 "k8s.io/client-go/tools/leaderelection" 25 "k8s.io/client-go/tools/leaderelection/resourcelock" 26 27 operatorApi "github.com/cilium/cilium/api/v1/operator/server" 28 ciliumdbg "github.com/cilium/cilium/cilium-dbg/cmd" 29 "github.com/cilium/cilium/operator/api" 30 "github.com/cilium/cilium/operator/auth" 31 "github.com/cilium/cilium/operator/endpointgc" 32 "github.com/cilium/cilium/operator/identitygc" 33 operatorK8s "github.com/cilium/cilium/operator/k8s" 34 operatorMetrics "github.com/cilium/cilium/operator/metrics" 35 operatorOption "github.com/cilium/cilium/operator/option" 36 "github.com/cilium/cilium/operator/pkg/bgpv2" 37 "github.com/cilium/cilium/operator/pkg/ciliumendpointslice" 38 "github.com/cilium/cilium/operator/pkg/ciliumenvoyconfig" 39 controllerruntime "github.com/cilium/cilium/operator/pkg/controller-runtime" 40 gatewayapi "github.com/cilium/cilium/operator/pkg/gateway-api" 41 "github.com/cilium/cilium/operator/pkg/ingress" 42 "github.com/cilium/cilium/operator/pkg/lbipam" 43 "github.com/cilium/cilium/operator/pkg/networkpolicy" 44 "github.com/cilium/cilium/operator/pkg/nodeipam" 45 "github.com/cilium/cilium/operator/pkg/secretsync" 46 operatorWatchers "github.com/cilium/cilium/operator/watchers" 47 "github.com/cilium/cilium/pkg/clustermesh/endpointslicesync" 48 "github.com/cilium/cilium/pkg/clustermesh/mcsapi" 49 operatorClusterMesh "github.com/cilium/cilium/pkg/clustermesh/operator" 50 cmtypes "github.com/cilium/cilium/pkg/clustermesh/types" 51 "github.com/cilium/cilium/pkg/controller" 52 "github.com/cilium/cilium/pkg/defaults" 53 "github.com/cilium/cilium/pkg/dial" 54 "github.com/cilium/cilium/pkg/gops" 55 "github.com/cilium/cilium/pkg/hive" 56 "github.com/cilium/cilium/pkg/ipam/allocator" 57 ipamOption "github.com/cilium/cilium/pkg/ipam/option" 58 "github.com/cilium/cilium/pkg/k8s/apis" 59 k8sClient "github.com/cilium/cilium/pkg/k8s/client" 60 k8sversion "github.com/cilium/cilium/pkg/k8s/version" 61 "github.com/cilium/cilium/pkg/kvstore" 62 "github.com/cilium/cilium/pkg/kvstore/store" 63 "github.com/cilium/cilium/pkg/logging" 64 "github.com/cilium/cilium/pkg/logging/logfields" 65 "github.com/cilium/cilium/pkg/metrics" 66 "github.com/cilium/cilium/pkg/option" 67 "github.com/cilium/cilium/pkg/pprof" 68 "github.com/cilium/cilium/pkg/version" 69 ) 70 71 var ( 72 Operator = cell.Module( 73 "operator", 74 "Cilium Operator", 75 76 Infrastructure, 77 ControlPlane, 78 ) 79 80 Infrastructure = cell.Module( 81 "operator-infra", 82 "Operator Infrastructure", 83 84 // Register the pprof HTTP handlers, to get runtime profiling data. 85 pprof.Cell, 86 cell.ProvidePrivate(func(cfg operatorPprofConfig) pprof.Config { 87 return pprof.Config{ 88 Pprof: cfg.OperatorPprof, 89 PprofAddress: cfg.OperatorPprofAddress, 90 PprofPort: cfg.OperatorPprofPort, 91 } 92 }), 93 cell.Config(operatorPprofConfig{ 94 OperatorPprofAddress: operatorOption.PprofAddressOperator, 95 OperatorPprofPort: operatorOption.PprofPortOperator, 96 }), 97 98 // Runs the gops agent, a tool to diagnose Go processes. 99 gops.Cell(defaults.GopsPortOperator), 100 101 // Provides Clientset, API for accessing Kubernetes objects. 102 k8sClient.Cell, 103 104 // Provides a ClientBuilderFunc that can be used by other cells to create a client. 105 k8sClient.ClientBuilderCell, 106 107 // Provides the modular metrics registry, metric HTTP server and legacy metrics cell. 108 operatorMetrics.Cell, 109 cell.Provide(func( 110 operatorCfg *operatorOption.OperatorConfig, 111 ) operatorMetrics.SharedConfig { 112 return operatorMetrics.SharedConfig{ 113 // Cloud provider specific allocators needs to read operatorCfg.EnableMetrics 114 // to add their metrics when it's set to true. Therefore, we leave the flag as global 115 // instead of declaring it as part of the metrics cell. 116 // This should be changed once the IPAM allocator is modularized. 117 EnableMetrics: operatorCfg.EnableMetrics, 118 EnableGatewayAPI: operatorCfg.EnableGatewayAPI, 119 } 120 }), 121 ) 122 123 // ControlPlane implements the control functions. 124 ControlPlane = cell.Module( 125 "operator-controlplane", 126 "Operator Control Plane", 127 128 cell.Config(cmtypes.DefaultClusterInfo), 129 cell.Invoke(cmtypes.ClusterInfo.InitClusterIDMax), 130 cell.Invoke(cmtypes.ClusterInfo.Validate), 131 132 cell.Invoke( 133 registerOperatorHooks, 134 ), 135 136 cell.Provide(func() *option.DaemonConfig { 137 return option.Config 138 }), 139 140 cell.Provide(func() *operatorOption.OperatorConfig { 141 return operatorOption.Config 142 }), 143 144 cell.Provide(func( 145 daemonCfg *option.DaemonConfig, 146 operatorCfg *operatorOption.OperatorConfig, 147 ) identitygc.SharedConfig { 148 return identitygc.SharedConfig{ 149 IdentityAllocationMode: daemonCfg.IdentityAllocationMode, 150 } 151 }), 152 153 cell.Provide(func( 154 daemonCfg *option.DaemonConfig, 155 ) ciliumendpointslice.SharedConfig { 156 return ciliumendpointslice.SharedConfig{ 157 EnableCiliumEndpointSlice: daemonCfg.EnableCiliumEndpointSlice, 158 } 159 }), 160 161 cell.Provide(func( 162 operatorCfg *operatorOption.OperatorConfig, 163 daemonCfg *option.DaemonConfig, 164 ) endpointgc.SharedConfig { 165 return endpointgc.SharedConfig{ 166 Interval: operatorCfg.EndpointGCInterval, 167 DisableCiliumEndpointCRD: daemonCfg.DisableCiliumEndpointCRD, 168 } 169 }), 170 171 api.HealthHandlerCell( 172 kvstoreEnabled, 173 isLeader.Load, 174 ), 175 api.MetricsHandlerCell, 176 controller.Cell, 177 operatorApi.SpecCell, 178 api.ServerCell, 179 180 // These cells are started only after the operator is elected leader. 181 WithLeaderLifecycle( 182 // The CRDs registration should be the first operation to be invoked after the operator is elected leader. 183 apis.RegisterCRDsCell, 184 operatorK8s.ResourcesCell, 185 186 bgpv2.Cell, 187 lbipam.Cell, 188 nodeipam.Cell, 189 auth.Cell, 190 store.Cell, 191 operatorClusterMesh.Cell, 192 endpointslicesync.Cell, 193 mcsapi.Cell, 194 legacyCell, 195 196 // When running in kvstore mode, the start hook of the identity GC 197 // cell blocks until the kvstore client has been initialized, which 198 // is performed by the legacyCell start hook. Hence, the identity GC 199 // cell is registered afterwards, to ensure the ordering of the 200 // setup operations. This is a hacky workaround until the kvstore is 201 // refactored into a proper cell. 202 identitygc.Cell, 203 204 // CiliumEndpointSlice controller depends on the CiliumEndpoint and 205 // CiliumEndpointSlice resources. It reconciles the state of CESs in the 206 // cluster based on the CEPs and CESs events. 207 // It is disabled if CiliumEndpointSlice is disabled in the cluster - 208 // when --enable-cilium-endpoint-slice is false. 209 ciliumendpointslice.Cell, 210 211 // Cilium Endpoint Garbage Collector. It removes all leaked Cilium 212 // Endpoints. Either once or periodically it validates all the present 213 // Cilium Endpoints and delete the ones that should be deleted. 214 endpointgc.Cell, 215 216 // Integrates the controller-runtime library and provides its components via Hive. 217 controllerruntime.Cell, 218 219 // Cilium Gateway API controller that manages the Gateway API related CRDs. 220 gatewayapi.Cell, 221 222 // Cilium Ingress controller that manages the Kubernetes Ingress related CRDs. 223 ingress.Cell, 224 225 // Cilium Secret synchronizes K8s TLS Secrets referenced by 226 // Ciliums "Ingress resources" from the application namespaces into a dedicated 227 // secrets namespace that is accessible by the Cilium Agents. 228 // Resources might be K8s `Ingress` or Gateway API `Gateway`. 229 secretsync.Cell, 230 231 // Cilium L7 LoadBalancing with Envoy. 232 ciliumenvoyconfig.Cell, 233 234 // Informational policy validation. 235 networkpolicy.Cell, 236 237 // Provide the logic to map DNS names matching Kubernetes services to the 238 // corresponding ClusterIP, without depending on CoreDNS. Leveraged by etcd 239 // and clustermesh. 240 dial.ServiceResolverCell, 241 ), 242 ) 243 244 binaryName = filepath.Base(os.Args[0]) 245 246 log = logging.DefaultLogger.WithField(logfields.LogSubsys, binaryName) 247 248 FlagsHooks []ProviderFlagsHooks 249 250 leaderElectionResourceLockName = "cilium-operator-resource-lock" 251 252 // Use a Go context so we can tell the leaderelection code when we 253 // want to step down 254 leaderElectionCtx context.Context 255 leaderElectionCtxCancel context.CancelFunc 256 257 // isLeader is an atomic boolean value that is true when the Operator is 258 // elected leader. Otherwise, it is false. 259 isLeader atomic.Bool 260 ) 261 262 func NewOperatorCmd(h *hive.Hive) *cobra.Command { 263 cmd := &cobra.Command{ 264 Use: binaryName, 265 Short: "Run " + binaryName, 266 Run: func(cobraCmd *cobra.Command, args []string) { 267 cmdRefDir := h.Viper().GetString(option.CMDRef) 268 if cmdRefDir != "" { 269 genMarkdown(cobraCmd, cmdRefDir) 270 os.Exit(0) 271 } 272 273 initEnv(h.Viper()) 274 275 if err := h.Run(logging.DefaultSlogLogger); err != nil { 276 log.Fatal(err) 277 } 278 }, 279 } 280 281 h.RegisterFlags(cmd.Flags()) 282 283 // Enable fallback to direct API probing to check for support of Leases in 284 // case Discovery API fails. 285 h.Viper().Set(option.K8sEnableAPIDiscovery, true) 286 287 // Overwrite the metrics namespace with the one specific for the Operator 288 metrics.Namespace = metrics.CiliumOperatorNamespace 289 290 cmd.AddCommand( 291 MetricsCmd, 292 StatusCmd, 293 ciliumdbg.TroubleshootCmd, 294 h.Command(), 295 ) 296 297 InitGlobalFlags(cmd, h.Viper()) 298 for _, hook := range FlagsHooks { 299 hook.RegisterProviderFlag(cmd, h.Viper()) 300 } 301 302 cobra.OnInitialize(option.InitConfig(cmd, "Cilium-Operator", "cilium-operators", h.Viper())) 303 304 return cmd 305 } 306 307 func Execute(cmd *cobra.Command) { 308 if err := cmd.Execute(); err != nil { 309 fmt.Println(err) 310 os.Exit(1) 311 } 312 } 313 314 func registerOperatorHooks(log *slog.Logger, lc cell.Lifecycle, llc *LeaderLifecycle, clientset k8sClient.Clientset, shutdowner hive.Shutdowner) { 315 var wg sync.WaitGroup 316 lc.Append(cell.Hook{ 317 OnStart: func(cell.HookContext) error { 318 wg.Add(1) 319 go func() { 320 runOperator(log, llc, clientset, shutdowner) 321 wg.Done() 322 }() 323 return nil 324 }, 325 OnStop: func(ctx cell.HookContext) error { 326 if err := llc.Stop(log, ctx); err != nil { 327 return err 328 } 329 doCleanup() 330 wg.Wait() 331 return nil 332 }, 333 }) 334 } 335 336 func initEnv(vp *viper.Viper) { 337 // Prepopulate option.Config with options from CLI. 338 option.Config.Populate(vp) 339 operatorOption.Config.Populate(vp) 340 341 // add hooks after setting up metrics in the option.Config 342 logging.DefaultLogger.Hooks.Add(metrics.NewLoggingHook()) 343 344 // Logging should always be bootstrapped first. Do not add any code above this! 345 if err := logging.SetupLogging(option.Config.LogDriver, logging.LogOptions(option.Config.LogOpt), binaryName, option.Config.Debug); err != nil { 346 log.Fatal(err) 347 } 348 349 option.LogRegisteredOptions(vp, log) 350 log.Infof("Cilium Operator %s", version.Version) 351 } 352 353 func doCleanup() { 354 isLeader.Store(false) 355 356 // Cancelling this context here makes sure that if the operator hold the 357 // leader lease, it will be released. 358 leaderElectionCtxCancel() 359 } 360 361 // runOperator implements the logic of leader election for cilium-operator using 362 // built-in leader election capability in kubernetes. 363 // See: https://github.com/kubernetes/client-go/blob/master/examples/leader-election/main.go 364 func runOperator(slog *slog.Logger, lc *LeaderLifecycle, clientset k8sClient.Clientset, shutdowner hive.Shutdowner) { 365 isLeader.Store(false) 366 367 leaderElectionCtx, leaderElectionCtxCancel = context.WithCancel(context.Background()) 368 369 if clientset.IsEnabled() { 370 capabilities := k8sversion.Capabilities() 371 if !capabilities.MinimalVersionMet { 372 log.Fatalf("Minimal kubernetes version not met: %s < %s", 373 k8sversion.Version(), k8sversion.MinimalVersionConstraint) 374 } 375 } 376 377 // We only support Operator in HA mode for Kubernetes Versions having support for 378 // LeasesResourceLock. 379 // See docs on capabilities.LeasesResourceLock for more context. 380 if !k8sversion.Capabilities().LeasesResourceLock { 381 log.Info("Support for coordination.k8s.io/v1 not present, fallback to non HA mode") 382 383 if err := lc.Start(slog, leaderElectionCtx); err != nil { 384 log.WithError(err).Fatal("Failed to start leading") 385 } 386 return 387 } 388 389 // Get hostname for identity name of the lease lock holder. 390 // We identify the leader of the operator cluster using hostname. 391 operatorID, err := os.Hostname() 392 if err != nil { 393 log.WithError(err).Fatal("Failed to get hostname when generating lease lock identity") 394 } 395 operatorID = fmt.Sprintf("%s-%s", operatorID, rand.String(10)) 396 397 ns := option.Config.K8sNamespace 398 // If due to any reason the CILIUM_K8S_NAMESPACE is not set we assume the operator 399 // to be in default namespace. 400 if ns == "" { 401 ns = metav1.NamespaceDefault 402 } 403 404 leResourceLock, err := resourcelock.NewFromKubeconfig( 405 resourcelock.LeasesResourceLock, 406 ns, 407 leaderElectionResourceLockName, 408 resourcelock.ResourceLockConfig{ 409 // Identity name of the lock holder 410 Identity: operatorID, 411 }, 412 clientset.RestConfig(), 413 operatorOption.Config.LeaderElectionRenewDeadline) 414 if err != nil { 415 log.WithError(err).Fatal("Failed to create resource lock for leader election") 416 } 417 418 // Start the leader election for running cilium-operators 419 log.Info("Waiting for leader election") 420 leaderelection.RunOrDie(leaderElectionCtx, leaderelection.LeaderElectionConfig{ 421 Name: leaderElectionResourceLockName, 422 423 Lock: leResourceLock, 424 ReleaseOnCancel: true, 425 426 LeaseDuration: operatorOption.Config.LeaderElectionLeaseDuration, 427 RenewDeadline: operatorOption.Config.LeaderElectionRenewDeadline, 428 RetryPeriod: operatorOption.Config.LeaderElectionRetryPeriod, 429 430 Callbacks: leaderelection.LeaderCallbacks{ 431 OnStartedLeading: func(ctx context.Context) { 432 if err := lc.Start(slog, ctx); err != nil { 433 log.WithError(err).Error("Failed to start when elected leader, shutting down") 434 shutdowner.Shutdown(hive.ShutdownWithError(err)) 435 } 436 }, 437 OnStoppedLeading: func() { 438 log.WithField("operator-id", operatorID).Info("Leader election lost") 439 // Cleanup everything here, and exit. 440 shutdowner.Shutdown(hive.ShutdownWithError(errors.New("Leader election lost"))) 441 }, 442 OnNewLeader: func(identity string) { 443 if identity == operatorID { 444 log.Info("Leading the operator HA deployment") 445 } else { 446 log.WithFields(logrus.Fields{ 447 "newLeader": identity, 448 "operatorID": operatorID, 449 }).Info("Leader re-election complete") 450 } 451 }, 452 }, 453 }) 454 } 455 456 func kvstoreEnabled() bool { 457 if option.Config.KVStore == "" { 458 return false 459 } 460 461 return option.Config.IdentityAllocationMode == option.IdentityAllocationModeKVstore || 462 operatorOption.Config.SyncK8sServices || 463 operatorOption.Config.SyncK8sNodes 464 } 465 466 var legacyCell = cell.Invoke(registerLegacyOnLeader) 467 468 func registerLegacyOnLeader(lc cell.Lifecycle, clientset k8sClient.Clientset, resources operatorK8s.Resources, factory store.Factory, svcResolver *dial.ServiceResolver) { 469 ctx, cancel := context.WithCancel(context.Background()) 470 legacy := &legacyOnLeader{ 471 ctx: ctx, 472 cancel: cancel, 473 clientset: clientset, 474 resources: resources, 475 storeFactory: factory, 476 svcResolver: svcResolver, 477 } 478 lc.Append(cell.Hook{ 479 OnStart: legacy.onStart, 480 OnStop: legacy.onStop, 481 }) 482 } 483 484 type legacyOnLeader struct { 485 ctx context.Context 486 cancel context.CancelFunc 487 clientset k8sClient.Clientset 488 wg sync.WaitGroup 489 resources operatorK8s.Resources 490 storeFactory store.Factory 491 svcResolver *dial.ServiceResolver 492 } 493 494 func (legacy *legacyOnLeader) onStop(_ cell.HookContext) error { 495 legacy.cancel() 496 497 // Wait for background goroutines to finish. 498 legacy.wg.Wait() 499 500 return nil 501 } 502 503 // OnOperatorStartLeading is the function called once the operator starts leading 504 // in HA mode. 505 func (legacy *legacyOnLeader) onStart(_ cell.HookContext) error { 506 isLeader.Store(true) 507 508 // Restart kube-dns as soon as possible since it helps etcd-operator to be 509 // properly setup. If kube-dns is not managed by Cilium it can prevent 510 // etcd from reaching out kube-dns in EKS. 511 // If this logic is modified, make sure the operator's clusterrole logic for 512 // pods/delete is also up-to-date. 513 if !legacy.clientset.IsEnabled() { 514 log.Infof("KubeDNS unmanaged pods controller disabled due to kubernetes support not enabled") 515 } else if option.Config.DisableCiliumEndpointCRD { 516 log.Infof("KubeDNS unmanaged pods controller disabled as %q option is set to 'disabled' in Cilium ConfigMap", option.DisableCiliumEndpointCRDName) 517 } else if operatorOption.Config.UnmanagedPodWatcherInterval != 0 { 518 legacy.wg.Add(1) 519 go func() { 520 defer legacy.wg.Done() 521 enableUnmanagedController(legacy.ctx, &legacy.wg, legacy.clientset) 522 }() 523 } 524 525 var ( 526 nodeManager allocator.NodeEventHandler 527 err error 528 withKVStore bool 529 ) 530 531 log.WithField(logfields.Mode, option.Config.IPAM).Info("Initializing IPAM") 532 533 switch ipamMode := option.Config.IPAM; ipamMode { 534 case ipamOption.IPAMAzure, 535 ipamOption.IPAMENI, 536 ipamOption.IPAMClusterPool, 537 ipamOption.IPAMMultiPool, 538 ipamOption.IPAMAlibabaCloud: 539 alloc, providerBuiltin := allocatorProviders[ipamMode] 540 if !providerBuiltin { 541 log.Fatalf("%s allocator is not supported by this version of %s", ipamMode, binaryName) 542 } 543 544 if err := alloc.Init(legacy.ctx); err != nil { 545 log.WithError(err).Fatalf("Unable to init %s allocator", ipamMode) 546 } 547 548 if pooledAlloc, ok := alloc.(operatorWatchers.PooledAllocatorProvider); ok { 549 // The following operation will block until all pools are restored, thus it 550 // is safe to continue starting node allocation right after return. 551 operatorWatchers.StartIPPoolAllocator(legacy.ctx, legacy.clientset, pooledAlloc, legacy.resources.CiliumPodIPPools) 552 } 553 554 nm, err := alloc.Start(legacy.ctx, &ciliumNodeUpdateImplementation{legacy.clientset}) 555 if err != nil { 556 log.WithError(err).Fatalf("Unable to start %s allocator", ipamMode) 557 } 558 559 nodeManager = nm 560 } 561 562 if operatorOption.Config.BGPAnnounceLBIP { 563 log.Info("Starting LB IP allocator") 564 operatorWatchers.StartBGPBetaLBIPAllocator(legacy.ctx, legacy.clientset, legacy.resources.Services) 565 } 566 567 if kvstoreEnabled() { 568 var goopts *kvstore.ExtraOptions 569 scopedLog := log.WithFields(logrus.Fields{ 570 "kvstore": option.Config.KVStore, 571 "address": option.Config.KVStoreOpt[fmt.Sprintf("%s.address", option.Config.KVStore)], 572 }) 573 574 if legacy.clientset.IsEnabled() && operatorOption.Config.SyncK8sServices { 575 clusterInfo := cmtypes.ClusterInfo{ 576 ID: option.Config.ClusterID, 577 Name: option.Config.ClusterName, 578 } 579 operatorWatchers.StartSynchronizingServices(legacy.ctx, &legacy.wg, operatorWatchers.ServiceSyncParameters{ 580 ClusterInfo: clusterInfo, 581 Clientset: legacy.clientset, 582 Services: legacy.resources.Services, 583 Endpoints: legacy.resources.Endpoints, 584 SharedOnly: true, 585 StoreFactory: legacy.storeFactory, 586 SyncCallback: func(_ context.Context) {}, 587 }) 588 } 589 590 if legacy.clientset.IsEnabled() { 591 // If K8s is enabled we can do the service translation automagically by 592 // looking at services from k8s and retrieve the service IP from that. 593 // This makes cilium to not depend on kube dns to interact with etcd 594 log := log.WithField(logfields.LogSubsys, "etcd") 595 goopts = &kvstore.ExtraOptions{ 596 DialOption: []grpc.DialOption{ 597 grpc.WithContextDialer(dial.NewContextDialer(log, legacy.svcResolver)), 598 }, 599 } 600 } 601 602 scopedLog.Info("Connecting to kvstore") 603 if err := kvstore.Setup(legacy.ctx, option.Config.KVStore, option.Config.KVStoreOpt, goopts); err != nil { 604 scopedLog.WithError(err).Fatal("Unable to setup kvstore") 605 } 606 607 if legacy.clientset.IsEnabled() && operatorOption.Config.SyncK8sNodes { 608 withKVStore = true 609 } 610 611 startKvstoreWatchdog() 612 } 613 614 if legacy.clientset.IsEnabled() && 615 (operatorOption.Config.RemoveCiliumNodeTaints || operatorOption.Config.SetCiliumIsUpCondition) { 616 log.WithFields(logrus.Fields{ 617 logfields.K8sNamespace: operatorOption.Config.CiliumK8sNamespace, 618 "label-selector": operatorOption.Config.CiliumPodLabels, 619 "remove-cilium-node-taints": operatorOption.Config.RemoveCiliumNodeTaints, 620 "set-cilium-node-taints": operatorOption.Config.SetCiliumNodeTaints, 621 "set-cilium-is-up-condition": operatorOption.Config.SetCiliumIsUpCondition, 622 }).Info("Managing Cilium Node Taints or Setting Cilium Is Up Condition for Kubernetes Nodes") 623 624 operatorWatchers.HandleNodeTolerationAndTaints(&legacy.wg, legacy.clientset, legacy.ctx.Done()) 625 } 626 627 ciliumNodeSynchronizer := newCiliumNodeSynchronizer(legacy.clientset, nodeManager, withKVStore) 628 629 if legacy.clientset.IsEnabled() { 630 if err := ciliumNodeSynchronizer.Start(legacy.ctx, &legacy.wg); err != nil { 631 log.WithError(err).Fatal("Unable to setup cilium node synchronizer") 632 } 633 634 if operatorOption.Config.NodesGCInterval != 0 { 635 operatorWatchers.RunCiliumNodeGC(legacy.ctx, &legacy.wg, legacy.clientset, ciliumNodeSynchronizer.ciliumNodeStore, operatorOption.Config.NodesGCInterval) 636 } 637 } 638 639 if option.Config.IPAM == ipamOption.IPAMClusterPool || option.Config.IPAM == ipamOption.IPAMMultiPool { 640 // We will use CiliumNodes as the source of truth for the podCIDRs. 641 // Once the CiliumNodes are synchronized with the operator we will 642 // be able to watch for K8s Node events which they will be used 643 // to create the remaining CiliumNodes. 644 <-ciliumNodeSynchronizer.ciliumNodeManagerQueueSynced 645 646 // We don't want CiliumNodes that don't have podCIDRs to be 647 // allocated with a podCIDR already being used by another node. 648 // For this reason we will call Resync after all CiliumNodes are 649 // synced with the operator to signal the node manager, since it 650 // knows all podCIDRs that are currently set in the cluster, that 651 // it can allocate podCIDRs for the nodes that don't have a podCIDR 652 // set. 653 nodeManager.Resync(legacy.ctx, time.Time{}) 654 } 655 656 if option.Config.IdentityAllocationMode == option.IdentityAllocationModeCRD { 657 if !legacy.clientset.IsEnabled() { 658 log.Fatal("CRD Identity allocation mode requires k8s to be configured.") 659 } 660 if operatorOption.Config.EndpointGCInterval == 0 { 661 log.Fatal("Cilium Identity garbage collector requires the CiliumEndpoint garbage collector to be enabled") 662 } 663 } 664 665 if legacy.clientset.IsEnabled() { 666 err = enableCNPWatcher(legacy.ctx, &legacy.wg, legacy.clientset) 667 if err != nil { 668 log.WithError(err).WithField(logfields.LogSubsys, "CNPWatcher").Fatal( 669 "Cannot connect to Kubernetes apiserver ") 670 } 671 672 err = enableCCNPWatcher(legacy.ctx, &legacy.wg, legacy.clientset) 673 if err != nil { 674 log.WithError(err).WithField(logfields.LogSubsys, "CCNPWatcher").Fatal( 675 "Cannot connect to Kubernetes apiserver ") 676 } 677 } 678 679 log.Info("Initialization complete") 680 return nil 681 }