Merge pull request #373 from AlmogBaku/master
K8s: add an option to configure "PathPrefixStrip" for the ingress-resource using annotation
This commit is contained in:
commit
70494117d1
4 changed files with 263 additions and 2 deletions
|
@ -619,7 +619,7 @@ Labels can be used on containers to override default behaviour:
|
||||||
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
|
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
|
||||||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||||
- `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.domain=traefik.localhost`: override the default domain
|
- `traefik.domain=traefik.localhost`: override the default domain
|
||||||
|
|
||||||
|
|
||||||
## Kubernetes Ingress backend
|
## Kubernetes Ingress backend
|
||||||
|
@ -651,6 +651,10 @@ Træfɪk can be configured to use Kubernetes Ingress as a backend configuration:
|
||||||
# namespaces = ["default","production"]
|
# namespaces = ["default","production"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Annotations can be used on containers to override default behaviour for the whole Ingress resource:
|
||||||
|
|
||||||
|
- `traefik.frontend.rule.type: PathPrefixStrip`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
|
||||||
|
|
||||||
You can find here an example [ingress](https://raw.githubusercontent.com/containous/traefik/master/examples/k8s.ingress.yaml) and [replication controller](https://raw.githubusercontent.com/containous/traefik/master/examples/k8s.rc.yaml).
|
You can find here an example [ingress](https://raw.githubusercontent.com/containous/traefik/master/examples/k8s.ingress.yaml) and [replication controller](https://raw.githubusercontent.com/containous/traefik/master/examples/k8s.rc.yaml).
|
||||||
|
|
||||||
## Consul backend
|
## Consul backend
|
||||||
|
|
|
@ -91,3 +91,21 @@ spec:
|
||||||
- backend:
|
- backend:
|
||||||
serviceName: service3
|
serviceName: service3
|
||||||
servicePort: 80
|
servicePort: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
# Another Ingress with PathPrefixStrip
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: whoami-ingress-stripped
|
||||||
|
annotations:
|
||||||
|
traefik.frontend.rule.type: "PathPrefixStrip"
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: foo.localhost
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /prefixWillBeStripped
|
||||||
|
backend:
|
||||||
|
serviceName: service1
|
||||||
|
servicePort: 80
|
||||||
|
|
|
@ -165,8 +165,24 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(pa.Path) > 0 {
|
if len(pa.Path) > 0 {
|
||||||
|
ruleType := i.Annotations["traefik.frontend.rule.type"]
|
||||||
|
|
||||||
|
switch strings.ToLower(ruleType) {
|
||||||
|
case "pathprefixstrip":
|
||||||
|
ruleType = "PathPrefixStrip"
|
||||||
|
case "pathstrip":
|
||||||
|
ruleType = "PathStrip"
|
||||||
|
case "path":
|
||||||
|
ruleType = "Path"
|
||||||
|
case "pathprefix":
|
||||||
|
ruleType = "PathPrefix"
|
||||||
|
default:
|
||||||
|
log.Warnf("Unknown RuleType `%s`, falling back to `PathPrefix", ruleType)
|
||||||
|
ruleType = "PathPrefix"
|
||||||
|
}
|
||||||
|
|
||||||
templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{
|
templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{
|
||||||
Rule: "PathPrefix:" + pa.Path,
|
Rule: ruleType + ":" + pa.Path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
services, err := k8sClient.GetServices(func(service k8s.Service) bool {
|
services, err := k8sClient.GetServices(func(service k8s.Service) bool {
|
||||||
|
|
|
@ -169,6 +169,229 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRuleType(t *testing.T) {
|
||||||
|
ingresses := []k8s.Ingress{
|
||||||
|
{
|
||||||
|
ObjectMeta: k8s.ObjectMeta{
|
||||||
|
Annotations: map[string]string{"traefik.frontend.rule.type": "PathPrefixStrip"}, //camel case
|
||||||
|
},
|
||||||
|
Spec: k8s.IngressSpec{
|
||||||
|
Rules: []k8s.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo1",
|
||||||
|
IngressRuleValue: k8s.IngressRuleValue{
|
||||||
|
HTTP: &k8s.HTTPIngressRuleValue{
|
||||||
|
Paths: []k8s.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/bar1",
|
||||||
|
Backend: k8s.IngressBackend{
|
||||||
|
ServiceName: "service1",
|
||||||
|
ServicePort: k8s.FromInt(801),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: k8s.ObjectMeta{
|
||||||
|
Annotations: map[string]string{"traefik.frontend.rule.type": "path"}, //lower case
|
||||||
|
},
|
||||||
|
Spec: k8s.IngressSpec{
|
||||||
|
Rules: []k8s.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo1",
|
||||||
|
IngressRuleValue: k8s.IngressRuleValue{
|
||||||
|
HTTP: &k8s.HTTPIngressRuleValue{
|
||||||
|
Paths: []k8s.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/bar2",
|
||||||
|
Backend: k8s.IngressBackend{
|
||||||
|
ServiceName: "service1",
|
||||||
|
ServicePort: k8s.FromInt(801),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: k8s.ObjectMeta{
|
||||||
|
Annotations: map[string]string{"traefik.frontend.rule.type": "PathPrefix"}, //path prefix
|
||||||
|
},
|
||||||
|
Spec: k8s.IngressSpec{
|
||||||
|
Rules: []k8s.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo2",
|
||||||
|
IngressRuleValue: k8s.IngressRuleValue{
|
||||||
|
HTTP: &k8s.HTTPIngressRuleValue{
|
||||||
|
Paths: []k8s.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/bar1",
|
||||||
|
Backend: k8s.IngressBackend{
|
||||||
|
ServiceName: "service1",
|
||||||
|
ServicePort: k8s.FromInt(801),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: k8s.ObjectMeta{
|
||||||
|
Annotations: map[string]string{"traefik.frontend.rule.type": "PathStrip"}, //path strip
|
||||||
|
},
|
||||||
|
Spec: k8s.IngressSpec{
|
||||||
|
Rules: []k8s.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo2",
|
||||||
|
IngressRuleValue: k8s.IngressRuleValue{
|
||||||
|
HTTP: &k8s.HTTPIngressRuleValue{
|
||||||
|
Paths: []k8s.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/bar2",
|
||||||
|
Backend: k8s.IngressBackend{
|
||||||
|
ServiceName: "service1",
|
||||||
|
ServicePort: k8s.FromInt(801),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: k8s.ObjectMeta{
|
||||||
|
Annotations: map[string]string{"traefik.frontend.rule.type": "PathXXStrip"}, //wrong rule
|
||||||
|
},
|
||||||
|
Spec: k8s.IngressSpec{
|
||||||
|
Rules: []k8s.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo1",
|
||||||
|
IngressRuleValue: k8s.IngressRuleValue{
|
||||||
|
HTTP: &k8s.HTTPIngressRuleValue{
|
||||||
|
Paths: []k8s.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/bar3",
|
||||||
|
Backend: k8s.IngressBackend{
|
||||||
|
ServiceName: "service1",
|
||||||
|
ServicePort: k8s.FromInt(801),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
services := []k8s.Service{
|
||||||
|
{
|
||||||
|
ObjectMeta: k8s.ObjectMeta{
|
||||||
|
Name: "service1",
|
||||||
|
UID: "1",
|
||||||
|
},
|
||||||
|
Spec: k8s.ServiceSpec{
|
||||||
|
ClusterIP: "10.0.0.1",
|
||||||
|
Ports: []k8s.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "http",
|
||||||
|
Port: 801,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
watchChan := make(chan interface{})
|
||||||
|
client := clientMock{
|
||||||
|
ingresses: ingresses,
|
||||||
|
services: services,
|
||||||
|
watchChan: watchChan,
|
||||||
|
}
|
||||||
|
provider := Kubernetes{disablePassHostHeaders: true}
|
||||||
|
actualConfig, err := provider.loadIngresses(client)
|
||||||
|
actual := actualConfig.Frontends
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[string]*types.Frontend{
|
||||||
|
"foo1/bar1": {
|
||||||
|
Backend: "foo1/bar1",
|
||||||
|
Routes: map[string]types.Route{
|
||||||
|
"/bar1": {
|
||||||
|
Rule: "PathPrefixStrip:/bar1",
|
||||||
|
},
|
||||||
|
"foo1": {
|
||||||
|
Rule: "Host:foo1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foo1/bar2": {
|
||||||
|
Backend: "foo1/bar2",
|
||||||
|
Routes: map[string]types.Route{
|
||||||
|
"/bar2": {
|
||||||
|
Rule: "Path:/bar2",
|
||||||
|
},
|
||||||
|
"foo1": {
|
||||||
|
Rule: "Host:foo1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foo2/bar1": {
|
||||||
|
Backend: "foo2/bar1",
|
||||||
|
Routes: map[string]types.Route{
|
||||||
|
"/bar1": {
|
||||||
|
Rule: "PathPrefix:/bar1",
|
||||||
|
},
|
||||||
|
"foo2": {
|
||||||
|
Rule: "Host:foo2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foo2/bar2": {
|
||||||
|
Backend: "foo2/bar2",
|
||||||
|
Routes: map[string]types.Route{
|
||||||
|
"/bar2": {
|
||||||
|
Rule: "PathStrip:/bar2",
|
||||||
|
},
|
||||||
|
"foo2": {
|
||||||
|
Rule: "Host:foo2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foo1/bar3": {
|
||||||
|
Backend: "foo1/bar3",
|
||||||
|
Routes: map[string]types.Route{
|
||||||
|
"/bar3": {
|
||||||
|
Rule: "PathPrefix:/bar3",
|
||||||
|
},
|
||||||
|
"foo1": {
|
||||||
|
Rule: "Host:foo1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actualJSON, _ := json.Marshal(actual)
|
||||||
|
expectedJSON, _ := json.Marshal(expected)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
|
t.Fatalf("expected %+v, got %+v", string(expectedJSON), string(actualJSON))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetPassHostHeader(t *testing.T) {
|
func TestGetPassHostHeader(t *testing.T) {
|
||||||
ingresses := []k8s.Ingress{{
|
ingresses := []k8s.Ingress{{
|
||||||
Spec: k8s.IngressSpec{
|
Spec: k8s.IngressSpec{
|
||||||
|
|
Loading…
Reference in a new issue