Skip to content

Commit

Permalink
Merge pull request #120 from stefanotorresi/feature/various-improvements
Browse files Browse the repository at this point in the history
Various improvements
  • Loading branch information
stefanotorresi authored Jan 16, 2020
2 parents 34ffe7d + df5b55b commit 8142776
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 390 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Exported data include:
- DRBD resources and connections stats
(note: only DBRD v9 is supported; for v8.4, please refer to the [Prometheus Node Exporter](https://github.com/prometheus/node_exporter) project)

A comprehensive list of all the metrics can be found in the [metrics document](doc/metric_spec.md).
A comprehensive list of all the metrics can be found in the [metrics document](doc/metrics.md).

## Installation

Expand Down
3 changes: 0 additions & 3 deletions corosync_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ type corosyncCollector struct {
}

func (c *corosyncCollector) Collect(ch chan<- prometheus.Metric) {
c.mutex.Lock()
defer c.mutex.Unlock()

log.Infoln("Collecting corosync metrics...")

err := c.collectRingErrorsTotal(ch)
Expand Down
107 changes: 33 additions & 74 deletions corosync_metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"testing"

"github.com/stretchr/testify/assert"
)

// TEST group quorum metrics
Expand Down Expand Up @@ -33,24 +35,11 @@ func TestQuoromMetricParsing(t *testing.T) {
`
voteQuorumInfo, quorate, _ := parseQuoromStatus([]byte(quoromStatus))

if voteQuorumInfo["expected_votes"] != 232 {
t.Errorf("expectedVotes should be 232 got instead: %d", voteQuorumInfo["expectedVotes"])
}
if voteQuorumInfo["highest_expected"] != 22 {
t.Errorf("expectedVotes should be 232 got instead: %d", voteQuorumInfo["highestExpected"])
}

if voteQuorumInfo["total_votes"] != 21 {
t.Errorf("expectedVotes should be 232 got instead: %d", voteQuorumInfo["totalVotes"])
}

if voteQuorumInfo["quorum"] != 421 {
t.Errorf("expectedVotes should be 421 got instead: %d", voteQuorumInfo["quorum"])
}

if quorate != 1 {
t.Errorf("quorate should be 1, got %v", quorate)
}
assert.Equal(t, 232, voteQuorumInfo["expected_votes"])
assert.Equal(t, 22, voteQuorumInfo["highest_expected"])
assert.Equal(t, 21, voteQuorumInfo["total_votes"])
assert.Equal(t, 421, voteQuorumInfo["quorum"])
assert.Equal(t, 1.0, quorate)
}

// TEST group RING metrics
Expand All @@ -67,13 +56,9 @@ func TestOneRingError(t *testing.T) {
`

ringErrorsTotal, err := parseRingStatus([]byte(ringStatusWithOneError))
RingExpectedErrors := 1
if ringErrorsTotal != RingExpectedErrors {
t.Errorf("ringErrors was incorrect, got: %d, expected: %d.", ringErrorsTotal, RingExpectedErrors)
}
if err != nil {
t.Errorf("error should be nil got instead: %s", err)
}

assert.Nil(t, err)
assert.Equal(t, 1, ringErrorsTotal)
}

func TestZeroRingErrors(t *testing.T) {
Expand All @@ -88,13 +73,9 @@ func TestZeroRingErrors(t *testing.T) {
`

ringErrorsTotal, err := parseRingStatus([]byte(ringStatusWithOneError))
RingExpectedErrors := 0
if ringErrorsTotal != RingExpectedErrors {
t.Errorf("ringErrors was incorrect, got: %d, expected: %d.", ringErrorsTotal, RingExpectedErrors)
}
if err != nil {
t.Errorf("error should be nil got instead: %s", err)
}

assert.Nil(t, err)
assert.Equal(t, 0, ringErrorsTotal)
}

// test that we recognize 3 rings error (for increasing metric later)
Expand All @@ -121,73 +102,51 @@ func TestMultipleRingErrors(t *testing.T) {
status = ring 1 active with no faults
`

ringErrorsTotal, err := parseRingStatus([]byte(ringStatusWithOneError))
if err != nil {
t.Error(err)
}

RingExpectedErrors := 3
if ringErrorsTotal != RingExpectedErrors {
t.Errorf("ringErrors was incorrect, got: %d, expected: %d.", ringErrorsTotal, RingExpectedErrors)
}

assert.Nil(t, err)
assert.Equal(t, 3, ringErrorsTotal)
}

func TestRingStatusParsingError(t *testing.T) {
_, err := parseRingStatus([]byte("some error occurred"))
if err == nil {
t.Fatal("a non nil error was expected")
}
if err.Error() != "corosync-cfgtool returned unexpected output: some error occurred" {
t.Errorf("Unexpected error: %v", err)
}

assert.Error(t, err)
assert.Contains(t, err.Error(), "some error occurred")
}

func TestNewCorosyncCollector(t *testing.T) {
_, err := NewCorosyncCollector("test/fake_corosync-cfgtool.sh", "test/fake_corosync-quorumtool.sh")
if err != nil {
t.Errorf("Unexpected error, got: %v", err)
}
assert.Nil(t, err)
}

func TestNewCorosyncCollectorChecksCfgtoolExistence(t *testing.T) {
_, err := NewCorosyncCollector("test/nonexistent", "test/fake_corosync-quorumtool.sh")
if err == nil {
t.Fatal("a non nil error was expected")
}
if err.Error() != "could not initialize Corosync collector: 'test/nonexistent' does not exist" {
t.Errorf("Unexpected error: %v", err)
}

assert.Error(t, err)
assert.Contains(t, err.Error(), "'test/nonexistent' does not exist")
}

func TestNewCorosyncCollectorChecksQuorumtoolExistence(t *testing.T) {

_, err := NewCorosyncCollector("test/fake_corosync-cfgtool.sh", "test/nonexistent")
if err == nil {
t.Fatal("a non nil error was expected")
}
if err.Error() != "could not initialize Corosync collector: 'test/nonexistent' does not exist" {
t.Errorf("Unexpected error: %v", err)
}

assert.Error(t, err)
assert.Contains(t, err.Error(), "'test/nonexistent' does not exist")
}

func TestNewCorosyncCollectorChecksCfgtoolExecutableBits(t *testing.T) {
_, err := NewCorosyncCollector("test/dummy", "test/fake_corosync-quorumtool.sh")
if err == nil {
t.Fatal("a non nil error was expected")
}
if err.Error() != "could not initialize Corosync collector: 'test/dummy' is not executable" {
t.Errorf("Unexpected error: %v", err)
}

assert.Error(t, err)
assert.Contains(t, err.Error(), "'test/dummy' is not executable")
}

func TestNewCorosyncCollectorChecksQuorumtoolExecutableBits(t *testing.T) {
_, err := NewCorosyncCollector("test/fake_corosync-cfgtool.sh", "test/dummy")
if err == nil {
t.Fatal("a non nil error was expected")
}
if err.Error() != "could not initialize Corosync collector: 'test/dummy' is not executable" {
t.Errorf("Unexpected error: %v", err)
}

assert.Error(t, err)
assert.Contains(t, err.Error(), "'test/dummy' is not executable")
}

func TestCorosyncCollector(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion doc/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ To avoid concurrent reads of the same source, all `Collect` methods are serializ

The collectors are very simple: they usually just invoke a bunch of system commands, then parse the output into bespoke data structures that can be used to build Prometheus metrics.

More details about these metrics can be found in the [metrics specification document](metric_spec.md).
More details about these metrics can be found in the [metrics specification document](metrics.md).
File renamed without changes.
8 changes: 2 additions & 6 deletions drbd_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,9 @@ type drbdCollector struct {
}

func (c *drbdCollector) Collect(ch chan<- prometheus.Metric) {
c.mutex.Lock()
defer c.mutex.Unlock()

log.Infoln("Collecting DRBD metrics...")

// set split brain metric
c.setDrbdSplitBrainMetric(ch)
c.recordDrbdSplitBrainMetric(ch)

drbdStatusRaw, err := exec.Command(c.drbdsetupPath, "status", "--json").Output()
if err != nil {
Expand Down Expand Up @@ -169,7 +165,7 @@ func parseDrbdStatus(statusRaw []byte) ([]drbdStatus, error) {
return drbdDevs, nil
}

func (c *drbdCollector) setDrbdSplitBrainMetric(ch chan<- prometheus.Metric) {
func (c *drbdCollector) recordDrbdSplitBrainMetric(ch chan<- prometheus.Metric) {

// set split brain metric
// by default if the custom hook is not set, the exporter will not be able to detect it
Expand Down
Loading

0 comments on commit 8142776

Please sign in to comment.