@marcel91200 / caddy Mirror · read-only / commits / 75f797de
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

reverseproxy: Implement health_uri, deprecate health_path, supports query (#4050)

* reverseproxy: Implement health_uri, replaces health_path, supports query Also fixes a bug with `health_status` Caddyfile parsing , it would always only take the first character of the status code even if it didn't end with "xx". * reverseproxy: Rename to URI, named logger, warn in Provision (for JSON)

Francis Lavoie committed Mar 29, 2021 at 20:36 UTC 75f797debdd6c4294497edba9889c6251a8542e7
4 files changed +123 -6
caddytest/integration/caddyfile_adapt/reverse_proxy_health_path_query.txt new
+75
@@ -0,0 +1,75 @@
1 +# Health with query in the uri
2 +:8443 {
3 + reverse_proxy localhost:54321 {
4 + health_uri /health?ready=1
5 + health_status 2xx
6 + }
7 +}
8 +
9 +# Health without query in the uri
10 +:8444 {
11 + reverse_proxy localhost:54321 {
12 + health_uri /health
13 + health_status 200
14 + }
15 +}
16 +
17 +----------
18 +{
19 + "apps": {
20 + "http": {
21 + "servers": {
22 + "srv0": {
23 + "listen": [
24 + ":8443"
25 + ],
26 + "routes": [
27 + {
28 + "handle": [
29 + {
30 + "handler": "reverse_proxy",
31 + "health_checks": {
32 + "active": {
33 + "expect_status": 2,
34 + "uri": "/health?ready=1"
35 + }
36 + },
37 + "upstreams": [
38 + {
39 + "dial": "localhost:54321"
40 + }
41 + ]
42 + }
43 + ]
44 + }
45 + ]
46 + },
47 + "srv1": {
48 + "listen": [
49 + ":8444"
50 + ],
51 + "routes": [
52 + {
53 + "handle": [
54 + {
55 + "handler": "reverse_proxy",
56 + "health_checks": {
57 + "active": {
58 + "expect_status": 200,
59 + "uri": "/health"
60 + }
61 + },
62 + "upstreams": [
63 + {
64 + "dial": "localhost:54321"
65 + }
66 + ]
67 + }
68 + ]
69 + }
70 + ]
71 + }
72 + }
73 + }
74 + }
75 +}
modules/caddyhttp/reverseproxy/caddyfile.go
+15 -2
@@ -288,6 +288,18 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
288 }
289 h.LoadBalancing.TryInterval = caddy.Duration(dur)
290
291 + case "health_uri":
292 + if !d.NextArg() {
293 + return d.ArgErr()
294 + }
295 + if h.HealthChecks == nil {
296 + h.HealthChecks = new(HealthChecks)
297 + }
298 + if h.HealthChecks.Active == nil {
299 + h.HealthChecks.Active = new(ActiveHealthChecks)
300 + }
301 + h.HealthChecks.Active.URI = d.Val()
302 +
303 case "health_path":
304 if !d.NextArg() {
305 return d.ArgErr()
@@ -299,6 +311,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
311 h.HealthChecks.Active = new(ActiveHealthChecks)
312 }
313 h.HealthChecks.Active.Path = d.Val()
314 + caddy.Log().Named("config.adapter.caddyfile").Warn("the 'health_path' subdirective is deprecated, please use 'health_uri' instead!")
315
316 case "health_port":
317 if !d.NextArg() {
@@ -382,7 +395,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
395 if len(val) == 3 && strings.HasSuffix(val, "xx") {
396 val = val[:1]
397 }
385 - statusNum, err := strconv.Atoi(val[:1])
398 + statusNum, err := strconv.Atoi(val)
399 if err != nil {
400 return d.Errf("bad status value '%s': %v", d.Val(), err)
401 }
@@ -463,7 +476,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
476 if len(arg) == 3 && strings.HasSuffix(arg, "xx") {
477 arg = arg[:1]
478 }
466 - statusNum, err := strconv.Atoi(arg[:1])
479 + statusNum, err := strconv.Atoi(arg)
480 if err != nil {
481 return d.Errf("bad status value '%s': %v", d.Val(), err)
482 }
modules/caddyhttp/reverseproxy/healthchecks.go
+15 -2
@@ -51,9 +51,13 @@ type HealthChecks struct {
51 // health checks (that is, health checks which occur in a
52 // background goroutine independently).
53 type ActiveHealthChecks struct {
54 - // The URI path to use for health checks.
54 + // The path to use for health checks.
55 + // DEPRECATED: Use 'uri' instead.
56 Path string `json:"path,omitempty"`
57
58 + // The URI (path and query) to use for health checks
59 + URI string `json:"uri,omitempty"`
60 +
61 // The port to use (if different from the upstream's dial
62 // address) for health checks.
63 Port int `json:"port,omitempty"`
@@ -79,6 +83,7 @@ type ActiveHealthChecks struct {
83 // body of a healthy backend.
84 ExpectBody string `json:"expect_body,omitempty"`
85
86 + uri *url.URL
87 httpClient *http.Client
88 bodyRegexp *regexp.Regexp
89 logger *zap.Logger
@@ -218,7 +223,15 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, host H
223 u := &url.URL{
224 Scheme: scheme,
225 Host: hostAddr,
221 - Path: h.HealthChecks.Active.Path,
226 + }
227 +
228 + // if we have a provisioned uri, use that, otherwise use
229 + // the deprecated Path option
230 + if h.HealthChecks.Active.uri != nil {
231 + u.Path = h.HealthChecks.Active.uri.Path
232 + u.RawQuery = h.HealthChecks.Active.uri.RawQuery
233 + } else {
234 + u.Path = h.HealthChecks.Active.Path
235 }
236
237 // adjust the port, if configured to be different
modules/caddyhttp/reverseproxy/reverseproxy.go
+18 -2
@@ -23,6 +23,7 @@ import (
23 "io"
24 "net"
25 "net/http"
26 + "net/url"
27 "regexp"
28 "strconv"
29 "strings"
@@ -273,8 +274,10 @@ func (h *Handler) Provision(ctx caddy.Context) error {
274 }
275
276 // if active health checks are enabled, configure them and start a worker
276 - if h.HealthChecks.Active != nil &&
277 - (h.HealthChecks.Active.Path != "" || h.HealthChecks.Active.Port != 0) {
277 + if h.HealthChecks.Active != nil && (h.HealthChecks.Active.Path != "" ||
278 + h.HealthChecks.Active.URI != "" ||
279 + h.HealthChecks.Active.Port != 0) {
280 +
281 h.HealthChecks.Active.logger = h.logger.Named("health_checker.active")
282
283 timeout := time.Duration(h.HealthChecks.Active.Timeout)
@@ -282,6 +285,19 @@ func (h *Handler) Provision(ctx caddy.Context) error {
285 timeout = 5 * time.Second
286 }
287
288 + if h.HealthChecks.Active.Path != "" {
289 + h.HealthChecks.Active.logger.Warn("the 'path' option is deprecated, please use 'uri' instead!")
290 + }
291 +
292 + // parse the URI string (supports path and query)
293 + if h.HealthChecks.Active.URI != "" {
294 + parsedURI, err := url.Parse(h.HealthChecks.Active.URI)
295 + if err != nil {
296 + return err
297 + }
298 + h.HealthChecks.Active.uri = parsedURI
299 + }
300 +
301 h.HealthChecks.Active.httpClient = &http.Client{
302 Timeout: timeout,
303 Transport: h.Transport,