github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/controller.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package k8s 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 "sync" 24 "time" 25 26 "github.com/nginxinc/kubernetes-ingress/internal/k8s/appprotect" 27 "k8s.io/client-go/informers" 28 29 "github.com/golang/glog" 30 "github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets" 31 "github.com/spiffe/go-spiffe/workload" 32 33 "k8s.io/apimachinery/pkg/fields" 34 "k8s.io/apimachinery/pkg/labels" 35 "k8s.io/apimachinery/pkg/util/intstr" 36 "k8s.io/client-go/kubernetes" 37 "k8s.io/client-go/kubernetes/scheme" 38 core_v1 "k8s.io/client-go/kubernetes/typed/core/v1" 39 "k8s.io/client-go/tools/cache" 40 "k8s.io/client-go/tools/leaderelection" 41 "k8s.io/client-go/tools/record" 42 43 "github.com/nginxinc/kubernetes-ingress/internal/configs" 44 "github.com/nginxinc/kubernetes-ingress/internal/metrics/collectors" 45 46 api_v1 "k8s.io/api/core/v1" 47 networking "k8s.io/api/networking/v1beta1" 48 meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 49 50 conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1" 51 conf_v1alpha1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1alpha1" 52 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/validation" 53 k8s_nginx "github.com/nginxinc/kubernetes-ingress/pkg/client/clientset/versioned" 54 k8s_nginx_informers "github.com/nginxinc/kubernetes-ingress/pkg/client/informers/externalversions" 55 56 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 57 "k8s.io/apimachinery/pkg/runtime/schema" 58 "k8s.io/client-go/dynamic" 59 "k8s.io/client-go/dynamic/dynamicinformer" 60 ) 61 62 const ( 63 ingressClassKey = "kubernetes.io/ingress.class" 64 // IngressControllerName holds Ingress Controller name 65 IngressControllerName = "nginx.org/ingress-controller" 66 ) 67 68 var ( 69 ingressLinkGVR = schema.GroupVersionResource{ 70 Group: "cis.f5.com", 71 Version: "v1", 72 Resource: "ingresslinks", 73 } 74 ingressLinkGVK = schema.GroupVersionKind{ 75 Group: "cis.f5.com", 76 Version: "v1", 77 Kind: "IngressLink", 78 } 79 ) 80 81 type podEndpoint struct { 82 Address string 83 PodName string 84 // MeshPodOwner is used for NGINX Service Mesh metrics 85 configs.MeshPodOwner 86 } 87 88 // LoadBalancerController watches Kubernetes API and 89 // reconfigures NGINX via NginxController when needed 90 type LoadBalancerController struct { 91 client kubernetes.Interface 92 confClient k8s_nginx.Interface 93 dynClient dynamic.Interface 94 cacheSyncs []cache.InformerSynced 95 sharedInformerFactory informers.SharedInformerFactory 96 confSharedInformerFactorry k8s_nginx_informers.SharedInformerFactory 97 configMapController cache.Controller 98 dynInformerFactory dynamicinformer.DynamicSharedInformerFactory 99 globalConfigurationController cache.Controller 100 ingressLinkInformer cache.SharedIndexInformer 101 ingressLister storeToIngressLister 102 svcLister cache.Store 103 endpointLister storeToEndpointLister 104 configMapLister storeToConfigMapLister 105 podLister indexerToPodLister 106 secretLister cache.Store 107 virtualServerLister cache.Store 108 virtualServerRouteLister cache.Store 109 appProtectPolicyLister cache.Store 110 appProtectLogConfLister cache.Store 111 globalConfigurationLister cache.Store 112 appProtectUserSigLister cache.Store 113 transportServerLister cache.Store 114 policyLister cache.Store 115 ingressLinkLister cache.Store 116 syncQueue *taskQueue 117 ctx context.Context 118 cancel context.CancelFunc 119 configurator *configs.Configurator 120 watchNginxConfigMaps bool 121 watchGlobalConfiguration bool 122 watchIngressLink bool 123 isNginxPlus bool 124 appProtectEnabled bool 125 recorder record.EventRecorder 126 defaultServerSecret string 127 ingressClass string 128 useIngressClassOnly bool 129 statusUpdater *statusUpdater 130 leaderElector *leaderelection.LeaderElector 131 reportIngressStatus bool 132 isLeaderElectionEnabled bool 133 leaderElectionLockName string 134 resync time.Duration 135 namespace string 136 controllerNamespace string 137 wildcardTLSSecret string 138 areCustomResourcesEnabled bool 139 enablePreviewPolicies bool 140 metricsCollector collectors.ControllerCollector 141 globalConfigurationValidator *validation.GlobalConfigurationValidator 142 transportServerValidator *validation.TransportServerValidator 143 spiffeController *spiffeController 144 internalRoutesEnabled bool 145 syncLock sync.Mutex 146 isNginxReady bool 147 isPrometheusEnabled bool 148 isLatencyMetricsEnabled bool 149 configuration *Configuration 150 secretStore secrets.SecretStore 151 appProtectConfiguration appprotect.Configuration 152 } 153 154 var keyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc 155 156 // NewLoadBalancerControllerInput holds the input needed to call NewLoadBalancerController. 157 type NewLoadBalancerControllerInput struct { 158 KubeClient kubernetes.Interface 159 ConfClient k8s_nginx.Interface 160 DynClient dynamic.Interface 161 ResyncPeriod time.Duration 162 Namespace string 163 NginxConfigurator *configs.Configurator 164 DefaultServerSecret string 165 AppProtectEnabled bool 166 IsNginxPlus bool 167 IngressClass string 168 UseIngressClassOnly bool 169 ExternalServiceName string 170 IngressLink string 171 ControllerNamespace string 172 ReportIngressStatus bool 173 IsLeaderElectionEnabled bool 174 LeaderElectionLockName string 175 WildcardTLSSecret string 176 ConfigMaps string 177 GlobalConfiguration string 178 AreCustomResourcesEnabled bool 179 EnablePreviewPolicies bool 180 MetricsCollector collectors.ControllerCollector 181 GlobalConfigurationValidator *validation.GlobalConfigurationValidator 182 TransportServerValidator *validation.TransportServerValidator 183 VirtualServerValidator *validation.VirtualServerValidator 184 SpireAgentAddress string 185 InternalRoutesEnabled bool 186 IsPrometheusEnabled bool 187 IsLatencyMetricsEnabled bool 188 IsTLSPassthroughEnabled bool 189 SnippetsEnabled bool 190 } 191 192 // NewLoadBalancerController creates a controller 193 func NewLoadBalancerController(input NewLoadBalancerControllerInput) *LoadBalancerController { 194 lbc := &LoadBalancerController{ 195 client: input.KubeClient, 196 confClient: input.ConfClient, 197 dynClient: input.DynClient, 198 configurator: input.NginxConfigurator, 199 defaultServerSecret: input.DefaultServerSecret, 200 appProtectEnabled: input.AppProtectEnabled, 201 isNginxPlus: input.IsNginxPlus, 202 ingressClass: input.IngressClass, 203 useIngressClassOnly: input.UseIngressClassOnly, 204 reportIngressStatus: input.ReportIngressStatus, 205 isLeaderElectionEnabled: input.IsLeaderElectionEnabled, 206 leaderElectionLockName: input.LeaderElectionLockName, 207 resync: input.ResyncPeriod, 208 namespace: input.Namespace, 209 controllerNamespace: input.ControllerNamespace, 210 wildcardTLSSecret: input.WildcardTLSSecret, 211 areCustomResourcesEnabled: input.AreCustomResourcesEnabled, 212 enablePreviewPolicies: input.EnablePreviewPolicies, 213 metricsCollector: input.MetricsCollector, 214 globalConfigurationValidator: input.GlobalConfigurationValidator, 215 transportServerValidator: input.TransportServerValidator, 216 internalRoutesEnabled: input.InternalRoutesEnabled, 217 isPrometheusEnabled: input.IsPrometheusEnabled, 218 isLatencyMetricsEnabled: input.IsLatencyMetricsEnabled, 219 } 220 221 eventBroadcaster := record.NewBroadcaster() 222 eventBroadcaster.StartLogging(glog.Infof) 223 eventBroadcaster.StartRecordingToSink(&core_v1.EventSinkImpl{ 224 Interface: core_v1.New(input.KubeClient.CoreV1().RESTClient()).Events(""), 225 }) 226 lbc.recorder = eventBroadcaster.NewRecorder(scheme.Scheme, 227 api_v1.EventSource{Component: "nginx-ingress-controller"}) 228 229 lbc.syncQueue = newTaskQueue(lbc.sync) 230 if input.SpireAgentAddress != "" { 231 var err error 232 lbc.spiffeController, err = NewSpiffeController(lbc.syncSVIDRotation, input.SpireAgentAddress) 233 if err != nil { 234 glog.Fatalf("failed to create Spiffe Controller: %v", err) 235 } 236 } 237 238 glog.V(3).Infof("Nginx Ingress Controller has class: %v", input.IngressClass) 239 240 lbc.sharedInformerFactory = informers.NewSharedInformerFactoryWithOptions(lbc.client, input.ResyncPeriod, informers.WithNamespace(lbc.namespace)) 241 242 // create handlers for resources we care about 243 lbc.addSecretHandler(createSecretHandlers(lbc)) 244 lbc.addIngressHandler(createIngressHandlers(lbc)) 245 lbc.addServiceHandler(createServiceHandlers(lbc)) 246 lbc.addEndpointHandler(createEndpointHandlers(lbc)) 247 lbc.addPodHandler() 248 249 if lbc.appProtectEnabled { 250 lbc.dynInformerFactory = dynamicinformer.NewDynamicSharedInformerFactory(lbc.dynClient, 0) 251 252 lbc.addAppProtectPolicyHandler(createAppProtectPolicyHandlers(lbc)) 253 lbc.addAppProtectLogConfHandler(createAppProtectLogConfHandlers(lbc)) 254 lbc.addAppProtectUserSigHandler(createAppProtectUserSigHandlers(lbc)) 255 } 256 257 if lbc.areCustomResourcesEnabled { 258 lbc.confSharedInformerFactorry = k8s_nginx_informers.NewSharedInformerFactoryWithOptions(lbc.confClient, input.ResyncPeriod, k8s_nginx_informers.WithNamespace(lbc.namespace)) 259 260 lbc.addVirtualServerHandler(createVirtualServerHandlers(lbc)) 261 lbc.addVirtualServerRouteHandler(createVirtualServerRouteHandlers(lbc)) 262 lbc.addTransportServerHandler(createTransportServerHandlers(lbc)) 263 lbc.addPolicyHandler(createPolicyHandlers(lbc)) 264 265 if input.GlobalConfiguration != "" { 266 lbc.watchGlobalConfiguration = true 267 ns, name, _ := ParseNamespaceName(input.GlobalConfiguration) 268 lbc.addGlobalConfigurationHandler(createGlobalConfigurationHandlers(lbc), ns, name) 269 } 270 } 271 272 if input.ConfigMaps != "" { 273 nginxConfigMapsNS, nginxConfigMapsName, err := ParseNamespaceName(input.ConfigMaps) 274 if err != nil { 275 glog.Warning(err) 276 } else { 277 lbc.watchNginxConfigMaps = true 278 lbc.addConfigMapHandler(createConfigMapHandlers(lbc, nginxConfigMapsName), nginxConfigMapsNS) 279 } 280 } 281 282 if input.IngressLink != "" { 283 lbc.watchIngressLink = true 284 lbc.addIngressLinkHandler(createIngressLinkHandlers(lbc), input.IngressLink) 285 } 286 287 if input.IsLeaderElectionEnabled { 288 lbc.addLeaderHandler(createLeaderHandler(lbc)) 289 } 290 291 lbc.statusUpdater = &statusUpdater{ 292 client: input.KubeClient, 293 namespace: input.ControllerNamespace, 294 externalServiceName: input.ExternalServiceName, 295 ingressLister: &lbc.ingressLister, 296 virtualServerLister: lbc.virtualServerLister, 297 virtualServerRouteLister: lbc.virtualServerRouteLister, 298 transportServerLister: lbc.transportServerLister, 299 policyLister: lbc.policyLister, 300 keyFunc: keyFunc, 301 confClient: input.ConfClient, 302 } 303 304 lbc.configuration = NewConfiguration( 305 lbc.HasCorrectIngressClass, 306 input.IsNginxPlus, 307 input.AppProtectEnabled, 308 input.InternalRoutesEnabled, 309 input.VirtualServerValidator, 310 input.GlobalConfigurationValidator, 311 input.TransportServerValidator, 312 input.IsTLSPassthroughEnabled, 313 input.SnippetsEnabled) 314 315 lbc.appProtectConfiguration = appprotect.NewConfiguration() 316 317 lbc.secretStore = secrets.NewLocalSecretStore(lbc.configurator) 318 319 lbc.updateIngressMetrics() 320 return lbc 321 } 322 323 // addLeaderHandler adds the handler for leader election to the controller 324 func (lbc *LoadBalancerController) addLeaderHandler(leaderHandler leaderelection.LeaderCallbacks) { 325 var err error 326 lbc.leaderElector, err = newLeaderElector(lbc.client, leaderHandler, lbc.controllerNamespace, lbc.leaderElectionLockName) 327 if err != nil { 328 glog.V(3).Infof("Error starting LeaderElection: %v", err) 329 } 330 } 331 332 // AddSyncQueue enqueues the provided item on the sync queue 333 func (lbc *LoadBalancerController) AddSyncQueue(item interface{}) { 334 lbc.syncQueue.Enqueue(item) 335 } 336 337 // addappProtectPolicyHandler creates dynamic informers for custom appprotect policy resource 338 func (lbc *LoadBalancerController) addAppProtectPolicyHandler(handlers cache.ResourceEventHandlerFuncs) { 339 informer := lbc.dynInformerFactory.ForResource(appprotect.PolicyGVR).Informer() 340 informer.AddEventHandler(handlers) 341 lbc.appProtectPolicyLister = informer.GetStore() 342 343 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 344 } 345 346 // addappProtectLogConfHandler creates dynamic informer for custom appprotect logging config resource 347 func (lbc *LoadBalancerController) addAppProtectLogConfHandler(handlers cache.ResourceEventHandlerFuncs) { 348 informer := lbc.dynInformerFactory.ForResource(appprotect.LogConfGVR).Informer() 349 informer.AddEventHandler(handlers) 350 lbc.appProtectLogConfLister = informer.GetStore() 351 352 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 353 } 354 355 // addappProtectUserSigHandler creates dynamic informer for custom appprotect user defined signature resource 356 func (lbc *LoadBalancerController) addAppProtectUserSigHandler(handlers cache.ResourceEventHandlerFuncs) { 357 informer := lbc.dynInformerFactory.ForResource(appprotect.UserSigGVR).Informer() 358 informer.AddEventHandler(handlers) 359 lbc.appProtectUserSigLister = informer.GetStore() 360 361 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 362 } 363 364 // addSecretHandler adds the handler for secrets to the controller 365 func (lbc *LoadBalancerController) addSecretHandler(handlers cache.ResourceEventHandlerFuncs) { 366 informer := lbc.sharedInformerFactory.Core().V1().Secrets().Informer() 367 informer.AddEventHandler(handlers) 368 lbc.secretLister = informer.GetStore() 369 370 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 371 } 372 373 // addServiceHandler adds the handler for services to the controller 374 func (lbc *LoadBalancerController) addServiceHandler(handlers cache.ResourceEventHandlerFuncs) { 375 informer := lbc.sharedInformerFactory.Core().V1().Services().Informer() 376 informer.AddEventHandler(handlers) 377 lbc.svcLister = informer.GetStore() 378 379 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 380 } 381 382 // addIngressHandler adds the handler for ingresses to the controller 383 func (lbc *LoadBalancerController) addIngressHandler(handlers cache.ResourceEventHandlerFuncs) { 384 informer := lbc.sharedInformerFactory.Networking().V1beta1().Ingresses().Informer() 385 informer.AddEventHandler(handlers) 386 lbc.ingressLister.Store = informer.GetStore() 387 388 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 389 } 390 391 // addEndpointHandler adds the handler for endpoints to the controller 392 func (lbc *LoadBalancerController) addEndpointHandler(handlers cache.ResourceEventHandlerFuncs) { 393 informer := lbc.sharedInformerFactory.Core().V1().Endpoints().Informer() 394 informer.AddEventHandler(handlers) 395 lbc.endpointLister.Store = informer.GetStore() 396 397 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 398 } 399 400 // addConfigMapHandler adds the handler for config maps to the controller 401 func (lbc *LoadBalancerController) addConfigMapHandler(handlers cache.ResourceEventHandlerFuncs, namespace string) { 402 lbc.configMapLister.Store, lbc.configMapController = cache.NewInformer( 403 cache.NewListWatchFromClient( 404 lbc.client.CoreV1().RESTClient(), 405 "configmaps", 406 namespace, 407 fields.Everything()), 408 &api_v1.ConfigMap{}, 409 lbc.resync, 410 handlers, 411 ) 412 lbc.cacheSyncs = append(lbc.cacheSyncs, lbc.configMapController.HasSynced) 413 } 414 415 func (lbc *LoadBalancerController) addPodHandler() { 416 informer := lbc.sharedInformerFactory.Core().V1().Pods().Informer() 417 lbc.podLister.Indexer = informer.GetIndexer() 418 419 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 420 } 421 422 func (lbc *LoadBalancerController) addVirtualServerHandler(handlers cache.ResourceEventHandlerFuncs) { 423 informer := lbc.confSharedInformerFactorry.K8s().V1().VirtualServers().Informer() 424 informer.AddEventHandler(handlers) 425 lbc.virtualServerLister = informer.GetStore() 426 427 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 428 } 429 430 func (lbc *LoadBalancerController) addVirtualServerRouteHandler(handlers cache.ResourceEventHandlerFuncs) { 431 informer := lbc.confSharedInformerFactorry.K8s().V1().VirtualServerRoutes().Informer() 432 informer.AddEventHandler(handlers) 433 lbc.virtualServerRouteLister = informer.GetStore() 434 435 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 436 } 437 438 func (lbc *LoadBalancerController) addPolicyHandler(handlers cache.ResourceEventHandlerFuncs) { 439 informer := lbc.confSharedInformerFactorry.K8s().V1().Policies().Informer() 440 informer.AddEventHandler(handlers) 441 lbc.policyLister = informer.GetStore() 442 443 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 444 } 445 446 func (lbc *LoadBalancerController) addGlobalConfigurationHandler(handlers cache.ResourceEventHandlerFuncs, namespace string, name string) { 447 lbc.globalConfigurationLister, lbc.globalConfigurationController = cache.NewInformer( 448 cache.NewListWatchFromClient( 449 lbc.confClient.K8sV1alpha1().RESTClient(), 450 "globalconfigurations", 451 namespace, 452 fields.Set{"metadata.name": name}.AsSelector()), 453 &conf_v1alpha1.GlobalConfiguration{}, 454 lbc.resync, 455 handlers, 456 ) 457 lbc.cacheSyncs = append(lbc.cacheSyncs, lbc.globalConfigurationController.HasSynced) 458 } 459 460 func (lbc *LoadBalancerController) addTransportServerHandler(handlers cache.ResourceEventHandlerFuncs) { 461 informer := lbc.confSharedInformerFactorry.K8s().V1alpha1().TransportServers().Informer() 462 informer.AddEventHandler(handlers) 463 lbc.transportServerLister = informer.GetStore() 464 465 lbc.cacheSyncs = append(lbc.cacheSyncs, informer.HasSynced) 466 } 467 468 func (lbc *LoadBalancerController) addIngressLinkHandler(handlers cache.ResourceEventHandlerFuncs, name string) { 469 optionsModifier := func(options *meta_v1.ListOptions) { 470 options.FieldSelector = fields.Set{"metadata.name": name}.String() 471 } 472 473 informer := dynamicinformer.NewFilteredDynamicInformer(lbc.dynClient, ingressLinkGVR, lbc.controllerNamespace, lbc.resync, 474 cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, optionsModifier) 475 476 informer.Informer().AddEventHandlerWithResyncPeriod(handlers, lbc.resync) 477 478 lbc.ingressLinkInformer = informer.Informer() 479 lbc.ingressLinkLister = informer.Informer().GetStore() 480 481 lbc.cacheSyncs = append(lbc.cacheSyncs, lbc.ingressLinkInformer.HasSynced) 482 } 483 484 // Run starts the loadbalancer controller 485 func (lbc *LoadBalancerController) Run() { 486 lbc.ctx, lbc.cancel = context.WithCancel(context.Background()) 487 488 if lbc.spiffeController != nil { 489 err := lbc.spiffeController.Start(lbc.ctx.Done(), lbc.addInternalRouteServer) 490 if err != nil { 491 glog.Fatal(err) 492 } 493 } 494 if lbc.leaderElector != nil { 495 go lbc.leaderElector.Run(lbc.ctx) 496 } 497 498 go lbc.sharedInformerFactory.Start(lbc.ctx.Done()) 499 if lbc.watchNginxConfigMaps { 500 go lbc.configMapController.Run(lbc.ctx.Done()) 501 } 502 if lbc.areCustomResourcesEnabled { 503 go lbc.confSharedInformerFactorry.Start(lbc.ctx.Done()) 504 } 505 if lbc.watchGlobalConfiguration { 506 go lbc.globalConfigurationController.Run(lbc.ctx.Done()) 507 } 508 if lbc.watchIngressLink { 509 go lbc.ingressLinkInformer.Run(lbc.ctx.Done()) 510 } 511 if lbc.appProtectEnabled { 512 go lbc.dynInformerFactory.Start(lbc.ctx.Done()) 513 } 514 515 glog.V(3).Infof("Waiting for %d caches to sync", len(lbc.cacheSyncs)) 516 517 if !cache.WaitForCacheSync(lbc.ctx.Done(), lbc.cacheSyncs...) { 518 return 519 } 520 521 lbc.preSyncSecrets() 522 523 glog.V(3).Infof("Starting the queue with %d initial elements", lbc.syncQueue.Len()) 524 525 go lbc.syncQueue.Run(time.Second, lbc.ctx.Done()) 526 <-lbc.ctx.Done() 527 } 528 529 // Stop shutdowns the load balancer controller 530 func (lbc *LoadBalancerController) Stop() { 531 lbc.cancel() 532 533 lbc.syncQueue.Shutdown() 534 } 535 536 func (lbc *LoadBalancerController) syncEndpoints(task task) { 537 key := task.Key 538 glog.V(3).Infof("Syncing endpoints %v", key) 539 540 obj, endpExists, err := lbc.endpointLister.GetByKey(key) 541 if err != nil { 542 lbc.syncQueue.Requeue(task, err) 543 return 544 } 545 546 if !endpExists { 547 return 548 } 549 550 endp := obj.(*api_v1.Endpoints) 551 resources := lbc.configuration.FindResourcesForEndpoints(endp.Namespace, endp.Name) 552 553 resourceExes := lbc.createExtendedResources(resources) 554 555 if len(resourceExes.IngressExes) > 0 { 556 glog.V(3).Infof("Updating Endpoints for %v", resourceExes.IngressExes) 557 err = lbc.configurator.UpdateEndpoints(resourceExes.IngressExes) 558 if err != nil { 559 glog.Errorf("Error updating endpoints for %v: %v", resourceExes.IngressExes, err) 560 } 561 } 562 563 if len(resourceExes.MergeableIngresses) > 0 { 564 glog.V(3).Infof("Updating Endpoints for %v", resourceExes.MergeableIngresses) 565 err = lbc.configurator.UpdateEndpointsMergeableIngress(resourceExes.MergeableIngresses) 566 if err != nil { 567 glog.Errorf("Error updating endpoints for %v: %v", resourceExes.MergeableIngresses, err) 568 } 569 } 570 571 if lbc.areCustomResourcesEnabled { 572 if len(resourceExes.VirtualServerExes) > 0 { 573 glog.V(3).Infof("Updating endpoints for %v", resourceExes.VirtualServerExes) 574 err := lbc.configurator.UpdateEndpointsForVirtualServers(resourceExes.VirtualServerExes) 575 if err != nil { 576 glog.Errorf("Error updating endpoints for %v: %v", resourceExes.VirtualServerExes, err) 577 } 578 } 579 580 if len(resourceExes.TransportServerExes) > 0 { 581 glog.V(3).Infof("Updating endpoints for %v", resourceExes.TransportServerExes) 582 err := lbc.configurator.UpdateEndpointsForTransportServers(resourceExes.TransportServerExes) 583 if err != nil { 584 glog.Errorf("Error updating endpoints for %v: %v", resourceExes.TransportServerExes, err) 585 } 586 } 587 } 588 } 589 590 func (lbc *LoadBalancerController) createExtendedResources(resources []Resource) configs.ExtendedResources { 591 var result configs.ExtendedResources 592 593 for _, r := range resources { 594 switch impl := r.(type) { 595 case *VirtualServerConfiguration: 596 vs := impl.VirtualServer 597 vsEx := lbc.createVirtualServerEx(vs, impl.VirtualServerRoutes) 598 result.VirtualServerExes = append(result.VirtualServerExes, vsEx) 599 case *IngressConfiguration: 600 if impl.IsMaster { 601 mergeableIng := lbc.createMergeableIngresses(impl) 602 result.MergeableIngresses = append(result.MergeableIngresses, mergeableIng) 603 } else { 604 ingEx := lbc.createIngressEx(impl.Ingress, impl.ValidHosts, nil) 605 result.IngressExes = append(result.IngressExes, ingEx) 606 } 607 case *TransportServerConfiguration: 608 tsEx := lbc.createTransportServerEx(impl.TransportServer, impl.ListenerPort) 609 result.TransportServerExes = append(result.TransportServerExes, tsEx) 610 } 611 } 612 613 return result 614 } 615 616 func (lbc *LoadBalancerController) syncConfigMap(task task) { 617 key := task.Key 618 glog.V(3).Infof("Syncing configmap %v", key) 619 620 obj, configExists, err := lbc.configMapLister.GetByKey(key) 621 if err != nil { 622 lbc.syncQueue.Requeue(task, err) 623 return 624 } 625 cfgParams := configs.NewDefaultConfigParams() 626 627 if configExists { 628 cfgm := obj.(*api_v1.ConfigMap) 629 cfgParams = configs.ParseConfigMap(cfgm, lbc.isNginxPlus, lbc.appProtectEnabled) 630 631 lbc.statusUpdater.SaveStatusFromExternalStatus(cfgm.Data["external-status-address"]) 632 } 633 634 resources := lbc.configuration.GetResources() 635 636 glog.V(3).Infof("Updating %v resources", len(resources)) 637 638 resourceExes := lbc.createExtendedResources(resources) 639 640 warnings, updateErr := lbc.configurator.UpdateConfig(cfgParams, resourceExes.IngressExes, resourceExes.MergeableIngresses, resourceExes.VirtualServerExes) 641 642 eventTitle := "Updated" 643 eventType := api_v1.EventTypeNormal 644 eventWarningMessage := "" 645 646 if updateErr != nil { 647 eventTitle = "UpdatedWithError" 648 eventType = api_v1.EventTypeWarning 649 eventWarningMessage = fmt.Sprintf("but was not applied: %v", updateErr) 650 } 651 652 if len(warnings) > 0 && updateErr == nil { 653 eventWarningMessage = "with warnings. Please check the logs" 654 } 655 656 if configExists { 657 cfgm := obj.(*api_v1.ConfigMap) 658 lbc.recorder.Eventf(cfgm, eventType, eventTitle, "Configuration from %v was updated %s", key, eventWarningMessage) 659 } 660 661 lbc.updateResourcesStatusAndEvents(resources, warnings, updateErr) 662 } 663 664 // preSyncSecrets adds Secret resources to the SecretStore. 665 // It must be called after the caches are synced but before the queue starts processing elements. 666 // If we don't add Secrets, there is a chance that during the IC start 667 // syncing an Ingress or other resource that references a Secret will happen before that Secret was synced. 668 // As a result, the IC will generate configuration for that resource assuming that the Secret is missing and 669 // it will report warnings. (See https://github.com/nginxinc/kubernetes-ingress/issues/1448 ) 670 func (lbc *LoadBalancerController) preSyncSecrets() { 671 objects := lbc.secretLister.List() 672 glog.V(3).Infof("PreSync %d Secrets", len(objects)) 673 674 for _, obj := range objects { 675 secret := obj.(*api_v1.Secret) 676 677 if !secrets.IsSupportedSecretType(secret.Type) { 678 glog.V(3).Infof("Ignoring Secret %s/%s of unsupported type %s", secret.Namespace, secret.Name, secret.Type) 679 continue 680 } 681 682 glog.V(3).Infof("Adding Secret: %s/%s", secret.Namespace, secret.Name) 683 lbc.secretStore.AddOrUpdateSecret(secret) 684 } 685 } 686 687 func (lbc *LoadBalancerController) sync(task task) { 688 glog.V(3).Infof("Syncing %v", task.Key) 689 if lbc.spiffeController != nil { 690 lbc.syncLock.Lock() 691 defer lbc.syncLock.Unlock() 692 } 693 switch task.Kind { 694 case ingress: 695 lbc.syncIngress(task) 696 lbc.updateIngressMetrics() 697 case configMap: 698 lbc.syncConfigMap(task) 699 case endpoints: 700 lbc.syncEndpoints(task) 701 case secret: 702 lbc.syncSecret(task) 703 case service: 704 lbc.syncService(task) 705 case virtualserver: 706 lbc.syncVirtualServer(task) 707 lbc.updateVirtualServerMetrics() 708 case virtualServerRoute: 709 lbc.syncVirtualServerRoute(task) 710 lbc.updateVirtualServerMetrics() 711 case globalConfiguration: 712 lbc.syncGlobalConfiguration(task) 713 case transportserver: 714 lbc.syncTransportServer(task) 715 case policy: 716 lbc.syncPolicy(task) 717 case appProtectPolicy: 718 lbc.syncAppProtectPolicy(task) 719 case appProtectLogConf: 720 lbc.syncAppProtectLogConf(task) 721 case appProtectUserSig: 722 lbc.syncAppProtectUserSig(task) 723 case ingressLink: 724 lbc.syncIngressLink(task) 725 } 726 727 if !lbc.isNginxReady && lbc.syncQueue.Len() == 0 { 728 lbc.isNginxReady = true 729 glog.V(3).Infof("NGINX is ready") 730 } 731 } 732 733 func (lbc *LoadBalancerController) syncIngressLink(task task) { 734 key := task.Key 735 glog.V(2).Infof("Adding, Updating or Deleting IngressLink: %v", key) 736 737 obj, exists, err := lbc.ingressLinkLister.GetByKey(key) 738 if err != nil { 739 lbc.syncQueue.Requeue(task, err) 740 return 741 } 742 743 if !exists { 744 // IngressLink got removed 745 lbc.statusUpdater.ClearStatusFromIngressLink() 746 } else { 747 // IngressLink is added or updated 748 link := obj.(*unstructured.Unstructured) 749 750 // spec.virtualServerAddress contains the IP of the BIG-IP device 751 ip, found, err := unstructured.NestedString(link.Object, "spec", "virtualServerAddress") 752 if err != nil { 753 glog.Errorf("Failed to get virtualServerAddress from IngressLink %s: %v", key, err) 754 lbc.statusUpdater.ClearStatusFromIngressLink() 755 } else if !found { 756 glog.Errorf("virtualServerAddress is not found in IngressLink %s", key) 757 lbc.statusUpdater.ClearStatusFromIngressLink() 758 } else if ip == "" { 759 glog.Warningf("IngressLink %s has the empty virtualServerAddress field", key) 760 lbc.statusUpdater.ClearStatusFromIngressLink() 761 } else { 762 lbc.statusUpdater.SaveStatusFromIngressLink(ip) 763 } 764 } 765 766 if lbc.reportStatusEnabled() { 767 ingresses := lbc.configuration.GetResourcesWithFilter(resourceFilter{Ingresses: true}) 768 769 glog.V(3).Infof("Updating status for %v Ingresses", len(ingresses)) 770 771 err := lbc.statusUpdater.UpdateExternalEndpointsForResources(ingresses) 772 if err != nil { 773 glog.Errorf("Error updating ingress status in syncIngressLink: %v", err) 774 } 775 } 776 777 if lbc.areCustomResourcesEnabled && lbc.reportCustomResourceStatusEnabled() { 778 virtualServers := lbc.configuration.GetResourcesWithFilter(resourceFilter{VirtualServers: true}) 779 780 glog.V(3).Infof("Updating status for %v VirtualServers", len(virtualServers)) 781 782 err := lbc.statusUpdater.UpdateExternalEndpointsForResources(virtualServers) 783 if err != nil { 784 glog.V(3).Infof("Error updating VirtualServer/VirtualServerRoute status in syncIngressLink: %v", err) 785 } 786 } 787 } 788 789 func (lbc *LoadBalancerController) syncPolicy(task task) { 790 key := task.Key 791 obj, polExists, err := lbc.policyLister.GetByKey(key) 792 if err != nil { 793 lbc.syncQueue.Requeue(task, err) 794 return 795 } 796 797 glog.V(2).Infof("Adding, Updating or Deleting Policy: %v\n", key) 798 799 if polExists { 800 pol := obj.(*conf_v1.Policy) 801 err := validation.ValidatePolicy(pol, lbc.isNginxPlus, lbc.enablePreviewPolicies, lbc.appProtectEnabled) 802 if err != nil { 803 msg := fmt.Sprintf("Policy %v/%v is invalid and was rejected: %v", pol.Namespace, pol.Name, err) 804 lbc.recorder.Eventf(pol, api_v1.EventTypeWarning, "Rejected", msg) 805 806 if lbc.reportCustomResourceStatusEnabled() { 807 err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateInvalid, "Rejected", msg) 808 if err != nil { 809 glog.V(3).Infof("Failed to update policy %s status: %v", key, err) 810 } 811 } 812 } else { 813 msg := fmt.Sprintf("Policy %v/%v was added or updated", pol.Namespace, pol.Name) 814 lbc.recorder.Eventf(pol, api_v1.EventTypeNormal, "AddedOrUpdated", msg) 815 816 if lbc.reportCustomResourceStatusEnabled() { 817 err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateValid, "AddedOrUpdated", msg) 818 if err != nil { 819 glog.V(3).Infof("Failed to update policy %s status: %v", key, err) 820 } 821 } 822 } 823 } 824 825 // it is safe to ignore the error 826 namespace, name, _ := ParseNamespaceName(key) 827 828 resources := lbc.configuration.FindResourcesForPolicy(namespace, name) 829 resourceExes := lbc.createExtendedResources(resources) 830 831 // Only VirtualServers support policies 832 if len(resourceExes.VirtualServerExes) == 0 { 833 return 834 } 835 836 warnings, updateErr := lbc.configurator.AddOrUpdateVirtualServers(resourceExes.VirtualServerExes) 837 lbc.updateResourcesStatusAndEvents(resources, warnings, updateErr) 838 839 // Note: updating the status of a policy based on a reload is not needed. 840 } 841 842 func (lbc *LoadBalancerController) syncTransportServer(task task) { 843 key := task.Key 844 obj, tsExists, err := lbc.transportServerLister.GetByKey(key) 845 if err != nil { 846 lbc.syncQueue.Requeue(task, err) 847 return 848 } 849 850 var changes []ResourceChange 851 var problems []ConfigurationProblem 852 853 if !tsExists { 854 glog.V(2).Infof("Deleting TransportServer: %v\n", key) 855 changes, problems = lbc.configuration.DeleteTransportServer(key) 856 } else { 857 glog.V(2).Infof("Adding or Updating TransportServer: %v\n", key) 858 ts := obj.(*conf_v1alpha1.TransportServer) 859 changes, problems = lbc.configuration.AddOrUpdateTransportServer(ts) 860 } 861 862 lbc.processChanges(changes) 863 lbc.processProblems(problems) 864 } 865 866 func (lbc *LoadBalancerController) syncGlobalConfiguration(task task) { 867 key := task.Key 868 obj, gcExists, err := lbc.globalConfigurationLister.GetByKey(key) 869 if err != nil { 870 lbc.syncQueue.Requeue(task, err) 871 return 872 } 873 874 var changes []ResourceChange 875 var problems []ConfigurationProblem 876 var validationErr error 877 878 if !gcExists { 879 glog.V(2).Infof("Deleting GlobalConfiguration: %v\n", key) 880 881 changes, problems = lbc.configuration.DeleteGlobalConfiguration() 882 } else { 883 glog.V(2).Infof("Adding or Updating GlobalConfiguration: %v\n", key) 884 885 gc := obj.(*conf_v1alpha1.GlobalConfiguration) 886 changes, problems, validationErr = lbc.configuration.AddOrUpdateGlobalConfiguration(gc) 887 } 888 889 updateErr := lbc.processChangesFromGlobalConfiguration(changes) 890 891 if gcExists { 892 eventTitle := "Updated" 893 eventType := api_v1.EventTypeNormal 894 eventMessage := fmt.Sprintf("GlobalConfiguration %s was added or updated", key) 895 896 if validationErr != nil { 897 eventTitle = "Rejected" 898 eventType = api_v1.EventTypeWarning 899 eventMessage = fmt.Sprintf("GlobalConfiguration %s is invalid and was rejected: %v", key, validationErr) 900 } 901 902 if updateErr != nil { 903 eventTitle += "WithError" 904 eventType = api_v1.EventTypeWarning 905 eventMessage = fmt.Sprintf("%s; with reload error: %v", eventMessage, updateErr) 906 } 907 908 gc := obj.(*conf_v1alpha1.GlobalConfiguration) 909 lbc.recorder.Eventf(gc, eventType, eventTitle, eventMessage) 910 } 911 912 lbc.processProblems(problems) 913 } 914 915 func (lbc *LoadBalancerController) syncVirtualServer(task task) { 916 key := task.Key 917 obj, vsExists, err := lbc.virtualServerLister.GetByKey(key) 918 if err != nil { 919 lbc.syncQueue.Requeue(task, err) 920 return 921 } 922 923 var changes []ResourceChange 924 var problems []ConfigurationProblem 925 926 if !vsExists { 927 glog.V(2).Infof("Deleting VirtualServer: %v\n", key) 928 929 changes, problems = lbc.configuration.DeleteVirtualServer(key) 930 } else { 931 glog.V(2).Infof("Adding or Updating VirtualServer: %v\n", key) 932 933 vs := obj.(*conf_v1.VirtualServer) 934 changes, problems = lbc.configuration.AddOrUpdateVirtualServer(vs) 935 } 936 937 lbc.processChanges(changes) 938 lbc.processProblems(problems) 939 } 940 941 func (lbc *LoadBalancerController) processProblems(problems []ConfigurationProblem) { 942 glog.V(3).Infof("Processing %v problems", len(problems)) 943 944 for _, p := range problems { 945 eventType := api_v1.EventTypeWarning 946 lbc.recorder.Event(p.Object, eventType, p.Reason, p.Message) 947 948 if lbc.reportCustomResourceStatusEnabled() { 949 state := conf_v1.StateWarning 950 if p.IsError { 951 state = conf_v1.StateInvalid 952 } 953 954 switch obj := p.Object.(type) { 955 case *networking.Ingress: 956 err := lbc.statusUpdater.ClearIngressStatus(*obj) 957 if err != nil { 958 glog.V(3).Infof("Error when updating the status for Ingress %v/%v: %v", obj.Namespace, obj.Name, err) 959 } 960 case *conf_v1.VirtualServer: 961 err := lbc.statusUpdater.UpdateVirtualServerStatus(obj, state, p.Reason, p.Message) 962 if err != nil { 963 glog.Errorf("Error when updating the status for VirtualServer %v/%v: %v", obj.Namespace, obj.Name, err) 964 } 965 case *conf_v1alpha1.TransportServer: 966 err := lbc.statusUpdater.UpdateTransportServerStatus(obj, state, p.Reason, p.Message) 967 if err != nil { 968 glog.Errorf("Error when updating the status for TransportServer %v/%v: %v", obj.Namespace, obj.Name, err) 969 } 970 case *conf_v1.VirtualServerRoute: 971 var emptyVSes []*conf_v1.VirtualServer 972 err := lbc.statusUpdater.UpdateVirtualServerRouteStatusWithReferencedBy(obj, state, p.Reason, p.Message, emptyVSes) 973 if err != nil { 974 glog.Errorf("Error when updating the status for VirtualServerRoute %v/%v: %v", obj.Namespace, obj.Name, err) 975 } 976 } 977 } 978 } 979 } 980 981 func (lbc *LoadBalancerController) processChanges(changes []ResourceChange) { 982 glog.V(3).Infof("Processing %v changes", len(changes)) 983 984 for _, c := range changes { 985 if c.Op == AddOrUpdate { 986 switch impl := c.Resource.(type) { 987 case *VirtualServerConfiguration: 988 vsEx := lbc.createVirtualServerEx(impl.VirtualServer, impl.VirtualServerRoutes) 989 990 warnings, addOrUpdateErr := lbc.configurator.AddOrUpdateVirtualServer(vsEx) 991 lbc.updateVirtualServerStatusAndEvents(impl, warnings, addOrUpdateErr) 992 case *IngressConfiguration: 993 if impl.IsMaster { 994 mergeableIng := lbc.createMergeableIngresses(impl) 995 996 warnings, addOrUpdateErr := lbc.configurator.AddOrUpdateMergeableIngress(mergeableIng) 997 lbc.updateMergeableIngressStatusAndEvents(impl, warnings, addOrUpdateErr) 998 } else { 999 // for regular Ingress, validMinionPaths is nil 1000 ingEx := lbc.createIngressEx(impl.Ingress, impl.ValidHosts, nil) 1001 1002 warnings, addOrUpdateErr := lbc.configurator.AddOrUpdateIngress(ingEx) 1003 lbc.updateRegularIngressStatusAndEvents(impl, warnings, addOrUpdateErr) 1004 } 1005 case *TransportServerConfiguration: 1006 tsEx := lbc.createTransportServerEx(impl.TransportServer, impl.ListenerPort) 1007 1008 addOrUpdateErr := lbc.configurator.AddOrUpdateTransportServer(tsEx) 1009 lbc.updateTransportServerStatusAndEvents(impl, addOrUpdateErr) 1010 } 1011 } else if c.Op == Delete { 1012 switch impl := c.Resource.(type) { 1013 case *VirtualServerConfiguration: 1014 key := getResourceKey(&impl.VirtualServer.ObjectMeta) 1015 1016 deleteErr := lbc.configurator.DeleteVirtualServer(key) 1017 if deleteErr != nil { 1018 glog.Errorf("Error when deleting configuration for VirtualServer %v: %v", key, deleteErr) 1019 } 1020 1021 _, vsExists, err := lbc.virtualServerLister.GetByKey(key) 1022 if err != nil { 1023 glog.Errorf("Error when getting VirtualServer for %v: %v", key, err) 1024 } 1025 1026 if vsExists { 1027 lbc.UpdateVirtualServerStatusAndEventsOnDelete(impl, c.Error, deleteErr) 1028 } 1029 case *IngressConfiguration: 1030 key := getResourceKey(&impl.Ingress.ObjectMeta) 1031 1032 glog.V(2).Infof("Deleting Ingress: %v\n", key) 1033 1034 deleteErr := lbc.configurator.DeleteIngress(key) 1035 if deleteErr != nil { 1036 glog.Errorf("Error when deleting configuration for Ingress %v: %v", key, deleteErr) 1037 } 1038 1039 _, ingExists, err := lbc.ingressLister.GetByKeySafe(key) 1040 if err != nil { 1041 glog.Errorf("Error when getting Ingress for %v: %v", key, err) 1042 } 1043 1044 if ingExists { 1045 lbc.UpdateIngressStatusAndEventsOnDelete(impl, c.Error, deleteErr) 1046 } 1047 case *TransportServerConfiguration: 1048 key := getResourceKey(&impl.TransportServer.ObjectMeta) 1049 1050 deleteErr := lbc.configurator.DeleteTransportServer(key) 1051 1052 if deleteErr != nil { 1053 glog.Errorf("Error when deleting configuration for TransportServer %v: %v", key, deleteErr) 1054 } 1055 1056 _, tsExists, err := lbc.transportServerLister.GetByKey(key) 1057 if err != nil { 1058 glog.Errorf("Error when getting TransportServer for %v: %v", key, err) 1059 } 1060 if tsExists { 1061 lbc.updateTransportServerStatusAndEventsOnDelete(impl, c.Error, deleteErr) 1062 } 1063 } 1064 } 1065 } 1066 } 1067 1068 // processChangesFromGlobalConfiguration processes changes that come from updates to the GlobalConfiguration resource. 1069 // Such changes need to be processed at once to prevent any inconsistencies in the generated NGINX config. 1070 func (lbc *LoadBalancerController) processChangesFromGlobalConfiguration(changes []ResourceChange) error { 1071 var updatedTSExes []*configs.TransportServerEx 1072 var deletedKeys []string 1073 1074 var updatedResources []Resource 1075 1076 for _, c := range changes { 1077 tsConfig := c.Resource.(*TransportServerConfiguration) 1078 1079 if c.Op == AddOrUpdate { 1080 tsEx := lbc.createTransportServerEx(tsConfig.TransportServer, tsConfig.ListenerPort) 1081 1082 updatedTSExes = append(updatedTSExes, tsEx) 1083 updatedResources = append(updatedResources, tsConfig) 1084 } else if c.Op == Delete { 1085 key := getResourceKey(&tsConfig.TransportServer.ObjectMeta) 1086 1087 deletedKeys = append(deletedKeys, key) 1088 } 1089 } 1090 1091 updateErr := lbc.configurator.UpdateTransportServers(updatedTSExes, deletedKeys) 1092 1093 lbc.updateResourcesStatusAndEvents(updatedResources, configs.Warnings{}, updateErr) 1094 1095 return updateErr 1096 } 1097 1098 func (lbc *LoadBalancerController) processAppProtectChanges(changes []appprotect.Change) { 1099 glog.V(3).Infof("Processing %v App Protect changes", len(changes)) 1100 1101 for _, c := range changes { 1102 if c.Op == appprotect.AddOrUpdate { 1103 switch impl := c.Resource.(type) { 1104 case *appprotect.PolicyEx: 1105 namespace := impl.Obj.GetNamespace() 1106 name := impl.Obj.GetName() 1107 resources := lbc.configuration.FindResourcesForAppProtectPolicyAnnotation(namespace, name) 1108 1109 for _, wafPol := range getWAFPoliciesForAppProtectPolicy(lbc.getAllPolicies(), namespace+"/"+name) { 1110 resources = append(resources, lbc.configuration.FindResourcesForPolicy(wafPol.Namespace, wafPol.Name)...) 1111 } 1112 1113 resourceExes := lbc.createExtendedResources(resources) 1114 1115 warnings, updateErr := lbc.configurator.AddOrUpdateAppProtectResource(impl.Obj, resourceExes.IngressExes, resourceExes.MergeableIngresses, resourceExes.VirtualServerExes) 1116 lbc.updateResourcesStatusAndEvents(resources, warnings, updateErr) 1117 lbc.recorder.Eventf(impl.Obj, api_v1.EventTypeNormal, "AddedOrUpdated", "AppProtectPolicy %v was added or updated", namespace+"/"+name) 1118 case *appprotect.LogConfEx: 1119 namespace := impl.Obj.GetNamespace() 1120 name := impl.Obj.GetName() 1121 resources := lbc.configuration.FindResourcesForAppProtectLogConfAnnotation(namespace, name) 1122 1123 for _, wafPol := range getWAFPoliciesForAppProtectLogConf(lbc.getAllPolicies(), namespace+"/"+name) { 1124 resources = append(resources, lbc.configuration.FindResourcesForPolicy(wafPol.Namespace, wafPol.Name)...) 1125 } 1126 1127 resourceExes := lbc.createExtendedResources(resources) 1128 1129 warnings, updateErr := lbc.configurator.AddOrUpdateAppProtectResource(impl.Obj, resourceExes.IngressExes, resourceExes.MergeableIngresses, resourceExes.VirtualServerExes) 1130 lbc.updateResourcesStatusAndEvents(resources, warnings, updateErr) 1131 lbc.recorder.Eventf(impl.Obj, api_v1.EventTypeNormal, "AddedOrUpdated", "AppProtectLogConfig %v was added or updated", namespace+"/"+name) 1132 } 1133 } else if c.Op == appprotect.Delete { 1134 switch impl := c.Resource.(type) { 1135 case *appprotect.PolicyEx: 1136 namespace := impl.Obj.GetNamespace() 1137 name := impl.Obj.GetName() 1138 resources := lbc.configuration.FindResourcesForAppProtectPolicyAnnotation(namespace, name) 1139 1140 for _, wafPol := range getWAFPoliciesForAppProtectPolicy(lbc.getAllPolicies(), namespace+"/"+name) { 1141 resources = append(resources, lbc.configuration.FindResourcesForPolicy(wafPol.Namespace, wafPol.Name)...) 1142 } 1143 1144 resourceExes := lbc.createExtendedResources(resources) 1145 1146 warnings, deleteErr := lbc.configurator.DeleteAppProtectPolicy(namespace+"/"+name, resourceExes.IngressExes, resourceExes.MergeableIngresses, resourceExes.VirtualServerExes) 1147 1148 lbc.updateResourcesStatusAndEvents(resources, warnings, deleteErr) 1149 1150 case *appprotect.LogConfEx: 1151 namespace := impl.Obj.GetNamespace() 1152 name := impl.Obj.GetName() 1153 resources := lbc.configuration.FindResourcesForAppProtectLogConfAnnotation(namespace, name) 1154 1155 for _, wafPol := range getWAFPoliciesForAppProtectLogConf(lbc.getAllPolicies(), namespace+"/"+name) { 1156 resources = append(resources, lbc.configuration.FindResourcesForPolicy(wafPol.Namespace, wafPol.Name)...) 1157 } 1158 1159 resourceExes := lbc.createExtendedResources(resources) 1160 1161 warnings, deleteErr := lbc.configurator.DeleteAppProtectLogConf(namespace+"/"+name, resourceExes.IngressExes, resourceExes.MergeableIngresses, resourceExes.VirtualServerExes) 1162 1163 lbc.updateResourcesStatusAndEvents(resources, warnings, deleteErr) 1164 } 1165 } 1166 } 1167 } 1168 1169 func (lbc *LoadBalancerController) processAppProtectUserSigChange(change appprotect.UserSigChange) { 1170 var delPols []string 1171 var allIngExes []*configs.IngressEx 1172 var allMergeableIngresses []*configs.MergeableIngresses 1173 var allVsExes []*configs.VirtualServerEx 1174 var allResources []Resource 1175 1176 for _, poladd := range change.PolicyAddsOrUpdates { 1177 resources := lbc.configuration.FindResourcesForAppProtectPolicyAnnotation(poladd.GetNamespace(), poladd.GetName()) 1178 1179 for _, wafPol := range getWAFPoliciesForAppProtectPolicy(lbc.getAllPolicies(), appprotect.GetNsName(poladd)) { 1180 resources = append(resources, lbc.configuration.FindResourcesForPolicy(wafPol.Namespace, wafPol.Name)...) 1181 } 1182 1183 resourceExes := lbc.createExtendedResources(resources) 1184 allIngExes = append(allIngExes, resourceExes.IngressExes...) 1185 allMergeableIngresses = append(allMergeableIngresses, resourceExes.MergeableIngresses...) 1186 allVsExes = append(allVsExes, resourceExes.VirtualServerExes...) 1187 allResources = append(allResources, resources...) 1188 } 1189 for _, poldel := range change.PolicyDeletions { 1190 resources := lbc.configuration.FindResourcesForAppProtectPolicyAnnotation(poldel.GetNamespace(), poldel.GetName()) 1191 1192 polNsName := appprotect.GetNsName(poldel) 1193 for _, wafPol := range getWAFPoliciesForAppProtectPolicy(lbc.getAllPolicies(), polNsName) { 1194 resources = append(resources, lbc.configuration.FindResourcesForPolicy(wafPol.Namespace, wafPol.Name)...) 1195 } 1196 1197 resourceExes := lbc.createExtendedResources(resources) 1198 allIngExes = append(allIngExes, resourceExes.IngressExes...) 1199 allMergeableIngresses = append(allMergeableIngresses, resourceExes.MergeableIngresses...) 1200 allVsExes = append(allVsExes, resourceExes.VirtualServerExes...) 1201 allResources = append(allResources, resources...) 1202 if len(resourceExes.IngressExes)+len(resourceExes.MergeableIngresses)+len(resourceExes.VirtualServerExes) > 0 { 1203 delPols = append(delPols, polNsName) 1204 } 1205 } 1206 1207 warnings, err := lbc.configurator.RefreshAppProtectUserSigs(change.UserSigs, delPols, allIngExes, allMergeableIngresses, allVsExes) 1208 if err != nil { 1209 glog.Errorf("Error when refreshing App Protect Policy User defined signatures: %v", err) 1210 } 1211 lbc.updateResourcesStatusAndEvents(allResources, warnings, err) 1212 } 1213 1214 func (lbc *LoadBalancerController) processAppProtectProblems(problems []appprotect.Problem) { 1215 glog.V(3).Infof("Processing %v App Protect problems", len(problems)) 1216 1217 for _, p := range problems { 1218 eventType := api_v1.EventTypeWarning 1219 lbc.recorder.Event(p.Object, eventType, p.Reason, p.Message) 1220 } 1221 } 1222 1223 func (lbc *LoadBalancerController) updateTransportServerStatusAndEventsOnDelete(tsConfig *TransportServerConfiguration, changeError string, deleteErr error) { 1224 eventType := api_v1.EventTypeWarning 1225 eventTitle := "Rejected" 1226 eventWarningMessage := "" 1227 var state string 1228 1229 // TransportServer either became invalid or lost its host or listener 1230 if changeError != "" { 1231 state = conf_v1.StateInvalid 1232 eventWarningMessage = fmt.Sprintf("with error: %s", changeError) 1233 } else if len(tsConfig.Warnings) > 0 { 1234 state = conf_v1.StateWarning 1235 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(tsConfig.Warnings)) 1236 } 1237 1238 // we don't need to report anything if eventWarningMessage is empty 1239 // in that case, the resource was deleted because its class became incorrect 1240 // (some other Ingress Controller will handle it) 1241 1242 if eventWarningMessage != "" { 1243 if deleteErr != nil { 1244 eventType = api_v1.EventTypeWarning 1245 eventTitle = "RejectedWithError" 1246 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, deleteErr) 1247 state = conf_v1.StateInvalid 1248 } 1249 1250 msg := fmt.Sprintf("TransportServer %s was rejected %s", getResourceKey(&tsConfig.TransportServer.ObjectMeta), eventWarningMessage) 1251 lbc.recorder.Eventf(tsConfig.TransportServer, eventType, eventTitle, msg) 1252 1253 if lbc.reportCustomResourceStatusEnabled() { 1254 err := lbc.statusUpdater.UpdateTransportServerStatus(tsConfig.TransportServer, state, eventTitle, msg) 1255 if err != nil { 1256 glog.Errorf("Error when updating the status for TransportServer %v/%v: %v", tsConfig.TransportServer.Namespace, tsConfig.TransportServer.Name, err) 1257 } 1258 } 1259 } 1260 } 1261 1262 func (lbc *LoadBalancerController) UpdateVirtualServerStatusAndEventsOnDelete(vsConfig *VirtualServerConfiguration, changeError string, deleteErr error) { 1263 eventType := api_v1.EventTypeWarning 1264 eventTitle := "Rejected" 1265 eventWarningMessage := "" 1266 state := "" 1267 1268 // VirtualServer either became invalid or lost its host 1269 if changeError != "" { 1270 eventWarningMessage = fmt.Sprintf("with error: %s", changeError) 1271 state = conf_v1.StateInvalid 1272 } else if len(vsConfig.Warnings) > 0 { 1273 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(vsConfig.Warnings)) 1274 state = conf_v1.StateWarning 1275 } 1276 1277 // we don't need to report anything if eventWarningMessage is empty 1278 // in that case, the resource was deleted because its class became incorrect 1279 // (some other Ingress Controller will handle it) 1280 if eventWarningMessage != "" { 1281 if deleteErr != nil { 1282 eventType = api_v1.EventTypeWarning 1283 eventTitle = "RejectedWithError" 1284 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, deleteErr) 1285 state = conf_v1.StateInvalid 1286 } 1287 1288 msg := fmt.Sprintf("VirtualServer %s was rejected %s", getResourceKey(&vsConfig.VirtualServer.ObjectMeta), eventWarningMessage) 1289 lbc.recorder.Eventf(vsConfig.VirtualServer, eventType, eventTitle, msg) 1290 1291 if lbc.reportCustomResourceStatusEnabled() { 1292 err := lbc.statusUpdater.UpdateVirtualServerStatus(vsConfig.VirtualServer, state, eventTitle, msg) 1293 if err != nil { 1294 glog.Errorf("Error when updating the status for VirtualServer %v/%v: %v", vsConfig.VirtualServer.Namespace, vsConfig.VirtualServer.Name, err) 1295 } 1296 } 1297 } 1298 1299 // for delete, no need to report VirtualServerRoutes 1300 // for each VSR, a dedicated problem exists 1301 } 1302 1303 func (lbc *LoadBalancerController) UpdateIngressStatusAndEventsOnDelete(ingConfig *IngressConfiguration, changeError string, deleteErr error) { 1304 eventTitle := "Rejected" 1305 eventWarningMessage := "" 1306 1307 // Ingress either became invalid or lost all its hosts 1308 if changeError != "" { 1309 eventWarningMessage = fmt.Sprintf("with error: %s", changeError) 1310 } else if len(ingConfig.Warnings) > 0 { 1311 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(ingConfig.Warnings)) 1312 } 1313 1314 // we don't need to report anything if eventWarningMessage is empty 1315 // in that case, the resource was deleted because its class became incorrect 1316 // (some other Ingress Controller will handle it) 1317 if eventWarningMessage != "" { 1318 if deleteErr != nil { 1319 eventTitle = "RejectedWithError" 1320 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, deleteErr) 1321 } 1322 1323 lbc.recorder.Eventf(ingConfig.Ingress, api_v1.EventTypeWarning, eventTitle, "%v was rejected: %v", getResourceKey(&ingConfig.Ingress.ObjectMeta), eventWarningMessage) 1324 if lbc.reportStatusEnabled() { 1325 err := lbc.statusUpdater.ClearIngressStatus(*ingConfig.Ingress) 1326 if err != nil { 1327 glog.V(3).Infof("Error clearing Ingress status: %v", err) 1328 } 1329 } 1330 } 1331 1332 // for delete, no need to report minions 1333 // for each minion, a dedicated problem exists 1334 } 1335 1336 func (lbc *LoadBalancerController) updateResourcesStatusAndEvents(resources []Resource, warnings configs.Warnings, operationErr error) { 1337 for _, r := range resources { 1338 switch impl := r.(type) { 1339 case *VirtualServerConfiguration: 1340 lbc.updateVirtualServerStatusAndEvents(impl, warnings, operationErr) 1341 case *IngressConfiguration: 1342 if impl.IsMaster { 1343 lbc.updateMergeableIngressStatusAndEvents(impl, warnings, operationErr) 1344 } else { 1345 lbc.updateRegularIngressStatusAndEvents(impl, warnings, operationErr) 1346 } 1347 case *TransportServerConfiguration: 1348 lbc.updateTransportServerStatusAndEvents(impl, operationErr) 1349 } 1350 } 1351 } 1352 1353 func (lbc *LoadBalancerController) updateMergeableIngressStatusAndEvents(ingConfig *IngressConfiguration, warnings configs.Warnings, operationErr error) { 1354 eventType := api_v1.EventTypeNormal 1355 eventTitle := "AddedOrUpdated" 1356 eventWarningMessage := "" 1357 1358 if len(ingConfig.Warnings) > 0 { 1359 eventType = api_v1.EventTypeWarning 1360 eventTitle = "AddedOrUpdatedWithWarning" 1361 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(ingConfig.Warnings)) 1362 } 1363 1364 if messages, ok := warnings[ingConfig.Ingress]; ok { 1365 eventType = api_v1.EventTypeWarning 1366 eventTitle = "AddedOrUpdatedWithWarning" 1367 eventWarningMessage = fmt.Sprintf("%s; with warning(s): %v", eventWarningMessage, formatWarningMessages(messages)) 1368 } 1369 1370 if operationErr != nil { 1371 eventType = api_v1.EventTypeWarning 1372 eventTitle = "AddedOrUpdatedWithError" 1373 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, operationErr) 1374 } 1375 1376 msg := fmt.Sprintf("Configuration for %v was added or updated %s", getResourceKey(&ingConfig.Ingress.ObjectMeta), eventWarningMessage) 1377 lbc.recorder.Eventf(ingConfig.Ingress, eventType, eventTitle, msg) 1378 1379 for _, fm := range ingConfig.Minions { 1380 minionEventType := api_v1.EventTypeNormal 1381 minionEventTitle := "AddedOrUpdated" 1382 minionEventWarningMessage := "" 1383 1384 minionChangeWarnings := ingConfig.ChildWarnings[getResourceKey(&fm.Ingress.ObjectMeta)] 1385 if len(minionChangeWarnings) > 0 { 1386 minionEventType = api_v1.EventTypeWarning 1387 minionEventTitle = "AddedOrUpdatedWithWarning" 1388 minionEventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(minionChangeWarnings)) 1389 } 1390 1391 if messages, ok := warnings[fm.Ingress]; ok { 1392 minionEventType = api_v1.EventTypeWarning 1393 minionEventTitle = "AddedOrUpdatedWithWarning" 1394 minionEventWarningMessage = fmt.Sprintf("%s; with warning(s): %v", minionEventWarningMessage, formatWarningMessages(messages)) 1395 } 1396 1397 if operationErr != nil { 1398 minionEventType = api_v1.EventTypeWarning 1399 minionEventTitle = "AddedOrUpdatedWithError" 1400 minionEventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", minionEventWarningMessage, operationErr) 1401 } 1402 1403 minionMsg := fmt.Sprintf("Configuration for %v/%v was added or updated %s", fm.Ingress.Namespace, fm.Ingress.Name, minionEventWarningMessage) 1404 lbc.recorder.Eventf(fm.Ingress, minionEventType, minionEventTitle, minionMsg) 1405 } 1406 1407 if lbc.reportStatusEnabled() { 1408 ings := []networking.Ingress{*ingConfig.Ingress} 1409 1410 for _, fm := range ingConfig.Minions { 1411 ings = append(ings, *fm.Ingress) 1412 } 1413 1414 err := lbc.statusUpdater.BulkUpdateIngressStatus(ings) 1415 if err != nil { 1416 glog.V(3).Infof("error updating ing status: %v", err) 1417 } 1418 } 1419 } 1420 1421 func (lbc *LoadBalancerController) updateRegularIngressStatusAndEvents(ingConfig *IngressConfiguration, warnings configs.Warnings, operationErr error) { 1422 eventType := api_v1.EventTypeNormal 1423 eventTitle := "AddedOrUpdated" 1424 eventWarningMessage := "" 1425 1426 if len(ingConfig.Warnings) > 0 { 1427 eventType = api_v1.EventTypeWarning 1428 eventTitle = "AddedOrUpdatedWithWarning" 1429 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(ingConfig.Warnings)) 1430 } 1431 1432 if messages, ok := warnings[ingConfig.Ingress]; ok { 1433 eventType = api_v1.EventTypeWarning 1434 eventTitle = "AddedOrUpdatedWithWarning" 1435 eventWarningMessage = fmt.Sprintf("%s; with warning(s): %v", eventWarningMessage, formatWarningMessages(messages)) 1436 } 1437 1438 if operationErr != nil { 1439 eventType = api_v1.EventTypeWarning 1440 eventTitle = "AddedOrUpdatedWithError" 1441 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, operationErr) 1442 } 1443 1444 msg := fmt.Sprintf("Configuration for %v was added or updated %s", getResourceKey(&ingConfig.Ingress.ObjectMeta), eventWarningMessage) 1445 lbc.recorder.Eventf(ingConfig.Ingress, eventType, eventTitle, msg) 1446 1447 if lbc.reportStatusEnabled() { 1448 err := lbc.statusUpdater.UpdateIngressStatus(*ingConfig.Ingress) 1449 if err != nil { 1450 glog.V(3).Infof("error updating ing status: %v", err) 1451 } 1452 } 1453 } 1454 1455 func (lbc *LoadBalancerController) updateTransportServerStatusAndEvents(tsConfig *TransportServerConfiguration, operationErr error) { 1456 eventTitle := "AddedOrUpdated" 1457 eventType := api_v1.EventTypeNormal 1458 eventWarningMessage := "" 1459 state := conf_v1.StateValid 1460 1461 if len(tsConfig.Warnings) > 0 { 1462 eventType = api_v1.EventTypeWarning 1463 eventTitle = "AddedOrUpdatedWithWarning" 1464 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(tsConfig.Warnings)) 1465 state = conf_v1.StateWarning 1466 } 1467 1468 if operationErr != nil { 1469 eventType = api_v1.EventTypeWarning 1470 eventTitle = "AddedOrUpdatedWithError" 1471 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, operationErr) 1472 state = conf_v1.StateInvalid 1473 } 1474 1475 msg := fmt.Sprintf("Configuration for %v was added or updated %s", getResourceKey(&tsConfig.TransportServer.ObjectMeta), eventWarningMessage) 1476 lbc.recorder.Eventf(tsConfig.TransportServer, eventType, eventTitle, msg) 1477 1478 if lbc.reportCustomResourceStatusEnabled() { 1479 err := lbc.statusUpdater.UpdateTransportServerStatus(tsConfig.TransportServer, state, eventTitle, msg) 1480 if err != nil { 1481 glog.Errorf("Error when updating the status for TransportServer %v/%v: %v", tsConfig.TransportServer.Namespace, tsConfig.TransportServer.Name, err) 1482 } 1483 } 1484 } 1485 1486 func (lbc *LoadBalancerController) updateVirtualServerStatusAndEvents(vsConfig *VirtualServerConfiguration, warnings configs.Warnings, operationErr error) { 1487 eventType := api_v1.EventTypeNormal 1488 eventTitle := "AddedOrUpdated" 1489 eventWarningMessage := "" 1490 state := conf_v1.StateValid 1491 1492 if len(vsConfig.Warnings) > 0 { 1493 eventType = api_v1.EventTypeWarning 1494 eventTitle = "AddedOrUpdatedWithWarning" 1495 eventWarningMessage = fmt.Sprintf("with warning(s): %s", formatWarningMessages(vsConfig.Warnings)) 1496 state = conf_v1.StateWarning 1497 } 1498 1499 if messages, ok := warnings[vsConfig.VirtualServer]; ok { 1500 eventType = api_v1.EventTypeWarning 1501 eventTitle = "AddedOrUpdatedWithWarning" 1502 eventWarningMessage = fmt.Sprintf("%s; with warning(s): %v", eventWarningMessage, formatWarningMessages(messages)) 1503 state = conf_v1.StateWarning 1504 } 1505 1506 if operationErr != nil { 1507 eventType = api_v1.EventTypeWarning 1508 eventTitle = "AddedOrUpdatedWithError" 1509 eventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", eventWarningMessage, operationErr) 1510 state = conf_v1.StateInvalid 1511 } 1512 1513 msg := fmt.Sprintf("Configuration for %v was added or updated %s", getResourceKey(&vsConfig.VirtualServer.ObjectMeta), eventWarningMessage) 1514 lbc.recorder.Eventf(vsConfig.VirtualServer, eventType, eventTitle, msg) 1515 1516 if lbc.reportCustomResourceStatusEnabled() { 1517 err := lbc.statusUpdater.UpdateVirtualServerStatus(vsConfig.VirtualServer, state, eventTitle, msg) 1518 if err != nil { 1519 glog.Errorf("Error when updating the status for VirtualServer %v/%v: %v", vsConfig.VirtualServer.Namespace, vsConfig.VirtualServer.Name, err) 1520 } 1521 } 1522 1523 for _, vsr := range vsConfig.VirtualServerRoutes { 1524 vsrEventType := api_v1.EventTypeNormal 1525 vsrEventTitle := "AddedOrUpdated" 1526 vsrEventWarningMessage := "" 1527 vsrState := conf_v1.StateValid 1528 1529 if messages, ok := warnings[vsr]; ok { 1530 vsrEventType = api_v1.EventTypeWarning 1531 vsrEventTitle = "AddedOrUpdatedWithWarning" 1532 vsrEventWarningMessage = fmt.Sprintf("with warning(s): %v", formatWarningMessages(messages)) 1533 vsrState = conf_v1.StateWarning 1534 } 1535 1536 if operationErr != nil { 1537 vsrEventType = api_v1.EventTypeWarning 1538 vsrEventTitle = "AddedOrUpdatedWithError" 1539 vsrEventWarningMessage = fmt.Sprintf("%s; but was not applied: %v", vsrEventWarningMessage, operationErr) 1540 vsrState = conf_v1.StateInvalid 1541 } 1542 1543 msg := fmt.Sprintf("Configuration for %v/%v was added or updated %s", vsr.Namespace, vsr.Name, vsrEventWarningMessage) 1544 lbc.recorder.Eventf(vsr, vsrEventType, vsrEventTitle, msg) 1545 1546 if lbc.reportCustomResourceStatusEnabled() { 1547 vss := []*conf_v1.VirtualServer{vsConfig.VirtualServer} 1548 err := lbc.statusUpdater.UpdateVirtualServerRouteStatusWithReferencedBy(vsr, vsrState, vsrEventTitle, msg, vss) 1549 if err != nil { 1550 glog.Errorf("Error when updating the status for VirtualServerRoute %v/%v: %v", vsr.Namespace, vsr.Name, err) 1551 } 1552 } 1553 } 1554 } 1555 1556 func (lbc *LoadBalancerController) syncVirtualServerRoute(task task) { 1557 key := task.Key 1558 obj, exists, err := lbc.virtualServerRouteLister.GetByKey(key) 1559 if err != nil { 1560 lbc.syncQueue.Requeue(task, err) 1561 return 1562 } 1563 1564 var changes []ResourceChange 1565 var problems []ConfigurationProblem 1566 1567 if !exists { 1568 glog.V(2).Infof("Deleting VirtualServerRoute: %v\n", key) 1569 1570 changes, problems = lbc.configuration.DeleteVirtualServerRoute(key) 1571 } else { 1572 glog.V(2).Infof("Adding or Updating VirtualServerRoute: %v\n", key) 1573 1574 vsr := obj.(*conf_v1.VirtualServerRoute) 1575 changes, problems = lbc.configuration.AddOrUpdateVirtualServerRoute(vsr) 1576 } 1577 1578 lbc.processChanges(changes) 1579 lbc.processProblems(problems) 1580 } 1581 1582 func (lbc *LoadBalancerController) syncIngress(task task) { 1583 key := task.Key 1584 ing, ingExists, err := lbc.ingressLister.GetByKeySafe(key) 1585 if err != nil { 1586 lbc.syncQueue.Requeue(task, err) 1587 return 1588 } 1589 1590 var changes []ResourceChange 1591 var problems []ConfigurationProblem 1592 1593 if !ingExists { 1594 glog.V(2).Infof("Deleting Ingress: %v\n", key) 1595 1596 changes, problems = lbc.configuration.DeleteIngress(key) 1597 } else { 1598 glog.V(2).Infof("Adding or Updating Ingress: %v\n", key) 1599 1600 changes, problems = lbc.configuration.AddOrUpdateIngress(ing) 1601 } 1602 1603 lbc.processChanges(changes) 1604 lbc.processProblems(problems) 1605 } 1606 1607 func (lbc *LoadBalancerController) updateIngressMetrics() { 1608 counters := lbc.configurator.GetIngressCounts() 1609 for nType, count := range counters { 1610 lbc.metricsCollector.SetIngresses(nType, count) 1611 } 1612 } 1613 1614 func (lbc *LoadBalancerController) updateVirtualServerMetrics() { 1615 vsCount, vsrCount := lbc.configurator.GetVirtualServerCounts() 1616 lbc.metricsCollector.SetVirtualServers(vsCount) 1617 lbc.metricsCollector.SetVirtualServerRoutes(vsrCount) 1618 } 1619 1620 func (lbc *LoadBalancerController) syncService(task task) { 1621 key := task.Key 1622 glog.V(3).Infof("Syncing service %v", key) 1623 1624 obj, exists, err := lbc.svcLister.GetByKey(key) 1625 if err != nil { 1626 lbc.syncQueue.Requeue(task, err) 1627 return 1628 } 1629 1630 // First case: the service is the external service for the Ingress Controller 1631 // In that case we need to update the statuses of all resources 1632 1633 if lbc.IsExternalServiceKeyForStatus(key) { 1634 1635 if !exists { 1636 // service got removed 1637 lbc.statusUpdater.ClearStatusFromExternalService() 1638 } else { 1639 // service added or updated 1640 lbc.statusUpdater.SaveStatusFromExternalService(obj.(*api_v1.Service)) 1641 } 1642 1643 if lbc.reportStatusEnabled() { 1644 ingresses := lbc.configuration.GetResourcesWithFilter(resourceFilter{Ingresses: true}) 1645 1646 glog.V(3).Infof("Updating status for %v Ingresses", len(ingresses)) 1647 1648 err := lbc.statusUpdater.UpdateExternalEndpointsForResources(ingresses) 1649 if err != nil { 1650 glog.Errorf("error updating ingress status in syncService: %v", err) 1651 } 1652 } 1653 1654 if lbc.areCustomResourcesEnabled && lbc.reportCustomResourceStatusEnabled() { 1655 virtualServers := lbc.configuration.GetResourcesWithFilter(resourceFilter{VirtualServers: true}) 1656 1657 glog.V(3).Infof("Updating status for %v VirtualServers", len(virtualServers)) 1658 1659 err := lbc.statusUpdater.UpdateExternalEndpointsForResources(virtualServers) 1660 if err != nil { 1661 glog.V(3).Infof("error updating VirtualServer/VirtualServerRoute status in syncService: %v", err) 1662 } 1663 } 1664 1665 // we don't return here because technically the same service could be used in the second case 1666 } 1667 1668 // Second case: the service is referenced by some resources in the cluster 1669 1670 // it is safe to ignore the error 1671 namespace, name, _ := ParseNamespaceName(key) 1672 1673 resources := lbc.configuration.FindResourcesForService(namespace, name) 1674 1675 if len(resources) == 0 { 1676 return 1677 } 1678 1679 glog.V(3).Infof("Updating %v resources", len(resources)) 1680 1681 resourceExes := lbc.createExtendedResources(resources) 1682 1683 warnings, updateErr := lbc.configurator.AddOrUpdateResources(resourceExes) 1684 lbc.updateResourcesStatusAndEvents(resources, warnings, updateErr) 1685 } 1686 1687 // IsExternalServiceForStatus matches the service specified by the external-service cli arg 1688 func (lbc *LoadBalancerController) IsExternalServiceForStatus(svc *api_v1.Service) bool { 1689 return lbc.statusUpdater.namespace == svc.Namespace && lbc.statusUpdater.externalServiceName == svc.Name 1690 } 1691 1692 // IsExternalServiceKeyForStatus matches the service key specified by the external-service cli arg 1693 func (lbc *LoadBalancerController) IsExternalServiceKeyForStatus(key string) bool { 1694 externalSvcKey := fmt.Sprintf("%s/%s", lbc.statusUpdater.namespace, lbc.statusUpdater.externalServiceName) 1695 return key == externalSvcKey 1696 } 1697 1698 // reportStatusEnabled determines if we should attempt to report status for Ingress resources. 1699 func (lbc *LoadBalancerController) reportStatusEnabled() bool { 1700 if lbc.reportIngressStatus { 1701 if lbc.isLeaderElectionEnabled { 1702 return lbc.leaderElector != nil && lbc.leaderElector.IsLeader() 1703 } 1704 return true 1705 } 1706 return false 1707 } 1708 1709 // reportCustomResourceStatusEnabled determines if we should attempt to report status for Custom Resources. 1710 func (lbc *LoadBalancerController) reportCustomResourceStatusEnabled() bool { 1711 if lbc.isLeaderElectionEnabled { 1712 return lbc.leaderElector != nil && lbc.leaderElector.IsLeader() 1713 } 1714 1715 return true 1716 } 1717 1718 func (lbc *LoadBalancerController) syncSecret(task task) { 1719 key := task.Key 1720 obj, secrExists, err := lbc.secretLister.GetByKey(key) 1721 if err != nil { 1722 lbc.syncQueue.Requeue(task, err) 1723 return 1724 } 1725 1726 namespace, name, err := ParseNamespaceName(key) 1727 if err != nil { 1728 glog.Warningf("Secret key %v is invalid: %v", key, err) 1729 return 1730 } 1731 1732 resources := lbc.configuration.FindResourcesForSecret(namespace, name) 1733 1734 if lbc.areCustomResourcesEnabled { 1735 secretPols := lbc.getPoliciesForSecret(namespace, name) 1736 for _, pol := range secretPols { 1737 resources = append(resources, lbc.configuration.FindResourcesForPolicy(pol.Namespace, pol.Name)...) 1738 } 1739 1740 resources = removeDuplicateResources(resources) 1741 } 1742 1743 glog.V(2).Infof("Found %v Resources with Secret %v", len(resources), key) 1744 1745 if !secrExists { 1746 lbc.secretStore.DeleteSecret(key) 1747 1748 glog.V(2).Infof("Deleting Secret: %v\n", key) 1749 1750 if len(resources) > 0 { 1751 lbc.handleRegularSecretDeletion(resources) 1752 } 1753 if lbc.isSpecialSecret(key) { 1754 glog.Warningf("A special TLS Secret %v was removed. Retaining the Secret.", key) 1755 } 1756 return 1757 } 1758 1759 glog.V(2).Infof("Adding / Updating Secret: %v\n", key) 1760 1761 secret := obj.(*api_v1.Secret) 1762 1763 lbc.secretStore.AddOrUpdateSecret(secret) 1764 1765 if lbc.isSpecialSecret(key) { 1766 lbc.handleSpecialSecretUpdate(secret) 1767 // we don't return here in case the special secret is also used in resources. 1768 } 1769 1770 if len(resources) > 0 { 1771 lbc.handleSecretUpdate(secret, resources) 1772 } 1773 } 1774 1775 func removeDuplicateResources(resources []Resource) []Resource { 1776 encountered := make(map[string]bool) 1777 var uniqueResources []Resource 1778 for _, r := range resources { 1779 key := r.GetKeyWithKind() 1780 if !encountered[key] { 1781 encountered[key] = true 1782 uniqueResources = append(uniqueResources, r) 1783 } 1784 } 1785 1786 return uniqueResources 1787 } 1788 1789 func (lbc *LoadBalancerController) isSpecialSecret(secretName string) bool { 1790 return secretName == lbc.defaultServerSecret || secretName == lbc.wildcardTLSSecret 1791 } 1792 1793 func (lbc *LoadBalancerController) handleRegularSecretDeletion(resources []Resource) { 1794 resourceExes := lbc.createExtendedResources(resources) 1795 1796 warnings, addOrUpdateErr := lbc.configurator.AddOrUpdateResources(resourceExes) 1797 1798 lbc.updateResourcesStatusAndEvents(resources, warnings, addOrUpdateErr) 1799 } 1800 1801 func (lbc *LoadBalancerController) handleSecretUpdate(secret *api_v1.Secret, resources []Resource) { 1802 secretNsName := secret.Namespace + "/" + secret.Name 1803 1804 var warnings configs.Warnings 1805 var addOrUpdateErr error 1806 1807 resourceExes := lbc.createExtendedResources(resources) 1808 warnings, addOrUpdateErr = lbc.configurator.AddOrUpdateResources(resourceExes) 1809 1810 if addOrUpdateErr != nil { 1811 glog.Errorf("Error when updating Secret %v: %v", secretNsName, addOrUpdateErr) 1812 lbc.recorder.Eventf(secret, api_v1.EventTypeWarning, "UpdatedWithError", "%v was updated, but not applied: %v", secretNsName, addOrUpdateErr) 1813 } 1814 1815 lbc.updateResourcesStatusAndEvents(resources, warnings, addOrUpdateErr) 1816 } 1817 1818 func (lbc *LoadBalancerController) handleSpecialSecretUpdate(secret *api_v1.Secret) { 1819 var specialSecretsToUpdate []string 1820 secretNsName := secret.Namespace + "/" + secret.Name 1821 err := secrets.ValidateTLSSecret(secret) 1822 if err != nil { 1823 glog.Errorf("Couldn't validate the special Secret %v: %v", secretNsName, err) 1824 lbc.recorder.Eventf(secret, api_v1.EventTypeWarning, "Rejected", "the special Secret %v was rejected, using the previous version: %v", secretNsName, err) 1825 return 1826 } 1827 1828 if secretNsName == lbc.defaultServerSecret { 1829 specialSecretsToUpdate = append(specialSecretsToUpdate, configs.DefaultServerSecretName) 1830 } 1831 if secretNsName == lbc.wildcardTLSSecret { 1832 specialSecretsToUpdate = append(specialSecretsToUpdate, configs.WildcardSecretName) 1833 } 1834 1835 err = lbc.configurator.AddOrUpdateSpecialTLSSecrets(secret, specialSecretsToUpdate) 1836 if err != nil { 1837 glog.Errorf("Error when updating the special Secret %v: %v", secretNsName, err) 1838 lbc.recorder.Eventf(secret, api_v1.EventTypeWarning, "UpdatedWithError", "the special Secret %v was updated, but not applied: %v", secretNsName, err) 1839 return 1840 } 1841 1842 lbc.recorder.Eventf(secret, api_v1.EventTypeNormal, "Updated", "the special Secret %v was updated", secretNsName) 1843 } 1844 1845 func getStatusFromEventTitle(eventTitle string) string { 1846 switch eventTitle { 1847 case "AddedOrUpdatedWithError", "Rejected", "NoVirtualServersFound", "Missing Secret", "UpdatedWithError": 1848 return conf_v1.StateInvalid 1849 case "AddedOrUpdatedWithWarning", "UpdatedWithWarning": 1850 return conf_v1.StateWarning 1851 case "AddedOrUpdated", "Updated": 1852 return conf_v1.StateValid 1853 } 1854 1855 return "" 1856 } 1857 1858 func (lbc *LoadBalancerController) updateVirtualServersStatusFromEvents() error { 1859 var allErrs []error 1860 for _, obj := range lbc.virtualServerLister.List() { 1861 vs := obj.(*conf_v1.VirtualServer) 1862 1863 if !lbc.HasCorrectIngressClass(vs) { 1864 glog.V(3).Infof("Ignoring VirtualServer %v based on class %v", vs.Name, vs.Spec.IngressClass) 1865 continue 1866 } 1867 1868 events, err := lbc.client.CoreV1().Events(vs.Namespace).List(context.TODO(), 1869 meta_v1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v,involvedObject.uid=%v", vs.Name, vs.UID)}) 1870 if err != nil { 1871 allErrs = append(allErrs, fmt.Errorf("error trying to get events for VirtualServer %v/%v: %w", vs.Namespace, vs.Name, err)) 1872 break 1873 } 1874 1875 if len(events.Items) == 0 { 1876 continue 1877 } 1878 1879 var timestamp time.Time 1880 var latestEvent api_v1.Event 1881 for _, event := range events.Items { 1882 if event.CreationTimestamp.After(timestamp) { 1883 latestEvent = event 1884 } 1885 } 1886 1887 err = lbc.statusUpdater.UpdateVirtualServerStatus(vs, getStatusFromEventTitle(latestEvent.Reason), latestEvent.Reason, latestEvent.Message) 1888 if err != nil { 1889 allErrs = append(allErrs, err) 1890 } 1891 } 1892 1893 if len(allErrs) > 0 { 1894 return fmt.Errorf("not all VirtualServers statuses were updated: %v", allErrs) 1895 } 1896 1897 return nil 1898 } 1899 1900 func (lbc *LoadBalancerController) updateVirtualServerRoutesStatusFromEvents() error { 1901 var allErrs []error 1902 for _, obj := range lbc.virtualServerRouteLister.List() { 1903 vsr := obj.(*conf_v1.VirtualServerRoute) 1904 1905 if !lbc.HasCorrectIngressClass(vsr) { 1906 glog.V(3).Infof("Ignoring VirtualServerRoute %v based on class %v", vsr.Name, vsr.Spec.IngressClass) 1907 continue 1908 } 1909 1910 events, err := lbc.client.CoreV1().Events(vsr.Namespace).List(context.TODO(), 1911 meta_v1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v,involvedObject.uid=%v", vsr.Name, vsr.UID)}) 1912 if err != nil { 1913 allErrs = append(allErrs, fmt.Errorf("error trying to get events for VirtualServerRoute %v/%v: %w", vsr.Namespace, vsr.Name, err)) 1914 break 1915 } 1916 1917 if len(events.Items) == 0 { 1918 continue 1919 } 1920 1921 var timestamp time.Time 1922 var latestEvent api_v1.Event 1923 for _, event := range events.Items { 1924 if event.CreationTimestamp.After(timestamp) { 1925 latestEvent = event 1926 } 1927 } 1928 1929 err = lbc.statusUpdater.UpdateVirtualServerRouteStatus(vsr, getStatusFromEventTitle(latestEvent.Reason), latestEvent.Reason, latestEvent.Message) 1930 if err != nil { 1931 allErrs = append(allErrs, err) 1932 } 1933 } 1934 1935 if len(allErrs) > 0 { 1936 return fmt.Errorf("not all VirtualServerRoutes statuses were updated: %v", allErrs) 1937 } 1938 1939 return nil 1940 } 1941 1942 func (lbc *LoadBalancerController) updatePoliciesStatus() error { 1943 var allErrs []error 1944 for _, obj := range lbc.policyLister.List() { 1945 pol := obj.(*conf_v1.Policy) 1946 1947 err := validation.ValidatePolicy(pol, lbc.isNginxPlus, lbc.enablePreviewPolicies, lbc.appProtectEnabled) 1948 if err != nil { 1949 msg := fmt.Sprintf("Policy %v/%v is invalid and was rejected: %v", pol.Namespace, pol.Name, err) 1950 err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateInvalid, "Rejected", msg) 1951 if err != nil { 1952 allErrs = append(allErrs, err) 1953 } 1954 } else { 1955 msg := fmt.Sprintf("Policy %v/%v was added or updated", pol.Namespace, pol.Name) 1956 err = lbc.statusUpdater.UpdatePolicyStatus(pol, conf_v1.StateValid, "AddedOrUpdated", msg) 1957 if err != nil { 1958 allErrs = append(allErrs, err) 1959 } 1960 } 1961 } 1962 1963 if len(allErrs) != 0 { 1964 return fmt.Errorf("not all Policies statuses were updated: %v", allErrs) 1965 } 1966 1967 return nil 1968 } 1969 1970 func (lbc *LoadBalancerController) updateTransportServersStatusFromEvents() error { 1971 var allErrs []error 1972 for _, obj := range lbc.transportServerLister.List() { 1973 ts := obj.(*conf_v1alpha1.TransportServer) 1974 1975 events, err := lbc.client.CoreV1().Events(ts.Namespace).List(context.TODO(), 1976 meta_v1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v,involvedObject.uid=%v", ts.Name, ts.UID)}) 1977 if err != nil { 1978 allErrs = append(allErrs, fmt.Errorf("error trying to get events for TransportServer %v/%v: %w", ts.Namespace, ts.Name, err)) 1979 break 1980 } 1981 1982 if len(events.Items) == 0 { 1983 continue 1984 } 1985 1986 var timestamp time.Time 1987 var latestEvent api_v1.Event 1988 for _, event := range events.Items { 1989 if event.CreationTimestamp.After(timestamp) { 1990 latestEvent = event 1991 } 1992 } 1993 1994 err = lbc.statusUpdater.UpdateTransportServerStatus(ts, getStatusFromEventTitle(latestEvent.Reason), latestEvent.Reason, latestEvent.Message) 1995 if err != nil { 1996 allErrs = append(allErrs, err) 1997 } 1998 } 1999 2000 if len(allErrs) > 0 { 2001 return fmt.Errorf("not all TransportServers statuses were updated: %v", allErrs) 2002 } 2003 2004 return nil 2005 } 2006 2007 func getIPAddressesFromEndpoints(endpoints []podEndpoint) []string { 2008 var endps []string 2009 for _, ep := range endpoints { 2010 endps = append(endps, ep.Address) 2011 } 2012 return endps 2013 } 2014 2015 func (lbc *LoadBalancerController) createMergeableIngresses(ingConfig *IngressConfiguration) *configs.MergeableIngresses { 2016 // for master Ingress, validMinionPaths are nil 2017 masterIngressEx := lbc.createIngressEx(ingConfig.Ingress, ingConfig.ValidHosts, nil) 2018 2019 var minions []*configs.IngressEx 2020 2021 for _, m := range ingConfig.Minions { 2022 minions = append(minions, lbc.createIngressEx(m.Ingress, ingConfig.ValidHosts, m.ValidPaths)) 2023 } 2024 2025 return &configs.MergeableIngresses{ 2026 Master: masterIngressEx, 2027 Minions: minions, 2028 } 2029 } 2030 2031 func (lbc *LoadBalancerController) createIngressEx(ing *networking.Ingress, validHosts map[string]bool, validMinionPaths map[string]bool) *configs.IngressEx { 2032 ingEx := &configs.IngressEx{ 2033 Ingress: ing, 2034 ValidHosts: validHosts, 2035 ValidMinionPaths: validMinionPaths, 2036 } 2037 2038 ingEx.SecretRefs = make(map[string]*secrets.SecretReference) 2039 2040 for _, tls := range ing.Spec.TLS { 2041 secretName := tls.SecretName 2042 secretKey := ing.Namespace + "/" + secretName 2043 2044 secretRef := lbc.secretStore.GetSecret(secretKey) 2045 if secretRef.Error != nil { 2046 glog.Warningf("Error trying to get the secret %v for Ingress %v: %v", secretName, ing.Name, secretRef.Error) 2047 } 2048 2049 ingEx.SecretRefs[secretName] = secretRef 2050 } 2051 2052 if lbc.isNginxPlus { 2053 if jwtKey, exists := ingEx.Ingress.Annotations[configs.JWTKeyAnnotation]; exists { 2054 secretName := jwtKey 2055 secretKey := ing.Namespace + "/" + secretName 2056 2057 secretRef := lbc.secretStore.GetSecret(secretKey) 2058 if secretRef.Error != nil { 2059 glog.Warningf("Error trying to get the secret %v for Ingress %v/%v: %v", secretName, ing.Namespace, ing.Name, secretRef.Error) 2060 } 2061 2062 ingEx.SecretRefs[secretName] = secretRef 2063 } 2064 if lbc.appProtectEnabled { 2065 if apPolicyAntn, exists := ingEx.Ingress.Annotations[configs.AppProtectPolicyAnnotation]; exists { 2066 policy, err := lbc.getAppProtectPolicy(ing) 2067 if err != nil { 2068 glog.Warningf("Error Getting App Protect policy %v for Ingress %v/%v: %v", apPolicyAntn, ing.Namespace, ing.Name, err) 2069 } else { 2070 ingEx.AppProtectPolicy = policy 2071 } 2072 } 2073 2074 if apLogConfAntn, exists := ingEx.Ingress.Annotations[configs.AppProtectLogConfAnnotation]; exists { 2075 logConf, err := lbc.getAppProtectLogConfAndDst(ing) 2076 if err != nil { 2077 glog.Warningf("Error Getting App Protect Log Config %v for Ingress %v/%v: %v", apLogConfAntn, ing.Namespace, ing.Name, err) 2078 } else { 2079 ingEx.AppProtectLogs = logConf 2080 } 2081 } 2082 } 2083 } 2084 2085 ingEx.Endpoints = make(map[string][]string) 2086 ingEx.HealthChecks = make(map[string]*api_v1.Probe) 2087 ingEx.ExternalNameSvcs = make(map[string]bool) 2088 ingEx.PodsByIP = make(map[string]configs.PodInfo) 2089 2090 if ing.Spec.Backend != nil { 2091 podEndps := []podEndpoint{} 2092 var external bool 2093 svc, err := lbc.getServiceForIngressBackend(ing.Spec.Backend, ing.Namespace) 2094 if err != nil { 2095 glog.V(3).Infof("Error getting service %v: %v", ing.Spec.Backend.ServiceName, err) 2096 } else { 2097 podEndps, external, err = lbc.getEndpointsForIngressBackend(ing.Spec.Backend, svc) 2098 if err == nil && external && lbc.isNginxPlus { 2099 ingEx.ExternalNameSvcs[svc.Name] = true 2100 } 2101 } 2102 2103 if err != nil { 2104 glog.Warningf("Error retrieving endpoints for the service %v: %v", ing.Spec.Backend.ServiceName, err) 2105 } 2106 2107 endps := getIPAddressesFromEndpoints(podEndps) 2108 2109 // endps is empty if there was any error before this point 2110 ingEx.Endpoints[ing.Spec.Backend.ServiceName+ing.Spec.Backend.ServicePort.String()] = endps 2111 2112 if lbc.isNginxPlus && lbc.isHealthCheckEnabled(ing) { 2113 healthCheck := lbc.getHealthChecksForIngressBackend(ing.Spec.Backend, ing.Namespace) 2114 if healthCheck != nil { 2115 ingEx.HealthChecks[ing.Spec.Backend.ServiceName+ing.Spec.Backend.ServicePort.String()] = healthCheck 2116 } 2117 } 2118 2119 if (lbc.isNginxPlus && lbc.isPrometheusEnabled) || lbc.isLatencyMetricsEnabled { 2120 for _, endpoint := range podEndps { 2121 ingEx.PodsByIP[endpoint.Address] = configs.PodInfo{ 2122 Name: endpoint.PodName, 2123 MeshPodOwner: endpoint.MeshPodOwner, 2124 } 2125 } 2126 } 2127 } 2128 2129 for _, rule := range ing.Spec.Rules { 2130 if !validHosts[rule.Host] { 2131 glog.V(3).Infof("Skipping host %s for Ingress %s", rule.Host, ing.Name) 2132 continue 2133 } 2134 2135 // check if rule has any paths 2136 if rule.IngressRuleValue.HTTP == nil { 2137 continue 2138 } 2139 2140 for _, path := range rule.HTTP.Paths { 2141 podEndps := []podEndpoint{} 2142 if validMinionPaths != nil && !validMinionPaths[path.Path] { 2143 glog.V(3).Infof("Skipping path %s for minion Ingress %s", path.Path, ing.Name) 2144 continue 2145 } 2146 2147 var external bool 2148 svc, err := lbc.getServiceForIngressBackend(&path.Backend, ing.Namespace) 2149 if err != nil { 2150 glog.V(3).Infof("Error getting service %v: %v", &path.Backend.ServiceName, err) 2151 } else { 2152 podEndps, external, err = lbc.getEndpointsForIngressBackend(&path.Backend, svc) 2153 if err == nil && external && lbc.isNginxPlus { 2154 ingEx.ExternalNameSvcs[svc.Name] = true 2155 } 2156 } 2157 2158 if err != nil { 2159 glog.Warningf("Error retrieving endpoints for the service %v: %v", path.Backend.ServiceName, err) 2160 } 2161 2162 endps := getIPAddressesFromEndpoints(podEndps) 2163 2164 // endps is empty if there was any error before this point 2165 ingEx.Endpoints[path.Backend.ServiceName+path.Backend.ServicePort.String()] = endps 2166 2167 // Pull active health checks from k8 api 2168 if lbc.isNginxPlus && lbc.isHealthCheckEnabled(ing) { 2169 healthCheck := lbc.getHealthChecksForIngressBackend(&path.Backend, ing.Namespace) 2170 if healthCheck != nil { 2171 ingEx.HealthChecks[path.Backend.ServiceName+path.Backend.ServicePort.String()] = healthCheck 2172 } 2173 } 2174 2175 if lbc.isNginxPlus || lbc.isLatencyMetricsEnabled { 2176 for _, endpoint := range podEndps { 2177 ingEx.PodsByIP[endpoint.Address] = configs.PodInfo{ 2178 Name: endpoint.PodName, 2179 MeshPodOwner: endpoint.MeshPodOwner, 2180 } 2181 } 2182 } 2183 } 2184 } 2185 2186 return ingEx 2187 } 2188 2189 func (lbc *LoadBalancerController) getAppProtectLogConfAndDst(ing *networking.Ingress) ([]configs.AppProtectLog, error) { 2190 var apLogs []configs.AppProtectLog 2191 if _, exists := ing.Annotations[configs.AppProtectLogConfDstAnnotation]; !exists { 2192 return apLogs, fmt.Errorf("Error: %v requires %v in %v", configs.AppProtectLogConfAnnotation, configs.AppProtectLogConfDstAnnotation, ing.Name) 2193 } 2194 2195 logDsts := strings.Split(ing.Annotations[configs.AppProtectLogConfDstAnnotation], ",") 2196 logConfNsNs := appprotect.ParseResourceReferenceAnnotationList(ing.Namespace, ing.Annotations[configs.AppProtectLogConfAnnotation]) 2197 if len(logDsts) != len(logConfNsNs) { 2198 return apLogs, fmt.Errorf("Error Validating App Protect Destination and Config for Ingress %v: LogConf and LogDestination must have equal number of items", ing.Name) 2199 } 2200 2201 for _, logDst := range logDsts { 2202 err := appprotect.ValidateAppProtectLogDestination(logDst) 2203 if err != nil { 2204 return apLogs, fmt.Errorf("Error Validating App Protect Destination Config for Ingress %v: %w", ing.Name, err) 2205 } 2206 } 2207 2208 for i, logConfNsN := range logConfNsNs { 2209 logConf, err := lbc.appProtectConfiguration.GetAppResource(appprotect.LogConfGVK.Kind, logConfNsN) 2210 if err != nil { 2211 return apLogs, fmt.Errorf("Error retrieving App Protect Log Config for Ingress %v: %w", ing.Name, err) 2212 } 2213 apLogs = append(apLogs, configs.AppProtectLog{ 2214 LogConf: logConf, 2215 Dest: logDsts[i], 2216 }) 2217 } 2218 2219 return apLogs, nil 2220 } 2221 2222 func (lbc *LoadBalancerController) getAppProtectPolicy(ing *networking.Ingress) (apPolicy *unstructured.Unstructured, err error) { 2223 polNsN := appprotect.ParseResourceReferenceAnnotation(ing.Namespace, ing.Annotations[configs.AppProtectPolicyAnnotation]) 2224 2225 apPolicy, err = lbc.appProtectConfiguration.GetAppResource(appprotect.PolicyGVK.Kind, polNsN) 2226 if err != nil { 2227 return nil, fmt.Errorf("Error retrieving App Protect Policy for Ingress %v: %w", ing.Name, err) 2228 } 2229 2230 return apPolicy, nil 2231 } 2232 2233 func (lbc *LoadBalancerController) createVirtualServerEx(virtualServer *conf_v1.VirtualServer, virtualServerRoutes []*conf_v1.VirtualServerRoute) *configs.VirtualServerEx { 2234 virtualServerEx := configs.VirtualServerEx{ 2235 VirtualServer: virtualServer, 2236 SecretRefs: make(map[string]*secrets.SecretReference), 2237 ApPolRefs: make(map[string]*unstructured.Unstructured), 2238 LogConfRefs: make(map[string]*unstructured.Unstructured), 2239 } 2240 2241 if virtualServer.Spec.TLS != nil && virtualServer.Spec.TLS.Secret != "" { 2242 secretKey := virtualServer.Namespace + "/" + virtualServer.Spec.TLS.Secret 2243 2244 secretRef := lbc.secretStore.GetSecret(secretKey) 2245 if secretRef.Error != nil { 2246 glog.Warningf("Error trying to get the secret %v for VirtualServer %v: %v", secretKey, virtualServer.Name, secretRef.Error) 2247 } 2248 2249 virtualServerEx.SecretRefs[secretKey] = secretRef 2250 } 2251 2252 policies, policyErrors := lbc.getPolicies(virtualServer.Spec.Policies, virtualServer.Namespace) 2253 for _, err := range policyErrors { 2254 glog.Warningf("Error getting policy for VirtualServer %s/%s: %v", virtualServer.Namespace, virtualServer.Name, err) 2255 } 2256 2257 err := lbc.addJWTSecretRefs(virtualServerEx.SecretRefs, policies) 2258 if err != nil { 2259 glog.Warningf("Error getting JWT secrets for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2260 } 2261 err = lbc.addIngressMTLSSecretRefs(virtualServerEx.SecretRefs, policies) 2262 if err != nil { 2263 glog.Warningf("Error getting IngressMTLS secret for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2264 } 2265 err = lbc.addEgressMTLSSecretRefs(virtualServerEx.SecretRefs, policies) 2266 if err != nil { 2267 glog.Warningf("Error getting EgressMTLS secrets for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2268 } 2269 err = lbc.addOIDCSecretRefs(virtualServerEx.SecretRefs, policies) 2270 if err != nil { 2271 glog.Warningf("Error getting OIDC secrets for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2272 } 2273 2274 err = lbc.addWAFPolicyRefs(virtualServerEx.ApPolRefs, virtualServerEx.LogConfRefs, policies) 2275 if err != nil { 2276 glog.Warningf("Error getting App Protect resource for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2277 } 2278 2279 endpoints := make(map[string][]string) 2280 externalNameSvcs := make(map[string]bool) 2281 podsByIP := make(map[string]configs.PodInfo) 2282 2283 for _, u := range virtualServer.Spec.Upstreams { 2284 endpointsKey := configs.GenerateEndpointsKey(virtualServer.Namespace, u.Service, u.Subselector, u.Port) 2285 2286 var endps []string 2287 if u.UseClusterIP { 2288 s, err := lbc.getServiceForUpstream(virtualServer.Namespace, u.Service, u.Port) 2289 if err != nil { 2290 glog.Warningf("Error getting Service for Upstream %v: %v", u.Service, err) 2291 } else { 2292 endps = append(endps, fmt.Sprintf("%s:%d", s.Spec.ClusterIP, u.Port)) 2293 } 2294 2295 } else { 2296 var podEndps []podEndpoint 2297 var err error 2298 2299 if len(u.Subselector) > 0 { 2300 podEndps, err = lbc.getEndpointsForSubselector(virtualServer.Namespace, u) 2301 } else { 2302 var external bool 2303 podEndps, external, err = lbc.getEndpointsForUpstream(virtualServer.Namespace, u.Service, u.Port) 2304 2305 if err == nil && external && lbc.isNginxPlus { 2306 externalNameSvcs[configs.GenerateExternalNameSvcKey(virtualServer.Namespace, u.Service)] = true 2307 } 2308 } 2309 2310 if err != nil { 2311 glog.Warningf("Error getting Endpoints for Upstream %v: %v", u.Name, err) 2312 } 2313 2314 endps = getIPAddressesFromEndpoints(podEndps) 2315 2316 if (lbc.isNginxPlus && lbc.isPrometheusEnabled) || lbc.isLatencyMetricsEnabled { 2317 for _, endpoint := range podEndps { 2318 podsByIP[endpoint.Address] = configs.PodInfo{ 2319 Name: endpoint.PodName, 2320 MeshPodOwner: endpoint.MeshPodOwner, 2321 } 2322 } 2323 } 2324 } 2325 2326 endpoints[endpointsKey] = endps 2327 2328 } 2329 2330 for _, r := range virtualServer.Spec.Routes { 2331 vsRoutePolicies, policyErrors := lbc.getPolicies(r.Policies, virtualServer.Namespace) 2332 for _, err := range policyErrors { 2333 glog.Warningf("Error getting policy for VirtualServer %s/%s: %v", virtualServer.Namespace, virtualServer.Name, err) 2334 } 2335 policies = append(policies, vsRoutePolicies...) 2336 2337 err = lbc.addJWTSecretRefs(virtualServerEx.SecretRefs, vsRoutePolicies) 2338 if err != nil { 2339 glog.Warningf("Error getting JWT secrets for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2340 } 2341 err = lbc.addEgressMTLSSecretRefs(virtualServerEx.SecretRefs, vsRoutePolicies) 2342 if err != nil { 2343 glog.Warningf("Error getting EgressMTLS secrets for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2344 } 2345 2346 err = lbc.addWAFPolicyRefs(virtualServerEx.ApPolRefs, virtualServerEx.LogConfRefs, vsRoutePolicies) 2347 if err != nil { 2348 glog.Warningf("Error getting WAF policies for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2349 } 2350 err = lbc.addOIDCSecretRefs(virtualServerEx.SecretRefs, vsRoutePolicies) 2351 if err != nil { 2352 glog.Warningf("Error getting OIDC secrets for VirtualServer %v/%v: %v", virtualServer.Namespace, virtualServer.Name, err) 2353 } 2354 } 2355 2356 for _, vsr := range virtualServerRoutes { 2357 for _, sr := range vsr.Spec.Subroutes { 2358 vsrSubroutePolicies, policyErrors := lbc.getPolicies(sr.Policies, vsr.Namespace) 2359 for _, err := range policyErrors { 2360 glog.Warningf("Error getting policy for VirtualServerRoute %s/%s: %v", vsr.Namespace, vsr.Name, err) 2361 } 2362 policies = append(policies, vsrSubroutePolicies...) 2363 2364 err = lbc.addJWTSecretRefs(virtualServerEx.SecretRefs, vsrSubroutePolicies) 2365 if err != nil { 2366 glog.Warningf("Error getting JWT secrets for VirtualServerRoute %v/%v: %v", vsr.Namespace, vsr.Name, err) 2367 } 2368 2369 err = lbc.addEgressMTLSSecretRefs(virtualServerEx.SecretRefs, vsrSubroutePolicies) 2370 if err != nil { 2371 glog.Warningf("Error getting EgressMTLS secrets for VirtualServerRoute %v/%v: %v", vsr.Namespace, vsr.Name, err) 2372 } 2373 2374 err = lbc.addOIDCSecretRefs(virtualServerEx.SecretRefs, vsrSubroutePolicies) 2375 if err != nil { 2376 glog.Warningf("Error getting OIDC secrets for VirtualServerRoute %v/%v: %v", vsr.Namespace, vsr.Name, err) 2377 } 2378 2379 err = lbc.addWAFPolicyRefs(virtualServerEx.ApPolRefs, virtualServerEx.LogConfRefs, vsrSubroutePolicies) 2380 if err != nil { 2381 glog.Warningf("Error getting WAF policies for VirtualServerRoute %v/%v: %v", vsr.Namespace, vsr.Name, err) 2382 } 2383 } 2384 2385 for _, u := range vsr.Spec.Upstreams { 2386 endpointsKey := configs.GenerateEndpointsKey(vsr.Namespace, u.Service, u.Subselector, u.Port) 2387 2388 var endps []string 2389 if u.UseClusterIP { 2390 s, err := lbc.getServiceForUpstream(vsr.Namespace, u.Service, u.Port) 2391 if err != nil { 2392 glog.Warningf("Error getting Service for Upstream %v: %v", u.Service, err) 2393 } else { 2394 endps = append(endps, fmt.Sprintf("%s:%d", s.Spec.ClusterIP, u.Port)) 2395 } 2396 2397 } else { 2398 var podEndps []podEndpoint 2399 var err error 2400 if len(u.Subselector) > 0 { 2401 podEndps, err = lbc.getEndpointsForSubselector(vsr.Namespace, u) 2402 } else { 2403 var external bool 2404 podEndps, external, err = lbc.getEndpointsForUpstream(vsr.Namespace, u.Service, u.Port) 2405 2406 if err == nil && external && lbc.isNginxPlus { 2407 externalNameSvcs[configs.GenerateExternalNameSvcKey(vsr.Namespace, u.Service)] = true 2408 } 2409 } 2410 if err != nil { 2411 glog.Warningf("Error getting Endpoints for Upstream %v: %v", u.Name, err) 2412 } 2413 2414 endps = getIPAddressesFromEndpoints(podEndps) 2415 2416 if lbc.isNginxPlus || lbc.isLatencyMetricsEnabled { 2417 for _, endpoint := range podEndps { 2418 podsByIP[endpoint.Address] = configs.PodInfo{ 2419 Name: endpoint.PodName, 2420 MeshPodOwner: endpoint.MeshPodOwner, 2421 } 2422 } 2423 } 2424 } 2425 endpoints[endpointsKey] = endps 2426 } 2427 } 2428 2429 virtualServerEx.Endpoints = endpoints 2430 virtualServerEx.VirtualServerRoutes = virtualServerRoutes 2431 virtualServerEx.ExternalNameSvcs = externalNameSvcs 2432 virtualServerEx.Policies = createPolicyMap(policies) 2433 virtualServerEx.PodsByIP = podsByIP 2434 2435 return &virtualServerEx 2436 } 2437 2438 func createPolicyMap(policies []*conf_v1.Policy) map[string]*conf_v1.Policy { 2439 result := make(map[string]*conf_v1.Policy) 2440 2441 for _, p := range policies { 2442 key := fmt.Sprintf("%s/%s", p.Namespace, p.Name) 2443 result[key] = p 2444 } 2445 2446 return result 2447 } 2448 2449 func (lbc *LoadBalancerController) getAllPolicies() []*conf_v1.Policy { 2450 var policies []*conf_v1.Policy 2451 2452 for _, obj := range lbc.policyLister.List() { 2453 pol := obj.(*conf_v1.Policy) 2454 2455 err := validation.ValidatePolicy(pol, lbc.isNginxPlus, lbc.enablePreviewPolicies, lbc.appProtectEnabled) 2456 if err != nil { 2457 glog.V(3).Infof("Skipping invalid Policy %s/%s: %v", pol.Namespace, pol.Name, err) 2458 continue 2459 } 2460 2461 policies = append(policies, pol) 2462 } 2463 2464 return policies 2465 } 2466 2467 func (lbc *LoadBalancerController) getPolicies(policies []conf_v1.PolicyReference, ownerNamespace string) ([]*conf_v1.Policy, []error) { 2468 var result []*conf_v1.Policy 2469 var errors []error 2470 2471 for _, p := range policies { 2472 polNamespace := p.Namespace 2473 if polNamespace == "" { 2474 polNamespace = ownerNamespace 2475 } 2476 2477 policyKey := fmt.Sprintf("%s/%s", polNamespace, p.Name) 2478 2479 policyObj, exists, err := lbc.policyLister.GetByKey(policyKey) 2480 if err != nil { 2481 errors = append(errors, fmt.Errorf("Failed to get policy %s: %w", policyKey, err)) 2482 continue 2483 } 2484 2485 if !exists { 2486 errors = append(errors, fmt.Errorf("Policy %s doesn't exist", policyKey)) 2487 continue 2488 } 2489 2490 policy := policyObj.(*conf_v1.Policy) 2491 2492 err = validation.ValidatePolicy(policy, lbc.isNginxPlus, lbc.enablePreviewPolicies, lbc.appProtectEnabled) 2493 if err != nil { 2494 errors = append(errors, fmt.Errorf("Policy %s is invalid: %w", policyKey, err)) 2495 continue 2496 } 2497 2498 result = append(result, policy) 2499 } 2500 2501 return result, errors 2502 } 2503 2504 func (lbc *LoadBalancerController) addJWTSecretRefs(secretRefs map[string]*secrets.SecretReference, policies []*conf_v1.Policy) error { 2505 for _, pol := range policies { 2506 if pol.Spec.JWTAuth == nil { 2507 continue 2508 } 2509 2510 secretKey := fmt.Sprintf("%v/%v", pol.Namespace, pol.Spec.JWTAuth.Secret) 2511 secretRef := lbc.secretStore.GetSecret(secretKey) 2512 2513 secretRefs[secretKey] = secretRef 2514 2515 if secretRef.Error != nil { 2516 return secretRef.Error 2517 } 2518 } 2519 2520 return nil 2521 } 2522 2523 func (lbc *LoadBalancerController) addIngressMTLSSecretRefs(secretRefs map[string]*secrets.SecretReference, policies []*conf_v1.Policy) error { 2524 for _, pol := range policies { 2525 if pol.Spec.IngressMTLS == nil { 2526 continue 2527 } 2528 2529 secretKey := fmt.Sprintf("%v/%v", pol.Namespace, pol.Spec.IngressMTLS.ClientCertSecret) 2530 secretRef := lbc.secretStore.GetSecret(secretKey) 2531 2532 secretRefs[secretKey] = secretRef 2533 2534 return secretRef.Error 2535 } 2536 2537 return nil 2538 } 2539 2540 func (lbc *LoadBalancerController) addEgressMTLSSecretRefs(secretRefs map[string]*secrets.SecretReference, policies []*conf_v1.Policy) error { 2541 for _, pol := range policies { 2542 if pol.Spec.EgressMTLS == nil { 2543 continue 2544 } 2545 if pol.Spec.EgressMTLS.TLSSecret != "" { 2546 secretKey := fmt.Sprintf("%v/%v", pol.Namespace, pol.Spec.EgressMTLS.TLSSecret) 2547 secretRef := lbc.secretStore.GetSecret(secretKey) 2548 2549 secretRefs[secretKey] = secretRef 2550 2551 if secretRef.Error != nil { 2552 return secretRef.Error 2553 } 2554 } 2555 if pol.Spec.EgressMTLS.TrustedCertSecret != "" { 2556 secretKey := fmt.Sprintf("%v/%v", pol.Namespace, pol.Spec.EgressMTLS.TrustedCertSecret) 2557 secretRef := lbc.secretStore.GetSecret(secretKey) 2558 2559 secretRefs[secretKey] = secretRef 2560 2561 if secretRef.Error != nil { 2562 return secretRef.Error 2563 } 2564 } 2565 } 2566 2567 return nil 2568 } 2569 2570 func (lbc *LoadBalancerController) addOIDCSecretRefs(secretRefs map[string]*secrets.SecretReference, policies []*conf_v1.Policy) error { 2571 for _, pol := range policies { 2572 if pol.Spec.OIDC == nil { 2573 continue 2574 } 2575 2576 secretKey := fmt.Sprintf("%v/%v", pol.Namespace, pol.Spec.OIDC.ClientSecret) 2577 secretRef := lbc.secretStore.GetSecret(secretKey) 2578 2579 secretRefs[secretKey] = secretRef 2580 2581 if secretRef.Error != nil { 2582 return secretRef.Error 2583 } 2584 } 2585 return nil 2586 } 2587 2588 // addWAFPolicyRefs ensures the app protect resources that are referenced in policies exist. 2589 func (lbc *LoadBalancerController) addWAFPolicyRefs( 2590 apPolRef, logConfRef map[string]*unstructured.Unstructured, 2591 policies []*conf_v1.Policy, 2592 ) error { 2593 for _, pol := range policies { 2594 if pol.Spec.WAF == nil { 2595 continue 2596 } 2597 2598 if pol.Spec.WAF.ApPolicy != "" { 2599 apPolKey := pol.Spec.WAF.ApPolicy 2600 if !strings.Contains(pol.Spec.WAF.ApPolicy, "/") { 2601 apPolKey = fmt.Sprintf("%v/%v", pol.Namespace, apPolKey) 2602 } 2603 2604 apPolicy, err := lbc.appProtectConfiguration.GetAppResource(appprotect.PolicyGVK.Kind, apPolKey) 2605 if err != nil { 2606 return fmt.Errorf("WAF policy %q is invalid: %w", apPolKey, err) 2607 } 2608 apPolRef[apPolKey] = apPolicy 2609 } 2610 2611 if pol.Spec.WAF.SecurityLog != nil && pol.Spec.WAF.SecurityLog.ApLogConf != "" { 2612 logConfKey := pol.Spec.WAF.SecurityLog.ApLogConf 2613 if !strings.Contains(pol.Spec.WAF.SecurityLog.ApLogConf, "/") { 2614 logConfKey = fmt.Sprintf("%v/%v", pol.Namespace, logConfKey) 2615 } 2616 2617 logConf, err := lbc.appProtectConfiguration.GetAppResource(appprotect.LogConfGVK.Kind, logConfKey) 2618 if err != nil { 2619 return fmt.Errorf("WAF policy %q is invalid: %w", logConfKey, err) 2620 } 2621 logConfRef[logConfKey] = logConf 2622 } 2623 2624 } 2625 return nil 2626 } 2627 2628 func (lbc *LoadBalancerController) getPoliciesForSecret(secretNamespace string, secretName string) []*conf_v1.Policy { 2629 return findPoliciesForSecret(lbc.getAllPolicies(), secretNamespace, secretName) 2630 } 2631 2632 func findPoliciesForSecret(policies []*conf_v1.Policy, secretNamespace string, secretName string) []*conf_v1.Policy { 2633 var res []*conf_v1.Policy 2634 2635 for _, pol := range policies { 2636 if pol.Spec.IngressMTLS != nil && pol.Spec.IngressMTLS.ClientCertSecret == secretName && pol.Namespace == secretNamespace { 2637 res = append(res, pol) 2638 } else if pol.Spec.JWTAuth != nil && pol.Spec.JWTAuth.Secret == secretName && pol.Namespace == secretNamespace { 2639 res = append(res, pol) 2640 } else if pol.Spec.EgressMTLS != nil && pol.Spec.EgressMTLS.TLSSecret == secretName && pol.Namespace == secretNamespace { 2641 res = append(res, pol) 2642 } else if pol.Spec.EgressMTLS != nil && pol.Spec.EgressMTLS.TrustedCertSecret == secretName && pol.Namespace == secretNamespace { 2643 res = append(res, pol) 2644 } else if pol.Spec.OIDC != nil && pol.Spec.OIDC.ClientSecret == secretName && pol.Namespace == secretNamespace { 2645 res = append(res, pol) 2646 } 2647 } 2648 2649 return res 2650 } 2651 2652 func getWAFPoliciesForAppProtectPolicy(pols []*conf_v1.Policy, key string) []*conf_v1.Policy { 2653 var policies []*conf_v1.Policy 2654 2655 for _, pol := range pols { 2656 if pol.Spec.WAF != nil && isMatchingResourceRef(pol.Namespace, pol.Spec.WAF.ApPolicy, key) { 2657 policies = append(policies, pol) 2658 } 2659 } 2660 2661 return policies 2662 } 2663 2664 func getWAFPoliciesForAppProtectLogConf(pols []*conf_v1.Policy, key string) []*conf_v1.Policy { 2665 var policies []*conf_v1.Policy 2666 2667 for _, pol := range pols { 2668 if pol.Spec.WAF != nil && pol.Spec.WAF.SecurityLog != nil && isMatchingResourceRef(pol.Namespace, pol.Spec.WAF.SecurityLog.ApLogConf, key) { 2669 policies = append(policies, pol) 2670 } 2671 } 2672 2673 return policies 2674 } 2675 2676 func isMatchingResourceRef(ownerNs, resRef, key string) bool { 2677 hasNamespace := strings.Contains(resRef, "/") 2678 if !hasNamespace { 2679 resRef = fmt.Sprintf("%v/%v", ownerNs, resRef) 2680 } 2681 return resRef == key 2682 } 2683 2684 func (lbc *LoadBalancerController) createTransportServerEx(transportServer *conf_v1alpha1.TransportServer, listenerPort int) *configs.TransportServerEx { 2685 endpoints := make(map[string][]string) 2686 podsByIP := make(map[string]string) 2687 2688 for _, u := range transportServer.Spec.Upstreams { 2689 podEndps, external, err := lbc.getEndpointsForUpstream(transportServer.Namespace, u.Service, uint16(u.Port)) 2690 if err != nil { 2691 glog.Warningf("Error getting Endpoints for Upstream %v: %v", u.Name, err) 2692 } 2693 2694 if external { 2695 glog.Warningf("ExternalName services are not yet supported in TransportServer upstreams") 2696 } 2697 2698 // subselector is not supported yet in TransportServer upstreams. That's why we pass "nil" here 2699 endpointsKey := configs.GenerateEndpointsKey(transportServer.Namespace, u.Service, nil, uint16(u.Port)) 2700 2701 endps := getIPAddressesFromEndpoints(podEndps) 2702 endpoints[endpointsKey] = endps 2703 2704 if lbc.isNginxPlus && lbc.isPrometheusEnabled { 2705 for _, endpoint := range podEndps { 2706 podsByIP[endpoint.Address] = endpoint.PodName 2707 } 2708 } 2709 } 2710 2711 return &configs.TransportServerEx{ 2712 ListenerPort: listenerPort, 2713 TransportServer: transportServer, 2714 Endpoints: endpoints, 2715 PodsByIP: podsByIP, 2716 } 2717 } 2718 2719 func (lbc *LoadBalancerController) getEndpointsForUpstream(namespace string, upstreamService string, upstreamPort uint16) (endps []podEndpoint, isExternal bool, err error) { 2720 svc, err := lbc.getServiceForUpstream(namespace, upstreamService, upstreamPort) 2721 if err != nil { 2722 return nil, false, fmt.Errorf("Error getting service %v: %w", upstreamService, err) 2723 } 2724 2725 backend := &networking.IngressBackend{ 2726 ServiceName: upstreamService, 2727 ServicePort: intstr.FromInt(int(upstreamPort)), 2728 } 2729 2730 endps, isExternal, err = lbc.getEndpointsForIngressBackend(backend, svc) 2731 if err != nil { 2732 return nil, false, fmt.Errorf("Error retrieving endpoints for the service %v: %w", upstreamService, err) 2733 } 2734 2735 return endps, isExternal, err 2736 } 2737 2738 func (lbc *LoadBalancerController) getEndpointsForSubselector(namespace string, upstream conf_v1.Upstream) (endps []podEndpoint, err error) { 2739 svc, err := lbc.getServiceForUpstream(namespace, upstream.Service, upstream.Port) 2740 if err != nil { 2741 return nil, fmt.Errorf("Error getting service %v: %w", upstream.Service, err) 2742 } 2743 2744 var targetPort int32 2745 2746 for _, port := range svc.Spec.Ports { 2747 if port.Port == int32(upstream.Port) { 2748 targetPort, err = lbc.getTargetPort(port, svc) 2749 if err != nil { 2750 return nil, fmt.Errorf("Error determining target port for port %v in service %v: %w", upstream.Port, svc.Name, err) 2751 } 2752 break 2753 } 2754 } 2755 2756 if targetPort == 0 { 2757 return nil, fmt.Errorf("No port %v in service %s", upstream.Port, svc.Name) 2758 } 2759 2760 endps, err = lbc.getEndpointsForServiceWithSubselector(targetPort, upstream.Subselector, svc) 2761 if err != nil { 2762 return nil, fmt.Errorf("Error retrieving endpoints for the service %v: %w", upstream.Service, err) 2763 } 2764 2765 return endps, err 2766 } 2767 2768 func (lbc *LoadBalancerController) getEndpointsForServiceWithSubselector(targetPort int32, subselector map[string]string, svc *api_v1.Service) (endps []podEndpoint, err error) { 2769 pods, err := lbc.podLister.ListByNamespace(svc.Namespace, labels.Merge(svc.Spec.Selector, subselector).AsSelector()) 2770 if err != nil { 2771 return nil, fmt.Errorf("Error getting pods in namespace %v that match the selector %v: %w", svc.Namespace, labels.Merge(svc.Spec.Selector, subselector), err) 2772 } 2773 2774 svcEps, err := lbc.endpointLister.GetServiceEndpoints(svc) 2775 if err != nil { 2776 glog.V(3).Infof("Error getting endpoints for service %s from the cache: %v", svc.Name, err) 2777 return nil, err 2778 } 2779 2780 endps = getEndpointsBySubselectedPods(targetPort, pods, svcEps) 2781 return endps, nil 2782 } 2783 2784 func getEndpointsBySubselectedPods(targetPort int32, pods []*api_v1.Pod, svcEps api_v1.Endpoints) (endps []podEndpoint) { 2785 for _, pod := range pods { 2786 for _, subset := range svcEps.Subsets { 2787 for _, port := range subset.Ports { 2788 if port.Port != targetPort { 2789 continue 2790 } 2791 for _, address := range subset.Addresses { 2792 if address.IP == pod.Status.PodIP { 2793 addr := fmt.Sprintf("%v:%v", pod.Status.PodIP, targetPort) 2794 ownerType, ownerName := getPodOwnerTypeAndName(pod) 2795 podEnd := podEndpoint{ 2796 Address: addr, 2797 PodName: getPodName(address.TargetRef), 2798 MeshPodOwner: configs.MeshPodOwner{ 2799 OwnerType: ownerType, 2800 OwnerName: ownerName, 2801 }, 2802 } 2803 endps = append(endps, podEnd) 2804 } 2805 } 2806 } 2807 } 2808 } 2809 return endps 2810 } 2811 2812 func getPodName(pod *api_v1.ObjectReference) string { 2813 if pod != nil { 2814 return pod.Name 2815 } 2816 return "" 2817 } 2818 2819 func (lbc *LoadBalancerController) getHealthChecksForIngressBackend(backend *networking.IngressBackend, namespace string) *api_v1.Probe { 2820 svc, err := lbc.getServiceForIngressBackend(backend, namespace) 2821 if err != nil { 2822 glog.V(3).Infof("Error getting service %v: %v", backend.ServiceName, err) 2823 return nil 2824 } 2825 svcPort := lbc.getServicePortForIngressPort(backend.ServicePort, svc) 2826 if svcPort == nil { 2827 return nil 2828 } 2829 pods, err := lbc.podLister.ListByNamespace(svc.Namespace, labels.Set(svc.Spec.Selector).AsSelector()) 2830 if err != nil { 2831 glog.V(3).Infof("Error fetching pods for namespace %v: %v", svc.Namespace, err) 2832 return nil 2833 } 2834 return findProbeForPods(pods, svcPort) 2835 } 2836 2837 func findProbeForPods(pods []*api_v1.Pod, svcPort *api_v1.ServicePort) *api_v1.Probe { 2838 if len(pods) > 0 { 2839 pod := pods[0] 2840 for _, container := range pod.Spec.Containers { 2841 for _, port := range container.Ports { 2842 if compareContainerPortAndServicePort(port, *svcPort) { 2843 // only http ReadinessProbes are useful for us 2844 if container.ReadinessProbe != nil && container.ReadinessProbe.ProbeHandler.HTTPGet != nil && container.ReadinessProbe.PeriodSeconds > 0 { 2845 return container.ReadinessProbe 2846 } 2847 } 2848 } 2849 } 2850 } 2851 return nil 2852 } 2853 2854 func compareContainerPortAndServicePort(containerPort api_v1.ContainerPort, svcPort api_v1.ServicePort) bool { 2855 targetPort := svcPort.TargetPort 2856 if (targetPort == intstr.IntOrString{}) { 2857 return svcPort.Port > 0 && svcPort.Port == containerPort.ContainerPort 2858 } 2859 switch targetPort.Type { 2860 case intstr.String: 2861 return targetPort.StrVal == containerPort.Name && svcPort.Protocol == containerPort.Protocol 2862 case intstr.Int: 2863 return targetPort.IntVal > 0 && targetPort.IntVal == containerPort.ContainerPort 2864 } 2865 return false 2866 } 2867 2868 func (lbc *LoadBalancerController) getExternalEndpointsForIngressBackend(backend *networking.IngressBackend, svc *api_v1.Service) []podEndpoint { 2869 address := fmt.Sprintf("%s:%d", svc.Spec.ExternalName, int32(backend.ServicePort.IntValue())) 2870 endpoints := []podEndpoint{ 2871 { 2872 Address: address, 2873 PodName: "", 2874 }, 2875 } 2876 return endpoints 2877 } 2878 2879 func (lbc *LoadBalancerController) getEndpointsForIngressBackend(backend *networking.IngressBackend, svc *api_v1.Service) (result []podEndpoint, isExternal bool, err error) { 2880 endps, err := lbc.endpointLister.GetServiceEndpoints(svc) 2881 if err != nil { 2882 if svc.Spec.Type == api_v1.ServiceTypeExternalName { 2883 if !lbc.isNginxPlus { 2884 return nil, false, fmt.Errorf("Type ExternalName Services feature is only available in NGINX Plus") 2885 } 2886 result = lbc.getExternalEndpointsForIngressBackend(backend, svc) 2887 return result, true, nil 2888 } 2889 glog.V(3).Infof("Error getting endpoints for service %s from the cache: %v", svc.Name, err) 2890 return nil, false, err 2891 } 2892 2893 result, err = lbc.getEndpointsForPort(endps, backend.ServicePort, svc) 2894 if err != nil { 2895 glog.V(3).Infof("Error getting endpoints for service %s port %v: %v", svc.Name, backend.ServicePort, err) 2896 return nil, false, err 2897 } 2898 return result, false, nil 2899 } 2900 2901 func (lbc *LoadBalancerController) getEndpointsForPort(endps api_v1.Endpoints, ingSvcPort intstr.IntOrString, svc *api_v1.Service) ([]podEndpoint, error) { 2902 var targetPort int32 2903 var err error 2904 2905 for _, port := range svc.Spec.Ports { 2906 if (ingSvcPort.Type == intstr.Int && port.Port == int32(ingSvcPort.IntValue())) || (ingSvcPort.Type == intstr.String && port.Name == ingSvcPort.String()) { 2907 targetPort, err = lbc.getTargetPort(port, svc) 2908 if err != nil { 2909 return nil, fmt.Errorf("Error determining target port for port %v in Ingress: %w", ingSvcPort, err) 2910 } 2911 break 2912 } 2913 } 2914 2915 if targetPort == 0 { 2916 return nil, fmt.Errorf("No port %v in service %s", ingSvcPort, svc.Name) 2917 } 2918 2919 for _, subset := range endps.Subsets { 2920 for _, port := range subset.Ports { 2921 if port.Port == targetPort { 2922 var endpoints []podEndpoint 2923 for _, address := range subset.Addresses { 2924 addr := fmt.Sprintf("%v:%v", address.IP, port.Port) 2925 podEnd := podEndpoint{ 2926 Address: addr, 2927 } 2928 if address.TargetRef != nil { 2929 parentType, parentName := lbc.getPodOwnerTypeAndNameFromAddress(address.TargetRef.Namespace, address.TargetRef.Name) 2930 podEnd.OwnerType = parentType 2931 podEnd.OwnerName = parentName 2932 podEnd.PodName = address.TargetRef.Name 2933 } 2934 endpoints = append(endpoints, podEnd) 2935 } 2936 return endpoints, nil 2937 } 2938 } 2939 } 2940 2941 return nil, fmt.Errorf("No endpoints for target port %v in service %s", targetPort, svc.Name) 2942 } 2943 2944 func (lbc *LoadBalancerController) getPodOwnerTypeAndNameFromAddress(ns, name string) (parentType, parentName string) { 2945 obj, exists, err := lbc.podLister.GetByKey(fmt.Sprintf("%s/%s", ns, name)) 2946 if err != nil { 2947 glog.Warningf("could not get pod by key %s/%s: %v", ns, name, err) 2948 return "", "" 2949 } 2950 if exists { 2951 pod := obj.(*api_v1.Pod) 2952 return getPodOwnerTypeAndName(pod) 2953 } 2954 return "", "" 2955 } 2956 2957 func getPodOwnerTypeAndName(pod *api_v1.Pod) (parentType, parentName string) { 2958 parentType = "deployment" 2959 for _, owner := range pod.GetOwnerReferences() { 2960 parentName = owner.Name 2961 if owner.Controller != nil && *owner.Controller { 2962 if owner.Kind == "StatefulSet" || owner.Kind == "DaemonSet" { 2963 parentType = strings.ToLower(owner.Kind) 2964 } 2965 if owner.Kind == "ReplicaSet" && strings.HasSuffix(owner.Name, pod.Labels["pod-template-hash"]) { 2966 parentName = strings.TrimSuffix(owner.Name, "-"+pod.Labels["pod-template-hash"]) 2967 } 2968 } 2969 } 2970 return parentType, parentName 2971 } 2972 2973 func (lbc *LoadBalancerController) getServicePortForIngressPort(ingSvcPort intstr.IntOrString, svc *api_v1.Service) *api_v1.ServicePort { 2974 for _, port := range svc.Spec.Ports { 2975 if (ingSvcPort.Type == intstr.Int && port.Port == int32(ingSvcPort.IntValue())) || (ingSvcPort.Type == intstr.String && port.Name == ingSvcPort.String()) { 2976 return &port 2977 } 2978 } 2979 return nil 2980 } 2981 2982 func (lbc *LoadBalancerController) getTargetPort(svcPort api_v1.ServicePort, svc *api_v1.Service) (int32, error) { 2983 if (svcPort.TargetPort == intstr.IntOrString{}) { 2984 return svcPort.Port, nil 2985 } 2986 2987 if svcPort.TargetPort.Type == intstr.Int { 2988 return int32(svcPort.TargetPort.IntValue()), nil 2989 } 2990 2991 pods, err := lbc.podLister.ListByNamespace(svc.Namespace, labels.Set(svc.Spec.Selector).AsSelector()) 2992 if err != nil { 2993 return 0, fmt.Errorf("Error getting pod information: %w", err) 2994 } 2995 2996 if len(pods) == 0 { 2997 return 0, fmt.Errorf("No pods of service %s", svc.Name) 2998 } 2999 3000 pod := pods[0] 3001 3002 portNum, err := findPort(pod, svcPort) 3003 if err != nil { 3004 return 0, fmt.Errorf("Error finding named port %v in pod %s: %w", svcPort, pod.Name, err) 3005 } 3006 3007 return portNum, nil 3008 } 3009 3010 func (lbc *LoadBalancerController) getServiceForUpstream(namespace string, upstreamService string, upstreamPort uint16) (*api_v1.Service, error) { 3011 backend := &networking.IngressBackend{ 3012 ServiceName: upstreamService, 3013 ServicePort: intstr.FromInt(int(upstreamPort)), 3014 } 3015 return lbc.getServiceForIngressBackend(backend, namespace) 3016 } 3017 3018 func (lbc *LoadBalancerController) getServiceForIngressBackend(backend *networking.IngressBackend, namespace string) (*api_v1.Service, error) { 3019 svcKey := namespace + "/" + backend.ServiceName 3020 svcObj, svcExists, err := lbc.svcLister.GetByKey(svcKey) 3021 if err != nil { 3022 return nil, err 3023 } 3024 3025 if svcExists { 3026 return svcObj.(*api_v1.Service), nil 3027 } 3028 3029 return nil, fmt.Errorf("service %s doesn't exist", svcKey) 3030 } 3031 3032 // HasCorrectIngressClass checks if resource ingress class annotation (if exists) or ingressClass string for VS/VSR is matching with ingress controller class 3033 func (lbc *LoadBalancerController) HasCorrectIngressClass(obj interface{}) bool { 3034 var class string 3035 var isIngress bool 3036 switch obj := obj.(type) { 3037 case *conf_v1.VirtualServer: 3038 class = obj.Spec.IngressClass 3039 case *conf_v1.VirtualServerRoute: 3040 class = obj.Spec.IngressClass 3041 case *conf_v1alpha1.TransportServer: 3042 class = obj.Spec.IngressClass 3043 case *networking.Ingress: 3044 isIngress = true 3045 class = obj.Annotations[ingressClassKey] 3046 if class == "" && obj.Spec.IngressClassName != nil { 3047 class = *obj.Spec.IngressClassName 3048 } else { 3049 // the annotation takes precedence over the field 3050 glog.Warningln("Using the DEPRECATED annotation 'kubernetes.io/ingress.class'. The 'ingressClassName' field will be ignored.") 3051 } 3052 3053 default: 3054 return false 3055 } 3056 3057 // useIngressClassOnly only applies for Ingress resources 3058 if lbc.useIngressClassOnly && isIngress { 3059 return class == lbc.ingressClass 3060 } 3061 return class == lbc.ingressClass || class == "" 3062 } 3063 3064 // isHealthCheckEnabled checks if health checks are enabled so we can only query pods if enabled. 3065 func (lbc *LoadBalancerController) isHealthCheckEnabled(ing *networking.Ingress) bool { 3066 if healthCheckEnabled, exists, err := configs.GetMapKeyAsBool(ing.Annotations, "nginx.com/health-checks", ing); exists { 3067 if err != nil { 3068 glog.Error(err) 3069 } 3070 return healthCheckEnabled 3071 } 3072 return false 3073 } 3074 3075 func formatWarningMessages(w []string) string { 3076 return strings.Join(w, "; ") 3077 } 3078 3079 func (lbc *LoadBalancerController) syncSVIDRotation(svidResponse *workload.X509SVIDs) { 3080 lbc.syncLock.Lock() 3081 defer lbc.syncLock.Unlock() 3082 glog.V(3).Info("Rotating SPIFFE Certificates") 3083 err := lbc.configurator.AddOrUpdateSpiffeCerts(svidResponse) 3084 if err != nil { 3085 glog.Errorf("failed to rotate SPIFFE certificates: %v", err) 3086 } 3087 } 3088 3089 func (lbc *LoadBalancerController) syncAppProtectPolicy(task task) { 3090 key := task.Key 3091 glog.V(3).Infof("Syncing AppProtectPolicy %v", key) 3092 obj, polExists, err := lbc.appProtectPolicyLister.GetByKey(key) 3093 if err != nil { 3094 lbc.syncQueue.Requeue(task, err) 3095 return 3096 } 3097 3098 var changes []appprotect.Change 3099 var problems []appprotect.Problem 3100 3101 if !polExists { 3102 glog.V(2).Infof("Deleting AppProtectPolicy: %v\n", key) 3103 3104 changes, problems = lbc.appProtectConfiguration.DeletePolicy(key) 3105 } else { 3106 glog.V(2).Infof("Adding or Updating AppProtectPolicy: %v\n", key) 3107 3108 changes, problems = lbc.appProtectConfiguration.AddOrUpdatePolicy(obj.(*unstructured.Unstructured)) 3109 } 3110 3111 lbc.processAppProtectChanges(changes) 3112 lbc.processAppProtectProblems(problems) 3113 } 3114 3115 func (lbc *LoadBalancerController) syncAppProtectLogConf(task task) { 3116 key := task.Key 3117 glog.V(3).Infof("Syncing AppProtectLogConf %v", key) 3118 obj, confExists, err := lbc.appProtectLogConfLister.GetByKey(key) 3119 if err != nil { 3120 lbc.syncQueue.Requeue(task, err) 3121 return 3122 } 3123 3124 var changes []appprotect.Change 3125 var problems []appprotect.Problem 3126 3127 if !confExists { 3128 glog.V(2).Infof("Deleting AppProtectLogConf: %v\n", key) 3129 3130 changes, problems = lbc.appProtectConfiguration.DeleteLogConf(key) 3131 } else { 3132 glog.V(2).Infof("Adding or Updating AppProtectLogConf: %v\n", key) 3133 3134 changes, problems = lbc.appProtectConfiguration.AddOrUpdateLogConf(obj.(*unstructured.Unstructured)) 3135 } 3136 3137 lbc.processAppProtectChanges(changes) 3138 lbc.processAppProtectProblems(problems) 3139 } 3140 3141 func (lbc *LoadBalancerController) syncAppProtectUserSig(task task) { 3142 key := task.Key 3143 glog.V(3).Infof("Syncing AppProtectUserSig %v", key) 3144 obj, sigExists, err := lbc.appProtectUserSigLister.GetByKey(key) 3145 if err != nil { 3146 lbc.syncQueue.Requeue(task, err) 3147 return 3148 } 3149 3150 var change appprotect.UserSigChange 3151 var problems []appprotect.Problem 3152 3153 if !sigExists { 3154 glog.V(2).Infof("Deleting AppProtectUserSig: %v\n", key) 3155 3156 change, problems = lbc.appProtectConfiguration.DeleteUserSig(key) 3157 } else { 3158 glog.V(2).Infof("Adding or Updating AppProtectUserSig: %v\n", key) 3159 3160 change, problems = lbc.appProtectConfiguration.AddOrUpdateUserSig(obj.(*unstructured.Unstructured)) 3161 } 3162 3163 lbc.processAppProtectUserSigChange(change) 3164 lbc.processAppProtectProblems(problems) 3165 } 3166 3167 // IsNginxReady returns ready status of NGINX 3168 func (lbc *LoadBalancerController) IsNginxReady() bool { 3169 return lbc.isNginxReady 3170 } 3171 3172 func (lbc *LoadBalancerController) addInternalRouteServer() { 3173 if lbc.internalRoutesEnabled { 3174 if err := lbc.configurator.AddInternalRouteConfig(); err != nil { 3175 glog.Warningf("failed to configure internal route server: %v", err) 3176 } 3177 } 3178 }