Repository: ClusterLabs/ha_cluster_exporter
Pull request #156 (2020-05-27 21:28:51)

support parsing corosync v2.99.0+ output
This is to address this issue https://github.com/ClusterLabs/ha_cluster_exporter/issues/147.


Patch:
diff --git a/collector/corosync/parser.go b/collector/corosync/parser.go
index 7c42c0c..05df8f7 100644
--- a/collector/corosync/parser.go
+++ b/collector/corosync/parser.go
@@ -93,7 +93,7 @@ func parseNodeId(cfgToolOutput []byte) (string, error) {
 }
 
 func parseRingIdAndSeq(cfgToolOutput []byte) (string, uint64, error) {
-	nodeRe := regexp.MustCompile(`(?m)Ring ID:\s+(\w+)/(\d+)`)
+	nodeRe := regexp.MustCompile(`(?m)Ring ID:\s+(\w+)[\.|/](\d+)`)
 	matches := nodeRe.FindSubmatch(cfgToolOutput)
 	if matches == nil {
 		return "", 0, errors.New("could not find Ring ID line")
@@ -128,7 +128,13 @@ func parseRings(cfgToolOutput []byte) []Ring {
 	   	id	= 192.168.125.15
 	   	status	= ring 0 active with no faults
 	*/
-	re := regexp.MustCompile(`(?m)RING ID (?P<number>\d+)\s+id \s*= (?P<address>.+)\s+status \s*= (?P<status>.+)`)
+	// in corosync v2.99.0+ this has changed to
+	/*
+	   Link ID 0
+	   	addr	= 192.168.125.15
+	   	status	= ring 0 active with no faults
+	*/
+	re := regexp.MustCompile(`(?m)(?P<prefix>RING|Link) ID (?P<number>\d+)\s+(?P<id>id|addr) \s*= (?P<address>.+)\s+status \s*= (?P<status>.+)`)
 	matches := re.FindAllSubmatch(cfgToolOutput, -1)
 	rings := make([]Ring, len(matches))
 	for i, match := range matches {


Test patch:
diff --git a/collector/corosync/parser_test.go b/collector/corosync/parser_test.go
index 1d0502d..0650de4 100644
--- a/collector/corosync/parser_test.go
+++ b/collector/corosync/parser_test.go
@@ -10,6 +10,75 @@ import (
 func TestParse(t *testing.T) {
 	p := NewParser()
 
+	cfgToolOutput := []byte(`Printing link status.
+Local node ID 1084780051
+Link ID 0
+		addr      = 10.0.0.1
+		status    = OK
+Link ID 1
+		addr      = 172.16.0.1
+		status    = OK`)
+
+	quoromToolOutput := []byte(`Quorum information
+------------------
+Date:             Sun Sep 29 16:10:37 2019
+Quorum provider:  corosync_votequorum
+Nodes:            2
+Node ID:          1084780051
+Ring ID:          1084780051.44
+Quorate:          Yes
+
+Votequorum information
+----------------------
+Expected votes:   232
+Highest expected: 22
+Total votes:      21
+Quorum:           421  
+Flags:            2Node Quorate WaitForAll 
+
+Membership information
+----------------------
+	Nodeid      Votes Name
+1084780051          1 dma-dog-hana01 (local)
+1084780052          1 dma-dog-hana02`)
+
+	status, err := p.Parse(cfgToolOutput, quoromToolOutput)
+	assert.NoError(t, err)
+
+	rings := status.Rings
+
+	assert.Len(t, rings, 2)
+	assert.Equal(t, "0", rings[0].Number)
+	assert.Equal(t, "10.0.0.1", rings[0].Address)
+	assert.False(t, rings[0].Faulty)
+	assert.Equal(t, "1", rings[1].Number)
+	assert.Equal(t, "172.16.0.1", rings[1].Address)
+	assert.False(t, rings[1].Faulty)
+
+	assert.True(t, status.Quorate)
+	assert.Equal(t, "1084780051", status.NodeId)
+	assert.Equal(t, "1084780051", status.RingId)
+	assert.EqualValues(t, 44, status.Seq)
+	assert.EqualValues(t, 232, status.QuorumVotes.ExpectedVotes)
+	assert.EqualValues(t, 22, status.QuorumVotes.HighestExpected)
+	assert.EqualValues(t, 21, status.QuorumVotes.TotalVotes)
+	assert.EqualValues(t, 421, status.QuorumVotes.Quorum)
+
+	members := status.Members
+	assert.Len(t, members, 2)
+	assert.Exactly(t, "1084780051", members[0].Id)
+	assert.Exactly(t, "dma-dog-hana01", members[0].Name)
+	assert.True(t, members[0].Local)
+	assert.EqualValues(t, 1, members[0].Votes)
+	assert.Exactly(t, "1084780052", members[1].Id)
+	assert.Exactly(t, "dma-dog-hana02", members[1].Name)
+	assert.False(t, members[1].Local)
+	assert.EqualValues(t, 1, members[1].Votes)
+}
+
+func TestLegacyParse(t *testing.T) {
+	p := NewParser()
+
 	cfgToolOutput := []byte(`Printing ring status.
 Local node ID 1084780051
 RING ID 0
@@ -77,6 +146,23 @@ Membership information
 }
 
 func TestParseFaultyRings(t *testing.T) {
+	cfgToolOutput := []byte(`Printing ring status.
+	Local node ID 16777226
+	Link ID 0
+			addr      = 10.0.0.1
+			status  = Marking ringid 0 interface 10.0.0.1 FAULTY
+	Link ID 1
+			addr      = 172.16.0.1
+			status  = ring 1 active with no faults`)
+
+	rings := parseRings(cfgToolOutput)
+
+	assert.Len(t, rings, 2)
+	assert.True(t, rings[0].Faulty)
+	assert.False(t, rings[1].Faulty)
+}
+
+func TestLegacyParseFaultyRings(t *testing.T) {
 	cfgToolOutput := []byte(`Printing ring status.
 	Local node ID 16777226
 	RING ID 0
@@ -130,6 +216,15 @@ func TestParseRingIdEmptyError(t *testing.T) {
 }
 
 func TestParseSeqUintError(t *testing.T) {
+	quoromToolOutput := []byte(`Ring ID:          1084780051.10000000000000000000000000000000000000000000000`)
+
+	_, _, err := parseRingIdAndSeq(quoromToolOutput)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "could not parse seq number to uint64")
+	assert.Contains(t, err.Error(), "value out of range")
+}
+
+func TestParseLegacySeqUintError(t *testing.T) {
 	quoromToolOutput := []byte(`Ring ID:          1084780051/10000000000000000000000000000000000000000000000`)
 
 	_, _, err := parseRingIdAndSeq(quoromToolOutput)