Skip to content
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

Merged
merged 1 commit into from
Oct 20, 2017

Conversation

dtomcej
Copy link
Contributor

@dtomcej dtomcej commented Aug 31, 2017

This PR provide a basis for updating the Kubernetes provider.

Fixes #2028

@dtomcej
Copy link
Contributor Author

dtomcej commented Aug 31, 2017

This PR will resolve #2028 and will provide a basis for updating the kubernetes provider

@ldez ldez changed the title Add Custom header parsing to Docker Provider [Fixes #2028] Add Custom header parsing to Docker Provider Aug 31, 2017
@dtomcej
Copy link
Contributor Author

dtomcej commented Sep 27, 2017

Still working on this.

@dtomcej
Copy link
Contributor Author

dtomcej commented Oct 1, 2017

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.

@dtomcej dtomcej removed the WIP label Oct 1, 2017
@dtomcej
Copy link
Contributor Author

dtomcej commented Oct 1, 2017

Ping @containous/traefik

@dtomcej
Copy link
Contributor Author

dtomcej commented Oct 1, 2017

If review is passed, will squash and rebase.

@ldez ldez added this to the 1.5 milestone Oct 1, 2017
Copy link
Contributor

@timoreimann timoreimann left a 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.

if requestHeaders, err := getLabel(container, types.LabelFrontendRequestHeader); err == nil {
for _, v := range strings.Split(requestHeaders, ",") {
k := strings.Split(v, ":")
h[k[0]] = k[1]
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

if responseHeaders, err := getLabel(container, types.LabelFrontendResponseHeader); err == nil {
for _, v := range strings.Split(responseHeaders, ",") {
k := strings.Split(v, ":")
h[k[0]] = k[1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

k := strings.Split(v, ":")
h[k[0]] = k[1]
}
}
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems legit.

@@ -74,6 +74,18 @@
basicAuth = [{{range getBasicAuth $container}}
"{{.}}",
{{end}}]
{{if getRequestHeaders $container}}
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kk.

{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{if getResponseHeaders $container}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@dtomcej
Copy link
Contributor Author

dtomcej commented Oct 13, 2017

@timoreimann Squashed, Rebased, Helper-ified, and Documented :)

@dtomcej
Copy link
Contributor Author

dtomcej commented Oct 13, 2017

ping @containous/traefik

Copy link
Contributor

@timoreimann timoreimann left a 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. 👍

if _, err := getLabel(container, types.LabelFrontendRequestHeader); err != nil {
return false
}
return true
Copy link
Contributor

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.

Copy link
Contributor

@ldez ldez left a 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.


log.Debugf("Loaded %s: %v", containerType, h)
return h

Copy link
Contributor

@ldez ldez Oct 19, 2017

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?


func parseCustomHeaders(container dockerData, containerType string) map[string]string {
h := make(map[string]string)
if r, err := getLabel(container, containerType); err == nil {
Copy link
Contributor

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

@@ -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 {
Copy link
Contributor

@ldez ldez Oct 19, 2017

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

k := strings.Split(v, ":")
if len(k) != 2 {
log.Warnf("Could not load header %v", k)
return h
Copy link
Contributor

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
@dtomcej
Copy link
Contributor Author

dtomcej commented Oct 20, 2017

@ldez corrections implemented!

Copy link
Contributor

@ldez ldez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Copy link
Member

@juliens juliens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@traefiker traefiker merged commit d973096 into traefik:master Oct 20, 2017
@ldez ldez added the kind/enhancement a new or improved feature. label Oct 25, 2017
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, ",") {
Copy link

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?

Copy link

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..."

Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants