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  }