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

Reduce marathon dependencies #355

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions api/src/main/scala/dcos/metronome/api/Binders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package api

import dcos.metronome.jobinfo.JobInfo.Embed
import dcos.metronome.model.JobId
import play.api.mvc.{ QueryStringBindable, PathBindable }
import mesosphere.marathon.api.v2.Validation.validateOrThrow
import dcos.metronome.utils.Validation.validateOrThrow
import play.api.mvc.{PathBindable, QueryStringBindable}

import scala.util.control.NonFatal

Expand Down
8 changes: 4 additions & 4 deletions api/src/main/scala/dcos/metronome/api/RestController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package dcos.metronome
package api

import com.eclipsesource.schema.SchemaValidator
import com.wix.accord.{ Failure, Success, Validator }
import mesosphere.marathon.api.v2.Validation
import play.api.http.{ ContentTypeOf, ContentTypes, Writeable }
import com.wix.accord.{Failure, Success, Validator}
import dcos.metronome.utils.Validation.failureWrites
import play.api.http.{ContentTypeOf, ContentTypes, Writeable}
import play.api.libs.json._
import play.api.mvc._

Expand All @@ -31,7 +31,7 @@ class RestController(cc: ControllerComponents) extends AbstractController(cc) {

def validateObject(a: A): Either[Result, A] = validator(a) match {
case Success => Right(a)
case f: Failure => Left(UnprocessableEntity(Validation.failureWrites.writes(f)))
case f: Failure => Left(UnprocessableEntity(failureWrites.writes(f)))
}

def readObject(jsValue: JsValue): Either[Result, A] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import dcos.metronome.api._
import dcos.metronome.api.v1.models.{ JobSpecFormat => _, _ }
import dcos.metronome.jobspec.JobSpecService
import dcos.metronome.model.{ JobId, JobRunSpec, JobSpec, ScheduleSpec }
import mesosphere.marathon.api.v2.json.Formats.FormatWithDefault
import dcos.metronome.utils.Formats.FormatWithDefault
import mesosphere.marathon.metrics.Metrics
import mesosphere.marathon.plugin.auth.{ Authenticator, Authorizer, CreateRunSpec, UpdateRunSpec }
import play.api.libs.functional.syntax._
Expand Down
10 changes: 5 additions & 5 deletions api/src/main/scala/dcos/metronome/api/v1/models/package.scala
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package dcos.metronome
package api.v1

import java.time.{ Instant, ZoneId }
import java.time.{Instant, ZoneId}
import java.time.format.DateTimeFormatter

import dcos.metronome.api._
import dcos.metronome.jobinfo.JobInfo
import dcos.metronome.jobrun.StartedJobRun
import dcos.metronome.model._
import dcos.metronome.scheduler.TaskState
import mesosphere.marathon.SemVer
import dcos.metronome.utils.SemVer
import mesosphere.marathon.core.task.Task
import mesosphere.marathon.state.{ Parameter, Timestamp }
import mesosphere.marathon.state.{Parameter, Timestamp}
import play.api.libs.functional.syntax._
import play.api.libs.json.Reads._
import play.api.libs.json.{ Json, _ }
import play.api.libs.json.{Json, _}

import scala.collection.JavaConverters._
import scala.concurrent.duration._

package object models {

import mesosphere.marathon.api.v2.json.Formats.FormatWithDefault
import dcos.metronome.utils.Formats.FormatWithDefault

implicit val errorFormat: Format[ErrorDetail] = Json.format[ErrorDetail]
implicit val unknownJobsFormat: Format[UnknownJob] = Json.format[UnknownJob]
Expand Down
31 changes: 20 additions & 11 deletions jobs/src/main/scala/dcos/metronome/MarathonBuildInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package dcos.metronome

import java.util.jar.{ Attributes, Manifest }

import mesosphere.marathon.SemVer
import mesosphere.marathon.io.IO
import mesosphere.marathon.stream.Implicits._
import dcos.metronome.utils.SemVer

import scala.Predef._
import scala.collection.JavaConverters
import scala.util.control.NonFatal

case object MarathonBuildInfo {
Expand All @@ -18,18 +16,29 @@ case object MarathonBuildInfo {
* first matching file for the first JAR in the class path. Instead, we need to enumerate through all of the
* manifests, and find the one that applies to the Marathon application jar.
*/
private lazy val marathonManifestPath: List[java.net.URL] =
getClass().getClassLoader().getResources("META-INF/MANIFEST.MF").toIterator.filter { manifest =>
marathonJar.findFirstMatchIn(manifest.getPath).nonEmpty
}.toList
private lazy val marathonManifestPath: List[java.net.URL] = {
val resources = JavaConverters.enumerationAsScalaIterator(getClass().getClassLoader().getResources("META-INF/MANIFEST.MF"))
resources
.filter(manifest => marathonJar.findFirstMatchIn(manifest.getPath).nonEmpty)
.toList
}

lazy val manifest: Option[Manifest] = marathonManifestPath match {
case Nil => None
case List(file) =>
val mf = new Manifest()
IO.using(file.openStream) { f =>
mf.read(f)

val closeable = file.openStream
try {
val mf = new Manifest()
mf.read(closeable)
Some(mf)
} finally {
try {
closeable.close()
} catch {
case ex: Exception =>
// suppress exceptions
}
}
case otherwise =>
throw new RuntimeException(s"Multiple marathon JAR manifests returned! ${otherwise}")
Expand Down
18 changes: 13 additions & 5 deletions jobs/src/main/scala/dcos/metronome/MetronomeBuildInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dcos.metronome

import java.util.jar.{ Attributes, Manifest }

import mesosphere.marathon.io.IO
import dcos.metronome.utils.SemVer

import scala.collection.JavaConverters._
import scala.io.Source
Expand Down Expand Up @@ -39,10 +39,18 @@ case object MetronomeBuildInfo {
lazy val manifest: Option[Manifest] = manifestPath match {
case Nil => None
case List(file) =>
val mf = new Manifest()
IO.using(file.openStream) { f =>
mf.read(f)
val closeable = file.openStream
try {
val mf = new Manifest()
mf.read(closeable)
Some(mf)
} finally {
try {
closeable.close()
} catch {
case ex: Exception =>
// suppress exceptions
}
}
case otherwise =>
throw new RuntimeException(s"Multiple metronome JAR manifests returned! $otherwise")
Expand All @@ -64,6 +72,6 @@ case object MetronomeBuildInfo {

lazy val scalaVersion: String = getAttribute("Scala-Version").getOrElse("2.x.x")

lazy val marathonVersion: mesosphere.marathon.SemVer = MarathonBuildInfo.version
lazy val marathonVersion: SemVer = MarathonBuildInfo.version

}
2 changes: 1 addition & 1 deletion jobs/src/main/scala/dcos/metronome/MetronomeInfo.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dcos.metronome

import mesosphere.marathon.SemVer
import dcos.metronome.utils.SemVer

case class MetronomeInfo(
version: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package dcos.metronome.model

trait EnvVarValueOrSecret
import mesosphere.marathon.plugin.{ EnvVarSecretRef, EnvVarString }

case class EnvVarValue(value: String) extends EnvVarValueOrSecret
trait EnvVarValueOrSecret extends mesosphere.marathon.plugin.EnvVarValue

case class EnvVarValue(value: String) extends EnvVarValueOrSecret with EnvVarString

object EnvVarValue {
implicit object playJsonFormat extends play.api.libs.json.Format[EnvVarValue] {
Expand All @@ -20,7 +22,7 @@ object EnvVarValue {
* @param secret The name of the secret to refer to. At runtime, the value of the
* secret will be injected into the value of the variable.
*/
case class EnvVarSecret(secret: String) extends EnvVarValueOrSecret
case class EnvVarSecret(secret: String) extends EnvVarValueOrSecret with EnvVarSecretRef

object EnvVarSecret {
implicit val playJsonFormat = play.api.libs.json.Json.format[EnvVarSecret]
Expand Down
10 changes: 4 additions & 6 deletions jobs/src/main/scala/dcos/metronome/model/JobSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ package model
import com.wix.accord.Validator
import com.wix.accord.dsl._
import dcos.metronome.model.JobRunSpec._
import dcos.metronome.utils.glue.MarathonConversions
import mesosphere.marathon.api.v2.Validation._
import mesosphere.marathon
import mesosphere.marathon.plugin.{ ApplicationSpec, NetworkSpec, Secret, VolumeSpec, VolumeMountSpec }
import dcos.metronome.utils.Validation.every
import mesosphere.marathon.plugin.{ApplicationSpec, NetworkSpec, VolumeMountSpec, VolumeSpec}

case class JobSpec(
id: JobId,
Expand All @@ -19,8 +17,8 @@ case class JobSpec(

override val user: Option[String] = run.user
override val acceptedResourceRoles: Set[String] = Set.empty
override val secrets: Map[String, Secret] = MarathonConversions.secretsToMarathon(run.secrets)
override val env: Map[String, marathon.state.EnvVarValue] = MarathonConversions.envVarToMarathon(run.env)
override val secrets: Map[String, mesosphere.marathon.plugin.Secret] = run.secrets
override val env: Map[String, mesosphere.marathon.plugin.EnvVarValue] = run.env
override val volumes: Seq[VolumeSpec] = Seq.empty
override val networks: Seq[NetworkSpec] = Seq.empty
override val volumeMounts: Seq[VolumeMountSpec] = Seq.empty
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package dcos.metronome
package model

import dcos.metronome.utils.glue.MarathonConversions
import mesosphere.marathon.plugin.{ ApplicationSpec, NetworkSpec, PathId, Secret, VolumeMountSpec, VolumeSpec }
import mesosphere.marathon.plugin
import mesosphere.marathon.plugin.{ ApplicationSpec, NetworkSpec, PathId, Secret, VolumeMountSpec, VolumeSpec }
import mesosphere.marathon.state.Timestamp

case class QueuedJobRunInfo(
Expand All @@ -16,7 +15,7 @@ case class QueuedJobRunInfo(
lazy val runId: String = id.path.last
override val user: Option[String] = run.user
override val secrets: Map[String, Secret] = Map.empty
override val env: Map[String, plugin.EnvVarValue] = MarathonConversions.envVarToMarathon(run.env)
override val env: Map[String, plugin.EnvVarValue] = run.env
override val labels = Map.empty[String, String]
override val volumes: Seq[VolumeSpec] = Seq.empty
override val networks: Seq[NetworkSpec] = Seq.empty
Expand Down
2 changes: 1 addition & 1 deletion jobs/src/main/scala/dcos/metronome/model/SecretDef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package dcos.metronome.model
* A secret declaration
* @param source reference to a secret which will be injected with a value from the secret store.
*/
case class SecretDef(source: String)
case class SecretDef(source: String) extends mesosphere.marathon.plugin.Secret

object SecretDef {
import play.api.libs.json.Reads._
Expand Down
12 changes: 12 additions & 0 deletions jobs/src/main/scala/dcos/metronome/utils/Formats.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dcos.metronome.utils

import play.api.libs.json.OFormat
import play.api.libs.functional.syntax._

object Formats {

implicit class FormatWithDefault[A](val m: OFormat[Option[A]]) extends AnyVal {
def withDefault(a: A): OFormat[A] = m.inmap(_.getOrElse(a), Some(_))
}

}
45 changes: 45 additions & 0 deletions jobs/src/main/scala/dcos/metronome/utils/SemVer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dcos.metronome.utils

/**
* Models a semantic version ( Copied from Marathon)
*/
case class SemVer(major: Int, minor: Int, build: Int, commit: Option[String]) extends Ordered[SemVer] {
override def toString(): String = commit match {
case Some(c) => s"$major.$minor.$build-$c"
case None => s"$major.$minor.$build"
}

override def compare(that: SemVer): Int = Seq(
major.compare(that.major),
minor.compare(that.minor),
build.compare(that.build),
commit.getOrElse("").compare(that.commit.getOrElse("")))
.find(_ != 0)
.getOrElse(0)
}

object SemVer {
val empty = SemVer(0, 0, 0, None)

// Matches e.g. 1.7.42 or v1.7.42
val versionPattern = """^(\d+)\.(\d+)\.(\d+)$""".r

// Matches e.g. 1.7.42-deadbeef or v1.7.42-deadbeef
val versionCommitPattern = """^v?(\d+)\.(\d+)\.(\d+)-(\w+)$""".r

/**
* Create SemVer from string which has the form if 1.7.42-deadbeef.
*/
def apply(version: String): SemVer =
version match {
case versionCommitPattern(major, minor, build, commit) =>
apply(major.toInt, minor.toInt, build.toInt, Some(commit))
case versionPattern(major, minor, build) =>
apply(major.toInt, minor.toInt, build.toInt)
case _ =>
throw new IllegalArgumentException(s"Could not parse version $version.")
}

def apply(major: Int, minor: Int, build: Int): SemVer =
apply(major, minor, build, None)
}
Loading