diff --git a/app/web/controllers/SystemCheck.scala b/app/web/controllers/SystemCheck.scala index 445a08892..b488e3d2b 100644 --- a/app/web/controllers/SystemCheck.scala +++ b/app/web/controllers/SystemCheck.scala @@ -3,11 +3,14 @@ package web.controllers import java.util.concurrent.TimeUnit import com.amazonaws.services.s3.AmazonS3 +import com.amazonaws.services.s3.model._ import com.mongodb.BasicDBObject import com.mongodb.casbah.MongoDB + import org.corespring.elasticsearch.WSClient import org.corespring.itemSearch.ElasticSearchConfig import org.corespring.models.error.CorespringInternalError + import play.api.Play.current import play.api.cache.Cache import play.api.libs.concurrent.Execution.Implicits._ @@ -16,55 +19,42 @@ import play.api.mvc.{ Action, Controller } import scala.concurrent.duration.Duration import scala.concurrent.{ Await, Future } +import scala.util.{ Failure, Success } class SystemCheck(s3: AmazonS3, db: MongoDB, elasticSearchConfig: ElasticSearchConfig) extends Controller { - def checkCache(): Either[CorespringInternalError, Unit] = { - Cache.set("test", "test") - Cache.get("test") match { + val timeUnit = Duration(5, TimeUnit.SECONDS) + + def checkCache(setCache: String, getCache: String): Future[Either[CorespringInternalError, Unit]] = Future { + Cache.set(setCache, setCache) + Cache.get(getCache) match { case Some(test) => if (test == "test") Right(()) else Left(CorespringInternalError("did not retrieve correct value from cache")) case None => Left(CorespringInternalError("could not retrieve any value from cache")) } } - def checkS3(): Either[CorespringInternalError, Unit] = { + def checkS3(_s3: AmazonS3, bucket: String): Future[Either[CorespringInternalError, Unit]] = Future { try { - val testBucket = "corespring-system-check" - val testObject = "circle.png" - val getS3Object = s3.getObject(testBucket, testObject) + val testBucket = new HeadBucketRequest(bucket) + _s3.headBucket(testBucket) Right(()) } catch { - case e: Throwable => Left(CorespringInternalError("S3 is not available")) + case e: Throwable => Left(CorespringInternalError("S3 / Bucket is not available")) } } - def checkDatabase(): Either[CorespringInternalError, Unit] = { - - val mainDb = db - val dbmodels = Seq( - "accessTokens", - "apiClients", - "contentcolls", - "fieldValues", - "itemsessions", - "orgs", - "subjects", - "users") + def checkDatabase(_db: MongoDB, dbmodels: Seq[String]): Future[Either[CorespringInternalError, Unit]] = Future { dbmodels.foldRight[Either[CorespringInternalError, Unit]](Right(()))((dbmodel, result) => { if (result.isRight) { - mainDb.getCollection(dbmodel).findOne() match { - case _: BasicDBObject => Right(()) - case _ => Left(CorespringInternalError("could not find collection: " + dbmodel)) - } + if (_db.collectionExists(dbmodel)) Right(()) + else Left(CorespringInternalError("could not find collection: " + dbmodel)) } else result }) } - def checkElasticSearch(): Either[CorespringInternalError, Unit] = { - - val cfg = elasticSearchConfig - val elasticSearchClient = WSClient(cfg.url) + def checkElasticSearch(_elasticSearchConfig: ElasticSearchConfig): Future[Either[CorespringInternalError, Unit]] = Future { + val elasticSearchClient = WSClient(_elasticSearchConfig.url) val elasticClientResult = elasticSearchClient.request("_cluster/health").get.flatMap[Either[CorespringInternalError, Unit]](response => Future { response.status match { case 200 => Right(()) @@ -73,28 +63,53 @@ class SystemCheck(s3: AmazonS3, db: MongoDB, elasticSearchConfig: ElasticSearchC } recover { case timeout: java.util.concurrent.TimeoutException => Left(CorespringInternalError("Timed out while connecting to ElasticSearch cluster")) }) - Await.result(elasticClientResult, Duration(5, TimeUnit.SECONDS)); + Await.result(elasticClientResult, timeUnit); } - def index = Action.async { - val timeout = play.api.libs.concurrent.Promise.timeout("Oops", Duration(6, TimeUnit.SECONDS)) + def index = Action.async { + + val timeoutCheck = play.api.libs.concurrent.Promise.timeout("Ooops", timeUnit).map { + case timeout: String => Left(CorespringInternalError("Timed out")) + } + + val testCache = "test" + val bucket = "corespring-system-check" + val dbmodels = Seq( + "accessTokens", + "apiClients", + "contentcolls", + "fieldValues", + "itemsessions", + "orgs", + "subjects", + "users") - val runChecks: Future[Either[CorespringInternalError, Unit]] = scala.concurrent.Future { - val results = List( - checkS3(), - checkCache(), - checkDatabase(), - checkElasticSearch()) + val futureCheckCache = checkCache(testCache,testCache) + val futureCheckS3 = checkS3(s3, bucket) + val futureCheckDatabase = checkDatabase(db, dbmodels) + val futureCheckElasticSearch = checkElasticSearch(elasticSearchConfig) - def isAnError(result: Either[CorespringInternalError, Unit]) = result match { - case Left(_) => true - case Right(_) => false - } - val errors = results.filter(isAnError) + def isAnError(result: Either[CorespringInternalError, Unit]) = result match { + case Left(_) => true + case Right(_) => false + } - if (errors.length == 0) Right() - else { + val results = Future.sequence( + Seq( + Future.firstCompletedOf(Seq(futureCheckCache, timeoutCheck)), + Future.firstCompletedOf(Seq(futureCheckS3, timeoutCheck)), + Future.firstCompletedOf(Seq(futureCheckDatabase, timeoutCheck)), + Future.firstCompletedOf(Seq(futureCheckElasticSearch, timeoutCheck)) + ) + ) + + results.map { res => + val errors = res.filter(isAnError) + + if (errors.length == 0) { + Ok + } else { val sb = new java.lang.StringBuilder errors.foreach { e => e match { @@ -104,17 +119,8 @@ class SystemCheck(s3: AmazonS3, db: MongoDB, elasticSearchConfig: ElasticSearchC case _ => Ok } } - Left(CorespringInternalError(sb.toString())) - } - } - - Future.firstCompletedOf(Seq(runChecks, timeout)).map { - case timeout: String => BadRequest("timeout") - case Right(_) => Ok - case Left(error: CorespringInternalError) => { - InternalServerError(JsObject(Seq("error" -> JsString("a check failed"), "moreInfo" -> JsString(error.message)))) + InternalServerError(JsObject(Seq("error" -> JsString("check(s) failed"), "moreInfo" -> JsString(sb.toString())))) } - case Left(_) => BadRequest("An unknown error occured") } } } \ No newline at end of file diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 0eb5a36e6..da4acc6bc 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -26,7 +26,7 @@ object Dependencies { val amapClient = "com.rabbitmq" % "amqp-client" % "3.0.2" val assetsLoader = ("com.ee" %% "assets-loader" % "0.12.5").exclude("com.yahoo.platform.yui", "yuicompressor") - val aws = "com.amazonaws" % "aws-java-sdk" % "1.10.0" + val aws = "com.amazonaws" % "aws-java-sdk" % "1.11.27" val casbah = "org.mongodb" %% "casbah" % "2.6.3" val closureCompiler = ("com.google.javascript" % "closure-compiler" % "rr2079.1" notTransitive ()).exclude("args4j", "args4j").exclude("com.google.guava", "guava").exclude("org.json", "json").exclude("com.google.protobuf", "protobuf-java").exclude("org.apache.ant", "ant").exclude("com.google.code.findbugs", "jsr305").exclude("com.googlecode.jarjar", "jarjar").exclude("junit", "junit") val commonsCodec = "commons-codec" % "commons-codec" % "1.10"