-
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 Custom header parsing to Docker Provider #2030
Conversation
This PR will resolve #2028 and will provide a basis for updating the kubernetes provider |
Still working on this. |
Ok. Submitting this for review. This PR allows the custom request and response headers to be set via docker labels. The labels get parsed, and invoke the headers middleware. |
Ping @containous/traefik |
If review is passed, will squash and rebase. |
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.
We should also extend the documentation.
provider/docker/docker.go
Outdated
if requestHeaders, err := getLabel(container, types.LabelFrontendRequestHeader); err == nil { | ||
for _, v := range strings.Split(requestHeaders, ",") { | ||
k := strings.Split(v, ":") | ||
h[k[0]] = k[1] |
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.
We will crash if the split in the previous line yields a single line only. Should we have some extra sanity check?
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.
Will do!
provider/docker/docker.go
Outdated
if responseHeaders, err := getLabel(container, types.LabelFrontendResponseHeader); err == nil { | ||
for _, v := range strings.Split(responseHeaders, ",") { | ||
k := strings.Split(v, ":") | ||
h[k[0]] = k[1] |
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.
Same here.
provider/docker/docker.go
Outdated
k := strings.Split(v, ":") | ||
h[k[0]] = k[1] | ||
} | ||
} |
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.
The parse logic for the requests and responses seems identical. Might be worth extracting into a little helper function.
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.
Seems legit.
templates/docker.tmpl
Outdated
@@ -74,6 +74,18 @@ | |||
basicAuth = [{{range getBasicAuth $container}} | |||
"{{.}}", | |||
{{end}}] | |||
{{if getRequestHeaders $container}} |
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.
Using the parse method for checking if request headers exist means we'll emit the log outputs twice: once in the check and once in the actual extraction (line 79). This might be somewhat confusing.
It might be better do introduce a little hasRequestHeaders
template function, similar to how we do it with other functions.
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.
kk.
templates/docker.tmpl
Outdated
{{$k}} = "{{$v}}" | ||
{{end}} | ||
{{end}} | ||
{{if getResponseHeaders $container}} |
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.
Same here.
bb51dba
to
255d9a1
Compare
@timoreimann Squashed, Rebased, Helper-ified, and Documented :) |
ping @containous/traefik |
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.
Left two optional improvement suggestions. Approving anyway, I'm fine with the status quo too. 👍
provider/docker/docker.go
Outdated
if _, err := getLabel(container, types.LabelFrontendRequestHeader); err != nil { | ||
return false | ||
} | ||
return true |
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.
Could also be
_, err := getLabel(container, types.LabelFrontendRequestHeader)
return err == nil
Similar with hasResponseHeaders
.
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.
Great job! A few comments.
provider/docker/docker.go
Outdated
|
||
log.Debugf("Loaded %s: %v", containerType, h) | ||
return h | ||
|
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.
could you remove this empty line?
provider/docker/docker.go
Outdated
|
||
func parseCustomHeaders(container dockerData, containerType string) map[string]string { | ||
h := make(map[string]string) | ||
if r, err := getLabel(container, containerType); err == nil { |
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.
maybe you could use explicit variable name instead of one letter.
By example:
h
->headers
r
->label
v
->pairs
k
->pair
provider/docker/docker.go
Outdated
@@ -721,6 +725,45 @@ func (p *Provider) getBasicAuth(container dockerData) []string { | |||
return []string{} | |||
} | |||
|
|||
func (p *Provider) hasRequestHeaders(container dockerData) bool { | |||
if _, err := getLabel(container, types.LabelFrontendRequestHeader); err != nil { |
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.
Maybe you could evaluate the length?
label, err := getLabel(container, types.LabelFrontendRequestHeader)
return err == nil && len(label) > 0
same for hasResponseHeaders
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.
👍
provider/docker/docker.go
Outdated
k := strings.Split(v, ":") | ||
if len(k) != 2 { | ||
log.Warnf("Could not load header %v", k) | ||
return h |
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.
If you add a return
you could add log.Errorf
instead of log.Warnf
In the case of an invalid key/value pair, you return the current map with previous values (or an empty map if it's the first pair), this seem strange:
- either you return a empty map (->
log.Errorf
) - or you only skip the invalid key/value pair (->
log.Warnf
)
update label parsing fix template ordering update to include response headers in templates abstract to helpers remove labels re-add labels move label for alphabet add doc on site better variable naming and error logic
@ldez corrections implemented! |
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
func parseCustomHeaders(container dockerData, containerType string) map[string]string { | ||
customHeaders := make(map[string]string) | ||
if label, err := getLabel(container, containerType); err == nil { | ||
for _, headers := range strings.Split(label, ",") { |
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.
Access-Control-Allow-Methods:POST,GET,OPTIONS
wouldn't this header cause this split to fail? maybe we should use a ;
similar to how the rules are separated?
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.
time="2017-12-01T00:03:00Z" level=warning msg="Could not load header "traefik.frontend.headers.customrequestheaders": [POST], skipping..."
time="2017-12-01T00:03:00Z" level=warning msg="Could not load header "traefik.frontend.headers.customrequestheaders": [OPTIONS], skipping..."
time="2017-12-01T00:03:00Z" level=warning msg="Could not load header "traefik.frontend.headers.customrequestheaders": [DELETE], skipping..."
time="2017-12-01T00:03:00Z" level=warning msg="Could not load header "traefik.frontend.headers.customrequestheaders": [PUT], skipping..."
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.
@vito-c please open an issue instead of comment on an already merged PR.
This PR provide a basis for updating the Kubernetes provider.
Fixes #2028