Skip to content

Commit 6cd928a

Browse files
authored
merge: PR #7 from feature/config
feature/config
2 parents 2f10fdb + da52fb3 commit 6cd928a

File tree

15 files changed

+680
-158
lines changed

15 files changed

+680
-158
lines changed

Makefile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ all: build test
33
# Build the application
44
build:
55
@echo -- Building
6-
@go build -o main.exe cmd/api/main.go
6+
@go build -o whitebox.exe ./cmd/api
77

88
# Run the application
99
run:
10-
@go run cmd/api/main.go
10+
@echo -- Running
11+
@go run ./cmd/api $(filter-out run,$(MAKECMDGOALS))
1112

1213
# Test the application
1314
test:
@@ -17,7 +18,7 @@ test:
1718
# Clean the binary
1819
clean:
1920
@echo -- Cleaning
20-
@rm -f main
21+
@rm -f whitebox
2122

2223
# Live-Reload
2324
watch:
@@ -32,3 +33,6 @@ watch:
3233
}"
3334

3435
.PHONY: all build run test clean watch
36+
37+
%:
38+
@:

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,11 @@ You can configure periodic probes using a simple `curl` command in a cron job or
173173
- [x] CI/CD for basic build/test workflow.
174174
- [x] JSON Subscriptions VPN-url's support.
175175
- [x] AmneziaWG protocol support.
176-
- [ ] Whitebox YAML configuration w/ auto-reload.
176+
- [x] Whitebox YAML configuration w/ auto-reload by SIGHUP.
177+
- [x] Response status/body validation.
178+
- [x] Custom HTTP-headers qualify support.
177179
- [ ] Authorization/OAuth 2.0 support.
178180
- [ ] Configuration for TLS protocol of HTTP probe support.
179-
- [ ] Response status/body validation.
180-
- [ ] Custom HTTP-headers qualify support.
181181
- [ ] More advanced metrics.
182182

183183
## Development

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.4.0
1+
1.0.0

cmd/api/cli.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
import (
4+
"log/slog"
5+
"os"
6+
7+
"github.com/alecthomas/kong"
8+
"github.com/goccy/go-yaml"
9+
"github.com/quyxishi/whitebox/internal/config"
10+
)
11+
12+
type CLI struct {
13+
Version kong.VersionFlag `short:"v" help:"Print version information and exit."`
14+
ConfigPath string `name:"config.file" short:"c" help:"Path to whitebox config file."`
15+
}
16+
17+
func (h *CLI) LoadConfig() (*config.WhiteboxConfig, error) {
18+
// if no config path provided, return default config
19+
if h.ConfigPath == "" {
20+
cfg := config.NewWhiteboxConfig()
21+
return &cfg, nil
22+
}
23+
24+
// if path provided, load from file
25+
file, err := os.Open(h.ConfigPath)
26+
if err != nil {
27+
return nil, err
28+
}
29+
defer func() {
30+
if err := file.Close(); err != nil {
31+
slog.Error("failed to close file instance", "err", err)
32+
}
33+
}()
34+
35+
var config config.WhiteboxConfig
36+
if err := yaml.NewDecoder(file).Decode(&config); err != nil {
37+
return nil, err
38+
}
39+
40+
return &config, nil
41+
}

cmd/api/main.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import (
1010
"syscall"
1111
"time"
1212

13+
"github.com/alecthomas/kong"
14+
"github.com/quyxishi/whitebox"
1315
"github.com/quyxishi/whitebox/internal/api"
16+
"github.com/quyxishi/whitebox/internal/config"
1417
mlog "github.com/quyxishi/whitebox/internal/log"
1518
)
1619

@@ -39,7 +42,48 @@ func gracefulShutdown(apiServer *http.Server, done chan bool) {
3942
done <- true
4043
}
4144

