committed by
GitHub
1 changed files with 122 additions and 0 deletions
@ -0,0 +1,122 @@ |
|||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
|||
//
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
// you may not use this file except in compliance with the License.
|
|||
// You may obtain a copy of the License at
|
|||
//
|
|||
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
//
|
|||
// Unless required by applicable law or agreed to in writing, software
|
|||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
// See the License for the specific language governing permissions and
|
|||
// limitations under the License.
|
|||
|
|||
package reverseproxy |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"fmt" |
|||
"net/http" |
|||
|
|||
"github.com/caddyserver/caddy/v2" |
|||
) |
|||
|
|||
func init() { |
|||
caddy.RegisterModule(adminUpstreams{}) |
|||
} |
|||
|
|||
// adminUpstreams is a module that provides the
|
|||
// /reverse_proxy/upstreams endpoint for the Caddy admin
|
|||
// API. This allows for checking the health of configured
|
|||
// reverse proxy upstreams in the pool.
|
|||
type adminUpstreams struct{} |
|||
|
|||
// upstreamResults holds the status of a particular upstream
|
|||
type upstreamStatus struct { |
|||
Address string `json:"address"` |
|||
Healthy bool `json:"healthy"` |
|||
NumRequests int `json:"num_requests"` |
|||
Fails int `json:"fails"` |
|||
} |
|||
|
|||
// CaddyModule returns the Caddy module information.
|
|||
func (adminUpstreams) CaddyModule() caddy.ModuleInfo { |
|||
return caddy.ModuleInfo{ |
|||
ID: "admin.api.reverse_proxy", |
|||
New: func() caddy.Module { return new(adminUpstreams) }, |
|||
} |
|||
} |
|||
|
|||
// Routes returns a route for the /reverse_proxy/upstreams endpoint.
|
|||
func (al adminUpstreams) Routes() []caddy.AdminRoute { |
|||
return []caddy.AdminRoute{ |
|||
{ |
|||
Pattern: "/reverse_proxy/upstreams", |
|||
Handler: caddy.AdminHandlerFunc(al.handleUpstreams), |
|||
}, |
|||
} |
|||
} |
|||
|
|||
// handleUpstreams reports the status of the reverse proxy
|
|||
// upstream pool.
|
|||
func (adminUpstreams) handleUpstreams(w http.ResponseWriter, r *http.Request) error { |
|||
if r.Method != http.MethodGet { |
|||
return caddy.APIError{ |
|||
HTTPStatus: http.StatusMethodNotAllowed, |
|||
Err: fmt.Errorf("method not allowed"), |
|||
} |
|||
} |
|||
|
|||
// Prep for a JSON response
|
|||
w.Header().Set("Content-Type", "application/json") |
|||
enc := json.NewEncoder(w) |
|||
|
|||
// Collect the results to respond with
|
|||
results := []upstreamStatus{} |
|||
|
|||
// Iterate over the upstream pool (needs to be fast)
|
|||
var rangeErr error |
|||
hosts.Range(func(key, val interface{}) bool { |
|||
address, ok := key.(string) |
|||
if !ok { |
|||
rangeErr = caddy.APIError{ |
|||
HTTPStatus: http.StatusInternalServerError, |
|||
Err: fmt.Errorf("could not type assert upstream address"), |
|||
} |
|||
return false |
|||
} |
|||
|
|||
upstream, ok := val.(*upstreamHost) |
|||
if !ok { |
|||
rangeErr = caddy.APIError{ |
|||
HTTPStatus: http.StatusInternalServerError, |
|||
Err: fmt.Errorf("could not type assert upstream struct"), |
|||
} |
|||
return false |
|||
} |
|||
|
|||
results = append(results, upstreamStatus{ |
|||
Address: address, |
|||
Healthy: !upstream.Unhealthy(), |
|||
NumRequests: upstream.NumRequests(), |
|||
Fails: upstream.Fails(), |
|||
}) |
|||
return true |
|||
}) |
|||
|
|||
// If an error happened during the range, return it
|
|||
if rangeErr != nil { |
|||
return rangeErr |
|||
} |
|||
|
|||
err := enc.Encode(results) |
|||
if err != nil { |
|||
return caddy.APIError{ |
|||
HTTPStatus: http.StatusInternalServerError, |
|||
Err: err, |
|||
} |
|||
} |
|||
|
|||
return nil |
|||
} |
Loading…
Reference in new issue