diff --git a/healthcheck/healthcheck.go b/healthcheck/healthcheck.go index ed70fd9a2..d578b98d0 100644 --- a/healthcheck/healthcheck.go +++ b/healthcheck/healthcheck.go @@ -35,7 +35,7 @@ type Options struct { } func (opt Options) String() string { - return fmt.Sprintf("[Path: %s Interval: %s]", opt.Path, opt.Interval) + return fmt.Sprintf("[Path: %s Port: %d Interval: %s]", opt.Path, opt.Port, opt.Interval) } // BackendHealthCheck HealthCheck configuration for a backend @@ -131,14 +131,14 @@ func checkBackend(currentBackend *BackendHealthCheck) { } func (backend *BackendHealthCheck) newRequest(serverURL *url.URL) (*http.Request, error) { - if backend.Options.Port == 0 { + if backend.Port == 0 { return http.NewRequest("GET", serverURL.String()+backend.Path, nil) } // copy the url and add the port to the host u := &url.URL{} *u = *serverURL - u.Host = net.JoinHostPort(u.Hostname(), strconv.Itoa(backend.Options.Port)) + u.Host = net.JoinHostPort(u.Hostname(), strconv.Itoa(backend.Port)) u.Path = u.Path + backend.Path return http.NewRequest("GET", u.String(), nil) diff --git a/integration/fixtures/healthcheck/port_overload.toml b/integration/fixtures/healthcheck/port_overload.toml new file mode 100644 index 000000000..b3c76db6c --- /dev/null +++ b/integration/fixtures/healthcheck/port_overload.toml @@ -0,0 +1,26 @@ +defaultEntryPoints = ["http"] + +logLevel = "DEBUG" + +[entryPoints] + [entryPoints.http] + address = ":8000" + +[web] + address = ":8080" + +[file] +[backends] + [backends.backend1] + [backends.backend1.healthcheck] + path = "/health" + port = 80 + interval = "1s" + [backends.backend1.servers.server1] + url = "http://{{.Server1}}:81" + +[frontends] + [frontends.frontend1] + backend = "backend1" + [frontends.frontend1.routes.test_1] + rule = "Host:test.localhost" diff --git a/integration/healthcheck_test.go b/integration/healthcheck_test.go index d993c4c7e..c1126eb45 100644 --- a/integration/healthcheck_test.go +++ b/integration/healthcheck_test.go @@ -165,3 +165,50 @@ func (s *HealthCheckSuite) doTestMultipleEntrypoints(c *check.C, fixture string) err = try.Request(frontend1Req, 2*time.Second, try.BodyContains(s.whoami1IP)) c.Assert(err, checker.Not(checker.IsNil)) } + +func (s *HealthCheckSuite) TestPortOverload(c *check.C) { + + // Set one whoami health to 200 + client := &http.Client{} + statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBuffer([]byte("200"))) + c.Assert(err, checker.IsNil) + _, err = client.Do(statusInternalServerErrorReq) + c.Assert(err, checker.IsNil) + + file := s.adaptFile(c, "fixtures/healthcheck/port_overload.toml", struct { + Server1 string + }{s.whoami1IP}) + defer os.Remove(file) + + cmd, display := s.traefikCmd(withConfigFile(file)) + defer display(c) + err = cmd.Start() + c.Assert(err, checker.IsNil) + defer cmd.Process.Kill() + + // wait for traefik + err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("Host:test.localhost")) + c.Assert(err, checker.IsNil) + + frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil) + c.Assert(err, checker.IsNil) + frontendHealthReq.Host = "test.localhost" + + //We test bad gateway because we use an invalid port for the backend + err = try.Request(frontendHealthReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway)) + c.Assert(err, checker.IsNil) + + // Set one whoami health to 500 + statusInternalServerErrorReq, err = http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBuffer([]byte("500"))) + c.Assert(err, checker.IsNil) + _, err = client.Do(statusInternalServerErrorReq) + c.Assert(err, checker.IsNil) + + // Waiting for Traefik healthcheck + try.Sleep(2 * time.Second) + + // Verify no backend service is available due to failing health checks + err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable)) + c.Assert(err, checker.IsNil) + +} diff --git a/server/server.go b/server/server.go index 0f5379d34..7bc45acb9 100644 --- a/server/server.go +++ b/server/server.go @@ -1112,6 +1112,7 @@ func parseHealthCheckOptions(lb healthcheck.LoadBalancer, backend string, hc *ty return &healthcheck.Options{ Path: hc.Path, + Port: hc.Port, Interval: interval, LB: lb, } diff --git a/types/types.go b/types/types.go index 7b8717ca4..1732e5f4d 100644 --- a/types/types.go +++ b/types/types.go @@ -45,6 +45,7 @@ type CircuitBreaker struct { // HealthCheck holds HealthCheck configuration type HealthCheck struct { Path string `json:"path,omitempty"` + Port int `json:"port,omitempty"` Interval string `json:"interval,omitempty"` }