Added ability to override frontend priority for k8s ingress router

This commit is contained in:
Kirill Orlov 2017-07-29 19:35:23 +03:00 committed by Ludovic Fernandez
parent 29390a3c4a
commit 94f922cd28
4 changed files with 163 additions and 1 deletions

View file

@ -1242,6 +1242,7 @@ Træfik can be configured to use Kubernetes Ingress as a backend configuration:
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 type (Default: `PathPrefix`).
- `traefik.frontend.priority: 3`: override the default frontend rule priority (Default: `len(Path)`).
Annotations can be used on the Kubernetes service to override default behaviour:

View file

@ -604,6 +604,45 @@ You should now be able to visit the websites in your browser.
* [cheeses.minikube/cheddar](http://cheeses.minikube/cheddar/)
* [cheeses.minikube/wensleydale](http://cheeses.minikube/wensleydale/)
## Specifying priority for routing
Sometimes you need to specify priority for ingress route, especially when handling wildcard routes.
This can be done by adding annotation `traefik.frontend.priority`, i.e.:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wildcard-cheeses
annotations:
traefik.frontend.priority: 1
spec:
rules:
- host: *.minikube
http:
paths:
- path: /
backend:
serviceName: stilton
servicePort: http
kind: Ingress
metadata:
name: specific-cheeses
annotations:
traefik.frontend.priority: 2
spec:
rules:
- host: specific.minikube
http:
paths:
- path: /
backend:
serviceName: stilton
servicePort: http
```
## Forwarding to ExternalNames
When specifying an [ExternalName](https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors),

View file

@ -192,11 +192,14 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
log.Errorf("Failed to retrieve basic auth configuration for ingress %s/%s: %s", i.ObjectMeta.Namespace, i.ObjectMeta.Name, err)
continue
}
priority := p.getPriority(pa, i)
templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
Backend: r.Host + pa.Path,
PassHostHeader: PassHostHeader,
Routes: make(map[string]types.Route),
Priority: len(pa.Path),
Priority: priority,
BasicAuth: basicAuthCreds,
WhitelistSourceRange: whitelistSourceRange,
}
@ -322,6 +325,23 @@ func getRuleForPath(pa v1beta1.HTTPIngressPath, i *v1beta1.Ingress) string {
return rule
}
func (p *Provider) getPriority(path v1beta1.HTTPIngressPath, i *v1beta1.Ingress) int {
priority := len(path.Path)
priorityRaw, ok := i.Annotations[types.LabelFrontendPriority]
if ok {
priorityParsed, err := strconv.Atoi(priorityRaw)
if err == nil {
priority = priorityParsed
} else {
log.Errorf("Error in ingress: failed to parse %q value %q.", types.LabelFrontendPriority, priorityRaw)
}
}
return priority
}
func handleBasicAuthConfig(i *v1beta1.Ingress, k8sClient Client) ([]string, error) {
authType, exists := i.Annotations[annotationKubernetesAuthType]
if !exists {

View file

@ -1778,6 +1778,108 @@ func TestIngressAnnotations(t *testing.T) {
assert.Equal(t, expected, actual)
}
func TestPriorityHeaderValue(t *testing.T) {
ingresses := []*v1beta1.Ingress{
{
ObjectMeta: v1.ObjectMeta{
Namespace: "testing",
Annotations: map[string]string{
types.LabelFrontendPriority: "1337",
},
},
Spec: v1beta1.IngressSpec{
Rules: []v1beta1.IngressRule{
{
Host: "foo",
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: []v1beta1.HTTPIngressPath{
{
Path: "/bar",
Backend: v1beta1.IngressBackend{
ServiceName: "service1",
ServicePort: intstr.FromInt(80),
},
},
},
},
},
},
},
},
},
}
services := []*v1.Service{
{
ObjectMeta: v1.ObjectMeta{
Name: "service1",
UID: "1",
Namespace: "testing",
},
Spec: v1.ServiceSpec{
ClusterIP: "10.0.0.1",
Type: "ExternalName",
ExternalName: "example.com",
Ports: []v1.ServicePort{
{
Name: "http",
Port: 80,
},
},
},
},
}
endpoints := []*v1.Endpoints{}
watchChan := make(chan interface{})
client := clientMock{
ingresses: ingresses,
services: services,
endpoints: endpoints,
watchChan: watchChan,
}
provider := Provider{}
actual, err := provider.loadIngresses(client)
if err != nil {
t.Fatalf("error %+v", err)
}
expected := &types.Configuration{
Backends: map[string]*types.Backend{
"foo/bar": {
Servers: map[string]types.Server{
"http://example.com": {
URL: "http://example.com",
Weight: 1,
},
},
CircuitBreaker: nil,
LoadBalancer: &types.LoadBalancer{
Sticky: false,
Method: "wrr",
},
},
},
Frontends: map[string]*types.Frontend{
"foo/bar": {
Backend: "foo/bar",
PassHostHeader: true,
Priority: 1337,
Routes: map[string]types.Route{
"/bar": {
Rule: "PathPrefix:/bar",
},
"foo": {
Rule: "Host:foo",
},
},
},
},
}
assert.Equal(t, expected, actual)
}
func TestInvalidPassHostHeaderValue(t *testing.T) {
ingresses := []*v1beta1.Ingress{
{