Added cluster/leader endpoint
This commit is contained in:
parent
0fa0c2256a
commit
9699dc2a85
3 changed files with 55 additions and 0 deletions
|
@ -2,15 +2,22 @@ package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenk/backoff"
|
"github.com/cenk/backoff"
|
||||||
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/log"
|
"github.com/containous/traefik/log"
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
"github.com/docker/leadership"
|
"github.com/docker/leadership"
|
||||||
|
"github.com/unrolled/render"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var templatesRenderer = render.New(render.Options{
|
||||||
|
Directory: "nowhere",
|
||||||
|
})
|
||||||
|
|
||||||
// Leadership allows leadership election using a KV store
|
// Leadership allows leadership election using a KV store
|
||||||
type Leadership struct {
|
type Leadership struct {
|
||||||
*safe.Pool
|
*safe.Pool
|
||||||
|
@ -98,7 +105,32 @@ func (l *Leadership) onElection(elected bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type leaderResponse struct {
|
||||||
|
Leader bool `json:"leader"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Leadership) getLeaderHandler(response http.ResponseWriter, request *http.Request) {
|
||||||
|
leader := &leaderResponse{Leader: l.IsLeader()}
|
||||||
|
|
||||||
|
status := http.StatusOK
|
||||||
|
if !leader.Leader {
|
||||||
|
// Set status to be `429`, as this will typically cause load balancers to stop sending requests to the instance without removing them from rotation.
|
||||||
|
status = http.StatusTooManyRequests
|
||||||
|
}
|
||||||
|
|
||||||
|
err := templatesRenderer.JSON(response, status, leader)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IsLeader returns true if current node is leader
|
// IsLeader returns true if current node is leader
|
||||||
func (l *Leadership) IsLeader() bool {
|
func (l *Leadership) IsLeader() bool {
|
||||||
return l.leader.Get().(bool)
|
return l.leader.Get().(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRoutes add dashboard routes on a router
|
||||||
|
func (l *Leadership) AddRoutes(router *mux.Router) {
|
||||||
|
// Expose cluster leader
|
||||||
|
router.Methods(http.MethodGet).Path("/api/cluster/leader").HandlerFunc(l.getLeaderHandler)
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ For more customization, see [entry points](/configuration/entrypoints/) document
|
||||||
| Path | Method | Description |
|
| Path | Method | Description |
|
||||||
|-----------------------------------------------------------------|------------------|-------------------------------------------|
|
|-----------------------------------------------------------------|------------------|-------------------------------------------|
|
||||||
| `/` | `GET` | Provides a simple HTML frontend of Træfik |
|
| `/` | `GET` | Provides a simple HTML frontend of Træfik |
|
||||||
|
| `/cluster/leader` | `GET` | JSON leader true/false response |
|
||||||
| `/health` | `GET` | JSON health metrics |
|
| `/health` | `GET` | JSON health metrics |
|
||||||
| `/api` | `GET` | Configuration for all providers |
|
| `/api` | `GET` | Configuration for all providers |
|
||||||
| `/api/providers` | `GET` | Providers |
|
| `/api/providers` | `GET` | Providers |
|
||||||
|
@ -222,6 +223,25 @@ curl -s "http://localhost:8080/api" | jq .
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Cluster Leadership
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -s "http://localhost:8080/cluster/leader" | jq .
|
||||||
|
```
|
||||||
|
```shell
|
||||||
|
< HTTP/1.1 200 OK
|
||||||
|
< Content-Type: application/json; charset=UTF-8
|
||||||
|
< Date: xxx
|
||||||
|
< Content-Length: 15
|
||||||
|
```
|
||||||
|
If the given node is not a cluster leader, an HTTP status of `429-Too-Many-Requests` will be returned.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
// current leadership status of the queried node
|
||||||
|
"leader": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Health
|
### Health
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
|
@ -739,6 +739,9 @@ func (s *Server) addInternalRoutes(entryPointName string, router *mux.Router) {
|
||||||
|
|
||||||
if s.globalConfiguration.API != nil && s.globalConfiguration.API.EntryPoint == entryPointName {
|
if s.globalConfiguration.API != nil && s.globalConfiguration.API.EntryPoint == entryPointName {
|
||||||
s.globalConfiguration.API.AddRoutes(router)
|
s.globalConfiguration.API.AddRoutes(router)
|
||||||
|
if s.leadership != nil {
|
||||||
|
s.leadership.AddRoutes(router)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue