redirect to another entryPoint per frontend
This commit is contained in:
parent
66e489addb
commit
5d6384e101
19 changed files with 251 additions and 14 deletions
|
@ -172,6 +172,7 @@ Labels can be used on containers to override default behaviour.
|
||||||
| `traefik.frontend.headers.customrequestheaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: `HEADER:value,HEADER2:value2` |
|
| `traefik.frontend.headers.customrequestheaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: `HEADER:value,HEADER2:value2` |
|
||||||
| `traefik.frontend.headers.customresponseheaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: `HEADER:value,HEADER2:value2` |
|
| `traefik.frontend.headers.customresponseheaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: `HEADER:value,HEADER2:value2` |
|
||||||
| `traefik.docker.network` | Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect <container_id>`) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name. |
|
| `traefik.docker.network` | Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect <container_id>`) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name. |
|
||||||
|
| `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||||
|
|
||||||
### On Service
|
### On Service
|
||||||
|
|
||||||
|
@ -188,6 +189,7 @@ Services labels can be used for overriding default behaviour
|
||||||
| `traefik.<service-name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
|
| `traefik.<service-name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
|
||||||
| `traefik.<service-name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
|
| `traefik.<service-name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
|
||||||
| `traefik.<service-name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
|
| `traefik.<service-name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
|
||||||
|
| `traefik.<service-name>.frontend.redirect` | Overrides `traefik.frontend.redirect`. |
|
||||||
|
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|
|
@ -88,6 +88,8 @@ Annotations can be used on containers to override default behaviour for the whol
|
||||||
Override the default frontend rule type. Default: `PathPrefix`.
|
Override the default frontend rule type. Default: `PathPrefix`.
|
||||||
- `traefik.frontend.priority: "3"`
|
- `traefik.frontend.priority: "3"`
|
||||||
Override the default frontend rule priority.
|
Override the default frontend rule priority.
|
||||||
|
- `traefik.frontend.redirect: https`:
|
||||||
|
Enables Redirect to another entryPoint for that frontend (e.g. HTTPS).
|
||||||
|
|
||||||
Annotations can be used on the Kubernetes service to override default behaviour:
|
Annotations can be used on the Kubernetes service to override default behaviour:
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ Labels can be used on task containers to override default behaviour:
|
||||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
||||||
|
| `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||||
| `traefik.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
| `traefik.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||||
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
||||||
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
||||||
|
|
|
@ -271,6 +271,7 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
||||||
"getEntryPoints": p.getEntryPoints,
|
"getEntryPoints": p.getEntryPoints,
|
||||||
"getBasicAuth": p.getBasicAuth,
|
"getBasicAuth": p.getBasicAuth,
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
|
"getRedirect": p.getRedirect,
|
||||||
"hasCircuitBreakerLabel": p.hasCircuitBreakerLabel,
|
"hasCircuitBreakerLabel": p.hasCircuitBreakerLabel,
|
||||||
"getCircuitBreakerExpression": p.getCircuitBreakerExpression,
|
"getCircuitBreakerExpression": p.getCircuitBreakerExpression,
|
||||||
"hasLoadBalancerLabel": p.hasLoadBalancerLabel,
|
"hasLoadBalancerLabel": p.hasLoadBalancerLabel,
|
||||||
|
@ -293,6 +294,7 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
||||||
"getServicePassHostHeader": p.getServicePassHostHeader,
|
"getServicePassHostHeader": p.getServicePassHostHeader,
|
||||||
"getServicePriority": p.getServicePriority,
|
"getServicePriority": p.getServicePriority,
|
||||||
"getServiceBackend": p.getServiceBackend,
|
"getServiceBackend": p.getServiceBackend,
|
||||||
|
"getServiceRedirect": p.getServiceRedirect,
|
||||||
"getWhitelistSourceRange": p.getWhitelistSourceRange,
|
"getWhitelistSourceRange": p.getWhitelistSourceRange,
|
||||||
"getRequestHeaders": p.getRequestHeaders,
|
"getRequestHeaders": p.getRequestHeaders,
|
||||||
"getResponseHeaders": p.getResponseHeaders,
|
"getResponseHeaders": p.getResponseHeaders,
|
||||||
|
@ -333,6 +335,7 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return configuration
|
return configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +473,14 @@ func (p *Provider) getServiceProtocol(container dockerData, serviceName string)
|
||||||
return p.getProtocol(container)
|
return p.getProtocol(container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract protocol from labels for a given service and a given docker container
|
||||||
|
func (p *Provider) getServiceRedirect(container dockerData, serviceName string) string {
|
||||||
|
if value, ok := getContainerServiceLabel(container, serviceName, "frontend.redirect"); ok {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return p.getRedirect(container)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) hasLoadBalancerLabel(container dockerData) bool {
|
func (p *Provider) hasLoadBalancerLabel(container dockerData) bool {
|
||||||
_, errMethod := getLabel(container, types.LabelBackendLoadbalancerMethod)
|
_, errMethod := getLabel(container, types.LabelBackendLoadbalancerMethod)
|
||||||
_, errSticky := getLabel(container, types.LabelBackendLoadbalancerSticky)
|
_, errSticky := getLabel(container, types.LabelBackendLoadbalancerSticky)
|
||||||
|
@ -831,6 +842,14 @@ func parseCustomHeaders(container dockerData, containerType string) map[string]s
|
||||||
}
|
}
|
||||||
return customHeaders
|
return customHeaders
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getRedirect(container dockerData) string {
|
||||||
|
if entryPointredirect, err := getLabel(container, types.LabelFrontendRedirect); err == nil {
|
||||||
|
return entryPointredirect
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func isContainerEnabled(container dockerData, exposedByDefault bool) bool {
|
func isContainerEnabled(container dockerData, exposedByDefault bool) bool {
|
||||||
return exposedByDefault && container.Labels[types.LabelEnable] != "false" || container.Labels[types.LabelEnable] == "true"
|
return exposedByDefault && container.Labels[types.LabelEnable] != "false" || container.Labels[types.LabelEnable] == "true"
|
||||||
}
|
}
|
||||||
|
|
|
@ -902,6 +902,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
BasicAuth: []string{},
|
BasicAuth: []string{},
|
||||||
|
Redirect: "",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test-docker-localhost-0": {
|
"route-frontend-Host-test-docker-localhost-0": {
|
||||||
Rule: "Host:test.docker.localhost",
|
Rule: "Host:test.docker.localhost",
|
||||||
|
@ -929,6 +930,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
types.LabelBackend: "foobar",
|
types.LabelBackend: "foobar",
|
||||||
types.LabelFrontendEntryPoints: "http,https",
|
types.LabelFrontendEntryPoints: "http,https",
|
||||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
types.LabelFrontendRedirect: "https",
|
||||||
}),
|
}),
|
||||||
ports(nat.PortMap{
|
ports(nat.PortMap{
|
||||||
"80/tcp": {},
|
"80/tcp": {},
|
||||||
|
@ -952,6 +954,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{"http", "https"},
|
EntryPoints: []string{"http", "https"},
|
||||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||||
|
Redirect: "https",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test1-docker-localhost-0": {
|
"route-frontend-Host-test1-docker-localhost-0": {
|
||||||
Rule: "Host:test1.docker.localhost",
|
Rule: "Host:test1.docker.localhost",
|
||||||
|
@ -963,6 +966,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
BasicAuth: []string{},
|
BasicAuth: []string{},
|
||||||
|
Redirect: "",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test2-docker-localhost-1": {
|
"route-frontend-Host-test2-docker-localhost-1": {
|
||||||
Rule: "Host:test2.docker.localhost",
|
Rule: "Host:test2.docker.localhost",
|
||||||
|
@ -1010,6 +1014,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{"http", "https"},
|
EntryPoints: []string{"http", "https"},
|
||||||
BasicAuth: []string{},
|
BasicAuth: []string{},
|
||||||
|
Redirect: "",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test1-docker-localhost-0": {
|
"route-frontend-Host-test1-docker-localhost-0": {
|
||||||
Rule: "Host:test1.docker.localhost",
|
Rule: "Host:test1.docker.localhost",
|
||||||
|
|
|
@ -333,6 +333,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
||||||
"traefik.service.port": "2503",
|
"traefik.service.port": "2503",
|
||||||
"traefik.service.frontend.entryPoints": "http,https",
|
"traefik.service.frontend.entryPoints": "http,https",
|
||||||
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
"traefik.service.frontend.redirect": "https",
|
||||||
}),
|
}),
|
||||||
ports(nat.PortMap{
|
ports(nat.PortMap{
|
||||||
"80/tcp": {},
|
"80/tcp": {},
|
||||||
|
@ -346,6 +347,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{"http", "https"},
|
EntryPoints: []string{"http", "https"},
|
||||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||||
|
Redirect: "https",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"service-service": {
|
"service-service": {
|
||||||
Rule: "Host:foo.docker.localhost",
|
Rule: "Host:foo.docker.localhost",
|
||||||
|
@ -379,6 +381,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
||||||
"traefik.service.frontend.priority": "5000",
|
"traefik.service.frontend.priority": "5000",
|
||||||
"traefik.service.frontend.entryPoints": "http,https,ws",
|
"traefik.service.frontend.entryPoints": "http,https,ws",
|
||||||
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
"traefik.service.frontend.redirect": "https",
|
||||||
}),
|
}),
|
||||||
ports(nat.PortMap{
|
ports(nat.PortMap{
|
||||||
"80/tcp": {},
|
"80/tcp": {},
|
||||||
|
@ -405,6 +408,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
||||||
Priority: 5000,
|
Priority: 5000,
|
||||||
EntryPoints: []string{"http", "https", "ws"},
|
EntryPoints: []string{"http", "https", "ws"},
|
||||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||||
|
Redirect: "https",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"service-service": {
|
"service-service": {
|
||||||
Rule: "Path:/mypath",
|
Rule: "Path:/mypath",
|
||||||
|
@ -416,6 +420,7 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
BasicAuth: []string{},
|
BasicAuth: []string{},
|
||||||
|
Redirect: "",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"service-anotherservice": {
|
"service-anotherservice": {
|
||||||
Rule: "Path:/anotherpath",
|
Rule: "Path:/anotherpath",
|
||||||
|
|
|
@ -665,6 +665,7 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
BasicAuth: []string{},
|
BasicAuth: []string{},
|
||||||
|
Redirect: "",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test-docker-localhost-0": {
|
"route-frontend-Host-test-docker-localhost-0": {
|
||||||
Rule: "Host:test.docker.localhost",
|
Rule: "Host:test.docker.localhost",
|
||||||
|
@ -699,6 +700,7 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
||||||
types.LabelBackend: "foobar",
|
types.LabelBackend: "foobar",
|
||||||
types.LabelFrontendEntryPoints: "http,https",
|
types.LabelFrontendEntryPoints: "http,https",
|
||||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
types.LabelFrontendRedirect: "https",
|
||||||
}),
|
}),
|
||||||
withEndpointSpec(modeVIP),
|
withEndpointSpec(modeVIP),
|
||||||
withEndpoint(virtualIP("1", "127.0.0.1/24")),
|
withEndpoint(virtualIP("1", "127.0.0.1/24")),
|
||||||
|
@ -719,6 +721,7 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{"http", "https"},
|
EntryPoints: []string{"http", "https"},
|
||||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||||
|
Redirect: "https",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test1-docker-localhost-0": {
|
"route-frontend-Host-test1-docker-localhost-0": {
|
||||||
Rule: "Host:test1.docker.localhost",
|
Rule: "Host:test1.docker.localhost",
|
||||||
|
@ -730,6 +733,7 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
BasicAuth: []string{},
|
BasicAuth: []string{},
|
||||||
|
Redirect: "",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test2-docker-localhost-1": {
|
"route-frontend-Host-test2-docker-localhost-1": {
|
||||||
Rule: "Host:test2.docker.localhost",
|
Rule: "Host:test2.docker.localhost",
|
||||||
|
|
|
@ -187,6 +187,8 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
whitelistSourceRangeAnnotation := i.Annotations[annotationKubernetesWhitelistSourceRange]
|
whitelistSourceRangeAnnotation := i.Annotations[annotationKubernetesWhitelistSourceRange]
|
||||||
whitelistSourceRange := provider.SplitAndTrimString(whitelistSourceRangeAnnotation)
|
whitelistSourceRange := provider.SplitAndTrimString(whitelistSourceRangeAnnotation)
|
||||||
|
|
||||||
|
entryPointRedirect, _ := i.Annotations[types.LabelFrontendRedirect]
|
||||||
|
|
||||||
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
||||||
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -203,6 +205,7 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
Priority: priority,
|
Priority: priority,
|
||||||
BasicAuth: basicAuthCreds,
|
BasicAuth: basicAuthCreds,
|
||||||
WhitelistSourceRange: whitelistSourceRange,
|
WhitelistSourceRange: whitelistSourceRange,
|
||||||
|
Redirect: entryPointRedirect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r.Host) > 0 {
|
if len(r.Host) > 0 {
|
||||||
|
|
|
@ -1105,6 +1105,36 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Paths: []v1beta1.HTTPIngressPath{
|
Paths: []v1beta1.HTTPIngressPath{
|
||||||
{
|
{
|
||||||
Path: "/auth-realm-customized",
|
Path: "/auth-realm-customized",
|
||||||
|
|
||||||
|
Backend: v1beta1.IngressBackend{
|
||||||
|
ServiceName: "service1",
|
||||||
|
ServicePort: intstr.FromInt(80),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Namespace: "testing",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"kubernetes.io/ingress.class": "traefik",
|
||||||
|
types.LabelFrontendRedirect: "https",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1beta1.IngressSpec{
|
||||||
|
Rules: []v1beta1.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "redirect",
|
||||||
|
IngressRuleValue: v1beta1.IngressRuleValue{
|
||||||
|
HTTP: &v1beta1.HTTPIngressRuleValue{
|
||||||
|
Paths: []v1beta1.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/https",
|
||||||
Backend: v1beta1.IngressBackend{
|
Backend: v1beta1.IngressBackend{
|
||||||
ServiceName: "service1",
|
ServiceName: "service1",
|
||||||
ServicePort: intstr.FromInt(80),
|
ServicePort: intstr.FromInt(80),
|
||||||
|
@ -1204,6 +1234,19 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Method: "wrr",
|
Method: "wrr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"redirect/https": {
|
||||||
|
Servers: map[string]types.Server{
|
||||||
|
"http://example.com": {
|
||||||
|
URL: "http://example.com",
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CircuitBreaker: nil,
|
||||||
|
LoadBalancer: &types.LoadBalancer{
|
||||||
|
Sticky: false,
|
||||||
|
Method: "wrr",
|
||||||
|
},
|
||||||
|
},
|
||||||
"test/whitelist-source-range": {
|
"test/whitelist-source-range": {
|
||||||
Servers: map[string]types.Server{
|
Servers: map[string]types.Server{
|
||||||
"http://example.com": {
|
"http://example.com": {
|
||||||
|
@ -1241,6 +1284,7 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Rule: "Host:foo",
|
Rule: "Host:foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Redirect: "",
|
||||||
},
|
},
|
||||||
"other/stuff": {
|
"other/stuff": {
|
||||||
Backend: "other/stuff",
|
Backend: "other/stuff",
|
||||||
|
@ -1253,6 +1297,7 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Rule: "Host:other",
|
Rule: "Host:other",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Redirect: "",
|
||||||
},
|
},
|
||||||
"basic/auth": {
|
"basic/auth": {
|
||||||
Backend: "basic/auth",
|
Backend: "basic/auth",
|
||||||
|
@ -1266,7 +1311,22 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
BasicAuth: []string{"myUser:myEncodedPW"},
|
BasicAuth: []string{"myUser:myEncodedPW"},
|
||||||
|
Redirect: "",
|
||||||
},
|
},
|
||||||
|
"redirect/https": {
|
||||||
|
Backend: "redirect/https",
|
||||||
|
PassHostHeader: true,
|
||||||
|
Routes: map[string]types.Route{
|
||||||
|
"/https": {
|
||||||
|
Rule: "PathPrefix:/https",
|
||||||
|
},
|
||||||
|
"redirect": {
|
||||||
|
Rule: "Host:redirect",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Redirect: "https",
|
||||||
|
},
|
||||||
|
|
||||||
"test/whitelist-source-range": {
|
"test/whitelist-source-range": {
|
||||||
Backend: "test/whitelist-source-range",
|
Backend: "test/whitelist-source-range",
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
|
@ -1282,6 +1342,7 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Rule: "Host:test",
|
Rule: "Host:test",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Redirect: "",
|
||||||
},
|
},
|
||||||
"rewrite/api": {
|
"rewrite/api": {
|
||||||
Backend: "rewrite/api",
|
Backend: "rewrite/api",
|
||||||
|
@ -1294,6 +1355,7 @@ func TestIngressAnnotations(t *testing.T) {
|
||||||
Rule: "Host:rewrite",
|
Rule: "Host:rewrite",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Redirect: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,13 @@ func (p *Provider) getBasicAuth(service rancherData) []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) getRedirect(service rancherData) string {
|
||||||
|
if redirect, err := getServiceLabel(service, types.LabelFrontendRedirect); err == nil {
|
||||||
|
return redirect
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) getFrontendName(service rancherData) string {
|
func (p *Provider) getFrontendName(service rancherData) string {
|
||||||
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
|
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
|
||||||
return provider.Normalize(p.getFrontendRule(service))
|
return provider.Normalize(p.getFrontendRule(service))
|
||||||
|
@ -239,6 +246,7 @@ func (p *Provider) loadRancherConfig(services []rancherData) *types.Configuratio
|
||||||
"getSticky": p.getSticky,
|
"getSticky": p.getSticky,
|
||||||
"hasStickinessLabel": p.hasStickinessLabel,
|
"hasStickinessLabel": p.hasStickinessLabel,
|
||||||
"getStickinessCookieName": p.getStickinessCookieName,
|
"getStickinessCookieName": p.getStickinessCookieName,
|
||||||
|
"getRedirect": p.getRedirect,
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter services
|
// filter services
|
||||||
|
@ -270,6 +278,7 @@ func (p *Provider) loadRancherConfig(services []rancherData) *types.Configuratio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return configuration
|
return configuration
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,6 +489,35 @@ func TestRancherGetPassHostHeader(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRancherGetRedirect(t *testing.T) {
|
||||||
|
provider := &Provider{
|
||||||
|
Domain: "rancher.localhost",
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
service rancherData
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
service: rancherData{
|
||||||
|
Name: "test-service",
|
||||||
|
Labels: map[string]string{
|
||||||
|
types.LabelFrontendRedirect: "https",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
expected: "https",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
actual := provider.getRedirect(test.service)
|
||||||
|
if actual != test.expected {
|
||||||
|
t.Fatalf("got %q, expected %q", actual, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRancherGetLabel(t *testing.T) {
|
func TestRancherGetLabel(t *testing.T) {
|
||||||
services := []struct {
|
services := []struct {
|
||||||
service rancherData
|
service rancherData
|
||||||
|
@ -544,6 +573,7 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
types.LabelPort: "80",
|
types.LabelPort: "80",
|
||||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
types.LabelFrontendRedirect: "https",
|
||||||
},
|
},
|
||||||
Health: "healthy",
|
Health: "healthy",
|
||||||
Containers: []string{"127.0.0.1"},
|
Containers: []string{"127.0.0.1"},
|
||||||
|
@ -556,6 +586,7 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
|
Redirect: "https",
|
||||||
|
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test-service-rancher-localhost": {
|
"route-frontend-Host-test-service-rancher-localhost": {
|
||||||
|
|
|
@ -1103,6 +1103,21 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf
|
||||||
log.Infof("Configured IP Whitelists: %s", frontend.WhitelistSourceRange)
|
log.Infof("Configured IP Whitelists: %s", frontend.WhitelistSourceRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(frontend.Redirect) > 0 {
|
||||||
|
proto := "http"
|
||||||
|
if server.globalConfiguration.EntryPoints[frontend.Redirect].TLS != nil {
|
||||||
|
proto = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
regex, replacement, err := server.buildRedirect(proto, entryPoint)
|
||||||
|
rewrite, err := middlewares.NewRewrite(regex, replacement, true)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error creating Frontend Redirect: %v", err)
|
||||||
|
}
|
||||||
|
n.Use(rewrite)
|
||||||
|
log.Debugf("Creating frontend %s redirect to %s", frontendName, proto)
|
||||||
|
}
|
||||||
|
|
||||||
if len(frontend.BasicAuth) > 0 {
|
if len(frontend.BasicAuth) > 0 {
|
||||||
users := types.Users{}
|
users := types.Users{}
|
||||||
for _, user := range frontend.BasicAuth {
|
for _, user := range frontend.BasicAuth {
|
||||||
|
@ -1254,21 +1269,13 @@ func (server *Server) wireFrontendBackend(serverRoute *serverRoute, handler http
|
||||||
func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *configuration.EntryPoint) (negroni.Handler, error) {
|
func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *configuration.EntryPoint) (negroni.Handler, error) {
|
||||||
regex := entryPoint.Redirect.Regex
|
regex := entryPoint.Redirect.Regex
|
||||||
replacement := entryPoint.Redirect.Replacement
|
replacement := entryPoint.Redirect.Replacement
|
||||||
|
var err error
|
||||||
if len(entryPoint.Redirect.EntryPoint) > 0 {
|
if len(entryPoint.Redirect.EntryPoint) > 0 {
|
||||||
regex = `^(?:https?:\/\/)?([\w\._-]+)(?::\d+)?(.*)$`
|
var protocol = "http"
|
||||||
if server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint] == nil {
|
|
||||||
return nil, errors.New("Unknown entrypoint " + entryPoint.Redirect.EntryPoint)
|
|
||||||
}
|
|
||||||
protocol := "http"
|
|
||||||
if server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint].TLS != nil {
|
if server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint].TLS != nil {
|
||||||
protocol = "https"
|
protocol = "https"
|
||||||
}
|
}
|
||||||
r, _ := regexp.Compile(`(:\d+)`)
|
regex, replacement, err = server.buildRedirect(protocol, entryPoint)
|
||||||
match := r.FindStringSubmatch(server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint].Address)
|
|
||||||
if len(match) == 0 {
|
|
||||||
return nil, errors.New("Bad Address format: " + server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint].Address)
|
|
||||||
}
|
|
||||||
replacement = protocol + "://$1" + match[0] + "$2"
|
|
||||||
}
|
}
|
||||||
rewrite, err := middlewares.NewRewrite(regex, replacement, true)
|
rewrite, err := middlewares.NewRewrite(regex, replacement, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1279,6 +1286,20 @@ func (server *Server) loadEntryPointConfig(entryPointName string, entryPoint *co
|
||||||
return rewrite, nil
|
return rewrite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (server *Server) buildRedirect(protocol string, entryPoint *configuration.EntryPoint) (string, string, error) {
|
||||||
|
regex := `^(?:https?:\/\/)?([\w\._-]+)(?::\d+)?(.*)$`
|
||||||
|
if server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint] == nil {
|
||||||
|
return "", "", fmt.Errorf("unknown target entrypoint %q", entryPoint.Redirect.EntryPoint)
|
||||||
|
}
|
||||||
|
r, _ := regexp.Compile(`(:\d+)`)
|
||||||
|
match := r.FindStringSubmatch(server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint].Address)
|
||||||
|
if len(match) == 0 {
|
||||||
|
return "", "", fmt.Errorf("bad Address format %q", server.globalConfiguration.EntryPoints[entryPoint.Redirect.EntryPoint].Address)
|
||||||
|
}
|
||||||
|
replacement := protocol + "://$1" + match[0] + "$2"
|
||||||
|
return regex, replacement, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (server *Server) buildDefaultHTTPRouter() *mux.Router {
|
func (server *Server) buildDefaultHTTPRouter() *mux.Router {
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
|
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
|
||||||
|
|
|
@ -903,6 +903,72 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerLoadConfigBuildRedirect(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
replacementProtocol string
|
||||||
|
globalConfiguration configuration.GlobalConfiguration
|
||||||
|
originEntryPointName string
|
||||||
|
expectedReplacement string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Redirect endpoint http to https with HTTPS protocol",
|
||||||
|
replacementProtocol: "https",
|
||||||
|
originEntryPointName: "http",
|
||||||
|
globalConfiguration: configuration.GlobalConfiguration{
|
||||||
|
EntryPoints: configuration.EntryPoints{
|
||||||
|
"http": &configuration.EntryPoint{
|
||||||
|
Address: ":80",
|
||||||
|
Redirect: &configuration.Redirect{
|
||||||
|
EntryPoint: "https",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"https": &configuration.EntryPoint{
|
||||||
|
Address: ":443",
|
||||||
|
TLS: &tls.TLS{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
expectedReplacement: "https://$1:443$2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Redirect endpoint http to http02 with HTTP protocol",
|
||||||
|
replacementProtocol: "http",
|
||||||
|
originEntryPointName: "http",
|
||||||
|
globalConfiguration: configuration.GlobalConfiguration{
|
||||||
|
EntryPoints: configuration.EntryPoints{
|
||||||
|
"http": &configuration.EntryPoint{
|
||||||
|
Address: ":80",
|
||||||
|
Redirect: &configuration.Redirect{
|
||||||
|
EntryPoint: "http02",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"http02": &configuration.EntryPoint{
|
||||||
|
Address: ":88",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
expectedReplacement: "http://$1:88$2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
srv := Server{globalConfiguration: test.globalConfiguration}
|
||||||
|
|
||||||
|
_, replacement, err := srv.buildRedirect(test.replacementProtocol, srv.globalConfiguration.EntryPoints[test.originEntryPointName])
|
||||||
|
|
||||||
|
require.NoError(t, err, "build redirect sent an unexpected error")
|
||||||
|
assert.Equal(t, test.expectedReplacement, replacement, "build redirect does not return the right replacement pattern")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func buildDynamicConfig(dynamicConfigBuilders ...func(*types.Configuration)) *types.Configuration {
|
func buildDynamicConfig(dynamicConfigBuilders ...func(*types.Configuration)) *types.Configuration {
|
||||||
config := &types.Configuration{
|
config := &types.Configuration{
|
||||||
Frontends: make(map[string]*types.Frontend),
|
Frontends: make(map[string]*types.Frontend),
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}"]
|
[frontends."frontend-{{getServiceBackend $container $serviceName}}"]
|
||||||
backend = "backend-{{getServiceBackend $container $serviceName}}"
|
backend = "backend-{{getServiceBackend $container $serviceName}}"
|
||||||
passHostHeader = {{getServicePassHostHeader $container $serviceName}}
|
passHostHeader = {{getServicePassHostHeader $container $serviceName}}
|
||||||
|
redirect = "{{getServiceRedirect $container $serviceName}}"
|
||||||
{{if getWhitelistSourceRange $container}}
|
{{if getWhitelistSourceRange $container}}
|
||||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
[frontends."frontend-{{$frontend}}"]
|
[frontends."frontend-{{$frontend}}"]
|
||||||
backend = "backend-{{getBackend $container}}"
|
backend = "backend-{{getBackend $container}}"
|
||||||
passHostHeader = {{getPassHostHeader $container}}
|
passHostHeader = {{getPassHostHeader $container}}
|
||||||
|
redirect = "{{getRedirect $container}}"
|
||||||
{{if getWhitelistSourceRange $container}}
|
{{if getWhitelistSourceRange $container}}
|
||||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
backend = "{{$frontend.Backend}}"
|
backend = "{{$frontend.Backend}}"
|
||||||
priority = {{$frontend.Priority}}
|
priority = {{$frontend.Priority}}
|
||||||
passHostHeader = {{$frontend.PassHostHeader}}
|
passHostHeader = {{$frontend.PassHostHeader}}
|
||||||
|
redirect = "{{$frontend.Redirect}}"
|
||||||
basicAuth = [{{range $frontend.BasicAuth}}
|
basicAuth = [{{range $frontend.BasicAuth}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
backend = "backend-{{getBackend $service}}"
|
backend = "backend-{{getBackend $service}}"
|
||||||
passHostHeader = {{getPassHostHeader $service}}
|
passHostHeader = {{getPassHostHeader $service}}
|
||||||
priority = {{getPriority $service}}
|
priority = {{getPriority $service}}
|
||||||
|
redirect = "{{getRedirect $service}}"
|
||||||
entryPoints = [{{range getEntryPoints $service}}
|
entryPoints = [{{range getEntryPoints $service}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{end}}]
|
||||||
|
|
|
@ -20,6 +20,7 @@ const (
|
||||||
LabelFrontendPriority = LabelPrefix + "frontend.priority"
|
LabelFrontendPriority = LabelPrefix + "frontend.priority"
|
||||||
LabelFrontendRule = LabelPrefix + "frontend.rule"
|
LabelFrontendRule = LabelPrefix + "frontend.rule"
|
||||||
LabelFrontendRuleType = LabelPrefix + "frontend.rule.type"
|
LabelFrontendRuleType = LabelPrefix + "frontend.rule.type"
|
||||||
|
LabelFrontendRedirect = LabelPrefix + "frontend.redirect"
|
||||||
LabelTraefikFrontendValue = LabelPrefix + "frontend.value"
|
LabelTraefikFrontendValue = LabelPrefix + "frontend.value"
|
||||||
LabelTraefikFrontendWhitelistSourceRange = LabelPrefix + "frontend.whitelistSourceRange"
|
LabelTraefikFrontendWhitelistSourceRange = LabelPrefix + "frontend.whitelistSourceRange"
|
||||||
LabelBackend = LabelPrefix + "backend"
|
LabelBackend = LabelPrefix + "backend"
|
||||||
|
|
|
@ -153,6 +153,7 @@ type Frontend struct {
|
||||||
Headers Headers `json:"headers,omitempty"`
|
Headers Headers `json:"headers,omitempty"`
|
||||||
Errors map[string]ErrorPage `json:"errors,omitempty"`
|
Errors map[string]ErrorPage `json:"errors,omitempty"`
|
||||||
RateLimit *RateLimit `json:"ratelimit,omitempty"`
|
RateLimit *RateLimit `json:"ratelimit,omitempty"`
|
||||||
|
Redirect string `json:"redirect,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadBalancerMethod holds the method of load balancing to use.
|
// LoadBalancerMethod holds the method of load balancing to use.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<span data-ng-repeat="entryPoint in frontendCtrl.frontend.entryPoints">
|
<span data-ng-repeat="entryPoint in frontendCtrl.frontend.entryPoints">
|
||||||
<span class="label label-primary">{{entryPoint}}</span><span data-ng-hide="$last"> </span>
|
<span class="label label-primary">{{entryPoint}}</span><span data-ng-hide="$last"> </span>
|
||||||
</span>
|
</span>
|
||||||
|
<span data-ng-show="frontendCtrl.frontend.redirect" class="label label-success">Redirect to {{frontendCtrl.frontend.redirect}}</span>
|
||||||
<span class="label label-warning" role="button" data-toggle="collapse" href="#{{frontendCtrl.frontend.backend}}" aria-expanded="false">Backend:{{frontendCtrl.frontend.backend}}</span>
|
<span class="label label-warning" role="button" data-toggle="collapse" href="#{{frontendCtrl.frontend.backend}}" aria-expanded="false">Backend:{{frontendCtrl.frontend.backend}}</span>
|
||||||
<span data-ng-show="frontendCtrl.frontend.passHostHeader" class="label label-warning">PassHostHeader</span>
|
<span data-ng-show="frontendCtrl.frontend.passHostHeader" class="label label-warning">PassHostHeader</span>
|
||||||
<span data-ng-repeat="whitelistSourceRange in frontendCtrl.frontend.whitelistSourceRange">
|
<span data-ng-repeat="whitelistSourceRange in frontendCtrl.frontend.whitelistSourceRange">
|
||||||
|
|
Loading…
Reference in a new issue