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,