-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Command-based port check in HostPortWaitStrategy in case of Docker for Mac #236
Command-based port check in HostPortWaitStrategy in case of Docker for Mac #236
Conversation
if (DockerClientFactory.instance().isUsing(ProxiedUnixSocketClientProviderStrategy.class)) { | ||
List<Integer> exposedPorts = container.getExposedPorts(); | ||
|
||
Integer exposedPort = exposedPorts.stream() |
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.
unfortunately, we have to do some reverse engineering to find the port originally exposed since it's not private (protected, in fact)
return; | ||
} | ||
|
||
String[][] commands = { |
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.
two strategies at this moment - one without BASH because it's not available in Alpine linux for example, and another one with BASH
public class HostPortWaitStrategy extends GenericContainer.AbstractWaitStrategy { | ||
|
||
private static final String SUCCESS_MARKER = "TESTCONTAINERS_SUCCESS"; |
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 have to use string-based success marker because exit code is not available
Sorry for being slow to respond to this. It seems like a neat idea - while it is a little 'hacky' it would insulate our users from this nasty issue, so is a good thing in the short term. I'm having some issues with tests running locally, though - not quite sure why, though I've not done much digging yet. Any ideas?
|
checkStrategy = () -> { | ||
for (String[] command : commands) { | ||
try { | ||
if (container.execInContainer(command).getStdout().contains(SUCCESS_MARKER)) { |
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.
This will cause a log message to come out at INFO level - might get a bit noisy when the check has to be repeated many times. I'm not quite sure of the best answer really, but maybe we should change the execInContainer
method so that it logs at DEBUG instead? What do you think?
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.
sounds great! The INFO level is a bit verbose for it. Where should we change 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.
org/testcontainers/containers/GenericContainer.java:820 would be the place.
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 mean, in this PR or as a separate change? :)
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.
Aha, oops! In this PR is fine I think!
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.
changed :)
Ah OK - may have found part of the problem.
Integer exposedPort = exposedPorts.stream()
.map(container::getMappedPort)
.filter(port::equals)
.findFirst()
.orElse(null); Seems to start off with the internal port numbers, but maps them to the external form before checking quality with Then the commands: { "/bin/sh", "-c", "nc -vz -w 1 localhost " + exposedPort + " && echo " + SUCCESS_MARKER },
{ "/bin/bash", "-c", "</dev/tcp/localhost/" + exposedPort + " && echo " + SUCCESS_MARKER } are picking up the external port number, which is not valid when executed inside the container. Maybe I've missed something important (!), but it seems to me that commenting out these lines should work: Integer exposedPort = exposedPorts.stream()
// .map(container::getMappedPort)
// .filter(port::equals)
.findFirst()
.orElse(null); |
FYI I've put a possible fix on this branch: https://github.com/testcontainers/testcontainers-java/tree/zeroturnaround-160-docker4mac_port_check If I've completely missed the point please let me know!!! |
@rnorth see my note on the PR. Yes, ideally, we should use "exposedPorts", BUT. Of course we can ignore it for now and use exposed ports directly |
Yeah OK - it's just that I think I understand how the streams flow maybe should work now... Should it perhaps be this? For each It's just that right now, it's returning |
@rnorth we perform |
But the result of that is that we get Basically we need something like |
@rnorth actually, you're right. Now is the question - why it passed locally on my machine :D let me take a look :D |
Hehe, docker never fails to surprise me! Maybe there's some different port mapping behaviour happening or something... |
@rnorth fixed :) Sorry, no idea how it happened. Maybe some last minute fix I forgot to test, sorry :) |
Great, thanks! |
Fixes #160
I did a test run on my Mac with Docker for Mac, everything is green :)
Consider it as a temporary hack until the issue with port forwarding is fixed on Docker's side