diff options
-rw-r--r-- | modules/caddyhttp/reverseproxy/caddyfile.go | 24 | ||||
-rw-r--r-- | modules/caddyhttp/reverseproxy/healthchecks.go | 28 | ||||
-rw-r--r-- | modules/caddyhttp/reverseproxy/hosts.go | 9 |
3 files changed, 52 insertions, 9 deletions
diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go index ab180b3d8..1c3b49447 100644 --- a/modules/caddyhttp/reverseproxy/caddyfile.go +++ b/modules/caddyhttp/reverseproxy/caddyfile.go @@ -16,6 +16,7 @@ package reverseproxy import ( "fmt" + "net" "net/http" "reflect" "strconv" @@ -354,6 +355,26 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { h.HealthChecks.Active.Path = d.Val() caddy.Log().Named("config.adapter.caddyfile").Warn("the 'health_path' subdirective is deprecated, please use 'health_uri' instead!") + case "health_upstream": + if !d.NextArg() { + return d.ArgErr() + } + if h.HealthChecks == nil { + h.HealthChecks = new(HealthChecks) + } + if h.HealthChecks.Active == nil { + h.HealthChecks.Active = new(ActiveHealthChecks) + } + _, port, err := net.SplitHostPort(d.Val()) + if err != nil { + return d.Errf("health_upstream is malformed '%s': %v", d.Val(), err) + } + _, err = strconv.Atoi(port) + if err != nil { + return d.Errf("bad port number '%s': %v", d.Val(), err) + } + h.HealthChecks.Active.Upstream = d.Val() + case "health_port": if !d.NextArg() { return d.ArgErr() @@ -364,6 +385,9 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if h.HealthChecks.Active == nil { h.HealthChecks.Active = new(ActiveHealthChecks) } + if h.HealthChecks.Active.Upstream != "" { + return d.Errf("the 'health_port' subdirective is ignored if 'health_upstream' is used!") + } portNum, err := strconv.Atoi(d.Val()) if err != nil { return d.Errf("bad port number '%s': %v", d.Val(), err) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index adb1bf5e8..3b5a6a3af 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -75,8 +75,16 @@ type ActiveHealthChecks struct { // The URI (path and query) to use for health checks URI string `json:"uri,omitempty"` + // The host:port to use (if different from the upstream's dial address) + // for health checks. This should be used in tandem with `health_header` and + // `{http.reverse_proxy.active.target_upstream}`. This can be helpful when + // creating an intermediate service to do a more thorough health check. + // If upstream is set, the active health check port is ignored. + Upstream string `json:"upstream,omitempty"` + // The port to use (if different from the upstream's dial - // address) for health checks. + // address) for health checks. If active upstream is set, + // this value is ignored. Port int `json:"port,omitempty"` // HTTP headers to set on health check requests. @@ -173,9 +181,14 @@ func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error { } for _, upstream := range h.Upstreams { - // if there's an alternative port for health-check provided in the config, - // then use it, otherwise use the port of upstream. - if a.Port != 0 { + // if there's an alternative upstream for health-check provided in the config, + // then use it, otherwise use the upstream's dial address. if upstream is used, + // then the port is ignored. + if a.Upstream != "" { + upstream.activeHealthCheckUpstream = a.Upstream + } else if a.Port != 0 { + // if there's an alternative port for health-check provided in the config, + // then use it, otherwise use the port of upstream. upstream.activeHealthCheckPort = a.Port } } @@ -350,7 +363,12 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ if err != nil { host = hostAddr } - if h.HealthChecks.Active.Port != 0 { + + // ignore active health check port if active upstream is provided as the + // active upstream already contains the replacement port + if h.HealthChecks.Active.Upstream != "" { + u.Host = h.HealthChecks.Active.Upstream + } else if h.HealthChecks.Active.Port != 0 { port := strconv.Itoa(h.HealthChecks.Active.Port) u.Host = net.JoinHostPort(host, port) } diff --git a/modules/caddyhttp/reverseproxy/hosts.go b/modules/caddyhttp/reverseproxy/hosts.go index be1146ac9..0a676e431 100644 --- a/modules/caddyhttp/reverseproxy/hosts.go +++ b/modules/caddyhttp/reverseproxy/hosts.go @@ -57,10 +57,11 @@ type Upstream struct { // HeaderAffinity string // IPAffinity string - activeHealthCheckPort int - healthCheckPolicy *PassiveHealthChecks - cb CircuitBreaker - unhealthy int32 // accessed atomically; status from active health checker + activeHealthCheckPort int + activeHealthCheckUpstream string + healthCheckPolicy *PassiveHealthChecks + cb CircuitBreaker + unhealthy int32 // accessed atomically; status from active health checker } // (pointer receiver necessary to avoid a race condition, since |