-
Notifications
You must be signed in to change notification settings - Fork 845
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
WIP: DO NOT MERGE: fix problem with docker USER networking w/ portMappings and ipAddress #4008
WIP: DO NOT MERGE: fix problem with docker USER networking w/ portMappings and ipAddress #4008
Conversation
@@ -218,19 +218,22 @@ class GroupManager @Inject() ( | |||
port | |||
} | |||
|
|||
def mergeServicePortsAndPortDefinitions(portDefinitions: Seq[PortDefinition], servicePorts: Seq[Int]) = { | |||
portDefinitions.zipAll(servicePorts, AppDefinition.RandomPortDefinition, AppDefinition.RandomPortValue).map { |
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 is inserting service ports even when portDefinitions
is empty! So I fixed it, and then service ports weren't merging properly with container port mappings. So I changed those bits too.
@@ -341,6 +342,89 @@ class AppsResourceTest extends MarathonSpec with MarathonActorSupport with Match | |||
JsonTestHelper.assertThatJsonString(response.getEntity.asInstanceOf[String]).correspondsToJsonOf(expected) | |||
} | |||
|
|||
/* | |||
test("Create a new app with IP/CT with virtual network foo w/ Docker") { |
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 really want this version of the unit test to work but I get a validation error with ClassCastExceptions that follow. no comprendo.
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.
@gkleiman @aquamatthias suggestions welcome
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 idea of the tests in this class is to exercise AppsResource
's methods with mocked dependencies, not with a proper GroupManager
.
Do we already have a test in GroupManager
that checks that it assign the right ports with an app like the one in this test? If the answer is yes, then we don't need this one. If it is not, then maybe we should add one there =).
I tried to make this test pass, but there are multiple problems with it, and I am not sure if we really need 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.
I started hacking on the group manager tests because this seemed futile. Was hoping that I was just missing something simple but from your explanation it seems I'm pushing the limits of what this suite of unit tests is aimed at.
There's probably a case to make for tests that live somewhere in between simpler unit testing and full-fledged integration testing. For example I want to round-trip test from a JSON create-app request down through an actual group manager, without the hassle of setting up a mesos environment that supports overlay networking.
We can probably remove this commented test for now since I've tried to augment via group manager tests, even though it's less ideal IMHO.
seeing a new error on a hot-patched cluster during integration testing:
|
previous reported error caused with this app JSON (note: hostport == None; only one port mapping) {
"id": "jdef-networking",
"cmd": "ip -o addr; sleep 30",
"cpus": 0.10,
"mem": 64,
"instances": 1,
"backoffFactor": 1.14472988585,
"backoffSeconds": 5,
"ipAddress": { "networkName": "overlay-1" },
"container": {
"type": "DOCKER",
"docker": {
"network": "USER",
"image": "busybox",
"portMappings": [{
"containerPort": 123, "servicePort": 80, "name": "foo"
}]
}
}
} |
private[state] def assignDynamicServicePorts(from: Group, to: Group): Group = { | ||
val portRange = Range(config.localPortMin(), config.localPortMax()) | ||
var taken = from.transitiveApps.flatMap(_.portNumbers) ++ to.transitiveApps.flatMap(_.portNumbers) | ||
var taken = (from.transitiveApps.flatMap(app => app.hostPorts.flatten ++ app.servicePorts) ++ | ||
to.transitiveApps.flatMap(app => app.hostPorts.flatten ++ app.servicePorts)).toSet |
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.
TODO: write unit test for this change.
Symptom: multiple apps using port mappings that didn't specify service ports would result in Marathon attempting to reassign the same service port (that was already assigned to app1) to app2. (e.g. portMappings: [{}]
)
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.
done
given app def:
|
@@ -415,7 +415,7 @@ object TaskBuilder { | |||
} | |||
|
|||
val allAssigned = effectivePorts.flatten ++ generatedPorts.values | |||
env += ("PORT" -> allAssigned.head.toString) | |||
allAssigned.headOption.foreach { port => env += ("PORT" -> port.toString) } |
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.
Should we add a test in which no ports are requested?
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.
yes. I've elaborated on the TODO in the top-level desc of this PR
private[state] def assignDynamicServicePorts(from: Group, to: Group): Group = { | ||
val portRange = Range(config.localPortMin(), config.localPortMax()) | ||
var taken = from.transitiveApps.flatMap(_.portNumbers) ++ to.transitiveApps.flatMap(_.portNumbers) | ||
var taken = (from.transitiveApps.flatMap(app => app.hostPorts.flatten ++ app.servicePorts) ++ |
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.
Would the following also work?
var taken = from.transitiveApps.flatMap(_.servicePorts) ++ to.transitiveApps.flatMap(_.servicePorts)
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'm seeing a theme here where you want to use service ports instead of host ports everywhere. I don't understand it. I'm probably missing something obvious. My understanding of portNumbers
was that they were cousins of hostPorts
. servicePorts
in my mind are completely different
UGLY: when in docker USER network mode generated container ports (when containerPort == 0 and hostPort == None) do indeed result in PORT0 being populated. so that's useful from an app perspective but it's not aligned with the service port and the appdef isn't updated with the generated container port -- which means that nothing outside of the app can associate the PORT0 value with the service port. not very helpful. |
|
||
containerPorts.getOrElse(runSpec.portNumbers) | ||
} | ||
val portNames = { |
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.
fixes #4005
Thanks! |
#3998 was merged prematurely. this PR attempts to fix additional bugs found in integration testing w/ development builds of dc/os
[{}]