refactor: replace cli parser with kong (!88)

https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter/-/merge_requests/88
This commit is contained in:
Hector 2023-06-20 20:16:23 +00:00
parent d584345fc6
commit 43cab7adc2
5 changed files with 81 additions and 117 deletions

View file

@ -114,23 +114,29 @@ There are no configuration files.
**CLI flags**
```
usage: exporter [<flags>]
🚀 Collect prometheus metrics from a running Fail2Ban instance
Flags:
-h, --help Show context-sensitive help (also try --help-long and --help-man).
-v, --version show version info and exit
--collector.f2b.socket="/var/run/fail2ban/fail2ban.sock"
path to the fail2ban server socket
--collector.textfile.directory=""
directory to read text files with metrics from
--web.listen-address=":9191"
address to use for the metrics server
--web.basic-auth.username=""
username to use to protect endpoints with basic auth
--web.basic-auth.password=""
password to use to protect endpoints with basic auth
--collector.f2b.exit-on-socket-connection-error
when set to true the exporter will immediately exit on a fail2ban socket connection error
-h, --help Show context-sensitive help.
-v, --version Show version info and exit
--web.listen-address=":9191" Address to use for the metrics server
($F2B_WEB_LISTEN_ADDRESS)
--collector.f2b.socket="/var/run/fail2ban/fail2ban.sock"
Path to the fail2ban server socket
($F2B_COLLECTOR_SOCKET)
--collector.f2b.exit-on-socket-connection-error
When set to true the exporter will immediately
exit on a fail2ban socket connection error
($F2B_EXIT_ON_SOCKET_CONN_ERROR)
--collector.textfile.directory=STRING
Directory to read text files with metrics from
($F2B_COLLECTOR_TEXT_PATH)
--web.basic-auth.username=STRING
Username to use to protect endpoints with basic auth
($F2B_WEB_BASICAUTH_USER)
--web.basic-auth.password=STRING
Password to use to protect endpoints with basic auth
($F2B_WEB_BASICAUTH_PASS)
```
**Environment variables**

View file

