Skip to content

Commit

Permalink
Add AppProtectVersion to Telemetry (#5554)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexFenlon authored and ssrahul96 committed Jun 20, 2024
1 parent e59673b commit 0d46b41
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 1 deletion.
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 AppProtect version

## 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

0 comments on commit 0d46b41

Please sign in to comment.