[meraki] Add switchport status filtering for device health metrics
Proposed commit message
This PR adds a new switchport_statuses config option (defaulting to ["connected"]) to filter switchport metrics by port status, reducing number of documents.
Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] I have made corresponding change to the default configuration files
- [ ] I have added tests that prove my fix is effective or that my feature works. Where relevant, I have used the
stresstest.shscript to run them under stress conditions and race detector to verify their stability. - [ ] I have added an entry in
./changelog/fragmentsusing the changelog tool.
Disruptive User Impact
Author's Checklist
- [ ]
How to test this PR locally
Related issues
Use cases
Screenshots
Logs
:robot: GitHub comments
Just comment with:
rundocs-build: Re-trigger the docs validation. (use unformatted text in the comment!)
This pull request does not have a backport label. If this is a bug or security fix, could you label this PR @gpop63? 🙏. For such, you'll need to label your PR with:
- The upcoming major version of the Elastic Stack
- The upcoming minor version of the Elastic Stack (if you're not pushing a breaking change)
To fixup this pull request, you need to add the backport labels for the needed branches, such as:
backport-8./dis the label to automatically backport to the8./dbranch./dis the digitbackport-active-allis the label that automatically backports to all active branches.backport-active-8is the label that automatically backports to all active minor branches for the 8 major.backport-active-9is the label that automatically backports to all active minor branches for the 9 major.
make sure to run nilaway
diff --git a/x-pack/metricbeat/module/meraki/config_test.go b/x-pack/metricbeat/module/meraki/config_test.go
index 363ae89755..03ef925d44 100644
--- a/x-pack/metricbeat/module/meraki/config_test.go
+++ b/x-pack/metricbeat/module/meraki/config_test.go
@@ -21,33 +21,33 @@ func TestDefaultConfig(t *testing.T) {
func TestConfigValidate(t *testing.T) {
// Missing BaseURL
- cfg := &config{ApiKey: "key", Organizations: []string{"org"}, Period: 10 * time.Second}
+ cfg := &config{ApiKey: "key", Organizations: []string{"org"}, Period: 10 * time.Second, SwitchportStatuses: []string{"connected"}}
cfg.BaseURL = ""
err := cfg.Validate()
assert.Error(t, err)
assert.Contains(t, err.Error(), "apiBaseURL is required")
// Missing ApiKey
- cfg = &config{BaseURL: "url", Organizations: []string{"org"}, Period: 10 * time.Second}
+ cfg = &config{BaseURL: "url", Organizations: []string{"org"}, Period: 10 * time.Second, SwitchportStatuses: []string{"connected"}}
cfg.ApiKey = ""
err = cfg.Validate()
assert.Error(t, err)
assert.Contains(t, err.Error(), "apiKey is required")
// Missing Organizations
- cfg = &config{BaseURL: "url", ApiKey: "key", Organizations: []string{}, Period: 10 * time.Second}
+ cfg = &config{BaseURL: "url", ApiKey: "key", Organizations: []string{}, Period: 10 * time.Second, SwitchportStatuses: []string{"connected"}}
err = cfg.Validate()
assert.Error(t, err)
assert.Contains(t, err.Error(), "organizations is required")
// Period too long
- cfg = &config{BaseURL: "url", ApiKey: "key", Organizations: []string{"org"}, Period: 301 * time.Second}
+ cfg = &config{BaseURL: "url", ApiKey: "key", Organizations: []string{"org"}, Period: 301 * time.Second, SwitchportStatuses: []string{"connected"}}
err = cfg.Validate()
assert.Error(t, err)
assert.Contains(t, err.Error(), "maximum allowed collection period")
// Valid config
- cfg = &config{BaseURL: "url", ApiKey: "key", Organizations: []string{"org"}, Period: 10 * time.Second}
+ cfg = &config{BaseURL: "url", ApiKey: "key", Organizations: []string{"org"}, Period: 10 * time.Second, SwitchportStatuses: []string{"connected"}}
err = cfg.Validate()
assert.NoError(t, err)
}
diff --git a/x-pack/metricbeat/module/meraki/device_health/switchports.go b/x-pack/metricbeat/module/meraki/device_health/switchports.go
index 6b1ca764c9..bd3621d8f5 100644
--- a/x-pack/metricbeat/module/meraki/device_health/switchports.go
+++ b/x-pack/metricbeat/module/meraki/device_health/switchports.go
@@ -28,17 +28,19 @@ type switchport struct {
// filterSwitchportsByStatus filters switchports by their status, comparing against the allowed statuses.
// The comparison is case insensitive. Switchports with nil portStatus are excluded.
func filterSwitchportsByStatus(switchports []*switchport, statusesToReport []string) []*switchport {
+ // Pre-compute lowercase allowed statuses for efficient lookup
+ allowedStatuses := make(map[string]struct{}, len(statusesToReport))
+ for _, status := range statusesToReport {
+ allowedStatuses[strings.ToLower(status)] = struct{}{}
+ }
+
var filtered []*switchport
for _, sp := range switchports {
if sp.portStatus == nil {
continue
}
- portStatus := strings.ToLower(sp.portStatus.Status)
- for _, allowed := range statusesToReport {
- if portStatus == strings.ToLower(allowed) {
- filtered = append(filtered, sp)
- break
- }
+ if _, ok := allowedStatuses[strings.ToLower(sp.portStatus.Status)]; ok {
+ filtered = append(filtered, sp)
}
}
return filtered
diff --git a/x-pack/metricbeat/module/meraki/device_health/switchports_test.go b/x-pack/metricbeat/module/meraki/device_health/switchports_test.go
index 5062ffb2d7..3e23c792da 100644
--- a/x-pack/metricbeat/module/meraki/device_health/switchports_test.go
+++ b/x-pack/metricbeat/module/meraki/device_health/switchports_test.go
@@ -154,6 +154,22 @@ func TestFilterSwitchportsByStatus(t *testing.T) {
expectedCount: 0,
expectedPortIDs: []string{},
},
+ {
+ name: "empty statusesToReport returns no ports",
+ switchports: []*switchport{
+ {
+ port: &sdk.ResponseItemSwitchGetOrganizationSwitchPortsBySwitchPorts{PortID: "1"},
+ portStatus: &sdk.ResponseItemSwitchGetDeviceSwitchPortsStatuses{PortID: "1", Status: "Connected"},
+ },
+ {
+ port: &sdk.ResponseItemSwitchGetOrganizationSwitchPortsBySwitchPorts{PortID: "2"},
+ portStatus: &sdk.ResponseItemSwitchGetDeviceSwitchPortsStatuses{PortID: "2", Status: "Disconnected"},
+ },
+ },
+ statusesToReport: []string{},
+ expectedCount: 0,
+ expectedPortIDs: []string{},
+ },
}
for _, tt := range tests {
Pinging @elastic/elastic-agent-data-plane (Team:Elastic-Agent-Data-Plane)