@ -2,108 +2,68 @@ package cfg
import (
"fmt"
"github.com/alecthomas/kingpin/v2"
"os"
"github.com/alecthomas/kong"
)
const (
socketEnvName = "F2B_COLLECTOR_SOCKET"
fileCollectorPathEnvName = "F2B_COLLECTOR_TEXT_PATH"
addressEnvName = "F2B_WEB_LISTEN_ADDRESS"
basicAuthUserEnvName = "F2B_WEB_BASICAUTH_USER"
basicAuthPassEnvName = "F2B_WEB_BASICAUTH_PASS"
exitOnSocketConnErrorEnvName = "F2B_EXIT_ON_SOCKET_CONN_ERROR"
)
type AppSettings struct {
VersionMode bool
MetricsAddress string
Fail2BanSocketPath string
FileCollectorPath string
BasicAuthProvider *hashedBasicAuth
ExitOnSocketConnError bool
}
func init() {
kingpin.HelpFlag.Short('h')
var cliStruct struct {
VersionMode bool `name:"version" short:"v" help:"Show version info and exit"`
ServerAddress string `name:"web.listen-address" env:"F2B_WEB_LISTEN_ADDRESS" help:"Address to use for the metrics server" default:"${default_address}"`
F2bSocketPath string `name:"collector.f2b.socket" env:"F2B_COLLECTOR_SOCKET" help:"Path to the fail2ban server socket" default:"${default_socket}"`
ExitOnSocketError bool `name:"collector.f2b.exit-on-socket-connection-error" env:"F2B_EXIT_ON_SOCKET_CONN_ERROR" help:"When set to true the exporter will immediately exit on a fail2ban socket connection error"`
TextFileExporterPath string `name:"collector.textfile.directory" env:"F2B_COLLECTOR_TEXT_PATH" help:"Directory to read text files with metrics from"`
BasicAuthUser string `name:"web.basic-auth.username" env:"F2B_WEB_BASICAUTH_USER" help:"Username to use to protect endpoints with basic auth"`
BasicAuthPass string `name:"web.basic-auth.password" env:"F2B_WEB_BASICAUTH_PASS" help:"Password to use to protect endpoints with basic auth"`
}
func Parse() *AppSettings {
settings := &AppSettings{}
readParamsFromCli(settings)
settings.validateFlags()
ctx := kong.Parse(
&cliStruct,
kong.Vars{
"default_socket": "/var/run/fail2ban/fail2ban.sock",
"default_address": ":9191",
},
kong.Name("fail2ban_exporter"),
kong.Description("🚀 Export prometheus metrics from a running Fail2Ban instance"),
kong.UsageOnError(),
)
validateFlags(ctx)
settings := &AppSettings{
VersionMode: cliStruct.VersionMode,
MetricsAddress: cliStruct.ServerAddress,
Fail2BanSocketPath: cliStruct.F2bSocketPath,
FileCollectorPath: cliStruct.TextFileExporterPath,
ExitOnSocketConnError: cliStruct.ExitOnSocketError,
BasicAuthProvider: newHashedBasicAuth(cliStruct.BasicAuthUser, cliStruct.BasicAuthPass),
}
return settings
}
func readParamsFromCli(settings *AppSettings) {
versionMode := kingpin.
Flag("version", "show version info and exit").
Short('v').
Default("false").
Bool()
socketPath := kingpin.
Flag("collector.f2b.socket", "path to the fail2ban server socket").
Default("/var/run/fail2ban/fail2ban.sock").
Envar(socketEnvName).
String()
fileCollectorPath := kingpin.
Flag("collector.textfile.directory", "directory to read text files with metrics from").
Default("").
Envar(fileCollectorPathEnvName).
String()
address := kingpin.
Flag("web.listen-address", "address to use for the metrics server").
Default(":9191").
Envar(addressEnvName).
String()
rawBasicAuthUsername := kingpin.
Flag("web.basic-auth.username", "username to use to protect endpoints with basic auth").
Default("").
Envar(basicAuthUserEnvName).
String()
rawBasicAuthPassword := kingpin.
Flag("web.basic-auth.password", "password to use to protect endpoints with basic auth").
Default("").
Envar(basicAuthPassEnvName).
String()
rawExitOnSocketConnError := kingpin.
Flag("collector.f2b.exit-on-socket-connection-error", "when set to true the exporter will immediately exit on a fail2ban socket connection error").
Default("false").
Envar(exitOnSocketConnErrorEnvName).
Bool()
kingpin.Parse()
settings.VersionMode = *versionMode
settings.MetricsAddress = *address
settings.Fail2BanSocketPath = *socketPath
settings.FileCollectorPath = *fileCollectorPath
settings.setBasicAuthValues(*rawBasicAuthUsername, *rawBasicAuthPassword)
settings.ExitOnSocketConnError = *rawExitOnSocketConnError
}
func (settings *AppSettings) setBasicAuthValues(rawUsername, rawPassword string) {
settings.BasicAuthProvider = newHashedBasicAuth(rawUsername, rawPassword)
}
func (settings *AppSettings) validateFlags() {
func validateFlags(cliCtx *kong.Context) {
var flagsValid = true
if !settings.VersionMode {
if settings.Fail2BanSocketPath == "" {
fmt.Println("error: fail2ban socket path must not be blank")
var messages = []string{}
if !cliStruct.VersionMode {
if cliStruct.F2bSocketPath == "" {
messages = append(messages, "error: fail2ban socket path must not be blank")
flagsValid = false
}
if settings.MetricsAddress == "" {
fmt.Println("error: invalid server address, must not be blank")
if cliStruct.ServerAddress == "" {
messages = append(messages, "error: invalid server address, must not be blank")
flagsValid = false
}
if (len(settings.BasicAuthProvider.username) > 0) != (len(settings.BasicAuthProvider.password) > 0) {
fmt.Println("error: to enable basic auth both the username and the password must be provided")
if (len(cliStruct.BasicAuthUser) > 0) != (len(cliStruct.BasicAuthPass) > 0) {
messages = append(messages, "error: to enable basic auth both the username and the password must be provided")
flagsValid = false
}
}
if !flagsValid {
kingpin.Usage()
cliCtx.PrintUsage(false)
fmt.Println()
for i := 0; i < len(messages); i++ {
fmt.Println(messages[i])
}
os.Exit(1)
}
}

10
cfg/settings.go Normal file
View file

@ -0,0 +1,10 @@
package cfg
type AppSettings struct {
VersionMode bool
MetricsAddress string
Fail2BanSocketPath string
FileCollectorPath string
BasicAuthProvider *hashedBasicAuth
ExitOnSocketConnError bool
}

4
go.mod
View file

@ -3,14 +3,13 @@ module gitlab.com/hectorjsmith/fail2ban-prometheus-exporter
go 1.20
require (
github.com/alecthomas/kingpin/v2 v2.3.2
github.com/alecthomas/kong v0.7.1
github.com/kisielk/og-rek v1.2.0
github.com/nlpodyssey/gopickle v0.2.0
github.com/prometheus/client_golang v1.16.0
)
require (
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
@ -18,7 +17,6 @@ require (
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.0 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
golang.org/x/sys v0.9.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
)

20
go.sum
View file

@ -1,12 +1,11 @@
github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@ -14,14 +13,13 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/kisielk/og-rek v1.2.0 h1:CTvDIin+YnetsSQAYbe+QNAxXU3B50C5hseEz8xEoJw=
github.com/kisielk/og-rek v1.2.0/go.mod h1:6ihsOSzSAxR/65S3Bn9zNihoEqRquhDQZ2c6I2+MG3c=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/nlpodyssey/gopickle v0.2.0 h1:4naD2DVylYJupQLbCQFdwo6yiXEmPyp+0xf5MVlrBDY=
github.com/nlpodyssey/gopickle v0.2.0/go.mod h1:YIUwjJ2O7+vnBsxUN+MHAAI3N+adqEGiw+nDpwW95bY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
@ -30,11 +28,6 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk=
github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -43,6 +36,3 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=