2017-07-06 17:28:13 +03:00
package integration
2017-02-07 01:00:54 +03:00
import (
"bytes"
2021-06-25 22:08:11 +03:00
"fmt"
2021-09-28 16:30:14 +03:00
"io"
2017-02-07 01:00:54 +03:00
"net/http"
"os"
2022-09-14 15:42:08 +03:00
"strings"
2024-01-09 19:00:07 +03:00
"testing"
2017-02-07 01:00:54 +03:00
"time"
2024-01-09 19:00:07 +03:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
2023-02-03 17:24:05 +03:00
"github.com/traefik/traefik/v3/integration/try"
2017-02-07 01:00:54 +03:00
)
2021-11-25 13:10:06 +03:00
// HealthCheck test suites.
2017-08-10 19:00:31 +03:00
type HealthCheckSuite struct {
BaseSuite
whoami1IP string
whoami2IP string
2021-06-25 22:08:11 +03:00
whoami3IP string
whoami4IP string
2017-08-10 19:00:31 +03:00
}
2017-02-07 01:00:54 +03:00
2024-01-09 19:00:07 +03:00
func TestHealthCheckSuite ( t * testing . T ) {
suite . Run ( t , new ( HealthCheckSuite ) )
}
func ( s * HealthCheckSuite ) SetupSuite ( ) {
s . BaseSuite . SetupSuite ( )
s . createComposeProject ( "healthcheck" )
s . composeUp ( )
2017-08-10 19:00:31 +03:00
2024-01-09 19:00:07 +03:00
s . whoami1IP = s . getComposeServiceIP ( "whoami1" )
s . whoami2IP = s . getComposeServiceIP ( "whoami2" )
s . whoami3IP = s . getComposeServiceIP ( "whoami3" )
s . whoami4IP = s . getComposeServiceIP ( "whoami4" )
2017-02-07 01:00:54 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TearDownSuite ( ) {
s . BaseSuite . TearDownSuite ( )
}
func ( s * HealthCheckSuite ) TestSimpleConfiguration ( ) {
file := s . adaptFile ( "fixtures/healthcheck/simple.toml" , struct {
2017-02-07 01:00:54 +03:00
Server1 string
Server2 string
2017-08-10 19:00:31 +03:00
} { s . whoami1IP , s . whoami2IP } )
2017-02-07 01:00:54 +03:00
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2017-02-07 01:00:54 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
require . NoError ( s . T ( ) , err )
2017-02-07 01:00:54 +03:00
2017-05-17 16:22:44 +03:00
frontendHealthReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
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 ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-02-07 01:00:54 +03:00
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 {
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-05-17 16:22:44 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-05-17 16:22:44 +03:00
}
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 ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-02-07 01:00:54 +03:00
2017-05-17 16:22:44 +03:00
// Change one whoami health to 200
2023-06-05 11:24:06 +03:00
statusOKReq1 , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBufferString ( "200" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-05-17 16:22:44 +03:00
_ , err = client . Do ( statusOKReq1 )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-02-07 01:00:54 +03:00
2017-05-17 16:22:44 +03:00
// Verify frontend health : after
err = try . Request ( frontendHealthReq , 3 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
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 )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
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 ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
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 ) )
2024-01-09 19:00:07 +03:00
assert . Error ( s . T ( ) , err )
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
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Equal ( s . T ( ) , http . StatusNotFound , resp . StatusCode )
2017-02-07 01:00:54 +03:00
}
2017-08-10 19:00:31 +03:00
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TestMultipleEntrypoints ( ) {
file := s . adaptFile ( "fixtures/healthcheck/multiple-entrypoints.toml" , struct {
2017-08-10 19:00:31 +03:00
Server1 string
Server2 string
} { s . whoami1IP , s . whoami2IP } )
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2017-08-10 19:00:31 +03:00
// Wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
// Check entrypoint http1
frontendHealthReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
frontendHealthReq . Host = "test.localhost"
2024-01-09 19:00:07 +03:00
err = try . Request ( frontendHealthReq , 5 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
// Check entrypoint http2
frontendHealthReq , err = http . NewRequest ( http . MethodGet , "http://127.0.0.1:9000/health" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
frontendHealthReq . Host = "test.localhost"
2024-01-09 19:00:07 +03:00
err = try . Request ( frontendHealthReq , 5 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
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 {
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-07-31 20:28:03 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-07-31 20:28:03 +03:00
}
// 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 ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
2018-07-31 20:28:03 +03:00
// reactivate the whoami2
2023-06-05 11:24:06 +03:00
statusInternalServerOkReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami2IP + "/health" , bytes . NewBufferString ( "200" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-07-31 20:28:03 +03:00
_ , err = client . Do ( statusInternalServerOkReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
frontend1Req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
frontend1Req . Host = "test.localhost"
frontend2Req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:9000/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
frontend2Req . Host = "test.localhost"
// Check if whoami1 never responds
err = try . Request ( frontend2Req , 2 * time . Second , try . BodyContains ( s . whoami1IP ) )
2024-01-09 19:00:07 +03:00
assert . Error ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
// Check if whoami1 never responds
err = try . Request ( frontend1Req , 2 * time . Second , try . BodyContains ( s . whoami1IP ) )
2024-01-09 19:00:07 +03:00
assert . Error ( s . T ( ) , err )
2017-08-10 19:00:31 +03:00
}
2017-09-18 16:50:03 +03:00
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TestPortOverload ( ) {
2017-09-18 16:50:03 +03:00
// Set one whoami health to 200
client := & http . Client { }
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBufferString ( "200" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
2024-01-09 19:00:07 +03:00
file := s . adaptFile ( "fixtures/healthcheck/port_overload.toml" , struct {
2017-09-18 16:50:03 +03:00
Server1 string
} { s . whoami1IP } )
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
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`)" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
frontendHealthReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
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 ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
// Set one whoami health to 500
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err = http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
// Verify no backend service is available due to failing health checks
err = try . Request ( frontendHealthReq , 3 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2017-09-18 16:50:03 +03:00
}
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.
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TestMultipleRoutersOnSameService ( ) {
file := s . adaptFile ( "fixtures/healthcheck/multiple-routers-one-same-service.toml" , struct {
2019-11-29 14:40:05 +03:00
Server1 string
} { s . whoami1IP } )
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2019-11-29 14:40:05 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`test.localhost`)" ) )
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// Set whoami health to 200 to be sure to start with the wanted status
client := & http . Client { }
2023-06-05 11:24:06 +03:00
statusOkReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBufferString ( "200" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
_ , err = client . Do ( statusOkReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// check healthcheck on web1 entrypoint
healthReqWeb1 , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/health" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
healthReqWeb1 . Host = "test.localhost"
err = try . Request ( healthReqWeb1 , 1 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// check healthcheck on web2 entrypoint
healthReqWeb2 , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:9000/health" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
healthReqWeb2 . Host = "test.localhost"
err = try . Request ( healthReqWeb2 , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// Set whoami health to 500
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// Verify no backend service is available due to failing health checks
err = try . Request ( healthReqWeb1 , 3 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
err = try . Request ( healthReqWeb2 , 3 * time . Second , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// Change one whoami health to 200
2023-06-05 11:24:06 +03:00
statusOKReq1 , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami1IP + "/health" , bytes . NewBufferString ( "200" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
_ , err = client . Do ( statusOKReq1 )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
// Verify health check
err = try . Request ( healthReqWeb1 , 3 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
err = try . Request ( healthReqWeb2 , 3 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-29 14:40:05 +03:00
}
2021-06-25 22:08:11 +03:00
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TestPropagate ( ) {
file := s . adaptFile ( "fixtures/healthcheck/propagate.toml" , struct {
2021-06-25 22:08:11 +03:00
Server1 string
Server2 string
Server3 string
Server4 string
} { s . whoami1IP , s . whoami2IP , s . whoami3IP , s . whoami4IP } )
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2021-06-25 22:08:11 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`root.localhost`)" ) )
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
rootReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
rootReq . Host = "root.localhost"
err = try . Request ( rootReq , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
// Bring whoami1 and whoami3 down
client := http . Client {
Timeout : 10 * time . Second ,
}
whoamiHosts := [ ] string { s . whoami1IP , s . whoami3IP }
for _ , whoami := range whoamiHosts {
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
}
try . Sleep ( time . Second )
2022-09-14 15:42:08 +03:00
want2 := ` IP: ` + s . whoami2IP
want4 := ` IP: ` + s . whoami4IP
2021-06-25 22:08:11 +03:00
2022-09-14 15:42:08 +03:00
// Verify load-balancing on root still works, and that we're getting an alternation between wsp2, and wsp4.
reachedServers := make ( map [ string ] int )
2024-02-19 17:44:03 +03:00
for range 4 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( rootReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2021-09-28 16:30:14 +03:00
body , err := io . ReadAll ( resp . Body )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2022-09-14 15:42:08 +03:00
if reachedServers [ s . whoami4IP ] > reachedServers [ s . whoami2IP ] {
2024-01-09 19:00:07 +03:00
assert . Contains ( s . T ( ) , string ( body ) , want2 )
2022-09-14 15:42:08 +03:00
reachedServers [ s . whoami2IP ] ++
continue
}
if reachedServers [ s . whoami2IP ] > reachedServers [ s . whoami4IP ] {
2024-01-09 19:00:07 +03:00
assert . Contains ( s . T ( ) , string ( body ) , want4 )
2022-09-14 15:42:08 +03:00
reachedServers [ s . whoami4IP ] ++
continue
}
// First iteration, so we can't tell whether it's going to be wsp2, or wsp4.
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami4IP ) {
reachedServers [ s . whoami4IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami2IP ) {
reachedServers [ s . whoami2IP ] ++
continue
}
2021-06-25 22:08:11 +03:00
}
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , 2 , reachedServers [ s . whoami2IP ] )
assert . Equal ( s . T ( ) , 2 , reachedServers [ s . whoami4IP ] )
2022-09-14 15:42:08 +03:00
2021-06-25 22:08:11 +03:00
fooReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
fooReq . Host = "foo.localhost"
// Verify load-balancing on foo still works, and that we're getting wsp2, wsp2, wsp2, wsp2, etc.
2022-09-14 15:42:08 +03:00
want := ` IP: ` + s . whoami2IP
2024-02-19 17:44:03 +03:00
for range 4 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( fooReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2021-09-28 16:30:14 +03:00
body , err := io . ReadAll ( resp . Body )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2024-01-09 19:00:07 +03:00
assert . Contains ( s . T ( ) , string ( body ) , want )
2021-06-25 22:08:11 +03:00
}
barReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
barReq . Host = "bar.localhost"
// Verify load-balancing on bar still works, and that we're getting wsp2, wsp2, wsp2, wsp2, etc.
want = ` IP: ` + s . whoami2IP
2024-02-19 17:44:03 +03:00
for range 4 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( barReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2021-09-28 16:30:14 +03:00
body , err := io . ReadAll ( resp . Body )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2024-01-09 19:00:07 +03:00
assert . Contains ( s . T ( ) , string ( body ) , want )
2021-06-25 22:08:11 +03:00
}
// Bring whoami2 and whoami4 down
whoamiHosts = [ ] string { s . whoami2IP , s . whoami4IP }
for _ , whoami := range whoamiHosts {
2023-06-05 11:24:06 +03:00
statusInternalServerErrorReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
_ , err = client . Do ( statusInternalServerErrorReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
}
try . Sleep ( time . Second )
// Verify that everything is down, and that we get 503s everywhere.
2024-02-19 17:44:03 +03:00
for range 2 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( rootReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Equal ( s . T ( ) , http . StatusServiceUnavailable , resp . StatusCode )
2021-06-25 22:08:11 +03:00
resp , err = client . Do ( fooReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Equal ( s . T ( ) , http . StatusServiceUnavailable , resp . StatusCode )
2021-06-25 22:08:11 +03:00
resp , err = client . Do ( barReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Equal ( s . T ( ) , http . StatusServiceUnavailable , resp . StatusCode )
2021-06-25 22:08:11 +03:00
}
// Bring everything back up.
whoamiHosts = [ ] string { s . whoami1IP , s . whoami2IP , s . whoami3IP , s . whoami4IP }
for _ , whoami := range whoamiHosts {
2023-06-05 11:24:06 +03:00
statusOKReq , err := http . NewRequest ( http . MethodPost , "http://" + whoami + "/health" , bytes . NewBufferString ( "200" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
_ , err = client . Do ( statusOKReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
}
try . Sleep ( time . Second )
// Verify everything is up on root router.
2022-09-14 15:42:08 +03:00
reachedServers = make ( map [ string ] int )
2024-02-19 17:44:03 +03:00
for range 4 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( rootReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2021-09-28 16:30:14 +03:00
body , err := io . ReadAll ( resp . Body )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2022-09-14 15:42:08 +03:00
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami1IP ) {
reachedServers [ s . whoami1IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami2IP ) {
reachedServers [ s . whoami2IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami3IP ) {
reachedServers [ s . whoami3IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami4IP ) {
reachedServers [ s . whoami4IP ] ++
continue
}
2021-06-25 22:08:11 +03:00
}
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami1IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami2IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami3IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami4IP ] )
2022-09-14 15:42:08 +03:00
2021-06-25 22:08:11 +03:00
// Verify everything is up on foo router.
2022-09-14 15:42:08 +03:00
reachedServers = make ( map [ string ] int )
2024-02-19 17:44:03 +03:00
for range 4 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( fooReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2021-09-28 16:30:14 +03:00
body , err := io . ReadAll ( resp . Body )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2022-09-14 15:42:08 +03:00
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami1IP ) {
reachedServers [ s . whoami1IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami2IP ) {
reachedServers [ s . whoami2IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami3IP ) {
reachedServers [ s . whoami3IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami4IP ) {
reachedServers [ s . whoami4IP ] ++
continue
}
2021-06-25 22:08:11 +03:00
}
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , 2 , reachedServers [ s . whoami1IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami2IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami3IP ] )
assert . Equal ( s . T ( ) , 0 , reachedServers [ s . whoami4IP ] )
2022-09-14 15:42:08 +03:00
2021-06-25 22:08:11 +03:00
// Verify everything is up on bar router.
2022-09-14 15:42:08 +03:00
reachedServers = make ( map [ string ] int )
2024-02-19 17:44:03 +03:00
for range 4 {
2021-06-25 22:08:11 +03:00
resp , err := client . Do ( barReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2021-09-28 16:30:14 +03:00
body , err := io . ReadAll ( resp . Body )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2022-09-14 15:42:08 +03:00
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami1IP ) {
reachedServers [ s . whoami1IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami2IP ) {
reachedServers [ s . whoami2IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami3IP ) {
reachedServers [ s . whoami3IP ] ++
continue
}
if strings . Contains ( string ( body ) , ` IP: ` + s . whoami4IP ) {
reachedServers [ s . whoami4IP ] ++
continue
}
2021-06-25 22:08:11 +03:00
}
2022-09-14 15:42:08 +03:00
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , 2 , reachedServers [ s . whoami1IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami2IP ] )
assert . Equal ( s . T ( ) , 1 , reachedServers [ s . whoami3IP ] )
assert . Equal ( s . T ( ) , 0 , reachedServers [ s . whoami4IP ] )
2021-06-25 22:08:11 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TestPropagateNoHealthCheck ( ) {
file := s . adaptFile ( "fixtures/healthcheck/propagate_no_healthcheck.toml" , struct {
2021-06-25 22:08:11 +03:00
Server1 string
} { s . whoami1IP } )
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2021-06-25 22:08:11 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`noop.localhost`)" ) , try . BodyNotContains ( "Host(`root.localhost`)" ) )
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
rootReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
rootReq . Host = "root.localhost"
err = try . Request ( rootReq , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusNotFound ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * HealthCheckSuite ) TestPropagateReload ( ) {
2021-06-25 22:08:11 +03:00
// Setup a WSP service without the healthcheck enabled (wsp-service1)
2024-01-09 19:00:07 +03:00
withoutHealthCheck := s . adaptFile ( "fixtures/healthcheck/reload_without_healthcheck.toml" , struct {
2021-06-25 22:08:11 +03:00
Server1 string
Server2 string
} { s . whoami1IP , s . whoami2IP } )
2024-01-09 19:00:07 +03:00
withHealthCheck := s . adaptFile ( "fixtures/healthcheck/reload_with_healthcheck.toml" , struct {
2021-06-25 22:08:11 +03:00
Server1 string
Server2 string
} { s . whoami1IP , s . whoami2IP } )
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( withoutHealthCheck ) )
2021-06-25 22:08:11 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 60 * time . Second , try . BodyContains ( "Host(`root.localhost`)" ) )
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
// Allow one of the underlying services on it to fail all servers HC (whoami2)
client := http . Client {
Timeout : 10 * time . Second ,
}
2023-06-05 11:24:06 +03:00
statusOKReq , err := http . NewRequest ( http . MethodPost , "http://" + s . whoami2IP + "/health" , bytes . NewBufferString ( "500" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
_ , err = client . Do ( statusOKReq )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
rootReq , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
rootReq . Host = "root.localhost"
// Check the failed service (whoami2) is getting requests, but answer 500
err = try . Request ( rootReq , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusServiceUnavailable ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
// Enable the healthcheck on the root WSP (wsp-service1) and let Traefik reload the config
fr1 , err := os . OpenFile ( withoutHealthCheck , os . O_APPEND | os . O_WRONLY , 0 o644 )
2024-01-09 19:00:07 +03:00
assert . NotNil ( s . T ( ) , fr1 )
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
err = fr1 . Truncate ( 0 )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
fr2 , err := os . ReadFile ( withHealthCheck )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
_ , err = fmt . Fprint ( fr1 , string ( fr2 ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
err = fr1 . Close ( )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
2024-01-09 19:00:07 +03:00
// Waiting for the reflected change.
err = try . Request ( rootReq , 5 * time . Second , try . StatusCodeIs ( http . StatusOK ) )
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
// Check the failed service (whoami2) is not getting requests
wantIPs := [ ] string { s . whoami1IP , s . whoami1IP , s . whoami1IP , s . whoami1IP }
for _ , ip := range wantIPs {
2024-01-09 19:00:07 +03:00
err = try . Request ( rootReq , 5 * time . Second , try . StatusCodeIs ( http . StatusOK ) , try . BodyContains ( "IP: " + ip ) )
require . NoError ( s . T ( ) , err )
2021-06-25 22:08:11 +03:00
}
}