diff --git a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala index ee1916531..6e75449a7 100644 --- a/app/org/thp/cortex/services/DockerJobRunnerSrv.scala +++ b/app/org/thp/cortex/services/DockerJobRunnerSrv.scala @@ -92,10 +92,12 @@ class DockerJobRunnerSrv(client: DockerClient, autoUpdate: Boolean, implicit val () }.andThen { case r ⇒ - if (!Files.exists(jobDirectory.resolve("output").resolve("output.json"))) { - val message = r.fold(e ⇒ s"Docker creation error: ${e.getMessage}\n", _ ⇒ "") + - Try(client.logs(containerCreation.id(), LogsParam.stdout(), LogsParam.stderr()).readFully()) - .recover { case e ⇒ s"Container logs can't be read (${e.getMessage}" } + val outputFile = jobDirectory.resolve("output").resolve("output.json") + if (!Files.exists(outputFile) || Files.size(outputFile) == 0) { + val output = Try(client.logs(containerCreation.id(), LogsParam.stdout(), LogsParam.stderr()).readFully()) + .fold(e ⇒ s"Container logs can't be read (${e.getMessage})", identity) + val message = r.fold(e ⇒ s"Docker creation error: ${e.getMessage}\n$output", _ ⇒ output) + val report = Json.obj("success" → false, "errorMessage" → message) Files.write(jobDirectory.resolve("output").resolve("output.json"), report.toString.getBytes(StandardCharsets.UTF_8)) } diff --git a/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala b/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala index 976e5abce..444ea1b01 100644 --- a/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala +++ b/app/org/thp/cortex/services/ProcessJobRunnerSrv.scala @@ -3,22 +3,18 @@ package org.thp.cortex.services import java.nio.charset.StandardCharsets import java.nio.file.{Files, Path, Paths} -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future} -import scala.sys.process.{Process, ProcessLogger} - -import play.api.Logger - import akka.actor.ActorSystem import javax.inject.{Inject, Singleton} +import org.elastic4play.utils.RichFuture import org.thp.cortex.models._ +import play.api.Logger +import play.api.libs.json.Json -import org.elastic4play.utils.RichFuture -import scala.sys.process._ +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.{ExecutionContext, Future} +import scala.sys.process.{Process, ProcessLogger, _} import scala.util.Try -import play.api.libs.json.Json - @Singleton class ProcessJobRunnerSrv @Inject()(implicit val system: ActorSystem) { @@ -37,19 +33,31 @@ class ProcessJobRunnerSrv @Inject()(implicit val system: ActorSystem) { def run(jobDirectory: Path, command: String, job: Job, timeout: Option[FiniteDuration])(implicit ec: ExecutionContext): Future[Unit] = { val baseDirectory = Paths.get(command).getParent.getParent + val output = StringBuilder.newBuilder logger.info(s"Execute $command in $baseDirectory, timeout is ${timeout.fold("none")(_.toString)}") val process = Process(Seq(command, jobDirectory.toString), baseDirectory.toFile) - .run(ProcessLogger(s ⇒ logger.info(s" Job ${job.id}: $s"))) + .run(ProcessLogger { s ⇒ + logger.info(s" Job ${job.id}: $s") + output ++= s + }) val execution = Future .apply { process.exitValue() () } + .map { _ ⇒ + val outputFile = jobDirectory.resolve("output").resolve("output.json") + if (!Files.exists(outputFile) || Files.size(outputFile) == 0) { + val report = Json.obj("success" → false, "errorMessage" → output.toString) + Files.write(outputFile, report.toString.getBytes(StandardCharsets.UTF_8)) + } + () + } .recoverWith { case error ⇒ logger.error(s"Execution of command $command failed", error) Future.apply { - val report = Json.obj("success" → false, "errorMessage" → error.getMessage) + val report = Json.obj("success" → false, "errorMessage" → s"${error.getMessage}\n$output") Files.write(jobDirectory.resolve("output").resolve("output.json"), report.toString.getBytes(StandardCharsets.UTF_8)) () }