45+
func hotReloadLoop(cli *CLI, configWrapper *config.WhiteboxConfigWrapper) {
46+
sigs := make(chan os.Signal, 1)
47+
signal.Notify(sigs, syscall.SIGHUP)
48+
49+
for {
50+
<-sigs // Listen for the sighup signal.
51+
slog.Info("SIGHUP received, reloading config")
52+
53+
newConfig, err := cli.LoadConfig()
54+
if err != nil {
55+
slog.Error("Unable to reload config file", "err", err)
56+
continue
57+
}
58+
59+
configWrapper.Update(newConfig)
60+
slog.Info("Config updated successfully")
61+
}
62+
}
63+
4264
func main() {
65+
var cli CLI
66+
67+
parser := kong.Must(&cli,
68+
kong.Name("whitebox"),
69+
kong.Description("A Prometheus exporter that provides availability monitoring of external VPN services"),
70+
kong.Vars{
71+
"version": whitebox.Version(),
72+
},
73+
)
74+
75+
_, err := parser.Parse(os.Args[1:])
76+
if err != nil {
77+
parser.FatalIfErrorf(fmt.Errorf("unable to parse cli args due: %w", err))
78+
}
79+
80+
cfg, err := cli.LoadConfig()
81+
if err != nil {
82+
parser.FatalIfErrorf(fmt.Errorf("unable to load config file due: %w", err))
83+
}
84+
85+
wrapper := config.NewConfigWrapper(cfg)
86+
4387
// Initialize the default structured logger writing to stdout
4488
// This configuration is flexible and can be adapted - e.g, by switching to JSON -
4589
// to ensure compatibility with log ingestion and aggregation systems.
@@ -51,17 +95,24 @@ func main() {
5195
handler := mlog.NewModuleHandler(os.Stdout, &opts)
5296
slog.SetDefault(slog.New(handler))
5397

98+
if cli.ConfigPath == "" {
99+
slog.Info("using default configuration (no config path provided)")
100+
} else {
101+
slog.Info("using configuration file w/", slog.Int("scopes", len(cfg.Scopes)), slog.String("path", cli.ConfigPath))
102+
}
103+
54104
// *
55105

56-
server := api.NewServer()
106+
server := api.NewServer(wrapper)
57107

58108
// Create a done channel to signal when the shutdown is complete.
59109
done := make(chan bool, 1)
60110

61111
// Run graceful shutdown in a separate goroutine.
62112
go gracefulShutdown(server, done)
113+
go hotReloadLoop(&cli, wrapper)
63114

64-
err := server.ListenAndServe()
115+
err = server.ListenAndServe()
65116
if err != nil && err != http.ErrServerClosed {
66117
panic(fmt.Sprintf("http server error: %s", err))
67118
}

go.mod

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,32 @@ module github.com/quyxishi/whitebox
33
go 1.25.3
44

55
require (
6+
github.com/alecthomas/kong v1.13.0
67
github.com/gin-contrib/cors v1.7.6
78
github.com/gin-gonic/gin v1.11.0
9+
github.com/goccy/go-yaml v1.19.1
810
github.com/joho/godotenv v1.5.1
911
gopkg.in/ini.v1 v1.67.0
1012
)
1113

1214
require (
13-
github.com/Masterminds/semver/v3 v3.4.0 // indirect
14-
github.com/amnezia-vpn/amneziawg-go v0.2.11 // indirect
15+
cel.dev/expr v0.24.0 // indirect
16+
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
1517
github.com/beorn7/perks v1.0.1 // indirect
1618
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1719
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
18-
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
19-
github.com/goccy/go-yaml v1.19.1 // indirect
20-
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
2120
github.com/mattn/go-colorable v0.1.14 // indirect
2221
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
23-
github.com/onsi/ginkgo/v2 v2.27.2 // indirect
2422
github.com/prometheus/client_model v0.6.2 // indirect
2523
github.com/prometheus/common v0.67.4 // indirect
2624
github.com/prometheus/procfs v0.19.2 // indirect
2725
github.com/quic-go/qpack v0.6.0 // indirect
2826
github.com/rogpeppe/go-internal v1.14.1 // indirect
29-
github.com/tevino/abool/v2 v2.1.0 // indirect
27+
github.com/stoewer/go-strcase v1.2.0 // indirect
3028
go.yaml.in/yaml/v2 v2.4.3 // indirect
29+
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
3130
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect
31+
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect
3232
)
3333

3434
require (
@@ -42,17 +42,17 @@ require (
4242
github.com/cloudflare/circl v1.6.1 // indirect
4343
github.com/cloudwego/base64x v0.1.6 // indirect
4444
github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 // indirect
45-
github.com/emirpasic/gods v1.18.1 // indirect
4645
github.com/fsnotify/fsnotify v1.9.0 // indirect
4746
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
48-
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect
47+
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
4948
github.com/gin-contrib/sse v1.1.0 // indirect
5049
github.com/go-playground/locales v0.14.1 // indirect
5150
github.com/go-playground/universal-translator v0.18.1 // indirect
5251
github.com/go-playground/validator/v10 v10.30.0 // indirect
5352
github.com/goccy/go-json v0.10.5 // indirect
5453
github.com/gogf/gf/v2 v2.9.6
5554
github.com/google/btree v1.1.3 // indirect
55+
github.com/google/cel-go v0.26.1
5656
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
5757
github.com/gvcgo/vpnparser v0.2.7
5858
github.com/json-iterator/go v1.1.12 // indirect
@@ -104,4 +104,4 @@ require (
104104
lukechampine.com/blake3 v1.4.1 // indirect
105105
)
106106

107-
replace gvisor.dev/gvisor => gvisor.dev/gvisor v0.0.0-20250828211149-1f30edfbb5d4
107+
replace gvisor.dev/gvisor => gvisor.dev/gvisor v0.0.0-20250828211149-1f30edfbb5d4

0 commit comments

Comments
 (0)