When an app definition is updated we should also consider the
kill selection.
Closes #4818.
When an app definition is updated we should also consider the
kill selection.
Closes #4818.
unit-test
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
Commit | Tree | Parents | Author | Summary | Date |
---|---|---|---|---|---|
f9577c37f015 | 795c17762e03 | 0dc7c3b97104 | jeschkies | Check kill selection change in `isUpgrade`. | Dec 9 2016, 5:20 PM |
0dc7c3b97104 | 9d1a57beef75 | 6984205bf542 | jeschkies | Update kill selection in App as well. (Show More…) | Dec 9 2016, 3:17 PM |
1 | package mesosphere.marathon.api.v2.json | |||
---|---|---|---|---|
1 | package mesosphere.marathon | |||
2 | package api.v2.json | |||
2 | 3 | |||
3 | 4 | import com.wix.accord.Validator | ||
4 | 5 | import com.wix.accord.dsl._ | ||
5 | 6 | import mesosphere.marathon.Features | ||
6 | 7 | import mesosphere.marathon.Protos.Constraint | ||
7 | 8 | import mesosphere.marathon.api.v2.Validation._ | ||
8 | 9 | import mesosphere.marathon.core.readiness.ReadinessCheck | ||
9 | 10 | import mesosphere.marathon.core.health.HealthCheck | ||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Line(s) | ||||
72 | 73 | version: Option[Timestamp] = None, | ||
73 | 74 | |||
74 | 75 | ipAddress: Option[IpAddress] = None, | ||
75 | 76 | |||
76 | 77 | residency: Option[Residency] = None, | ||
77 | 78 | |||
78 | 79 | secrets: Option[Map[String, Secret]] = None, | ||
79 | 80 | |||
80 | unreachableStrategy: Option[UnreachableStrategy] = None) { | |||
81 | unreachableStrategy: Option[UnreachableStrategy] = None, | |||
81 | 82 | |||
83 | killSelection: Option[KillSelection] = None) { | |||
84 | ||||
82 | 85 | require(version.isEmpty || onlyVersionOrIdSet, "The 'version' field may only be combined with the 'id' field.") | ||
83 | 86 | |||
84 | 87 | protected[api] def onlyVersionOrIdSet: Boolean = productIterator forall { | ||
85 | 88 | case x: Some[Any] => x == version || x == id // linter:ignore UnlikelyEquality | ||
86 | 89 | case _ => true | ||
87 | 90 | } | ||
88 | 91 | |||
89 | 92 | def isResident: Boolean = residency.isDefined | ||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Line(s) | ||||
144 | 147 | // Setting the version in AppUpdate means that the user wants to revert to that version. In that | ||
145 | 148 | // case, we do not update the current AppDefinition but revert completely to the specified version. | ||
146 | 149 | // For all other updates, the GroupVersioningUtil will determine a new version if the AppDefinition | ||
147 | 150 | // has really changed. | ||
148 | 151 | versionInfo = app.versionInfo, | ||
149 | 152 | residency = residency.orElse(app.residency), | ||
150 | 153 | secrets = secrets.getOrElse(app.secrets), | ||
151 | 154 | taskKillGracePeriod = taskKillGracePeriod.orElse(app.taskKillGracePeriod), | ||
152 | unreachableStrategy = unreachableStrategy.getOrElse(app.unreachableStrategy) | |||
155 | unreachableStrategy = unreachableStrategy.getOrElse(app.unreachableStrategy), | |||
156 | killSelection = killSelection.getOrElse(app.killSelection) | |||
153 | 157 | ) | ||
154 | 158 | |||
155 | 159 | def withCanonizedIds(base: PathId = PathId.empty): AppUpdate = copy( | ||
156 | 160 | id = id.map(_.canonicalPath(base)), | ||
157 | 161 | dependencies = dependencies.map(_.map(_.canonicalPath(base))) | ||
158 | 162 | ) | ||
159 | 163 | } | ||
160 | 164 | |||
Show All 23 Lines |
Show First 20 Lines • Show All 1335 Lines • ▼ Show 20 Line(s) | |||
1336 | 1336 | (__ \ "storeUrls").readNullable[Seq[String]] ~ | |
---|---|---|---|
1337 | 1337 | (__ \ "requirePorts").readNullable[Boolean] ~ | |
1338 | 1338 | (__ \ "backoffSeconds").readNullable[Long].map(_.map(_.seconds)) ~ | |
1339 | 1339 | (__ \ "backoffFactor").readNullable[Double] ~ | |
1340 | 1340 | (__ \ "maxLaunchDelaySeconds").readNullable[Long].map(_.map(_.seconds)) ~ | |
1341 | 1341 | (__ \ "container").readNullable[Container] ~ | |
1342 | 1342 | (__ \ "healthChecks").readNullable[Set[HealthCheck]] ~ | |
1343 | 1343 | (__ \ "dependencies").readNullable[Set[PathId]] ~ | |
1344 | (__ \ "unreachableStrategy").readNullable[UnreachableStrategy] | ||
1345 | |||
1344 | (__ \ "unreachableStrategy").readNullable[UnreachableStrategy] ~ | ||
1345 | (__ \ "killSelection").readNullable[KillSelection] | ||
1346 | 1346 | ) ((id, cmd, args, user, env, instances, cpus, mem, disk, gpus, executor, constraints, storeUrls, requirePorts, | |
1347 | backoffSeconds, backoffFactor, maxLaunchDelaySeconds, container, healthChecks, dependencies, unreachableStrategy) => | ||
1347 | backoffSeconds, backoffFactor, maxLaunchDelaySeconds, container, healthChecks, dependencies, unreachableStrategy, | ||
1348 | killSelection) => | ||
1348 | 1349 | AppUpdate( | |
1349 | 1350 | id = id, cmd = cmd, args = args, user = user, env = env, instances = instances, cpus = cpus, mem = mem, | |
1350 | 1351 | disk = disk, gpus = gpus, executor = executor, constraints = constraints, | |
1351 | 1352 | storeUrls = storeUrls, requirePorts = requirePorts, | |
1352 | 1353 | backoff = backoffSeconds, backoffFactor = backoffFactor, maxLaunchDelay = maxLaunchDelaySeconds, | |
1353 | 1354 | container = container, healthChecks = healthChecks, dependencies = dependencies, | |
1354 | unreachableStrategy = unreachableStrategy.map(Raml.fromRaml(_)) | ||
1355 | unreachableStrategy = unreachableStrategy.map(Raml.fromRaml(_)), | ||
1356 | killSelection = killSelection.map(Raml.fromRaml(_)) | ||
1355 | 1357 | ) | |
1356 | 1358 | ).flatMap { update => | |
1357 | 1359 | // necessary because of case class limitations (good for another 21 fields) | |
1358 | 1360 | case class ExtraFields( | |
1359 | 1361 | uris: Option[Seq[String]], | |
1360 | 1362 | fetch: Option[Seq[FetchUri]], | |
1361 | 1363 | upgradeStrategy: Option[UpgradeStrategy], | |
1362 | 1364 | labels: Option[Map[String, String]], | |
▲ Show 20 Lines • Show All 105 Lines • Show Last 20 Lines |
Show First 20 Lines • Show All 315 Lines • ▼ Show 20 Line(s) | |||
316 | 316 | dependencies != to.dependencies || | |
---|---|---|---|
317 | 317 | upgradeStrategy != to.upgradeStrategy || | |
318 | 318 | labels != to.labels || | |
319 | 319 | acceptedResourceRoles != to.acceptedResourceRoles || | |
320 | 320 | ipAddress != to.ipAddress || | |
321 | 321 | readinessChecks != to.readinessChecks || | |
322 | 322 | residency != to.residency || | |
323 | 323 | secrets != to.secrets || | |
324 | unreachableStrategy != to.unreachableStrategy | ||
324 | unreachableStrategy != to.unreachableStrategy || | ||
325 | killSelection != to.killSelection | ||
325 | 326 | } | |
326 | 327 | case _ => | |
327 | 328 | // A validation rule will ensure, this can not happen | |
328 | 329 | throw new IllegalStateException("Can't change app to pod") | |
329 | 330 | } | |
330 | 331 | ||
331 | 332 | /** | |
332 | 333 | * Returns the changed app definition that is marked for restarting. | |
▲ Show 20 Lines • Show All 367 Lines • Show Last 20 Lines |
1 | package mesosphere.marathon.state | ||
---|---|---|---|
1 | package mesosphere.marathon | ||
2 | package state | ||
2 | 3 | ||
3 | 4 | import com.wix.accord._ | |
4 | 5 | import com.wix.accord.dsl._ | |
5 | 6 | import mesosphere.marathon.plugin | |
6 | 7 | ||
7 | 8 | sealed trait EnvVarValue extends plugin.EnvVarValue { | |
8 | 9 | val valueValidator = new Validator[EnvVarValue] { | |
9 | 10 | override def apply(v: EnvVarValue) = | |
▲ Show 20 Lines • Show All 80 Lines • Show Last 20 Lines |
1 | package mesosphere.marathon.api.v2.json | |||
---|---|---|---|---|
1 | package mesosphere.marathon | |||
2 | package api.v2.json | |||
2 | 3 | |||
3 | 4 | import mesosphere.marathon.core.health.{ MarathonHttpHealthCheck, PortReference } | ||
4 | import mesosphere.marathon.state.ResourceRole | |||
5 | import mesosphere.marathon.state.{ KillSelection, ResourceRole } | |||
5 | 6 | import mesosphere.marathon.test.MarathonSpec | ||
6 | 7 | import org.scalatest.Matchers | ||
7 | 8 | import play.api.libs.json.{ JsResultException, Json } | ||
8 | 9 | |||
9 | 10 | class AppUpdateFormatTest extends MarathonSpec with Matchers { | ||
10 | 11 | import Formats._ | ||
11 | 12 | |||
12 | 13 | // regression test for #1176 | ||
Show All 24 Lines | ||||
37 | 38 | val json = Json.parse(""" { "id": "test", "acceptedResourceRoles": ["*"] }""") | ||
38 | 39 | val appUpdate = json.as[AppUpdate] | ||
39 | 40 | appUpdate.acceptedResourceRoles should equal(Some(Set(ResourceRole.Unreserved))) | ||
40 | 41 | } | ||
41 | 42 | |||
42 | 43 | test("FromJSON should fail when 'acceptedResourceRoles' is defined but empty") { | ||
43 | 44 | val json = Json.parse(""" { "id": "test", "acceptedResourceRoles": [] }""") | ||
44 | 45 | a[JsResultException] shouldBe thrownBy { json.as[AppUpdate] } | ||
46 | } | |||
47 | ||||
48 | test("FromJSON should parse kill selection") { | |||
49 | val json = Json.parse(""" { "id": "test", "killSelection": "OldestFirst" }""") | |||
50 | val appUpdate = json.as[AppUpdate] | |||
51 | appUpdate.killSelection should be(Some(KillSelection.OldestFirst)) | |||
52 | } | |||
53 | ||||
54 | test("FromJSON should default to empty kill selection") { | |||
55 | val json = Json.parse(""" { "id": "test" }""") | |||
56 | val appUpdate = json.as[AppUpdate] | |||
57 | appUpdate.killSelection should not be 'defined | |||
45 | 58 | } | ||
46 | 59 | |||
47 | 60 | // Regression test for #3140 | ||
48 | 61 | test("FromJSON should set healthCheck portIndex to 0 when neither port nor portIndex are set") { | ||
49 | 62 | val json = Json.parse(""" { "id": "test", "healthChecks": [{ "path": "/", "protocol": "HTTP" }] } """) | ||
50 | 63 | val appUpdate = json.as[AppUpdate] | ||
51 | 64 | appUpdate.healthChecks.get.head.asInstanceOf[MarathonHttpHealthCheck].portIndex should equal(Some(PortReference(0))) | ||
52 | 65 | } | ||
53 | 66 | |||
54 | 67 | } |
Show First 20 Lines • Show All 572 Lines • ▼ Show 20 Line(s) | |||
573 | 573 | val appDef = AppDefinition(id = runSpecId, container = Some(Docker())) | |
---|---|---|---|
574 | 574 | val appUpdate = AppUpdate(container = Some(Docker(portMappings = Seq( | |
575 | 575 | Container.PortMapping(containerPort = 4000, protocol = "tcp") | |
576 | 576 | )))) | |
577 | 577 | val roundTrip = appUpdate(appDef) | |
578 | 578 | roundTrip.container.get.portMappings should have size 1 | |
579 | 579 | roundTrip.container.get.portMappings.head.containerPort should be (4000) | |
580 | 580 | } | |
581 | |||
582 | test("app update changes kill selection") { | ||
583 | val appDef = AppDefinition(id = runSpecId, killSelection = KillSelection.YoungestFirst) | ||
584 | val update = AppUpdate(killSelection = Some(KillSelection.OldestFirst)) | ||
585 | val result = update(appDef) | ||
586 | result.killSelection should be(KillSelection.OldestFirst) | ||
587 | } | ||
581 | 588 | } |
double-package please