diff --git a/cmd/glbc/main.go b/cmd/glbc/main.go index afe328de38..27ca225b2c 100644 --- a/cmd/glbc/main.go +++ b/cmd/glbc/main.go @@ -40,6 +40,7 @@ import ( ingctx "k8s.io/ingress-gce/pkg/context" "k8s.io/ingress-gce/pkg/controller" + "k8s.io/ingress-gce/pkg/metrics" "k8s.io/ingress-gce/pkg/neg" negtypes "k8s.io/ingress-gce/pkg/neg/types" @@ -131,6 +132,9 @@ func main() { } kubeSystemUID := kubeSystemNS.GetUID() + // Initialize ingress usage metrics. + ingresMetrics := metrics.NewIngressMetrics() + cloud := app.NewGCEClient() defaultBackendServicePort := app.DefaultBackendServicePort(kubeClient) ctxConfig := ingctx.ControllerContextConfig{ @@ -144,7 +148,7 @@ func main() { ASMConfigMapNamespace: flags.F.ASMConfigMapBasedConfigNamespace, ASMConfigMapName: flags.F.ASMConfigMapBasedConfigCMName, } - ctx := ingctx.NewControllerContext(kubeConfig, kubeClient, backendConfigClient, frontendConfigClient, cloud, namer, kubeSystemUID, ctxConfig) + ctx := ingctx.NewControllerContext(kubeConfig, kubeClient, backendConfigClient, frontendConfigClient, cloud, namer, kubeSystemUID, ingresMetrics, ctxConfig) go app.RunHTTPServer(ctx.HealthCheck) if !flags.F.LeaderElection.LeaderElect { @@ -229,6 +233,9 @@ func runControllers(ctx *ingctx.ControllerContext) { go fwc.Run() klog.V(0).Infof("firewall controller started") + // Export ingress usage metrics. + go ctx.IngressMetrics.Run(stopCh) + ctx.Start(stopCh) lbc.Init() lbc.Run() diff --git a/pkg/context/context.go b/pkg/context/context.go index 97e4f9e9ea..37275aaee2 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -40,6 +40,7 @@ import ( "k8s.io/ingress-gce/pkg/common/typed" frontendconfigclient "k8s.io/ingress-gce/pkg/frontendconfig/client/clientset/versioned" informerfrontendconfig "k8s.io/ingress-gce/pkg/frontendconfig/client/informers/externalversions/frontendconfig/v1beta1" + "k8s.io/ingress-gce/pkg/metrics" "k8s.io/ingress-gce/pkg/utils" "k8s.io/ingress-gce/pkg/utils/namer" "k8s.io/klog" @@ -75,6 +76,8 @@ type ControllerContext struct { DestinationRuleInformer cache.SharedIndexInformer ConfigMapInformer cache.SharedIndexInformer + IngressMetrics *metrics.IngressMetrics + healthChecks map[string]func() error lock sync.Mutex @@ -106,6 +109,7 @@ func NewControllerContext( cloud *gce.Cloud, namer *namer.Namer, kubeSystemUID types.UID, + ingressMetrics *metrics.IngressMetrics, config ControllerContextConfig) *ControllerContext { context := &ControllerContext{ @@ -114,6 +118,7 @@ func NewControllerContext( Cloud: cloud, ClusterNamer: namer, KubeSystemUID: kubeSystemUID, + IngressMetrics: ingressMetrics, ControllerContextConfig: config, IngressInformer: informerv1beta1.NewIngressInformer(kubeClient, config.Namespace, config.ResyncPeriod, utils.NewNamespaceIndexer()), ServiceInformer: informerv1.NewServiceInformer(kubeClient, config.Namespace, config.ResyncPeriod, utils.NewNamespaceIndexer()), diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 5a2f49c2fe..bdd360699f 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -45,6 +45,7 @@ import ( "k8s.io/ingress-gce/pkg/healthchecks" "k8s.io/ingress-gce/pkg/instances" "k8s.io/ingress-gce/pkg/loadbalancers" + "k8s.io/ingress-gce/pkg/metrics" negtypes "k8s.io/ingress-gce/pkg/neg/types" ingsync "k8s.io/ingress-gce/pkg/sync" "k8s.io/ingress-gce/pkg/tls" @@ -531,6 +532,10 @@ func (lbc *LoadBalancerController) sync(key string) error { if err != nil && ingExists { lbc.ctx.Recorder(ing.Namespace).Eventf(ing, apiv1.EventTypeWarning, "GC", fmt.Sprintf("Error during GC: %v", err)) } + // Delete the ingress state for metrics after GC is successful. + if err == nil && ingExists { + lbc.ctx.IngressMetrics.Delete(key) + } return err } @@ -555,6 +560,9 @@ func (lbc *LoadBalancerController) sync(key string) error { syncErr := lbc.ingSyncer.Sync(syncState) if syncErr != nil { lbc.ctx.Recorder(ing.Namespace).Eventf(ing, apiv1.EventTypeWarning, "Sync", fmt.Sprintf("Error during sync: %v", syncErr.Error())) + } else { + // Insert/update the ingress state for metrics after successful sync. + lbc.ctx.IngressMetrics.Set(key, metrics.NewIngressState(ing, urlMap.AllServicePorts())) } // Garbage collection will occur regardless of an error occurring. If an error occurred, diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index ba5b34cb23..8a7e7225d9 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -42,6 +42,7 @@ import ( "k8s.io/ingress-gce/pkg/flags" "k8s.io/ingress-gce/pkg/instances" "k8s.io/ingress-gce/pkg/loadbalancers" + "k8s.io/ingress-gce/pkg/metrics" "k8s.io/ingress-gce/pkg/test" "k8s.io/ingress-gce/pkg/tls" "k8s.io/ingress-gce/pkg/utils" @@ -72,7 +73,7 @@ func newLoadBalancerController() *LoadBalancerController { HealthCheckPath: "/", DefaultBackendHealthCheckPath: "/healthz", } - ctx := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, fakeGCE, namer, "" /*kubeSystemUID*/, ctxConfig) + ctx := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, fakeGCE, namer, "" /*kubeSystemUID*/, metrics.NewIngressMetrics(), ctxConfig) lbc := NewLoadBalancerController(ctx, stopCh) // TODO(rramkumar): Fix this so we don't have to override with our fake lbc.instancePool = instances.NewNodePool(instances.NewFakeInstanceGroups(sets.NewString(), namer), namer) diff --git a/pkg/controller/translator/translator_test.go b/pkg/controller/translator/translator_test.go index c0310400b4..1449aa3e94 100644 --- a/pkg/controller/translator/translator_test.go +++ b/pkg/controller/translator/translator_test.go @@ -65,7 +65,7 @@ func fakeTranslator() *Translator { HealthCheckPath: "/", DefaultBackendHealthCheckPath: "/healthz", } - ctx := context.NewControllerContext(nil, client, backendConfigClient, nil, nil, defaultNamer, "" /*kubeSystemUID*/, ctxConfig) + ctx := context.NewControllerContext(nil, client, backendConfigClient, nil, nil, defaultNamer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) gce := &Translator{ ctx: ctx, } diff --git a/pkg/firewalls/controller_test.go b/pkg/firewalls/controller_test.go index f2c0524261..761ca8228b 100644 --- a/pkg/firewalls/controller_test.go +++ b/pkg/firewalls/controller_test.go @@ -46,7 +46,7 @@ func newFirewallController() *FirewallController { DefaultBackendSvcPort: test.DefaultBeSvcPort, } - ctx := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, fakeGCE, defaultNamer, "" /*kubeSystemUID*/, ctxConfig) + ctx := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, fakeGCE, defaultNamer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) fwc := NewFirewallController(ctx, []string{"30000-32767"}) fwc.hasSynced = func() bool { return true } diff --git a/pkg/metrics/features.go b/pkg/metrics/features.go new file mode 100644 index 0000000000..d09409a2d2 --- /dev/null +++ b/pkg/metrics/features.go @@ -0,0 +1,219 @@ +package metrics + +import ( + "fmt" + "strconv" + + "k8s.io/api/networking/v1beta1" + "k8s.io/ingress-gce/pkg/utils" + "k8s.io/klog" +) + +type Feature string + +func (f Feature) String() string { + return string(f) +} + +const ( + // allowHTTPKey tells the Ingress controller to allow/block HTTP access. + allowHTTPKey = "kubernetes.io/ingress.allow-http" + ingressClassKey = "kubernetes.io/ingress.class" + gceIngressClass = "gce" + gceMultiIngressClass = "gce-multi-cluster" + gceL7ILBIngressClass = "gce-internal" + // preSharedCertKey represents the specific pre-shared SSL + // certificate for the Ingress controller to use. + preSharedCertKey = "ingress.gcp.kubernetes.io/pre-shared-cert" + managedCertKey = "networking.gke.io/managed-certificates" + // staticIPKey is the annotation key used by controller to record GCP static ip. + staticIPKey = "ingress.kubernetes.io/static-ip" + + ingress = Feature("Ingress") + externalIngress = Feature("ExternalIngress") + internalIngress = Feature("InternalIngress") + httpEnabled = Feature("HTTPEnabled") + hostBasedRouting = Feature("HostBasedRouting") + pathBasedRouting = Feature("PathBasedRouting") + tlsTermination = Feature("TLSTermination") + secretBasedCertsForTLS = Feature("SecretBasedCertsForTLS") + preSharedCertsForTLS = Feature("PreSharedCertsForTLS") + managedCertsForTLS = Feature("ManagedCertsForTLS") + staticGlobalIP = Feature("StaticGlobalIP") + + servicePort = Feature("L7LBServicePort") + externalServicePort = Feature("L7XLBServicePort") + internalServicePort = Feature("L7ILBServicePort") + neg = Feature("NEG") + cloudCDN = Feature("CloudCDN") + cloudArmor = Feature("CloudArmor") + cloudIAP = Feature("CloudIAP") + backendTimeout = Feature("BackendTimeout") + backendConnectionDraining = Feature("BackendConnectionDraining") + clientIPAffinity = Feature("ClientIPAffinity") + cookieAffinity = Feature("CookieAffinity") + customRequestHeaders = Feature("CustomRequestHeaders") +) + +// FeaturesForIngress returns the list of features for given ingress. +func FeaturesForIngress(ing *v1beta1.Ingress) []Feature { + features := []Feature{ingress} + + ingKey := fmt.Sprintf("%s/%s", ing.Namespace, ing.Name) + klog.V(4).Infof("Listing features for Ingress %s", ingKey) + ingAnnotations := ing.Annotations + + // Determine the type of ingress based on ingress class. + ingClass := ingAnnotations[ingressClassKey] + klog.V(6).Infof("Ingress class value for ingress %s: %s", ingKey, ingClass) + switch ingClass { + case "", gceIngressClass, gceMultiIngressClass: + features = append(features, externalIngress) + case gceL7ILBIngressClass: + features = append(features, internalIngress) + } + + // Determine if http is enabled. + if val, ok := ingAnnotations[allowHTTPKey]; !ok { + klog.V(6).Infof("Annotation %s does not exist for ingress %s", allowHTTPKey, ingKey) + features = append(features, httpEnabled) + } else { + klog.V(6).Infof("User specified value for annotation %s on ingress %s: %s", allowHTTPKey, ingKey, val) + v, err := strconv.ParseBool(val) + if err != nil { + klog.Errorf("Failed to parse %s for annotation %s on ingress %s", val, allowHTTPKey, ingKey) + } + if err == nil && v { + features = append(features, httpEnabled) + } + } + + // An ingress without a host or http-path is ignored. + hostBased, pathBased := false, false + if len(ing.Spec.Rules) == 0 { + klog.V(6).Infof("Neither host-based nor path-based routing rules are setup for ingress %s", ingKey) + } + for _, rule := range ing.Spec.Rules { + if rule.HTTP != nil && len(rule.HTTP.Paths) > 0 { + klog.V(6).Infof("User specified http paths for ingress %s: %v", ingKey, rule.HTTP.Paths) + pathBased = true + } + if rule.Host != "" { + klog.V(6).Infof("User specified host for ingress %s: %v", ingKey, rule.Host) + hostBased = true + } + if pathBased && hostBased { + break + } + } + if hostBased { + features = append(features, hostBasedRouting) + } + if pathBased { + features = append(features, pathBasedRouting) + } + + // SSL certificate based features. + sslConfigured := false + if val, ok := ingAnnotations[preSharedCertKey]; ok { + klog.V(6).Infof("Specified pre-shared certs for ingress %s: %v", ingKey, val) + sslConfigured = true + features = append(features, preSharedCertsForTLS) + } + if val, ok := ingAnnotations[managedCertKey]; ok { + klog.V(6).Infof("Specified google managed certs for ingress %s: %v", ingKey, val) + sslConfigured = true + features = append(features, managedCertsForTLS) + } + if hasSecretBasedCerts(ing) { + sslConfigured = true + features = append(features, secretBasedCertsForTLS) + } + if sslConfigured { + klog.V(6).Infof("TLS termination is configured for ingress %s", ingKey) + features = append(features, tlsTermination) + } + + // Both user specified and ingress controller managed global static ips are reported. + if val, ok := ingAnnotations[staticIPKey]; ok && val != "" { + klog.V(6).Infof("Specified static for ingress %s: %s", ingKey, val) + features = append(features, staticGlobalIP) + } + klog.V(4).Infof("Features for ingress %s/%s: %v", ing.Namespace, ing.Name, features) + return features +} + +// hasSecretBasedCerts returns true if ingress spec contains a secret based cert. +func hasSecretBasedCerts(ing *v1beta1.Ingress) bool { + for _, tlsSecret := range ing.Spec.TLS { + if tlsSecret.SecretName == "" { + continue + } + klog.V(6).Infof("User specified secret for ingress %s/%s: %s", ing.Namespace, ing.Name, tlsSecret.SecretName) + return true + } + return false +} + +// FeaturesForServicePort returns the list of features for given service port. +func FeaturesForServicePort(sp utils.ServicePort) []Feature { + features := []Feature{servicePort} + svcPortKey := newServicePortKey(sp).string() + klog.V(4).Infof("Listing features for service port %s", svcPortKey) + if sp.L7ILBEnabled { + klog.V(6).Infof("L7 ILB is enabled for service port %s", svcPortKey) + features = append(features, internalServicePort) + } else { + features = append(features, externalServicePort) + } + if sp.NEGEnabled { + klog.V(6).Infof("NEG is enabled for service port %s", svcPortKey) + features = append(features, neg) + } + if sp.BackendConfig == nil { + klog.V(4).Infof("Features for Service port %s: %v", svcPortKey, features) + return features + } + + beConfig := fmt.Sprintf("%s/%s", sp.BackendConfig.Namespace, sp.BackendConfig.Name) + klog.V(6).Infof("Backend config specified for service port %s: %s", svcPortKey, beConfig) + + if sp.BackendConfig.Spec.Cdn != nil && sp.BackendConfig.Spec.Cdn.Enabled { + klog.V(6).Infof("Cloud CDN is enabled for service port %s", svcPortKey) + features = append(features, cloudCDN) + } + if sp.BackendConfig.Spec.Iap != nil && sp.BackendConfig.Spec.Iap.Enabled { + klog.V(6).Infof("Cloud IAP is enabled for service port %s", svcPortKey) + features = append(features, cloudIAP) + } + // Possible list of Affinity types: + // NONE, CLIENT_IP, GENERATED_COOKIE, CLIENT_IP_PROTO, or CLIENT_IP_PORT_PROTO. + if sp.BackendConfig.Spec.SessionAffinity != nil { + affinityType := sp.BackendConfig.Spec.SessionAffinity.AffinityType + switch affinityType { + case "GENERATED_COOKIE": + features = append(features, cookieAffinity) + case "CLIENT_IP", "CLIENT_IP_PROTO", "CLIENT_IP_PORT_PROTO": + features = append(features, clientIPAffinity) + } + klog.V(6).Infof("Session affinity %s is configured for service port %s", affinityType, svcPortKey) + } + if sp.BackendConfig.Spec.SecurityPolicy != nil { + klog.V(6).Infof("Security policy %s is configured for service port %s", sp.BackendConfig.Spec.SecurityPolicy, svcPortKey) + features = append(features, cloudArmor) + } + if sp.BackendConfig.Spec.TimeoutSec != nil { + klog.V(6).Infof("Backend timeout(%v secs) is configured for service port %s", sp.BackendConfig.Spec.TimeoutSec, svcPortKey) + features = append(features, backendTimeout) + } + if sp.BackendConfig.Spec.ConnectionDraining != nil { + klog.V(6).Infof("Backend connection draining(%v secs) is configured for service port %s", sp.BackendConfig.Spec.ConnectionDraining.DrainingTimeoutSec, svcPortKey) + features = append(features, backendConnectionDraining) + } + if sp.BackendConfig.Spec.CustomRequestHeaders != nil { + klog.V(6).Infof("Custom request headers configured for service port %s: %v", svcPortKey, sp.BackendConfig.Spec.CustomRequestHeaders.Headers) + features = append(features, customRequestHeaders) + } + klog.V(4).Infof("Features for Service port %s: %v", svcPortKey, features) + return features +} diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go new file mode 100644 index 0000000000..367502afc7 --- /dev/null +++ b/pkg/metrics/metrics.go @@ -0,0 +1,249 @@ +package metrics + +import ( + "fmt" + "sync" + "time" + + "github.com/prometheus/client_golang/prometheus" + "k8s.io/api/networking/v1beta1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/ingress-gce/pkg/utils" + "k8s.io/klog" +) + +const ( + label = "Feature" +) + +var ( + metricsInterval = 20 * time.Second + ingressCount = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "number_of_ingresses", + Help: "Number of Ingresses", + }, + []string{label}, + ) + servicePortCount = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "number_of_service_ports", + Help: "Number of Service Ports", + }, + []string{label}, + ) +) + +// init registers ingress usage metrics. +func init() { + klog.V(3).Infof("Registering Ingress usage metrics %v and %v", ingressCount, servicePortCount) + prometheus.MustRegister(ingressCount, servicePortCount) +} + +// IngressState defines an ingress and its associated service ports. +type IngressState struct { + ingress *v1beta1.Ingress + servicePorts []utils.ServicePort +} + +// NewIngressState returns ingress state for given ingress and service ports. +func NewIngressState(ing *v1beta1.Ingress, svcPorts []utils.ServicePort) IngressState { + return IngressState{ingress: ing, servicePorts: svcPorts} +} + +// IngressMetrics contains the state of the all ingresses. +type IngressMetrics struct { + ingressMap map[string]IngressState + sync.Mutex +} + +// NewIngressMetrics initializes IngressMetrics and starts a go routine to compute and export metrics periodically. +func NewIngressMetrics() *IngressMetrics { + return &IngressMetrics{ingressMap: make(map[string]IngressState)} +} + +// servicePortKey defines a service port uniquely. +// Note that same service port combination used by ILB and XLB are treated as separate service ports. +type servicePortKey struct { + svcPortID utils.ServicePortID + isL7ILBEnabled bool +} + +func newServicePortKey(svcPort utils.ServicePort) servicePortKey { + return servicePortKey{svcPortID: svcPort.ID, isL7ILBEnabled: svcPort.L7ILBEnabled} +} + +func (spk servicePortKey) string() string { + if spk.isL7ILBEnabled { + return fmt.Sprintf("%s/%s", spk.svcPortID, "ILB") + } + return fmt.Sprintf("%s/%s", spk.svcPortID, "XLB") +} + +func (im *IngressMetrics) Run(stopCh <-chan struct{}) { + klog.V(3).Infof("Ingress Metrics initialized. Metrics will be exported at an interval of %v", metricsInterval) + // Compute and export metrics periodically. + go func() { + // Wait for ingress states to be populated in the cache before computing metrics. + time.Sleep(metricsInterval) + wait.Until(im.Export, metricsInterval, stopCh) + }() + <-stopCh +} + +// Set inserts/updates given key-value pair. +func (im *IngressMetrics) Set(ingKey string, ing IngressState) { + im.Lock() + defer im.Unlock() + + if im.ingressMap == nil { + klog.Fatalf("Ingress Metrics failed to initialize correctly.") + } + im.ingressMap[ingKey] = ing +} + +// Delete deletes given key from the map. +func (im *IngressMetrics) Delete(ingKey string) { + im.Lock() + defer im.Unlock() + + delete(im.ingressMap, ingKey) +} + +// Export computes and exports ingress usage metrics. +func (im *IngressMetrics) Export() { + ingCount, svcPortCount := im.computeMetrics() + + klog.V(3).Infof("Exporting ingress usage metrics. Ingress Count: %#v, Service Port count: %#v", ingCount, svcPortCount) + for feature, count := range ingCount { + ingressCount.With(prometheus.Labels{label: feature.String()}).Set(float64(count)) + } + + for feature, count := range svcPortCount { + servicePortCount.With(prometheus.Labels{label: feature.String()}).Set(float64(count)) + } + klog.V(3).Infof("Ingress usage metrics exported.") +} + +// computeMetrics traverses all ingresses and computes, +// 1. Count of GCE ingresses for each feature. +// 2. Count of service-port pairs that backs up a GCE ingress for each feature. +func (im *IngressMetrics) computeMetrics() (map[Feature]int, map[Feature]int) { + ingCount, svcPortCount := initializeCounts() + // servicePortFeatures tracks the list of service-ports and their features. + // This is to avoid re-computing features for a service-port. + svcPortFeatures := make(map[servicePortKey][]Feature) + klog.V(4).Infof("Computing Ingress usage metrics from ingress state map: %#v", im.ingressMap) + im.Lock() + defer im.Unlock() + + for ingKey, ingState := range im.ingressMap { + // Both frontend and backend associated ingress features are tracked. + currIngFeatures := make(map[Feature]bool) + klog.V(6).Infof("Computing frontend based features for ingress %s", ingKey) + // Add frontend associated ingress features. + for _, feature := range FeaturesForIngress(ingState.ingress) { + currIngFeatures[feature] = true + } + klog.V(6).Infof("Frontend based features for ingress %s: %v", ingKey, currIngFeatures) + klog.V(6).Infof("Computing backend based features for ingress %s", ingKey) + for _, svcPort := range ingState.servicePorts { + svcPortKey := newServicePortKey(svcPort) + klog.V(6).Infof("Computing features for service-port %s", svcPortKey.string()) + svcFeatures, ok := svcPortFeatures[svcPortKey] + if !ok { + svcFeatures = FeaturesForServicePort(svcPort) + } + // Add backend associated ingress features. + for _, sf := range svcFeatures { + // Ignore features specific to the service. + if !isServiceFeature(sf) { + currIngFeatures[sf] = true + } + } + if ok { + // Skip re-computing features for a service port. + klog.V(4).Infof("Features for service port %s exists, skipping.", svcPortKey.string()) + continue + } + svcPortFeatures[svcPortKey] = svcFeatures + klog.V(6).Infof("Features for service port %s: %v", svcPortKey.string(), svcFeatures) + // Update service port feature counts. + updateServicePortCount(svcPortCount, svcFeatures) + } + klog.V(6).Infof("Features for ingress %s: %v", ingKey, currIngFeatures) + // Merge current ingress to update ingress feature counts. + updateIngressCount(ingCount, currIngFeatures) + } + + klog.V(4).Infof("Ingress usage metrics computed.") + return ingCount, svcPortCount +} + +// initializeCounts initializes feature count maps for ingress and service ports. +// This is required in order to reset counts for features that do not exist now +// but existed before. +func initializeCounts() (map[Feature]int, map[Feature]int) { + return map[Feature]int{ + ingress: 0, + externalIngress: 0, + internalIngress: 0, + httpEnabled: 0, + hostBasedRouting: 0, + pathBasedRouting: 0, + tlsTermination: 0, + secretBasedCertsForTLS: 0, + preSharedCertsForTLS: 0, + managedCertsForTLS: 0, + staticGlobalIP: 0, + neg: 0, + cloudCDN: 0, + cloudArmor: 0, + cloudIAP: 0, + backendTimeout: 0, + backendConnectionDraining: 0, + clientIPAffinity: 0, + cookieAffinity: 0, + customRequestHeaders: 0, + }, + // service port counts + map[Feature]int{ + servicePort: 0, + externalServicePort: 0, + internalServicePort: 0, + neg: 0, + cloudCDN: 0, + cloudArmor: 0, + cloudIAP: 0, + backendTimeout: 0, + backendConnectionDraining: 0, + clientIPAffinity: 0, + cookieAffinity: 0, + customRequestHeaders: 0, + } +} + +// updateServicePortCount inserts/increments service port counts by 1 for given features. +func updateServicePortCount(svcPortCount map[Feature]int, features []Feature) { + for _, feature := range features { + svcPortCount[feature] += 1 + } +} + +// updateIngressCount inserts/increments ingress counts by 1 for given feature map. +func updateIngressCount(ingCount map[Feature]int, features map[Feature]bool) { + for feature := range features { + ingCount[feature] += 1 + } +} + +// isServiceFeature returns true if given feature applies only to service-port but +// not to the ingress that references this service-port. +func isServiceFeature(feature Feature) bool { + serviceFeatures := map[Feature]bool{ + servicePort: true, + externalServicePort: true, + internalServicePort: true, + } + return serviceFeatures[feature] +} diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go new file mode 100644 index 0000000000..723017161d --- /dev/null +++ b/pkg/metrics/metrics_test.go @@ -0,0 +1,693 @@ +package metrics + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/types" + + "k8s.io/api/networking/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + backendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1beta1" + "k8s.io/ingress-gce/pkg/utils" +) + +var ( + testTTL = int64(10) + defaultNamespace = "default" + testServicePorts = []utils.ServicePort{ + { + ID: utils.ServicePortID{ + Service: types.NamespacedName{ + Name: "dummy-service", + Namespace: defaultNamespace, + }, + Port: intstr.FromInt(80), + }, + BackendConfig: &backendconfigv1beta1.BackendConfig{ + Spec: backendconfigv1beta1.BackendConfigSpec{ + Cdn: &backendconfigv1beta1.CDNConfig{ + Enabled: true, + CachePolicy: &backendconfigv1beta1.CacheKeyPolicy{}, + }, + SessionAffinity: &backendconfigv1beta1.SessionAffinityConfig{ + AffinityType: "GENERATED_COOKIE", + AffinityCookieTtlSec: &testTTL, + }, + SecurityPolicy: &backendconfigv1beta1.SecurityPolicyConfig{ + Name: "security-policy-1", + }, + ConnectionDraining: &backendconfigv1beta1.ConnectionDrainingConfig{ + DrainingTimeoutSec: testTTL, + }, + }, + }, + }, + { + ID: utils.ServicePortID{ + Service: types.NamespacedName{ + Name: "foo-service", + Namespace: defaultNamespace, + }, + Port: intstr.FromInt(80), + }, + NEGEnabled: true, + BackendConfig: &backendconfigv1beta1.BackendConfig{ + Spec: backendconfigv1beta1.BackendConfigSpec{ + Iap: &backendconfigv1beta1.IAPConfig{ + Enabled: true, + }, + SessionAffinity: &backendconfigv1beta1.SessionAffinityConfig{ + AffinityType: "CLIENT_IP", + AffinityCookieTtlSec: &testTTL, + }, + TimeoutSec: &testTTL, + CustomRequestHeaders: &backendconfigv1beta1.CustomRequestHeadersConfig{ + Headers: []string{}, + }, + }, + }, + }, + // NEG default backend. + { + ID: utils.ServicePortID{ + Service: types.NamespacedName{ + Name: "dummy-service", + Namespace: defaultNamespace, + }, + Port: intstr.FromInt(80), + }, + NEGEnabled: true, + L7ILBEnabled: true, + }, + { + ID: utils.ServicePortID{ + Service: types.NamespacedName{ + Name: "bar-service", + Namespace: defaultNamespace, + }, + Port: intstr.FromInt(5000), + }, + NEGEnabled: true, + L7ILBEnabled: true, + BackendConfig: &backendconfigv1beta1.BackendConfig{ + Spec: backendconfigv1beta1.BackendConfigSpec{ + Iap: &backendconfigv1beta1.IAPConfig{ + Enabled: true, + }, + SessionAffinity: &backendconfigv1beta1.SessionAffinityConfig{ + AffinityType: "GENERATED_COOKIE", + AffinityCookieTtlSec: &testTTL, + }, + ConnectionDraining: &backendconfigv1beta1.ConnectionDrainingConfig{ + DrainingTimeoutSec: testTTL, + }, + }, + }, + }, + } + ingressStates = []struct { + desc string + ing *v1beta1.Ingress + frontendFeatures []Feature + svcPorts []utils.ServicePort + backendFeatures []Feature + }{ + { + "empty spec", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress0", + }, + }, + []Feature{ingress, externalIngress, httpEnabled}, + []utils.ServicePort{}, + nil, + }, + { + "http disabled", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress1", + Annotations: map[string]string{ + allowHTTPKey: "false"}, + }, + }, + []Feature{ingress, externalIngress}, + []utils.ServicePort{}, + nil, + }, + { + "default backend", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress2", + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{}, + }, + }, + []Feature{ingress, externalIngress, httpEnabled}, + []utils.ServicePort{testServicePorts[0]}, + []Feature{servicePort, externalServicePort, cloudCDN, + cookieAffinity, cloudArmor, backendConnectionDraining}, + }, + { + "host rule only", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress3", + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: "foo.bar", + }, + }, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, hostBasedRouting}, + []utils.ServicePort{}, + nil, + }, + { + "both host and path rules", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress4", + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: "foo.bar", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/foo", + Backend: v1beta1.IngressBackend{ + ServiceName: "foo-service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, + hostBasedRouting, pathBasedRouting}, + []utils.ServicePort{testServicePorts[1]}, + []Feature{servicePort, externalServicePort, neg, cloudIAP, + clientIPAffinity, backendTimeout, customRequestHeaders}, + }, + { + "default backend and host rule", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress5", + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{ + { + Host: "foo.bar", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/foo", + Backend: v1beta1.IngressBackend{ + ServiceName: "foo-service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, + hostBasedRouting, pathBasedRouting}, + testServicePorts[:2], + []Feature{servicePort, externalServicePort, cloudCDN, + cookieAffinity, cloudArmor, backendConnectionDraining, neg, cloudIAP, + clientIPAffinity, backendTimeout, customRequestHeaders}, + }, + { + "tls termination with pre-shared certs", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress6", + Annotations: map[string]string{ + preSharedCertKey: "pre-shared-cert1,pre-shared-cert2", + }, + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{}, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, + preSharedCertsForTLS, tlsTermination}, + []utils.ServicePort{testServicePorts[0]}, + []Feature{servicePort, externalServicePort, cloudCDN, + cookieAffinity, cloudArmor, backendConnectionDraining}, + }, + { + "tls termination with google managed certs", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress7", + Annotations: map[string]string{ + managedCertKey: "managed-cert1,managed-cert2", + }, + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{}, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, + managedCertsForTLS, tlsTermination}, + []utils.ServicePort{testServicePorts[0]}, + []Feature{servicePort, externalServicePort, cloudCDN, + cookieAffinity, cloudArmor, backendConnectionDraining}, + }, + { + "tls termination with pre-shared and google managed certs", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress8", + Annotations: map[string]string{ + preSharedCertKey: "pre-shared-cert1,pre-shared-cert2", + managedCertKey: "managed-cert1,managed-cert2", + }, + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{}, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, + preSharedCertsForTLS, managedCertsForTLS, tlsTermination}, + []utils.ServicePort{testServicePorts[0]}, + []Feature{servicePort, externalServicePort, cloudCDN, + cookieAffinity, cloudArmor, backendConnectionDraining}, + }, + { + "tls termination with pre-shared and secret based certs", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress9", + Annotations: map[string]string{ + preSharedCertKey: "pre-shared-cert1,pre-shared-cert2", + }, + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: "foo.bar", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/foo", + Backend: v1beta1.IngressBackend{ + ServiceName: "foo-service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + TLS: []v1beta1.IngressTLS{ + { + Hosts: []string{"foo.bar"}, + SecretName: "secret-1", + }, + }, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, hostBasedRouting, + pathBasedRouting, preSharedCertsForTLS, secretBasedCertsForTLS, tlsTermination}, + []utils.ServicePort{testServicePorts[1]}, + []Feature{servicePort, externalServicePort, neg, cloudIAP, + clientIPAffinity, backendTimeout, customRequestHeaders}, + }, + { + "global static ip", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress10", + Annotations: map[string]string{ + preSharedCertKey: "pre-shared-cert1,pre-shared-cert2", + staticIPKey: "10.0.1.2", + }, + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{}, + }, + }, + []Feature{ingress, externalIngress, httpEnabled, + preSharedCertsForTLS, tlsTermination, staticGlobalIP}, + []utils.ServicePort{testServicePorts[0]}, + []Feature{servicePort, externalServicePort, cloudCDN, + cookieAffinity, cloudArmor, backendConnectionDraining}, + }, + { + "default backend, host rule for internal load-balancer", + &v1beta1.Ingress{ + ObjectMeta: v1.ObjectMeta{ + Namespace: defaultNamespace, + Name: "ingress11", + Annotations: map[string]string{ + ingressClassKey: gceL7ILBIngressClass, + }, + }, + Spec: v1beta1.IngressSpec{ + Backend: &v1beta1.IngressBackend{ + ServiceName: "dummy-service", + ServicePort: intstr.FromInt(80), + }, + Rules: []v1beta1.IngressRule{ + { + Host: "bar", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/bar", + Backend: v1beta1.IngressBackend{ + ServiceName: "bar-service", + ServicePort: intstr.FromInt(5000), + }, + }, + }, + }, + }, + }, + }, + }, + }, + []Feature{ingress, internalIngress, httpEnabled, + hostBasedRouting, pathBasedRouting}, + []utils.ServicePort{testServicePorts[2], testServicePorts[3]}, + []Feature{servicePort, internalServicePort, neg, cloudIAP, + cookieAffinity, backendConnectionDraining}, + }, + } +) + +func TestFeaturesForIngress(t *testing.T) { + t.Parallel() + for _, tc := range ingressStates { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + gotFrontendFeatures := FeaturesForIngress(tc.ing) + if diff := cmp.Diff(tc.frontendFeatures, gotFrontendFeatures); diff != "" { + t.Fatalf("Got diff for frontend features (-want +got):\n%s", diff) + } + }) + } +} + +func TestFeaturesForServicePort(t *testing.T) { + t.Parallel() + for _, tc := range ingressStates { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + backendFeatureMap := make(map[Feature]bool) + var gotBackendFeatures []Feature + for _, svcPort := range tc.svcPorts { + for _, feature := range FeaturesForServicePort(svcPort) { + if backendFeatureMap[feature] { + continue + } + backendFeatureMap[feature] = true + gotBackendFeatures = append(gotBackendFeatures, feature) + } + } + if diff := cmp.Diff(tc.backendFeatures, gotBackendFeatures); diff != "" { + t.Fatalf("Got diff for backend features (-want +got):\n%s", diff) + } + }) + } +} + +func TestComputeMetrics(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + desc string + ingressStates []IngressState + expectIngressCount map[Feature]int + expectSvcPortCount map[Feature]int + }{ + { + "frontend features only", + []IngressState{ + NewIngressState(ingressStates[0].ing, ingressStates[0].svcPorts), + NewIngressState(ingressStates[1].ing, ingressStates[1].svcPorts), + NewIngressState(ingressStates[3].ing, ingressStates[3].svcPorts), + }, + map[Feature]int{ + backendConnectionDraining: 0, + backendTimeout: 0, + clientIPAffinity: 0, + cloudArmor: 0, + cloudCDN: 0, + cloudIAP: 0, + cookieAffinity: 0, + customRequestHeaders: 0, + externalIngress: 3, + httpEnabled: 2, + hostBasedRouting: 1, + ingress: 3, + internalIngress: 0, + managedCertsForTLS: 0, + neg: 0, + pathBasedRouting: 0, + preSharedCertsForTLS: 0, + secretBasedCertsForTLS: 0, + staticGlobalIP: 0, + tlsTermination: 0, + }, + map[Feature]int{ + backendConnectionDraining: 0, + backendTimeout: 0, + clientIPAffinity: 0, + cloudArmor: 0, + cloudCDN: 0, + cloudIAP: 0, + cookieAffinity: 0, + customRequestHeaders: 0, + internalServicePort: 0, + servicePort: 0, + externalServicePort: 0, + neg: 0, + }, + }, + { + "features for internal and external load-balancers", + []IngressState{ + NewIngressState(ingressStates[0].ing, ingressStates[0].svcPorts), + NewIngressState(ingressStates[1].ing, ingressStates[1].svcPorts), + NewIngressState(ingressStates[3].ing, ingressStates[3].svcPorts), + NewIngressState(ingressStates[11].ing, ingressStates[11].svcPorts), + }, + map[Feature]int{ + backendConnectionDraining: 1, + backendTimeout: 0, + clientIPAffinity: 0, + cloudArmor: 0, + cloudCDN: 0, + cloudIAP: 1, + cookieAffinity: 1, + customRequestHeaders: 0, + externalIngress: 3, + httpEnabled: 3, + hostBasedRouting: 2, + ingress: 4, + internalIngress: 1, + managedCertsForTLS: 0, + neg: 1, + pathBasedRouting: 1, + preSharedCertsForTLS: 0, + secretBasedCertsForTLS: 0, + staticGlobalIP: 0, + tlsTermination: 0, + }, + map[Feature]int{ + backendConnectionDraining: 1, + backendTimeout: 0, + clientIPAffinity: 0, + cloudArmor: 0, + cloudCDN: 0, + cloudIAP: 1, + cookieAffinity: 1, + customRequestHeaders: 0, + internalServicePort: 2, + servicePort: 2, + externalServicePort: 0, + neg: 2, + }, + }, + { + "frontend and backend features", + []IngressState{ + NewIngressState(ingressStates[2].ing, ingressStates[2].svcPorts), + NewIngressState(ingressStates[4].ing, ingressStates[4].svcPorts), + NewIngressState(ingressStates[6].ing, ingressStates[6].svcPorts), + NewIngressState(ingressStates[8].ing, ingressStates[8].svcPorts), + NewIngressState(ingressStates[10].ing, ingressStates[10].svcPorts), + }, + map[Feature]int{ + backendConnectionDraining: 4, + backendTimeout: 1, + clientIPAffinity: 1, + cloudArmor: 4, + cloudCDN: 4, + cloudIAP: 1, + cookieAffinity: 4, + customRequestHeaders: 1, + externalIngress: 5, + httpEnabled: 5, + hostBasedRouting: 1, + ingress: 5, + internalIngress: 0, + managedCertsForTLS: 1, + neg: 1, + pathBasedRouting: 1, + preSharedCertsForTLS: 3, + secretBasedCertsForTLS: 0, + staticGlobalIP: 1, + tlsTermination: 3, + }, + map[Feature]int{ + backendConnectionDraining: 1, + backendTimeout: 1, + clientIPAffinity: 1, + cloudArmor: 1, + cloudCDN: 1, + cloudIAP: 1, + cookieAffinity: 1, + customRequestHeaders: 1, + internalServicePort: 0, + servicePort: 2, + externalServicePort: 2, + neg: 1, + }, + }, + { + "all ingress features", + []IngressState{ + NewIngressState(ingressStates[0].ing, ingressStates[0].svcPorts), + NewIngressState(ingressStates[1].ing, ingressStates[1].svcPorts), + NewIngressState(ingressStates[2].ing, ingressStates[2].svcPorts), + NewIngressState(ingressStates[3].ing, ingressStates[3].svcPorts), + NewIngressState(ingressStates[4].ing, ingressStates[4].svcPorts), + NewIngressState(ingressStates[5].ing, ingressStates[5].svcPorts), + NewIngressState(ingressStates[6].ing, ingressStates[6].svcPorts), + NewIngressState(ingressStates[7].ing, ingressStates[7].svcPorts), + NewIngressState(ingressStates[8].ing, ingressStates[8].svcPorts), + NewIngressState(ingressStates[9].ing, ingressStates[9].svcPorts), + NewIngressState(ingressStates[10].ing, ingressStates[10].svcPorts), + NewIngressState(ingressStates[11].ing, ingressStates[11].svcPorts), + }, + map[Feature]int{ + backendConnectionDraining: 7, + backendTimeout: 3, + clientIPAffinity: 3, + cloudArmor: 6, + cloudCDN: 6, + cloudIAP: 4, + cookieAffinity: 7, + customRequestHeaders: 3, + externalIngress: 11, + httpEnabled: 11, + hostBasedRouting: 5, + ingress: 12, + internalIngress: 1, + managedCertsForTLS: 2, + neg: 4, + pathBasedRouting: 4, + preSharedCertsForTLS: 4, + secretBasedCertsForTLS: 1, + staticGlobalIP: 1, + tlsTermination: 5, + }, + map[Feature]int{ + backendConnectionDraining: 2, + backendTimeout: 1, + clientIPAffinity: 1, + cloudArmor: 1, + cloudCDN: 1, + cloudIAP: 2, + cookieAffinity: 2, + customRequestHeaders: 1, + internalServicePort: 2, + servicePort: 4, + externalServicePort: 2, + neg: 3, + }, + }, + } { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + ingMetrics := NewIngressMetrics() + for _, ingState := range tc.ingressStates { + ingKey := fmt.Sprintf("%s/%s", defaultNamespace, ingState.ingress.Name) + ingMetrics.Set(ingKey, ingState) + } + gotIngressCount, gotSvcPortCount := ingMetrics.computeMetrics() + if diff := cmp.Diff(tc.expectIngressCount, gotIngressCount); diff != "" { + t.Errorf("Got diff for ingress features count (-want +got):\n%s", diff) + } + if diff := cmp.Diff(tc.expectSvcPortCount, gotSvcPortCount); diff != "" { + t.Fatalf("Got diff for service port features count (-want +got):\n%s", diff) + } + }) + } +} diff --git a/pkg/neg/controller_test.go b/pkg/neg/controller_test.go index f0dde5ec18..8439898b95 100644 --- a/pkg/neg/controller_test.go +++ b/pkg/neg/controller_test.go @@ -89,7 +89,7 @@ func newTestController(kubeClient kubernetes.Interface) *Controller { ASMConfigMapNamespace: "kube-system", ASMConfigMapName: "ingress-controller-config-test", } - context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, gce.NewFakeGCECloud(gce.DefaultTestClusterValues()), namer, "" /*kubeSystemUID*/, ctxConfig) + context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, gce.NewFakeGCECloud(gce.DefaultTestClusterValues()), namer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) // Hack the context.Init func. configMapInformer := informerv1.NewConfigMapInformer(kubeClient, context.Namespace, context.ResyncPeriod, utils.NewNamespaceIndexer()) diff --git a/pkg/neg/manager_test.go b/pkg/neg/manager_test.go index 68cdc8c591..d51320e4d8 100644 --- a/pkg/neg/manager_test.go +++ b/pkg/neg/manager_test.go @@ -74,7 +74,7 @@ func NewTestSyncerManager(kubeClient kubernetes.Interface) *syncerManager { ResyncPeriod: 1 * time.Second, DefaultBackendSvcPort: defaultBackend, } - context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, gce.NewFakeGCECloud(gce.DefaultTestClusterValues()), namer, "" /*kubeSystemUID*/, ctxConfig) + context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, gce.NewFakeGCECloud(gce.DefaultTestClusterValues()), namer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) manager := newSyncerManager( namer, diff --git a/pkg/neg/readiness/reflector_test.go b/pkg/neg/readiness/reflector_test.go index 61fdab5d84..903ca50630 100644 --- a/pkg/neg/readiness/reflector_test.go +++ b/pkg/neg/readiness/reflector_test.go @@ -63,7 +63,7 @@ func fakeContext() *context.ControllerContext { } fakeGCE := gce.NewFakeGCECloud(gce.DefaultTestClusterValues()) negtypes.MockNetworkEndpointAPIs(fakeGCE) - context := context.NewControllerContext(nil, kubeClient, nil, nil, fakeGCE, namer, "" /*kubeSystemUID*/, ctxConfig) + context := context.NewControllerContext(nil, kubeClient, nil, nil, fakeGCE, namer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) return context } diff --git a/pkg/neg/syncers/syncer_test.go b/pkg/neg/syncers/syncer_test.go index ed5c8c6d40..9b842929d2 100644 --- a/pkg/neg/syncers/syncer_test.go +++ b/pkg/neg/syncers/syncer_test.go @@ -88,7 +88,7 @@ func newSyncerTester() *syncerTester { ResyncPeriod: 1 * time.Second, DefaultBackendSvcPort: defaultBackend, } - context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, nil, namer, "" /*kubeSystemUID*/, ctxConfig) + context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, nil, namer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) negSyncerKey := negtypes.NegSyncerKey{ Namespace: testServiceNamespace, Name: testServiceName, diff --git a/pkg/neg/syncers/transaction_test.go b/pkg/neg/syncers/transaction_test.go index 649199e1a0..f3c15bd713 100644 --- a/pkg/neg/syncers/transaction_test.go +++ b/pkg/neg/syncers/transaction_test.go @@ -835,7 +835,7 @@ func newTestTransactionSyncer(fakeGCE negtypes.NetworkEndpointGroupCloud, negTyp ResyncPeriod: 1 * time.Second, DefaultBackendSvcPort: defaultBackend, } - context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, nil, namer, "" /*kubeSystemUID*/, ctxConfig) + context := context.NewControllerContext(nil, kubeClient, backendConfigClient, nil, nil, namer, "" /*kubeSystemUID*/, nil /*IngressMetrics*/, ctxConfig) svcPort := negtypes.NegSyncerKey{ Namespace: testNamespace, Name: testService,