-
Notifications
You must be signed in to change notification settings - Fork 5.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add annotation to allow modifiers to be used properly in kubernetes #3481
Conversation
@@ -156,7 +156,8 @@ The following general annotations are applicable on the Ingress object: | |||
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. | | |||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. | | |||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers should be used (`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`). Default: `PathPrefix`. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should or rather can?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is crazy legacy code in there that allows for "ReplacePath" to be used as the rule-type. But we want to discourage it (hence the log.warn, and it not being listed in the "should" list), but it can technically be used to maintain backwards compatibility to people already using it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I will update the wording to "can" and anyone that goes "but can you do X" can bite me
provider/kubernetes/kubernetes.go
Outdated
rules = append(rules, ruleType+":"+pa.Path) | ||
case ruleTypeReplacePath: | ||
rules = append(rules, ruleType+":"+pa.Path) | ||
log.Warnf("Using %s as rule-type will be deprecated in the future. Please use request-modifier annotation instead", ruleType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we name the full new annotation name?
@@ -421,6 +443,27 @@ func getRuleForPath(pa extensionsv1beta1.HTTPIngressPath, i *extensionsv1beta1.I | |||
} | |||
rules = append(rules, ruleTypeReplacePath+":"+rootPath) | |||
} | |||
|
|||
if requestModifier := getStringValue(i.Annotations, annotationKubernetesRequestModifier, ""); requestModifier != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the annotation consists of all whitespaces only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rude
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, added tests to include a bunch of other oddities
provider/kubernetes/kubernetes.go
Outdated
// Split annotation to determine modifier type | ||
modifierParts := strings.Split(strings.Trim(requestModifier, " :"), ":") | ||
if len(modifierParts) < 2 { | ||
return "", fmt.Errorf("could not get rule due to incomplete rule: %q", requestModifier) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this error message different from the one in line 452 to allow distinguishing?
provider/kubernetes/kubernetes.go
Outdated
switch modifier { | ||
case ruleTypeAddPrefix, ruleTypeReplacePath, ruleTypeReplacePathRegex: | ||
if ruleType == ruleTypeReplacePath { | ||
return "", fmt.Errorf("cannot use '%s: %s' and '%s: %s'", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? Can we include a reason?
provider/kubernetes/annotations.go
Outdated
@@ -31,6 +31,7 @@ const ( | |||
annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages" | |||
annotationKubernetesBuffering = "ingress.kubernetes.io/buffering" | |||
annotationKubernetesAppRoot = "ingress.kubernetes.io/app-root" | |||
annotationKubernetesRequestModifier = "ingress.kubernetes.io/request-modifier" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you possibly check if a similar annotation already exists with Nginx, and if so, whether it makes sense to copy the name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^ Not really as in: I checked, and nginx does not provide that kind of functionality through an annotation. We are providing "new" functionality with this one.
@@ -156,7 +156,8 @@ The following general annotations are applicable on the Ingress object: | |||
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. | | |||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. | | |||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers can be used (`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`). Default: `PathPrefix`. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about linking to the path matchers documentation here?
@@ -156,7 +156,8 @@ The following general annotations are applicable on the Ingress object: | |||
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. | | |||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. | | |||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers can be used (`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`). Default: `PathPrefix`. | | |||
| `traefik.ingress.kubernetes.io/request-modifier: AddPath: /users` | Add a request modifier to the backend request. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to request modifiers docs from here?
@@ -156,7 +156,8 @@ The following general annotations are applicable on the Ingress object: | |||
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. | | |||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. | | |||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we leave a note that ReplacePath
is deprecated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess if we are going to leave the message in the log, we might as well note in the docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could argue that we should phrase the log message even stronger: that the old way will not be deprecated but is from now on effectively. This means that we will still support it but plan to remove support in a future release. At least, that's what I remember we (in particular @ldez) did in the past to migrate options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have completely remove annotations with the previous "label" style from the documentation.
I think can do the same here.
provider/kubernetes/kubernetes.go
Outdated
case ruleTypeReplacePath: | ||
log.Warnf("Using %s as %s will be deprecated in the future. Please use the %s annotation instead", ruleType, annotationKubernetesRuleType, annotationKubernetesRequestModifier) | ||
default: | ||
return "", fmt.Errorf("cannot use nonexistent, or non-matcher rule: %q", ruleType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about adding a case "":
and log the non-existent case separately? This would be slightly clearer as we don't have to log an empty string.
provider/kubernetes/kubernetes.go
Outdated
return strings.Join(rules, ";"), nil | ||
} | ||
|
||
func parseRequestModifier(requestModifier, ruleType string) (string, error) { | ||
if strings.Trim(requestModifier, " :") == "" { | ||
return "", fmt.Errorf("could not get rule due to empty rule: %q", requestModifier) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd simplify to "rule %q is empty"
as the calling site already provides context that the error is about rule retrieval.
provider/kubernetes/kubernetes.go
Outdated
// Split annotation to determine modifier type | ||
modifierParts := strings.Split(strings.Trim(requestModifier, " :"), ":") | ||
if len(modifierParts) < 2 { | ||
return "", fmt.Errorf("could not get rule due to incomplete rule (missing rule type or value): %q", requestModifier) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion to simplify to "rule %q is missing type or value"
.
provider/kubernetes/kubernetes.go
Outdated
return strings.Join(rules, ";"), nil | ||
} | ||
|
||
func parseRequestModifier(requestModifier, ruleType string) (string, error) { | ||
if strings.Trim(requestModifier, " :") == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TrimRight
should suffice, shouldn't it?
provider/kubernetes/kubernetes.go
Outdated
switch modifier { | ||
case ruleTypeAddPrefix, ruleTypeReplacePath, ruleTypeReplacePathRegex: | ||
if ruleType == ruleTypeReplacePath { | ||
return "", fmt.Errorf("cannot use '%s: %s' and '%s: %s, as this leads to rule duplication, and unintended behavior'", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing closing '
.
provider/kubernetes/kubernetes.go
Outdated
annotationKubernetesRuleType, ruleTypeReplacePath, annotationKubernetesRequestModifier, modifier) | ||
} | ||
default: | ||
return "", fmt.Errorf("cannot use nonexistent, or non-modifier rule: %q", modifier) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion for separate empty string case here too.
76e5f66
to
f6c5d5b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
wording fix review add tests update regex to be more friendly add docs allll the tests add space review: simplify. review: parseRequestModifier. review: doc. fix error wording fix review
@@ -154,7 +154,8 @@ The following general annotations are applicable on the Ingress object: | |||
| `traefik.ingress.kubernetes.io/redirect-regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-replacement`. | | |||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. | | |||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. | | |||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers can be used [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines). Note: ReplacePath is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`. | | |||
| `traefik.ingress.kubernetes.io/request-modifier: AddPath: /users` | Add a [request modifier](/basics/#modifiers) to the backend request. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like there is a type - should'n it be AddPrefix
instead of AddPath
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tompson thanks. After changing to AddPrefix
my ingress started working :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ferrarimarco can you maybe share your ingress configuration? I still cannot get mine working
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: a12
labels:
app: a1
chart: a1
release: a1
heritage: Tiller
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/preserve-host: "true"
traefik.ingress.kubernetes.io/app-root: "/index.html"
traefik.ingress.kubernetes.io/request-modifier: "AddPrefix: /a1"
spec:
rules:
- host: host1.tld
http:
paths:
- path: /test/aaaa
backend:
serviceName: service-name
servicePort: http
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much!
Unfortunately I am still not able to get my desired configuration to work.
I got a backend that is available under /app
and I want a traefik configuration that allows user to call it with /app
or with /oldapp
- both ways should work exactly the same.
I thought my config should look something like
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: default
annotations:
kubernetes.io/ingress.class: traefik
spec:
rules:
- host: httpecho.kube.troii.net
http:
paths:
- path: /app
backend:
serviceName: echo-server
servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: default
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/request-modifier: "AddPrefix: /app"
spec:
rules:
- host: httpecho.kube.troii.net
http:
paths:
- path: /oldapp
backend:
serviceName: echo-server
servicePort: 80
---
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: default
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
traefik.ingress.kubernetes.io/request-modifier: "AddPrefix: /app"
spec:
rules:
- host: httpecho.kube.troii.net
http:
paths:
- path: /oldapp
backend:
serviceName: echo-server
servicePort: 80
- path: /app
backend:
serviceName: echo-server
servicePort: 80
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @dtomcej ! should this already work with v1.6.5 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into the commit history and it seems like this will be in included in 1.7.0 but is not part of 1.6.5 - so I will have to wait to try it
What does this PR do?
Adds a
request-modifier
annotation to the kubernetes provider, that will allow the modifiers to be used (AddPrefix, ReplacePath, ReplacePathRegex
) properly, and without inferfering with the matcher rules.Motivation
Fixes #2985, #3230
More
Additional Notes
This PR also introduces a warning when users use
ReplacePath
as a rule-type, as it is a modifier, not a matcher rule.