Added cluster/leader endpoint

This commit is contained in:
Alex Antonov 2018-03-22 13:00:05 -04:00 committed by Traefiker Bot
parent 0fa0c2256a
commit 9699dc2a85
3 changed files with 55 additions and 0 deletions

View file

@ -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)
}

View file

@ -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

View file

@ -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)
}
} }
} }