2017-07-06 17:28:13 +03:00
package integration
2017-02-07 01:00:54 +03:00
import (
"bytes"
"net/http"
"os"
"time"
"github.com/go-check/check"
2020-09-16 16:46:04 +03:00
"github.com/traefik/traefik/v2/integration/try"
2017-02-07 01:00:54 +03:00
checker "github.com/vdemeester/shakers"
)
2020-05-11 13:06:07 +03:00
// HealthCheck test suites (using libcompose).
2017-08-10 19:00:31 +03:00
type HealthCheckSuite struct {
BaseSuite
whoami1IP string
whoami2IP string
}
2017-02-07 01:00:54 +03:00
2017-04-26 02:08:15 +03:00
func ( s * HealthCheckSuite ) SetUpSuite ( c * check . C ) {
2017-02-07 01:00:54 +03:00
s . createComposeProject ( c , "healthcheck" )
s . composeProject . Start ( c )
2017-08-10 19:00:31 +03:00
s . whoami1IP = s . composeProject . Container ( c , "whoami1" ) . NetworkSettings . IPAddress
s . whoami2IP = s . composeProject . Container ( c , "whoami2" ) . NetworkSettings . IPAddress
2017-02-07 01:00:54 +03:00
}
2017-04-26 02:08:15 +03:00
func ( s * HealthCheckSuite ) TestSimpleConfiguration ( c * check . C ) {
2017-02-07 01:00:54 +03:00
file := s . adaptFile ( c , "fixtures/healthcheck/simple.toml" , struct {
Server1 string
Server2 string
2017-08-10 19:00:31 +03:00
} { s . whoami1IP , s . whoami2IP } )
2017-02-07 01:00:54 +03:00
defer os . Remove ( file )
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
2017-02-07 01:00:54 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2017-02-07 01:00:54 +03:00
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
frontendHealthReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
frontendHealthReq . Host = "test.localhost"
2017-02-07 01:00:54 +03:00
2017-05-17 16:22:44 +03:00
err = try . Request ( frontendHealthReq , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
// Fix all whoami health to 500
client := & http . Client { }
2017-08-10 19:00:31 +03:00
whoamiHosts := [ ] string { s . whoami1IP , s . whoami2IP }
2017-05-17 16:22:44 +03:00
for _ , whoami := range whoamiHosts {
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBuffer ( [ ] byte ( "500" ) ) )
c . Assert ( err , checker . IsNil )
_ , err = client . Do ( statusInternalServerErrorReq )
c . Assert ( err , checker . IsNil )
}
2017-07-10 13:11:44 +03:00
// Verify no backend service is available due to failing health checks
err = try . Request ( frontendHealthReq , 3 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
// Change one whoami health to 200
2017-08-10 19:00:31 +03:00
statusOKReq1 , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBuffer ( [ ] byte ( "200" ) ) )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
_ , err = client . Do ( statusOKReq1 )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
// Verify frontend health : after
err = try . Request ( frontendHealthReq , 3 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
2017-02-07 01:00:54 +03:00
2017-05-17 16:22:44 +03:00
frontendReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
frontendReq . Host = "test.localhost"
2017-02-07 01:00:54 +03:00
2017-07-10 13:11:44 +03:00
// Check if whoami1 responds
2017-08-10 19:00:31 +03:00
err = try . Request ( frontendReq , 500 * time . Millisecond , try . BodyContains ( s . whoami1IP ) )
2017-02-07 01:00:54 +03:00
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
// Check if the service with bad health check (whoami2) never respond.
2017-08-10 19:00:31 +03:00
err = try . Request ( frontendReq , 2 * time . Second , try . BodyContains ( s . whoami2IP ) )
2017-05-17 16:22:44 +03:00
c . Assert ( err , checker . Not ( checker . IsNil ) )
2017-02-07 01:00:54 +03:00
// TODO validate : run on 80
2017-05-17 16:22:44 +03:00
resp , err := http . Get ( "http://127.0.0.1:8000/" )
2017-02-07 01:00:54 +03:00
// Expected a 404 as we did not configure anything
c . Assert ( err , checker . IsNil )
2017-05-17 16:22:44 +03:00
c . Assert ( resp . StatusCode , checker . Equals , http . StatusNotFound )
2017-02-07 01:00:54 +03:00
}
2017-08-10 19:00:31 +03:00
2019-06-05 23:18:06 +03:00
func ( s * HealthCheckSuite ) TestMultipleEntrypoints ( c * check . C ) {
file := s . adaptFile ( c , "fixtures/healthcheck/multiple-entrypoints.toml" , struct {
2017-08-10 19:00:31 +03:00
Server1 string
Server2 string
} { s . whoami1IP , s . whoami2IP } )
defer os . Remove ( file )
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
2017-08-10 19:00:31 +03:00
err := cmd . Start ( )
c . Assert ( err , checker . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2017-08-10 19:00:31 +03:00
// Wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://localhost:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
2017-08-10 19:00:31 +03:00
c . Assert ( err , checker . IsNil )
// Check entrypoint http1
frontendHealthReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
c . Assert ( err , checker . IsNil )
frontendHealthReq . Host = "test.localhost"
err = try . Request ( frontendHealthReq , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
// Check entrypoint http2
frontendHealthReq , err = http . NewRequest ( http . MethodGet , "http://127.0.0.1:9000/health" , nil )
c . Assert ( err , checker . IsNil )
frontendHealthReq . Host = "test.localhost"
err = try . Request ( frontendHealthReq , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
2018-07-31 20:28:03 +03:00
// Set the both whoami health to 500
2017-08-10 19:00:31 +03:00
client := & http . Client { }
2018-07-31 20:28:03 +03:00
whoamiHosts := [ ] string { s . whoami1IP , s . whoami2IP }
for _ , whoami := range whoamiHosts {
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBuffer ( [ ] byte ( "500" ) ) )
c . Assert ( err , checker . IsNil )
_ , err = client . Do ( statusInternalServerErrorReq )
c . Assert ( err , checker . IsNil )
}
// Verify no backend service is available due to failing health checks
2018-11-14 12:18:03 +03:00
err = try . Request ( frontendHealthReq , 5 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
2017-08-10 19:00:31 +03:00
c . Assert ( err , checker . IsNil )
2018-07-31 20:28:03 +03:00
// reactivate the whoami2
statusInternalServerOkReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami2IP + "/health" , bytes . NewBuffer ( [ ] byte ( "200" ) ) )
c . Assert ( err , checker . IsNil )
_ , err = client . Do ( statusInternalServerOkReq )
c . Assert ( err , checker . IsNil )
2017-08-10 19:00:31 +03:00
frontend1Req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
c . Assert ( err , checker . IsNil )
frontend1Req . Host = "test.localhost"
frontend2Req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:9000/" , nil )
c . Assert ( err , checker . IsNil )
frontend2Req . Host = "test.localhost"
// Check if whoami1 never responds
err = try . Request ( frontend2Req , 2 * time . Second , try . BodyContains ( s . whoami1IP ) )
2018-07-31 20:28:03 +03:00
c . Assert ( err , checker . NotNil )
2017-08-10 19:00:31 +03:00
// Check if whoami1 never responds
err = try . Request ( frontend1Req , 2 * time . Second , try . BodyContains ( s . whoami1IP ) )
2018-07-31 20:28:03 +03:00
c . Assert ( err , checker . NotNil )
2017-08-10 19:00:31 +03:00
}
2017-09-18 16:50:03 +03:00
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 )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2017-09-18 16:50:03 +03:00
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
2017-09-18 16:50:03 +03:00
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"
2018-07-03 11:02:03 +03:00
// We test bad gateway because we use an invalid port for the backend
2017-09-18 16:50:03 +03:00
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 )
// 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 )
}
2019-11-29 14:40:05 +03:00
2020-05-11 13:06:07 +03:00
// Checks if all the loadbalancers created will correctly update the server status.
2019-11-29 14:40:05 +03:00
func ( s * HealthCheckSuite ) TestMultipleRoutersOnSameService ( c * check . C ) {
file := s . adaptFile ( c , "fixtures/healthcheck/multiple-routers-one-same-service.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 )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2019-11-29 14:40:05 +03:00
// wait for traefik
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
c . Assert ( err , checker . IsNil )
// Set whoami health to 200 to be sure to start with the wanted status
client := & http . Client { }
statusOkReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBuffer ( [ ] byte ( "200" ) ) )
c . Assert ( err , checker . IsNil )
_ , err = client . Do ( statusOkReq )
c . Assert ( err , checker . IsNil )
// check healthcheck on web1 entrypoint
healthReqWeb1 , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
c . Assert ( err , checker . IsNil )
healthReqWeb1 . Host = "test.localhost"
err = try . Request ( healthReqWeb1 , 1 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
// check healthcheck on web2 entrypoint
healthReqWeb2 , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:9000/health" , nil )
c . Assert ( err , checker . IsNil )
healthReqWeb2 . Host = "test.localhost"
err = try . Request ( healthReqWeb2 , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
// Set 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 )
// Verify no backend service is available due to failing health checks
err = try . Request ( healthReqWeb1 , 3 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
c . Assert ( err , checker . IsNil )
err = try . Request ( healthReqWeb2 , 3 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
c . Assert ( err , checker . IsNil )
// Change one whoami health to 200
statusOKReq1 , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBuffer ( [ ] byte ( "200" ) ) )
c . Assert ( err , checker . IsNil )
_ , err = client . Do ( statusOKReq1 )
c . Assert ( err , checker . IsNil )
// Verify health check
err = try . Request ( healthReqWeb1 , 3 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
err = try . Request ( healthReqWeb2 , 3 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
c . Assert ( err , checker . IsNil )
}