-
Notifications
You must be signed in to change notification settings - Fork 89
Description
What happened?
I was using the docker compose rule and found that after adding health checks to my docker-compose.yml the docker compose rule fails because it cannot it can't find the internal port for a random container and then triggers this exception:
Line 91 in a2adeae
| .orElseThrow(() -> new IllegalArgumentException("No internal port '" + internalPort + "' for container '" + containerName + "': " + portMappings)); |
Did some digging, and came to the conclusion that this breaks because there is some flawed logic in the parsing of the ports from docker-compose output.
-
We grab the process output from running
docker-compose pshere and pass it into theparseFromDockerComposePsmethod:Line 228 in 446e363
return Ports.parseFromDockerComposePs(psOutput(service), dockerMachine.getIp()); -
Within
parseFromDockerComposePs, a regex is used to match the ports within the output
Line 30 in f07795c
private static final Pattern PORT_PATTERN = Pattern.compile("((\\d+).(\\d+).(\\d+).(\\d+)):(\\d+)->(\\d+)/tcp");
When there are no health checks within the docker-compose.yml, the output often looks like this:
Name Command State Ports
--------------------------------------------------------------------------------
container.name.here service/bin/linux- Up 0.0.0.0:1234->1234/tcp
amd64/go ...
Here the regex matches successfully and pulls port 1234 out of 0.0.0.0:1234->1234/tcp
When there are health checks, the output for docker-compose ps gets shifted and truncated at a random spot, causing the port information to be split across multiple lines:
Name Command State Ports
--------------------------------------------------------------------------------
container.name.here service/bin/linux- Up (healthy) 0.0.0.0:1234->1234/
amd64/go ... tcp
This makes it so that the regex is unable to be matched, so no ports are returned from parseFromDockerComposePs, and then the entire docker compose rule fails (as mentioned above).
Here is a test case that confirms this is the issue:
@Test
public void testcase() {
Pattern PORT_PATTERN = Pattern.compile("((\\d+).(\\d+).(\\d+).(\\d+)):(\\d+)->(\\d+)/tcp");
String psOutput = " Name Command State Ports \n"
+ "--------------------------------------------------------------------------------\n"
+ "container.name.here service/bin/linux- Up (healthy) 0.0.0.0:1234->1234/t\n"
+ " amd64/go ... cp ";
Matcher matcher = PORT_PATTERN.matcher(psOutput);
System.out.println(matcher.find()); // False
String psOutput2 = " Name Command State Ports \n"
+ "--------------------------------------------------------------------------------\n"
+ "container.name.here service/bin/linux- Up (healthy) 0.0.0.0:1234->1234/tcp\n" // Added -cp
+ " amd64/go ... cp ";
Matcher matcher2 = PORT_PATTERN.matcher(psOutput2);
System.out.println(matcher2.find()); // True
}
What did you want to happen?
The parsing of the ports from the command line output should not fail because the whitespacing changed, it should be clever enough to pull out the port information from the output (since all the information is there). Either we do some manipulation of the output coming from docker-compose ps, or make the regex that parses it do a little more