1
0
Fork 0

Add a method option to the service Health Check

This commit is contained in:
Douglas De Toni Machado 2022-08-08 10:22:07 -03:00 committed by GitHub
parent 2a2ea759d1
commit af749f1864
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 93 additions and 8 deletions

View file

@ -214,6 +214,7 @@ func (s *Server) SetDefaults() {
type ServerHealthCheck struct {
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
Method string `json:"method,omitempty" toml:"method,omitempty" yaml:"method,omitempty" export:"true"`
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty" export:"true"`
// FIXME change string to ptypes.Duration
Interval string `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty" export:"true"`

View file

@ -150,6 +150,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service0.loadbalancer.healthcheck.hostname": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.interval": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.path": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.method": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.port": "42",
"traefik.http.services.Service0.loadbalancer.healthcheck.scheme": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.timeout": "foobar",
@ -165,6 +166,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.healthcheck.hostname": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.interval": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.path": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.method": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.port": "42",
"traefik.http.services.Service1.loadbalancer.healthcheck.scheme": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.timeout": "foobar",
@ -649,6 +651,7 @@ func TestDecodeConfiguration(t *testing.T) {
HealthCheck: &dynamic.ServerHealthCheck{
Scheme: "foobar",
Path: "foobar",
Method: "foobar",
Port: 42,
Interval: "foobar",
Timeout: "foobar",
@ -676,6 +679,7 @@ func TestDecodeConfiguration(t *testing.T) {
HealthCheck: &dynamic.ServerHealthCheck{
Scheme: "foobar",
Path: "foobar",
Method: "foobar",
Port: 42,
Interval: "foobar",
Timeout: "foobar",
@ -1138,6 +1142,7 @@ func TestEncodeConfiguration(t *testing.T) {
HealthCheck: &dynamic.ServerHealthCheck{
Scheme: "foobar",
Path: "foobar",
Method: "foobar",
Port: 42,
Interval: "foobar",
Timeout: "foobar",
@ -1164,6 +1169,7 @@ func TestEncodeConfiguration(t *testing.T) {
HealthCheck: &dynamic.ServerHealthCheck{
Scheme: "foobar",
Path: "foobar",
Method: "foobar",
Port: 42,
Interval: "foobar",
Timeout: "foobar",
@ -1324,6 +1330,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Hostname": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Interval": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Path": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Method": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Port": "42",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Scheme": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Timeout": "foobar",
@ -1339,6 +1346,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Hostname": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Interval": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Path": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Method": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Port": "42",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Scheme": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Timeout": "foobar",

View file

@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"time"
@ -60,6 +61,7 @@ type Options struct {
Hostname string
Scheme string
Path string
Method string
Port int
FollowRedirects bool
Transport http.RoundTripper
@ -69,7 +71,7 @@ type Options struct {
}
func (opt Options) String() string {
return fmt.Sprintf("[Hostname: %s Headers: %v Path: %s Port: %d Interval: %s Timeout: %s FollowRedirects: %v]", opt.Hostname, opt.Headers, opt.Path, opt.Port, opt.Interval, opt.Timeout, opt.FollowRedirects)
return fmt.Sprintf("[Hostname: %s Headers: %v Path: %s Method: %s Port: %d Interval: %s Timeout: %s FollowRedirects: %v]", opt.Hostname, opt.Headers, opt.Path, opt.Method, opt.Port, opt.Interval, opt.Timeout, opt.FollowRedirects)
}
type backendURL struct {
@ -101,8 +103,8 @@ func (b *BackendConfig) newRequest(serverURL *url.URL) (*http.Request, error) {
return http.NewRequest(http.MethodGet, u.String(), http.NoBody)
}
// this function adds additional http headers and hostname to http.request.
func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request {
// setRequestOptions sets all request options present on the BackendConfig.
func (b *BackendConfig) setRequestOptions(req *http.Request) *http.Request {
if b.Options.Hostname != "" {
req.Host = b.Options.Hostname
}
@ -110,6 +112,11 @@ func (b *BackendConfig) addHeadersAndHost(req *http.Request) *http.Request {
for k, v := range b.Options.Headers {
req.Header.Set(k, v)
}
if b.Options.Method != "" {
req.Method = strings.ToUpper(b.Options.Method)
}
return req
}
@ -246,7 +253,7 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
return fmt.Errorf("failed to create HTTP request: %w", err)
}
req = backend.addHeadersAndHost(req)
req = backend.setRequestOptions(req)
client := http.Client{
Timeout: backend.Options.Timeout,

View file

@ -288,13 +288,14 @@ func TestNewRequest(t *testing.T) {
}
}
func TestAddHeadersAndHost(t *testing.T) {
func TestRequestOptions(t *testing.T) {
testCases := []struct {
desc string
serverURL string
options Options
expectedHostname string
expectedHeader string
expectedMethod string
}{
{
desc: "override hostname",
@ -305,6 +306,7 @@ func TestAddHeadersAndHost(t *testing.T) {
},
expectedHostname: "myhost",
expectedHeader: "",
expectedMethod: http.MethodGet,
},
{
desc: "not override hostname",
@ -315,6 +317,7 @@ func TestAddHeadersAndHost(t *testing.T) {
},
expectedHostname: "backend1:80",
expectedHeader: "",
expectedMethod: http.MethodGet,
},
{
desc: "custom header",
@ -326,6 +329,7 @@ func TestAddHeadersAndHost(t *testing.T) {
},
expectedHostname: "backend1:80",
expectedHeader: "foo",
expectedMethod: http.MethodGet,
},
{
desc: "custom header with hostname override",
@ -337,6 +341,17 @@ func TestAddHeadersAndHost(t *testing.T) {
},
expectedHostname: "myhost",
expectedHeader: "foo",
expectedMethod: http.MethodGet,
},
{
desc: "custom method",
serverURL: "http://backend1:80",
options: Options{
Path: "/",
Method: http.MethodHead,
},
expectedHostname: "backend1:80",
expectedMethod: http.MethodHead,
},
}
@ -353,11 +368,12 @@ func TestAddHeadersAndHost(t *testing.T) {
req, err := backend.newRequest(u)
require.NoError(t, err, "failed to create new backend request")
req = backend.addHeadersAndHost(req)
req = backend.setRequestOptions(req)
assert.Equal(t, "http://backend1:80/", req.URL.String())
assert.Equal(t, test.expectedHostname, req.Host)
assert.Equal(t, test.expectedHeader, req.Header.Get("Custom-Header"))
assert.Equal(t, test.expectedMethod, req.Method)
})
}
}

View file

@ -360,6 +360,7 @@ func buildHealthCheckOptions(ctx context.Context, lb healthcheck.Balancer, backe
return &healthcheck.Options{
Scheme: hc.Scheme,
Path: hc.Path,
Method: hc.Method,
Port: hc.Port,
Interval: interval,
Timeout: timeout,