diff options
Diffstat (limited to 'crashbox-server/src/main/scala')
11 files changed, 91 insertions, 65 deletions
diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/BuildDef.scala b/crashbox-server/src/main/scala/io/crashbox/ci/BuildDef.scala new file mode 100644 index 0000000..898c222 --- /dev/null +++ b/crashbox-server/src/main/scala/io/crashbox/ci/BuildDef.scala @@ -0,0 +1,8 @@ +package io.crashbox.ci + +case class BuildDef( + image: String, + script: String +) + +case class ParseError(message: String) diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Core.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Core.scala index 39a1aec..cb1db5c 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Core.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/Core.scala @@ -8,7 +8,7 @@ import akka.event.LoggingAdapter import akka.stream.ActorMaterializer import com.typesafe.config.Config -trait Core { +class Core { implicit val system: ActorSystem = ActorSystem("crashbox") implicit val materializer = ActorMaterializer() diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Executors.scala b/crashbox-server/src/main/scala/io/crashbox/ci/DockerExecutor.scala index 045bf89..b5405c7 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Executors.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/DockerExecutor.scala @@ -16,7 +16,12 @@ import com.spotify.docker.client.exceptions.ContainerNotFoundException import com.spotify.docker.client.messages.{ContainerConfig, HostConfig} import com.spotify.docker.client.messages.HostConfig.Bind -trait Executors { core: Core => +case class ExecutionId(containerId: String) { + override def toString = containerId +} + +class DockerExecutor(implicit core: Core) { + import core._ val dockerClient = DefaultDockerClient.builder().uri("unix:///run/docker.sock").build() @@ -29,10 +34,6 @@ trait Executors { core: Core => def containerWorkDirectory = "/home/crashbox" def containerKillTimeout = 10.seconds - case class ExecutionId(containerId: String) { - override def toString = containerId - } - def startExecution( image: String, script: String, diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Git.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Git.scala new file mode 100644 index 0000000..db39891 --- /dev/null +++ b/crashbox-server/src/main/scala/io/crashbox/ci/Git.scala @@ -0,0 +1,21 @@ +package io.crashbox.ci + +import java.io.File +import java.net.URL + +import scala.concurrent.Future + +import org.eclipse.jgit.api.{Git => JGit} + +object Git { + + def fetchSource(from: URL, to: File)(implicit core: Core): Future[File] = { + import core._ + Future { + log.debug(s"Cloning git repo from $from to $to") + JGit.cloneRepository.setURI(from.toURI.toString).setDirectory(to).call() + to + }(blockingDispatcher) + } + +} diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/HttpApi.scala b/crashbox-server/src/main/scala/io/crashbox/ci/HttpApi.scala index c9e62c3..cbdbbf1 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/HttpApi.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/HttpApi.scala @@ -14,7 +14,8 @@ import akka.stream.scaladsl.{Source => Src} import akka.stream.scaladsl.StreamConverters import spray.json._ -trait HttpApi { self: Core with Schedulers with Storage => +class HttpApi(scheduler: Scheduler, storage: Storage)(implicit core: Core) { + import core._ val endpoint = "api" @@ -46,21 +47,21 @@ trait HttpApi { self: Core with Schedulers with Storage => path("submit") { post { entity(as[Request]) { req => - val scheduled = scheduleBuild(req.url).map(_.toString()) + val scheduled = scheduler.scheduleBuild(req.url).map(_.toString()) complete(scheduled) } } } ~ path(Segment / "cancel") { buildId => post { - cancelBuild(UUID.fromString(buildId)) + scheduler.cancelBuild(UUID.fromString(buildId)) complete(204 -> None) } } ~ path(Segment / "logs") { buildId => get { val src = StreamConverters - .fromInputStream(() => readLog(UUID.fromString(buildId), 0)) + .fromInputStream(() => storage.readLog(UUID.fromString(buildId), 0)) .map { bs => bs.utf8String } diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Main.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Main.scala index 55971b1..ae9499d 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Main.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/Main.scala @@ -6,22 +6,24 @@ import akka.http.scaladsl.Http import scala.concurrent._ import scala.concurrent.duration._ -object Main - extends Core - with Schedulers - with Storage - with Executors - with Parsers - with Source - with HttpApi { +object Main { + + implicit val core = new Core() + import core._ + + val storage = new Storage() + val executor = new DockerExecutor + val scheduler = new Scheduler(executor, storage) + val api = new HttpApi(scheduler, storage) + def main(args: Array[String]): Unit = { - reapDeadBuilds() - Await.result(setupDatabase(), 10.seconds) + executor.reapDeadBuilds() + Await.result(storage.setupDatabase(), 10.seconds) val host = config.getString("crashbox.host") val port = config.getInt("crashbox.port") - Http(system).bindAndHandle(httpApi, host, port) onComplete { + Http(system).bindAndHandle(api.httpApi, host, port) onComplete { case Success(_) => log.info(s"Listening on $host:$port") case Failure(ex) => diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Parsers.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Parser.scala index 020521c..a8b4f19 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Parsers.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/Parser.scala @@ -5,17 +5,10 @@ import java.nio.file.Files import scala.collection.JavaConverters._ -trait Parsers { +object Parser { def defaultImage = "crashbox/default" - case class BuildDef( - image: String, - script: String - ) - - case class ParseError(message: String) - def parseBuild(workdir: File): Either[BuildDef, ParseError] = { val file = new File(workdir, ".crashbox.txt") if (!file.exists()) { diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Schedulers.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Scheduler.scala index 0beec31..f263a9c 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Schedulers.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/Scheduler.scala @@ -12,22 +12,18 @@ import scala.util.{Failure, Success} import akka.actor.{Actor, ActorLogging, ActorRef, Props, Terminated} import akka.util.Timeout -trait Schedulers { - self: Core with Source with Executors with Parsers with Storage => +class Scheduler( + val executor: DockerExecutor, + storage: Storage +)(implicit core: Core) { + import Scheduler._ + import core._ + import executor._ + import storage._ private def newTempDir: File = Files.createTempDirectory("crashbox-run").toFile() - sealed trait BuildState - case class Cloning(url: URL) extends BuildState - case class Parsing(dir: File) extends BuildState - case class Starting(dir: File, buildDef: BuildDef) extends BuildState - case class Running(id: ExecutionId) extends BuildState - - sealed trait EndBuildState extends BuildState - case class Finished(status: Int) extends EndBuildState - case class Failed(message: String) extends EndBuildState - class BuildManager( buildId: BuildId, url: URL @@ -55,7 +51,7 @@ trait Schedulers { case state @ Cloning(url) => log.debug("Update build state: cloning") updateBuildState(buildId, state) - fetchSource(url, newTempDir) onComplete { + Git.fetchSource(url, newTempDir) onComplete { case Success(dir) => self ! Parsing(dir) case Failure(err) => @@ -66,7 +62,7 @@ trait Schedulers { log.debug("Update build state: parsing") updateBuildState(buildId, state) buildDir = Some(src) - parseBuild(src) match { + Parser.parseBuild(src) match { case Left(buildDef) => self ! Starting(src, buildDef) case Right(err) => @@ -160,3 +156,17 @@ trait Schedulers { } } + +object Scheduler { + + sealed trait BuildState + case class Cloning(url: URL) extends BuildState + case class Parsing(dir: File) extends BuildState + case class Starting(dir: File, buildDef: BuildDef) extends BuildState + case class Running(id: ExecutionId) extends BuildState + + sealed trait EndBuildState extends BuildState + case class Finished(status: Int) extends EndBuildState + case class Failed(message: String) extends EndBuildState + +} diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Source.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Source.scala deleted file mode 100644 index dffb5ea..0000000 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Source.scala +++ /dev/null @@ -1,19 +0,0 @@ -package io.crashbox.ci - -import java.io.File -import java.net.URL - -import scala.concurrent.Future - -import org.eclipse.jgit.api.Git - -trait Source { self: Core => - - def fetchSource(from: URL, to: File): Future[File] = - Future { - log.debug(s"Cloning git repo from $from to $to") - Git.cloneRepository.setURI(from.toURI.toString).setDirectory(to).call() - to - }(blockingDispatcher) - -} diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/Storage.scala b/crashbox-server/src/main/scala/io/crashbox/ci/Storage.scala index 0f095eb..bb995ef 100644 --- a/crashbox-server/src/main/scala/io/crashbox/ci/Storage.scala +++ b/crashbox-server/src/main/scala/io/crashbox/ci/Storage.scala @@ -12,9 +12,9 @@ import scala.concurrent.Future import java.util.UUID import slick.jdbc.H2Profile.api._ -trait Storage { self: Core with Parsers with Schedulers => - - type BuildId = UUID +class Storage(implicit core: Core) { + import core._ + import Scheduler._ case class Build( id: BuildId, diff --git a/crashbox-server/src/main/scala/io/crashbox/ci/package.scala b/crashbox-server/src/main/scala/io/crashbox/ci/package.scala new file mode 100644 index 0000000..183f9b5 --- /dev/null +++ b/crashbox-server/src/main/scala/io/crashbox/ci/package.scala @@ -0,0 +1,9 @@ +package io.crashbox + +import java.util.UUID + +package object ci { + + type BuildId = UUID + +} |