From bd6566eea853c1203ccb04cee1b3b5040d5ace36 Mon Sep 17 00:00:00 2001 From: Hector Date: Sun, 29 Aug 2021 17:05:48 +0100 Subject: [PATCH] new status command Add support for running the `status` command and processing the server response data. Add new metric for the number of jails. --- src/exporter.go | 18 ++++++++++++++++++ src/socket/fail2banSocket.go | 35 +++++++++++++++++++++++++++++++++-- src/socket/protocol.go | 1 + 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/exporter.go b/src/exporter.go index 5d568c3..6dd422f 100644 --- a/src/exporter.go +++ b/src/exporter.go @@ -54,6 +54,11 @@ var ( "Check if the fail2ban server is up", nil, nil, ) + metricJailCount = prometheus.NewDesc( + prometheus.BuildFQName(sockNamespace, "", "jail_count"), + "Number of defined jails", + nil, nil, + ) ) type Exporter struct { @@ -73,6 +78,7 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { } if e.socket != nil { ch <- metricServerPing + ch <- metricJailCount } } @@ -86,6 +92,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) { } if e.socket != nil { e.collectServerPingMetric(ch) + e.collectJailCountMetric(ch) } } @@ -164,6 +171,17 @@ func (e *Exporter) collectServerPingMetric(ch chan<- prometheus.Metric) { ) } +func (e *Exporter) collectJailCountMetric(ch chan<- prometheus.Metric) { + jails, err := e.socket.GetJails() + var count float64 = 0 + if err == nil { + count = float64(len(jails)) + } + ch <- prometheus.MustNewConstMetric( + metricJailCount, prometheus.GaugeValue, count, + ) +} + func printAppVersion() { fmt.Println(version) fmt.Printf(" build date: %s\r\n commit hash: %s\r\n built by: %s\r\n", date, commit, builtBy) diff --git a/src/socket/fail2banSocket.go b/src/socket/fail2banSocket.go index 35513c8..48e2ad6 100644 --- a/src/socket/fail2banSocket.go +++ b/src/socket/fail2banSocket.go @@ -3,7 +3,8 @@ package socket import ( "log" "net" - + "fmt" + "strings" "github.com/kisielk/og-rek" "github.com/nlpodyssey/gopickle/types" ) @@ -37,6 +38,36 @@ func (s *Fail2BanSocket) Ping() bool { } log.Printf("unexpected response data: %s", t) } - log.Printf("unexpected response format - cannot parse: %v", response) + log.Printf("(%s) unexpected response format - cannot parse: %v", pingCommand, response) return false } + +func (s *Fail2BanSocket) GetJails() ([]string, error) { + response, err := s.sendCommand([]string{statusCommand}) + if err != nil { + return nil, err + } + + if lvl1, ok := response.(*types.Tuple); ok { + if lvl2, ok := lvl1.Get(1).(*types.List); ok { + if lvl3, ok := lvl2.Get(1).(*types.Tuple); ok { + if lvl4, ok := lvl3.Get(1).(string); ok { + splitJails := strings.Split(lvl4, ",") + return trimSpaceForAll(splitJails), nil + } + } + } + } + return nil, newBadFormatError(statusCommand, response) +} + +func newBadFormatError(command string, data interface{}) error { + return fmt.Errorf("(%s) unexpected response format - cannot parse: %v", command, data) +} + +func trimSpaceForAll(slice []string) []string { + for i := range slice { + slice[i] = strings.TrimSpace(slice[i]) + } + return slice +} diff --git a/src/socket/protocol.go b/src/socket/protocol.go index 1cf533d..5320f5b 100644 --- a/src/socket/protocol.go +++ b/src/socket/protocol.go @@ -10,6 +10,7 @@ import ( const ( commandTerminator = "" pingCommand = "ping" + statusCommand = "status" socketReadBufferSize = 1024 )