diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index 4d7bd8ff..b9475929 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -356,36 +356,37 @@ func (l *CheckDrivesize) addMetrics(metricPrefix string, drive map[string]string } driveFreeMetricLabel := fmt.Sprintf("%s free %%", metricPrefix) - if check.HasThreshold(driveFreeMetricLabel) || check.HasThreshold("free") || check.HasThreshold("free_pct") || check.HasThreshold("free_bytes") { - check.warnThreshold = check.TransformMultipleKeywords([]string{"free_pct", "free_bytes"}, "free", check.warnThreshold) - check.critThreshold = check.TransformMultipleKeywords([]string{"free_pct", "free_bytes"}, "free", check.critThreshold) + if check.HasThreshold(driveFreeMetricLabel) || check.HasThreshold("free") || check.HasThreshold("free_pct") || check.HasThreshold("free_bytes") || check.HasThreshold("free %") { + check.warnThreshold = check.TransformMultipleKeywords([]string{"free_pct", "free_bytes", "free %"}, "free", check.warnThreshold) + check.critThreshold = check.TransformMultipleKeywords([]string{"free_pct", "free_bytes", "free %"}, "free", check.critThreshold) perfLabel := fmt.Sprintf("%s free", metricPrefix) check.AddBytePercentMetrics("free", perfLabel, magic*float64(usage.Free), magic*float64(total), drive) check.processMetricsWithSpecializedKeyword("drive", perfLabel, drive) } driveUsagePctMetricLabel := fmt.Sprintf("%s used %%", metricPrefix) - if check.HasThreshold(driveUsagePctMetricLabel) || check.HasThreshold("used") || check.HasThreshold("used_pct") || check.HasThreshold("used_bytes") { - check.warnThreshold = check.TransformMultipleKeywords([]string{"used_pct", "used_bytes"}, "used", check.warnThreshold) - check.critThreshold = check.TransformMultipleKeywords([]string{"used_pct", "used_bytes"}, "used", check.critThreshold) + if check.HasThreshold(driveUsagePctMetricLabel) || check.HasThreshold("used") || check.HasThreshold("used_pct") || check.HasThreshold("used_bytes") || check.HasThreshold("used %") { + check.warnThreshold = check.TransformMultipleKeywords([]string{"used_pct", "used_bytes", "used %"}, "used", check.warnThreshold) + check.critThreshold = check.TransformMultipleKeywords([]string{"used_pct", "used_bytes", "used %"}, "used", check.critThreshold) perfLabel := fmt.Sprintf("%s used", metricPrefix) check.AddBytePercentMetrics("used", perfLabel, magic*float64(usage.Used), magic*float64(total), drive) check.processMetricsWithSpecializedKeyword("drive", perfLabel, drive) } driveInodesUsedPctMetricLabel := fmt.Sprintf("%s inodes_used %%", metricPrefix) - if check.HasThreshold(driveInodesUsedPctMetricLabel) || check.HasThreshold("inodes") || check.HasThreshold("inodes_used") || check.HasThreshold("inodes_used_pct") { - check.warnThreshold = check.TransformMultipleKeywords([]string{"inodes_used_pct"}, "inodes_used", check.warnThreshold) - check.critThreshold = check.TransformMultipleKeywords([]string{"inodes_used_pct"}, "inodes_used", check.critThreshold) + if check.HasThreshold(driveInodesUsedPctMetricLabel) || check.HasThreshold("inodes") || check.HasThreshold("inodes_used") || check.HasThreshold("inodes_used_pct") || + check.HasThreshold("inodes_used %") { + check.warnThreshold = check.TransformMultipleKeywords([]string{"inodes_used_pct", "inodes_used %"}, "inodes_used", check.warnThreshold) + check.critThreshold = check.TransformMultipleKeywords([]string{"inodes_used_pct", "inodes_used %"}, "inodes_used", check.critThreshold) perfLabel := fmt.Sprintf("%s inodes_used", metricPrefix) check.AddPercentMetrics("inodes_used", perfLabel, float64(usage.InodesUsed), float64(usage.InodesTotal), drive) check.processMetricsWithSpecializedKeyword("drive", perfLabel, drive) } driveInodesFreePctMetricLabel := fmt.Sprintf("%s inodes_free %%", metricPrefix) - if check.HasThreshold(driveInodesFreePctMetricLabel) || check.HasThreshold("inodes_free") || check.HasThreshold("inodes_free_pct") { - check.warnThreshold = check.TransformMultipleKeywords([]string{"inodes_free_pct"}, "inodes_free", check.warnThreshold) - check.critThreshold = check.TransformMultipleKeywords([]string{"inodes_free_pct"}, "inodes_free", check.critThreshold) + if check.HasThreshold(driveInodesFreePctMetricLabel) || check.HasThreshold("inodes_free") || check.HasThreshold("inodes_free_pct") || check.HasThreshold("inodes_free %") { + check.warnThreshold = check.TransformMultipleKeywords([]string{"inodes_free_pct", "inodes_free %"}, "inodes_free", check.warnThreshold) + check.critThreshold = check.TransformMultipleKeywords([]string{"inodes_free_pct", "inodes_free %"}, "inodes_free", check.critThreshold) perfLabel := fmt.Sprintf("%s inodes_free", metricPrefix) check.AddPercentMetrics("inodes_free", perfLabel, float64(usage.InodesFree), float64(usage.InodesTotal), drive) check.processMetricsWithSpecializedKeyword("drive", perfLabel, drive) diff --git a/pkg/snclient/check_drivesize_test.go b/pkg/snclient/check_drivesize_test.go index 9744fea8..2ec4a6c2 100644 --- a/pkg/snclient/check_drivesize_test.go +++ b/pkg/snclient/check_drivesize_test.go @@ -83,3 +83,69 @@ func TestNonexistingDrive(t *testing.T) { StopTestAgent(t, snc) } + +func TestRootDriveThresholdsDrivePercentSign(t *testing.T) { + snc := StartTestAgent(t, "") + + // This tests the conditions using '[drive] used %' keyword + res := snc.RunCheck("check_drivesize", []string{"drive=/", "warn='/ used %' >= 0", "crit=none"}) + assert.Equalf(t, CheckExitWarning, res.State, "state should be WARNING") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "crit='/ used %' >= 0"}) + assert.Equalf(t, CheckExitCritical, res.State, "state should be CRITICAL") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "warn='/ used %' >= 0", "crit='/ used %' >= 0"}) + assert.Equalf(t, CheckExitCritical, res.State, "state should be CRITICAL") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "warn='/ used %' >= 0", "crit='/ used %' >= 0", "ok='/ used %' >= 0"}) + assert.Equalf(t, CheckExitOK, res.State, "state should be CRITICAL") + + StopTestAgent(t, snc) +} + +func TestRootDriveThresholdsUsedPct(t *testing.T) { + snc := StartTestAgent(t, "") + + // This tests the conditions using '[drive] used_pct' keyword + res := snc.RunCheck("check_drivesize", []string{"drive=/", "warn='/ used_pct' >= 0", "crit=none"}) + assert.Equalf(t, CheckExitWarning, res.State, "state should be WARNING") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "crit='/ used_pct' >= 0"}) + assert.Equalf(t, CheckExitCritical, res.State, "state should be CRITICAL") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "warn='/ used_pct' >= 0", "crit='/ used_pct' >= 0"}) + assert.Equalf(t, CheckExitCritical, res.State, "state should be CRITICAL") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "warn='/ used_pct' >= 0", "crit='/ used_pct' >= 0", "ok='/ used_pct' >= 0"}) + assert.Equalf(t, CheckExitOK, res.State, "state should be CRITICAL") + + StopTestAgent(t, snc) +} + +func TestRootDriveThresholdsUsedPercentSign(t *testing.T) { + snc := StartTestAgent(t, "") + + // Generic 'used %' keyword, should trigger + res := snc.RunCheck("check_drivesize", []string{"drive=/", "warning='used %' gt 0", "critical=none"}) + assert.Equalf(t, CheckExitWarning, res.State, "state should be WARNING") + + res = snc.RunCheck("check_drivesize", []string{"drive=/", "critical='used %' gt 0"}) + assert.Equalf(t, CheckExitCritical, res.State, "state should be CRITICAL") + + StopTestAgent(t, snc) +} + +func TestRootDriveSpecializedDriveConditions(t *testing.T) { + snc := StartTestAgent(t, "") + + // In critical conditions, the second one is filtered as it contains the drive="/" keyword. + // Since such a condition is present, other critical conditions are filtered out for that entry + res := snc.RunCheck("check_drivesize", []string{"drive=/", "critical='used %' gt 0", "critical=drive eq '/' and 'used_pct' gt 100"}) + assert.Equalf(t, CheckExitOK, res.State, "state should be OK") + + // Filtering does not work here, since the specialized condition is in the warning threshold, not critical threshold + res = snc.RunCheck("check_drivesize", []string{"drive=/", "critical='used %' gt 0", "warning=drive eq '/' and 'used_pct' gt 0"}) + assert.Equalf(t, CheckExitCritical, res.State, "state should be WARNING") + + StopTestAgent(t, snc) +} diff --git a/pkg/snclient/check_temperature.go b/pkg/snclient/check_temperature.go index 12dbc285..2df8df30 100644 --- a/pkg/snclient/check_temperature.go +++ b/pkg/snclient/check_temperature.go @@ -124,14 +124,19 @@ func (l *CheckTemperature) addSensor(check *CheckData, sensor *temperatureStat, minVal := utils.ToPrecision(sensor.Min, 3) maxVal := utils.ToPrecision(sensor.High, 3) + var warning, critical ConditionList + if sensor.Min != 0 || sensor.Critical != 0 { + warning = check.ExpandMetricMacros(check.TransformMultipleKeywords([]string{"temp", "temperature"}, sensorKey, check.warnThreshold), entry) + critical = check.ExpandMetricMacros(check.TransformMultipleKeywords([]string{"temp", "temperature"}, sensorKey, check.critThreshold), entry) + } check.result.Metrics = append(check.result.Metrics, &CheckMetric{ ThresholdName: sensorKey, Name: sensorKey, Value: utils.ToPrecision(sensor.Temperature, 3), Min: &minVal, Max: &maxVal, - Warning: check.ExpandMetricMacros(check.TransformMultipleKeywords([]string{"temp", "temperature"}, sensorKey, check.warnThreshold), entry), - Critical: check.ExpandMetricMacros(check.TransformMultipleKeywords([]string{"temp", "temperature"}, sensorKey, check.critThreshold), entry), + Warning: warning, + Critical: critical, }) check.listData = append(check.listData, entry) diff --git a/pkg/snclient/checkdata.go b/pkg/snclient/checkdata.go index de6f9574..e82df076 100644 --- a/pkg/snclient/checkdata.go +++ b/pkg/snclient/checkdata.go @@ -239,7 +239,8 @@ func (cd *CheckData) finalizeOutput() (*CheckResult, error) { cd.setStateFromMaps(finalMacros) // Metrics are checked last, which also sets the final state log.Tracef("checking warning, critical, and ok thresholds on check metrics") - cd.CheckMetrics(cd.warnThreshold, cd.critThreshold, cd.okThreshold) + // metrics save their own warning and critical thresholds, but ok thresholds come from check itself + cd.CheckMetrics(cd.okThreshold) switch { case cd.result.Output != "": @@ -483,16 +484,16 @@ func (cd *CheckData) Check(data map[string]string, warnCond, critCond, okCond Co } // CheckMetrics tries warn/crit/ok conditions against given metrics and sets final state accordingly -func (cd *CheckData) CheckMetrics(warnCond, critCond, okCond ConditionList) { +func (cd *CheckData) CheckMetrics(okCond ConditionList) { // each metric is ran through conditions individually for _, metric := range cd.result.Metrics { state := CheckExitOK - if metric.CheckForThresholds(&warnCond) { + if metric.CheckForThresholds(&metric.Warning) { state = CheckExitWarning } - if metric.CheckForThresholds(&critCond) { + if metric.CheckForThresholds(&metric.Critical) { state = CheckExitCritical } diff --git a/pkg/snclient/checkmetric.go b/pkg/snclient/checkmetric.go index 737df9bb..c67f4f20 100644 --- a/pkg/snclient/checkmetric.go +++ b/pkg/snclient/checkmetric.go @@ -191,7 +191,7 @@ func (m *CheckMetric) BuildCheckData() (data map[string]string) { return data } -// Metrics have a defined way for specifying key / values +// Returns if at least one condition in the conditionList is found to be correct // //nolint:dogsled // only need corrects list here func (m *CheckMetric) CheckForThresholds(conditionList *ConditionList) (result bool) { @@ -199,5 +199,5 @@ func (m *CheckMetric) CheckForThresholds(conditionList *ConditionList) (result b corrects, _, _, _ := conditionList.performMatches(data, true) - return len(corrects) > 1 + return len(corrects) > 0 }