From 1e72d6558a9ac13b6edad508ed793e6ba761f37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lorenz=20K=C3=A4stle?= Date: Thu, 29 Jun 2023 11:54:13 +0200 Subject: [PATCH] Remove metric sub package --- metric/metric.go | 224 ------------------------------------------ metric/metric_test.go | 170 -------------------------------- 2 files changed, 394 deletions(-) delete mode 100644 metric/metric.go delete mode 100644 metric/metric_test.go diff --git a/metric/metric.go b/metric/metric.go deleted file mode 100644 index e3e9dbc..0000000 --- a/metric/metric.go +++ /dev/null @@ -1,224 +0,0 @@ -package metric - -import ( - "errors" - "fmt" - "github.com/NETWAYS/go-check" - "github.com/NETWAYS/go-check/perfdata" - "regexp" - "strconv" - "strings" -) - -var ( - reThreshold = regexp.MustCompile(`(?i)^(\d+)\s*(%|[TGMK]i?B)?$`) - ErrThresholdInvalid = errors.New("threshold invalid") -) - -const ( - KibiByte uint64 = 1024 - MebiByte = 1024 * KibiByte - GibiByte = 1024 * MebiByte - TebiByte = 1024 * GibiByte -) - -// Metric allows to check a metric for levels specified by its thresholds. -// -// Is currently implemented for byte values in IEC - which is what Nagios plugins use. -type Metric struct { - Value uint64 - Warning uint64 - Critical uint64 - Total uint64 - Type string -} - -// NewMetric returns a new Metric. -// TODO Value can not be greater than Total -func NewMetric(value, total uint64) *Metric { - return &Metric{Value: value, Total: total} -} - -// SetWarning parses warning level for free OR used and remembers the absolute value. -// -// Used: -// Total 100 MB; Threshold 80% => If 80 MB used. Returns warning -// -// Free: -// Total 100MB; Threshold 80% => If 20 MB free. Returns warning -func (m *Metric) SetWarning(threshold string) (err error) { - // TODO Refactor - var thresh uint64 - - switch m.Type { - case "used": - thresh, err = ThresholdUsed(threshold, m.Total) - if err != nil { - return fmt.Errorf("warning: %w", err) - } - case "free": - thresh, err = ThresholdFree(threshold, m.Total) - if err != nil { - return fmt.Errorf("warning: %w", err) - } - default: - return fmt.Errorf("wrong type, please specify 'used' OR 'free'") - } - - m.Warning = thresh - - return nil -} - -// SetCritical parses critical level for free OR used and remembers the absolute value. -// -// Used: -// Total 100 MB; Threshold 90% => If 90 MB used. Returns critical -// -// Free: -// Total 100MB; Threshold 90% => If 10 MB free. Returns critical -func (m *Metric) SetCritical(threshold string) (err error) { - // TODO Refactor - var thresh uint64 - - switch m.Type { - case "used": - thresh, err = ThresholdUsed(threshold, m.Total) - if err != nil { - return fmt.Errorf("critical: %w", err) - } - case "free": - thresh, err = ThresholdFree(threshold, m.Total) - if err != nil { - return fmt.Errorf("critical: %w", err) - } - default: - return fmt.Errorf("wrong type, please specify 'used' OR 'free'") - } - - m.Critical = thresh - - return nil -} - -// Status returns the Icinga status in perspective to the current value and thresholds. -// -// Free: -// Value <= Warning will result in warning state -// Value <= Critical will result in critical state -// -// Used: -// Value >= Warning will result in warning state -// Value >= Critical will result in critical state -func (m *Metric) Status() int { - switch m.Type { - case "used": - if m.Critical > 0 && m.Value >= m.Critical { - return check.Critical - } else if m.Warning > 0 && m.Value >= m.Warning { - return check.Warning - } else { - return check.OK - } - case "free": - if m.Critical > 0 && m.Value <= m.Critical { - return check.Critical - } else if m.Warning > 0 && m.Value <= m.Warning { - return check.Warning - } else { - return check.OK - } - default: - return check.Unknown - } -} - -// Perfdata returns a perfdata.Perfdata object for output with a plugin. -// -// Values are scaled down to MB, so they are more readable. And we won't need that much precision. -func (m *Metric) Perfdata(label string) perfdata.Perfdata { - // TODO If the values are to small, the value will be evaluated as 0 - return perfdata.Perfdata{ - Label: label, - Value: m.Value / MebiByte, - //Value: float64(m.Value) / float64(MebiByte), - Uom: "MB", // Warning: This should be IEC, but Nagios plugins won't know that. - Warn: &check.Threshold{Upper: float64(m.Warning / MebiByte)}, - //Warn: &check.Threshold{Upper: float64(m.Warning) / float64(MebiByte)}, - Crit: &check.Threshold{Upper: float64(m.Critical / MebiByte)}, - //Crit: &check.Threshold{Upper: float64(m.Critical) / float64(MebiByte)}, - Min: 0, - Max: m.Total / MebiByte, - //Max: float64(m.Total) / float64(MebiByte), - } -} - -// ThresholdFree returns the threshold level relative to the total. -// -// 10% free from 100MB = 90MB used -// 15MB free from 100MB = 85MB used -func ThresholdFree(threshold string, total uint64) (uint64, error) { - level, err := ParseThreshold(threshold, total) - if err != nil { - return 0, err - } - - return total - level, nil -} - -// ThresholdUsed returns the threshold level relative to the total. -// -// 90% used from 100MB = 10MB free (available) -// 85MB used from 100MB = 15MB free (available) -func ThresholdUsed(threshold string, total uint64) (uint64, error) { - level, err := ParseThreshold(threshold, total) - if err != nil { - return 0, err - } - - return level, nil -} - -// ParseThreshold returns the parsed unit(UOM) from threshold -// -// Total = 100MB; Threshold = 10% => 10MB -// Total = 100MB; Threshold = 30MB => 30MB -// Viable units are: kb, kib, mb, mib, gb, gib, tb, tib, % -func ParseThreshold(threshold string, total uint64) (uint64, error) { - match := reThreshold.FindStringSubmatch(threshold) - if match == nil { - return 0, ErrThresholdInvalid - } - - value, err := strconv.ParseUint(match[1], 10, 64) - if err != nil { - return 0, err - } - - if match[2] == "%" { - if value > 100 { - return 0, fmt.Errorf("percentage can't be larger than 100") - } - - level := (float64(value) / 100) * float64(total) - - return uint64(level), nil - } - - var level uint64 - - switch u := strings.ToLower(match[2]); u { - case "kb", "kib": - level = value * KibiByte - case "", "mb", "mib": - level = value * MebiByte - case "gb", "gib": - level = value * GibiByte - case "tb", "tib": - level = value * TebiByte - default: - return 0, fmt.Errorf("invalid unit") - } - - return level, nil -} diff --git a/metric/metric_test.go b/metric/metric_test.go deleted file mode 100644 index 315d835..0000000 --- a/metric/metric_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package metric - -import ( - "fmt" - "github.com/NETWAYS/go-check" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestNewMetric(t *testing.T) { - m := NewMetric(10*MebiByte, 100*MebiByte) - - assert.Equal(t, m.Value, 10*MebiByte) - assert.Equal(t, m.Total, 100*MebiByte) -} - -func TestSimpleMetric_SetWarning(t *testing.T) { - m := &Metric{Value: 10 * MebiByte, Total: 100 * MebiByte, Type: "free"} - - err := m.SetWarning("10%") - assert.NoError(t, err) - assert.Equal(t, 90*MebiByte, m.Warning) - - m = &Metric{Value: 90 * MebiByte, Total: 100 * MebiByte, Type: "used"} - - err = m.SetWarning("90%") - assert.NoError(t, err) - assert.Equal(t, 90*MebiByte, m.Warning) -} - -func TestSimpleMetric_SetCritical(t *testing.T) { - m := &Metric{Value: 10 * MebiByte, Total: 100 * MebiByte, Type: "free"} - - err := m.SetCritical("20%") - assert.NoError(t, err) - assert.Equal(t, 80*MebiByte, m.Critical) - - m = &Metric{Value: 80 * MebiByte, Total: 100 * MebiByte, Type: "used"} - - err = m.SetCritical("80%") - assert.NoError(t, err) - assert.Equal(t, 80*MebiByte, m.Critical) -} - -// nolint: dupl -func TestThresholdFree(t *testing.T) { - threshold, err := ThresholdFree("10%", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 90*MebiByte, threshold) - - threshold, err = ThresholdFree("20MB", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 80*MebiByte, threshold) - - threshold, err = ThresholdFree("10", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 90*MebiByte, threshold) - - threshold, err = ThresholdFree("25MiB", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 75*MebiByte, threshold) - - threshold, err = ThresholdFree("25GiB", 100*GibiByte) - assert.NoError(t, err) - assert.Equal(t, 75*GibiByte, threshold) - - threshold, err = ThresholdFree("25TiB", 100*TebiByte) - assert.NoError(t, err) - assert.Equal(t, 75*TebiByte, threshold) - - _, err = ThresholdFree("101%", 100*MebiByte) - if assert.Error(t, err) { - assert.Equal(t, fmt.Errorf("percentage can't be larger than 100"), err) - } - - _, err = ThresholdFree("50Exmaple", 100*MebiByte) - if assert.Error(t, err) { - assert.Equal(t, fmt.Errorf("threshold invalid"), err) - } -} - -// nolint: dupl -func TestThresholdUsed(t *testing.T) { - threshold, err := ThresholdUsed("90%", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 90*MebiByte, threshold) - - threshold, err = ThresholdUsed("80MB", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 80*MebiByte, threshold) - - threshold, err = ThresholdUsed("90", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 90*MebiByte, threshold) - - threshold, err = ThresholdUsed("75MiB", 100*MebiByte) - assert.NoError(t, err) - assert.Equal(t, 75*MebiByte, threshold) - - threshold, err = ThresholdUsed("75GiB", 100*GibiByte) - assert.NoError(t, err) - assert.Equal(t, 75*GibiByte, threshold) - - threshold, err = ThresholdUsed("75TiB", 100*TebiByte) - assert.NoError(t, err) - assert.Equal(t, 75*TebiByte, threshold) - - _, err = ThresholdUsed("101%", 100*MebiByte) - if assert.Error(t, err) { - assert.Equal(t, fmt.Errorf("percentage can't be larger than 100"), err) - } - - _, err = ThresholdUsed("50Exmaple", 100*MebiByte) - if assert.Error(t, err) { - assert.Equal(t, fmt.Errorf("threshold invalid"), err) - } -} - -func TestSimpleMetric_StatusFree(t *testing.T) { - m := &Metric{Value: 30 * MebiByte, Total: 100 * MebiByte, Type: "free"} - err := m.SetCritical("90%") // 10 MB available space - assert.NoError(t, err) - - err = m.SetWarning("80%") // 20 MB available space - assert.NoError(t, err) - assert.Equal(t, check.OK, m.Status()) - - m.Value = 20 * MebiByte - assert.Equal(t, check.Warning, m.Status()) - - m.Value = 10 * MebiByte - assert.Equal(t, check.Critical, m.Status()) -} - -func TestSimpleMetric_StatusUsed(t *testing.T) { - m := &Metric{Value: 79 * MebiByte, Total: 100 * MebiByte, Type: "used"} - err := m.SetCritical("90%") // 10 MB available space - assert.NoError(t, err) - - err = m.SetWarning("80%") // 20 MB available space - assert.NoError(t, err) - - assert.Equal(t, check.OK, m.Status()) - - m.Value = 80 * MebiByte - assert.Equal(t, check.Warning, m.Status()) - - m.Value = 90 * MebiByte - assert.Equal(t, check.Critical, m.Status()) -} - -func TestSimpleMetric_Perfdata(t *testing.T) { - m := &Metric{Value: 10 * MebiByte, Total: 100 * MebiByte, Type: "free"} - err := m.SetCritical("10%") // 10 MB - assert.NoError(t, err) - - err = m.SetWarning("20%") // 20 MB - assert.NoError(t, err) - - assert.Equal(t, "/=10MB;80;90;0;100", m.Perfdata("/").String()) - - m = &Metric{Value: 90 * MebiByte, Total: 100 * MebiByte, Type: "used"} - err = m.SetCritical("90%") - assert.NoError(t, err) - - err = m.SetWarning("80%") - assert.NoError(t, err) - - assert.Equal(t, "/=90MB;80;90;0;100", m.Perfdata("/").String()) -}