mirror of
https://github.com/traefik/traefik.git
synced 2026-06-19 07:36:07 +00:00
Merge branch v3.6 into master
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
[global]
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
noColor = true
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":8888"
|
||||
allowACMEByPass = true
|
||||
[entryPoints.web.http.redirections.entryPoint]
|
||||
to = ":8443"
|
||||
scheme = "https"
|
||||
|
||||
[entryPoints.websecure]
|
||||
address = ":8443"
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
|
||||
## dynamic configuration ##
|
||||
|
||||
[http.routers]
|
||||
[http.routers.acme-challenge]
|
||||
entryPoints = ["web"]
|
||||
rule = "PathPrefix(`/.well-known/acme-challenge/`)"
|
||||
service = "acme-solver"
|
||||
|
||||
[http.services]
|
||||
[http.services.acme-solver]
|
||||
[http.services.acme-solver.loadBalancer]
|
||||
[[http.services.acme-solver.loadBalancer.servers]]
|
||||
url = "{{ .AcmeSolverURL }}"
|
||||
@@ -232,15 +232,17 @@ func (s *BaseSuite) createComposeProject(name string) {
|
||||
|
||||
func (s *BaseSuite) createContainer(ctx context.Context, containerConfig composeService, id string, mounts []mount.Mount) (testcontainers.Container, error) {
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: containerConfig.Image,
|
||||
Env: containerConfig.Environment,
|
||||
Cmd: containerConfig.Command,
|
||||
Labels: containerConfig.Labels,
|
||||
Name: id,
|
||||
Hostname: containerConfig.Hostname,
|
||||
Privileged: containerConfig.Privileged,
|
||||
Networks: []string{s.network.Name},
|
||||
Image: containerConfig.Image,
|
||||
Env: containerConfig.Environment,
|
||||
Cmd: containerConfig.Command,
|
||||
Labels: containerConfig.Labels,
|
||||
Name: id,
|
||||
Networks: []string{s.network.Name},
|
||||
ConfigModifier: func(config *container.Config) {
|
||||
config.Hostname = containerConfig.Hostname
|
||||
},
|
||||
HostConfigModifier: func(config *container.HostConfig) {
|
||||
config.Privileged = containerConfig.Privileged
|
||||
if containerConfig.CapAdd != nil {
|
||||
config.CapAdd = containerConfig.CapAdd
|
||||
}
|
||||
|
||||
+30
-28
@@ -7,12 +7,10 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -20,6 +18,8 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/modules/k3s"
|
||||
"github.com/traefik/traefik/v3/integration/try"
|
||||
"github.com/traefik/traefik/v3/pkg/api"
|
||||
)
|
||||
@@ -27,7 +27,11 @@ import (
|
||||
var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata")
|
||||
|
||||
// K8sSuite tests suite.
|
||||
type K8sSuite struct{ BaseSuite }
|
||||
type K8sSuite struct {
|
||||
BaseSuite
|
||||
|
||||
k3sContainer *k3s.K3sContainer
|
||||
}
|
||||
|
||||
func TestK8sSuite(t *testing.T) {
|
||||
suite.Run(t, new(K8sSuite))
|
||||
@@ -36,47 +40,45 @@ func TestK8sSuite(t *testing.T) {
|
||||
func (s *K8sSuite) SetupSuite() {
|
||||
s.BaseSuite.SetupSuite()
|
||||
|
||||
s.createComposeProject("k8s")
|
||||
s.composeUp()
|
||||
|
||||
abs, err := filepath.Abs("./fixtures/k8s/config.skip/kubeconfig.yaml")
|
||||
manifests, err := filepath.Glob("./fixtures/k8s/*.yml")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := os.Stat(abs)
|
||||
return err
|
||||
})
|
||||
opts := make([]testcontainers.ContainerCustomizer, 0, len(manifests))
|
||||
for _, m := range manifests {
|
||||
opts = append(opts, k3s.WithManifest(m))
|
||||
}
|
||||
|
||||
s.k3sContainer, err = k3s.Run(s.T().Context(), k3sImage, opts...)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
data, err := os.ReadFile(abs)
|
||||
kubeConfigYaml, err := s.k3sContainer.GetKubeConfig(s.T().Context())
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
content := strings.ReplaceAll(string(data), "https://server:6443", fmt.Sprintf("https://%s", net.JoinHostPort(s.getComposeServiceIP("server"), "6443")))
|
||||
|
||||
err = os.WriteFile(abs, []byte(content), 0o644)
|
||||
kubeconfigPath := filepath.Join(s.T().TempDir(), "kubeconfig.yaml")
|
||||
err = os.WriteFile(kubeconfigPath, kubeConfigYaml, 0o644)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = os.Setenv("KUBECONFIG", abs)
|
||||
err = os.Setenv("KUBECONFIG", kubeconfigPath)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TearDownSuite() {
|
||||
s.BaseSuite.TearDownSuite()
|
||||
if s.k3sContainer != nil {
|
||||
if s.T().Failed() || *showLog {
|
||||
k3sLogs, err := s.k3sContainer.Logs(s.T().Context())
|
||||
if err == nil {
|
||||
if res, err := io.ReadAll(k3sLogs); err == nil {
|
||||
s.T().Log(string(res))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generatedFiles := []string{
|
||||
"./fixtures/k8s/config.skip/kubeconfig.yaml",
|
||||
"./fixtures/k8s/config.skip/k3s.log",
|
||||
"./fixtures/k8s/coredns.yaml",
|
||||
"./fixtures/k8s/rolebindings.yaml",
|
||||
"./fixtures/k8s/traefik.yaml",
|
||||
"./fixtures/k8s/ccm.yaml",
|
||||
}
|
||||
|
||||
for _, filename := range generatedFiles {
|
||||
if err := os.Remove(filename); err != nil {
|
||||
if err := s.k3sContainer.Terminate(s.T().Context()); err != nil {
|
||||
log.Warn().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
s.BaseSuite.TearDownSuite()
|
||||
}
|
||||
|
||||
func (s *K8sSuite) TestIngressConfiguration() {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
services:
|
||||
server:
|
||||
image: rancher/k3s:v1.34.2-k3s1
|
||||
privileged: true
|
||||
command:
|
||||
- server
|
||||
- --disable-agent
|
||||
- --disable=coredns
|
||||
- --disable=servicelb
|
||||
- --disable=traefik
|
||||
- --disable=local-storage
|
||||
- --disable=metrics-server
|
||||
- --log=/output/k3s.log
|
||||
- --bind-address=server
|
||||
- --tls-san=server
|
||||
- --tls-san=172.31.42.3
|
||||
- --tls-san=172.31.42.4
|
||||
environment:
|
||||
K3S_CLUSTER_SECRET: somethingtotallyrandom
|
||||
K3S_TOKEN: somethingtotallyrandom
|
||||
K3S_KUBECONFIG_OUTPUT: /output/kubeconfig.yaml
|
||||
K3S_KUBECONFIG_MODE: 666
|
||||
volumes:
|
||||
- ./fixtures/k8s/config.skip:/output
|
||||
- ./fixtures/k8s:/var/lib/rancher/k3s/server/manifests
|
||||
|
||||
node:
|
||||
image: rancher/k3s:v1.34.2-k3s1
|
||||
privileged: true
|
||||
environment:
|
||||
K3S_TOKEN: somethingtotallyrandom
|
||||
K3S_URL: https://server:6443
|
||||
K3S_CLUSTER_SECRET: somethingtotallyrandom
|
||||
@@ -2419,6 +2419,43 @@ func waitForWritePartial(t *testing.T, conn net.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestAllowACMEByPassRedirect() {
|
||||
// Start a local server that simulates an ACME challenge solver.
|
||||
acmeSolver := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
_, _ = rw.Write([]byte("acme-challenge-token"))
|
||||
}))
|
||||
defer acmeSolver.Close()
|
||||
|
||||
file := s.adaptFile("fixtures/simple_acme_bypass_redirect.toml", struct {
|
||||
AcmeSolverURL string
|
||||
}{
|
||||
AcmeSolverURL: acmeSolver.URL,
|
||||
})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
// Wait for Traefik to be ready with the user-defined ACME challenge router.
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.BodyContains("acme-challenge@file"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
noRedirectClient := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
// ACME challenge path should NOT be redirected — it should reach the solver.
|
||||
resp, err := noRedirectClient.Get("http://127.0.0.1:8888/.well-known/acme-challenge/test-token")
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), http.StatusOK, resp.StatusCode)
|
||||
|
||||
// Normal path should be redirected to HTTPS.
|
||||
resp, err = noRedirectClient.Get("http://127.0.0.1:8888/other-path")
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), http.StatusMovedPermanently, resp.StatusCode)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestFailoverService() {
|
||||
s.createComposeProject("base")
|
||||
|
||||
|
||||
+15
-15
@@ -5,7 +5,7 @@
|
||||
"traefik"
|
||||
],
|
||||
"service": "api@internal",
|
||||
"rule": "PathPrefix(`/api`)",
|
||||
"rule": "PathPrefix(\"/api\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": 9223372036854775806,
|
||||
"observability": {
|
||||
@@ -28,7 +28,7 @@
|
||||
"dashboard_stripprefix@internal"
|
||||
],
|
||||
"service": "dashboard@internal",
|
||||
"rule": "PathPrefix(`/`)",
|
||||
"rule": "PathPrefix(\"/\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": 9223372036854775805,
|
||||
"observability": {
|
||||
@@ -42,12 +42,12 @@
|
||||
"traefik"
|
||||
]
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-1c0cf64bde37d9d0df06@kubernetesgateway": {
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3@kubernetesgateway": {
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"service": "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-1c0cf64bde37d9d0df06-wrr",
|
||||
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
||||
"service": "httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3-wrr",
|
||||
"rule": "Host(\"foo.com\") \u0026\u0026 Path(\"/bar\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": 100008,
|
||||
"observability": {
|
||||
@@ -61,12 +61,12 @@
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-1c0cf64bde37d9d0df06@kubernetesgateway": {
|
||||
"httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-af329269dd38031b03e3@kubernetesgateway": {
|
||||
"entryPoints": [
|
||||
"websecure"
|
||||
],
|
||||
"service": "httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-1c0cf64bde37d9d0df06-wrr",
|
||||
"rule": "Host(`foo.com`) \u0026\u0026 Path(`/bar`)",
|
||||
"service": "httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-af329269dd38031b03e3-wrr",
|
||||
"rule": "Host(\"foo.com\") \u0026\u0026 Path(\"/bar\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": 100008,
|
||||
"tls": {},
|
||||
@@ -142,7 +142,7 @@
|
||||
"http://10.42.0.6:80": "UP"
|
||||
}
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-1c0cf64bde37d9d0df06-wrr@kubernetesgateway": {
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3-wrr@kubernetesgateway": {
|
||||
"weighted": {
|
||||
"services": [
|
||||
{
|
||||
@@ -153,10 +153,10 @@
|
||||
},
|
||||
"status": "enabled",
|
||||
"usedBy": [
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-1c0cf64bde37d9d0df06@kubernetesgateway"
|
||||
"httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3@kubernetesgateway"
|
||||
]
|
||||
},
|
||||
"httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-1c0cf64bde37d9d0df06-wrr@kubernetesgateway": {
|
||||
"httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-af329269dd38031b03e3-wrr@kubernetesgateway": {
|
||||
"weighted": {
|
||||
"services": [
|
||||
{
|
||||
@@ -167,7 +167,7 @@
|
||||
},
|
||||
"status": "enabled",
|
||||
"usedBy": [
|
||||
"httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-1c0cf64bde37d9d0df06@kubernetesgateway"
|
||||
"httproute-default-http-app-1-gw-default-my-https-gateway-ep-websecure-0-af329269dd38031b03e3@kubernetesgateway"
|
||||
]
|
||||
},
|
||||
"noop@internal": {
|
||||
@@ -180,7 +180,7 @@
|
||||
"footcp"
|
||||
],
|
||||
"service": "tcproute-default-tcp-app-1-gw-default-my-tcp-gateway-ep-footcp-0-e3b0c44298fc1c149afb-wrr",
|
||||
"rule": "HostSNI(`*`)",
|
||||
"rule": "HostSNI(\"*\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": -1,
|
||||
"status": "enabled",
|
||||
@@ -193,7 +193,7 @@
|
||||
"footlsterminate"
|
||||
],
|
||||
"service": "tcproute-default-tcp-app-1-gw-default-my-tls-gateway-ep-footlsterminate-0-e3b0c44298fc1c149afb-wrr",
|
||||
"rule": "HostSNI(`*`)",
|
||||
"rule": "HostSNI(\"*\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": -1,
|
||||
"tls": {
|
||||
@@ -209,7 +209,7 @@
|
||||
"footlspassthrough"
|
||||
],
|
||||
"service": "tlsroute-default-tls-app-1-gw-default-my-tls-gateway-ep-footlspassthrough-0-e3b0c44298fc1c149afb-wrr",
|
||||
"rule": "HostSNI(`foo.bar`)",
|
||||
"rule": "HostSNI(\"foo.bar\")",
|
||||
"ruleSyntax": "default",
|
||||
"priority": 7,
|
||||
"tls": {
|
||||
|
||||
Reference in New Issue
Block a user