refactor: move server setup code to new package (!90)

* Move code setting up the HTTP server to it's own package
* This helps clean up the `main` function and make it easier to read
* Rename the `BasicAuthMiddleware` to remove reference to Basic since it can now handle any type of auth type

https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/-/merge_requests/90
This commit is contained in:
Hector 2023-06-21 10:58:43 +00:00
parent 41b05f7e16
commit 11c4b26c0b
5 changed files with 72 additions and 46 deletions

View File

@ -3,23 +3,17 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"net/http"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/cfg" "gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/cfg"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/collector/f2b" "gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/collector/f2b"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/collector/textfile" "gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/collector/textfile"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/server" "gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/server"
) )
const (
metricsPath = "/metrics"
)
var ( var (
version = "dev" version = "dev"
commit = "none" commit = "none"
@ -32,26 +26,6 @@ func printAppVersion() {
fmt.Printf(" build date: %s\r\n commit hash: %s\r\n built by: %s\r\n", date, commit, builtBy) fmt.Printf(" build date: %s\r\n commit hash: %s\r\n built by: %s\r\n", date, commit, builtBy)
} }
func rootHtmlHandler(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(
`<html>
<head><title>Fail2Ban Exporter</title></head>
<body>
<h1>Fail2Ban Exporter</h1>
<p><a href="` + metricsPath + `">Metrics</a></p>
</body>
</html>`))
if err != nil {
log.Printf("error handling root url: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
func metricHandler(w http.ResponseWriter, r *http.Request, collector *textfile.Collector) {
promhttp.Handler().ServeHTTP(w, r)
collector.WriteTextFileMetrics(w, r)
}
func main() { func main() {
appSettings := cfg.Parse() appSettings := cfg.Parse()
if appSettings.VersionMode { if appSettings.VersionMode {
@ -67,21 +41,7 @@ func main() {
textFileCollector := textfile.NewCollector(appSettings) textFileCollector := textfile.NewCollector(appSettings)
prometheus.MustRegister(textFileCollector) prometheus.MustRegister(textFileCollector)
http.HandleFunc("/", server.BasicAuthMiddleware(rootHtmlHandler, appSettings.AuthProvider)) svrErr := server.StartServer(appSettings, textFileCollector)
http.HandleFunc(metricsPath, server.BasicAuthMiddleware(
func(w http.ResponseWriter, r *http.Request) {
metricHandler(w, r, textFileCollector)
},
appSettings.AuthProvider,
))
log.Printf("metrics available at '%s'", metricsPath)
svrErr := make(chan error)
go func() {
svrErr <- http.ListenAndServe(appSettings.MetricsAddress, nil)
}()
log.Print("ready")
err := <-svrErr err := <-svrErr
log.Fatal(err) log.Fatal(err)
} }

View File

@ -6,7 +6,7 @@ import (
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/auth" "gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/auth"
) )
func BasicAuthMiddleware(handlerFunc http.HandlerFunc, authProvider auth.AuthProvider) http.HandlerFunc { func AuthMiddleware(handlerFunc http.HandlerFunc, authProvider auth.AuthProvider) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if authProvider.IsAllowed(r) { if authProvider.IsAllowed(r) {
handlerFunc.ServeHTTP(w, r) handlerFunc.ServeHTTP(w, r)

View File

@ -18,13 +18,13 @@ func newTestRequest() *http.Request {
return httptest.NewRequest(http.MethodGet, "http://example.com", nil) return httptest.NewRequest(http.MethodGet, "http://example.com", nil)
} }
func executeBasicAuthMiddlewareTest(t *testing.T, authMatches bool, expectedCode int, expectedCallCount int) { func executeAuthMiddlewareTest(t *testing.T, authMatches bool, expectedCode int, expectedCallCount int) {
callCount := 0 callCount := 0
testHandler := func(w http.ResponseWriter, r *http.Request) { testHandler := func(w http.ResponseWriter, r *http.Request) {
callCount++ callCount++
} }
handler := BasicAuthMiddleware(testHandler, testAuthProvider{match: authMatches}) handler := AuthMiddleware(testHandler, testAuthProvider{match: authMatches})
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
request := newTestRequest() request := newTestRequest()
handler.ServeHTTP(recorder, request) handler.ServeHTTP(recorder, request)
@ -38,9 +38,9 @@ func executeBasicAuthMiddlewareTest(t *testing.T, authMatches bool, expectedCode
} }
func Test_GIVEN_MatchingBasicAuth_WHEN_MethodCalled_THEN_RequestProcessed(t *testing.T) { func Test_GIVEN_MatchingBasicAuth_WHEN_MethodCalled_THEN_RequestProcessed(t *testing.T) {
executeBasicAuthMiddlewareTest(t, true, http.StatusOK, 1) executeAuthMiddlewareTest(t, true, http.StatusOK, 1)
} }
func Test_GIVEN_NonMatchingBasicAuth_WHEN_MethodCalled_THEN_RequestRejected(t *testing.T) { func Test_GIVEN_NonMatchingBasicAuth_WHEN_MethodCalled_THEN_RequestRejected(t *testing.T) {
executeBasicAuthMiddlewareTest(t, false, http.StatusUnauthorized, 0) executeAuthMiddlewareTest(t, false, http.StatusUnauthorized, 0)
} }

33
server/handler.go Normal file
View File

@ -0,0 +1,33 @@
package server
import (
"log"
"net/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/collector/textfile"
)
const (
metricsPath = "/metrics"
)
func rootHtmlHandler(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(
`<html>
<head><title>Fail2Ban Exporter</title></head>
<body>
<h1>Fail2Ban Exporter</h1>
<p><a href="` + metricsPath + `">Metrics</a></p>
</body>
</html>`))
if err != nil {
log.Printf("error handling root url: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
func metricHandler(w http.ResponseWriter, r *http.Request, collector *textfile.Collector) {
promhttp.Handler().ServeHTTP(w, r)
collector.WriteTextFileMetrics(w, r)
}

33
server/server.go Normal file
View File

@ -0,0 +1,33 @@
package server
import (
"log"
"net/http"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/cfg"
"gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/collector/textfile"
)
func StartServer(
appSettings *cfg.AppSettings,
textFileCollector *textfile.Collector,
) chan error {
http.HandleFunc("/", AuthMiddleware(
rootHtmlHandler,
appSettings.AuthProvider,
))
http.HandleFunc(metricsPath, AuthMiddleware(
func(w http.ResponseWriter, r *http.Request) {
metricHandler(w, r, textFileCollector)
},
appSettings.AuthProvider,
))
log.Printf("metrics available at '%s'", metricsPath)
svrErr := make(chan error)
go func() {
svrErr <- http.ListenAndServe(appSettings.MetricsAddress, nil)
}()
log.Print("ready")
return svrErr
}