Skip to content

Commit

Permalink
Add telemetry data - ingresses (#5406)
Browse files Browse the repository at this point in the history
  • Loading branch information
jjngx authored Apr 17, 2024
1 parent 4917a0e commit 68f523b
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 2 deletions.
3 changes: 3 additions & 0 deletions docs/content/overview/product-telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ If you would prefer to avoid sending any telemetry data, you can [opt-out](#opt-
## Data Collected

These are the data points collected and reported by NGINX Ingress Controller:

- **Project Name** The name of the software, which will be labelled `NIC`.
- **Project Version** NGINX Ingress Controller version.
- **Project Architecture** The architecture of the kubernetes environment. (e.g. amd64, arm64, etc...)
Expand All @@ -33,6 +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.


## Opt out

Expand Down
13 changes: 13 additions & 0 deletions internal/telemetry/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ func (c *Collector) Secrets() (int, error) {
return len(c.Config.SecretStore.GetSecretReferenceMap()), nil
}

// IngressCount returns number of Ingresses in the namespaces watched by NIC.
func (c *Collector) IngressCount() int {
if c.Config.Configurator == nil {
return 0
}
ic := c.Config.Configurator.GetIngressCounts()
total := 0
for _, v := range ic {
total += v
}
return total
}

// lookupPlatform takes a string representing a K8s PlatformID
// retrieved from a cluster node and returns a string
// representing the platform name.
Expand Down
4 changes: 4 additions & 0 deletions internal/telemetry/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func (c *Collector) Collect(ctx context.Context) {
TransportServers: int64(report.TransportServers),
Replicas: int64(report.NICReplicaCount),
Secrets: int64(report.Secrets),
Ingresses: int64(report.IngressCount),
},
}

Expand Down Expand Up @@ -143,6 +144,7 @@ type Report struct {
VirtualServerRoutes int
TransportServers int
Secrets int
IngressCount int
}

// BuildReport takes context, collects telemetry data and builds the report.
Expand Down Expand Up @@ -190,6 +192,7 @@ func (c *Collector) BuildReport(ctx context.Context) (Report, error) {
if err != nil {
glog.Errorf("Error collecting telemetry data: Secrets: %v", err)
}
ingressCount := c.IngressCount()

return Report{
Name: "NIC",
Expand All @@ -205,5 +208,6 @@ func (c *Collector) BuildReport(ctx context.Context) (Report, error) {
VirtualServerRoutes: vsrCount,
TransportServers: tsCount,
Secrets: secrets,
IngressCount: ingressCount,
}, err
}
187 changes: 185 additions & 2 deletions internal/telemetry/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import (
"testing"
"time"

"github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets"

"github.com/nginxinc/kubernetes-ingress/internal/configs"
"github.com/nginxinc/kubernetes-ingress/internal/configs/version1"
"github.com/nginxinc/kubernetes-ingress/internal/configs/version2"
"github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets"
"github.com/nginxinc/kubernetes-ingress/internal/nginx"

"github.com/google/go-cmp/cmp"
"github.com/nginxinc/kubernetes-ingress/internal/telemetry"
conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1"
tel "github.com/nginxinc/telemetry-exporter/pkg/telemetry"
coreV1 "k8s.io/api/core/v1"
networkingV1 "k8s.io/api/networking/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -249,6 +251,101 @@ func TestCollectClusterVersion(t *testing.T) {
}
}

func TestIngressCountReportsNoDeployedIngresses(t *testing.T) {
t.Parallel()

buf := &bytes.Buffer{}
exp := &telemetry.StdoutExporter{Endpoint: buf}
cfg := telemetry.CollectorConfig{
Configurator: newConfigurator(t),
K8sClientReader: newTestClientset(node1, kubeNS),
Version: telemetryNICData.ProjectVersion,
}

c, err := telemetry.NewCollector(cfg, telemetry.WithExporter(exp))
if err != nil {
t.Fatal(err)
}
c.Collect(context.Background())

telData := tel.Data{
ProjectName: telemetryNICData.ProjectName,
ProjectVersion: telemetryNICData.ProjectVersion,
ProjectArchitecture: telemetryNICData.ProjectArchitecture,
ClusterNodeCount: 1,
ClusterID: telemetryNICData.ClusterID,
ClusterVersion: telemetryNICData.ClusterVersion,
ClusterPlatform: "other",
}

nicResourceCounts := telemetry.NICResourceCounts{
VirtualServers: 0,
VirtualServerRoutes: 0,
TransportServers: 0,
Ingresses: 0,
}

td := telemetry.Data{
telData,
nicResourceCounts,
}

want := fmt.Sprintf("%+v", &td)
got := buf.String()
if !cmp.Equal(want, got) {
t.Error(cmp.Diff(want, got))
}
}

func TestIngressCountReportsNumberOfDeployedIngresses(t *testing.T) {
t.Parallel()

buf := &bytes.Buffer{}
exp := &telemetry.StdoutExporter{Endpoint: buf}

configurator := newConfiguratorWithIngress(t)

cfg := telemetry.CollectorConfig{
Configurator: configurator,
K8sClientReader: newTestClientset(node1, kubeNS),
Version: telemetryNICData.ProjectVersion,
}

c, err := telemetry.NewCollector(cfg, telemetry.WithExporter(exp))
if err != nil {
t.Fatal(err)
}
c.Collect(context.Background())

telData := tel.Data{
ProjectName: telemetryNICData.ProjectName,
ProjectVersion: telemetryNICData.ProjectVersion,
ProjectArchitecture: telemetryNICData.ProjectArchitecture,
ClusterNodeCount: 1,
ClusterID: telemetryNICData.ClusterID,
ClusterVersion: telemetryNICData.ClusterVersion,
ClusterPlatform: "other",
}

nicResourceCounts := telemetry.NICResourceCounts{
VirtualServers: 0,
VirtualServerRoutes: 0,
TransportServers: 0,
Ingresses: 1,
}

td := telemetry.Data{
telData,
nicResourceCounts,
}

want := fmt.Sprintf("%+v", &td)
got := buf.String()
if !cmp.Equal(want, got) {
t.Error(cmp.Diff(want, got))
}
}

func TestCountVirtualServers(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -666,10 +763,95 @@ func TestCountSecretsAddTwoSecretsAndDeleteOne(t *testing.T) {
}
}

func createCafeIngressEx() configs.IngressEx {
cafeIngress := networkingV1.Ingress{
ObjectMeta: metaV1.ObjectMeta{
Name: "cafe-ingress",
Namespace: "default",
Annotations: map[string]string{
"kubernetes.io/ingress.class": "nginx",
},
},
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{
Paths: []networkingV1.HTTPIngressPath{
{
Path: "/coffee",
Backend: networkingV1.IngressBackend{
Service: &networkingV1.IngressServiceBackend{
Name: "coffee-svc",
Port: networkingV1.ServiceBackendPort{
Number: 80,
},
},
},
},
{
Path: "/tea",
Backend: networkingV1.IngressBackend{
Service: &networkingV1.IngressServiceBackend{
Name: "tea-svc",
Port: networkingV1.ServiceBackendPort{
Number: 80,
},
},
},
},
},
},
},
},
},
},
}
cafeIngressEx := configs.IngressEx{
Ingress: &cafeIngress,
Endpoints: map[string][]string{
"coffee-svc80": {"10.0.0.1:80"},
"tea-svc80": {"10.0.0.2:80"},
},
ExternalNameSvcs: map[string]bool{},
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",
},
},
}
return cafeIngressEx
}

