diff --git a/docs/toml.md b/docs/toml.md index 3d1845a9c..c3aa5f4f0 100644 --- a/docs/toml.md +++ b/docs/toml.md @@ -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.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.domain=traefik.localhost`: override the default domain +- `traefik.domain=traefik.localhost`: override the default domain ## Kubernetes Ingress backend @@ -651,6 +651,10 @@ Træfɪk can be configured to use Kubernetes Ingress as a backend configuration: # 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). ## Consul backend diff --git a/examples/k8s.ingress.yaml b/examples/k8s.ingress.yaml index aac7798e4..e340406bf 100644 --- a/examples/k8s.ingress.yaml +++ b/examples/k8s.ingress.yaml @@ -91,3 +91,21 @@ spec: - backend: serviceName: service3 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 diff --git a/provider/kubernetes.go b/provider/kubernetes.go index a355addbd..33261f2c9 100644 --- a/provider/kubernetes.go +++ b/provider/kubernetes.go @@ -165,14 +165,24 @@ func (provider *Kubernetes) loadIngresses(k8sClient k8s.Client) (*types.Configur } } if len(pa.Path) > 0 { - if _, ok := i.Annotations["PathPrefixStrip"]; ok { - templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{ - Rule: "PathPrefixStrip:" + pa.Path, - } - } else { - templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{ - Rule: "PathPrefix:" + pa.Path, - } + var ruleType string = 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.Debugf("Unknown RuleType `%s`, falling back to `PathPrefix", ruleType) + ruleType = "PathPrefix" + } + + templateObjects.Frontends[r.Host+pa.Path].Routes[pa.Path] = types.Route{ + Rule: ruleType + ":" + pa.Path, } } services, err := k8sClient.GetServices(func(service k8s.Service) bool { diff --git a/provider/kubernetes_test.go b/provider/kubernetes_test.go index b7cf6ae44..95c4d8178 100644 --- a/provider/kubernetes_test.go +++ b/provider/kubernetes_test.go @@ -169,20 +169,25 @@ func TestLoadIngresses(t *testing.T) { } } -func TestPathPrefixStrip(t *testing.T) { - ingresses := []k8s.Ingress{{ - Spec: k8s.IngressSpec{ - Rules: []k8s.IngressRule{ - { - Host: "foo", - IngressRuleValue: k8s.IngressRuleValue{ - HTTP: &k8s.HTTPIngressRuleValue{ - Paths: []k8s.HTTPIngressPath{ - { - Path: "/bar", - Backend: k8s.IngressBackend{ - ServiceName: "service1", - ServicePort: k8s.FromInt(801), +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), + }, }, }, }, @@ -191,8 +196,107 @@ func TestPathPrefixStrip(t *testing.T) { }, }, }, - }} - ingresses[0].Annotations = map[string]string{"PathPrefixStrip": "true"} + { + 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{ @@ -224,14 +328,58 @@ func TestPathPrefixStrip(t *testing.T) { } expected := map[string]*types.Frontend{ - "foo/bar": { - Backend: "foo/bar", + "foo1/bar1": { + Backend: "foo1/bar1", Routes: map[string]types.Route{ - "/bar": { - Rule: "PathPrefixStrip:/bar", + "/bar1": { + Rule: "PathPrefixStrip:/bar1", }, - "foo": { - Rule: "Host:foo", + "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", }, }, },