Add global health check interval parameter.

The new parameter allows to set a health check interval valid for all
backends. Custom values set per provider may override the global one.
This commit is contained in:
Timo Reimann 2017-03-24 09:36:33 +01:00
parent ce492895e2
commit 25345427c3
6 changed files with 71 additions and 12 deletions

View file

@ -269,6 +269,27 @@ Supported filters:
# attempts = 3 # attempts = 3
``` ```
## Health check configuration
```toml
# Enable custom health check options.
#
# Optional
#
[healthcheck]
# Set the default health check interval. Will only be effective if health check
# paths are defined. Given provider-specific support, the value may be
# overridden on a per-backend basis.
# Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw
# values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: "30s"
#
# interval = "30s"
```
## ACME (Let's Encrypt) configuration ## ACME (Let's Encrypt) configuration
```toml ```toml

View file

@ -2,6 +2,7 @@ package healthcheck
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"sync" "sync"
@ -12,9 +13,6 @@ import (
"github.com/vulcand/oxy/roundrobin" "github.com/vulcand/oxy/roundrobin"
) )
// DefaultInterval is the default health check interval.
const DefaultInterval = 30 * time.Second
var singleton *HealthCheck var singleton *HealthCheck
var once sync.Once var once sync.Once
@ -33,6 +31,10 @@ type Options struct {
LB LoadBalancer LB LoadBalancer
} }
func (opt Options) String() string {
return fmt.Sprintf("[Path: %s Interval: %s]", opt.Path, opt.Interval)
}
// BackendHealthCheck HealthCheck configuration for a backend // BackendHealthCheck HealthCheck configuration for a backend
type BackendHealthCheck struct { type BackendHealthCheck struct {
Options Options

View file

@ -27,6 +27,9 @@ import (
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
) )
// DefaultHealthCheckInterval is the default health check interval.
const DefaultHealthCheckInterval = 30 * time.Second
// TraefikConfiguration holds GlobalConfiguration and other stuff // TraefikConfiguration holds GlobalConfiguration and other stuff
type TraefikConfiguration struct { type TraefikConfiguration struct {
GlobalConfiguration `mapstructure:",squash"` GlobalConfiguration `mapstructure:",squash"`
@ -52,6 +55,7 @@ type GlobalConfiguration struct {
IdleTimeout flaeg.Duration `description:"maximum amount of time an idle (keep-alive) connection will remain idle before closing itself."` IdleTimeout flaeg.Duration `description:"maximum amount of time an idle (keep-alive) connection will remain idle before closing itself."`
InsecureSkipVerify bool `description:"Disable SSL certificate verification"` InsecureSkipVerify bool `description:"Disable SSL certificate verification"`
Retry *Retry `description:"Enable retry sending request if network error"` Retry *Retry `description:"Enable retry sending request if network error"`
HealthCheck *HealthCheckConfig `description:"Health check parameters"`
Docker *docker.Provider `description:"Enable Docker backend"` Docker *docker.Provider `description:"Enable Docker backend"`
File *file.Provider `description:"Enable File backend"` File *file.Provider `description:"Enable File backend"`
Web *WebProvider `description:"Enable Web backend"` Web *WebProvider `description:"Enable Web backend"`
@ -337,6 +341,11 @@ type Retry struct {
Attempts int `description:"Number of attempts"` Attempts int `description:"Number of attempts"`
} }
// HealthCheckConfig contains health check configuration parameters.
type HealthCheckConfig struct {
Interval flaeg.Duration `description:"Default periodicity of enabled health checks"`
}
// NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values // NewTraefikDefaultPointersConfiguration creates a TraefikConfiguration with pointers default values
func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
//default Docker //default Docker
@ -461,6 +470,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
Rancher: &defaultRancher, Rancher: &defaultRancher,
DynamoDB: &defaultDynamoDB, DynamoDB: &defaultDynamoDB,
Retry: &Retry{}, Retry: &Retry{},
HealthCheck: &HealthCheckConfig{},
} }
//default Rancher //default Rancher
@ -485,6 +495,9 @@ func NewTraefikConfiguration() *TraefikConfiguration {
ProvidersThrottleDuration: flaeg.Duration(2 * time.Second), ProvidersThrottleDuration: flaeg.Duration(2 * time.Second),
MaxIdleConnsPerHost: 200, MaxIdleConnsPerHost: 200,
IdleTimeout: flaeg.Duration(180 * time.Second), IdleTimeout: flaeg.Duration(180 * time.Second),
HealthCheck: &HealthCheckConfig{
Interval: flaeg.Duration(DefaultHealthCheckInterval),
},
CheckNewVersion: true, CheckNewVersion: true,
}, },
ConfigFile: "", ConfigFile: "",

View file

