mirror of
https://github.com/traefik/traefik
synced 2026-02-03 06:30:31 +00:00
Support permanent-redirect and temporal-redirect annotations
This commit is contained in:
@@ -318,6 +318,10 @@ The following annotations are organized by category for easier navigation.
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-iouse-regex" href="#opt-nginx-ingress-kubernetes-iouse-regex" title="#opt-nginx-ingress-kubernetes-iouse-regex">`nginx.ingress.kubernetes.io/use-regex`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iorewrite-target" href="#opt-nginx-ingress-kubernetes-iorewrite-target" title="#opt-nginx-ingress-kubernetes-iorewrite-target">`nginx.ingress.kubernetes.io/rewrite-target`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect">`nginx.ingress.kubernetes.io/permanent-redirect`</a> | Defaults to a 301 Moved Permanently status code. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect-code" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code">`nginx.ingress.kubernetes.io/permanent-redirect-code`</a> | Only valid 3XX HTTP Status Codes are accepted. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iotemporal-redirect" href="#opt-nginx-ingress-kubernetes-iotemporal-redirect" title="#opt-nginx-ingress-kubernetes-iotemporal-redirect">`nginx.ingress.kubernetes.io/temporal-redirect`</a> | Takes precedence over the `permanent-redirect` annotation. Defaults to a 302 Found status code. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iotemporal-redirect-code" href="#opt-nginx-ingress-kubernetes-iotemporal-redirect-code" title="#opt-nginx-ingress-kubernetes-iotemporal-redirect-code">`nginx.ingress.kubernetes.io/temporal-redirect-code`</a> | Only valid 3XX HTTP Status Codes are accepted. |
|
||||
|
||||
### IP Whitelist
|
||||
|
||||
@@ -393,9 +397,6 @@ The following annotations are organized by category for easier navigation.
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-window">`nginx.ingress.kubernetes.io/global-rate-limit-window`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-key">`nginx.ingress.kubernetes.io/global-rate-limit-key`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs" href="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs" title="#opt-nginx-ingress-kubernetes-ioglobal-rate-limit-ignored-cidrs">`nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect">`nginx.ingress.kubernetes.io/permanent-redirect`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopermanent-redirect-code" href="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code" title="#opt-nginx-ingress-kubernetes-iopermanent-redirect-code">`nginx.ingress.kubernetes.io/permanent-redirect-code`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iotemporal-redirect" href="#opt-nginx-ingress-kubernetes-iotemporal-redirect" title="#opt-nginx-ingress-kubernetes-iotemporal-redirect">`nginx.ingress.kubernetes.io/temporal-redirect`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iopreserve-trailing-slash" href="#opt-nginx-ingress-kubernetes-iopreserve-trailing-slash" title="#opt-nginx-ingress-kubernetes-iopreserve-trailing-slash">`nginx.ingress.kubernetes.io/preserve-trailing-slash`</a> | Traefik preserves trailing slash by default. |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-cookie-domain" href="#opt-nginx-ingress-kubernetes-ioproxy-cookie-domain" title="#opt-nginx-ingress-kubernetes-ioproxy-cookie-domain">`nginx.ingress.kubernetes.io/proxy-cookie-domain`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-cookie-path" href="#opt-nginx-ingress-kubernetes-ioproxy-cookie-path" title="#opt-nginx-ingress-kubernetes-ioproxy-cookie-path">`nginx.ingress.kubernetes.io/proxy-cookie-path`</a> | |
|
||||
|
||||
@@ -645,6 +645,9 @@ type RedirectRegex struct {
|
||||
Replacement string `json:"replacement,omitempty" toml:"replacement,omitempty" yaml:"replacement,omitempty"`
|
||||
// Permanent defines whether the redirection is permanent (308).
|
||||
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
|
||||
|
||||
// StatusCode is for supporting the NGINX annotations related to redirect.
|
||||
StatusCode *int `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
@@ -663,7 +666,7 @@ type RedirectScheme struct {
|
||||
// ForcePermanentRedirect is an internal field (not exposed in configuration).
|
||||
// When set to true, this forces the use of permanent redirects 308, regardless of the request method.
|
||||
// Used by the provider ingress-ngin.
|
||||
ForcePermanentRedirect bool `json:"-" toml:"-" yaml:"-" label:"-"`
|
||||
ForcePermanentRedirect bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
@@ -918,7 +918,7 @@ func (in *Middleware) DeepCopyInto(out *Middleware) {
|
||||
if in.RedirectRegex != nil {
|
||||
in, out := &in.RedirectRegex, &out.RedirectRegex
|
||||
*out = new(RedirectRegex)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RedirectScheme != nil {
|
||||
in, out := &in.RedirectScheme, &out.RedirectScheme
|
||||
@@ -1186,6 +1186,11 @@ func (in *RateLimit) DeepCopy() *RateLimit {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RedirectRegex) DeepCopyInto(out *RedirectRegex) {
|
||||
*out = *in
|
||||
if in.StatusCode != nil {
|
||||
in, out := &in.StatusCode, &out.StatusCode
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -18,32 +18,32 @@ const typeName = "Redirect"
|
||||
var uriRegexp = regexp.MustCompile(`^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`)
|
||||
|
||||
type redirect struct {
|
||||
next http.Handler
|
||||
regex *regexp.Regexp
|
||||
replacement string
|
||||
permanent bool
|
||||
forcePermanentRedirect bool
|
||||
errHandler utils.ErrorHandler
|
||||
name string
|
||||
rawURL func(*http.Request) string
|
||||
next http.Handler
|
||||
regex *regexp.Regexp
|
||||
replacement string
|
||||
permanent bool
|
||||
statusCode *int
|
||||
errHandler utils.ErrorHandler
|
||||
name string
|
||||
rawURL func(*http.Request) string
|
||||
}
|
||||
|
||||
// New creates a Redirect middleware.
|
||||
func newRedirect(next http.Handler, regex, replacement string, permanent bool, forcePermanentRedirect bool, rawURL func(*http.Request) string, name string) (http.Handler, error) {
|
||||
func newRedirect(next http.Handler, regex, replacement string, permanent bool, statusCode *int, rawURL func(*http.Request) string, name string) (http.Handler, error) {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &redirect{
|
||||
regex: re,
|
||||
replacement: replacement,
|
||||
permanent: permanent,
|
||||
forcePermanentRedirect: forcePermanentRedirect,
|
||||
errHandler: utils.DefaultHandler,
|
||||
next: next,
|
||||
name: name,
|
||||
rawURL: rawURL,
|
||||
regex: re,
|
||||
replacement: replacement,
|
||||
permanent: permanent,
|
||||
statusCode: statusCode,
|
||||
errHandler: utils.DefaultHandler,
|
||||
next: next,
|
||||
name: name,
|
||||
rawURL: rawURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
if newURL != oldURL {
|
||||
handler := &moveHandler{location: parsedURL, permanent: r.permanent, forcePermanentRedirect: r.forcePermanentRedirect}
|
||||
handler := &moveHandler{location: parsedURL, permanent: r.permanent, statusCode: r.statusCode}
|
||||
handler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
@@ -84,9 +84,9 @@ func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
type moveHandler struct {
|
||||
location *url.URL
|
||||
permanent bool
|
||||
forcePermanentRedirect bool
|
||||
location *url.URL
|
||||
permanent bool
|
||||
statusCode *int
|
||||
}
|
||||
|
||||
func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
@@ -104,8 +104,8 @@ func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if m.forcePermanentRedirect {
|
||||
status = http.StatusPermanentRedirect
|
||||
if m.statusCode != nil {
|
||||
status = *m.statusCode
|
||||
}
|
||||
|
||||
rw.WriteHeader(status)
|
||||
|
||||
@@ -17,7 +17,7 @@ func NewRedirectRegex(ctx context.Context, next http.Handler, conf dynamic.Redir
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
logger.Debug().Msgf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement)
|
||||
|
||||
return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, false, rawURL, name)
|
||||
return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, conf.StatusCode, rawURL, name)
|
||||
}
|
||||
|
||||
func rawURL(req *http.Request) string {
|
||||
|
||||
@@ -40,7 +40,13 @@ func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.Redi
|
||||
|
||||
rs := &redirectScheme{name: name}
|
||||
|
||||
handler, err := newRedirect(next, uriPattern, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, conf.ForcePermanentRedirect, rs.clientRequestURL, name)
|
||||
var permanentRedirectCode *int
|
||||
if conf.ForcePermanentRedirect {
|
||||
status := http.StatusPermanentRedirect
|
||||
permanentRedirectCode = &status
|
||||
}
|
||||
|
||||
handler, err := newRedirect(next, uriPattern, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, permanentRedirectCode, rs.clientRequestURL, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -871,7 +871,7 @@ func (in *MiddlewareSpec) DeepCopyInto(out *MiddlewareSpec) {
|
||||
if in.RedirectRegex != nil {
|
||||
in, out := &in.RedirectRegex, &out.RedirectRegex
|
||||
*out = new(dynamic.RedirectRegex)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RedirectScheme != nil {
|
||||
in, out := &in.RedirectScheme, &out.RedirectScheme
|
||||
|
||||
@@ -26,6 +26,11 @@ type ingressConfig struct {
|
||||
UseRegex *bool `annotation:"nginx.ingress.kubernetes.io/use-regex"`
|
||||
RewriteTarget *string `annotation:"nginx.ingress.kubernetes.io/rewrite-target"`
|
||||
|
||||
PermanentRedirect *string `annotation:"nginx.ingress.kubernetes.io/permanent-redirect"`
|
||||
PermanentRedirectCode *int `annotation:"nginx.ingress.kubernetes.io/permanent-redirect-code"`
|
||||
TemporalRedirect *string `annotation:"nginx.ingress.kubernetes.io/temporal-redirect"`
|
||||
TemporalRedirectCode *int `annotation:"nginx.ingress.kubernetes.io/temporal-redirect-code"`
|
||||
|
||||
Affinity *string `annotation:"nginx.ingress.kubernetes.io/affinity"`
|
||||
SessionCookieName *string `annotation:"nginx.ingress.kubernetes.io/session-cookie-name"`
|
||||
SessionCookieSecure *bool `annotation:"nginx.ingress.kubernetes.io/session-cookie-secure"`
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-permanent-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/permanent-redirect: "https://www.google.com"
|
||||
nginx.ingress.kubernetes.io/permanent-redirect-code: "300"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: permanent-redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-permanent-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/permanent-redirect: "https://www.google.com"
|
||||
nginx.ingress.kubernetes.io/permanent-redirect-code: "500"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: permanent-redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-permanent-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/permanent-redirect: "https://www.google.com"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: permanent-redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-temporal-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/temporal-redirect: "https://www.google.com"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: temporal-redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/permanent-redirect: "https://www.traefik.io"
|
||||
nginx.ingress.kubernetes.io/temporal-redirect: "https://www.google.com"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-temporal-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/temporal-redirect: "https://www.google.com"
|
||||
nginx.ingress.kubernetes.io/temporal-redirect-code: "308"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: temporal-redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ingress-with-temporal-redirect
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/temporal-redirect: "https://www.google.com"
|
||||
nginx.ingress.kubernetes.io/temporal-redirect-code: "429"
|
||||
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: temporal-redirect.localhost
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: whoami
|
||||
port:
|
||||
number: 80
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"maps"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
@@ -810,6 +811,8 @@ func (p *Provider) applyMiddlewares(namespace, routerKey, rulePath string, ingre
|
||||
// TODO: check how to remove this, and create the HTTP router elsewhere.
|
||||
p.applySSLRedirectConfiguration(routerKey, ingressConfig, hasTLS, rt, conf)
|
||||
|
||||
applyRedirect(routerKey, ingressConfig, rt, conf)
|
||||
|
||||
applyUpstreamVhost(routerKey, ingressConfig, rt, conf)
|
||||
|
||||
if err := p.applyCustomHeaders(routerKey, ingressConfig, rt, conf); err != nil {
|
||||
@@ -819,6 +822,48 @@ func (p *Provider) applyMiddlewares(namespace, routerKey, rulePath string, ingre
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyRedirect(routerName string, ingressConfig ingressConfig, rt *dynamic.Router, conf *dynamic.Configuration) {
|
||||
if ingressConfig.PermanentRedirect == nil && ingressConfig.TemporalRedirect == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
redirectURL string
|
||||
code int
|
||||
)
|
||||
|
||||
if ingressConfig.PermanentRedirect != nil {
|
||||
redirectURL = *ingressConfig.PermanentRedirect
|
||||
code = ptr.Deref(ingressConfig.PermanentRedirectCode, http.StatusMovedPermanently)
|
||||
|
||||
// NGINX only accepts valid redirect codes and defaults to 301.
|
||||
if code < 300 || code > 308 {
|
||||
code = http.StatusMovedPermanently
|
||||
}
|
||||
}
|
||||
|
||||
// TemporalRedirect takes precedence over the PermanentRedirect.
|
||||
if ingressConfig.TemporalRedirect != nil {
|
||||
redirectURL = *ingressConfig.TemporalRedirect
|
||||
code = ptr.Deref(ingressConfig.TemporalRedirectCode, http.StatusFound)
|
||||
|
||||
// NGINX only accepts valid redirect codes and defaults to 302.
|
||||
if code < 300 || code > 308 {
|
||||
code = http.StatusFound
|
||||
}
|
||||
}
|
||||
|
||||
redirectMiddlewareName := routerName + "-redirect"
|
||||
conf.HTTP.Middlewares[redirectMiddlewareName] = &dynamic.Middleware{
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: redirectURL,
|
||||
StatusCode: &code,
|
||||
},
|
||||
}
|
||||
rt.Middlewares = append(rt.Middlewares, redirectMiddlewareName)
|
||||
}
|
||||
|
||||
func (p *Provider) applyCustomHeaders(routerName string, ingressConfig ingressConfig, rt *dynamic.Router, conf *dynamic.Configuration) error {
|
||||
customHeaders := ptr.Deref(ingressConfig.CustomHeaders, "")
|
||||
if customHeaders == "" {
|
||||
|
||||
@@ -2,6 +2,7 @@ package ingressnginx
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -1063,6 +1064,384 @@ func TestLoadIngresses(t *testing.T) {
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Permanent Redirect",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/14-ingress-with-permanent-redirect.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-permanent-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`permanent-redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-permanent-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-permanent-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-permanent-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusMovedPermanently),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-permanent-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Permanent Redirect Code - wrong code",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/14-ingress-with-permanent-redirect-code-wrong-code.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-permanent-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`permanent-redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-permanent-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-permanent-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-permanent-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusMovedPermanently),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-permanent-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Permanent Redirect Code - correct code",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/14-ingress-with-permanent-redirect-code-correct-code.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-permanent-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`permanent-redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-permanent-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-permanent-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-permanent-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusMultipleChoices),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-permanent-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Temporal Redirect takes precedence over Permanent Redirect",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/16-ingress-with-temporal-and-permanent-redirect.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusFound),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Temporal Redirect",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/15-ingress-with-temporal-redirect.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-temporal-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`temporal-redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-temporal-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-temporal-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-temporal-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusFound),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-temporal-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Temporal Redirect Code - wrong code",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/17-ingress-with-temporal-redirect-code-wrong-code.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-temporal-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`temporal-redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-temporal-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-temporal-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-temporal-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusFound),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-temporal-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Temporal Redirect Code - correct code",
|
||||
paths: []string{
|
||||
"services.yml",
|
||||
"ingressclasses.yml",
|
||||
"ingresses/17-ingress-with-temporal-redirect-code-correct-code.yml",
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-ingress-with-temporal-redirect-rule-0-path-0": {
|
||||
Rule: "Host(`temporal-redirect.localhost`) && Path(`/`)",
|
||||
RuleSyntax: "default",
|
||||
Service: "default-ingress-with-temporal-redirect-whoami-80",
|
||||
Middlewares: []string{"default-ingress-with-temporal-redirect-rule-0-path-0-redirect"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-ingress-with-temporal-redirect-rule-0-path-0-redirect": {
|
||||
RedirectRegex: &dynamic.RedirectRegex{
|
||||
Regex: ".*",
|
||||
Replacement: "https://www.google.com",
|
||||
StatusCode: ptr.To(http.StatusPermanentRedirect),
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-ingress-with-temporal-redirect-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
Strategy: "wrr",
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: dynamic.DefaultFlushInterval,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
||||
Reference in New Issue
Block a user