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: Admin endpoint for reporting upstream statuses (#4125)
Francis Lavoie committed
Apr 21, 2021 at 15:43 UTC
4d0474e3b8a985f730fadc797066f41bb232bef8
1 file changed
+122
modules/caddyhttp/reverseproxy/admin.go
new
+122
@@ -0,0 +1,122 @@
1
+// Copyright 2015 Matthew Holt and The Caddy Authors
2
+//
3
+// Licensed under the Apache License, Version 2.0 (the "License");
4
+// you may not use this file except in compliance with the License.
5
+// You may obtain a copy of the License at
6
+//
7
+// http://www.apache.org/licenses/LICENSE-2.0
8
+//
9
+// Unless required by applicable law or agreed to in writing, software
10
+// distributed under the License is distributed on an "AS IS" BASIS,
11
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+// See the License for the specific language governing permissions and
13
+// limitations under the License.
14
+
15
+package reverseproxy
16
+
17
+import (
18
+ "encoding/json"
19
+ "fmt"
20
+ "net/http"
21
+
22
+ "github.com/caddyserver/caddy/v2"
23
+)
24
+
25
+func init() {
26
+ caddy.RegisterModule(adminUpstreams{})
27
+}
28
+
29
+// adminUpstreams is a module that provides the
30
+// /reverse_proxy/upstreams endpoint for the Caddy admin
31
+// API. This allows for checking the health of configured
32
+// reverse proxy upstreams in the pool.
33
+type adminUpstreams struct{}
34
+
35
+// upstreamResults holds the status of a particular upstream
36
+type upstreamStatus struct {
37
+ Address string `json:"address"`
38
+ Healthy bool `json:"healthy"`
39
+ NumRequests int `json:"num_requests"`
40
+ Fails int `json:"fails"`
41
+}
42
+
43
+// CaddyModule returns the Caddy module information.
44
+func (adminUpstreams) CaddyModule() caddy.ModuleInfo {
45
+ return caddy.ModuleInfo{
46
+ ID: "admin.api.reverse_proxy",
47
+ New: func() caddy.Module { return new(adminUpstreams) },
48
+ }
49
+}
50
+
51
+// Routes returns a route for the /reverse_proxy/upstreams endpoint.
52
+func (al adminUpstreams) Routes() []caddy.AdminRoute {
53
+ return []caddy.AdminRoute{
54
+ {
55
+ Pattern: "/reverse_proxy/upstreams",
56
+ Handler: caddy.AdminHandlerFunc(al.handleUpstreams),
57
+ },
58
+ }
59
+}
60
+
61
+// handleUpstreams reports the status of the reverse proxy
62
+// upstream pool.
63
+func (adminUpstreams) handleUpstreams(w http.ResponseWriter, r *http.Request) error {
64
+ if r.Method != http.MethodGet {
65
+ return caddy.APIError{
66
+ HTTPStatus: http.StatusMethodNotAllowed,
67
+ Err: fmt.Errorf("method not allowed"),
68
+ }
69
+ }
70
+
71
+ // Prep for a JSON response
72
+ w.Header().Set("Content-Type", "application/json")
73
+ enc := json.NewEncoder(w)
74
+
75
+ // Collect the results to respond with
76
+ results := []upstreamStatus{}
77
+
78
+ // Iterate over the upstream pool (needs to be fast)
79
+ var rangeErr error
80
+ hosts.Range(func(key, val interface{}) bool {
81
+ address, ok := key.(string)
82
+ if !ok {
83
+ rangeErr = caddy.APIError{
84
+ HTTPStatus: http.StatusInternalServerError,
85
+ Err: fmt.Errorf("could not type assert upstream address"),
86
+ }
87
+ return false
88
+ }
89
+
90
+ upstream, ok := val.(*upstreamHost)
91
+ if !ok {
92
+ rangeErr = caddy.APIError{
93
+ HTTPStatus: http.StatusInternalServerError,
94
+ Err: fmt.Errorf("could not type assert upstream struct"),
95
+ }
96
+ return false
97
+ }
98
+
99
+ results = append(results, upstreamStatus{
100
+ Address: address,
101
+ Healthy: !upstream.Unhealthy(),
102
+ NumRequests: upstream.NumRequests(),
103
+ Fails: upstream.Fails(),
104
+ })
105
+ return true
106
+ })
107
+
108
+ // If an error happened during the range, return it
109
+ if rangeErr != nil {
110
+ return rangeErr
111
+ }
112
+
113
+ err := enc.Encode(results)
114
+ if err != nil {
115
+ return caddy.APIError{
116
+ HTTPStatus: http.StatusInternalServerError,
117
+ Err: err,
118
+ }
119
+ }
120
+
121
+ return nil
122
+}