func getResourceKey(namespace, name string) string {
return fmt.Sprintf("%s_%s", namespace, name)
}

func newConfiguratorWithIngress(t *testing.T) *configs.Configurator {
t.Helper()

ingressEx := createCafeIngressEx()
c := newConfigurator(t)
_, err := c.AddOrUpdateIngress(&ingressEx)
if err != nil {
t.Fatal(err)
}
return c
}

func newConfigurator(t *testing.T) *configs.Configurator {
t.Helper()

Expand Down Expand Up @@ -705,6 +887,7 @@ func newConfigurator(t *testing.T) *configs.Configurator {
IsPrometheusEnabled: false,
IsLatencyMetricsEnabled: false,
})

return cnf
}

Expand Down
3 changes: 3 additions & 0 deletions internal/telemetry/data.avdl
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,8 @@ It is the UID of the `kube-system` Namespace. */
/** Secrets is the number of Secret resources managed by the Ingress Controller. */
long? Secrets = null;

/** Ingresses is the number of Ingresses. */
long? Ingresses = null;

}
}
2 changes: 2 additions & 0 deletions internal/telemetry/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,6 @@ type NICResourceCounts struct {
Replicas int64
// Secrets is the number of Secret resources managed by the Ingress Controller.
Secrets int64
// Ingresses is the number of Ingresses.
Ingresses int64
}
Original file line number Diff line number Diff line change
Expand Up @@ -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("Ingresses", d.Ingresses))

return attrs
}
Expand Down

0 comments on commit 68f523b

Please sign in to comment.