diff --git a/docs/content/overview/product-telemetry.md b/docs/content/overview/product-telemetry.md index 5a23fa5151..edf98540c8 100644 --- a/docs/content/overview/product-telemetry.md +++ b/docs/content/overview/product-telemetry.md @@ -34,7 +34,8 @@ These are the data points collected and reported by NGINX Ingress Controller: - **TransportServers** The number of TransportServer resources managed by NGINX Ingress Controller. - **Replicas** Number of Deployment replicas, or Daemonset instances. - **Secrets** Number of Secret resources managed by NGINX Ingress Controller. -- **Ingress Count** Number of Ingresses. +- **Services** Number of Services referenced by VirtualServers, VirtualServerRoutes, TransportServers and Ingresses. +- **IngressCount** Number of Ingresses. ## Opt out diff --git a/internal/configs/configurator.go b/internal/configs/configurator.go index 35c3b395f4..59ab0a6ffc 100644 --- a/internal/configs/configurator.go +++ b/internal/configs/configurator.go @@ -123,6 +123,7 @@ type Configurator struct { templateExecutorV2 *version2.TemplateExecutor ingresses map[string]*IngressEx minions map[string]map[string]bool + mergeableIngresses map[string]*MergeableIngresses virtualServers map[string]*VirtualServerEx transportServers map[string]*TransportServerEx tlsPassthroughPairs map[string]tlsPassthroughPair @@ -180,6 +181,7 @@ func NewConfigurator(p ConfiguratorParams) *Configurator { templateExecutor: p.TemplateExecutor, templateExecutorV2: p.TemplateExecutorV2, minions: make(map[string]map[string]bool), + mergeableIngresses: make(map[string]*MergeableIngresses), tlsPassthroughPairs: make(map[string]tlsPassthroughPair), isPlus: p.IsPlus, isWildcardEnabled: p.IsWildcardEnabled, @@ -475,6 +477,9 @@ func (cnf *Configurator) addOrUpdateMergeableIngress(mergeableIngs *MergeableIng minionName := objectMetaToFileName(&minion.Ingress.ObjectMeta) cnf.minions[name][minionName] = true } + + cnf.mergeableIngresses[name] = mergeableIngs + if (cnf.isPlus && cnf.isPrometheusEnabled) || cnf.isLatencyMetricsEnabled { cnf.updateIngressMetricsLabels(mergeableIngs.Master, nginxCfg.Upstreams) } @@ -955,6 +960,7 @@ func (cnf *Configurator) DeleteIngress(key string, skipReload bool) error { delete(cnf.ingresses, name) delete(cnf.minions, name) + delete(cnf.mergeableIngresses, name) if (cnf.isPlus && cnf.isPrometheusEnabled) || cnf.isLatencyMetricsEnabled { cnf.deleteIngressMetricsLabels(key) @@ -1542,6 +1548,106 @@ func (cnf *Configurator) GetIngressCounts() map[string]int { return counters } +// GetServiceCount returns the total number of unique services referenced by Ingresses, VS's, VSR's, and TS's +func (cnf *Configurator) GetServiceCount() int { + setOfUniqueServices := make(map[string]bool) + cnf.addVSAndVSRServicesToSet(setOfUniqueServices) + cnf.addTSServicesToSet(setOfUniqueServices) + cnf.addIngressesServicesToSet(setOfUniqueServices) + return len(setOfUniqueServices) +} + +// addVSAndVSRServicesToSet adds services from VirtualServers and VirtualServerRoutes to the set +func (cnf *Configurator) addVSAndVSRServicesToSet(set map[string]bool) { + for _, vs := range cnf.virtualServers { + ns := vs.VirtualServer.Namespace + for _, upstream := range vs.VirtualServer.Spec.Upstreams { + svc := upstream.Service + addServiceToSet(set, ns, svc) + + if upstream.Backup != "" { + addServiceToSet(set, ns, upstream.Backup) + } + + if upstream.HealthCheck != nil && upstream.HealthCheck.GRPCService != "" { + addServiceToSet(set, ns, upstream.HealthCheck.GRPCService) + } + } + + for _, vsr := range vs.VirtualServerRoutes { + ns := vsr.Namespace + for _, upstream := range vsr.Spec.Upstreams { + svc := upstream.Service + addServiceToSet(set, ns, svc) + + if upstream.Backup != "" { + addServiceToSet(set, ns, upstream.Backup) + } + + if upstream.HealthCheck != nil && upstream.HealthCheck.GRPCService != "" { + addServiceToSet(set, ns, upstream.HealthCheck.GRPCService) + } + } + } + } +} + +// addTSServicesToSet adds services from TransportServers to the set +func (cnf *Configurator) addTSServicesToSet(set map[string]bool) { + for _, ts := range cnf.transportServers { + ns := ts.TransportServer.Namespace + for _, upstream := range ts.TransportServer.Spec.Upstreams { + svc := upstream.Service + addServiceToSet(set, ns, svc) + + if upstream.Backup != "" { + addServiceToSet(set, ns, upstream.Backup) + } + + } + } +} + +// addIngressesServicesToSet adds services from Ingresses to the set +func (cnf *Configurator) addIngressesServicesToSet(set map[string]bool) { + for _, ing := range cnf.ingresses { + cnf.addIngressServicesToSet(ing, set) + } + for _, mergeIngs := range cnf.mergeableIngresses { + cnf.addIngressServicesToSet(mergeIngs.Master, set) + for _, minion := range mergeIngs.Minions { + cnf.addIngressServicesToSet(minion, set) + } + } +} + +// addIngressServicesToSet processes a single ingress and adds its services to the set +func (cnf *Configurator) addIngressServicesToSet(ing *IngressEx, set map[string]bool) { + if ing == nil || ing.Ingress == nil { + return + } + ns := ing.Ingress.Namespace + if ing.Ingress.Spec.DefaultBackend != nil && ing.Ingress.Spec.DefaultBackend.Service != nil { + svc := ing.Ingress.Spec.DefaultBackend.Service.Name + addServiceToSet(set, ns, svc) + } + for _, rule := range ing.Ingress.Spec.Rules { + if rule.HTTP != nil { + for _, path := range rule.HTTP.Paths { + if path.Backend.Service != nil { + svc := path.Backend.Service.Name + addServiceToSet(set, ns, svc) + } + } + } + } +} + +// Helper function to add services to the set +func addServiceToSet(set map[string]bool, ns string, svc string) { + set[fmt.Sprintf("%s/%s", ns, svc)] = true +} + // GetVirtualServerCounts returns the total count of // VirtualServer and VirtualServerRoute resources that are handled by the Ingress Controller func (cnf *Configurator) GetVirtualServerCounts() (int, int) { diff --git a/internal/telemetry/collector.go b/internal/telemetry/collector.go index f8adf3ff43..32d30d6c0c 100644 --- a/internal/telemetry/collector.go +++ b/internal/telemetry/collector.go @@ -116,6 +116,7 @@ func (c *Collector) Collect(ctx context.Context) { TransportServers: int64(report.TransportServers), Replicas: int64(report.NICReplicaCount), Secrets: int64(report.Secrets), + Services: int64(report.ServiceCount), Ingresses: int64(report.IngressCount), }, } @@ -142,6 +143,7 @@ type Report struct { NICReplicaCount int VirtualServers int VirtualServerRoutes int + ServiceCount int TransportServers int Secrets int IngressCount int @@ -152,10 +154,12 @@ func (c *Collector) BuildReport(ctx context.Context) (Report, error) { vsCount := 0 vsrCount := 0 tsCount := 0 + serviceCount := 0 if c.Config.Configurator != nil { vsCount, vsrCount = c.Config.Configurator.GetVirtualServerCounts() tsCount = c.Config.Configurator.GetTransportServerCounts() + serviceCount = c.Config.Configurator.GetServiceCount() } clusterID, err := c.ClusterID(ctx) @@ -206,6 +210,7 @@ func (c *Collector) BuildReport(ctx context.Context) (Report, error) { NICReplicaCount: replicas, VirtualServers: vsCount, VirtualServerRoutes: vsrCount, + ServiceCount: serviceCount, TransportServers: tsCount, Secrets: secrets, IngressCount: ingressCount, diff --git a/internal/telemetry/collector_test.go b/internal/telemetry/collector_test.go index 019819e223..c6cd6bcae2 100644 --- a/internal/telemetry/collector_test.go +++ b/internal/telemetry/collector_test.go @@ -332,6 +332,7 @@ func TestIngressCountReportsNumberOfDeployedIngresses(t *testing.T) { VirtualServerRoutes: 0, TransportServers: 0, Ingresses: 1, + Services: 2, } td := telemetry.Data{ @@ -763,6 +764,492 @@ func TestCountSecretsAddTwoSecretsAndDeleteOne(t *testing.T) { } } +func TestCountVirtualServersServices(t *testing.T) { + t.Parallel() + + testCases := []struct { + testName string + expectedTraceDataOnAdd telemetry.Report + expectedTraceDataOnDelete telemetry.Report + virtualServers []*configs.VirtualServerEx + deleteCount int + }{ + { + testName: "Create and delete 1 VirtualServer with 2 upstreams", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 2, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + virtualServers: []*configs.VirtualServerEx{ + { + VirtualServer: &conf_v1.VirtualServer{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "ns-1", + Name: "coffee", + }, + Spec: conf_v1.VirtualServerSpec{ + Upstreams: []conf_v1.Upstream{ + { + Name: "coffee", + Service: "coffee-svc", + }, + { + Name: "coffee2", + Service: "coffee-svc2", + }, + }, + }, + }, + }, + }, + deleteCount: 1, + }, + { + testName: "Same service in 2 upstreams is only counted once", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 1, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + virtualServers: []*configs.VirtualServerEx{ + { + VirtualServer: &conf_v1.VirtualServer{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "ns-1", + Name: "coffee", + }, + Spec: conf_v1.VirtualServerSpec{ + Upstreams: []conf_v1.Upstream{ + { + Name: "coffee", + Service: "same-svc", + }, + { + Name: "coffee2", + Service: "same-svc", + }, + }, + }, + }, + }, + }, + deleteCount: 1, + }, + { + testName: "A backup service is counted in addition to the primary service", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 2, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + virtualServers: []*configs.VirtualServerEx{ + { + VirtualServer: &conf_v1.VirtualServer{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "ns-1", + Name: "coffee", + }, + Spec: conf_v1.VirtualServerSpec{ + Upstreams: []conf_v1.Upstream{ + { + Name: "coffee", + Service: "same-svc", + Backup: "backup-service", + }, + }, + }, + }, + }, + }, + deleteCount: 1, + }, + { + testName: "A grpc service is counted in addition to the primary service and backup service", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 3, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + virtualServers: []*configs.VirtualServerEx{ + { + VirtualServer: &conf_v1.VirtualServer{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "ns-1", + Name: "coffee", + }, + Spec: conf_v1.VirtualServerSpec{ + Upstreams: []conf_v1.Upstream{ + { + Name: "coffee", + Service: "same-svc", + Backup: "backup-service", + HealthCheck: &conf_v1.HealthCheck{ + GRPCService: "grpc-service", + }, + }, + }, + }, + }, + }, + }, + deleteCount: 1, + }, + } + + for _, test := range testCases { + configurator := newConfigurator(t) + + c, err := telemetry.NewCollector(telemetry.CollectorConfig{ + K8sClientReader: newTestClientset(kubeNS, node1, pod1, replica), + Configurator: configurator, + Version: telemetryNICData.ProjectVersion, + SecretStore: newSecretStore(t), + }) + if err != nil { + t.Fatal(err) + } + c.Config.PodNSName = types.NamespacedName{ + Namespace: "nginx-ingress", + Name: "nginx-ingress", + } + + for _, vs := range test.virtualServers { + _, err := configurator.AddOrUpdateVirtualServer(vs) + if err != nil { + t.Fatal(err) + } + } + + gotTraceDataOnAdd, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount)) + } + + for i := 0; i < test.deleteCount; i++ { + vs := test.virtualServers[i] + key := getResourceKey(vs.VirtualServer.Namespace, vs.VirtualServer.Name) + err := configurator.DeleteVirtualServer(key, false) + if err != nil { + t.Fatal(err) + } + } + + gotTraceDataOnDelete, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount)) + } + } +} + +func TestCountTransportServersServices(t *testing.T) { + t.Parallel() + + testCases := []struct { + testName string + expectedTraceDataOnAdd telemetry.Report + expectedTraceDataOnDelete telemetry.Report + transportServers []*configs.TransportServerEx + deleteCount int + }{ + { + testName: "Create and delete 1 TransportServer with 2 upstreams", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 2, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + transportServers: []*configs.TransportServerEx{ + { + TransportServer: &conf_v1.TransportServer{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "ns-1", + Name: "coffee", + }, + Spec: conf_v1.TransportServerSpec{ + Action: &conf_v1.TransportServerAction{ + Pass: "coffee", + }, + Upstreams: []conf_v1.TransportServerUpstream{ + { + Name: "coffee", + Service: "coffee-svc", + }, + { + Name: "coffee2", + Service: "coffee-svc2", + }, + }, + }, + }, + }, + }, + deleteCount: 1, + }, + { + testName: "Same service in 2 upstreams is only counted once", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 1, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + transportServers: []*configs.TransportServerEx{ + { + TransportServer: &conf_v1.TransportServer{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "ns-1", + Name: "coffee", + }, + Spec: conf_v1.TransportServerSpec{ + Action: &conf_v1.TransportServerAction{ + Pass: "coffee", + }, + Upstreams: []conf_v1.TransportServerUpstream{ + { + Name: "coffee", + Service: "same-svc", + }, + { + Name: "coffee2", + Service: "same-svc", + }, + }, + }, + }, + }, + }, + deleteCount: 1, + }, + } + + for _, test := range testCases { + configurator := newConfigurator(t) + + c, err := telemetry.NewCollector(telemetry.CollectorConfig{ + K8sClientReader: newTestClientset(kubeNS, node1, pod1, replica), + Configurator: configurator, + Version: telemetryNICData.ProjectVersion, + SecretStore: newSecretStore(t), + }) + if err != nil { + t.Fatal(err) + } + c.Config.PodNSName = types.NamespacedName{ + Namespace: "nginx-ingress", + Name: "nginx-ingress", + } + + for _, ts := range test.transportServers { + _, err := configurator.AddOrUpdateTransportServer(ts) + if err != nil { + t.Fatal(err) + } + } + + gotTraceDataOnAdd, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount)) + } + + for i := 0; i < test.deleteCount; i++ { + ts := test.transportServers[i] + key := getResourceKey(ts.TransportServer.Namespace, ts.TransportServer.Name) + err := configurator.DeleteTransportServer(key) + if err != nil { + t.Fatal(err) + } + } + + gotTraceDataOnDelete, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount)) + } + } +} + +func TestCountIngressesServices(t *testing.T) { + t.Parallel() + + testCases := []struct { + testName string + expectedTraceDataOnAdd telemetry.Report + expectedTraceDataOnDelete telemetry.Report + ingress configs.IngressEx + deleteCount int + }{ + { + testName: "Create and delete 1 Ingress with 2 services", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 2, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + ingress: createCafeIngressEx(), + deleteCount: 1, + }, + } + + for _, tc := range testCases { + test := tc + configurator := newConfigurator(t) + + c, err := telemetry.NewCollector(telemetry.CollectorConfig{ + K8sClientReader: newTestClientset(kubeNS, node1, pod1, replica), + Configurator: configurator, + Version: telemetryNICData.ProjectVersion, + SecretStore: newSecretStore(t), + }) + if err != nil { + t.Fatal(err) + } + c.Config.PodNSName = types.NamespacedName{ + Namespace: "nginx-ingress", + Name: "nginx-ingress", + } + + _, err = configurator.AddOrUpdateIngress(&test.ingress) + if err != nil { + t.Fatal(err) + } + + gotTraceDataOnAdd, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount)) + } + + for i := 0; i < test.deleteCount; i++ { + ing := test.ingress + + key := fmt.Sprintf("%s/%s", ing.Ingress.Namespace, ing.Ingress.Name) + err := configurator.DeleteIngress(key, false) + if err != nil { + t.Fatal(err) + } + } + + if err != nil { + t.Fatal(err) + } + + gotTraceDataOnDelete, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount)) + } + } +} + +func TestCountMergeableIngressesServices(t *testing.T) { + t.Parallel() + + testCases := []struct { + testName string + expectedTraceDataOnAdd telemetry.Report + expectedTraceDataOnDelete telemetry.Report + ingress *configs.MergeableIngresses + deleteCount int + }{ + { + testName: "Create and delete 1 MergeableIngress with 2 services", + expectedTraceDataOnAdd: telemetry.Report{ + ServiceCount: 2, + }, + expectedTraceDataOnDelete: telemetry.Report{ + ServiceCount: 0, + }, + ingress: createMergeableCafeIngress(), + deleteCount: 1, + }, + } + + for _, tc := range testCases { + test := tc + + configurator := newConfigurator(t) + + c, err := telemetry.NewCollector(telemetry.CollectorConfig{ + K8sClientReader: newTestClientset(kubeNS, node1, pod1, replica), + Configurator: configurator, + Version: telemetryNICData.ProjectVersion, + SecretStore: newSecretStore(t), + }) + if err != nil { + t.Fatal(err) + } + c.Config.PodNSName = types.NamespacedName{ + Namespace: "nginx-ingress", + Name: "nginx-ingress", + } + + _, err = configurator.AddOrUpdateMergeableIngress(test.ingress) + if err != nil { + t.Fatal(err) + } + + gotTraceDataOnAdd, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnAdd.ServiceCount, gotTraceDataOnAdd.ServiceCount)) + } + + for i := 0; i < test.deleteCount; i++ { + ing := test.ingress + + key := fmt.Sprintf("%s/%s", ing.Master.Ingress.Namespace, ing.Master.Ingress.Name) + err := configurator.DeleteIngress(key, false) + if err != nil { + t.Fatal(err) + } + } + + if err != nil { + t.Fatal(err) + } + + gotTraceDataOnDelete, err := c.BuildReport(context.Background()) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount) { + t.Error(cmp.Diff(test.expectedTraceDataOnDelete.ServiceCount, gotTraceDataOnDelete.ServiceCount)) + } + } +} + func createCafeIngressEx() configs.IngressEx { cafeIngress := networkingV1.Ingress{ ObjectMeta: metaV1.ObjectMeta{ @@ -836,6 +1323,159 @@ func createCafeIngressEx() configs.IngressEx { return cafeIngressEx } +func createMergeableCafeIngress() *configs.MergeableIngresses { + master := networkingV1.Ingress{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "cafe-ingress-master", + Namespace: "default", + Annotations: map[string]string{ + "kubernetes.io/ingress.class": "nginx", + "nginx.org/mergeable-ingress-type": "master", + }, + }, + Spec: networkingV1.IngressSpec{ + TLS: []networkingV1.IngressTLS{ + { + Hosts: []string{"cafe.example.com"}, + SecretName: "cafe-secret", + }, + }, + Rules: []networkingV1.IngressRule{ + { + Host: "cafe.example.com", + IngressRuleValue: networkingV1.IngressRuleValue{ + HTTP: &networkingV1.HTTPIngressRuleValue{ // HTTP must not be nil for Master + Paths: []networkingV1.HTTPIngressPath{}, + }, + }, + }, + }, + }, + } + + coffeeMinion := networkingV1.Ingress{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "cafe-ingress-coffee-minion", + Namespace: "default", + Annotations: map[string]string{ + "kubernetes.io/ingress.class": "nginx", + "nginx.org/mergeable-ingress-type": "minion", + }, + }, + Spec: networkingV1.IngressSpec{ + Rules: []networkingV1.IngressRule{ + { + Host: "cafe.example.com", + IngressRuleValue: networkingV1.IngressRuleValue{ + HTTP: &networkingV1.HTTPIngressRuleValue{ + Paths: []networkingV1.HTTPIngressPath{ + { + Path: "/coffee", + Backend: networkingV1.IngressBackend{ + Service: &networkingV1.IngressServiceBackend{ + Name: "coffee-svc", + Port: networkingV1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + teaMinion := networkingV1.Ingress{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "cafe-ingress-tea-minion", + Namespace: "default", + Annotations: map[string]string{ + "kubernetes.io/ingress.class": "nginx", + "nginx.org/mergeable-ingress-type": "minion", + }, + }, + Spec: networkingV1.IngressSpec{ + Rules: []networkingV1.IngressRule{ + { + Host: "cafe.example.com", + IngressRuleValue: networkingV1.IngressRuleValue{ + HTTP: &networkingV1.HTTPIngressRuleValue{ + Paths: []networkingV1.HTTPIngressPath{ + { + Path: "/tea", + Backend: networkingV1.IngressBackend{ + Service: &networkingV1.IngressServiceBackend{ + Name: "tea-svc", + Port: networkingV1.ServiceBackendPort{ + Number: 80, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + mergeableIngresses := &configs.MergeableIngresses{ + Master: &configs.IngressEx{ + Ingress: &master, + Endpoints: map[string][]string{ + "coffee-svc80": {"10.0.0.1:80"}, + "tea-svc80": {"10.0.0.2:80"}, + }, + ValidHosts: map[string]bool{ + "cafe.example.com": true, + }, + SecretRefs: map[string]*secrets.SecretReference{ + "cafe-secret": { + Secret: &coreV1.Secret{ + Type: coreV1.SecretTypeTLS, + }, + Path: "/etc/nginx/secrets/default-cafe-secret", + Error: nil, + }, + }, + }, + Minions: []*configs.IngressEx{ + { + Ingress: &coffeeMinion, + Endpoints: map[string][]string{ + "coffee-svc80": {"10.0.0.1:80"}, + }, + ValidHosts: map[string]bool{ + "cafe.example.com": true, + }, + ValidMinionPaths: map[string]bool{ + "/coffee": true, + }, + SecretRefs: map[string]*secrets.SecretReference{}, + }, + { + Ingress: &teaMinion, + Endpoints: map[string][]string{ + "tea-svc80": {"10.0.0.2:80"}, + }, + ValidHosts: map[string]bool{ + "cafe.example.com": true, + }, + ValidMinionPaths: map[string]bool{ + "/tea": true, + }, + SecretRefs: map[string]*secrets.SecretReference{}, + }, + }, + } + + return mergeableIngresses +} + func getResourceKey(namespace, name string) string { return fmt.Sprintf("%s_%s", namespace, name) } diff --git a/internal/telemetry/data.avdl b/internal/telemetry/data.avdl index ce16345061..e8ae13b0cb 100644 --- a/internal/telemetry/data.avdl +++ b/internal/telemetry/data.avdl @@ -33,21 +33,24 @@ It is the UID of the `kube-system` Namespace. */ /** ClusterNodeCount is the number of nodes in the cluster. */ long? ClusterNodeCount = null; - /** VirtualServers is the number of VirtualServer resources managed by the Ingress Controller. */ + /** VirtualServers is the number of VirtualServer resources managed by NGINX Ingress Controller. */ long? VirtualServers = null; - /** VirtualServerRoutes is the number of VirtualServerRoute resources managed by the Ingress Controller. */ + /** VirtualServerRoutes is the number of VirtualServerRoute resources managed by NGINX Ingress Controller. */ long? VirtualServerRoutes = null; - /** TransportServers is the number of TransportServer resources managed by the Ingress Controller. */ + /** TransportServers is the number of TransportServer resources by NGINX Ingress Controller. */ long? TransportServers = null; - /** Replicas is the number of NIC replicas. */ + /** Replicas is the number of NGINX Ingress Controller replicas. */ long? Replicas = null; /** Secrets is the number of Secret resources managed by the Ingress Controller. */ long? Secrets = null; + /** Services is the number of services in the cluster referenced by NGINX Ingress Controller */ + long? Services = null; + /** Ingresses is the number of Ingresses. */ long? Ingresses = null; diff --git a/internal/telemetry/exporter.go b/internal/telemetry/exporter.go index 94b50b8441..dba9a08233 100644 --- a/internal/telemetry/exporter.go +++ b/internal/telemetry/exporter.go @@ -72,6 +72,8 @@ type NICResourceCounts struct { Replicas int64 // Secrets is the number of Secret resources managed by the Ingress Controller. Secrets int64 + // Services is the number of services referenced by NGINX Ingress Controller in the cluster + Services int64 // Ingresses is the number of Ingresses. Ingresses int64 } diff --git a/internal/telemetry/nicresourcecounts_attributes_generated.go b/internal/telemetry/nicresourcecounts_attributes_generated.go index 90e726d052..bee3e82a0a 100644 --- a/internal/telemetry/nicresourcecounts_attributes_generated.go +++ b/internal/telemetry/nicresourcecounts_attributes_generated.go @@ -18,6 +18,7 @@ func (d *NICResourceCounts) Attributes() []attribute.KeyValue { attrs = append(attrs, attribute.Int64("TransportServers", d.TransportServers)) attrs = append(attrs, attribute.Int64("Replicas", d.Replicas)) attrs = append(attrs, attribute.Int64("Secrets", d.Secrets)) + attrs = append(attrs, attribute.Int64("Services", d.Services)) attrs = append(attrs, attribute.Int64("Ingresses", d.Ingresses)) return attrs