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

auto hostname attribute #563

Merged
merged 1 commit into from
Apr 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,9 @@ When specifying the `command` field in your job hash, use `url-runner.bash` (mak

## Constraints

These constraints will currently only work against attributes that are specifically set on the Mesos slaves [as described in the Mesos documentation](http://mesos.apache.org/documentation/latest/configuration).
(i.e. the `hostname` attribute is not currently automatically available for constraints [as it is in Marathon](https://mesosphere.github.io/marathon/docs/constraints))
These constraints will work against attributes that are specifically set on the Mesos slaves [as described in the Mesos documentation](http://mesos.apache.org/documentation/latest/configuration).

If a `hostname` attribute is not explicitly specified, one will automatically be created and made available for constraints. It should be noted that calling out specific hostnames is not resilient to slave failure and should be avoided if possible.

### EQUALS constraint

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.apache.mesos.chronos.scheduler.mesos

import org.apache.mesos.Protos
import org.apache.mesos.chronos.scheduler.jobs.constraints.Constraint
import java.util.logging.Logger
import scala.collection.JavaConverters._

/**
* Helper for checking resource offer against job constraints
*/
object ConstraintChecker {
private[this] val log = Logger.getLogger(getClass.getName)
val Hostname = "hostname"

def checkConstraints(offer: Protos.Offer, constraints: Seq[Constraint]): Boolean = {
var attributes = offer.getAttributesList.asScala

if (!attributes.exists(attr => attr.getName == Hostname)) {
log.fine(s"adding hostname-attribute=${offer.getHostname} to offer=${offer}")
val hostnameText = Protos.Value.Text.newBuilder().setValue(offer.getHostname).build()
val hostnameAttribute = Protos.Attribute.newBuilder().setName(Hostname).setText(hostnameText).setType(Protos.Value.Type.TEXT).build()
attributes = offer.getAttributesList.asScala :+ hostnameAttribute
}

constraints.forall(_.matches(attributes))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,6 @@ class MesosJobFramework @Inject()(
def generateLaunchableTasks(offerResources: mutable.HashMap[Offer, Resources]): mutable.Buffer[(String, BaseJob, Offer)] = {
val tasks = mutable.Buffer[(String, BaseJob, Offer)]()

def checkConstraints(attributes: Seq[Protos.Attribute], constraints: Seq[Constraint]): Boolean = {
constraints.foreach { c =>
if (!c.matches(attributes)) {
return false
}
}
true
}

@tailrec
def generate() {
taskManager.getTask match {
Expand All @@ -143,7 +134,7 @@ class MesosJobFramework @Inject()(
case None =>
val neededResources = new Resources(job)
offerResources.toIterator.find { ors =>
ors._2.canSatisfy(neededResources) && checkConstraints(ors._1.getAttributesList.asScala, job.constraints)
ors._2.canSatisfy(neededResources) && ConstraintChecker.checkConstraints(ors._1, job.constraints)
} match {
case Some((offer, resources)) =>
// Subtract this job's resource requirements from the remaining available resources in this offer.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.apache.mesos.chronos.scheduler.mesos

import mesosphere.mesos.protos._
import org.apache.mesos.chronos.scheduler.jobs.constraints.ConstraintSpecHelper
import org.apache.mesos.Protos
import java.util.logging.Logger
import org.specs2.mock.Mockito
import org.specs2.mutable.SpecificationWithJUnit
import org.apache.mesos.chronos.scheduler.jobs.constraints.LikeConstraint
import org.apache.mesos.chronos.scheduler.jobs.constraints.EqualsConstraint
import mesosphere.mesos.protos.Implicits._
import org.specs2.specification.BeforeEach

class ConstraintCheckerSpec extends SpecificationWithJUnit
with Mockito
with ConstraintSpecHelper {

val offer = Protos.Offer.newBuilder()
.setId(OfferID("1"))
.setFrameworkId(FrameworkID("chronos"))
.setSlaveId(SlaveID("slave-1"))
.setHostname("slave.one.com")
.addAttributes(createTextAttribute("rack", "rack-1"))
.build()

val offerWithHostname = Protos.Offer.newBuilder()
.setId(OfferID("1"))
.setFrameworkId(FrameworkID("chronos"))
.setSlaveId(SlaveID("slave-1"))
.setHostname("slave.one.com")
.addAttributes(createTextAttribute("hostname", "slave.explicit.com"))
.build()

"check constraints" should {

"be true when equal" in {
val constraints = Seq(EqualsConstraint("rack", "rack-1"))
ConstraintChecker.checkConstraints(offer, constraints) must beTrue
}

"be false when not equal" in {
val constraints = Seq(EqualsConstraint("rack", "rack-2"))
ConstraintChecker.checkConstraints(offer, constraints) must beFalse
}

"be true when like" in {
val constraints = Seq(LikeConstraint("rack", "rack-[1-3]"))
ConstraintChecker.checkConstraints(offer, constraints) must beTrue
}

"be false when not like" in {
val constraints = Seq(LikeConstraint("rack", "rack-[2-3]"))
ConstraintChecker.checkConstraints(offer, constraints) must beFalse
}

"be true when hostname equal" in {
val constraints = Seq(EqualsConstraint("hostname", "slave.one.com"))
ConstraintChecker.checkConstraints(offer, constraints) must beTrue
}

"be false when hostname not equal" in {
val constraints = Seq(EqualsConstraint("hostname", "slave.two.com"))
ConstraintChecker.checkConstraints(offer, constraints) must beFalse
}

"be false when hostname explicitly set to something else and not equal" in {
val constraints = Seq(EqualsConstraint("hostname", "slave.one.com"))
ConstraintChecker.checkConstraints(offerWithHostname, constraints) must beFalse
}

"be true when hostname explicitly set to something else and equal" in {
val constraints = Seq(EqualsConstraint("hostname", "slave.explicit.com"))
ConstraintChecker.checkConstraints(offerWithHostname, constraints) must beTrue
}
}
}