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

Fix: Use exact service name match when searching container labels #39

Merged
merged 1 commit into from
Jul 10, 2024

Conversation

damfleu
Copy link

@damfleu damfleu commented Jul 7, 2024

There is an issue with findContainerByServiceName where it incorrectly matches containers with similar names, specifically when one service name is a prefix of the other.

The check that the label contains the string traefik.<svcType>.services.<svcName> will match for both the service name <svcName> but also services such as <svcName>-suffix. If the docker container for the longer service is looked up first, then it will incorrectly retrieve the port binding from that container.

The labels should be in the format traefik.<svcType>.services.<svcName>.<attribute> so just add a dot at the end of the needle and use HasPrefix() to ensure an exact match. The added test verifies the fix for this issue where hello would end up with "http://192.168.100.100:5566" instead of 5555. Unfortunately, since it depends in which order the containers will be iterated over, it doesn't fail (without the fix) all the time.

Here is the output of a non-passing run:

[...]
time="2024-07-07T12:13:53+02:00" level=debug msg="found container 'hello-test' (hello-test) for service 'hello'"
time="2024-07-07T12:13:53+02:00" level=debug msg="overriding service port from container host-port: using 5566 (was 5555) for hello@docker" service=hello@docker service-type=http
time="2024-07-07T12:13:53+02:00" level=info msg="publishing http://192.168.100.100:5566" service=hello@docker service-type=http
traefik/http/routers/hello/service: hello
traefik/http/routers/hello/tls/certResolver: default
traefik/http/services/hello-test/loadBalancer/servers/0/url: http://192.168.100.100:5566
traefik/http/services/hello-test/loadBalancer/passHostHeader: true
traefik/http/services/hello/loadBalancer/servers/0/url: http://192.168.100.100:5566
traefik/http/routers/hello-test/service: hello-test
traefik/http/routers/hello-test/rule: Host(`hello-test.local`)
traefik/http/routers/hello-test/tls/certResolver: default
traefik/http/routers/hello/rule: Host(`hello.local`)
traefik/http/services/hello/loadBalancer/passHostHeader: true
    traefik-kop/docker_helpers_test.go:320:
                Error Trace:    traefik-kop/docker_helpers_test.go:320
                                                        traefik-kop/docker_test.go:133
                Error:          Not equal:
                                expected: "http://192.168.100.100:5555"
                                actual  : "http://192.168.100.100:5566"

                                Diff:
                                --- Expected
                                +++ Actual
                                @@ -1 +1 @@
                                -http://192.168.100.100:5555
                                +http://192.168.100.100:5566
                Test:           Test_samePrefix
                Messages:       service has wrong IP at key: traefik/http/services/hello/loadBalancer/servers/0/url
--- FAIL: Test_samePrefix (0.01s)
FAIL
FAIL    github.com/jittering/traefik-kop        0.842s

@chetan
Copy link
Contributor

chetan commented Jul 7, 2024

I'm not sure why I used Contains originally instead of HasPrefix, as that would have been more appropriate. Nonetheless, rather than use a regex, why not simply append a dot to the needle? Wouldn't that have the same effect here or are there cases the regex would more completely cover?

The goal is to find a label like traefik.http.routers.hello.[attribute]=[value] without looking for a specific attribute which may not be there in all cases. I don't think we'd ever have the case of a bare label like traefik.http.routers.hello=[value], but even in this case we could also check for an exact match (without the dot).

`findContainerByServiceName` incorrectly matched containers based on
service and router names when there were two services with similar
names, specifically when one service name was a prefix of the other.

Add a dot to the service and router needles and compare the labels with
HasPrefix() to ensure that only the exact matches get picked up.
@damfleu
Copy link
Author

damfleu commented Jul 7, 2024

I'm not sure why I used Contains originally instead of HasPrefix, as that would have been more appropriate.

Though in this case HasPrefix would have had the same issue!

Nonetheless, rather than use a regex, why not simply append a dot to the needle? Wouldn't that have the same effect here or are there cases the regex would more completely cover?

The goal is to find a label like traefik.http.routers.hello.[attribute]=[value] without looking for a specific attribute which may not be there in all cases. I don't think we'd ever have the case of a bare label like traefik.http.routers.hello=[value], but even in this case we could also check for an exact match (without the dot).

Right, I went with that at first and then used a regex to handle exactly the case where the label ends there. I just didn't want to assume that wasn't be a valid case. Using HasPrefix() and adding a dot to the needle sounds good, it should cover all cases where an attribute is expected.

@damfleu damfleu force-pushed the damfleu/fix/service-name-prefix branch from 2a64b15 to 7db2c37 Compare July 7, 2024 21:13
@chetan
Copy link
Contributor

chetan commented Jul 7, 2024

Though in this case HasPrefix would have had the same issue!

Yup, you are totally correct, I was just commenting on my odd choice there 😖. Started out as a quick hack. It worked, I shipped!

@damfleu
Copy link
Author

damfleu commented Jul 8, 2024

Thanks for the comments, code has been updated, let me know what you think!

@chetan chetan merged commit d4112dc into jittering:main Jul 10, 2024
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants