diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..1e57e85b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# Extracted from https://github.com/ulrich/macaron-factory/blob/master/.gitignore
+# Ignore all dotfiles...
+.*
+# except for .gitignore
+!.gitignore
+
+# Ignore Play! working directory #
+db
+eclipse
+lib
+log
+logs
+modules
+precompiled
+project/project
+project/target
+target
+tmp
+test-result
+server.pid
+*.iml
+*.eml
+activator-*.sbt
+node_modules
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 00000000..35bc3e63
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,65 @@
+module.exports = function(grunt) {
+
+ grunt.initConfig({
+ clean: {
+ dist: {
+ src: ['_site/dist']
+ }
+ },
+ watch: {
+ scripts: {
+ files: ['src/**/*.*', 'src/*.*'],
+ tasks: ['build'],
+ options: {
+ spawn: false
+ }
+ }
+ },
+ copy: {
+ main: {
+ files: [
+ ]
+ }
+ },
+ concat: {
+ vendorjs: {
+ src: [
+ ],
+ dest: 'public/lib.js'
+ },
+ vendorcss: {
+ src: [
+ ],
+ dest: 'public/css/lib.css'
+ },
+ appjs: {
+ src: [
+ 'src/main.js',
+ 'src/*/*.js'
+ ],
+ dest: 'public/app.js'
+ },
+ },
+ jshint: {
+ cerebro: {
+ src: [
+
+ ]
+ }
+ },
+ qunit: {
+ all: []
+ }
+ });
+ grunt.loadNpmTasks('grunt-contrib-clean');
+ grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-connect');
+ grunt.loadNpmTasks('grunt-contrib-copy');
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-qunit');
+ grunt.loadNpmTasks("grunt-jscs");
+ grunt.registerTask('dev', ['watch'])
+ grunt.registerTask('build',
+ ['clean', 'copy', 'concat' ]);
+};
diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala
new file mode 100644
index 00000000..eb6c0274
--- /dev/null
+++ b/app/controllers/Application.scala
@@ -0,0 +1,12 @@
+package controllers
+
+import play.api.mvc.{Action, Controller}
+import play.api.http.MimeTypes
+
+object Application extends Controller {
+
+ def index = Action {
+ Ok(views.html.Index())
+ }
+
+}
diff --git a/app/controllers/ClusterOverviewController.scala b/app/controllers/ClusterOverviewController.scala
new file mode 100644
index 00000000..cb0d72b4
--- /dev/null
+++ b/app/controllers/ClusterOverviewController.scala
@@ -0,0 +1,33 @@
+package controllers
+
+import elastic.ElasticClient._
+import models.overview.ClusterOverview
+import play.api.mvc.{Action, Controller}
+
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
+
+
+object ClusterOverviewController extends Controller {
+
+ def index = Action.async {
+ request => {
+ val host = request.queryString.getOrElse("host", Seq("http://localhost:9200")).head
+ try {
+ val response = Future.sequence(
+ Seq(clusterState(host), nodesStats(host), indicesStats(host), clusterSettings(host), aliases(host), clusterHealth(host), nodes(host), main(host))
+ ).map { f =>
+ new ClusterOverview(f(0).body, f(1).body, f(2).body, f(3).body, f(4).body, f(5).body, f(6).body, f(7).body).json
+ }.recover {
+ case e =>
+ throw e
+ }
+ response.map(Ok(_))
+ } catch {
+ case _ => Future.successful(Status(500)(s"Cannot connect to $host"))
+ }
+ }
+
+ }
+
+}
diff --git a/app/controllers/HostsController.scala b/app/controllers/HostsController.scala
new file mode 100644
index 00000000..47f6dc2b
--- /dev/null
+++ b/app/controllers/HostsController.scala
@@ -0,0 +1,20 @@
+package controllers
+
+import play.api.Play
+import play.api.libs.json.{JsArray, JsString}
+import play.api.mvc.{Action, Controller}
+
+
+class HostsController extends Controller {
+
+ def index = Action {
+ request => {
+ val hosts = Play.current.configuration.getConfigSeq("hosts") match {
+ case Some(a) => a.map { b => b.getString("host").get }
+ case None => Seq()
+ }
+ Ok(JsArray(hosts.map(JsString(_))))
+ }
+ }
+
+}
diff --git a/app/controllers/Main.scala b/app/controllers/Main.scala
new file mode 100644
index 00000000..4235a94c
--- /dev/null
+++ b/app/controllers/Main.scala
@@ -0,0 +1,10 @@
+package controllers
+
+import controllers.elasticsearch.ElasticsearchController
+import elastic.ElasticClient
+
+object Main extends ElasticsearchController {
+
+ def index = processRequest(ElasticClient.main(_))
+
+}
diff --git a/app/controllers/elasticsearch/ClearIndexCacheController.scala b/app/controllers/elasticsearch/ClearIndexCacheController.scala
new file mode 100644
index 00000000..c4e19e58
--- /dev/null
+++ b/app/controllers/elasticsearch/ClearIndexCacheController.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class ClearIndexCacheController extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.clearIndexCache(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/CloseIndexController.scala b/app/controllers/elasticsearch/CloseIndexController.scala
new file mode 100644
index 00000000..af03d964
--- /dev/null
+++ b/app/controllers/elasticsearch/CloseIndexController.scala
@@ -0,0 +1,10 @@
+package controllers.elasticsearch
+
+
+import elastic.ElasticClient
+
+class CloseIndexController extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.closeIndex(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/DeleteIndexController.scala b/app/controllers/elasticsearch/DeleteIndexController.scala
new file mode 100644
index 00000000..80eeb21d
--- /dev/null
+++ b/app/controllers/elasticsearch/DeleteIndexController.scala
@@ -0,0 +1,10 @@
+package controllers.elasticsearch
+
+
+import elastic.ElasticClient
+
+class DeleteIndexController extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.deleteIndex(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/DisableShardAllocationController.scala b/app/controllers/elasticsearch/DisableShardAllocationController.scala
new file mode 100644
index 00000000..64ab5c2b
--- /dev/null
+++ b/app/controllers/elasticsearch/DisableShardAllocationController.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class DisableShardAllocationController extends ElasticsearchController {
+
+ def index() = processRequest(ElasticClient.disableShardAllocation(_))
+
+}
diff --git a/app/controllers/elasticsearch/ElasticsearchController.scala b/app/controllers/elasticsearch/ElasticsearchController.scala
new file mode 100644
index 00000000..1e2d4e5a
--- /dev/null
+++ b/app/controllers/elasticsearch/ElasticsearchController.scala
@@ -0,0 +1,27 @@
+package controllers.elasticsearch
+
+import elastic.ElasticResponse
+import play.api.Logger
+import play.api.mvc.{Action, Controller}
+
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
+
+trait ElasticsearchController extends Controller {
+
+ protected val logger = Logger("elastic")
+
+ def processRequest(f: (String => Future[ElasticResponse])) = Action.async {
+ request =>
+ val host = request.queryString.getOrElse("host", Seq("http://localhost:9200")).head
+ try {
+ val response = f(host)
+ response.map { r =>
+ Status(r.status)(r.body)
+ }
+ } catch {
+ case _ => Future.successful(Status(500)(s"Cannot connect to $host"))
+ }
+ }
+
+}
diff --git a/app/controllers/elasticsearch/EnableShardAllocationController.scala b/app/controllers/elasticsearch/EnableShardAllocationController.scala
new file mode 100644
index 00000000..ae1c4e2d
--- /dev/null
+++ b/app/controllers/elasticsearch/EnableShardAllocationController.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class EnableShardAllocationController extends ElasticsearchController {
+
+ def index() = processRequest(ElasticClient.enableShardAllocation(_))
+
+}
diff --git a/app/controllers/elasticsearch/GetIndexMapping.scala b/app/controllers/elasticsearch/GetIndexMapping.scala
new file mode 100644
index 00000000..0ea24517
--- /dev/null
+++ b/app/controllers/elasticsearch/GetIndexMapping.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class GetIndexMapping extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.getIndexMapping(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/GetIndexSettings.scala b/app/controllers/elasticsearch/GetIndexSettings.scala
new file mode 100644
index 00000000..78165adb
--- /dev/null
+++ b/app/controllers/elasticsearch/GetIndexSettings.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class GetIndexSettings extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.getIndexSettings(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/NodeStatsController.scala b/app/controllers/elasticsearch/NodeStatsController.scala
new file mode 100644
index 00000000..568b41e3
--- /dev/null
+++ b/app/controllers/elasticsearch/NodeStatsController.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class NodeStatsController extends ElasticsearchController {
+
+ def index(nodes: String) = processRequest(ElasticClient.nodesStats(nodes, _))
+
+}
diff --git a/app/controllers/elasticsearch/OpenIndexController.scala b/app/controllers/elasticsearch/OpenIndexController.scala
new file mode 100644
index 00000000..dc7b8949
--- /dev/null
+++ b/app/controllers/elasticsearch/OpenIndexController.scala
@@ -0,0 +1,10 @@
+package controllers.elasticsearch
+
+
+import elastic.ElasticClient
+
+class OpenIndexController extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.openIndex(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/OptimizeIndexController.scala b/app/controllers/elasticsearch/OptimizeIndexController.scala
new file mode 100644
index 00000000..b4b8ab78
--- /dev/null
+++ b/app/controllers/elasticsearch/OptimizeIndexController.scala
@@ -0,0 +1,12 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+import play.api.mvc.{Action, Controller}
+
+import scala.concurrent.ExecutionContext.Implicits.global
+
+class OptimizeIndexController extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.optimizeIndex(indices, _))
+
+}
diff --git a/app/controllers/elasticsearch/PutClusterSettings.scala b/app/controllers/elasticsearch/PutClusterSettings.scala
new file mode 100644
index 00000000..39321ae6
--- /dev/null
+++ b/app/controllers/elasticsearch/PutClusterSettings.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class PutClusterSettings extends ElasticsearchController {
+
+ def index = processRequest(ElasticClient.putClusterSettings("", _))
+
+}
diff --git a/app/controllers/elasticsearch/RefreshIndexController.scala b/app/controllers/elasticsearch/RefreshIndexController.scala
new file mode 100644
index 00000000..2c7645ae
--- /dev/null
+++ b/app/controllers/elasticsearch/RefreshIndexController.scala
@@ -0,0 +1,9 @@
+package controllers.elasticsearch
+
+import elastic.ElasticClient
+
+class RefreshIndexController extends ElasticsearchController {
+
+ def index(indices: String) = processRequest(ElasticClient.refreshIndex(indices, _))
+
+}
diff --git a/app/elastic/ElasticClient.scala b/app/elastic/ElasticClient.scala
new file mode 100644
index 00000000..843d3e94
--- /dev/null
+++ b/app/elastic/ElasticClient.scala
@@ -0,0 +1,74 @@
+package elastic
+
+import play.api.Play.current
+import play.api.libs.ws.WS
+import play.api.mvc.Results.EmptyContent
+
+trait ElasticClient {
+
+ def main(host: String) =
+ ElasticResponse(WS.url(s"$host").get())
+
+ def clusterState(host: String) =
+ ElasticResponse(WS.url(s"$host/_cluster/state/master_node,routing_table,routing_nodes,blocks").get())
+
+ def indicesStats(host: String) =
+ ElasticResponse(WS.url(s"$host/_stats/docs,store").get())
+
+ def nodesStats(host: String) =
+ ElasticResponse(WS.url(s"$host/_nodes/stats/jvm,fs,os,process").get())
+
+ def nodesStats(node: String, host: String) =
+ ElasticResponse(WS.url(s"$host/_nodes/$node/stats?human").get())
+
+ def clusterSettings(host: String) =
+ ElasticResponse(WS.url(s"$host/_cluster/settings").get())
+
+ def aliases(host: String) =
+ ElasticResponse(WS.url(s"$host/_aliases").get())
+
+ def clusterHealth(host: String) =
+ ElasticResponse(WS.url(s"$host/_cluster/health").get())
+
+ def nodes(host: String) =
+ ElasticResponse(WS.url(s"$host/_nodes/_all/os,jvm").get())
+
+ def closeIndex(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_close").post(EmptyContent()))
+
+ def openIndex(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_open").post(EmptyContent()))
+
+ def refreshIndex(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_refresh").post(EmptyContent()))
+
+ def optimizeIndex(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_optimize").post(EmptyContent()))
+
+ def clearIndexCache(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_cache/clear").post(EmptyContent()))
+
+ def deleteIndex(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index").delete())
+
+ def getIndexSettings(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_settings").get())
+
+ def getIndexMapping(index: String, host: String) =
+ ElasticResponse(WS.url(s"$host/$index/_mapping").get())
+
+ def putClusterSettings(settings: String, host: String) =
+ ElasticResponse(WS.url(s"$host/_cluster/settings").put(settings))
+
+ private def allocationSettings(value: String) =
+ s"""{"transient": {"cluster": {"routing": {"allocation": {"enable": \"$value\"}}}}}"""
+
+ def enableShardAllocation(host: String) =
+ putClusterSettings(allocationSettings("all"), host)
+
+ def disableShardAllocation(host: String) =
+ putClusterSettings(allocationSettings("none"), host)
+
+}
+
+object ElasticClient extends ElasticClient
diff --git a/app/elastic/ElasticResponse.scala b/app/elastic/ElasticResponse.scala
new file mode 100644
index 00000000..61d9a76b
--- /dev/null
+++ b/app/elastic/ElasticResponse.scala
@@ -0,0 +1,17 @@
+package elastic
+
+import play.api.libs.json.JsValue
+import play.api.libs.ws.WSResponse
+
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
+
+case class ElasticResponse(status: Int, body: JsValue)
+
+object ElasticResponse {
+
+ def apply(response: Future[WSResponse]): Future[ElasticResponse] = response.map {
+ r => ElasticResponse(r.status, r.json)
+ }
+
+}
diff --git a/app/models/ClusterHealth.scala b/app/models/ClusterHealth.scala
new file mode 100644
index 00000000..63ecfbdd
--- /dev/null
+++ b/app/models/ClusterHealth.scala
@@ -0,0 +1,25 @@
+package models
+
+import play.api.libs.json.{JsObject, JsString, JsValue}
+
+class ClusterHealth(data: JsValue) {
+
+ def json() = {
+ JsObject(Seq(
+ "cluster_name" -> (data \ "cluster_name").as[JsString],
+ "status" -> (data \ "status").as[JsString],
+ "number_of_nodes" -> (data \ "number_of_nodes").as[JsString],
+ "active_primary_shards" -> (data \ "active_primary_shards").as[JsString],
+ "active_shards" -> (data \ "active_shards").as[JsString],
+ "relocating_shards" -> (data \ "relocating_shards").as[JsString],
+ "initializing_shards" -> (data \ "initializing_shards").as[JsString],
+ "unassigned_shards" -> (data \ "unassigned_shards").as[JsString],
+ "delayed_unassigned_shards" -> (data \ "delayed_unassigned_shards").as[JsString],
+ "number_of_pending_tasks" -> (data \ "number_of_pending_tasks").as[JsString],
+ "number_of_in_flight_fetch" -> (data \ "number_of_in_flight_fetch").as[JsString],
+ "task_max_waiting_in_queue_millis" -> (data \ "task_max_waiting_in_queue_millis").as[JsString],
+ "active_shards_percent_as_number" -> (data \ "active_shards_percent_as_number").as[JsString]
+ ))
+ }
+
+}
diff --git a/app/models/overview/ClusterOverview.scala b/app/models/overview/ClusterOverview.scala
new file mode 100644
index 00000000..39127fc2
--- /dev/null
+++ b/app/models/overview/ClusterOverview.scala
@@ -0,0 +1,140 @@
+package models.overview
+
+import elastic.ElasticClient._
+import play.api.libs.json._
+
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.Future
+
+class ClusterOverview(clusterState: JsValue, nodesStats: JsValue, indicesStats: JsValue,
+ clusterSettings: JsValue, aliases: JsValue, clusterHealth: JsValue,
+ nodes: JsValue, main: JsValue) {
+
+ def json: JsValue = {
+ val indices = Indices(clusterState, indicesStats, aliases)
+ val clusterNodes = Nodes(clusterState, nodesStats, nodes)
+
+ val persistentAllocation = (clusterSettings \ "persistent" \ "cluster" \ "routing" \ "allocation" \ "enable").asOpt[String].getOrElse("all")
+ val transientAllocation = (clusterSettings \ "transient" \ "cluster" \ "routing" \ "allocation" \ "enable").asOpt[String]
+ val shardAllocation = transientAllocation.getOrElse(persistentAllocation).equals("all")
+
+ JsObject(Seq(
+ // clusterHealth
+ "cluster_name" -> (clusterHealth \ "cluster_name").as[JsString],
+ "status" -> (clusterHealth \ "status").as[JsString],
+ "number_of_nodes" -> (clusterHealth \ "number_of_nodes").as[JsNumber],
+ "active_primary_shards" -> (clusterHealth \ "active_primary_shards").as[JsNumber],
+ "active_shards" -> (clusterHealth \ "active_shards").as[JsNumber],
+ "relocating_shards" -> (clusterHealth \ "relocating_shards").as[JsNumber],
+ "initializing_shards" -> (clusterHealth \ "initializing_shards").as[JsNumber],
+ "unassigned_shards" -> (clusterHealth \ "unassigned_shards").as[JsNumber],
+ // indicesStats
+ "docs_count" -> (indicesStats \ "_all" \ "primaries" \ "docs" \ "count").asOpt[JsNumber].getOrElse(JsNumber(0)),
+ "size_in_bytes" -> (indicesStats \ "_all" \ "total" \ "store" \ "size_in_bytes").asOpt[JsNumber].getOrElse(JsNumber(0)),
+ "total_indices" -> JsNumber(indices.size),
+ "closed_indices" -> JsNumber(indices.count { idx => (idx \ "closed").as[Boolean] } ),
+ "special_indices" -> JsNumber(indices.count { idx => (idx \ "special").as[Boolean] } ),
+ "indices" -> JsArray(indices),
+ "nodes" -> JsArray(clusterNodes),
+ "shard_allocation" -> JsBoolean(shardAllocation)
+ ))
+ }
+}
+
+object Nodes {
+
+ def apply(clusterState: JsValue, nodesStats: JsValue, nodes: JsValue): Seq[JsValue] = {
+ val currentMaster = (clusterState \ "master_node").as[String]
+ (nodes \ "nodes").as[JsObject].value.map { case (nodeId, info) =>
+ val master = (info \ "attributes" \ "master").asOpt[String].getOrElse("true").equals("true")
+ val data = (info \ "attributes" \ "data").asOpt[String].getOrElse("true").equals("true")
+ val client = (info \ "attributes" \ "client").asOpt[String].getOrElse("false").equals("true")
+
+ val stats = (nodesStats \ "nodes" \ nodeId).as[JsObject]
+ val totalInBytes = (stats \ "fs" \ "total" \ "total_in_bytes").asOpt[Long].getOrElse(0l) // FIXME: 1.X
+ val diskFreeInBytes = (stats \ "fs" \ "total" \ "free_in_bytes").asOpt[Long].getOrElse(0l) // FIXME: 1.X
+ val cpuPercent = (stats \ "process" \ "cpu" \ "percent").asOpt[JsNumber].getOrElse((stats \ "os" \ "user").as[JsNumber])
+ Json.obj(
+ "id" -> JsString(nodeId),
+ "current_master" -> JsBoolean(nodeId.equals(currentMaster)),
+ "name" -> (info \ "name").as[JsString],
+ "host" -> (info \ "host").as[JsString],
+ "ip" -> (info \ "ip").as[JsString],
+ "es_version" -> (info \ "version").as[JsString],
+ "jvm_version" -> (info \ "jvm" \ "version").as[JsString],
+ "load_average" -> JsNumber(BigDecimal((stats \ "os" \ "load_average").asOpt[Int].getOrElse(0))),// FIXME: 1.X
+ "available_processors" -> (info \ "os" \ "available_processors").as[JsNumber],
+ "cpu_percent" -> cpuPercent,
+ "master" -> JsBoolean(master && !client),
+ "data" -> JsBoolean(data && !client),
+ "client" -> JsBoolean(client || !master && !data),
+ "heap" -> Json.obj(
+ "used" -> (stats \ "jvm" \ "mem" \ "heap_used_in_bytes").as[JsNumber],
+ "committed" -> (stats \ "jvm" \ "mem" \ "heap_committed_in_bytes").as[JsNumber],
+ "used_percent" -> (stats \ "jvm" \ "mem" \ "heap_used_percent").as[JsNumber],
+ "max" -> (stats \ "jvm" \ "mem" \ "heap_max_in_bytes").as[JsNumber]
+ ),
+ "disk" -> Json.obj(
+ "total_in_bytes" -> JsNumber(totalInBytes),
+ "disk_free_in_bytes" -> JsNumber(diskFreeInBytes),
+ "used_percent" -> JsNumber(100 - (100 * (diskFreeInBytes.toFloat / totalInBytes.toFloat)).toInt)
+ )
+ )
+ }.toSeq
+ }
+
+}
+
+object Indices {
+
+ def apply(clusterState: JsValue, indicesStats: JsValue, aliases: JsValue) = {
+ val routingTable = (clusterState \ "routing_table" \ "indices").as[JsObject]
+ val openIndices = routingTable.value.map { case (index, shards) =>
+ val stats = (indicesStats \ "indices" \ index).asOpt[JsObject].getOrElse(Json.obj())
+ val indexShards = (shards \ "shards").as[JsObject].values.flatMap { case shards =>
+ shards.as[JsArray].value.map { instance =>
+ (instance \ "node").asOpt[String].getOrElse("unassigned") -> instance
+ }
+ }.groupBy(_._1).mapValues { shards => JsArray(shards.map(_._2).toSeq) }.toSeq
+
+ val numShards = (shards \ "shards").as[JsObject].keys.size
+ val numReplicas = (shards \ "shards" \ "0").as[JsArray].value.size - 1
+
+ val unhealthy = indexShards.find(_._1.equals("unassigned")).isDefined
+ val special = index.startsWith(".")
+
+ JsObject(Seq(
+ "name" -> JsString(index),
+ "closed" -> JsBoolean(false),
+ "special" -> JsBoolean(special),
+ "unhealthy" -> JsBoolean(unhealthy),
+ "doc_count" -> (stats \ "primaries" \ "docs" \ "count").asOpt[JsNumber].getOrElse(JsNumber(0)),
+ "deleted_docs" -> (stats \ "primaries" \ "docs" \ "deleted").asOpt[JsNumber].getOrElse(JsNumber(0)),
+ "size_in_bytes" -> (stats \ "primaries" \ "store" \ "size_in_bytes").asOpt[JsNumber].getOrElse(JsNumber(0)),
+ "total_size_in_bytes" -> (stats \ "total" \ "store" \ "size_in_bytes").asOpt[JsNumber].getOrElse(JsNumber(0)),
+ "aliases" -> JsArray((aliases \ index \ "aliases").as[JsObject].keys.map(JsString(_)).toSeq),
+ "num_shards" -> JsNumber(numShards),
+ "num_replicas" -> JsNumber(numReplicas),
+ "shards" -> JsObject(indexShards)
+ ))
+ }.toSeq
+
+ openIndices ++ ClosedIndices(clusterState)
+ }
+
+}
+
+object ClosedIndices {
+
+ def apply(clusterState: JsValue) = {
+ val blocks = (clusterState \ "blocks" \ "indices").asOpt[JsObject].getOrElse(Json.obj())
+ blocks.keys.collect {
+ case index if (blocks \ index \ "4").asOpt[JsObject].isDefined =>
+ Json.obj(
+ "name" -> JsString(index),
+ "closed" -> JsBoolean(true),
+ "special" -> JsBoolean(index.startsWith("."))
+ )
+ }
+ }
+}
diff --git a/app/views/Index.scala.html b/app/views/Index.scala.html
new file mode 100644
index 00000000..72578de8
--- /dev/null
+++ b/app/views/Index.scala.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.sbt b/build.sbt
new file mode 100644
index 00000000..e0d51b25
--- /dev/null
+++ b/build.sbt
@@ -0,0 +1,21 @@
+name := "cerebro"
+
+version := "0.0.1"
+
+scalaVersion := "2.11.6"
+
+libraryDependencies ++= Seq(
+ "org.webjars" %% "webjars-play" % "2.4.0-1",
+ "org.webjars" % "angularjs" % "1.5.0",
+ "org.webjars" % "bootstrap" % "4.0.0-alpha.2",
+ "org.webjars" % "font-awesome" % "4.5.0",
+ "org.webjars.bower" % "tether" % "1.1.1",
+ "org.elasticsearch" % "elasticsearch" % "2.2.0",
+ "com.typesafe.play" %% "play-ws" % "2.4.6",
+ "org.specs2" %% "specs2-junit" % "3.6.5",
+ "org.specs2" %% "specs2-core" % "3.6.5"
+)
+
+lazy val root = (project in file(".")).enablePlugins(PlayScala)
+
+pipelineStages := Seq(digest, gzip)
diff --git a/conf/application.conf b/conf/application.conf
new file mode 100644
index 00000000..4753280f
--- /dev/null
+++ b/conf/application.conf
@@ -0,0 +1,35 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+# If you deploy your application to several instances be sure to use the same key!
+application.secret="ki:s:[[@=Ag?QI`W2jMwkY:eqvrJ]JqoJyi2axj3ZvOv^/KavOT4ViJSv?6YY4[N"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+hosts = [
+ {
+ host = "http://localhost:9200"
+ },
+ {
+ host = "http://localhost:9201"
+ }
+]
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory .
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
diff --git a/conf/logger.xml b/conf/logger.xml
new file mode 100644
index 00000000..7e15b77b
--- /dev/null
+++ b/conf/logger.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ ${application.home}/logs/application.log
+
+ %date - [%level] - from %logger in %thread %n%message%n%xException%n
+
+
+
+
+
+ %coloredLevel %logger{15} - %message%n%xException{5}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/routes b/conf/routes
new file mode 100644
index 00000000..be5643ae
--- /dev/null
+++ b/conf/routes
@@ -0,0 +1,31 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+
+# Home page
+GET / controllers.Application.index()
+
+#
+GET /main controllers.Main.index()
+GET /apis/overview controllers.ClusterOverviewController.index()
+POST /apis/:indices/_close @controllers.elasticsearch.CloseIndexController.index(indices)
+POST /apis/:indices/_open @controllers.elasticsearch.OpenIndexController.index(indices)
+POST /apis/:indices/_optimize @controllers.elasticsearch.OptimizeIndexController.index(indices)
+POST /apis/:indices/_cache/clear @controllers.elasticsearch.ClearIndexCacheController.index(indices)
+POST /apis/:indices/_refresh @controllers.elasticsearch.RefreshIndexController.index(indices)
+DELETE /apis/:indices/_delete @controllers.elasticsearch.DeleteIndexController.index(indices)
+GET /apis/:index/_settings @controllers.elasticsearch.GetIndexSettings.index(index)
+GET /apis/:index/_mapping @controllers.elasticsearch.GetIndexMapping.index(index)
+PUT /apis/_cluster/settings @controllers.elasticsearch.PutClusterSettings.index
+GET /apis/_nodes/:nodes/stats @controllers.elasticsearch.NodeStatsController.index(nodes)
+PUT /apis/disable_allocation @controllers.elasticsearch.DisableShardAllocationController.index()
+PUT /apis/enable_allocation @controllers.elasticsearch.EnableShardAllocationController.index()
+
+GET /apis/hosts @controllers.HostsController.index
+
+
+# Map the JS resource paths
+GET /webjars/*file controllers.WebJarAssets.at(file)
+GET /assets/*file controllers.Assets.at(path="/public", file)
+GET /*file controllers.Assets.versioned(path="/public", file: Asset)
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..2de481bf
--- /dev/null
+++ b/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "cerebro",
+ "version": "0.0.1",
+ "description": "cerebro - elasticsearch admin",
+ "main": "index.html",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/lmenezes/cerebro.git"
+ },
+ "author": "Leonardo Menezes",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/lmenezes/cerebro/issues"
+ },
+ "devDependencies": {
+ "grunt": "^0.4.5",
+ "grunt-contrib-clean": "^0.5.0",
+ "grunt-contrib-concat": "^0.3.0",
+ "grunt-contrib-connect": "^0.5.0",
+ "grunt-contrib-copy": "^0.4.1",
+ "grunt-contrib-jshint": "^0.8.0",
+ "grunt-contrib-qunit": "^0.4.0",
+ "grunt-contrib-watch": "^0.5.3",
+ "grunt-jscs": "^1.8.0",
+ "grunt-karma": "^0.6.2",
+ "karma": "~0.10.9",
+ "karma-chrome-launcher": "~0.1.2",
+ "karma-coffee-preprocessor": "~0.1.2",
+ "karma-firefox-launcher": "~0.1.3",
+ "karma-html2js-preprocessor": "~0.1.0",
+ "karma-jasmine": "~0.1.5",
+ "karma-phantomjs-launcher": "~0.1.2",
+ "karma-requirejs": "~0.2.1",
+ "karma-script-launcher": "~0.1.0",
+ "requirejs": "~2.1.10"
+ },
+ "directories": {
+ "test": "tests"
+ },
+ "dependencies": {}
+}
diff --git a/project/build.properties b/project/build.properties
new file mode 100644
index 00000000..be6c454f
--- /dev/null
+++ b/project/build.properties
@@ -0,0 +1 @@
+sbt.version=0.13.5
diff --git a/project/plugins.sbt b/project/plugins.sbt
new file mode 100644
index 00000000..b748c8fb
--- /dev/null
+++ b/project/plugins.sbt
@@ -0,0 +1,16 @@
+// Comment to get more information during initialization
+logLevel := Level.Warn
+
+// The Typesafe repository
+resolvers += "Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/"
+
+// Use the Play sbt plugin for Play projects
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.6")
+
+addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.4")
+
+addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.0.0")
+
+addSbtPlugin("com.typesafe.sbt" % "sbt-gzip" % "1.0.0")
+
+addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0")
diff --git a/public/alerts.html b/public/alerts.html
new file mode 100644
index 00000000..40da8906
--- /dev/null
+++ b/public/alerts.html
@@ -0,0 +1,15 @@
+
diff --git a/public/app.js b/public/app.js
new file mode 100644
index 00000000..64882e19
--- /dev/null
+++ b/public/app.js
@@ -0,0 +1,1099 @@
+'use strict';
+
+angular.module('cerebro', ['ngRoute']).config(['$routeProvider',
+ function($routeProvider) {
+ $routeProvider.
+ when('/overview', {
+ templateUrl: 'overview.html',
+ controller: 'OverviewController'
+ }).
+ when('/connect', {
+ templateUrl: 'connect.html',
+ controller: 'ConnectController'
+ }).
+ otherwise({redirectTo: '/connect'});
+ }]);
+
+angular.module('cerebro').controller('AlertsController', ['$scope', 'AlertService',
+ function($scope, AlertService) {
+
+ $scope.alerts = [];
+
+ $scope.$watch(
+ function() {
+ return AlertService.alerts;
+ },
+ function(newValue, oldValue) {
+ $scope.alerts = AlertService.alerts;
+ }
+ );
+
+ $scope.remove = function(id) {
+ AlertService.remove(id);
+ };
+
+ }
+
+]);
+
+angular.module('cerebro').controller('ConnectController', [
+ '$scope', '$location', 'DataService', 'AlertService',
+ function($scope, $location, DataService, AlertService) {
+
+ $scope.hosts = undefined;
+
+ $scope.connecting = false;
+
+ $scope.host = undefined;
+
+ DataService.getHosts(
+ function(hosts) {
+ $scope.hosts = hosts;
+ },
+ function(error) {
+
+ }
+ );
+
+ $scope.connect = function(host) {
+ if (host) {
+ $scope.connecting = true;
+ DataService.setHost(
+ host,
+ function(response) {
+ $location.path("/overview");
+ $scope.host = DataService.getHost();
+ },
+ function(response) {
+ $scope.connecting = false;
+ AlertService.error("Error connecting to " + host, response);
+ }
+ );
+ }
+ };
+
+ }]);
+
+angular.module('cerebro').controller('ModalController', ['$scope', 'ModalService',
+ function($scope, ModalService) {
+
+ $scope.service = ModalService;
+
+ $scope.close = function() {
+ $scope.service.close();
+ };
+
+ $scope.confirm = function() {
+ $scope.service.confirm();
+ };
+
+ }
+]);
+
+angular.module('cerebro').controller('NavbarController', ['PageService', '$scope', '$http', 'DataService',
+ function (PageService, $scope, $http, DataService) {
+
+ $scope.status = undefined;
+ $scope.cluster_name = undefined;
+ $scope.host = undefined;
+
+ $scope.$watch(
+ function () {
+ return DataService.getData();
+ },
+ function (data) {
+ if (data) {
+ $scope.status = data.status;
+ $scope.cluster_name = data.cluster_name;
+ $scope.host = DataService.getHost();
+ } else {
+ $scope.status = undefined;
+ $scope.cluster_name = undefined;
+ $scope.host = undefined;
+ }
+ }
+ );
+
+ }]);
+
+angular.module('cerebro').controller('OverviewController', ['$scope', '$http', '$window', 'DataService', 'AlertService', 'ModalService',
+ function ($scope, $http, $window, DataService, AlertService, ModalService) {
+
+ $scope.indices = undefined;
+ $scope.nodes = undefined;
+ $scope.unassigned_shards = 0;
+ $scope.indices_filter = new IndexFilter('', true, false, true, true, 0);
+ $scope.nodes_filter = new NodeFilter('', true, false, false, 0);
+ $scope.closed_indices = 0;
+ $scope.special_indices = 0;
+ $scope.expandedView = false;
+ $scope.shardAllocation = true;
+
+ $scope.getPageSize = function() {
+ return Math.max(Math.round($window.innerWidth / 280), 1);
+ };
+
+ $scope.paginator = new Paginator(1, $scope.getPageSize(), [], $scope.indices_filter);
+
+ $scope.page = $scope.paginator.getPage();
+
+ $($window).resize(function() {
+ $scope.$apply(function() {
+ $scope.paginator.setPageSize($scope.getPageSize());
+ });
+ });
+
+ $scope.$watch(
+ function() {
+ return DataService.getData();
+ },
+ function(data) {
+ if (data) {
+ $scope.setIndices(data.indices);
+ $scope.setNodes(data.nodes);
+ $scope.unassigned_shards = data.unassigned_shards;
+ $scope.closed_indices = data.closed_indices;
+ $scope.special_indices = data.special_indices;
+ $scope.shardAllocation = data.shard_allocation;
+ } else {
+ $scope.indices = undefined;
+ $scope.nodes = undefined;
+ }
+ }
+ );
+
+ $scope.$watch('paginator', function() {
+ if (DataService.getData()) {
+ $scope.setIndices(DataService.getData().indices);
+ }
+ }, true);
+
+ $scope.setIndices = function(indices) {
+ $scope.paginator.setCollection(indices);
+ $scope.page = $scope.paginator.getPage();
+ };
+
+ $scope.$watch('nodes_filter', function() {
+ if (DataService.getData()) {
+ $scope.setNodes(DataService.getData().nodes);
+ }
+ },
+ true);
+
+ $scope.setNodes = function(nodes) {
+ $scope.nodes = nodes.filter(function(node) {
+ return $scope.nodes_filter.matches(node);
+ });
+ };
+
+ var success = function(data) {
+ DataService.forceRefresh();
+ AlertService.success('Operation successfully executed', data);
+ };
+
+ var error = function(data) {
+ AlertService.error('Operation failed', data);
+ };
+
+ var displayInfo = function(info) {
+ ModalService.showInfo(info);
+ };
+
+ $scope.openIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Open ' + index + '?',
+ function() {
+ DataService.openIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.closeIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Close ' + index + '?',
+ function() {
+ DataService.closeIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.deleteIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Delete ' + index + '?',
+ function() {
+ DataService.deleteIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.clearIndexCache = function(index) {
+ ModalService.promptConfirmation(
+ 'Clear ' + index + ' cache?',
+ function() {
+ DataService.clearIndexCache(index, success, error);
+ }
+ );
+ };
+
+ $scope.refreshIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Refresh index ' + index + '?',
+ function() {
+ DataService.refreshIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.optimizeIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Optimize index ' + index + '?',
+ function() {
+ DataService.optimizeIndex(index, success, error);
+ }
+ );
+ };
+
+ // Mass actions
+
+ $scope.closeIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Close all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.closeIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.openIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Open all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.openIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.optimizeIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Optimize all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.optimizeIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.refreshIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Refresh all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.refreshIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.clearIndicesCache = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Clear all ' + indices.length + ' selected indices cache?',
+ function() {
+ DataService.clearIndexCache(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.deleteIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Delete all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.deleteIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.nodeStats = function(node) {
+ DataService.nodeStats(node, displayInfo, error);
+ };
+
+ $scope.getIndexSettings = function (index) {
+ DataService.getIndexSettings(index, displayInfo, error);
+ };
+
+ $scope.getIndexMapping = function (index) {
+ DataService.getIndexMapping(index, displayInfo, error);
+ };
+
+ $scope.disableShardAllocation = function () {
+ DataService.disableShardAllocation(success, error);
+ };
+
+ $scope.enableShardAllocation = function () {
+ DataService.enableShardAllocation(success, error);
+ };
+
+ }]);
+
+angular.module('cerebro').directive('ngPagination', ['$document', function($document) {
+
+ return {
+ scope: {
+ paginator: '=paginator',
+ page: '=page',
+ label: '=label'
+ },
+ templateUrl: 'pagination.html',
+ link: function(scope, element, attrs) {
+ var handler = function(event) {
+ var $target = $(event.target);
+ if ($target.is('input, textarea')) {
+ return;
+ }
+ if (event.keyCode == 39 && scope.page.next) {
+ scope.$apply(function() {
+ scope.paginator.nextPage();
+ event.preventDefault();
+ });
+ }
+ if (event.keyCode == 37 && scope.page.previous) {
+ scope.$apply(function() {
+ scope.paginator.previousPage();
+ event.preventDefault();
+ });
+ }
+ };
+
+ $document.bind('keydown', handler);
+ element.on('$destroy', function() {
+ $document.unbind('keydown', handler);
+ });
+ }
+ };
+}]);
+
+function Paginator(page, pageSize, collection, filter) {
+
+ this.filter = filter;
+
+ this.page = page;
+
+ this.pageSize = pageSize;
+
+ this.$collection = collection ? collection : [];
+
+ this.nextPage = function() {
+ this.page += 1;
+ };
+
+ this.previousPage = function() {
+ this.page -= 1;
+ };
+
+ this.setPageSize = function(newSize) {
+ this.pageSize = newSize;
+ };
+
+ this.getPageSize = function() {
+ return this.pageSize;
+ };
+
+ this.getCurrentPage = function() {
+ return this.page;
+ };
+
+ this.getPage = function() {
+ var results = this.getResults();
+ var total = results.length;
+
+ var first = total > 0 ? ((this.page - 1) * this.pageSize) + 1 : 0;
+ while (total < first) {
+ this.previousPage();
+ first = (this.page - 1) * this.pageSize + 1;
+ }
+ var lastPage = this.page * this.pageSize > total;
+ var last = lastPage ? total : this.page * this.pageSize;
+
+ var elements = total > 0 ? results.slice(first - 1, last) : [];
+
+ var next = this.pageSize * this.page < total;
+ var previous = this.page > 1;
+ while (elements.length < this.pageSize) {
+ elements.push(null);
+ }
+ return new Page(elements, total, first, last, next, previous);
+ };
+
+ this.setCollection = function(collection) {
+ if (this.filter.getSorting()) {
+ this.$collection = collection.sort(this.filter.getSorting());
+ } else {
+ this.$collection = collection;
+ }
+ };
+
+ this.getResults = function() {
+ var filter = this.filter;
+ var collection = this.$collection;
+ if (filter.isBlank()) {
+ return collection;
+ } else {
+ var filtered = [];
+ collection.forEach(function(item) {
+ if (filter.matches(item)) {
+ filtered.push(item);
+ }
+ });
+ return filtered;
+ }
+ };
+
+ this.getCollection = function() {
+ return this.$collection;
+ };
+
+}
+
+function Page(elements, total, first, last, next, previous) {
+ this.elements = elements;
+ this.total = total;
+ this.first = first;
+ this.last = last;
+ this.next = next;
+ this.previous = previous;
+}
+
+
+angular.module('cerebro').directive('ngProgress',
+ function () {
+
+ return {
+ scope: {
+ value: '=value',
+ max: '=max',
+ text: '=text'
+ },
+ template: function (elem, attrs) {
+ return '{{text}} ' +
+ ' 0.75}}}">' +
+ '{{value}}%' +
+ ' '
+ }
+ };
+ }
+);
+
+angular.module('cerebro').directive('ngShard',
+ function () {
+
+ return {
+ scope: {
+ shard: '=shard'
+ },
+ template: function (elem, attrs) {
+ return '' +
+ '{{shard.shard}} ' +
+ ' ';
+ }
+ };
+ }
+);
+
+angular.module('cerebro').filter('bytes', function() {
+
+ var UNITS = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];
+
+ function stringify(bytes) {
+ if (bytes > 0) {
+ var e = Math.floor(Math.log(bytes) / Math.log(1024));
+ return (bytes / Math.pow(1024, e)).toFixed(2) + UNITS[e];
+ } else {
+ return 0 + UNITS[0];
+ }
+ }
+
+ return function(bytes) {
+ return stringify(bytes);
+ };
+
+});
+
+function IndexFilter(name, closed, special, healthy, asc, timestamp) {
+ this.name = name;
+ this.closed = closed;
+ this.special = special;
+ this.healthy = healthy;
+ this.sort = 'name';
+ this.asc = asc;
+ this.timestamp = timestamp;
+
+ this.getSorting = function() {
+ var asc = this.asc;
+ switch (this.sort) {
+ case 'name':
+ return function(a, b) {
+ if (asc) {
+ return a.name.localeCompare(b.name);
+ } else {
+ return b.name.localeCompare(a.name);
+ }
+ };
+ default:
+ return undefined;
+ }
+ };
+
+ this.clone = function() {
+ return new IndexFilter(
+ this.name,
+ this.closed,
+ this.special,
+ this.healthy,
+ this.asc,
+ this.timestamp
+ );
+ };
+
+ this.equals = function(other) {
+ return (
+ other !== null &&
+ this.name === other.name &&
+ this.closed === other.closed &&
+ this.special === other.special &&
+ this.healthy === other.healthy &&
+ this.asc === other.asc &&
+ this.timestamp === other.timestamp
+ );
+ };
+
+ this.isBlank = function() {
+ return (
+ !this.name &&
+ this.closed &&
+ this.special &&
+ this.healthy &&
+ this.asc
+ );
+ };
+
+ this.matches = function(index) {
+ var matches = true;
+ if (!this.special && index.special) {
+ matches = false;
+ }
+ if (!this.closed && index.closed) {
+ matches = false;
+ }
+ // Hide healthy == show unhealthy only
+ if (!this.healthy && !index.unhealthy) {
+ matches = false;
+ }
+ if (matches && this.name) {
+ try {
+ var regExp = new RegExp(this.name.trim(), 'i');
+ matches = regExp.test(index.name);
+ if (!matches && index.aliases) {
+ for (var idx = 0; idx < index.aliases.length; idx++) {
+ if ((matches = regExp.test(index.aliases[idx]))) {
+ break;
+ }
+ }
+ }
+ }
+ catch (err) { // if not valid regexp, still try normal matching
+ matches = index.name.indexOf(this.name.toLowerCase()) != -1;
+ if (!matches) {
+ for (var idx = 0; idx < index.aliases.length; idx++) {
+ var alias = index.aliases[idx].toLowerCase();
+ matches = true;
+ if ((matches = (alias.indexOf(this.name.toLowerCase()) != -1))) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return matches;
+ };
+
+}
+
+function NodeFilter(name, data, master, client, timestamp) {
+ this.name = name;
+ this.data = data;
+ this.master = master;
+ this.client = client;
+ this.timestamp = timestamp;
+
+ this.clone = function() {
+ return new NodeFilter(this.name, this.data, this.master, this.client);
+ };
+
+ this.getSorting = function() {
+ return undefined;
+ };
+
+ this.equals = function(other) {
+ return (
+ other !== null &&
+ this.name == other.name &&
+ this.data == other.data &&
+ this.master == other.master &&
+ this.client == other.client &&
+ this.timestamp == other.timestamp
+ );
+ };
+
+ this.isBlank = function() {
+ return !this.name && (this.data && this.master && this.client);
+ };
+
+ this.matches = function(node) {
+ if (this.isBlank()) {
+ return true;
+ } else {
+ return this.matchesName(node.name) && this.matchesType(node);
+ }
+ };
+
+ this.matchesType = function(node) {
+ return (
+ node.data && this.data ||
+ node.master && this.master ||
+ node.client && this.client
+ );
+ };
+
+ this.matchesName = function(name) {
+ if (this.name) {
+ return name.toLowerCase().indexOf(this.name.toLowerCase()) != -1;
+ } else {
+ return true;
+ }
+ };
+
+}
+
+var Alert = function(message, response, level, _class, icon) {
+ var currentDate = new Date();
+ this.message = message;
+ this.response = response;
+ this.level = level;
+ this.class = _class;
+ this.icon = icon;
+ this.timestamp = currentDate;
+ this.id = 'alert_box_' + currentDate.getTime();
+
+ this.hasResponse = function() {
+ return this.response;
+ };
+
+ this.getResponse = function() {
+ if (this.response) {
+ return JSON.stringify(this.response, undefined, 2);
+ }
+ };
+};
+
+angular.module('cerebro').factory('AlertService', function() {
+ this.maxAlerts = 3;
+
+ this.alerts = [];
+
+ // removes ALL alerts
+ this.clear = function() {
+ this.alerts.length = 0;
+ };
+
+ // remove a particular alert message
+ this.remove = function(id) {
+ $('#' + id).fadeTo(1000, 0).slideUp(200, function() {
+ $(this).remove();
+ });
+ this.alerts = this.alerts.filter(function(a) {
+ return id != a.id;
+ });
+ };
+
+ // creates an error alert
+ this.error = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 7500;
+ var alert = new Alert(msg, resp, 'error', 'red', 'fa fa-warning');
+ return this.addAlert(alert, timeout);
+ };
+
+ // creates an info alert
+ this.info = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 2500;
+ var alert = new Alert(msg, resp, 'info', 'blue', 'fa fa-info');
+ return this.addAlert(alert, timeout);
+ };
+
+ // creates success alert
+ this.success = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 2500;
+ var alert = new Alert(msg, resp, 'success', 'green', 'fa fa-check');
+ return this.addAlert(alert, timeout);
+ };
+
+ // creates a warn alert
+ this.warn = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 5000;
+ var alert = new Alert(msg, resp, 'warn', 'yellow', 'fa fa-info');
+ return this.addAlert(alert, timeout);
+ };
+
+ this.addAlert = function(alert, timeout) {
+ this.alerts.unshift(alert);
+ var service = this;
+ setTimeout(function() {
+ service.remove(alert.id);
+ }, timeout);
+ if (this.alerts.length >= this.maxAlerts) {
+ this.alerts.length = 3;
+ }
+ return alert.id;
+ };
+
+ return this;
+});
+
+angular.module('cerebro').factory('DataService', function ($rootScope, $timeout, $http, $location) {
+
+ var data = undefined; // current data
+
+ var host = undefined;
+
+ var baseUrl = $location.protocol() + '://' + $location.host() + ':' + $location.port();
+
+ var refresh = function(success, error) {
+ if (host) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/overview',
+ params: {host: host}
+ };
+ $http(config).
+ success(function(response) {
+ data = response;
+ if (success) {
+ success(response);
+ }
+ }).
+ error(function(response) {
+ data = undefined;
+ if (error) {
+ error(response);
+ }
+ });
+ } else {
+ $location.path("/connect");
+ }
+ };
+
+ var autoRefresh = function () {
+ refresh();
+ $timeout(autoRefresh, 3000);
+ };
+
+ this.getData = function() {
+ return data;
+ };
+
+ this.forceRefresh = function() {
+ refresh();
+ };
+
+ this.getHost = function() {
+ return host;
+ };
+
+ this.setHost = function(newHost, success, error) {
+ data = undefined;
+ host = newHost;
+ refresh(success, error);
+ };
+
+ autoRefresh();
+
+ this.closeIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_close',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.openIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_open',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.optimizeIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_optimize',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.refreshIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_refresh',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.clearIndexCache = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_cache/clear',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.deleteIndex = function(index, success, error) {
+ var config = {
+ method: 'DELETE',
+ url: baseUrl + '/apis/' + index + '/_delete',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.getIndexSettings = function(index, success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/' + index + '/_settings',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.getIndexMapping = function(index, success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/' + index + '/_mapping',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.nodeStats = function(node, success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/_nodes/' + node + '/stats',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.enableShardAllocation = function(success, error) {
+ var config = {
+ method: 'PUT',
+ url: baseUrl + '/apis/enable_allocation',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.disableShardAllocation = function(success, error) {
+ var config = {
+ method: 'PUT',
+ url: baseUrl + '/apis/disable_allocation',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.getHosts = function (success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/hosts'
+ };
+ $http(config).success(success).error(error);
+ };
+
+ return this;
+
+});
+
+angular.module('cerebro').factory('ModalService', ['$sce', function ($sce) {
+
+ this.text = undefined;
+ this.confirm = undefined;
+
+ this.info = undefined;
+
+ this.promptConfirmation = function (body, confirmCallback) {
+ this.text = body;
+ this.confirm = confirmCallback;
+ this.info = undefined;
+ };
+
+ this.showInfo = function (info) {
+ this.info = $sce.trustAsHtml(JSON.stringify(info, '', 2));
+ //$scope.body= $sce.trustAsHtml(JSONTree.create(info));
+ this.confirm = undefined;
+ this.text = undefined;
+ };
+
+ return this;
+}]);
+
+angular.module('cerebro').factory('PageService', ['DataService', '$rootScope', '$document',
+ function (DataService, $rootScope, $document) {
+
+ var link = $document[0].querySelector('link[rel~=\'icon\']');
+ var clusterName = undefined;
+ var clusterStatus = undefined;
+
+ if (link) {
+ var faviconUrl = link.href;
+ var img = $document[0].createElement('img');
+ img.src = faviconUrl;
+ }
+
+ $rootScope.$watch(
+ function () {
+ return DataService.getData();
+ },
+ function (data) {
+ if (data) {
+ setPageTitle(data.cluster_name);
+ setFavIconColor(data.status);
+ }
+ }
+ );
+
+ var setPageTitle = function (newClusterName) {
+ if (clusterName !== newClusterName) {
+ if (newClusterName) {
+ clusterName = newClusterName;
+ $rootScope.title = 'cerebro[' + clusterName + ']';
+ } else {
+ clusterName = undefined;
+ $rootScope.title = 'cerebro - no connection';
+ }
+ }
+ };
+
+ var setFavIconColor = function(newClusterStatus) {
+ if (link && clusterStatus !== newClusterStatus) {
+ clusterStatus = newClusterStatus;
+ try {
+ var colors = {green: '#1AC98E', yellow: '#E4D836', red: '#E64759'};
+ var color = clusterStatus ? colors[clusterStatus] : '#222426';
+ var canvas = $document[0].createElement('canvas');
+ canvas.width = 16;
+ canvas.height = 16;
+ var context = canvas.getContext('2d');
+ context.drawImage(img, 0, 0);
+ context.globalCompositeOperation = 'source-in';
+ context.fillStyle = color;
+ context.fillRect(0, 0, 16, 16);
+ context.fill();
+ link.type = 'image/png';
+ link.href = canvas.toDataURL();
+ } catch (exception) {
+ //
+ }
+ }
+ };
+
+ return this;
+
+ }]);
+
+angular.module('cerebro').controller('StatsController', ['$scope', '$http', 'DataService',
+ function ($scope, $http, DataService) {
+
+ $scope.number_of_nodes = undefined;
+
+ $scope.indices = undefined;
+
+ $scope.active_primary_shards = undefined;
+ $scope.active_shards = undefined;
+ $scope.relocating_shards = undefined;
+ $scope.initializing_shards = undefined;
+ $scope.unassigned_shards = undefined;
+ $scope.total_shards = undefined;
+
+ $scope.docs_count = undefined;
+
+ $scope.size_in_bytes = undefined;
+
+ $scope.cluster_name = undefined;
+
+ $scope.$watch(
+ function () {
+ return DataService.getData();
+ },
+ function (data) {
+ if (data) {
+ $scope.number_of_nodes = data.number_of_nodes;
+ $scope.indices = data.indices.length;
+ $scope.active_primary_shards = data.active_primary_shards;
+ $scope.active_shards = data.active_shards;
+ $scope.relocating_shards = data.relocating_shards;
+ $scope.initializing_shards = data.initializing_shards;
+ $scope.unassigned_shards = data.unassigned_shards;
+ $scope.docs_count = data.docs_count;
+ $scope.size_in_bytes = data.size_in_bytes;
+ $scope.cluster_name = data.cluster_name;
+
+ $scope.total_shards = $scope.active_shards +
+ $scope.relocating_shards +
+ $scope.initializing_shards +
+ $scope.unassigned_shards;
+ }
+ }
+ );
+
+ }]);
\ No newline at end of file
diff --git a/public/connect.html b/public/connect.html
new file mode 100644
index 00000000..b72a3c78
--- /dev/null
+++ b/public/connect.html
@@ -0,0 +1,36 @@
+
+
+
+
Welcome to Cerebro
+
+
+
+ Known hosts
+
+
+
+
+
+
+
+ {{host}}
+
+
+
+
+
+
+
+
diff --git a/public/css/app.css b/public/css/app.css
new file mode 100755
index 00000000..0882a6a3
--- /dev/null
+++ b/public/css/app.css
@@ -0,0 +1,382 @@
+html, body {
+ height: 100%;
+}
+body {
+ padding-top: 50px;
+}
+
+.content {
+ padding-top: 20px;
+ padding-bottom: 10px;
+ font-size: 13px;
+ font-weight: 300;
+ height: 100%;
+ min-height: 100%;
+}
+
+.navbar-fixed-top {
+ border: 0;
+}
+
+.main {
+ padding: 20px;
+}
+
+@media (min-width: 768px) {
+ .main {
+ padding-right: 40px;
+ padding-left: 40px;
+ }
+}
+
+.main .page-header {
+ margin-top: 0;
+}
+
+/** Overview **/
+table.shard-map {
+ table-layout: fixed;
+ -webkit-touch-callout: none; /* iOS Safari */
+ -webkit-user-select: none; /* Chrome/Safari/Opera */
+ -khtml-user-select: none; /* Konqueror */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE/Edge */
+ user-select: none; /* non-prefixed version, currently */
+}
+
+@-moz-document url-prefix() {
+ table.shard-map {
+ table-layout: auto;
+ }
+ table.shard-map tr td {
+ width: 16.67%;
+ }
+}
+
+.table.shard-map td, .table th {
+ padding: .4rem !important;
+}
+
+.disabled {
+ opacity: 0.2;
+}
+
+.title {
+ font-weight: 500;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ display: block;
+}
+
+.subtitle {
+ font-size: 11px;
+ font-weight: 400;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ display: block;
+}
+
+.detail {
+ font-size: 10px;
+ font-weight: 300;
+}
+
+/** Navbar **/
+.navbar-red {
+ /*background-color: #222426 !important;*/
+ border-bottom: 5px solid #E64759 !important;
+}
+
+.navbar-yellow {
+ /*background-color: #222426 !important;*/
+ border-bottom: 5px solid #E4D836 !important;
+}
+
+.navbar-green {
+ /*background-color: #222426 !important;*/
+ border-bottom: 5px solid #1AC98E !important;
+}
+.navbar- {
+ border-bottom: 5px solid #55595c !important;
+}
+
+/** Shards **/
+.shard {
+ display: inline-block;
+ width: 22px;
+ height: 22px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 16px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+.shard-started {
+ border: 2px solid #1AC98E;
+ color: #1AC98E;
+}
+
+.shard-initializing {
+ border: 1px solid #1CA8DD;
+ color: #1CA8DD;
+}
+
+.shard-relocated {
+ border: 1px solid #9F85FF;
+ color: #9F85FF;
+}
+
+.shard-recovering {
+ border: 1px solid #E4D836;
+ color: #E4D836;
+}
+
+.shard-unassigned {
+ border: 1px solid #8B8F95;
+ color: #8B8F95;
+}
+
+.shard-replica {
+ border: 1px dashed;
+ opacity: 0.7;
+}
+
+/** Cluster stats **/
+.stats {
+ padding-top: 0px;
+ padding-bottom: 20px;
+}
+
+.stat {
+ border: 1px solid #55595c;
+ text-align: center;
+ width: 100%;
+ display: inline-block;
+ min-height: 32px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ height: auto;
+ line-height: 28px;
+}
+
+.stat-value {
+ font-size: 16px;
+}
+
+.stat-description {
+ font-size: 12px;
+ font-weight: 300;
+}
+
+/** Thin progress bars **/
+.row-condensed {
+ margin-right: -.1875rem !important;
+ margin-left: -.1875rem !important;
+}
+.col-condensed {
+ margin-left: 0px;
+ margin-right: 0px;
+ padding-left: 2px !important;
+ padding-right: 2px !important;
+}
+.progress-thin {
+ height: 2px !important;
+ margin-bottom: 0em !important;
+}
+
+/** Colors **/
+
+.label-details {
+ background-color: #1CA8DD;
+}
+
+/** Forms Inverse **/
+.form-inverse {
+ background-color: #434749 !important;
+ border-color: #4d5154 !important;
+ color: #fff !important;
+}
+.form-inverse:-webkit-input-placeholder { color: white; font-weight: 800; }
+.form-inverse:-moz-placeholder { color: white; }
+.form-inverse:-moz-placeholder { color: white; }
+.form-inverse:-ms-input-placeholder { color: white; }
+
+/** Nodes **/
+.node-badges {
+ width: 20px;
+ display: inline-block;
+ float: left;
+}
+.node-info {
+ margin-left: 20px;
+}
+
+.normal-action {
+ cursor: pointer;
+}
+
+.bordered {
+ border: 1px solid #ccc;
+}
+.pgnt-info {
+ text-align: center;
+ width: 100%;
+ display: block;
+ line-height: 20px;
+ vertical-align: middle;
+ height: 20px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.pgnt-btn {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ display: block;
+ font-size: 12px;
+ font-weight: 300;
+ height: 20px;
+ line-height: 18px;
+ text-align: center;
+ width: 29px;
+}
+.inactive-action {
+ color: #8B8F95;
+}
+.form-element {
+ margin-bottom: 10px;
+}
+.inline-checkbox {
+ margin-top: 5px;
+}
+.page-ctrl {
+ margin-top: 8px;
+ margin-bottom: 5px;
+}
+.table-control {
+ line-height: 50px !important;
+}
+.node-labels {
+ padding-top: 5px;
+}
+.dropdown-menu {
+ color: #fff !important;
+ background-color: #373a3c !important;
+ font-size: 12px !important;
+ font-weight: 300;
+}
+.dropdown-item {
+ color: #fff !important;
+}
+.dropdown-item:hover {
+ color: #373a3c !important;
+}
+
+.red {
+ color: #E64759 !important;
+}
+
+.yellow {
+ color: #E4D836 !important;
+}
+
+.green {
+ color: #1AC98E !important;
+}
+.blue {
+ color: #1CA8DD !important;
+}
+.alerts {
+ padding-top: 40px;
+ position: fixed;
+ padding-left: 50px;
+ right: 25px;
+ width: 50%;
+ top: 30px;
+ z-index: 1000000;
+ min-width: 400px;
+}
+.alert-block {
+ font-size: 12px;
+ font-weight: 300;
+ padding-top: 10px;
+ padding-bottom: 0px;
+ text-align: left;
+ opacity: 0.90;
+}
+
+.alert {
+ margin-bottom: 0px;
+ padding-top: 6px;
+ padding-bottom: 6px;
+ background: #434749;
+ border: 1px solid #4d5154 !important;
+}
+.modal-dialog {
+ margin-top: 120px !important;
+}
+.modal-content {
+ background: #373a3c !important;
+ border: 1px solid #434749 !important;
+ color: #fff;
+}
+.modal-body {
+ color: #fff;
+ font-size: 13px !important;
+}
+.modal-footer {
+ border: none !important;
+}
+.modal-header {
+ border: none !important;
+}
+.btn {
+ background: #434749 !important;
+ border: 2px solid !important;
+ font-size: 13px !important;
+ opacity: 0.7 !important;
+}
+.btn:hover {
+ opacity: 1 !important;
+}
+.btn-default {
+ color: #8B8F95 !important;
+ border-color: #8B8F95 !important;
+}
+.btn-default {
+ color: #8B8F95 !important;
+ border-color: #8B8F95 !important;
+}
+.btn-primary {
+ color: #1AC98E !important;
+ border-color: #1AC98E !important;
+}
+.nav-element {
+ display: block;
+ padding-top: .425rem;
+ padding-bottom: .425rem;
+}
+.table-header {
+ font-size: 15px;
+ font-weight: 400;
+}
+.connect-page {
+ display: table-cell;
+ vertical-align: middle;
+ float: none;
+}
+
+.navbar-dark .navbar-nav .nav-link {
+ font-weight: 300 !important;
+}
diff --git a/public/css/lib.css b/public/css/lib.css
new file mode 100644
index 00000000..e69de29b
diff --git a/public/img/favicon.png b/public/img/favicon.png
new file mode 100644
index 00000000..c7d92d2a
Binary files /dev/null and b/public/img/favicon.png differ
diff --git a/public/info.html b/public/info.html
new file mode 100644
index 00000000..c51fc547
--- /dev/null
+++ b/public/info.html
@@ -0,0 +1,13 @@
+
diff --git a/public/lib.js b/public/lib.js
new file mode 100644
index 00000000..e69de29b
diff --git a/public/modal.html b/public/modal.html
new file mode 100644
index 00000000..42595782
--- /dev/null
+++ b/public/modal.html
@@ -0,0 +1,19 @@
+
+
+
+
+
{{service.text}}
+
{{service.info}}
+
+
+
+
diff --git a/public/navbar.html b/public/navbar.html
new file mode 100644
index 00000000..b2a5076f
--- /dev/null
+++ b/public/navbar.html
@@ -0,0 +1,28 @@
+
+ CEREBRO
+
+
+
+ overview
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Not connected
+
+
+ {{host}}
+
+
+
+
+
diff --git a/public/overview.html b/public/overview.html
new file mode 100644
index 00000000..c33d663a
--- /dev/null
+++ b/public/overview.html
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{index.name}}
+
+
+
+
+
+ {{index.aliases[0]}}
+
+
+
+
+ shards: {{index.num_shards}} * {{index.num_replicas}} |
+ docs: {{index.doc_count | number}} |
+ size: {{index.size_in_bytes | bytes}}
+
+
+
+
+
+
+
+
+
+
+
+ {{unassigned_shards}} unassigned shards
+
+
+ show only unhealthy indices
+ show all indices
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{node.name}}
+
+
+
{{node.host}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JVM: {{node.jvm_version}}
+ ES: {{node.es_version}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/pagination.html b/public/pagination.html
new file mode 100644
index 00000000..c95de1bb
--- /dev/null
+++ b/public/pagination.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{page.first | number:0}}-{{page.last | number:0}} of {{page.total | number:0}} {{label || ''}}
+
+
\ No newline at end of file
diff --git a/public/stats.html b/public/stats.html
new file mode 100644
index 00000000..aab77950
--- /dev/null
+++ b/public/stats.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+ {{cluster_name}}
+
+
+
+
+
+
+ {{number_of_nodes | number:0}}
+
+
+ nodes
+
+
+
+
+
+
+ {{indices | number:0}}
+
+
+ indices
+
+
+
+
+
+
+ {{total_shards | number:0}}
+
+
+ shards
+
+
+
+
+
+
+ {{docs_count | number:0}}
+
+
+ docs
+
+
+
+
+
+
+ {{size_in_bytes | bytes}}
+
+
+
+
+
+
+
diff --git a/src/controllers/alerts.js b/src/controllers/alerts.js
new file mode 100644
index 00000000..e0fd3b80
--- /dev/null
+++ b/src/controllers/alerts.js
@@ -0,0 +1,21 @@
+angular.module('cerebro').controller('AlertsController', ['$scope', 'AlertService',
+ function($scope, AlertService) {
+
+ $scope.alerts = [];
+
+ $scope.$watch(
+ function() {
+ return AlertService.alerts;
+ },
+ function(newValue, oldValue) {
+ $scope.alerts = AlertService.alerts;
+ }
+ );
+
+ $scope.remove = function(id) {
+ AlertService.remove(id);
+ };
+
+ }
+
+]);
diff --git a/src/controllers/connect.js b/src/controllers/connect.js
new file mode 100644
index 00000000..364a2e2e
--- /dev/null
+++ b/src/controllers/connect.js
@@ -0,0 +1,37 @@
+angular.module('cerebro').controller('ConnectController', [
+ '$scope', '$location', 'DataService', 'AlertService',
+ function($scope, $location, DataService, AlertService) {
+
+ $scope.hosts = undefined;
+
+ $scope.connecting = false;
+
+ $scope.host = undefined;
+
+ DataService.getHosts(
+ function(hosts) {
+ $scope.hosts = hosts;
+ },
+ function(error) {
+
+ }
+ );
+
+ $scope.connect = function(host) {
+ if (host) {
+ $scope.connecting = true;
+ DataService.setHost(
+ host,
+ function(response) {
+ $location.path("/overview");
+ $scope.host = DataService.getHost();
+ },
+ function(response) {
+ $scope.connecting = false;
+ AlertService.error("Error connecting to " + host, response);
+ }
+ );
+ }
+ };
+
+ }]);
diff --git a/src/controllers/modal.js b/src/controllers/modal.js
new file mode 100644
index 00000000..52ab9c71
--- /dev/null
+++ b/src/controllers/modal.js
@@ -0,0 +1,15 @@
+angular.module('cerebro').controller('ModalController', ['$scope', 'ModalService',
+ function($scope, ModalService) {
+
+ $scope.service = ModalService;
+
+ $scope.close = function() {
+ $scope.service.close();
+ };
+
+ $scope.confirm = function() {
+ $scope.service.confirm();
+ };
+
+ }
+]);
diff --git a/src/controllers/navbar.js b/src/controllers/navbar.js
new file mode 100644
index 00000000..4a9fd36b
--- /dev/null
+++ b/src/controllers/navbar.js
@@ -0,0 +1,25 @@
+angular.module('cerebro').controller('NavbarController', ['PageService', '$scope', '$http', 'DataService',
+ function (PageService, $scope, $http, DataService) {
+
+ $scope.status = undefined;
+ $scope.cluster_name = undefined;
+ $scope.host = undefined;
+
+ $scope.$watch(
+ function () {
+ return DataService.getData();
+ },
+ function (data) {
+ if (data) {
+ $scope.status = data.status;
+ $scope.cluster_name = data.cluster_name;
+ $scope.host = DataService.getHost();
+ } else {
+ $scope.status = undefined;
+ $scope.cluster_name = undefined;
+ $scope.host = undefined;
+ }
+ }
+ );
+
+ }]);
diff --git a/src/controllers/overview.js b/src/controllers/overview.js
new file mode 100644
index 00000000..8aabaa53
--- /dev/null
+++ b/src/controllers/overview.js
@@ -0,0 +1,232 @@
+angular.module('cerebro').controller('OverviewController', ['$scope', '$http', '$window', 'DataService', 'AlertService', 'ModalService',
+ function ($scope, $http, $window, DataService, AlertService, ModalService) {
+
+ $scope.indices = undefined;
+ $scope.nodes = undefined;
+ $scope.unassigned_shards = 0;
+ $scope.indices_filter = new IndexFilter('', true, false, true, true, 0);
+ $scope.nodes_filter = new NodeFilter('', true, false, false, 0);
+ $scope.closed_indices = 0;
+ $scope.special_indices = 0;
+ $scope.expandedView = false;
+ $scope.shardAllocation = true;
+
+ $scope.getPageSize = function() {
+ return Math.max(Math.round($window.innerWidth / 280), 1);
+ };
+
+ $scope.paginator = new Paginator(1, $scope.getPageSize(), [], $scope.indices_filter);
+
+ $scope.page = $scope.paginator.getPage();
+
+ $($window).resize(function() {
+ $scope.$apply(function() {
+ $scope.paginator.setPageSize($scope.getPageSize());
+ });
+ });
+
+ $scope.$watch(
+ function() {
+ return DataService.getData();
+ },
+ function(data) {
+ if (data) {
+ $scope.setIndices(data.indices);
+ $scope.setNodes(data.nodes);
+ $scope.unassigned_shards = data.unassigned_shards;
+ $scope.closed_indices = data.closed_indices;
+ $scope.special_indices = data.special_indices;
+ $scope.shardAllocation = data.shard_allocation;
+ } else {
+ $scope.indices = undefined;
+ $scope.nodes = undefined;
+ }
+ }
+ );
+
+ $scope.$watch('paginator', function() {
+ if (DataService.getData()) {
+ $scope.setIndices(DataService.getData().indices);
+ }
+ }, true);
+
+ $scope.setIndices = function(indices) {
+ $scope.paginator.setCollection(indices);
+ $scope.page = $scope.paginator.getPage();
+ };
+
+ $scope.$watch('nodes_filter', function() {
+ if (DataService.getData()) {
+ $scope.setNodes(DataService.getData().nodes);
+ }
+ },
+ true);
+
+ $scope.setNodes = function(nodes) {
+ $scope.nodes = nodes.filter(function(node) {
+ return $scope.nodes_filter.matches(node);
+ });
+ };
+
+ var success = function(data) {
+ DataService.forceRefresh();
+ AlertService.success('Operation successfully executed', data);
+ };
+
+ var error = function(data) {
+ AlertService.error('Operation failed', data);
+ };
+
+ var displayInfo = function(info) {
+ ModalService.showInfo(info);
+ };
+
+ $scope.openIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Open ' + index + '?',
+ function() {
+ DataService.openIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.closeIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Close ' + index + '?',
+ function() {
+ DataService.closeIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.deleteIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Delete ' + index + '?',
+ function() {
+ DataService.deleteIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.clearIndexCache = function(index) {
+ ModalService.promptConfirmation(
+ 'Clear ' + index + ' cache?',
+ function() {
+ DataService.clearIndexCache(index, success, error);
+ }
+ );
+ };
+
+ $scope.refreshIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Refresh index ' + index + '?',
+ function() {
+ DataService.refreshIndex(index, success, error);
+ }
+ );
+ };
+
+ $scope.optimizeIndex = function(index) {
+ ModalService.promptConfirmation(
+ 'Optimize index ' + index + '?',
+ function() {
+ DataService.optimizeIndex(index, success, error);
+ }
+ );
+ };
+
+ // Mass actions
+
+ $scope.closeIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Close all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.closeIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.openIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Open all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.openIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.optimizeIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Optimize all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.optimizeIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.refreshIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Refresh all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.refreshIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.clearIndicesCache = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Clear all ' + indices.length + ' selected indices cache?',
+ function() {
+ DataService.clearIndexCache(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.deleteIndices = function() {
+ var indices = $scope.paginator.getResults().map(function(index) {
+ return index.name;
+ });
+ ModalService.promptConfirmation(
+ 'Delete all ' + indices.length + ' selected indices?',
+ function() {
+ DataService.deleteIndex(indices.join(","), success, error);
+ }
+ );
+ };
+
+ $scope.nodeStats = function(node) {
+ DataService.nodeStats(node, displayInfo, error);
+ };
+
+ $scope.getIndexSettings = function (index) {
+ DataService.getIndexSettings(index, displayInfo, error);
+ };
+
+ $scope.getIndexMapping = function (index) {
+ DataService.getIndexMapping(index, displayInfo, error);
+ };
+
+ $scope.disableShardAllocation = function () {
+ DataService.disableShardAllocation(success, error);
+ };
+
+ $scope.enableShardAllocation = function () {
+ DataService.enableShardAllocation(success, error);
+ };
+
+ }]);
diff --git a/src/directives/pagination.js b/src/directives/pagination.js
new file mode 100644
index 00000000..44ee6e48
--- /dev/null
+++ b/src/directives/pagination.js
@@ -0,0 +1,128 @@
+angular.module('cerebro').directive('ngPagination', ['$document', function($document) {
+
+ return {
+ scope: {
+ paginator: '=paginator',
+ page: '=page',
+ label: '=label'
+ },
+ templateUrl: 'pagination.html',
+ link: function(scope, element, attrs) {
+ var handler = function(event) {
+ var $target = $(event.target);
+ if ($target.is('input, textarea')) {
+ return;
+ }
+ if (event.keyCode == 39 && scope.page.next) {
+ scope.$apply(function() {
+ scope.paginator.nextPage();
+ event.preventDefault();
+ });
+ }
+ if (event.keyCode == 37 && scope.page.previous) {
+ scope.$apply(function() {
+ scope.paginator.previousPage();
+ event.preventDefault();
+ });
+ }
+ };
+
+ $document.bind('keydown', handler);
+ element.on('$destroy', function() {
+ $document.unbind('keydown', handler);
+ });
+ }
+ };
+}]);
+
+function Paginator(page, pageSize, collection, filter) {
+
+ this.filter = filter;
+
+ this.page = page;
+
+ this.pageSize = pageSize;
+
+ this.$collection = collection ? collection : [];
+
+ this.nextPage = function() {
+ this.page += 1;
+ };
+
+ this.previousPage = function() {
+ this.page -= 1;
+ };
+
+ this.setPageSize = function(newSize) {
+ this.pageSize = newSize;
+ };
+
+ this.getPageSize = function() {
+ return this.pageSize;
+ };
+
+ this.getCurrentPage = function() {
+ return this.page;
+ };
+
+ this.getPage = function() {
+ var results = this.getResults();
+ var total = results.length;
+
+ var first = total > 0 ? ((this.page - 1) * this.pageSize) + 1 : 0;
+ while (total < first) {
+ this.previousPage();
+ first = (this.page - 1) * this.pageSize + 1;
+ }
+ var lastPage = this.page * this.pageSize > total;
+ var last = lastPage ? total : this.page * this.pageSize;
+
+ var elements = total > 0 ? results.slice(first - 1, last) : [];
+
+ var next = this.pageSize * this.page < total;
+ var previous = this.page > 1;
+ while (elements.length < this.pageSize) {
+ elements.push(null);
+ }
+ return new Page(elements, total, first, last, next, previous);
+ };
+
+ this.setCollection = function(collection) {
+ if (this.filter.getSorting()) {
+ this.$collection = collection.sort(this.filter.getSorting());
+ } else {
+ this.$collection = collection;
+ }
+ };
+
+ this.getResults = function() {
+ var filter = this.filter;
+ var collection = this.$collection;
+ if (filter.isBlank()) {
+ return collection;
+ } else {
+ var filtered = [];
+ collection.forEach(function(item) {
+ if (filter.matches(item)) {
+ filtered.push(item);
+ }
+ });
+ return filtered;
+ }
+ };
+
+ this.getCollection = function() {
+ return this.$collection;
+ };
+
+}
+
+function Page(elements, total, first, last, next, previous) {
+ this.elements = elements;
+ this.total = total;
+ this.first = first;
+ this.last = last;
+ this.next = next;
+ this.previous = previous;
+}
+
diff --git a/src/directives/progress.js b/src/directives/progress.js
new file mode 100644
index 00000000..075bdb42
--- /dev/null
+++ b/src/directives/progress.js
@@ -0,0 +1,19 @@
+angular.module('cerebro').directive('ngProgress',
+ function () {
+
+ return {
+ scope: {
+ value: '=value',
+ max: '=max',
+ text: '=text'
+ },
+ template: function (elem, attrs) {
+ return '{{text}} ' +
+ ' 0.75}}}">' +
+ '{{value}}%' +
+ ' '
+ }
+ };
+ }
+);
diff --git a/src/directives/shard.js b/src/directives/shard.js
new file mode 100644
index 00000000..16be5f2b
--- /dev/null
+++ b/src/directives/shard.js
@@ -0,0 +1,15 @@
+angular.module('cerebro').directive('ngShard',
+ function () {
+
+ return {
+ scope: {
+ shard: '=shard'
+ },
+ template: function (elem, attrs) {
+ return '' +
+ '{{shard.shard}} ' +
+ ' ';
+ }
+ };
+ }
+);
diff --git a/src/filters/bytes.js b/src/filters/bytes.js
new file mode 100644
index 00000000..94d0d8c2
--- /dev/null
+++ b/src/filters/bytes.js
@@ -0,0 +1,18 @@
+angular.module('cerebro').filter('bytes', function() {
+
+ var UNITS = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];
+
+ function stringify(bytes) {
+ if (bytes > 0) {
+ var e = Math.floor(Math.log(bytes) / Math.log(1024));
+ return (bytes / Math.pow(1024, e)).toFixed(2) + UNITS[e];
+ } else {
+ return 0 + UNITS[0];
+ }
+ }
+
+ return function(bytes) {
+ return stringify(bytes);
+ };
+
+});
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 00000000..476b777b
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,15 @@
+'use strict';
+
+angular.module('cerebro', ['ngRoute']).config(['$routeProvider',
+ function($routeProvider) {
+ $routeProvider.
+ when('/overview', {
+ templateUrl: 'overview.html',
+ controller: 'OverviewController'
+ }).
+ when('/connect', {
+ templateUrl: 'connect.html',
+ controller: 'ConnectController'
+ }).
+ otherwise({redirectTo: '/connect'});
+ }]);
diff --git a/src/overview/index_filter.js b/src/overview/index_filter.js
new file mode 100644
index 00000000..2931cd02
--- /dev/null
+++ b/src/overview/index_filter.js
@@ -0,0 +1,99 @@
+function IndexFilter(name, closed, special, healthy, asc, timestamp) {
+ this.name = name;
+ this.closed = closed;
+ this.special = special;
+ this.healthy = healthy;
+ this.sort = 'name';
+ this.asc = asc;
+ this.timestamp = timestamp;
+
+ this.getSorting = function() {
+ var asc = this.asc;
+ switch (this.sort) {
+ case 'name':
+ return function(a, b) {
+ if (asc) {
+ return a.name.localeCompare(b.name);
+ } else {
+ return b.name.localeCompare(a.name);
+ }
+ };
+ default:
+ return undefined;
+ }
+ };
+
+ this.clone = function() {
+ return new IndexFilter(
+ this.name,
+ this.closed,
+ this.special,
+ this.healthy,
+ this.asc,
+ this.timestamp
+ );
+ };
+
+ this.equals = function(other) {
+ return (
+ other !== null &&
+ this.name === other.name &&
+ this.closed === other.closed &&
+ this.special === other.special &&
+ this.healthy === other.healthy &&
+ this.asc === other.asc &&
+ this.timestamp === other.timestamp
+ );
+ };
+
+ this.isBlank = function() {
+ return (
+ !this.name &&
+ this.closed &&
+ this.special &&
+ this.healthy &&
+ this.asc
+ );
+ };
+
+ this.matches = function(index) {
+ var matches = true;
+ if (!this.special && index.special) {
+ matches = false;
+ }
+ if (!this.closed && index.closed) {
+ matches = false;
+ }
+ // Hide healthy == show unhealthy only
+ if (!this.healthy && !index.unhealthy) {
+ matches = false;
+ }
+ if (matches && this.name) {
+ try {
+ var regExp = new RegExp(this.name.trim(), 'i');
+ matches = regExp.test(index.name);
+ if (!matches && index.aliases) {
+ for (var idx = 0; idx < index.aliases.length; idx++) {
+ if ((matches = regExp.test(index.aliases[idx]))) {
+ break;
+ }
+ }
+ }
+ }
+ catch (err) { // if not valid regexp, still try normal matching
+ matches = index.name.indexOf(this.name.toLowerCase()) != -1;
+ if (!matches) {
+ for (var idx = 0; idx < index.aliases.length; idx++) {
+ var alias = index.aliases[idx].toLowerCase();
+ matches = true;
+ if ((matches = (alias.indexOf(this.name.toLowerCase()) != -1))) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return matches;
+ };
+
+}
diff --git a/src/overview/node_filter.js b/src/overview/node_filter.js
new file mode 100644
index 00000000..4d2628f4
--- /dev/null
+++ b/src/overview/node_filter.js
@@ -0,0 +1,55 @@
+function NodeFilter(name, data, master, client, timestamp) {
+ this.name = name;
+ this.data = data;
+ this.master = master;
+ this.client = client;
+ this.timestamp = timestamp;
+
+ this.clone = function() {
+ return new NodeFilter(this.name, this.data, this.master, this.client);
+ };
+
+ this.getSorting = function() {
+ return undefined;
+ };
+
+ this.equals = function(other) {
+ return (
+ other !== null &&
+ this.name == other.name &&
+ this.data == other.data &&
+ this.master == other.master &&
+ this.client == other.client &&
+ this.timestamp == other.timestamp
+ );
+ };
+
+ this.isBlank = function() {
+ return !this.name && (this.data && this.master && this.client);
+ };
+
+ this.matches = function(node) {
+ if (this.isBlank()) {
+ return true;
+ } else {
+ return this.matchesName(node.name) && this.matchesType(node);
+ }
+ };
+
+ this.matchesType = function(node) {
+ return (
+ node.data && this.data ||
+ node.master && this.master ||
+ node.client && this.client
+ );
+ };
+
+ this.matchesName = function(name) {
+ if (this.name) {
+ return name.toLowerCase().indexOf(this.name.toLowerCase()) != -1;
+ } else {
+ return true;
+ }
+ };
+
+}
diff --git a/src/services/alerts.js b/src/services/alerts.js
new file mode 100644
index 00000000..146d7cba
--- /dev/null
+++ b/src/services/alerts.js
@@ -0,0 +1,83 @@
+var Alert = function(message, response, level, _class, icon) {
+ var currentDate = new Date();
+ this.message = message;
+ this.response = response;
+ this.level = level;
+ this.class = _class;
+ this.icon = icon;
+ this.timestamp = currentDate;
+ this.id = 'alert_box_' + currentDate.getTime();
+
+ this.hasResponse = function() {
+ return this.response;
+ };
+
+ this.getResponse = function() {
+ if (this.response) {
+ return JSON.stringify(this.response, undefined, 2);
+ }
+ };
+};
+
+angular.module('cerebro').factory('AlertService', function() {
+ this.maxAlerts = 3;
+
+ this.alerts = [];
+
+ // removes ALL alerts
+ this.clear = function() {
+ this.alerts.length = 0;
+ };
+
+ // remove a particular alert message
+ this.remove = function(id) {
+ $('#' + id).fadeTo(1000, 0).slideUp(200, function() {
+ $(this).remove();
+ });
+ this.alerts = this.alerts.filter(function(a) {
+ return id != a.id;
+ });
+ };
+
+ // creates an error alert
+ this.error = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 7500;
+ var alert = new Alert(msg, resp, 'error', 'red', 'fa fa-warning');
+ return this.addAlert(alert, timeout);
+ };
+
+ // creates an info alert
+ this.info = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 2500;
+ var alert = new Alert(msg, resp, 'info', 'blue', 'fa fa-info');
+ return this.addAlert(alert, timeout);
+ };
+
+ // creates success alert
+ this.success = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 2500;
+ var alert = new Alert(msg, resp, 'success', 'green', 'fa fa-check');
+ return this.addAlert(alert, timeout);
+ };
+
+ // creates a warn alert
+ this.warn = function(msg, resp, timeout) {
+ timeout = timeout ? timeout : 5000;
+ var alert = new Alert(msg, resp, 'warn', 'yellow', 'fa fa-info');
+ return this.addAlert(alert, timeout);
+ };
+
+ this.addAlert = function(alert, timeout) {
+ this.alerts.unshift(alert);
+ var service = this;
+ setTimeout(function() {
+ service.remove(alert.id);
+ }, timeout);
+ if (this.alerts.length >= this.maxAlerts) {
+ this.alerts.length = 3;
+ }
+ return alert.id;
+ };
+
+ return this;
+});
diff --git a/src/services/data.js b/src/services/data.js
new file mode 100644
index 00000000..0d616775
--- /dev/null
+++ b/src/services/data.js
@@ -0,0 +1,190 @@
+angular.module('cerebro').factory('DataService', function ($rootScope, $timeout, $http, $location) {
+
+ var data = undefined; // current data
+
+ var host = undefined;
+
+ var baseUrl = $location.protocol() + '://' + $location.host() + ':' + $location.port();
+
+ var refresh = function(success, error) {
+ if (host) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/overview',
+ params: {host: host}
+ };
+ $http(config).
+ success(function(response) {
+ data = response;
+ if (success) {
+ success(response);
+ }
+ }).
+ error(function(response) {
+ data = undefined;
+ if (error) {
+ error(response);
+ }
+ });
+ } else {
+ $location.path("/connect");
+ }
+ };
+
+ var autoRefresh = function () {
+ refresh();
+ $timeout(autoRefresh, 3000);
+ };
+
+ this.getData = function() {
+ return data;
+ };
+
+ this.forceRefresh = function() {
+ refresh();
+ };
+
+ this.getHost = function() {
+ return host;
+ };
+
+ this.setHost = function(newHost, success, error) {
+ data = undefined;
+ host = newHost;
+ refresh(success, error);
+ };
+
+ autoRefresh();
+
+ this.closeIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_close',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.openIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_open',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.optimizeIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_optimize',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.refreshIndex = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_refresh',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.clearIndexCache = function(index, success, error) {
+ var config = {
+ method: 'POST',
+ url: baseUrl + '/apis/' + index + '/_cache/clear',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.deleteIndex = function(index, success, error) {
+ var config = {
+ method: 'DELETE',
+ url: baseUrl + '/apis/' + index + '/_delete',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.getIndexSettings = function(index, success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/' + index + '/_settings',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.getIndexMapping = function(index, success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/' + index + '/_mapping',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.nodeStats = function(node, success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/_nodes/' + node + '/stats',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.enableShardAllocation = function(success, error) {
+ var config = {
+ method: 'PUT',
+ url: baseUrl + '/apis/enable_allocation',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.disableShardAllocation = function(success, error) {
+ var config = {
+ method: 'PUT',
+ url: baseUrl + '/apis/disable_allocation',
+ params: {host: host}
+ };
+ $http(config).
+ success(success).
+ error(error);
+ };
+
+ this.getHosts = function (success, error) {
+ var config = {
+ method: 'GET',
+ url: baseUrl + '/apis/hosts'
+ };
+ $http(config).success(success).error(error);
+ };
+
+ return this;
+
+});
diff --git a/src/services/modal.js b/src/services/modal.js
new file mode 100644
index 00000000..1d02fe70
--- /dev/null
+++ b/src/services/modal.js
@@ -0,0 +1,22 @@
+angular.module('cerebro').factory('ModalService', ['$sce', function ($sce) {
+
+ this.text = undefined;
+ this.confirm = undefined;
+
+ this.info = undefined;
+
+ this.promptConfirmation = function (body, confirmCallback) {
+ this.text = body;
+ this.confirm = confirmCallback;
+ this.info = undefined;
+ };
+
+ this.showInfo = function (info) {
+ this.info = $sce.trustAsHtml(JSON.stringify(info, '', 2));
+ //$scope.body= $sce.trustAsHtml(JSONTree.create(info));
+ this.confirm = undefined;
+ this.text = undefined;
+ };
+
+ return this;
+}]);
diff --git a/src/services/page.js b/src/services/page.js
new file mode 100644
index 00000000..4a167c23
--- /dev/null
+++ b/src/services/page.js
@@ -0,0 +1,63 @@
+angular.module('cerebro').factory('PageService', ['DataService', '$rootScope', '$document',
+ function (DataService, $rootScope, $document) {
+
+ var link = $document[0].querySelector('link[rel~=\'icon\']');
+ var clusterName = undefined;
+ var clusterStatus = undefined;
+
+ if (link) {
+ var faviconUrl = link.href;
+ var img = $document[0].createElement('img');
+ img.src = faviconUrl;
+ }
+
+ $rootScope.$watch(
+ function () {
+ return DataService.getData();
+ },
+ function (data) {
+ if (data) {
+ setPageTitle(data.cluster_name);
+ setFavIconColor(data.status);
+ }
+ }
+ );
+
+ var setPageTitle = function (newClusterName) {
+ if (clusterName !== newClusterName) {
+ if (newClusterName) {
+ clusterName = newClusterName;
+ $rootScope.title = 'cerebro[' + clusterName + ']';
+ } else {
+ clusterName = undefined;
+ $rootScope.title = 'cerebro - no connection';
+ }
+ }
+ };
+
+ var setFavIconColor = function(newClusterStatus) {
+ if (link && clusterStatus !== newClusterStatus) {
+ clusterStatus = newClusterStatus;
+ try {
+ var colors = {green: '#1AC98E', yellow: '#E4D836', red: '#E64759'};
+ var color = clusterStatus ? colors[clusterStatus] : '#222426';
+ var canvas = $document[0].createElement('canvas');
+ canvas.width = 16;
+ canvas.height = 16;
+ var context = canvas.getContext('2d');
+ context.drawImage(img, 0, 0);
+ context.globalCompositeOperation = 'source-in';
+ context.fillStyle = color;
+ context.fillRect(0, 0, 16, 16);
+ context.fill();
+ link.type = 'image/png';
+ link.href = canvas.toDataURL();
+ } catch (exception) {
+ //
+ }
+ }
+ };
+
+ return this;
+
+ }]);
diff --git a/src/stats/stats.js b/src/stats/stats.js
new file mode 100644
index 00000000..bfd7e1c6
--- /dev/null
+++ b/src/stats/stats.js
@@ -0,0 +1,46 @@
+angular.module('cerebro').controller('StatsController', ['$scope', '$http', 'DataService',
+ function ($scope, $http, DataService) {
+
+ $scope.number_of_nodes = undefined;
+
+ $scope.indices = undefined;
+
+ $scope.active_primary_shards = undefined;
+ $scope.active_shards = undefined;
+ $scope.relocating_shards = undefined;
+ $scope.initializing_shards = undefined;
+ $scope.unassigned_shards = undefined;
+ $scope.total_shards = undefined;
+
+ $scope.docs_count = undefined;
+
+ $scope.size_in_bytes = undefined;
+
+ $scope.cluster_name = undefined;
+
+ $scope.$watch(
+ function () {
+ return DataService.getData();
+ },
+ function (data) {
+ if (data) {
+ $scope.number_of_nodes = data.number_of_nodes;
+ $scope.indices = data.indices.length;
+ $scope.active_primary_shards = data.active_primary_shards;
+ $scope.active_shards = data.active_shards;
+ $scope.relocating_shards = data.relocating_shards;
+ $scope.initializing_shards = data.initializing_shards;
+ $scope.unassigned_shards = data.unassigned_shards;
+ $scope.docs_count = data.docs_count;
+ $scope.size_in_bytes = data.size_in_bytes;
+ $scope.cluster_name = data.cluster_name;
+
+ $scope.total_shards = $scope.active_shards +
+ $scope.relocating_shards +
+ $scope.initializing_shards +
+ $scope.unassigned_shards;
+ }
+ }
+ );
+
+ }]);
\ No newline at end of file
diff --git a/test/controllers/ClusterOverviewControllerSpec.scala b/test/controllers/ClusterOverviewControllerSpec.scala
new file mode 100644
index 00000000..50276382
--- /dev/null
+++ b/test/controllers/ClusterOverviewControllerSpec.scala
@@ -0,0 +1,21 @@
+package controllers
+
+import models.overview.ClusterInitializingShards
+import org.specs2.Specification
+
+class ClusterOverviewControllerSpec extends Specification {
+
+ def is =
+ s2"""
+ ClusterOverviewController should
+
+ return cluster_name $clusterName
+ """
+
+ def clusterName = {
+ (clusterWithoutData \ "cluster_name").as[String] mustEqual "elasticsearch"
+ (clusterWithData \ "cluster_name").as[String] mustEqual "elasticsearch"
+ (clusterInitializing \ "cluster_name").as[String] mustEqual "elasticsearch"
+ (clusterRelocating \ "cluster_name").as[String] mustEqual "elasticsearch"
+ }
+}
diff --git a/test/models/overview/ClusterDisabledAllocation.scala b/test/models/overview/ClusterDisabledAllocation.scala
new file mode 100644
index 00000000..4801bb42
--- /dev/null
+++ b/test/models/overview/ClusterDisabledAllocation.scala
@@ -0,0 +1,24 @@
+package models.overview
+
+import play.api.libs.json.Json
+
+object ClusterDisabledAllocation extends ClusterWithData {
+
+ override val clusterSettings = Json.parse(
+ """
+ |{
+ | "persistent" : { },
+ | "transient" : {
+ | "cluster" : {
+ | "routing" : {
+ | "allocation" : {
+ | "enable" : "none"
+ | }
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+}
diff --git a/test/models/overview/ClusterInitializingShards.scala b/test/models/overview/ClusterInitializingShards.scala
new file mode 100644
index 00000000..cb2d696f
--- /dev/null
+++ b/test/models/overview/ClusterInitializingShards.scala
@@ -0,0 +1,721 @@
+package models.overview
+
+import play.api.libs.json.Json
+
+object ClusterInitializingShards {
+
+ def apply() = new ClusterOverview(clusterState, nodesStats, indicesStats, clusterSettings, aliases, clusterHealth, nodes, main)
+
+ val clusterState = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "master_node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "blocks" : { },
+ | "routing_table" : {
+ | "indices" : {
+ | "hello" : {
+ | "shards" : {
+ | "1" : [ {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "rNdtAPz_RhKVBp6dpAH1cw"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "hlwc94lZRvOoBoaxyEWIGg"
+ | }
+ | } ],
+ | "4" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 10,
+ | "allocation_id" : {
+ | "id" : "Kyne0gDVQEasq9VxUUsxbg"
+ | }
+ | }, {
+ | "state" : "UNASSIGNED",
+ | "primary" : false,
+ | "node" : null,
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 10,
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | } ],
+ | "2" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 15,
+ | "allocation_id" : {
+ | "id" : "rN62kibSRZq0RxcwxEHKKw"
+ | }
+ | }, {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 15,
+ | "allocation_id" : {
+ | "id" : "2G3Hs3CnT5uvhpeOmHZyYg"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | } ],
+ | "3" : [ {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 11,
+ | "allocation_id" : {
+ | "id" : "NhG91IW6RCW1KAbSx67O9g"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 11,
+ | "allocation_id" : {
+ | "id" : "b4Gdtk7uTuSINaZ_YdaJdg"
+ | }
+ | } ],
+ | "0" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 17,
+ | "allocation_id" : {
+ | "id" : "13mrI6FhRjGEk7xG7xYJvg"
+ | }
+ | }, {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 17,
+ | "allocation_id" : {
+ | "id" : "FbfzrPiySEaOzGMRZRDf7w"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | } ]
+ | }
+ | }
+ | }
+ | },
+ | "routing_nodes" : {
+ | "unassigned" : [ {
+ | "state" : "UNASSIGNED",
+ | "primary" : false,
+ | "node" : null,
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 10,
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | } ],
+ | "nodes" : {
+ | "VOiMU2k5SuStH3-X1uuBGw" : [ {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "rNdtAPz_RhKVBp6dpAH1cw"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 15,
+ | "allocation_id" : {
+ | "id" : "rN62kibSRZq0RxcwxEHKKw"
+ | }
+ | }, {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 11,
+ | "allocation_id" : {
+ | "id" : "NhG91IW6RCW1KAbSx67O9g"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 17,
+ | "allocation_id" : {
+ | "id" : "13mrI6FhRjGEk7xG7xYJvg"
+ | }
+ | } ],
+ | "cPsT9o5FQ3WRnvqSTXHiVQ" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "hlwc94lZRvOoBoaxyEWIGg"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 10,
+ | "allocation_id" : {
+ | "id" : "Kyne0gDVQEasq9VxUUsxbg"
+ | }
+ | }, {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 15,
+ | "allocation_id" : {
+ | "id" : "2G3Hs3CnT5uvhpeOmHZyYg"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 11,
+ | "allocation_id" : {
+ | "id" : "b4Gdtk7uTuSINaZ_YdaJdg"
+ | }
+ | }, {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 17,
+ | "allocation_id" : {
+ | "id" : "FbfzrPiySEaOzGMRZRDf7w"
+ | },
+ | "unassigned_info" : {
+ | "reason" : "REPLICA_ADDED",
+ | "at" : "2016-03-19T14:13:39.833Z"
+ | }
+ | } ]
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val nodesStats = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "nodes" : {
+ | "VOiMU2k5SuStH3-X1uuBGw" : {
+ | "timestamp" : 1458396821721,
+ | "name" : "Random",
+ | "transport_address" : "127.0.0.1:9301",
+ | "host" : "127.0.0.1",
+ | "ip" : [ "127.0.0.1:9301", "NONE" ],
+ | "os" : {
+ | "timestamp" : 1458396821721,
+ | "load_average" : 3.48583984375,
+ | "mem" : {
+ | "total_in_bytes" : 8589934592,
+ | "free_in_bytes" : 57360384,
+ | "used_in_bytes" : 8532574208,
+ | "free_percent" : 1,
+ | "used_percent" : 99
+ | },
+ | "swap" : {
+ | "total_in_bytes" : 2147483648,
+ | "free_in_bytes" : 1292369920,
+ | "used_in_bytes" : 855113728
+ | }
+ | },
+ | "process" : {
+ | "timestamp" : 1458396821721,
+ | "open_file_descriptors" : 283,
+ | "max_file_descriptors" : 10240,
+ | "cpu" : {
+ | "percent" : 0,
+ | "total_in_millis" : 204184
+ | },
+ | "mem" : {
+ | "total_virtual_in_bytes" : 5328396288
+ | }
+ | },
+ | "jvm" : {
+ | "timestamp" : 1458396821721,
+ | "uptime_in_millis" : 1013104,
+ | "mem" : {
+ | "heap_used_in_bytes" : 65155904,
+ | "heap_used_percent" : 6,
+ | "heap_committed_in_bytes" : 259522560,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_used_in_bytes" : 68894384,
+ | "non_heap_committed_in_bytes" : 70033408,
+ | "pools" : {
+ | "young" : {
+ | "used_in_bytes" : 17017328,
+ | "max_in_bytes" : 286326784,
+ | "peak_used_in_bytes" : 71630848,
+ | "peak_max_in_bytes" : 286326784
+ | },
+ | "survivor" : {
+ | "used_in_bytes" : 2022296,
+ | "max_in_bytes" : 35782656,
+ | "peak_used_in_bytes" : 8912896,
+ | "peak_max_in_bytes" : 35782656
+ | },
+ | "old" : {
+ | "used_in_bytes" : 46116280,
+ | "max_in_bytes" : 715849728,
+ | "peak_used_in_bytes" : 46116280,
+ | "peak_max_in_bytes" : 715849728
+ | }
+ | }
+ | },
+ | "threads" : {
+ | "count" : 99,
+ | "peak_count" : 103
+ | },
+ | "gc" : {
+ | "collectors" : {
+ | "young" : {
+ | "collection_count" : 173,
+ | "collection_time_in_millis" : 861
+ | },
+ | "old" : {
+ | "collection_count" : 1,
+ | "collection_time_in_millis" : 16
+ | }
+ | }
+ | },
+ | "buffer_pools" : {
+ | "direct" : {
+ | "count" : 126,
+ | "used_in_bytes" : 20107771,
+ | "total_capacity_in_bytes" : 20107771
+ | },
+ | "mapped" : {
+ | "count" : 7,
+ | "used_in_bytes" : 531368,
+ | "total_capacity_in_bytes" : 531368
+ | }
+ | }
+ | },
+ | "fs" : {
+ | "timestamp" : 1458396821721,
+ | "total" : {
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 41476603904,
+ | "available_in_bytes" : 41214459904
+ | },
+ | "data" : [ {
+ | "path" : "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/1",
+ | "mount" : "/ (/dev/disk1)",
+ | "type" : "hfs",
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 41476603904,
+ | "available_in_bytes" : 41214459904
+ | } ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ" : {
+ | "timestamp" : 1458396821720,
+ | "name" : "Cecilia Reyes",
+ | "transport_address" : "127.0.0.1:9300",
+ | "host" : "127.0.0.1",
+ | "ip" : [ "127.0.0.1:9300", "NONE" ],
+ | "os" : {
+ | "timestamp" : 1458396821720,
+ | "load_average" : 3.48583984375,
+ | "mem" : {
+ | "total_in_bytes" : 8589934592,
+ | "free_in_bytes" : 57360384,
+ | "used_in_bytes" : 8532574208,
+ | "free_percent" : 1,
+ | "used_percent" : 99
+ | },
+ | "swap" : {
+ | "total_in_bytes" : 2147483648,
+ | "free_in_bytes" : 1292369920,
+ | "used_in_bytes" : 855113728
+ | }
+ | },
+ | "process" : {
+ | "timestamp" : 1458396821720,
+ | "open_file_descriptors" : 309,
+ | "max_file_descriptors" : 10240,
+ | "cpu" : {
+ | "percent" : 0,
+ | "total_in_millis" : 439157
+ | },
+ | "mem" : {
+ | "total_virtual_in_bytes" : 5336465408
+ | }
+ | },
+ | "jvm" : {
+ | "timestamp" : 1458396821721,
+ | "uptime_in_millis" : 12257739,
+ | "mem" : {
+ | "heap_used_in_bytes" : 152293128,
+ | "heap_used_percent" : 14,
+ | "heap_committed_in_bytes" : 259522560,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_used_in_bytes" : 80998704,
+ | "non_heap_committed_in_bytes" : 82624512,
+ | "pools" : {
+ | "young" : {
+ | "used_in_bytes" : 42576208,
+ | "max_in_bytes" : 286326784,
+ | "peak_used_in_bytes" : 71630848,
+ | "peak_max_in_bytes" : 286326784
+ | },
+ | "survivor" : {
+ | "used_in_bytes" : 4755944,
+ | "max_in_bytes" : 35782656,
+ | "peak_used_in_bytes" : 8912896,
+ | "peak_max_in_bytes" : 35782656
+ | },
+ | "old" : {
+ | "used_in_bytes" : 104965192,
+ | "max_in_bytes" : 715849728,
+ | "peak_used_in_bytes" : 104965192,
+ | "peak_max_in_bytes" : 715849728
+ | }
+ | }
+ | },
+ | "threads" : {
+ | "count" : 102,
+ | "peak_count" : 106
+ | },
+ | "gc" : {
+ | "collectors" : {
+ | "young" : {
+ | "collection_count" : 252,
+ | "collection_time_in_millis" : 1611
+ | },
+ | "old" : {
+ | "collection_count" : 1,
+ | "collection_time_in_millis" : 12
+ | }
+ | }
+ | },
+ | "buffer_pools" : {
+ | "direct" : {
+ | "count" : 206,
+ | "used_in_bytes" : 28678155,
+ | "total_capacity_in_bytes" : 28678155
+ | },
+ | "mapped" : {
+ | "count" : 9,
+ | "used_in_bytes" : 536675,
+ | "total_capacity_in_bytes" : 536675
+ | }
+ | },
+ | "classes" : {
+ | "current_loaded_count" : 7623,
+ | "total_loaded_count" : 7623,
+ | "total_unloaded_count" : 0
+ | }
+ | },
+ | "fs" : {
+ | "timestamp" : 1458396821721,
+ | "total" : {
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 41476603904,
+ | "available_in_bytes" : 41214459904
+ | },
+ | "data" : [ {
+ | "path" : "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/0",
+ | "mount" : "/ (/dev/disk1)",
+ | "type" : "hfs",
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 41476603904,
+ | "available_in_bytes" : 41214459904
+ | } ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val indicesStats = Json.parse(
+ """
+ |{
+ | "_shards" : {
+ | "total" : 10,
+ | "successful" : 5,
+ | "failed" : 0
+ | },
+ | "_all" : {
+ | "primaries" : {
+ | "docs" : {
+ | "count" : 108680,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 2026271,
+ | "throttle_time_in_millis" : 0
+ | }
+ | },
+ | "total" : {
+ | "docs" : {
+ | "count" : 108680,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 2026271,
+ | "throttle_time_in_millis" : 0
+ | }
+ | }
+ | },
+ | "indices" : {
+ | "hello" : {
+ | "primaries" : {
+ | "docs" : {
+ | "count" : 108680,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 2026271,
+ | "throttle_time_in_millis" : 0
+ | }
+ | },
+ | "total" : {
+ | "docs" : {
+ | "count" : 108680,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 2026271,
+ | "throttle_time_in_millis" : 0
+ | }
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterSettings = Json.parse(
+ """
+ |{
+ | "persistent" : { },
+ | "transient" : { }
+ |}
+ """.stripMargin
+ )
+
+ val aliases = Json.parse(
+ """
+ |{
+ | "hello" : {
+ | "aliases" : { }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterHealth = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "status" : "yellow",
+ | "timed_out" : false,
+ | "number_of_nodes" : 2,
+ | "number_of_data_nodes" : 2,
+ | "active_primary_shards" : 5,
+ | "active_shards" : 5,
+ | "relocating_shards" : 0,
+ | "initializing_shards" : 4,
+ | "unassigned_shards" : 1,
+ | "delayed_unassigned_shards" : 0,
+ | "number_of_pending_tasks" : 0,
+ | "number_of_in_flight_fetch" : 0,
+ | "task_max_waiting_in_queue_millis" : 0,
+ | "active_shards_percent_as_number" : 50
+ |}
+ """.stripMargin
+ )
+
+ val nodes = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "nodes" : {
+ | "VOiMU2k5SuStH3-X1uuBGw" : {
+ | "name" : "Random",
+ | "transport_address" : "127.0.0.1:9301",
+ | "host" : "127.0.0.1",
+ | "ip" : "127.0.0.1",
+ | "version" : "2.1.0",
+ | "build" : "72cd1f1",
+ | "http_address" : "127.0.0.1:9201",
+ | "os" : {
+ | "refresh_interval_in_millis" : 1000,
+ | "available_processors" : 8,
+ | "allocated_processors" : 8
+ | },
+ | "jvm" : {
+ | "pid" : 16419,
+ | "version" : "1.8.0_72",
+ | "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version" : "25.72-b15",
+ | "vm_vendor" : "Oracle Corporation",
+ | "start_time_in_millis" : 1458393717991,
+ | "mem" : {
+ | "heap_init_in_bytes" : 268435456,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_init_in_bytes" : 2555904,
+ | "non_heap_max_in_bytes" : 0,
+ | "direct_max_in_bytes" : 1037959168
+ | },
+ | "gc_collectors" : [ "ParNew", "ConcurrentMarkSweep" ],
+ | "memory_pools" : [ "Code Cache", "Metaspace", "Compressed Class Space", "Par Eden Space", "Par Survivor Space", "CMS Old Gen" ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ" : {
+ | "name" : "Cecilia Reyes",
+ | "transport_address" : "127.0.0.1:9300",
+ | "host" : "127.0.0.1",
+ | "ip" : "127.0.0.1",
+ | "version" : "2.1.0",
+ | "build" : "72cd1f1",
+ | "http_address" : "127.0.0.1:9200",
+ | "os" : {
+ | "refresh_interval_in_millis" : 1000,
+ | "name" : "Mac OS X",
+ | "arch" : "x86_64",
+ | "version" : "10.11.3",
+ | "available_processors" : 8,
+ | "allocated_processors" : 8
+ | },
+ | "jvm" : {
+ | "pid" : 60169,
+ | "version" : "1.8.0_72",
+ | "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version" : "25.72-b15",
+ | "vm_vendor" : "Oracle Corporation",
+ | "start_time_in_millis" : 1458345474505,
+ | "mem" : {
+ | "heap_init_in_bytes" : 268435456,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_init_in_bytes" : 2555904,
+ | "non_heap_max_in_bytes" : 0,
+ | "direct_max_in_bytes" : 1037959168
+ | },
+ | "gc_collectors" : [ "ParNew", "ConcurrentMarkSweep" ],
+ | "memory_pools" : [ "Code Cache", "Metaspace", "Compressed Class Space", "Par Eden Space", "Par Survivor Space", "CMS Old Gen" ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val main = Json.parse(
+ """
+ |{
+ | "name" : "Cecilia Reyes",
+ | "cluster_name" : "elasticsearch",
+ | "version" : {
+ | "number" : "2.1.0",
+ | "build_hash" : "72cd1f1a3eee09505e036106146dc1949dc5dc87",
+ | "build_timestamp" : "2015-11-18T22:40:03Z",
+ | "build_snapshot" : false,
+ | "lucene_version" : "5.3.1"
+ | },
+ | "tagline" : "You Know, for Search"
+ |}
+ """.stripMargin
+ )
+
+}
diff --git a/test/models/overview/ClusterOverviewSpec.scala b/test/models/overview/ClusterOverviewSpec.scala
new file mode 100644
index 00000000..1a614fe4
--- /dev/null
+++ b/test/models/overview/ClusterOverviewSpec.scala
@@ -0,0 +1,121 @@
+package models.overview
+
+import org.specs2.Specification
+
+object ClusterOverviewSpec extends Specification {
+
+ def is =
+ s2"""
+ ClusterOverview should
+
+ return cluster_name $clusterName
+ return number of nodes $numberOfNodes
+ return number of active primary shards $activePrimaryShards
+ return number of active shards $activeShards
+ return number of relocating shards $relocatingShards
+ return number of initializing shards $initializingShards
+ return number of unassigned shards $unassignedShards
+ return cluster doc count $docsCount
+ return cluster size in bytes $sizeInBytes
+ return number of indices $totalIndices
+ return number of closed indices $closedIndices
+ return number of special indices $specialIndices
+ return state of shard allocation $shardAllocation
+ """
+
+ val clusterWithoutData = ClusterWithoutData().json
+ val clusterWithData = ClusterWithData().json
+ val clusterInitializing = ClusterInitializingShards().json
+ val clusterRelocating = ClusterRelocatingShards().json
+ val clusterDiabledAllocation = ClusterDisabledAllocation().json
+
+ def clusterName = {
+ (clusterWithoutData \ "cluster_name").as[String] mustEqual "elasticsearch"
+ (clusterWithData \ "cluster_name").as[String] mustEqual "elasticsearch"
+ (clusterInitializing \ "cluster_name").as[String] mustEqual "elasticsearch"
+ (clusterRelocating \ "cluster_name").as[String] mustEqual "elasticsearch"
+ }
+
+ def numberOfNodes = {
+ (clusterWithoutData \ "number_of_nodes").as[Int] mustEqual 2
+ (clusterWithData \ "number_of_nodes").as[Int] mustEqual 2
+ (clusterInitializing \ "number_of_nodes").as[Int] mustEqual 2
+ (clusterRelocating \ "number_of_nodes").as[Int] mustEqual 3
+ }
+
+ def activePrimaryShards = {
+ (clusterWithoutData \ "active_primary_shards").as[Int] mustEqual 0
+ (clusterWithData \ "active_primary_shards").as[Int] mustEqual 8
+ (clusterInitializing \ "active_primary_shards").as[Int] mustEqual 5
+ (clusterRelocating \ "active_primary_shards").as[Int] mustEqual 5
+ }
+
+ def activeShards = {
+ (clusterWithoutData \ "active_shards").as[Int] mustEqual 0
+ (clusterWithData \ "active_shards").as[Int] mustEqual 11
+ (clusterInitializing \ "active_shards").as[Int] mustEqual 5
+ (clusterRelocating \ "active_primary_shards").as[Int] mustEqual 5
+ }
+
+ def relocatingShards = {
+ (clusterWithoutData \ "relocating_shards").as[Int] mustEqual 0
+ (clusterWithData \ "relocating_shards").as[Int] mustEqual 0
+ (clusterInitializing \ "relocating_shards").as[Int] mustEqual 0
+ (clusterRelocating \ "relocating_shards").as[Int] mustEqual 2
+ }
+
+ def initializingShards = {
+ (clusterWithoutData \ "initializing_shards").as[Int] mustEqual 0
+ (clusterWithData \ "initializing_shards").as[Int] mustEqual 0
+ (clusterInitializing \ "initializing_shards").as[Int] mustEqual 4
+ (clusterRelocating \ "initializing_shards").as[Int] mustEqual 0
+ }
+
+ def unassignedShards = {
+ (clusterWithoutData \ "unassigned_shards").as[Int] mustEqual 0
+ (clusterWithData \ "unassigned_shards").as[Int] mustEqual 0
+ (clusterInitializing \ "unassigned_shards").as[Int] mustEqual 1
+ (clusterRelocating \ "unassigned_shards").as[Int] mustEqual 0
+ }
+
+ def docsCount = {
+ (clusterWithoutData \ "docs_count").as[Int] mustEqual 0
+ (clusterWithData \ "docs_count").as[Int] mustEqual 3
+ (clusterInitializing \ "docs_count").as[Int] mustEqual 108680
+ (clusterRelocating \ "docs_count").as[Int] mustEqual 108680
+ }
+
+ def sizeInBytes = {
+ (clusterWithoutData \ "size_in_bytes").as[Int] mustEqual 0
+ (clusterWithData \ "size_in_bytes").as[Int] mustEqual 16184
+ (clusterInitializing \ "size_in_bytes").as[Int] mustEqual 2026271
+ (clusterRelocating \ "size_in_bytes").as[Int] mustEqual 4052542
+ }
+
+ def totalIndices = {
+ (clusterWithoutData \ "total_indices").as[Int] mustEqual 0
+ (clusterWithData \ "total_indices").as[Int] mustEqual 3
+ (clusterInitializing \ "total_indices").as[Int] mustEqual 1
+ (clusterRelocating \ "total_indices").as[Int] mustEqual 1
+ }
+
+ def closedIndices = {
+ (clusterWithoutData \ "closed_indices").as[Int] mustEqual 0
+ (clusterWithData \ "closed_indices").as[Int] mustEqual 1
+ (clusterInitializing \ "closed_indices").as[Int] mustEqual 0
+ (clusterRelocating \ "closed_indices").as[Int] mustEqual 0
+ }
+
+ def specialIndices = {
+ (clusterWithoutData \ "special_indices").as[Int] mustEqual 0
+ (clusterWithData \ "special_indices").as[Int] mustEqual 1
+ (clusterInitializing \ "special_indices").as[Int] mustEqual 0
+ (clusterRelocating \ "special_indices").as[Int] mustEqual 0
+ }
+
+ def shardAllocation = {
+ (clusterWithData \ "shard_allocation").as[Boolean] mustEqual true
+ (clusterDiabledAllocation \ "shard_allocation").as[Boolean] mustEqual false
+ }
+
+}
diff --git a/test/models/overview/ClusterRelocatingShards.scala b/test/models/overview/ClusterRelocatingShards.scala
new file mode 100644
index 00000000..4a0974e7
--- /dev/null
+++ b/test/models/overview/ClusterRelocatingShards.scala
@@ -0,0 +1,862 @@
+package models.overview
+
+import play.api.libs.json.Json
+
+object ClusterRelocatingShards extends ClusterStub {
+
+ val clusterState = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "master_node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "blocks" : { },
+ | "routing_table" : {
+ | "indices" : {
+ | "hello" : {
+ | "shards" : {
+ | "1" : [ {
+ | "state" : "RELOCATING",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : "xIcHb7CPRH-_m4VGCtBV-w",
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 18,
+ | "expected_shard_size_in_bytes" : 407699,
+ | "allocation_id" : {
+ | "id" : "rNdtAPz_RhKVBp6dpAH1cw",
+ | "relocation_id" : "avGC6WQeTzqRnQyBE9O_bQ"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 18,
+ | "allocation_id" : {
+ | "id" : "hlwc94lZRvOoBoaxyEWIGg"
+ | }
+ | } ],
+ | "4" : [ {
+ | "state" : "STARTED",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "A4Dfk71HTriXU1OVBFQIeA"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "Kyne0gDVQEasq9VxUUsxbg"
+ | }
+ | } ],
+ | "2" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "rN62kibSRZq0RxcwxEHKKw"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "2G3Hs3CnT5uvhpeOmHZyYg"
+ | }
+ | } ],
+ | "3" : [ {
+ | "state" : "STARTED",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "NhG91IW6RCW1KAbSx67O9g"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "b4Gdtk7uTuSINaZ_YdaJdg"
+ | }
+ | } ],
+ | "0" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 19,
+ | "allocation_id" : {
+ | "id" : "13mrI6FhRjGEk7xG7xYJvg"
+ | }
+ | }, {
+ | "state" : "RELOCATING",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : "xIcHb7CPRH-_m4VGCtBV-w",
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 19,
+ | "expected_shard_size_in_bytes" : 405582,
+ | "allocation_id" : {
+ | "id" : "FbfzrPiySEaOzGMRZRDf7w",
+ | "relocation_id" : "fU5MEf2SSyGi40BscFJQsw"
+ | }
+ | } ]
+ | }
+ | }
+ | }
+ | },
+ | "routing_nodes" : {
+ | "unassigned" : [ ],
+ | "nodes" : {
+ | "VOiMU2k5SuStH3-X1uuBGw" : [ {
+ | "state" : "RELOCATING",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : "xIcHb7CPRH-_m4VGCtBV-w",
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 18,
+ | "expected_shard_size_in_bytes" : 407699,
+ | "allocation_id" : {
+ | "id" : "rNdtAPz_RhKVBp6dpAH1cw",
+ | "relocation_id" : "avGC6WQeTzqRnQyBE9O_bQ"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "A4Dfk71HTriXU1OVBFQIeA"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "rN62kibSRZq0RxcwxEHKKw"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : false,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "NhG91IW6RCW1KAbSx67O9g"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "relocating_node" : null,
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 19,
+ | "allocation_id" : {
+ | "id" : "13mrI6FhRjGEk7xG7xYJvg"
+ | }
+ | } ],
+ | "xIcHb7CPRH-_m4VGCtBV-w" : [ {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "xIcHb7CPRH-_m4VGCtBV-w",
+ | "relocating_node" : "VOiMU2k5SuStH3-X1uuBGw",
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 18,
+ | "expected_shard_size_in_bytes" : 407699,
+ | "allocation_id" : {
+ | "id" : "avGC6WQeTzqRnQyBE9O_bQ",
+ | "relocation_id" : "rNdtAPz_RhKVBp6dpAH1cw"
+ | }
+ | }, {
+ | "state" : "INITIALIZING",
+ | "primary" : false,
+ | "node" : "xIcHb7CPRH-_m4VGCtBV-w",
+ | "relocating_node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 19,
+ | "expected_shard_size_in_bytes" : 405582,
+ | "allocation_id" : {
+ | "id" : "fU5MEf2SSyGi40BscFJQsw",
+ | "relocation_id" : "FbfzrPiySEaOzGMRZRDf7w"
+ | }
+ | } ],
+ | "cPsT9o5FQ3WRnvqSTXHiVQ" : [ {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 1,
+ | "index" : "hello",
+ | "version" : 18,
+ | "allocation_id" : {
+ | "id" : "hlwc94lZRvOoBoaxyEWIGg"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 4,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "Kyne0gDVQEasq9VxUUsxbg"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 2,
+ | "index" : "hello",
+ | "version" : 16,
+ | "allocation_id" : {
+ | "id" : "2G3Hs3CnT5uvhpeOmHZyYg"
+ | }
+ | }, {
+ | "state" : "STARTED",
+ | "primary" : true,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : null,
+ | "shard" : 3,
+ | "index" : "hello",
+ | "version" : 12,
+ | "allocation_id" : {
+ | "id" : "b4Gdtk7uTuSINaZ_YdaJdg"
+ | }
+ | }, {
+ | "state" : "RELOCATING",
+ | "primary" : false,
+ | "node" : "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node" : "xIcHb7CPRH-_m4VGCtBV-w",
+ | "shard" : 0,
+ | "index" : "hello",
+ | "version" : 19,
+ | "expected_shard_size_in_bytes" : 405582,
+ | "allocation_id" : {
+ | "id" : "FbfzrPiySEaOzGMRZRDf7w",
+ | "relocation_id" : "fU5MEf2SSyGi40BscFJQsw"
+ | }
+ | } ]
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val nodesStats = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "nodes" : {
+ | "VOiMU2k5SuStH3-X1uuBGw" : {
+ | "timestamp" : 1458467882703,
+ | "name" : "Random",
+ | "transport_address" : "127.0.0.1:9301",
+ | "host" : "127.0.0.1",
+ | "ip" : [ "127.0.0.1:9301", "NONE" ],
+ | "os" : {
+ | "timestamp" : 1458467882703,
+ | "load_average" : 3.46435546875,
+ | "mem" : {
+ | "total_in_bytes" : 8589934592,
+ | "free_in_bytes" : 160845824,
+ | "used_in_bytes" : 8429088768,
+ | "free_percent" : 2,
+ | "used_percent" : 98
+ | },
+ | "swap" : {
+ | "total_in_bytes" : 3221225472,
+ | "free_in_bytes" : 1782317056,
+ | "used_in_bytes" : 1438908416
+ | }
+ | },
+ | "process" : {
+ | "timestamp" : 1458467882703,
+ | "open_file_descriptors" : 341,
+ | "max_file_descriptors" : 10240,
+ | "cpu" : {
+ | "percent" : 0,
+ | "total_in_millis" : 221649
+ | },
+ | "mem" : {
+ | "total_virtual_in_bytes" : 5311496192
+ | }
+ | },
+ | "jvm" : {
+ | "timestamp" : 1458467882703,
+ | "uptime_in_millis" : 2812465,
+ | "mem" : {
+ | "heap_used_in_bytes" : 109357464,
+ | "heap_used_percent" : 10,
+ | "heap_committed_in_bytes" : 259522560,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_used_in_bytes" : 70464888,
+ | "non_heap_committed_in_bytes" : 71409664,
+ | "pools" : {
+ | "young" : {
+ | "used_in_bytes" : 60805240,
+ | "max_in_bytes" : 286326784,
+ | "peak_used_in_bytes" : 71630848,
+ | "peak_max_in_bytes" : 286326784
+ | },
+ | "survivor" : {
+ | "used_in_bytes" : 2424584,
+ | "max_in_bytes" : 35782656,
+ | "peak_used_in_bytes" : 8912896,
+ | "peak_max_in_bytes" : 35782656
+ | },
+ | "old" : {
+ | "used_in_bytes" : 46127640,
+ | "max_in_bytes" : 715849728,
+ | "peak_used_in_bytes" : 46127640,
+ | "peak_max_in_bytes" : 715849728
+ | }
+ | }
+ | },
+ | "threads" : {
+ | "count" : 81,
+ | "peak_count" : 103
+ | },
+ | "gc" : {
+ | "collectors" : {
+ | "young" : {
+ | "collection_count" : 174,
+ | "collection_time_in_millis" : 866
+ | },
+ | "old" : {
+ | "collection_count" : 1,
+ | "collection_time_in_millis" : 16
+ | }
+ | }
+ | },
+ | "buffer_pools" : {
+ | "direct" : {
+ | "count" : 125,
+ | "used_in_bytes" : 20117010,
+ | "total_capacity_in_bytes" : 20117010
+ | },
+ | "mapped" : {
+ | "count" : 16,
+ | "used_in_bytes" : 1065237,
+ | "total_capacity_in_bytes" : 1065237
+ | }
+ | }
+ | },
+ | "fs" : {
+ | "timestamp" : 1458467882703,
+ | "total" : {
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 40472023040,
+ | "available_in_bytes" : 40209879040
+ | },
+ | "data" : [ {
+ | "path" : "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/1",
+ | "mount" : "/ (/dev/disk1)",
+ | "type" : "hfs",
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 40472023040,
+ | "available_in_bytes" : 40209879040
+ | } ]
+ | }
+ | },
+ | "xIcHb7CPRH-_m4VGCtBV-w" : {
+ | "timestamp" : 1458467882703,
+ | "name" : "Force",
+ | "transport_address" : "127.0.0.1:9302",
+ | "host" : "127.0.0.1",
+ | "ip" : [ "127.0.0.1:9302", "NONE" ],
+ | "os" : {
+ | "timestamp" : 1458467882703,
+ | "load_average" : 3.46435546875,
+ | "mem" : {
+ | "total_in_bytes" : 8589934592,
+ | "free_in_bytes" : 160845824,
+ | "used_in_bytes" : 8429088768,
+ | "free_percent" : 2,
+ | "used_percent" : 98
+ | },
+ | "swap" : {
+ | "total_in_bytes" : 3221225472,
+ | "free_in_bytes" : 1782317056,
+ | "used_in_bytes" : 1438908416
+ | }
+ | },
+ | "process" : {
+ | "timestamp" : 1458467882703,
+ | "open_file_descriptors" : 287,
+ | "max_file_descriptors" : 10240,
+ | "cpu" : {
+ | "percent" : 0,
+ | "total_in_millis" : 9698
+ | },
+ | "mem" : {
+ | "total_virtual_in_bytes" : 5304852480
+ | }
+ | },
+ | "jvm" : {
+ | "timestamp" : 1458467882703,
+ | "uptime_in_millis" : 20926,
+ | "mem" : {
+ | "heap_used_in_bytes" : 61247544,
+ | "heap_used_percent" : 5,
+ | "heap_committed_in_bytes" : 259522560,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_used_in_bytes" : 45875264,
+ | "non_heap_committed_in_bytes" : 46505984,
+ | "pools" : {
+ | "young" : {
+ | "used_in_bytes" : 42389104,
+ | "max_in_bytes" : 286326784,
+ | "peak_used_in_bytes" : 71630848,
+ | "peak_max_in_bytes" : 286326784
+ | },
+ | "survivor" : {
+ | "used_in_bytes" : 7531480,
+ | "max_in_bytes" : 35782656,
+ | "peak_used_in_bytes" : 8912888,
+ | "peak_max_in_bytes" : 35782656
+ | },
+ | "old" : {
+ | "used_in_bytes" : 11326960,
+ | "max_in_bytes" : 715849728,
+ | "peak_used_in_bytes" : 11326960,
+ | "peak_max_in_bytes" : 715849728
+ | }
+ | }
+ | },
+ | "threads" : {
+ | "count" : 78,
+ | "peak_count" : 78
+ | },
+ | "gc" : {
+ | "collectors" : {
+ | "young" : {
+ | "collection_count" : 4,
+ | "collection_time_in_millis" : 52
+ | },
+ | "old" : {
+ | "collection_count" : 1,
+ | "collection_time_in_millis" : 16
+ | }
+ | }
+ | },
+ | "buffer_pools" : {
+ | "direct" : {
+ | "count" : 79,
+ | "used_in_bytes" : 16786963,
+ | "total_capacity_in_bytes" : 16786963
+ | },
+ | "mapped" : {
+ | "count" : 0,
+ | "used_in_bytes" : 0,
+ | "total_capacity_in_bytes" : 0
+ | }
+ | }
+ | },
+ | "fs" : {
+ | "timestamp" : 1458467882704,
+ | "total" : {
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 40471994368,
+ | "available_in_bytes" : 40209850368
+ | },
+ | "data" : [ {
+ | "path" : "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/2",
+ | "mount" : "/ (/dev/disk1)",
+ | "type" : "hfs",
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 40471994368,
+ | "available_in_bytes" : 40209850368
+ | } ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ" : {
+ | "timestamp" : 1458467882703,
+ | "name" : "Cecilia Reyes",
+ | "transport_address" : "127.0.0.1:9300",
+ | "host" : "127.0.0.1",
+ | "ip" : [ "127.0.0.1:9300", "NONE" ],
+ | "os" : {
+ | "timestamp" : 1458467882703,
+ | "load_average" : 3.46435546875,
+ | "mem" : {
+ | "total_in_bytes" : 8589934592,
+ | "free_in_bytes" : 160845824,
+ | "used_in_bytes" : 8429088768,
+ | "free_percent" : 2,
+ | "used_percent" : 98
+ | },
+ | "swap" : {
+ | "total_in_bytes" : 3221225472,
+ | "free_in_bytes" : 1782317056,
+ | "used_in_bytes" : 1438908416
+ | }
+ | },
+ | "process" : {
+ | "timestamp" : 1458467882703,
+ | "open_file_descriptors" : 356,
+ | "max_file_descriptors" : 10240,
+ | "cpu" : {
+ | "percent" : 0,
+ | "total_in_millis" : 461242
+ | },
+ | "mem" : {
+ | "total_virtual_in_bytes" : 5319544832
+ | }
+ | },
+ | "jvm" : {
+ | "timestamp" : 1458467882703,
+ | "uptime_in_millis" : 14057100,
+ | "mem" : {
+ | "heap_used_in_bytes" : 80014736,
+ | "heap_used_percent" : 7,
+ | "heap_committed_in_bytes" : 259522560,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_used_in_bytes" : 81637648,
+ | "non_heap_committed_in_bytes" : 83148800,
+ | "pools" : {
+ | "young" : {
+ | "used_in_bytes" : 61420544,
+ | "max_in_bytes" : 286326784,
+ | "peak_used_in_bytes" : 71630848,
+ | "peak_max_in_bytes" : 286326784
+ | },
+ | "survivor" : {
+ | "used_in_bytes" : 1478648,
+ | "max_in_bytes" : 35782656,
+ | "peak_used_in_bytes" : 8912896,
+ | "peak_max_in_bytes" : 35782656
+ | },
+ | "old" : {
+ | "used_in_bytes" : 17115544,
+ | "max_in_bytes" : 715849728,
+ | "peak_used_in_bytes" : 104965192,
+ | "peak_max_in_bytes" : 715849728
+ | }
+ | }
+ | },
+ | "threads" : {
+ | "count" : 85,
+ | "peak_count" : 106
+ | },
+ | "gc" : {
+ | "collectors" : {
+ | "young" : {
+ | "collection_count" : 254,
+ | "collection_time_in_millis" : 1635
+ | },
+ | "old" : {
+ | "collection_count" : 2,
+ | "collection_time_in_millis" : 134
+ | }
+ | }
+ | },
+ | "buffer_pools" : {
+ | "direct" : {
+ | "count" : 173,
+ | "used_in_bytes" : 28642823,
+ | "total_capacity_in_bytes" : 28642823
+ | },
+ | "mapped" : {
+ | "count" : 15,
+ | "used_in_bytes" : 891872,
+ | "total_capacity_in_bytes" : 891872
+ | }
+ | },
+ | "classes" : {
+ | "current_loaded_count" : 7609,
+ | "total_loaded_count" : 7623,
+ | "total_unloaded_count" : 14
+ | }
+ | },
+ | "fs" : {
+ | "timestamp" : 1458467882703,
+ | "total" : {
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 40472023040,
+ | "available_in_bytes" : 40209879040
+ | },
+ | "data" : [ {
+ | "path" : "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/0",
+ | "mount" : "/ (/dev/disk1)",
+ | "type" : "hfs",
+ | "total_in_bytes" : 249804886016,
+ | "free_in_bytes" : 40472023040,
+ | "available_in_bytes" : 40209879040
+ | } ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val indicesStats = Json.parse(
+ """
+ |{
+ | "_shards" : {
+ | "total" : 10,
+ | "successful" : 10,
+ | "failed" : 0
+ | },
+ | "_all" : {
+ | "primaries" : {
+ | "docs" : {
+ | "count" : 108680,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 2026271,
+ | "throttle_time_in_millis" : 0
+ | }
+ | },
+ | "total" : {
+ | "docs" : {
+ | "count" : 217360,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 4052542,
+ | "throttle_time_in_millis" : 0
+ | }
+ | }
+ | },
+ | "indices" : {
+ | "hello" : {
+ | "primaries" : {
+ | "docs" : {
+ | "count" : 108680,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 2026271,
+ | "throttle_time_in_millis" : 0
+ | }
+ | },
+ | "total" : {
+ | "docs" : {
+ | "count" : 217360,
+ | "deleted" : 0
+ | },
+ | "store" : {
+ | "size_in_bytes" : 4052542,
+ | "throttle_time_in_millis" : 0
+ | }
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterSettings = Json.parse(
+ """
+ |{
+ | "persistent" : { },
+ | "transient" : { }
+ |}
+ """.stripMargin
+ )
+
+ val aliases = Json.parse(
+ """
+ |{
+ | "hello" : {
+ | "aliases" : { }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterHealth = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "status" : "green",
+ | "timed_out" : false,
+ | "number_of_nodes" : 3,
+ | "number_of_data_nodes" : 3,
+ | "active_primary_shards" : 5,
+ | "active_shards" : 10,
+ | "relocating_shards" : 2,
+ | "initializing_shards" : 0,
+ | "unassigned_shards" : 0,
+ | "delayed_unassigned_shards" : 0,
+ | "number_of_pending_tasks" : 0,
+ | "number_of_in_flight_fetch" : 0,
+ | "task_max_waiting_in_queue_millis" : 0,
+ | "active_shards_percent_as_number" : 100
+ |}
+ """.stripMargin
+ )
+
+ val nodes = Json.parse(
+ """
+ |{
+ | "cluster_name" : "elasticsearch",
+ | "nodes" : {
+ | "VOiMU2k5SuStH3-X1uuBGw" : {
+ | "name" : "Random",
+ | "transport_address" : "127.0.0.1:9301",
+ | "host" : "127.0.0.1",
+ | "ip" : "127.0.0.1",
+ | "version" : "2.1.0",
+ | "build" : "72cd1f1",
+ | "http_address" : "127.0.0.1:9201",
+ | "os" : {
+ | "refresh_interval_in_millis" : 1000,
+ | "available_processors" : 8,
+ | "allocated_processors" : 8
+ | },
+ | "jvm" : {
+ | "pid" : 16419,
+ | "version" : "1.8.0_72",
+ | "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version" : "25.72-b15",
+ | "vm_vendor" : "Oracle Corporation",
+ | "start_time_in_millis" : 1458393717991,
+ | "mem" : {
+ | "heap_init_in_bytes" : 268435456,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_init_in_bytes" : 2555904,
+ | "non_heap_max_in_bytes" : 0,
+ | "direct_max_in_bytes" : 1037959168
+ | },
+ | "gc_collectors" : [ "ParNew", "ConcurrentMarkSweep" ],
+ | "memory_pools" : [ "Code Cache", "Metaspace", "Compressed Class Space", "Par Eden Space", "Par Survivor Space", "CMS Old Gen" ]
+ | }
+ | },
+ | "xIcHb7CPRH-_m4VGCtBV-w" : {
+ | "name" : "Force",
+ | "transport_address" : "127.0.0.1:9302",
+ | "host" : "127.0.0.1",
+ | "ip" : "127.0.0.1",
+ | "version" : "2.1.0",
+ | "build" : "72cd1f1",
+ | "http_address" : "127.0.0.1:9202",
+ | "os" : {
+ | "refresh_interval_in_millis" : 1000,
+ | "available_processors" : 8,
+ | "allocated_processors" : 8
+ | },
+ | "jvm" : {
+ | "pid" : 76352,
+ | "version" : "1.8.0_72",
+ | "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version" : "25.72-b15",
+ | "vm_vendor" : "Oracle Corporation",
+ | "start_time_in_millis" : 1458467861836,
+ | "mem" : {
+ | "heap_init_in_bytes" : 268435456,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_init_in_bytes" : 2555904,
+ | "non_heap_max_in_bytes" : 0,
+ | "direct_max_in_bytes" : 1037959168
+ | },
+ | "gc_collectors" : [ "ParNew", "ConcurrentMarkSweep" ],
+ | "memory_pools" : [ "Code Cache", "Metaspace", "Compressed Class Space", "Par Eden Space", "Par Survivor Space", "CMS Old Gen" ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ" : {
+ | "name" : "Cecilia Reyes",
+ | "transport_address" : "127.0.0.1:9300",
+ | "host" : "127.0.0.1",
+ | "ip" : "127.0.0.1",
+ | "version" : "2.1.0",
+ | "build" : "72cd1f1",
+ | "http_address" : "127.0.0.1:9200",
+ | "os" : {
+ | "refresh_interval_in_millis" : 1000,
+ | "name" : "Mac OS X",
+ | "arch" : "x86_64",
+ | "version" : "10.11.3",
+ | "available_processors" : 8,
+ | "allocated_processors" : 8
+ | },
+ | "jvm" : {
+ | "pid" : 60169,
+ | "version" : "1.8.0_72",
+ | "vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version" : "25.72-b15",
+ | "vm_vendor" : "Oracle Corporation",
+ | "start_time_in_millis" : 1458345474505,
+ | "mem" : {
+ | "heap_init_in_bytes" : 268435456,
+ | "heap_max_in_bytes" : 1037959168,
+ | "non_heap_init_in_bytes" : 2555904,
+ | "non_heap_max_in_bytes" : 0,
+ | "direct_max_in_bytes" : 1037959168
+ | },
+ | "gc_collectors" : [ "ParNew", "ConcurrentMarkSweep" ],
+ | "memory_pools" : [ "Code Cache", "Metaspace", "Compressed Class Space", "Par Eden Space", "Par Survivor Space", "CMS Old Gen" ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val main = Json.parse(
+ """
+ |{
+ | "name" : "Cecilia Reyes",
+ | "cluster_name" : "elasticsearch",
+ | "version" : {
+ | "number" : "2.1.0",
+ | "build_hash" : "72cd1f1a3eee09505e036106146dc1949dc5dc87",
+ | "build_timestamp" : "2015-11-18T22:40:03Z",
+ | "build_snapshot" : false,
+ | "lucene_version" : "5.3.1"
+ | },
+ | "tagline" : "You Know, for Search"
+ |}
+ """.stripMargin
+ )
+
+}
diff --git a/test/models/overview/ClusterStub.scala b/test/models/overview/ClusterStub.scala
new file mode 100644
index 00000000..20008cbf
--- /dev/null
+++ b/test/models/overview/ClusterStub.scala
@@ -0,0 +1,25 @@
+package models.overview
+
+import play.api.libs.json.JsValue
+
+trait ClusterStub {
+
+ def apply() = new ClusterOverview(clusterState, nodesStats, indicesStats, clusterSettings, aliases, clusterHealth, nodes, main)
+
+ val clusterState: JsValue
+
+ val nodesStats: JsValue
+
+ val indicesStats: JsValue
+
+ val clusterSettings: JsValue
+
+ val aliases: JsValue
+
+ val clusterHealth: JsValue
+
+ val nodes: JsValue
+
+ val main: JsValue
+
+}
diff --git a/test/models/overview/ClusterWithData.scala b/test/models/overview/ClusterWithData.scala
new file mode 100644
index 00000000..304260df
--- /dev/null
+++ b/test/models/overview/ClusterWithData.scala
@@ -0,0 +1,715 @@
+package models.overview
+
+import play.api.libs.json.Json
+
+trait ClusterWithData extends ClusterStub {
+
+ val clusterState = Json.parse(
+ """
+ |{
+ | "cluster_name": "elasticsearch",
+ | "master_node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "blocks" : {
+ | "indices" : {
+ | "foo" : {
+ | "4" : {
+ | "description" : "index closed",
+ | "retryable" : false,
+ | "levels" : [ "read", "write" ]
+ | }
+ | }
+ | }
+ | },
+ | "routing_table": {
+ | "indices": {
+ | "bar": {
+ | "shards": {
+ | "0": [
+ | {
+ | "state": "STARTED",
+ | "primary": false,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 0,
+ | "index": "bar",
+ | "version": 3,
+ | "allocation_id": {
+ | "id": "ns_A3bOnS26LHP9aMMoNqQ"
+ | }
+ | },
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node": null,
+ | "shard": 0,
+ | "index": "bar",
+ | "version": 3,
+ | "allocation_id": {
+ | "id": "KpTuITnDRju5huuD7K42JQ"
+ | }
+ | }
+ | ]
+ | }
+ | },
+ | ".foobar": {
+ | "shards": {
+ | "0": [
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 0,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "av2CBQ7ZR6mpYP4hN45SFQ"
+ | }
+ | }
+ | ],
+ | "1": [
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node": null,
+ | "shard": 1,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "WA41NgmPRdyuV1Bdf3xAIw"
+ | }
+ | }
+ | ],
+ | "2": [
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 2,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "9i-1Ze0iTyyGreKtd6uNlQ"
+ | }
+ | }
+ | ],
+ | "3": [
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node": null,
+ | "shard": 3,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "QqhRDD_DST6P0By3QaKjug"
+ | }
+ | }
+ | ],
+ | "4": [
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 4,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "w30rCs_vRIeWWNdPD6yinA"
+ | }
+ | }
+ | ]
+ | }
+ | }
+ | }
+ | },
+ | "routing_nodes": {
+ | "unassigned": [],
+ | "nodes": {
+ | "MoDcZdJkQGK2RpYTvJhQlA": [
+ | {
+ | "state": "STARTED",
+ | "primary": false,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 0,
+ | "index": "bar",
+ | "version": 3,
+ | "allocation_id": {
+ | "id": "ns_A3bOnS26LHP9aMMoNqQ"
+ | }
+ | },
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 4,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "w30rCs_vRIeWWNdPD6yinA"
+ | }
+ | },
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 2,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "9i-1Ze0iTyyGreKtd6uNlQ"
+ | }
+ | },
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "MoDcZdJkQGK2RpYTvJhQlA",
+ | "relocating_node": null,
+ | "shard": 0,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "av2CBQ7ZR6mpYP4hN45SFQ"
+ | }
+ | }
+ | ],
+ | "cPsT9o5FQ3WRnvqSTXHiVQ": [
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node": null,
+ | "shard": 0,
+ | "index": "bar",
+ | "version": 3,
+ | "allocation_id": {
+ | "id": "KpTuITnDRju5huuD7K42JQ"
+ | }
+ | },
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node": null,
+ | "shard": 1,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "WA41NgmPRdyuV1Bdf3xAIw"
+ | }
+ | },
+ | {
+ | "state": "STARTED",
+ | "primary": true,
+ | "node": "cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "relocating_node": null,
+ | "shard": 3,
+ | "index": ".foobar",
+ | "version": 2,
+ | "allocation_id": {
+ | "id": "QqhRDD_DST6P0By3QaKjug"
+ | }
+ | }
+ | ]
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val nodesStats = Json.parse(
+ """
+ |{
+ | "cluster_name": "elasticsearch",
+ | "nodes": {
+ | "MoDcZdJkQGK2RpYTvJhQlA": {
+ | "timestamp": 1458349671429,
+ | "name": "Solara",
+ | "transport_address": "127.0.0.1:9301",
+ | "host": "127.0.0.1",
+ | "ip": [
+ | "127.0.0.1:9301",
+ | "NONE"
+ | ],
+ | "os": {
+ | "timestamp": 1458349670762,
+ | "load_average": 3.34326171875,
+ | "mem": {
+ | "total_in_bytes": 8589934592,
+ | "free_in_bytes": 33009664,
+ | "used_in_bytes": 8556924928,
+ | "free_percent": 0,
+ | "used_percent": 100
+ | },
+ | "swap": {
+ | "total_in_bytes": 2147483648,
+ | "free_in_bytes": 1729626112,
+ | "used_in_bytes": 417857536
+ | }
+ | },
+ | "process": {
+ | "timestamp": 1458349670762,
+ | "open_file_descriptors": 271,
+ | "max_file_descriptors": 10240,
+ | "cpu": {
+ | "percent": 0,
+ | "total_in_millis": 46412
+ | },
+ | "mem": {
+ | "total_virtual_in_bytes": 5282828288
+ | }
+ | },
+ | "jvm": {
+ | "timestamp": 1458349670762,
+ | "uptime_in_millis": 4187845,
+ | "mem": {
+ | "heap_used_in_bytes": 86912928,
+ | "heap_used_percent": 8,
+ | "heap_committed_in_bytes": 259522560,
+ | "heap_max_in_bytes": 1037959168,
+ | "non_heap_used_in_bytes": 54344920,
+ | "non_heap_committed_in_bytes": 55156736,
+ | "pools": {
+ | "young": {
+ | "used_in_bytes": 67421744,
+ | "max_in_bytes": 286326784,
+ | "peak_used_in_bytes": 71630848,
+ | "peak_max_in_bytes": 286326784
+ | },
+ | "survivor": {
+ | "used_in_bytes": 6942440,
+ | "max_in_bytes": 35782656,
+ | "peak_used_in_bytes": 8912888,
+ | "peak_max_in_bytes": 35782656
+ | },
+ | "old": {
+ | "used_in_bytes": 12548744,
+ | "max_in_bytes": 715849728,
+ | "peak_used_in_bytes": 12548744,
+ | "peak_max_in_bytes": 715849728
+ | }
+ | }
+ | },
+ | "threads": {
+ | "count": 71,
+ | "peak_count": 87
+ | },
+ | "gc": {
+ | "collectors": {
+ | "young": {
+ | "collection_count": 5,
+ | "collection_time_in_millis": 76
+ | },
+ | "old": {
+ | "collection_count": 1,
+ | "collection_time_in_millis": 18
+ | }
+ | }
+ | },
+ | "buffer_pools": {
+ | "direct": {
+ | "count": 79,
+ | "used_in_bytes": 14167303,
+ | "total_capacity_in_bytes": 14167303
+ | },
+ | "mapped": {
+ | "count": 0,
+ | "used_in_bytes": 0,
+ | "total_capacity_in_bytes": 0
+ | }
+ | }
+ | },
+ | "fs": {
+ | "timestamp": 1458349670762,
+ | "total": {
+ | "total_in_bytes": 249804886016,
+ | "free_in_bytes": 41525211136,
+ | "available_in_bytes": 41263067136
+ | },
+ | "data": [
+ | {
+ | "path": "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/1",
+ | "mount": "/ (/dev/disk1)",
+ | "type": "hfs",
+ | "total_in_bytes": 249804886016,
+ | "free_in_bytes": 41525211136,
+ | "available_in_bytes": 41263067136
+ | }
+ | ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ": {
+ | "timestamp": 1458349671429,
+ | "name": "Cecilia Reyes",
+ | "transport_address": "127.0.0.1:9300",
+ | "host": "127.0.0.1",
+ | "ip": [
+ | "127.0.0.1:9300",
+ | "NONE"
+ | ],
+ | "os": {
+ | "timestamp": 1458349670762,
+ | "load_average": 3.34326171875,
+ | "mem": {
+ | "total_in_bytes": 8589934592,
+ | "free_in_bytes": 33009664,
+ | "used_in_bytes": 8556924928,
+ | "free_percent": 0,
+ | "used_percent": 100
+ | },
+ | "swap": {
+ | "total_in_bytes": 2147483648,
+ | "free_in_bytes": 1729626112,
+ | "used_in_bytes": 417857536
+ | }
+ | },
+ | "process": {
+ | "timestamp": 1458349670762,
+ | "open_file_descriptors": 280,
+ | "max_file_descriptors": 10240,
+ | "cpu": {
+ | "percent": 0,
+ | "total_in_millis": 49096
+ | },
+ | "mem": {
+ | "total_virtual_in_bytes": 5301309440
+ | }
+ | },
+ | "jvm": {
+ | "timestamp": 1458349670762,
+ | "uptime_in_millis": 4196395,
+ | "mem": {
+ | "heap_used_in_bytes": 70134792,
+ | "heap_used_percent": 6,
+ | "heap_committed_in_bytes": 259522560,
+ | "heap_max_in_bytes": 1037959168,
+ | "non_heap_used_in_bytes": 61118128,
+ | "non_heap_committed_in_bytes": 62324736,
+ | "pools": {
+ | "young": {
+ | "used_in_bytes": 52733792,
+ | "max_in_bytes": 286326784,
+ | "peak_used_in_bytes": 71630848,
+ | "peak_max_in_bytes": 286326784
+ | },
+ | "survivor": {
+ | "used_in_bytes": 2375848,
+ | "max_in_bytes": 35782656,
+ | "peak_used_in_bytes": 8912896,
+ | "peak_max_in_bytes": 35782656
+ | },
+ | "old": {
+ | "used_in_bytes": 15025152,
+ | "max_in_bytes": 715849728,
+ | "peak_used_in_bytes": 15025152,
+ | "peak_max_in_bytes": 715849728
+ | }
+ | }
+ | },
+ | "threads": {
+ | "count": 77,
+ | "peak_count": 106
+ | },
+ | "gc": {
+ | "collectors": {
+ | "young": {
+ | "collection_count": 7,
+ | "collection_time_in_millis": 93
+ | },
+ | "old": {
+ | "collection_count": 1,
+ | "collection_time_in_millis": 12
+ | }
+ | }
+ | },
+ | "buffer_pools": {
+ | "direct": {
+ | "count": 153,
+ | "used_in_bytes": 23280699,
+ | "total_capacity_in_bytes": 23280699
+ | },
+ | "mapped": {
+ | "count": 0,
+ | "used_in_bytes": 0,
+ | "total_capacity_in_bytes": 0
+ | }
+ | },
+ | "classes": {
+ | "current_loaded_count": 7446,
+ | "total_loaded_count": 7446,
+ | "total_unloaded_count": 0
+ | }
+ | },
+ | "fs": {
+ | "timestamp": 1458349670762,
+ | "total": {
+ | "total_in_bytes": 249804886016,
+ | "free_in_bytes": 41525211136,
+ | "available_in_bytes": 41263067136
+ | },
+ | "data": [
+ | {
+ | "path": "/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/0",
+ | "mount": "/ (/dev/disk1)",
+ | "type": "hfs",
+ | "total_in_bytes": 249804886016,
+ | "free_in_bytes": 41525211136,
+ | "available_in_bytes": 41263067136
+ | }
+ | ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val indicesStats = Json.parse(
+ """
+ |{
+ | "_shards": {
+ | "total": 11,
+ | "successful": 11,
+ | "failed": 0
+ | },
+ | "_all": {
+ | "primaries": {
+ | "docs": {
+ | "count": 3,
+ | "deleted": 0
+ | },
+ | "store": {
+ | "size_in_bytes": 9902,
+ | "throttle_time_in_millis": 0
+ | }
+ | },
+ | "total": {
+ | "docs": {
+ | "count": 5,
+ | "deleted": 0
+ | },
+ | "store": {
+ | "size_in_bytes": 16184,
+ | "throttle_time_in_millis": 0
+ | }
+ | }
+ | },
+ | "indices": {
+ | "bar": {
+ | "primaries": {
+ | "docs": {
+ | "count": 1,
+ | "deleted": 0
+ | },
+ | "store": {
+ | "size_in_bytes": 3076,
+ | "throttle_time_in_millis": 0
+ | }
+ | },
+ | "total": {
+ | "docs": {
+ | "count": 2,
+ | "deleted": 0
+ | },
+ | "store": {
+ | "size_in_bytes": 6152,
+ | "throttle_time_in_millis": 0
+ | }
+ | }
+ | },
+ | ".foobar": {
+ | "primaries": {
+ | "docs": {
+ | "count": 1,
+ | "deleted": 0
+ | },
+ | "store": {
+ | "size_in_bytes": 3620,
+ | "throttle_time_in_millis": 0
+ | }
+ | },
+ | "total": {
+ | "docs": {
+ | "count": 1,
+ | "deleted": 0
+ | },
+ | "store": {
+ | "size_in_bytes": 3620,
+ | "throttle_time_in_millis": 0
+ | }
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterSettings = Json.parse(
+ """
+ |{
+ | "persistent": {},
+ | "transient": {}
+ |}
+ """.stripMargin
+ )
+
+ val aliases = Json.parse(
+ """
+ |{
+ | "bar": {
+ | "aliases": {
+ | "active": {}
+ | }
+ | },
+ | ".foobar": {
+ | "aliases": {}
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterHealth = Json.parse(
+ """
+ |{
+ | "cluster_name": "elasticsearch",
+ | "status": "green",
+ | "timed_out": false,
+ | "number_of_nodes": 2,
+ | "number_of_data_nodes": 2,
+ | "active_primary_shards": 8,
+ | "active_shards": 11,
+ | "relocating_shards": 0,
+ | "initializing_shards": 0,
+ | "unassigned_shards": 0,
+ | "delayed_unassigned_shards": 0,
+ | "number_of_pending_tasks": 0,
+ | "number_of_in_flight_fetch": 0,
+ | "task_max_waiting_in_queue_millis": 0,
+ | "active_shards_percent_as_number": 100
+ |}
+ """.stripMargin
+ )
+
+ val nodes = Json.parse(
+ """
+ |{
+ | "cluster_name": "elasticsearch",
+ | "nodes": {
+ | "MoDcZdJkQGK2RpYTvJhQlA": {
+ | "name": "Solara",
+ | "transport_address": "127.0.0.1:9301",
+ | "host": "127.0.0.1",
+ | "ip": "127.0.0.1",
+ | "version": "2.1.0",
+ | "build": "72cd1f1",
+ | "http_address": "127.0.0.1:9201",
+ | "os": {
+ | "refresh_interval_in_millis": 1000,
+ | "available_processors": 8,
+ | "allocated_processors": 8
+ | },
+ | "jvm": {
+ | "pid": 60238,
+ | "version": "1.8.0_72",
+ | "vm_name": "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version": "25.72-b15",
+ | "vm_vendor": "Oracle Corporation",
+ | "start_time_in_millis": 1458345483045,
+ | "mem": {
+ | "heap_init_in_bytes": 268435456,
+ | "heap_max_in_bytes": 1037959168,
+ | "non_heap_init_in_bytes": 2555904,
+ | "non_heap_max_in_bytes": 0,
+ | "direct_max_in_bytes": 1037959168
+ | },
+ | "gc_collectors": [
+ | "ParNew",
+ | "ConcurrentMarkSweep"
+ | ],
+ | "memory_pools": [
+ | "Code Cache",
+ | "Metaspace",
+ | "Compressed Class Space",
+ | "Par Eden Space",
+ | "Par Survivor Space",
+ | "CMS Old Gen"
+ | ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ": {
+ | "name": "Cecilia Reyes",
+ | "transport_address": "127.0.0.1:9300",
+ | "host": "127.0.0.1",
+ | "ip": "127.0.0.1",
+ | "version": "2.1.0",
+ | "build": "72cd1f1",
+ | "http_address": "127.0.0.1:9200",
+ | "os": {
+ | "refresh_interval_in_millis": 1000,
+ | "name": "Mac OS X",
+ | "arch": "x86_64",
+ | "version": "10.11.3",
+ | "available_processors": 8,
+ | "allocated_processors": 8
+ | },
+ | "jvm": {
+ | "pid": 60169,
+ | "version": "1.8.0_72",
+ | "vm_name": "Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version": "25.72-b15",
+ | "vm_vendor": "Oracle Corporation",
+ | "start_time_in_millis": 1458345474505,
+ | "mem": {
+ | "heap_init_in_bytes": 268435456,
+ | "heap_max_in_bytes": 1037959168,
+ | "non_heap_init_in_bytes": 2555904,
+ | "non_heap_max_in_bytes": 0,
+ | "direct_max_in_bytes": 1037959168
+ | },
+ | "gc_collectors": [
+ | "ParNew",
+ | "ConcurrentMarkSweep"
+ | ],
+ | "memory_pools": [
+ | "Code Cache",
+ | "Metaspace",
+ | "Compressed Class Space",
+ | "Par Eden Space",
+ | "Par Survivor Space",
+ | "CMS Old Gen"
+ | ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val main = Json.parse(
+ """
+ |{
+ | "name": "Cecilia Reyes",
+ | "cluster_name": "elasticsearch",
+ | "version": {
+ | "number": "2.1.0",
+ | "build_hash": "72cd1f1a3eee09505e036106146dc1949dc5dc87",
+ | "build_timestamp": "2015-11-18T22:40:03Z",
+ | "build_snapshot": false,
+ | "lucene_version": "5.3.1"
+ | },
+ | "tagline": "You Know, for Search"
+ |}
+ """.stripMargin
+ )
+
+}
+
+object ClusterWithData extends ClusterWithData
diff --git a/test/models/overview/ClusterWithoutData.scala b/test/models/overview/ClusterWithoutData.scala
new file mode 100644
index 00000000..2398e93a
--- /dev/null
+++ b/test/models/overview/ClusterWithoutData.scala
@@ -0,0 +1,462 @@
+package models.overview
+
+import play.api.libs.json.Json
+
+object ClusterWithoutData extends ClusterStub {
+
+ val clusterState = Json.parse(
+ """
+ |{
+ | "cluster_name":"elasticsearch",
+ | "master_node":"cPsT9o5FQ3WRnvqSTXHiVQ",
+ | "blocks":{
+ |
+ | },
+ | "routing_table":{
+ | "indices":{
+ |
+ | }
+ | },
+ | "routing_nodes":{
+ | "unassigned":[
+ |
+ | ],
+ | "nodes":{
+ | "MoDcZdJkQGK2RpYTvJhQlA":[
+ |
+ | ],
+ | "cPsT9o5FQ3WRnvqSTXHiVQ":[
+ |
+ | ]
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val nodesStats = Json.parse(
+ """
+ |{
+ | "cluster_name":"elasticsearch",
+ | "nodes":{
+ | "MoDcZdJkQGK2RpYTvJhQlA":{
+ | "timestamp":1458346589015,
+ | "name":"Solara",
+ | "transport_address":"127.0.0.1:9301",
+ | "host":"127.0.0.1",
+ | "ip":[
+ | "127.0.0.1:9301",
+ | "NONE"
+ | ],
+ | "os":{
+ | "timestamp":1458346589015,
+ | "load_average":3.17138671875,
+ | "mem":{
+ | "total_in_bytes":8589934592,
+ | "free_in_bytes":101085184,
+ | "used_in_bytes":8488849408,
+ | "free_percent":1,
+ | "used_percent":99
+ | },
+ | "swap":{
+ | "total_in_bytes":2147483648,
+ | "free_in_bytes":1736966144,
+ | "used_in_bytes":410517504
+ | }
+ | },
+ | "process":{
+ | "timestamp":1458346589015,
+ | "open_file_descriptors":257,
+ | "max_file_descriptors":10240,
+ | "cpu":{
+ | "percent":0,
+ | "total_in_millis":24084
+ | },
+ | "mem":{
+ | "total_virtual_in_bytes":5274689536
+ | }
+ | },
+ | "jvm":{
+ | "timestamp":1458346589015,
+ | "uptime_in_millis":1106048,
+ | "mem":{
+ | "heap_used_in_bytes":28420720,
+ | "heap_used_percent":2,
+ | "heap_committed_in_bytes":259522560,
+ | "heap_max_in_bytes":1037959168,
+ | "non_heap_used_in_bytes":50725848,
+ | "non_heap_committed_in_bytes":51486720,
+ | "pools":{
+ | "young":{
+ | "used_in_bytes":8929536,
+ | "max_in_bytes":286326784,
+ | "peak_used_in_bytes":71630848,
+ | "peak_max_in_bytes":286326784
+ | },
+ | "survivor":{
+ | "used_in_bytes":6942440,
+ | "max_in_bytes":35782656,
+ | "peak_used_in_bytes":8912888,
+ | "peak_max_in_bytes":35782656
+ | },
+ | "old":{
+ | "used_in_bytes":12548744,
+ | "max_in_bytes":715849728,
+ | "peak_used_in_bytes":12548744,
+ | "peak_max_in_bytes":715849728
+ | }
+ | }
+ | },
+ | "threads":{
+ | "count":67,
+ | "peak_count":87
+ | },
+ | "gc":{
+ | "collectors":{
+ | "young":{
+ | "collection_count":5,
+ | "collection_time_in_millis":76
+ | },
+ | "old":{
+ | "collection_count":1,
+ | "collection_time_in_millis":18
+ | }
+ | }
+ | },
+ | "buffer_pools":{
+ | "direct":{
+ | "count":71,
+ | "used_in_bytes":13640062,
+ | "total_capacity_in_bytes":13640062
+ | },
+ | "mapped":{
+ | "count":0,
+ | "used_in_bytes":0,
+ | "total_capacity_in_bytes":0
+ | }
+ | }
+ | },
+ | "fs":{
+ | "timestamp":1458346589015,
+ | "total":{
+ | "total_in_bytes":249804886016,
+ | "free_in_bytes":41567444992,
+ | "available_in_bytes":41305300992
+ | },
+ | "data":[
+ | {
+ | "path":"/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/1",
+ | "mount":"/ (/dev/disk1)",
+ | "type":"hfs",
+ | "total_in_bytes":249804886016,
+ | "free_in_bytes":41567444992,
+ | "available_in_bytes":41305300992
+ | }
+ | ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ":{
+ | "timestamp":1458346589015,
+ | "name":"Cecilia Reyes",
+ | "transport_address":"127.0.0.1:9300",
+ | "host":"127.0.0.1",
+ | "ip":[
+ | "127.0.0.1:9300",
+ | "NONE"
+ | ],
+ | "os":{
+ | "timestamp":1458346589015,
+ | "load_average":3.17138671875,
+ | "mem":{
+ | "total_in_bytes":8589934592,
+ | "free_in_bytes":101085184,
+ | "used_in_bytes":8488849408,
+ | "free_percent":1,
+ | "used_percent":99
+ | },
+ | "swap":{
+ | "total_in_bytes":2147483648,
+ | "free_in_bytes":1736966144,
+ | "used_in_bytes":410517504
+ | }
+ | },
+ | "process":{
+ | "timestamp":1458346589015,
+ | "open_file_descriptors":265,
+ | "max_file_descriptors":10240,
+ | "cpu":{
+ | "percent":0,
+ | "total_in_millis":23221
+ | },
+ | "mem":{
+ | "total_virtual_in_bytes":5287575552
+ | }
+ | },
+ | "jvm":{
+ | "timestamp":1458346589015,
+ | "uptime_in_millis":1114598,
+ | "mem":{
+ | "heap_used_in_bytes":24190184,
+ | "heap_used_percent":2,
+ | "heap_committed_in_bytes":259522560,
+ | "heap_max_in_bytes":1037959168,
+ | "non_heap_used_in_bytes":53616440,
+ | "non_heap_committed_in_bytes":54919168,
+ | "pools":{
+ | "young":{
+ | "used_in_bytes":4830480,
+ | "max_in_bytes":286326784,
+ | "peak_used_in_bytes":71630848,
+ | "peak_max_in_bytes":286326784
+ | },
+ | "survivor":{
+ | "used_in_bytes":4334552,
+ | "max_in_bytes":35782656,
+ | "peak_used_in_bytes":8912896,
+ | "peak_max_in_bytes":35782656
+ | },
+ | "old":{
+ | "used_in_bytes":15025152,
+ | "max_in_bytes":715849728,
+ | "peak_used_in_bytes":15025152,
+ | "peak_max_in_bytes":715849728
+ | }
+ | }
+ | },
+ | "threads":{
+ | "count":72,
+ | "peak_count":106
+ | },
+ | "gc":{
+ | "collectors":{
+ | "young":{
+ | "collection_count":6,
+ | "collection_time_in_millis":85
+ | },
+ | "old":{
+ | "collection_count":1,
+ | "collection_time_in_millis":12
+ | }
+ | }
+ | },
+ | "buffer_pools":{
+ | "direct":{
+ | "count":122,
+ | "used_in_bytes":18508157,
+ | "total_capacity_in_bytes":18508157
+ | },
+ | "mapped":{
+ | "count":0,
+ | "used_in_bytes":0,
+ | "total_capacity_in_bytes":0
+ | }
+ | },
+ | "classes":{
+ | "current_loaded_count":6988,
+ | "total_loaded_count":6988,
+ | "total_unloaded_count":0
+ | }
+ | },
+ | "fs":{
+ | "timestamp":1458346589015,
+ | "total":{
+ | "total_in_bytes":249804886016,
+ | "free_in_bytes":41567444992,
+ | "available_in_bytes":41305300992
+ | },
+ | "data":[
+ | {
+ | "path":"/Users/leonardo.menezes/Downloads/elasticsearch-2.1.0/data/elasticsearch/nodes/0",
+ | "mount":"/ (/dev/disk1)",
+ | "type":"hfs",
+ | "total_in_bytes":249804886016,
+ | "free_in_bytes":41567444992,
+ | "available_in_bytes":41305300992
+ | }
+ | ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val indicesStats = Json.parse(
+ """
+ |{
+ | "_shards":{
+ | "total":0,
+ | "successful":0,
+ | "failed":0
+ | },
+ | "_all":{
+ | "primaries":{
+ |
+ | },
+ | "total":{
+ |
+ | }
+ | },
+ | "indices":{
+ |
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val clusterSettings = Json.parse(
+ """
+ |{
+ | "persistent":{
+ |
+ | },
+ | "transient":{
+ |
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val aliases = Json.parse(
+ """
+ |{
+ |
+ |}
+ """.stripMargin
+ )
+
+ val clusterHealth = Json.parse(
+ """
+ |{
+ | "cluster_name":"elasticsearch",
+ | "status":"green",
+ | "timed_out":false,
+ | "number_of_nodes":2,
+ | "number_of_data_nodes":2,
+ | "active_primary_shards":0,
+ | "active_shards":0,
+ | "relocating_shards":0,
+ | "initializing_shards":0,
+ | "unassigned_shards":0,
+ | "delayed_unassigned_shards":0,
+ | "number_of_pending_tasks":0,
+ | "number_of_in_flight_fetch":0,
+ | "task_max_waiting_in_queue_millis":0,
+ | "active_shards_percent_as_number":100
+ |}
+ """.stripMargin
+ )
+
+ val nodes = Json.parse(
+ """
+ |{
+ | "cluster_name":"elasticsearch",
+ | "nodes":{
+ | "MoDcZdJkQGK2RpYTvJhQlA":{
+ | "name":"Solara",
+ | "transport_address":"127.0.0.1:9301",
+ | "host":"127.0.0.1",
+ | "ip":"127.0.0.1",
+ | "version":"2.1.0",
+ | "build":"72cd1f1",
+ | "http_address":"127.0.0.1:9201",
+ | "os":{
+ | "refresh_interval_in_millis":1000,
+ | "available_processors":8,
+ | "allocated_processors":8
+ | },
+ | "jvm":{
+ | "pid":60238,
+ | "version":"1.8.0_72",
+ | "vm_name":"Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version":"25.72-b15",
+ | "vm_vendor":"Oracle Corporation",
+ | "start_time_in_millis":1458345483045,
+ | "mem":{
+ | "heap_init_in_bytes":268435456,
+ | "heap_max_in_bytes":1037959168,
+ | "non_heap_init_in_bytes":2555904,
+ | "non_heap_max_in_bytes":0,
+ | "direct_max_in_bytes":1037959168
+ | },
+ | "gc_collectors":[
+ | "ParNew",
+ | "ConcurrentMarkSweep"
+ | ],
+ | "memory_pools":[
+ | "Code Cache",
+ | "Metaspace",
+ | "Compressed Class Space",
+ | "Par Eden Space",
+ | "Par Survivor Space",
+ | "CMS Old Gen"
+ | ]
+ | }
+ | },
+ | "cPsT9o5FQ3WRnvqSTXHiVQ":{
+ | "name":"Cecilia Reyes",
+ | "transport_address":"127.0.0.1:9300",
+ | "host":"127.0.0.1",
+ | "ip":"127.0.0.1",
+ | "version":"2.1.0",
+ | "build":"72cd1f1",
+ | "http_address":"127.0.0.1:9200",
+ | "os":{
+ | "refresh_interval_in_millis":1000,
+ | "name":"Mac OS X",
+ | "arch":"x86_64",
+ | "version":"10.11.3",
+ | "available_processors":8,
+ | "allocated_processors":8
+ | },
+ | "jvm":{
+ | "pid":60169,
+ | "version":"1.8.0_72",
+ | "vm_name":"Java HotSpot(TM) 64-Bit Server VM",
+ | "vm_version":"25.72-b15",
+ | "vm_vendor":"Oracle Corporation",
+ | "start_time_in_millis":1458345474505,
+ | "mem":{
+ | "heap_init_in_bytes":268435456,
+ | "heap_max_in_bytes":1037959168,
+ | "non_heap_init_in_bytes":2555904,
+ | "non_heap_max_in_bytes":0,
+ | "direct_max_in_bytes":1037959168
+ | },
+ | "gc_collectors":[
+ | "ParNew",
+ | "ConcurrentMarkSweep"
+ | ],
+ | "memory_pools":[
+ | "Code Cache",
+ | "Metaspace",
+ | "Compressed Class Space",
+ | "Par Eden Space",
+ | "Par Survivor Space",
+ | "CMS Old Gen"
+ | ]
+ | }
+ | }
+ | }
+ |}
+ """.stripMargin
+ )
+
+ val main = Json.parse(
+ """
+ |{
+ | "name":"Cecilia Reyes",
+ | "cluster_name":"elasticsearch",
+ | "version":{
+ | "number":"2.1.0",
+ | "build_hash":"72cd1f1a3eee09505e036106146dc1949dc5dc87",
+ | "build_timestamp":"2015-11-18T22:40:03Z",
+ | "build_snapshot":false,
+ | "lucene_version":"5.3.1"
+ | },
+ | "tagline":"You Know, for Search"
+ |}
+ """.stripMargin
+ )
+
+}