Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AppProtectVersion to Telemetry #5554

Merged
merged 8 commits into from
May 16, 2024
3 changes: 2 additions & 1 deletion cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const (
versionLabel = "app.kubernetes.io/version"
appProtectVersionLabel = "appprotect.f5.com/version"
agentVersionLabel = "app.nginx.org/agent-version"
appProtectVersionPath = "/opt/app_protect/VERSION"
appProtectVersionPath = "/opt/app_protect/RELEASE"
)

func main() {
Expand Down Expand Up @@ -184,6 +184,7 @@ func main() {
DefaultServerSecret: *defaultServerSecret,
AppProtectEnabled: *appProtect,
AppProtectDosEnabled: *appProtectDos,
AppProtectVersion: appProtectVersion,
IsNginxPlus: *nginxPlus,
IngressClass: *ingressClass,
ExternalServiceName: *externalService,
Expand Down
1 change: 1 addition & 0 deletions docs/content/overview/product-telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ These are the data points collected and reported by NGINX Ingress Controller:
- **OIDCPolicies** Number of OIDC policies.
- **WAFPolicies** Number of WAF policies.
- **GlobalConfiguration** Represents the use of a GlobalConfiguration resource.
- **AppProtectVersion** The Version of AppProtect.
AlexFenlon marked this conversation as resolved.
Show resolved Hide resolved

## Opt out

Expand Down
2 changes: 2 additions & 0 deletions internal/k8s/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ type NewLoadBalancerControllerInput struct {
DefaultServerSecret string
AppProtectEnabled bool
AppProtectDosEnabled bool
AppProtectVersion string
IsNginxPlus bool
IngressClass string
ExternalServiceName string
Expand Down Expand Up @@ -364,6 +365,7 @@ func NewLoadBalancerController(input NewLoadBalancerControllerInput) *LoadBalanc
Period: 24 * time.Hour,
K8sClientReader: input.KubeClient,
Version: input.NICVersion,
AppProtectVersion: input.AppProtectVersion,
GlobalConfiguration: lbc.watchGlobalConfiguration,
Configurator: lbc.configurator,
SecretStore: lbc.secretStore,
Expand Down
5 changes: 5 additions & 0 deletions internal/telemetry/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ func (c *Collector) PolicyCount() map[string]int {
return policyCounters
}

// AppProtectVersion returns the AppProtect Version
func (c *Collector) AppProtectVersion() string {
return c.Config.AppProtectVersion
}

// lookupPlatform takes a string representing a K8s PlatformID
// retrieved from a cluster node and returns a string
// representing the platform name.
Expand Down
8 changes: 8 additions & 0 deletions internal/telemetry/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ type CollectorConfig struct {

// Policies gets all policies
Policies func() []*conf_v1.Policy

// AppProtectVersion represents the version of App Protect.
AppProtectVersion string
}

// NewCollector takes 0 or more options and creates a new TraceReporter.
Expand Down Expand Up @@ -133,6 +136,7 @@ func (c *Collector) Collect(ctx context.Context) {
WAFPolicies: int64(report.WAFCount),
GlobalConfiguration: report.GlobalConfiguration,
IngressAnnotations: report.IngressAnnotations,
AppProtectVersion: report.AppProtectVersion,
},
}

Expand Down Expand Up @@ -173,6 +177,7 @@ type Report struct {
WAFCount int
GlobalConfiguration bool
IngressAnnotations []string
AppProtectVersion string
}

// BuildReport takes context, collects telemetry data and builds the report.
Expand Down Expand Up @@ -241,6 +246,8 @@ func (c *Collector) BuildReport(ctx context.Context) (Report, error) {

ingressAnnotations := c.IngressAnnotations()

appProtectVersion := c.AppProtectVersion()

return Report{
Name: "NIC",
Version: c.Config.Version,
Expand Down Expand Up @@ -268,5 +275,6 @@ func (c *Collector) BuildReport(ctx context.Context) (Report, error) {
WAFCount: wafCount,
GlobalConfiguration: c.Config.GlobalConfiguration,
IngressAnnotations: ingressAnnotations,
AppProtectVersion: appProtectVersion,
}, err
}
113 changes: 113 additions & 0 deletions internal/telemetry/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,119 @@ func TestIngressCountReportsNumberOfDeployedIngresses(t *testing.T) {
}
}

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

testCases := []struct {
name string
appProtectVersion string
wantVersion string
}{
{
name: "AppProtect 4.8",
appProtectVersion: "4.8.1",
wantVersion: "4.8.1",
},
{
name: "AppProtect 4.9",
appProtectVersion: "4.9",
wantVersion: "4.9",
},
{
name: "AppProtect 5.1",
appProtectVersion: "5.1",
wantVersion: "5.1",
},
{
name: "No AppProtect Installed",
appProtectVersion: "",
wantVersion: "",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
buf := &bytes.Buffer{}
exp := &telemetry.StdoutExporter{Endpoint: buf}

configurator := newConfiguratorWithIngress(t)

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

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

ver := c.AppProtectVersion()

if tc.wantVersion != ver {
t.Errorf("want: %s, got: %s", tc.wantVersion, ver)
}
})
}
}

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

testCases := []struct {
name string
appProtectVersion string
wantVersion string
}{
{
name: "AppProtect Not Installed",
appProtectVersion: "",
wantVersion: "4.8.1",
},
{
name: "Cant Find AppProtect 4.9",
appProtectVersion: "4.9",
wantVersion: "",
},
{
name: "Found Different AppProtect Version",
appProtectVersion: "5.1",
wantVersion: "4.9",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
buf := &bytes.Buffer{}
exp := &telemetry.StdoutExporter{Endpoint: buf}

configurator := newConfiguratorWithIngress(t)

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

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

ver := c.AppProtectVersion()

if tc.wantVersion == ver {
t.Errorf("want: %s, got: %s", tc.wantVersion, ver)
}
})
}
}

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

Expand Down
3 changes: 3 additions & 0 deletions internal/telemetry/data.avdl
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,8 @@ It is the UID of the `kube-system` Namespace. */
/** IngressAnnotations is the list of annotations resources managed by NGINX Ingress Controller */
union {null, array<string>} IngressAnnotations = null;

/** AppProtectVersion represents the version of AppProtect. */
string? AppProtectVersion = null;

}
}
2 changes: 2 additions & 0 deletions internal/telemetry/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,6 @@ type NICResourceCounts struct {
GlobalConfiguration bool
// IngressAnnotations is the list of annotations resources managed by NGINX Ingress Controller
IngressAnnotations []string
// AppProtectVersion represents the version of AppProtect.
AppProtectVersion string
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func (d *NICResourceCounts) Attributes() []attribute.KeyValue {
attrs = append(attrs, attribute.Int64("WAFPolicies", d.WAFPolicies))
attrs = append(attrs, attribute.Bool("GlobalConfiguration", d.GlobalConfiguration))
attrs = append(attrs, attribute.StringSlice("IngressAnnotations", d.IngressAnnotations))
attrs = append(attrs, attribute.String("AppProtectVersion", d.AppProtectVersion))

return attrs
}
Expand Down
Loading