Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to show more aliases #395

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM openjdk:11-jre-slim

ENV CEREBRO_VERSION 0.8.4

ADD target/universal/cerebro-${CEREBRO_VERSION}.tgz /opt

RUN mv /opt/cerebro-$CEREBRO_VERSION /opt/cerebro \
&& apt-get update \
&& apt-get install -y wget \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /opt/cerebro/logs \
&& sed -i '/<appender-ref ref="FILE"\/>/d' /opt/cerebro/conf/logback.xml \
&& addgroup -gid 1000 cerebro \
&& adduser -gid 1000 -uid 1000 cerebro \
&& chown -R cerebro:cerebro /opt/cerebro

WORKDIR /opt/cerebro
EXPOSE 9000
USER cerebro
ENTRYPOINT [ "/opt/cerebro/bin/cerebro" ]
3 changes: 2 additions & 1 deletion app/models/commons/NodeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ trait NodeInfo {
"ml.machine_memory",
"xpack.installed",
"transform.node",
"ml.max_open_jobs"
"ml.max_open_jobs",
"ml.max_jvm_size"
)

def attrs(info: JsValue) = {
Expand Down
2 changes: 1 addition & 1 deletion app/models/commons/NodeRoles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ object NodeRoles {

def apply(nodeInfo: JsValue): NodeRoles = {
// >= 7.10
val dataRoles = Seq("data", "data_content", "data_hot", "data_warm", "data_cold").map(JsString)
val dataRoles = Seq("data", "data_content", "data_hot", "data_warm", "data_cold", "data_frozen").map(JsString)

(nodeInfo \ "roles").asOpt[JsArray] match {
case Some(JsArray(roles)) => // >= 5.X
Expand Down
6 changes: 5 additions & 1 deletion app/models/nodes/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ object Node extends NodeInfo {
"master" -> JsBoolean(roles.master),
"coordinating" -> JsBoolean(roles.coordinating),
"ingest" -> JsBoolean(roles.ingest),
"data" -> JsBoolean(roles.data)
"data" -> JsBoolean(roles.data),
"roles" -> JsArray(info \ "roles" match {
case JsDefined(JsArray(roles)) => roles
case _ => Seq.empty
})
)
}

Expand Down
9 changes: 6 additions & 3 deletions app/models/overview/ClosedIndex.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package models.overview

import play.api.libs.json.{JsBoolean, JsString, Json}
import play.api.libs.json.{JsBoolean, JsNumber, JsString, JsValue, Json}

object ClosedIndex {

def apply(name: String) =
def apply(name: String, aliases: JsValue, numShards: JsNumber, numReplicas: JsNumber) =
Json.obj(
"name" -> JsString(name),
"closed" -> JsBoolean(true),
"special" -> JsBoolean(name.startsWith("."))
"special" -> JsBoolean(name.startsWith(".")),
"aliases" -> aliases,
"num_shards" -> numShards,
"num_replicas" -> numReplicas
)

}
6 changes: 5 additions & 1 deletion app/models/overview/ClusterOverview.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,13 @@ object ClusterOverview {
Index(index, indexStats, shards, indexAliases, indexBlock)
}.toSeq

val metadata = (clusterState \ "metadata" \ "indices").as[JsObject]
val closedIndices = blocks.value.collect { // ES < 7.X does not return routing_table for closed indices
case (name, block) if !routingTable.contains(name) && (block \ "4").isDefined =>
ClosedIndex(name)
val indexAliases = (metadata \ name \ "aliases").as[JsArray]
val numShards = JsNumber((metadata \ name \ "settings" \ "index" \ "number_of_shards").as[JsString].value.toInt)
val numReplicas = JsNumber((metadata \ name \ "settings" \ "index" \ "number_of_replicas").as[JsString].value.toInt)
ClosedIndex(name, indexAliases, numShards, numReplicas)
}

indices ++ closedIndices
Expand Down
2 changes: 2 additions & 0 deletions app/models/overview/Index.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ object Index {
"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.as[JsObject].keys.map(JsString(_)).toSeq), // 1.4 < does not return aliases obj
"is_write_true_aliases" -> JsArray(aliases.as[JsObject].fieldSet.filter(
_._2.as[JsObject].fieldSet.contains("is_write_index", JsBoolean(true))).map(_._1).map(JsString(_)).toSeq),
"num_shards" -> JsNumber((routingTable \ "shards").as[JsObject].keys.map(_.toInt).max + 1),
"num_replicas" -> JsNumber((routingTable \ "shards" \ "0").as[JsArray].value.size - 1),
"shards" -> JsObject(shardMap)
Expand Down
10 changes: 8 additions & 2 deletions app/models/overview/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ object Node extends NodeInfo {
"data" -> JsBoolean(nodeRoles.data),
"coordinating" -> JsBoolean(nodeRoles.coordinating),
"ingest" -> JsBoolean(nodeRoles.ingest),
"roles" -> JsArray(info \ "roles" match {
case JsDefined(JsArray(roles)) => roles
case _ => Seq.empty
}),
"heap" -> Json.obj(
"used" -> (stats \ "jvm" \ "mem" \ "heap_used_in_bytes").as[JsNumber],
"committed" -> (stats \ "jvm" \ "mem" \ "heap_committed_in_bytes").as[JsNumber],
Expand Down Expand Up @@ -59,8 +63,10 @@ object Node extends NodeInfo {
}

def cpuPercent(nodeStats: JsValue): JsNumber = {
val cpu = (nodeStats \ "os" \ "cpu" \ "percent").asOpt[Int].getOrElse(// 5.X
(nodeStats \ "os" \ "cpu_percent").asOpt[Int].getOrElse(0) // FIXME 2.X
val cpu = (nodeStats \ "os" \ "cpu" \ "percent").asOpt[Int].filter(i => i > 0).getOrElse(// 5.X
(nodeStats \ "process" \ "cpu" \ "percent").asOpt[Int].filter(i => i > 0).getOrElse( // 7.X
(nodeStats \ "os" \ "cpu_percent").asOpt[Int].getOrElse(0) // FIXME 2.X
)
)
JsNumber(BigDecimal(cpu))
}
Expand Down
2 changes: 1 addition & 1 deletion app/services/overview/OverviewDataService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class OverviewDataService @Inject()(client: ElasticClient) {

def overview(target: ElasticServer): Future[JsValue] = {
val apis = Seq(
"_cluster/state/master_node,routing_table,blocks",
"_cluster/state/master_node,routing_table,blocks,metadata",
"_nodes/stats/jvm,fs,os,process?human=true",
"_stats/docs,store?ignore_unavailable=true",
"_cluster/settings",
Expand Down
79 changes: 65 additions & 14 deletions public/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,7 @@ angular.module('cerebro').controller('OverviewController', ['$scope', '$http',
$scope.special_indices = 0;
$scope.shardAllocation = true;

$scope.indices_filter = new IndexFilter('', false, false, true, true, 0);
$scope.indices_filter = new IndexFilter('', [], false, false, true, true, 0);
$scope.nodes_filter = new NodeFilter('', true, false, false, false, 0);

$scope.getPageSize = function() {
Expand Down Expand Up @@ -1192,6 +1192,14 @@ angular.module('cerebro').controller('OverviewController', ['$scope', '$http',
$scope.$watch('nodes_filter', function() {
if ($scope.data) {
$scope.setNodes($scope.data.nodes);
if ($scope.nodes_filter.name) {
$scope.indices_filter.nodes = $scope.nodes.map(function (node) {
return node.id;
});
} else {
$scope.indices_filter.nodes = [];
}
$scope.setIndices($scope.data.indices);
}
},
true);
Expand Down Expand Up @@ -2265,8 +2273,9 @@ function GroupedSettings(settings) {
this.groups = Object.values(groups);
}

function IndexFilter(name, closed, special, healthy, asc, timestamp) {
function IndexFilter(name, nodes, closed, special, healthy, asc, timestamp) {
this.name = name;
this.nodes = nodes;
this.closed = closed;
this.special = special;
this.healthy = healthy;
Expand Down Expand Up @@ -2294,6 +2303,7 @@ function IndexFilter(name, closed, special, healthy, asc, timestamp) {
// eslint-disable-next-line no-unused-vars
return new IndexFilter(
this.name,
this.nodes,
this.closed,
this.special,
this.healthy,
Expand All @@ -2306,6 +2316,7 @@ function IndexFilter(name, closed, special, healthy, asc, timestamp) {
return (
other !== null &&
this.name === other.name &&
this.nodes === other.nodes &&
this.closed === other.closed &&
this.special === other.special &&
this.healthy === other.healthy &&
Expand Down Expand Up @@ -2360,6 +2371,12 @@ function IndexFilter(name, closed, special, healthy, asc, timestamp) {
}
}
}
if (matches && this.nodes.length > 0) {
var shardNodes = Object.keys(index.shards);
matches = this.nodes.filter(function(node) {
return shardNodes.indexOf(node) != -1;
}).length > 0;
}
return matches;
};
}
Expand Down Expand Up @@ -2402,11 +2419,53 @@ function NodeFilter(name, data, master, ingest, coordinating, timestamp) {
};

this.matches = function(node) {
if (this.isBlank()) {
return true;
} else {
return this.matchesName(node.name) && this.matchesType(node);
var matches = true;
if (!this.matchesType(node)) {
matches = false;
}
if (matches && this.name) {
try {
var regExp = new RegExp(this.name.trim(), 'i');
matches = regExp.test(node.name);
if (!matches) {
var attrs = Object.values(node.attributes);
for (var idx = 0; idx < attrs.length; idx++) {
if ((matches = regExp.test(attrs[idx]))) {
break;
}
}
}
if (!matches) {
for (idx = 0; idx < node.roles.length; idx++) {
if ((matches = regExp.test(node.roles[idx]))) {
break;
}
}
}
} catch (err) { // if not valid regexp, still try normal matching
matches = node.name.indexOf(this.name.toLowerCase()) != -1;
if (!matches) {
var _attrs = Object.values(node.attributes);
for (var _idx = 0; _idx < _attrs.length; _idx++) {
var attr = _attrs[_idx].toLowerCase();
matches = true;
if ((matches = (attr.indexOf(this.name.toLowerCase()) != -1))) {
break;
}
}
}
if (!matches) {
for (_idx = 0; _idx < node.roles.length; _idx++) {
var role = node.roles[_idx].toLowerCase();
matches = true;
if ((matches = (role.indexOf(this.name.toLowerCase()) != -1))) {
break;
}
}
}
}
}
return matches;
};

this.matchesType = function(node) {
Expand All @@ -2417,14 +2476,6 @@ function NodeFilter(name, data, master, ingest, coordinating, timestamp) {
node.coordinating && this.coordinating
);
};

this.matchesName = function(name) {
if (this.name) {
return name.toLowerCase().indexOf(this.name.toLowerCase()) != -1;
} else {
return true;
}
};
}

// eslint-disable-next-line no-unused-vars
Expand Down
5 changes: 4 additions & 1 deletion public/nodes/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="col-lg-3 col-md-4 col-sm-5 col-xs-12 form-group">
<input type="text" ng-model="filter.name"
class="form-control form-control-sm"
placeholder="filter nodes by name">
placeholder="filter nodes and indices by nodes">
</div>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12 noselect">
<div class="checkbox">
Expand Down Expand Up @@ -86,6 +86,9 @@
<span ng-repeat="(attr, value) in node.attributes">
<span class="label label-success" title="{{attr}}">{{value}}</span>
</span>
<span ng-repeat="value in node.roles">
<span class="label label-success" ng-show="['data_content','data_hot','data_warm','data_cold','data_frozen'].includes(value)">{{value}}</span>
</span>
</div>
</div>
<div class="node-labels">
Expand Down
36 changes: 25 additions & 11 deletions public/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<div class="row">
<div class="col-lg-6 col-sm-6 form-group">
<input type="text" ng-model="nodes_filter.name" class="form-control form-control-sm"
placeholder="filter nodes by name">
placeholder="filter nodes and indices by nodes">
</div>
</div>
</div>
Expand Down Expand Up @@ -63,18 +63,18 @@
<i class="fa fa-lock fa-2x table-control red normal-action" title="enable shard allocation" ng-click="enableShardAllocation()"
ng-hide="shardAllocation"></i>
</div>
<div class="col-lg-3 col-md-6">
<i class="fa fa-expand fa-2x normal-action table-control" ng-hide="expandedView"
title="expand view" ng-click="expandedView = true"></i>
<i class="fa fa-compress fa-2x normal-action table-control" ng-show="expandedView"
title="condense view" ng-click="expandedView = false"></i>
</div>
<div class="col-lg-3 col-md-6">
<i class="fa fa-sort-alpha-asc fa-2x normal-action table-control" title="sort ascending"
ng-show="indices_filter.asc" ng-click="indices_filter.asc = false"></i>
<i class="fa fa-sort-alpha-desc fa-2x normal-action table-control" title="sort descending"
ng-hide="indices_filter.asc" ng-click="indices_filter.asc = true"></i>
</div>
<div class="col-lg-3 col-md-6">
<i class="fa fa-eye fa-2x normal-action table-control" ng-hide="showAllAliases"
title="show all aliases" ng-click="showAllAliases = true"></i>
<i class="fa fa-eye-slash fa-2x normal-action table-control" ng-show="showAllAliases"
title="show single alias" ng-click="showAllAliases = false"></i>
</div>
<div class="col-lg-3 col-md-6">
<div class="dropdown">
<span class="title normal-action" type="button" id="dropcluster" data-toggle="dropdown"
Expand Down Expand Up @@ -157,9 +157,19 @@
</ul>
</div>
<div class="subtitle" ng-show="index.aliases.length">
<div class="title">
<i class="fa fa-tag"></i> {{index.aliases[0]}}
<span ng-show="index.aliases.length > 1">(+{{index.aliases.length - 1}})</span>
<div ng-hide="showAllAliases" class="title">
<span ng-show="index.aliases.length == 1">
<span ng-show="index.is_write_true_aliases.includes(index.aliases[0])"><i class="fa fa-tag alert-info"></i> {{index.aliases[0]}}</span>
<span ng-hide="index.is_write_true_aliases.includes(index.aliases[0])"><i class="fa fa-tag"></i> {{index.aliases[0]}}</span>
</span>
<span ng-show="index.aliases.length > 1">
<span ng-show="index.is_write_true_aliases.includes(index.aliases[0])"><i class="fa fa-tags alert-info"></i> {{index.aliases[0]}}(+{{index.aliases.length - 1}})</span>
<span ng-hide="index.is_write_true_aliases.includes(index.aliases[0])"><i class="fa fa-tags"></i> {{index.aliases[0]}}(+{{index.aliases.length - 1}})</span>
</span>
</div>
<div ng-show="showAllAliases" class="title" ng-repeat="alias in index.aliases">
<span ng-show="index.is_write_true_aliases.includes(alias)"><i class="fa fa-tag alert-info"></i> {{alias}}</span>
<span ng-hide="index.is_write_true_aliases.includes(alias)"><i class="fa fa-tag"></i> {{alias}}</span>
</div>
</div>
<div class="detail">
Expand All @@ -169,6 +179,7 @@
<span><small>size: {{index.size_in_bytes | bytes}}</small></span>
</span>
<span ng-show="index.closed">
<span><small>shards: {{index.num_shards}} * {{index.num_replicas + 1}}</small></span><br>
<span><small><i>index closed</i></small></span>
</span>
</div>
Expand Down Expand Up @@ -235,9 +246,12 @@
<span ng-repeat="(attr, value) in node.attributes">
<span class="label label-success" title="{{attr}}">{{value}}</span>
</span>
<span ng-repeat="value in node.roles">
<span class="label label-success" ng-show="['data_content','data_hot','data_warm','data_cold','data_frozen'].includes(value)">{{value}}</span>
</span>
</div>
</div>
<div ng-show="expandedView" class="node-labels">
<div class="node-labels">
<span class="label label-primary">JVM: {{node.jvm_version}}</span>
<span class="label label-primary">ES: {{node.es_version}}</span>
</div>
Expand Down
10 changes: 9 additions & 1 deletion src/app/components/overview/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ angular.module('cerebro').controller('OverviewController', ['$scope', '$http',
$scope.special_indices = 0;
$scope.shardAllocation = true;

$scope.indices_filter = new IndexFilter('', false, false, true, true, 0);
$scope.indices_filter = new IndexFilter('', [], false, false, true, true, 0);
$scope.nodes_filter = new NodeFilter('', true, false, false, false, 0);

$scope.getPageSize = function() {
Expand Down Expand Up @@ -93,6 +93,14 @@ angular.module('cerebro').controller('OverviewController', ['$scope', '$http',
$scope.$watch('nodes_filter', function() {
if ($scope.data) {
$scope.setNodes($scope.data.nodes);
if ($scope.nodes_filter.name) {
$scope.indices_filter.nodes = $scope.nodes.map(function (node) {
return node.id;
});
} else {
$scope.indices_filter.nodes = [];
}
$scope.setIndices($scope.data.indices);
}
},
true);
Expand Down
Loading