Merge branch v3.4 into master
This commit is contained in:
commit
289d6e5dca
195 changed files with 1963 additions and 892 deletions
|
|
@ -2,7 +2,6 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -43,7 +42,7 @@ func (s *ConsulSuite) SetupSuite() {
|
|||
s.consulURL = fmt.Sprintf("http://%s", consulAddr)
|
||||
|
||||
kv, err := valkeyrie.NewStore(
|
||||
context.Background(),
|
||||
s.T().Context(),
|
||||
consul.StoreName,
|
||||
[]string{consulAddr},
|
||||
&consul.Config{
|
||||
|
|
@ -63,7 +62,7 @@ func (s *ConsulSuite) TearDownSuite() {
|
|||
}
|
||||
|
||||
func (s *ConsulSuite) TearDownTest() {
|
||||
err := s.kvClient.DeleteTree(context.Background(), "traefik")
|
||||
err := s.kvClient.DeleteTree(s.T().Context(), "traefik")
|
||||
if err != nil && !errors.Is(err, store.ErrKeyNotFound) {
|
||||
require.ErrorIs(s.T(), err, store.ErrKeyNotFound)
|
||||
}
|
||||
|
|
@ -118,7 +117,7 @@ func (s *ConsulSuite) TestSimpleConfiguration() {
|
|||
}
|
||||
|
||||
for k, v := range data {
|
||||
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
|
||||
err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +177,7 @@ func (s *ConsulSuite) TestDeleteRootKey() {
|
|||
|
||||
file := s.adaptFile("fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := s.T().Context()
|
||||
svcaddr := net.JoinHostPort(s.getComposeServiceIP("whoami"), "80")
|
||||
|
||||
data := map[string]string{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -41,7 +40,7 @@ func (s *EtcdSuite) SetupSuite() {
|
|||
var err error
|
||||
s.etcdAddr = net.JoinHostPort(s.getComposeServiceIP("etcd"), "2379")
|
||||
s.kvClient, err = valkeyrie.NewStore(
|
||||
context.Background(),
|
||||
s.T().Context(),
|
||||
etcdv3.StoreName,
|
||||
[]string{s.etcdAddr},
|
||||
&etcdv3.Config{
|
||||
|
|
@ -108,7 +107,7 @@ func (s *EtcdSuite) TestSimpleConfiguration() {
|
|||
}
|
||||
|
||||
for k, v := range data {
|
||||
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
|
||||
err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
|
|||
28
integration/fixtures/https/max_concurrent_stream.toml
Normal file
28
integration/fixtures/https/max_concurrent_stream.toml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
[global]
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
|
||||
[serversTransport]
|
||||
insecureSkipVerify=true
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":8000"
|
||||
[entryPoints.web.http2]
|
||||
maxConcurrentStreams = 42
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
|
||||
## dynamic configuration ##
|
||||
|
||||
[tls.stores]
|
||||
[tls.stores.default.defaultCertificate]
|
||||
certFile = "resources/tls/local.cert"
|
||||
keyFile = "resources/tls/local.key"
|
||||
|
|
@ -2291,7 +2291,7 @@ spec:
|
|||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: RootCA cannot have both Secret and ConfigMap defined.
|
||||
rule: has(self.secret) && has(self.configMap)
|
||||
rule: '!has(self.secret) || !has(self.configMap)'
|
||||
type: array
|
||||
rootCAsSecrets:
|
||||
description: |-
|
||||
|
|
@ -2436,7 +2436,7 @@ spec:
|
|||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: RootCA cannot have both Secret and ConfigMap defined.
|
||||
rule: has(self.secret) && has(self.configMap)
|
||||
rule: '!has(self.secret) || !has(self.configMap)'
|
||||
type: array
|
||||
rootCAsSecrets:
|
||||
description: |-
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
|
||||
[core]
|
||||
defaultRuleSyntax = "{{ .DefaultRuleSyntax }}"
|
||||
|
||||
# dynamic configuration
|
||||
[http.routers]
|
||||
[http.routers.without]
|
||||
|
|
@ -108,7 +108,9 @@ func getHelloClientGRPCh2c() (helloworld.GreeterClient, func() error, error) {
|
|||
return helloworld.NewGreeterClient(conn), conn.Close, nil
|
||||
}
|
||||
|
||||
func callHelloClientGRPC(name string, secure bool) (string, error) {
|
||||
func callHelloClientGRPC(t *testing.T, name string, secure bool) (string, error) {
|
||||
t.Helper()
|
||||
|
||||
var client helloworld.GreeterClient
|
||||
var closer func() error
|
||||
var err error
|
||||
|
|
@ -123,24 +125,26 @@ func callHelloClientGRPC(name string, secure bool) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
r, err := client.SayHello(context.Background(), &helloworld.HelloRequest{Name: name})
|
||||
r, err := client.SayHello(t.Context(), &helloworld.HelloRequest{Name: name})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return r.GetMessage(), nil
|
||||
}
|
||||
|
||||
func callStreamExampleClientGRPC() (helloworld.Greeter_StreamExampleClient, func() error, error) {
|
||||
func callStreamExampleClientGRPC(t *testing.T) (helloworld.Greeter_StreamExampleClient, func() error, error) {
|
||||
t.Helper()
|
||||
|
||||
client, closer, err := getHelloClientGRPC()
|
||||
if err != nil {
|
||||
return nil, closer, err
|
||||
}
|
||||
t, err := client.StreamExample(context.Background(), &helloworld.StreamExampleRequest{})
|
||||
s, err := client.StreamExample(t.Context(), &helloworld.StreamExampleRequest{})
|
||||
if err != nil {
|
||||
return nil, closer, err
|
||||
}
|
||||
|
||||
return t, closer, nil
|
||||
return s, closer, nil
|
||||
}
|
||||
|
||||
func (s *GRPCSuite) TestGRPC() {
|
||||
|
|
@ -172,7 +176,7 @@ func (s *GRPCSuite) TestGRPC() {
|
|||
|
||||
var response string
|
||||
err = try.Do(1*time.Second, func() error {
|
||||
response, err = callHelloClientGRPC("World", true)
|
||||
response, err = callHelloClientGRPC(s.T(), "World", true)
|
||||
return err
|
||||
})
|
||||
assert.NoError(s.T(), err)
|
||||
|
|
@ -204,7 +208,7 @@ func (s *GRPCSuite) TestGRPCh2c() {
|
|||
|
||||
var response string
|
||||
err = try.Do(1*time.Second, func() error {
|
||||
response, err = callHelloClientGRPC("World", false)
|
||||
response, err = callHelloClientGRPC(s.T(), "World", false)
|
||||
return err
|
||||
})
|
||||
assert.NoError(s.T(), err)
|
||||
|
|
@ -240,7 +244,7 @@ func (s *GRPCSuite) TestGRPCh2cTermination() {
|
|||
|
||||
var response string
|
||||
err = try.Do(1*time.Second, func() error {
|
||||
response, err = callHelloClientGRPC("World", true)
|
||||
response, err = callHelloClientGRPC(s.T(), "World", true)
|
||||
return err
|
||||
})
|
||||
assert.NoError(s.T(), err)
|
||||
|
|
@ -276,7 +280,7 @@ func (s *GRPCSuite) TestGRPCInsecure() {
|
|||
|
||||
var response string
|
||||
err = try.Do(1*time.Second, func() error {
|
||||
response, err = callHelloClientGRPC("World", true)
|
||||
response, err = callHelloClientGRPC(s.T(), "World", true)
|
||||
return err
|
||||
})
|
||||
assert.NoError(s.T(), err)
|
||||
|
|
@ -314,7 +318,7 @@ func (s *GRPCSuite) TestGRPCBuffer() {
|
|||
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
|
||||
assert.NoError(s.T(), err)
|
||||
var client helloworld.Greeter_StreamExampleClient
|
||||
client, closer, err := callStreamExampleClientGRPC()
|
||||
client, closer, err := callStreamExampleClientGRPC(s.T())
|
||||
defer func() { _ = closer() }()
|
||||
assert.NoError(s.T(), err)
|
||||
|
||||
|
|
@ -367,7 +371,7 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval() {
|
|||
assert.NoError(s.T(), err)
|
||||
|
||||
var client helloworld.Greeter_StreamExampleClient
|
||||
client, closer, err := callStreamExampleClientGRPC()
|
||||
client, closer, err := callStreamExampleClientGRPC(s.T())
|
||||
defer func() {
|
||||
_ = closer()
|
||||
stopStreamExample <- true
|
||||
|
|
@ -422,7 +426,7 @@ func (s *GRPCSuite) TestGRPCWithRetry() {
|
|||
|
||||
var response string
|
||||
err = try.Do(1*time.Second, func() error {
|
||||
response, err = callHelloClientGRPC("World", true)
|
||||
response, err = callHelloClientGRPC(s.T(), "World", true)
|
||||
return err
|
||||
})
|
||||
assert.NoError(s.T(), err)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package integration
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -19,6 +20,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
// HTTPSSuite tests suite.
|
||||
|
|
@ -1174,3 +1176,38 @@ func (s *HTTPSSuite) TestWithInvalidTLSOption() {
|
|||
assert.Nil(s.T(), conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestMaxConcurrentStream() {
|
||||
file := s.adaptFile("fixtures/https/max_concurrent_stream.toml", struct{}{})
|
||||
|
||||
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG", "--accesslog")
|
||||
|
||||
// Wait for traefik.
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("api@internal"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// Add client self-signed cert.
|
||||
roots := x509.NewCertPool()
|
||||
certContent, err := os.ReadFile("./resources/tls/local.cert")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
roots.AppendCertsFromPEM(certContent)
|
||||
|
||||
// Open a connection to inspect SettingsFrame.
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:8000", &tls.Config{
|
||||
RootCAs: roots,
|
||||
NextProtos: []string{"h2"},
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
framer := http2.NewFramer(nil, conn)
|
||||
frame, err := framer.ReadFrame()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
fr, ok := frame.(*http2.SettingsFrame)
|
||||
require.True(s.T(), ok)
|
||||
|
||||
maxConcurrentStream, ok := fr.Value(http2.SettingMaxConcurrentStreams)
|
||||
assert.True(s.T(), ok)
|
||||
assert.Equal(s.T(), uint32(42), maxConcurrentStream)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ func (s *BaseSuite) displayTraefikLogFile(path string) {
|
|||
}
|
||||
|
||||
func (s *BaseSuite) SetupSuite() {
|
||||
if isDockerDesktop(context.Background(), s.T()) {
|
||||
if isDockerDesktop(s.T()) {
|
||||
_, err := os.Stat(tailscaleSecretFilePath)
|
||||
require.NoError(s.T(), err, "Tailscale need to be configured when running integration tests with Docker Desktop: (https://doc.traefik.io/traefik/v2.11/contributing/building-testing/#testing)")
|
||||
}
|
||||
|
|
@ -116,7 +116,6 @@ func (s *BaseSuite) SetupSuite() {
|
|||
// TODO
|
||||
// stdlog.SetOutput(log.Logger)
|
||||
|
||||
ctx := context.Background()
|
||||
// Create docker network
|
||||
// docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
|
||||
var opts []network.NetworkCustomizer
|
||||
|
|
@ -129,18 +128,18 @@ func (s *BaseSuite) SetupSuite() {
|
|||
},
|
||||
},
|
||||
}))
|
||||
dockerNetwork, err := network.New(ctx, opts...)
|
||||
dockerNetwork, err := network.New(s.T().Context(), opts...)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
s.network = dockerNetwork
|
||||
s.hostIP = "172.31.42.1"
|
||||
if isDockerDesktop(ctx, s.T()) {
|
||||
s.hostIP = getDockerDesktopHostIP(ctx, s.T())
|
||||
if isDockerDesktop(s.T()) {
|
||||
s.hostIP = getDockerDesktopHostIP(s.T())
|
||||
s.setupVPN(tailscaleSecretFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string {
|
||||
func getDockerDesktopHostIP(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
req := testcontainers.ContainerRequest{
|
||||
|
|
@ -151,13 +150,13 @@ func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string {
|
|||
Cmd: []string{"getent", "hosts", "host.docker.internal"},
|
||||
}
|
||||
|
||||
con, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
con, err := testcontainers.GenericContainer(t.Context(), testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: req,
|
||||
Started: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
closer, err := con.Logs(ctx)
|
||||
closer, err := con.Logs(t.Context())
|
||||
require.NoError(t, err)
|
||||
|
||||
all, err := io.ReadAll(closer)
|
||||
|
|
@ -170,15 +169,15 @@ func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string {
|
|||
return matches[0]
|
||||
}
|
||||
|
||||
func isDockerDesktop(ctx context.Context, t *testing.T) bool {
|
||||
func isDockerDesktop(t *testing.T) bool {
|
||||
t.Helper()
|
||||
|
||||
cli, err := testcontainers.NewDockerClientWithOpts(ctx)
|
||||
cli, err := testcontainers.NewDockerClientWithOpts(t.Context())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create docker client: %s", err)
|
||||
}
|
||||
|
||||
info, err := cli.Info(ctx)
|
||||
info, err := cli.Info(t.Context())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get docker info: %s", err)
|
||||
}
|
||||
|
|
@ -191,7 +190,7 @@ func (s *BaseSuite) TearDownSuite() {
|
|||
|
||||
err := try.Do(5*time.Second, func() error {
|
||||
if s.network != nil {
|
||||
err := s.network.Remove(context.Background())
|
||||
err := s.network.Remove(s.T().Context())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -218,7 +217,7 @@ func (s *BaseSuite) createComposeProject(name string) {
|
|||
s.containers = map[string]testcontainers.Container{}
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := s.T().Context()
|
||||
|
||||
for id, containerConfig := range composeConfigData.Services {
|
||||
var mounts []mount.Mount
|
||||
|
|
@ -273,7 +272,7 @@ func (s *BaseSuite) createContainer(ctx context.Context, containerConfig compose
|
|||
if containerConfig.CapAdd != nil {
|
||||
config.CapAdd = containerConfig.CapAdd
|
||||
}
|
||||
if !isDockerDesktop(ctx, s.T()) {
|
||||
if !isDockerDesktop(s.T()) {
|
||||
config.ExtraHosts = append(config.ExtraHosts, "host.docker.internal:"+s.hostIP)
|
||||
}
|
||||
config.Mounts = mounts
|
||||
|
|
@ -292,7 +291,7 @@ func (s *BaseSuite) createContainer(ctx context.Context, containerConfig compose
|
|||
func (s *BaseSuite) composeUp(services ...string) {
|
||||
for name, con := range s.containers {
|
||||
if len(services) == 0 || slices.Contains(services, name) {
|
||||
err := con.Start(context.Background())
|
||||
err := con.Start(s.T().Context())
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
|
@ -303,7 +302,7 @@ func (s *BaseSuite) composeStop(services ...string) {
|
|||
for name, con := range s.containers {
|
||||
if len(services) == 0 || slices.Contains(services, name) {
|
||||
timeout := 10 * time.Second
|
||||
err := con.Stop(context.Background(), &timeout)
|
||||
err := con.Stop(s.T().Context(), &timeout)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
|
@ -312,7 +311,7 @@ func (s *BaseSuite) composeStop(services ...string) {
|
|||
// composeDown stops all compose project services and removes the corresponding containers.
|
||||
func (s *BaseSuite) composeDown() {
|
||||
for _, c := range s.containers {
|
||||
err := c.Terminate(context.Background())
|
||||
err := c.Terminate(s.T().Context())
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
s.containers = map[string]testcontainers.Container{}
|
||||
|
|
@ -383,7 +382,7 @@ func (s *BaseSuite) displayLogK3S() {
|
|||
|
||||
func (s *BaseSuite) displayLogCompose() {
|
||||
for name, ctn := range s.containers {
|
||||
readCloser, err := ctn.Logs(context.Background())
|
||||
readCloser, err := ctn.Logs(s.T().Context())
|
||||
require.NoError(s.T(), err)
|
||||
for {
|
||||
b := make([]byte, 1024)
|
||||
|
|
@ -451,7 +450,7 @@ func (s *BaseSuite) getComposeServiceIP(name string) string {
|
|||
if !ok {
|
||||
return ""
|
||||
}
|
||||
ip, err := container.ContainerIP(context.Background())
|
||||
ip, err := container.ContainerIP(s.T().Context())
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
|
@ -501,7 +500,7 @@ func (s *BaseSuite) setupVPN(keyFile string) {
|
|||
func (s *BaseSuite) composeExec(service string, args ...string) string {
|
||||
require.Contains(s.T(), s.containers, service)
|
||||
|
||||
_, reader, err := s.containers[service].Exec(context.Background(), args)
|
||||
_, reader, err := s.containers[service].Exec(s.T().Context(), args)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
content, err := io.ReadAll(reader)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
|
@ -74,7 +73,7 @@ func (s *K8sConformanceSuite) SetupSuite() {
|
|||
s.T().Fatal(err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := s.T().Context()
|
||||
|
||||
// Ensure image is available locally.
|
||||
images, err := provider.ListImages(ctx)
|
||||
|
|
@ -146,7 +145,7 @@ func (s *K8sConformanceSuite) SetupSuite() {
|
|||
}
|
||||
|
||||
func (s *K8sConformanceSuite) TearDownSuite() {
|
||||
ctx := context.Background()
|
||||
ctx := s.T().Context()
|
||||
|
||||
if s.T().Failed() || *showLog {
|
||||
k3sLogs, err := s.k3sContainer.Logs(ctx)
|
||||
|
|
@ -173,7 +172,7 @@ func (s *K8sConformanceSuite) TearDownSuite() {
|
|||
|
||||
func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
|
||||
// Wait for traefik to start
|
||||
k3sContainerIP, err := s.k3sContainer.ContainerIP(context.Background())
|
||||
k3sContainerIP, err := s.k3sContainer.ContainerIP(s.T().Context())
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = try.GetRequest("http://"+k3sContainerIP+":9000/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
|
@ -51,7 +50,7 @@ func (s *RedisSentinelSuite) SetupSuite() {
|
|||
net.JoinHostPort(s.getComposeServiceIP("sentinel3"), "26379"),
|
||||
}
|
||||
kv, err := valkeyrie.NewStore(
|
||||
context.Background(),
|
||||
s.T().Context(),
|
||||
redis.StoreName,
|
||||
s.redisEndpoints,
|
||||
&redis.Config{
|
||||
|
|
@ -157,7 +156,7 @@ func (s *RedisSentinelSuite) TestSentinelConfiguration() {
|
|||
}
|
||||
|
||||
for k, v := range data {
|
||||
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
|
||||
err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -43,7 +42,7 @@ func (s *RedisSuite) SetupSuite() {
|
|||
s.redisEndpoints = append(s.redisEndpoints, net.JoinHostPort(s.getComposeServiceIP("redis"), "6379"))
|
||||
|
||||
kv, err := valkeyrie.NewStore(
|
||||
context.Background(),
|
||||
s.T().Context(),
|
||||
redis.StoreName,
|
||||
s.redisEndpoints,
|
||||
&redis.Config{},
|
||||
|
|
@ -112,7 +111,7 @@ func (s *RedisSuite) TestSimpleConfiguration() {
|
|||
}
|
||||
|
||||
for k, v := range data {
|
||||
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
|
||||
err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
server0:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
noOverrideAllowlist:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
consul:
|
||||
image: consul:1.6
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
consul:
|
||||
image: consul:1.6.2
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
simple:
|
||||
image: swarm:1.0.0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
nginx1:
|
||||
image: nginx:1.25.3-alpine3.18
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
etcd:
|
||||
image: quay.io/coreos/etcd:v3.5.14
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
server1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
server:
|
||||
image: rancher/k3s:v1.21.14-k3s1
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
pebble:
|
||||
image: letsencrypt/pebble:v2.3.1
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
redis:
|
||||
image: redis:5.0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
master:
|
||||
image: redis
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
tailscaled:
|
||||
hostname: traefik-tests-gw # This will become the tailscale device name
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami-a:
|
||||
image: traefik/whoamitcp
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
timeoutEndpoint:
|
||||
image: yaman/timeout
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
tempo:
|
||||
hostname: tempo
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
whoami-a:
|
||||
image: traefik/whoamiudp:latest
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
noOverrideWhitelist:
|
||||
image: traefik/whoami
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
zookeeper:
|
||||
image: zookeeper:3.5
|
||||
|
|
|
|||
|
|
@ -711,11 +711,11 @@ func (s *SimpleSuite) TestWithDefaultRuleSyntax() {
|
|||
require.NoError(s.T(), err)
|
||||
|
||||
// router2 has an error because it uses the wrong rule syntax (v3 instead of v2)
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("error while parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// router3 has an error because it uses the wrong rule syntax (v2 instead of v3)
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("error while adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
@ -741,11 +741,11 @@ func (s *SimpleSuite) TestWithoutDefaultRuleSyntax() {
|
|||
require.NoError(s.T(), err)
|
||||
|
||||
// router2 has an error because it uses the wrong rule syntax (v3 instead of v2)
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("error while adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// router2 has an error because it uses the wrong rule syntax (v2 instead of v3)
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("error while parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
@ -1606,9 +1606,10 @@ func (s *SimpleSuite) TestSanitizePath() {
|
|||
|
||||
whoami1URL := "http://" + net.JoinHostPort(s.getComposeServiceIP("whoami1"), "80")
|
||||
|
||||
file := s.adaptFile("fixtures/simple_clean_path.toml", struct {
|
||||
Server1 string
|
||||
}{whoami1URL})
|
||||
file := s.adaptFile("fixtures/simple_sanitize_path.toml", struct {
|
||||
Server1 string
|
||||
DefaultRuleSyntax string
|
||||
}{whoami1URL, "v3"})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
|
|
@ -1641,6 +1642,116 @@ func (s *SimpleSuite) TestSanitizePath() {
|
|||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Implicit encoded dot dots call to the route with a middleware",
|
||||
request: "GET /without/%2E%2E/with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Implicit with encoded unreserved character call to the route with a middleware",
|
||||
request: "GET /%77ith HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Explicit call to the route with a middleware, and disable path sanitization",
|
||||
request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8001",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Explicit call to the route without a middleware, and disable path sanitization",
|
||||
request: "GET /without HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8001",
|
||||
expected: http.StatusOK,
|
||||
body: "GET /without HTTP/1.1",
|
||||
},
|
||||
{
|
||||
desc: "Implicit call to the route with a middleware, and disable path sanitization",
|
||||
request: "GET /without/../with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8001",
|
||||
// The whoami is redirecting to /with, but the path is not sanitized.
|
||||
expected: http.StatusMovedPermanently,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
conn, err := net.Dial("tcp", test.target)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
_, err = conn.Write([]byte(test.request))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
resp, err := http.ReadResponse(bufio.NewReader(conn), nil)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
assert.Equalf(s.T(), test.expected, resp.StatusCode, "%s failed with %d instead of %d", test.desc, resp.StatusCode, test.expected)
|
||||
|
||||
if test.body != "" {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Contains(s.T(), string(body), test.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestSanitizePathSyntaxV2() {
|
||||
s.createComposeProject("base")
|
||||
|
||||
s.composeUp()
|
||||
defer s.composeDown()
|
||||
|
||||
whoami1URL := "http://" + net.JoinHostPort(s.getComposeServiceIP("whoami1"), "80")
|
||||
|
||||
file := s.adaptFile("fixtures/simple_sanitize_path.toml", struct {
|
||||
Server1 string
|
||||
DefaultRuleSyntax string
|
||||
}{whoami1URL, "v2"})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix(`/with`)"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
request string
|
||||
target string
|
||||
body string
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
desc: "Explicit call to the route with a middleware",
|
||||
request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Explicit call to the route without a middleware",
|
||||
request: "GET /without HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusOK,
|
||||
body: "GET /without HTTP/1.1",
|
||||
},
|
||||
{
|
||||
desc: "Implicit call to the route with a middleware",
|
||||
request: "GET /without/../with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Implicit encoded dot dots call to the route with a middleware",
|
||||
request: "GET /without/%2E%2E/with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Implicit with encoded unreserved character call to the route with a middleware",
|
||||
request: "GET /%77ith HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8000",
|
||||
expected: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "Explicit call to the route with a middleware, and disable path sanitization",
|
||||
request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package integration
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -43,7 +42,7 @@ func (s *ZookeeperSuite) SetupSuite() {
|
|||
|
||||
var err error
|
||||
s.kvClient, err = valkeyrie.NewStore(
|
||||
context.Background(),
|
||||
s.T().Context(),
|
||||
zookeeper.StoreName,
|
||||
[]string{s.zookeeperAddr},
|
||||
&zookeeper.Config{
|
||||
|
|
@ -110,7 +109,7 @@ func (s *ZookeeperSuite) TestSimpleConfiguration() {
|
|||
}
|
||||
|
||||
for k, v := range data {
|
||||
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
|
||||
err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue