mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-26 13:43:47 +03:00
reverseproxy: Active health checks request body option (#6520)
* Add an option to specify the body used for active health checks * Replacer on request body
This commit is contained in:
parent
043fe41ab8
commit
54a0c8f948
3 changed files with 78 additions and 12 deletions
|
@ -0,0 +1,40 @@
|
||||||
|
:8884
|
||||||
|
|
||||||
|
reverse_proxy 127.0.0.1:65535 {
|
||||||
|
health_uri /health
|
||||||
|
health_request_body "test body"
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":8884"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "reverse_proxy",
|
||||||
|
"health_checks": {
|
||||||
|
"active": {
|
||||||
|
"body": "test body",
|
||||||
|
"uri": "/health"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"upstreams": [
|
||||||
|
{
|
||||||
|
"dial": "127.0.0.1:65535"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,19 +69,20 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
|
||||||
// lb_retry_match <request-matcher>
|
// lb_retry_match <request-matcher>
|
||||||
//
|
//
|
||||||
// # active health checking
|
// # active health checking
|
||||||
// health_uri <uri>
|
// health_uri <uri>
|
||||||
// health_port <port>
|
// health_port <port>
|
||||||
// health_interval <interval>
|
// health_interval <interval>
|
||||||
// health_passes <num>
|
// health_passes <num>
|
||||||
// health_fails <num>
|
// health_fails <num>
|
||||||
// health_timeout <duration>
|
// health_timeout <duration>
|
||||||
// health_status <status>
|
// health_status <status>
|
||||||
// health_body <regexp>
|
// health_body <regexp>
|
||||||
|
// health_method <value>
|
||||||
|
// health_request_body <value>
|
||||||
// health_follow_redirects
|
// health_follow_redirects
|
||||||
// health_headers {
|
// health_headers {
|
||||||
// <field> [<values...>]
|
// <field> [<values...>]
|
||||||
// }
|
// }
|
||||||
// health_method <value>
|
|
||||||
//
|
//
|
||||||
// # passive health checking
|
// # passive health checking
|
||||||
// fail_duration <duration>
|
// fail_duration <duration>
|
||||||
|
@ -425,6 +426,18 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||||
}
|
}
|
||||||
h.HealthChecks.Active.Method = d.Val()
|
h.HealthChecks.Active.Method = d.Val()
|
||||||
|
|
||||||
|
case "health_request_body":
|
||||||
|
if !d.NextArg() {
|
||||||
|
return d.ArgErr()
|
||||||
|
}
|
||||||
|
if h.HealthChecks == nil {
|
||||||
|
h.HealthChecks = new(HealthChecks)
|
||||||
|
}
|
||||||
|
if h.HealthChecks.Active == nil {
|
||||||
|
h.HealthChecks.Active = new(ActiveHealthChecks)
|
||||||
|
}
|
||||||
|
h.HealthChecks.Active.Body = d.Val()
|
||||||
|
|
||||||
case "health_interval":
|
case "health_interval":
|
||||||
if !d.NextArg() {
|
if !d.NextArg() {
|
||||||
return d.ArgErr()
|
return d.ArgErr()
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -93,6 +94,9 @@ type ActiveHealthChecks struct {
|
||||||
// The HTTP method to use for health checks (default "GET").
|
// The HTTP method to use for health checks (default "GET").
|
||||||
Method string `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
|
|
||||||
|
// The body to send with the health check request.
|
||||||
|
Body string `json:"body,omitempty"`
|
||||||
|
|
||||||
// Whether to follow HTTP redirects in response to active health checks (default off).
|
// Whether to follow HTTP redirects in response to active health checks (default off).
|
||||||
FollowRedirects bool `json:"follow_redirects,omitempty"`
|
FollowRedirects bool `json:"follow_redirects,omitempty"`
|
||||||
|
|
||||||
|
@ -396,6 +400,16 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
|
||||||
u.Path = h.HealthChecks.Active.Path
|
u.Path = h.HealthChecks.Active.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replacer used for both body and headers. Only globals (env vars, system info, etc.) are available
|
||||||
|
repl := caddy.NewReplacer()
|
||||||
|
|
||||||
|
// if body is provided, create a reader for it, otherwise nil
|
||||||
|
var requestBody io.Reader
|
||||||
|
if h.HealthChecks.Active.Body != "" {
|
||||||
|
// set body, using replacer
|
||||||
|
requestBody = strings.NewReader(repl.ReplaceAll(h.HealthChecks.Active.Body, ""))
|
||||||
|
}
|
||||||
|
|
||||||
// attach dialing information to this request, as well as context values that
|
// attach dialing information to this request, as well as context values that
|
||||||
// may be expected by handlers of this request
|
// may be expected by handlers of this request
|
||||||
ctx := h.ctx.Context
|
ctx := h.ctx.Context
|
||||||
|
@ -403,15 +417,14 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
|
||||||
ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{
|
ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{
|
||||||
dialInfoVarKey: dialInfo,
|
dialInfoVarKey: dialInfo,
|
||||||
})
|
})
|
||||||
req, err := http.NewRequestWithContext(ctx, h.HealthChecks.Active.Method, u.String(), nil)
|
req, err := http.NewRequestWithContext(ctx, h.HealthChecks.Active.Method, u.String(), requestBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("making request: %v", err)
|
return fmt.Errorf("making request: %v", err)
|
||||||
}
|
}
|
||||||
ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *req)
|
ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *req)
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
|
|
||||||
// set headers, using a replacer with only globals (env vars, system info, etc.)
|
// set headers, using replacer
|
||||||
repl := caddy.NewReplacer()
|
|
||||||
repl.Set("http.reverse_proxy.active.target_upstream", networkAddr)
|
repl.Set("http.reverse_proxy.active.target_upstream", networkAddr)
|
||||||
for key, vals := range h.HealthChecks.Active.Headers {
|
for key, vals := range h.HealthChecks.Active.Headers {
|
||||||
key = repl.ReplaceAll(key, "")
|
key = repl.ReplaceAll(key, "")
|
||||||
|
|
Loading…
Reference in a new issue