2019-11-28 23:56:04 +03:00
package integration
import (
"bytes"
2022-08-11 16:42:07 +03:00
"context"
2019-11-28 23:56:04 +03:00
"encoding/json"
2023-09-25 17:38:07 +03:00
"errors"
2021-11-25 13:10:06 +03:00
"fmt"
"net"
2019-11-28 23:56:04 +03:00
"net/http"
"os"
"path/filepath"
2024-01-09 19:00:07 +03:00
"testing"
2019-11-28 23:56:04 +03:00
"time"
2022-09-12 18:40:09 +03:00
"github.com/kvtools/consul"
2022-01-12 16:42:21 +03:00
"github.com/kvtools/valkeyrie"
"github.com/kvtools/valkeyrie/store"
2019-11-28 23:56:04 +03:00
"github.com/pmezard/go-difflib/difflib"
2024-01-09 19:00:07 +03:00
"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"
"github.com/traefik/traefik/v3/pkg/api"
2019-11-28 23:56:04 +03:00
)
2021-11-25 13:10:06 +03:00
// Consul test suites.
2019-11-28 23:56:04 +03:00
type ConsulSuite struct {
BaseSuite
2021-11-25 13:10:06 +03:00
kvClient store . Store
consulURL string
2019-11-28 23:56:04 +03:00
}
2024-01-09 19:00:07 +03:00
func TestConsulSuite ( t * testing . T ) {
suite . Run ( t , new ( ConsulSuite ) )
2023-09-25 17:38:07 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * ConsulSuite ) SetupSuite ( ) {
s . BaseSuite . SetupSuite ( )
s . createComposeProject ( "consul" )
s . composeUp ( )
2021-11-25 13:10:06 +03:00
2024-01-09 19:00:07 +03:00
consulAddr := net . JoinHostPort ( s . getComposeServiceIP ( "consul" ) , "8500" )
2021-11-25 13:10:06 +03:00
s . consulURL = fmt . Sprintf ( "http://%s" , consulAddr )
2019-11-28 23:56:04 +03:00
kv , err := valkeyrie . NewStore (
2022-08-11 16:42:07 +03:00
context . Background ( ) ,
2022-09-12 18:40:09 +03:00
consul . StoreName ,
2021-11-25 13:10:06 +03:00
[ ] string { consulAddr } ,
2022-09-12 18:40:09 +03:00
& consul . Config {
2019-11-28 23:56:04 +03:00
ConnectionTimeout : 10 * time . Second ,
} ,
)
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err , "Cannot create store consul" )
2019-11-28 23:56:04 +03:00
s . kvClient = kv
// wait for consul
err = try . Do ( 60 * time . Second , try . KVExists ( kv , "test" ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * ConsulSuite ) TearDownSuite ( ) {
s . BaseSuite . TearDownSuite ( )
}
2019-11-28 23:56:04 +03:00
2024-01-09 19:00:07 +03:00
func ( s * ConsulSuite ) TearDownTest ( ) {
err := s . kvClient . DeleteTree ( context . Background ( ) , "traefik" )
if err != nil && ! errors . Is ( err , store . ErrKeyNotFound ) {
require . ErrorIs ( s . T ( ) , err , store . ErrKeyNotFound )
}
}
func ( s * ConsulSuite ) TestSimpleConfiguration ( ) {
file := s . adaptFile ( "fixtures/consul/simple.toml" , struct { ConsulAddress string } { s . consulURL } )
2019-11-28 23:56:04 +03:00
data := map [ string ] string {
"traefik/http/routers/Router0/entryPoints/0" : "web" ,
"traefik/http/routers/Router0/middlewares/0" : "compressor" ,
"traefik/http/routers/Router0/middlewares/1" : "striper" ,
"traefik/http/routers/Router0/service" : "simplesvc" ,
"traefik/http/routers/Router0/rule" : "Host(`kv1.localhost`)" ,
"traefik/http/routers/Router0/priority" : "42" ,
"traefik/http/routers/Router0/tls" : "" ,
"traefik/http/routers/Router1/rule" : "Host(`kv2.localhost`)" ,
"traefik/http/routers/Router1/priority" : "42" ,
"traefik/http/routers/Router1/tls/domains/0/main" : "aaa.localhost" ,
"traefik/http/routers/Router1/tls/domains/0/sans/0" : "aaa.aaa.localhost" ,
"traefik/http/routers/Router1/tls/domains/0/sans/1" : "bbb.aaa.localhost" ,
"traefik/http/routers/Router1/tls/domains/1/main" : "bbb.localhost" ,
"traefik/http/routers/Router1/tls/domains/1/sans/0" : "aaa.bbb.localhost" ,
"traefik/http/routers/Router1/tls/domains/1/sans/1" : "bbb.bbb.localhost" ,
"traefik/http/routers/Router1/entryPoints/0" : "web" ,
"traefik/http/routers/Router1/service" : "simplesvc" ,
"traefik/http/services/simplesvc/loadBalancer/servers/0/url" : "http://10.0.1.1:8888" ,
"traefik/http/services/simplesvc/loadBalancer/servers/1/url" : "http://10.0.1.1:8889" ,
"traefik/http/services/srvcA/loadBalancer/servers/0/url" : "http://10.0.1.2:8888" ,
"traefik/http/services/srvcA/loadBalancer/servers/1/url" : "http://10.0.1.2:8889" ,
"traefik/http/services/srvcB/loadBalancer/servers/0/url" : "http://10.0.1.3:8888" ,
"traefik/http/services/srvcB/loadBalancer/servers/1/url" : "http://10.0.1.3:8889" ,
"traefik/http/services/mirror/mirroring/service" : "simplesvc" ,
"traefik/http/services/mirror/mirroring/mirrors/0/name" : "srvcA" ,
"traefik/http/services/mirror/mirroring/mirrors/0/percent" : "42" ,
"traefik/http/services/mirror/mirroring/mirrors/1/name" : "srvcB" ,
"traefik/http/services/mirror/mirroring/mirrors/1/percent" : "42" ,
"traefik/http/services/Service03/weighted/services/0/name" : "srvcA" ,
"traefik/http/services/Service03/weighted/services/0/weight" : "42" ,
"traefik/http/services/Service03/weighted/services/1/name" : "srvcB" ,
"traefik/http/services/Service03/weighted/services/1/weight" : "42" ,
"traefik/http/middlewares/compressor/compress" : "" ,
"traefik/http/middlewares/striper/stripPrefix/prefixes/0" : "foo" ,
"traefik/http/middlewares/striper/stripPrefix/prefixes/1" : "bar" ,
}
for k , v := range data {
2022-08-11 16:42:07 +03:00
err := s . kvClient . Put ( context . Background ( ) , k , [ ] byte ( v ) , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
}
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2020-02-10 17:48:06 +03:00
2019-11-28 23:56:04 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 2 * time . Second ,
2020-02-10 17:48:06 +03:00
try . BodyContains ( ` "striper@consul": ` , ` "compressor@consul": ` , ` "srvcA@consul": ` , ` "srvcB@consul": ` ) ,
)
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
resp , err := http . Get ( "http://127.0.0.1:8080/api/rawdata" )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
var obtained api . RunTimeRepresentation
err = json . NewDecoder ( resp . Body ) . Decode ( & obtained )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
got , err := json . MarshalIndent ( obtained , "" , " " )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
expectedJSON := filepath . FromSlash ( "testdata/rawdata-consul.json" )
if * updateExpected {
2021-03-04 22:08:03 +03:00
err = os . WriteFile ( expectedJSON , got , 0 o666 )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
}
2021-03-04 22:08:03 +03:00
expected , err := os . ReadFile ( expectedJSON )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-28 23:56:04 +03:00
if ! bytes . Equal ( expected , got ) {
diff := difflib . UnifiedDiff {
FromFile : "Expected" ,
A : difflib . SplitLines ( string ( expected ) ) ,
ToFile : "Got" ,
B : difflib . SplitLines ( string ( got ) ) ,
Context : 3 ,
}
text , err := difflib . GetUnifiedDiffString ( diff )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err , text )
2019-11-28 23:56:04 +03:00
}
}
2023-09-25 17:38:07 +03:00
2024-01-09 19:00:07 +03:00
func ( s * ConsulSuite ) assertWhoami ( host string , expectedStatusCode int ) {
2023-09-25 17:38:07 +03:00
req , 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 )
2023-09-25 17:38:07 +03:00
req . Host = host
resp , err := try . ResponseUntilStatusCode ( req , 15 * time . Second , expectedStatusCode )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2023-09-25 17:38:07 +03:00
resp . Body . Close ( )
}
2024-01-09 19:00:07 +03:00
func ( s * ConsulSuite ) TestDeleteRootKey ( ) {
2023-09-25 17:38:07 +03:00
// This test case reproduce the issue: https://github.com/traefik/traefik/issues/8092
2024-01-09 19:00:07 +03:00
file := s . adaptFile ( "fixtures/consul/simple.toml" , struct { ConsulAddress string } { s . consulURL } )
2023-09-25 17:38:07 +03:00
ctx := context . Background ( )
2024-01-09 19:00:07 +03:00
svcaddr := net . JoinHostPort ( s . getComposeServiceIP ( "whoami" ) , "80" )
2023-09-25 17:38:07 +03:00
data := map [ string ] string {
"traefik/http/routers/Router0/entryPoints/0" : "web" ,
"traefik/http/routers/Router0/rule" : "Host(`kv1.localhost`)" ,
"traefik/http/routers/Router0/service" : "simplesvc0" ,
"traefik/http/routers/Router1/entryPoints/0" : "web" ,
"traefik/http/routers/Router1/rule" : "Host(`kv2.localhost`)" ,
"traefik/http/routers/Router1/service" : "simplesvc1" ,
"traefik/http/services/simplesvc0/loadBalancer/servers/0/url" : "http://" + svcaddr ,
"traefik/http/services/simplesvc1/loadBalancer/servers/0/url" : "http://" + svcaddr ,
}
for k , v := range data {
err := s . kvClient . Put ( ctx , k , [ ] byte ( v ) , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2023-09-25 17:38:07 +03:00
}
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( file ) )
2023-09-25 17:38:07 +03:00
// wait for traefik
2024-01-09 19:00:07 +03:00
err := try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 2 * time . Second ,
2023-09-25 17:38:07 +03:00
try . BodyContains ( ` "Router0@consul": ` , ` "Router1@consul": ` , ` "simplesvc0@consul": ` , ` "simplesvc1@consul": ` ) ,
)
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
s . assertWhoami ( "kv1.localhost" , http . StatusOK )
s . assertWhoami ( "kv2.localhost" , http . StatusOK )
2023-09-25 17:38:07 +03:00
// delete router1
err = s . kvClient . DeleteTree ( ctx , "traefik/http/routers/Router1" )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
s . assertWhoami ( "kv1.localhost" , http . StatusOK )
s . assertWhoami ( "kv2.localhost" , http . StatusNotFound )
2023-09-25 17:38:07 +03:00
// delete simple services and router0
err = s . kvClient . DeleteTree ( ctx , "traefik" )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
s . assertWhoami ( "kv1.localhost" , http . StatusNotFound )
s . assertWhoami ( "kv2.localhost" , http . StatusNotFound )
2023-09-25 17:38:07 +03:00
}