@ -659,8 +659,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
log.Errorf("Skipping frontend %s...", frontendName) log.Errorf("Skipping frontend %s...", frontendName)
continue frontend continue frontend
} }
hcOpts := parseHealthCheckOptions(rebalancer, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck) hcOpts := parseHealthCheckOptions(rebalancer, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck)
if hcOpts != nil { if hcOpts != nil {
log.Debugf("Setting up backend health check %s", *hcOpts)
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts)
} }
} }
@ -685,8 +686,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
continue frontend continue frontend
} }
} }
hcOpts := parseHealthCheckOptions(rr, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck) hcOpts := parseHealthCheckOptions(rr, frontend.Backend, configuration.Backends[frontend.Backend].HealthCheck, *globalConfiguration.HealthCheck)
if hcOpts != nil { if hcOpts != nil {
log.Debugf("Setting up backend health check %s", *hcOpts)
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts) backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts)
} }
} }
@ -847,12 +849,12 @@ func (server *Server) buildDefaultHTTPRouter() *mux.Router {
return router return router
} }
func parseHealthCheckOptions(lb healthcheck.LoadBalancer, backend string, hc *types.HealthCheck) *healthcheck.Options { func parseHealthCheckOptions(lb healthcheck.LoadBalancer, backend string, hc *types.HealthCheck, hcConfig HealthCheckConfig) *healthcheck.Options {
if hc == nil || hc.Path == "" { if hc == nil || hc.Path == "" {
return nil return nil
} }
interval := healthcheck.DefaultInterval interval := time.Duration(hcConfig.Interval)
if hc.Interval != "" { if hc.Interval != "" {
intervalOverride, err := time.ParseDuration(hc.Interval) intervalOverride, err := time.ParseDuration(hc.Interval)
switch { switch {

View file

@ -7,6 +7,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/containous/flaeg"
"github.com/containous/traefik/healthcheck" "github.com/containous/traefik/healthcheck"
"github.com/containous/traefik/types" "github.com/containous/traefik/types"
"github.com/vulcand/oxy/roundrobin" "github.com/vulcand/oxy/roundrobin"
@ -41,6 +42,7 @@ func TestServerLoadConfigHealthCheckOptions(t *testing.T) {
EntryPoints: EntryPoints{ EntryPoints: EntryPoints{
"http": &EntryPoint{}, "http": &EntryPoint{},
}, },
HealthCheck: &HealthCheckConfig{Interval: flaeg.Duration(5 * time.Second)},
} }
dynamicConfigs := configs{ dynamicConfigs := configs{
@ -87,6 +89,7 @@ func TestServerLoadConfigHealthCheckOptions(t *testing.T) {
func TestServerParseHealthCheckOptions(t *testing.T) { func TestServerParseHealthCheckOptions(t *testing.T) {
lb := &testLoadBalancer{} lb := &testLoadBalancer{}
globalInterval := 15 * time.Second
tests := []struct { tests := []struct {
desc string desc string
@ -113,7 +116,7 @@ func TestServerParseHealthCheckOptions(t *testing.T) {
}, },
wantOpts: &healthcheck.Options{ wantOpts: &healthcheck.Options{
Path: "/path", Path: "/path",
Interval: healthcheck.DefaultInterval, Interval: globalInterval,
LB: lb, LB: lb,
}, },
}, },
@ -121,11 +124,11 @@ func TestServerParseHealthCheckOptions(t *testing.T) {
desc: "sub-zero interval", desc: "sub-zero interval",
hc: &types.HealthCheck{ hc: &types.HealthCheck{
Path: "/path", Path: "/path",
Interval: "-15s", Interval: "-42s",
}, },
wantOpts: &healthcheck.Options{ wantOpts: &healthcheck.Options{
Path: "/path", Path: "/path",
Interval: healthcheck.DefaultInterval, Interval: globalInterval,
LB: lb, LB: lb,
}, },
}, },
@ -148,7 +151,7 @@ func TestServerParseHealthCheckOptions(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
gotOpts := parseHealthCheckOptions(lb, "backend", test.hc) gotOpts := parseHealthCheckOptions(lb, "backend", test.hc, HealthCheckConfig{Interval: flaeg.Duration(globalInterval)})
if !reflect.DeepEqual(gotOpts, test.wantOpts) { if !reflect.DeepEqual(gotOpts, test.wantOpts) {
t.Errorf("got health check options %+v, want %+v", gotOpts, test.wantOpts) t.Errorf("got health check options %+v, want %+v", gotOpts, test.wantOpts)
} }

View file

@ -311,6 +311,24 @@
# #
# attempts = 3 # attempts = 3
# Enable custom health check options.
#
# Optional
#
# [healthcheck]
# Set the default health check interval. Will only be effective if health check
# paths are defined. Given provider-specific support, the value may be
# overridden on a per-backend basis.
# Can be provided in a format supported by Go's time.ParseDuration function or
# as raw values (digits). If no units are provided, the value is parsed assuming
# seconds.
#
# Optional
# Default: "30s"
#
# interval = "30s"
################################################################ ################################################################
# Web configuration backend # Web configuration backend
################################################################ ################################################################