rproxy and servewaf replace the one-process smallwebwaf (closes #172, closes #165)
check / check (push) Failing after 14m44s
check / check (push) Failing after 14m44s
`smallwebwaf` with no command now prints the commands and exits with status 2. The image runs rproxy, or servewaf with SMALLWEBWAF_COMMAND=servewaf. The passing-on code, its settings and its log fields and metric go. internal/proxy keeps the checks, answers, reports and own endpoints; its tests run through the real rproxy. The documents describe the pair. Judgement call: clients.json keeps token_refused, since state files refuse unknown fields. Deviation: script/gitea-requests sets SWWAF_LOG_REQUEST_HEADERS, to label requests. Partially verified: make example-app and make gitea-requests never built the image, as Ubuntu's snapshot service answered 5xx. Model: opus-5-5
This commit was merged in pull request #184.
This commit is contained in:
1 parent
17c5dd2438
commit
344ce13c96
71 files changed
+2653
-5493
No files matched your search
@@ -17,13 +17,16 @@ import (
|
||||
// healthCheckTimeout bounds the whole health check.
|
||||
const healthCheckTimeout = 5 * time.Second
|
||||
|
||||
var errHealthEndpoint = errors.New("smallwebwaf's health endpoint answered")
|
||||
var errHealthEndpoint = errors.New("the health endpoint answered")
|
||||
|
||||
// HealthCheck is the container's health check. It returns 0 while
|
||||
// smallwebwaf answers its health endpoint on 127.0.0.1, at the port in
|
||||
// SWWAF_LISTEN_ADDR, and the app accepts connections at the address in
|
||||
// SWWAF_UPSTREAM_URL. Otherwise it writes why to stderr and returns 1.
|
||||
// It reads no other setting, nor a file that another names, so neither
|
||||
// HealthCheck is the container's health check. In servewaf's container, where
|
||||
// SMALLWEBWAF_COMMAND is servewaf, it returns 0 while servewaf answers its health
|
||||
// endpoint on 127.0.0.1, at the port in SWWAF_LISTEN_ADDR. In rproxy's container,
|
||||
// where SMALLWEBWAF_COMMAND is rproxy, unset or empty, it returns 0 while rproxy
|
||||
// answers its health endpoint on 127.0.0.1, at the port in SWRP_LISTEN_ADDR, and
|
||||
// the app accepts connections at the address in SWRP_UPSTREAM_URL. Otherwise,
|
||||
// any other value of SMALLWEBWAF_COMMAND included, it writes why to stderr and
|
||||
// returns 1. It reads no other setting, nor a file that another names, so neither
|
||||
// can fail it.
|
||||
// args are the arguments after `healthcheck`; it takes none, and given
|
||||
// one it names it on stderr and returns 1 without checking anything.
|
||||
@@ -38,7 +41,20 @@ func HealthCheck(
|
||||
return 1
|
||||
}
|
||||
|
||||
err := healthCheck(ctx, lookupEnv)
|
||||
ctx, cancel := context.WithTimeout(ctx, healthCheckTimeout)
|
||||
defer cancel()
|
||||
|
||||
command, err := config.Command(lookupEnv)
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
err = fmt.Errorf("invalid setting: %w", err)
|
||||
case command == "servewaf":
|
||||
err = checkServeWAF(ctx, lookupEnv)
|
||||
default:
|
||||
err = checkRProxyAndApp(ctx, lookupEnv)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(stderr, "unhealthy:", err)
|
||||
|
||||
@@ -48,16 +64,48 @@ func HealthCheck(
|
||||
return 0
|
||||
}
|
||||
|
||||
func healthCheck(ctx context.Context, lookupEnv func(string) (string, bool)) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, healthCheckTimeout)
|
||||
defer cancel()
|
||||
|
||||
listenAddr, upstreamURL, err := config.ListenAddrAndUpstreamURL(lookupEnv)
|
||||
// checkServeWAF asks servewaf's health endpoint.
|
||||
func checkServeWAF(ctx context.Context, lookupEnv func(string) (string, bool)) error {
|
||||
listenAddr, err := config.ServeWAFListenAddr(lookupEnv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid setting: %w", err)
|
||||
}
|
||||
|
||||
// The settings have checked that the address has a port.
|
||||
err = askHealthEndpoint(ctx, listenAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ask servewaf: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkRProxyAndApp asks rproxy's health endpoint, and connects to the app.
|
||||
func checkRProxyAndApp(
|
||||
ctx context.Context, lookupEnv func(string) (string, bool),
|
||||
) error {
|
||||
listenAddr, upstreamURL, err := config.RProxyListenAddrAndUpstreamURL(lookupEnv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid setting: %w", err)
|
||||
}
|
||||
|
||||
err = askHealthEndpoint(ctx, listenAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ask rproxy: %w", err)
|
||||
}
|
||||
|
||||
conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", appAddress(upstreamURL))
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect to the app: %w", err)
|
||||
}
|
||||
|
||||
_ = conn.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// askHealthEndpoint asks the health endpoint on 127.0.0.1 at the port of
|
||||
// listenAddr, which the settings have checked has one.
|
||||
func askHealthEndpoint(ctx context.Context, listenAddr string) error {
|
||||
_, port, _ := net.SplitHostPort(listenAddr)
|
||||
health := "http://" + net.JoinHostPort("127.0.0.1", port) + proxy.HealthPath
|
||||
|
||||
@@ -68,7 +116,7 @@ func healthCheck(ctx context.Context, lookupEnv func(string) (string, bool)) err
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ask smallwebwaf: %w", err)
|
||||
return fmt.Errorf("send the request: %w", err)
|
||||
}
|
||||
|
||||
_ = res.Body.Close()
|
||||
@@ -77,13 +125,6 @@ func healthCheck(ctx context.Context, lookupEnv func(string) (string, bool)) err
|
||||
return fmt.Errorf("%w %s", errHealthEndpoint, res.Status)
|
||||
}
|
||||
|
||||
conn, err := (&net.Dialer{}).DialContext(ctx, "tcp", appAddress(upstreamURL))
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect to the app: %w", err)
|
||||
}
|
||||
|
||||
_ = conn.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user