745ab42e38e033ffdaf7a1957813d95240355a86
[ccsdk/features.git] /
1 (function( $, app, i18n ) {
2
3         var ui = app.ns("ui");
4         var services = app.ns("services");
5
6         // ( master ) master = true, data = true 
7         // ( coordinator ) master = true, data = false
8         // ( worker ) master = false, data = true;
9         // ( client ) master = false, data = false;
10         // http enabled ?
11
12         function nodeSort_name(a, b) {
13                 if (!(a.cluster && b.cluster)) {
14                         return 0;
15                 }
16                 return a.cluster.name.toString().localeCompare( b.cluster.name.toString() );
17         }
18
19         function nodeSort_addr( a, b ) {
20                 if (!(a.cluster && b.cluster)) {
21                         return 0;
22                 }
23                 return a.cluster.transport_address.toString().localeCompare( b.cluster.transport_address.toString() );
24         }
25
26         function nodeSort_type( a, b ) {
27                 if (!(a.cluster && b.cluster)) {
28                         return 0;
29                 }
30                 if( a.master_node ) {
31                         return -1;
32                 } else if( b.master_node ) {
33                         return 1;
34                 } else if( a.data_node && !b.data_node ) {
35                         return -1;
36                 } else if( b.data_node && !a.data_node ) {
37                         return 1;
38                 } else {
39                         return a.cluster.name.toString().localeCompare( b.cluster.name.toString() );
40                 }
41         }
42
43         var NODE_SORT_TYPES = {
44                 "Sort.ByName": nodeSort_name,
45                 "Sort.ByAddress": nodeSort_addr,
46                 "Sort.ByType": nodeSort_type
47         };
48
49         function nodeFilter_none( a ) {
50                 return true;
51         }
52
53         function nodeFilter_clients( a ) {
54                 return (a.master_node || a.data_node );
55         }
56
57
58         ui.ClusterOverview = ui.Page.extend({
59                 defaults: {
60                         cluster: null // (reqired) an instanceof app.services.Cluster
61                 },
62                 init: function() {
63                         this._super();
64                         this.cluster = this.config.cluster;
65                         this.prefs = services.Preferences.instance();
66                         this._clusterState = this.config.clusterState;
67                         this._clusterState.on("data", this.draw_handler );
68                         this._refreshButton = new ui.RefreshButton({
69                                 onRefresh: this.refresh.bind(this),
70                                 onChange: function( btn ) {
71                                         if( btn.value === -1 ) {
72                                                 this.draw_handler();
73                                         }
74                                 }.bind( this )
75                         });
76                         var nodeSortPref = this.prefs.get("clusterOverview-nodeSort") || Object.keys(NODE_SORT_TYPES)[0];
77                         this._nodeSort = NODE_SORT_TYPES[ nodeSortPref ];
78                         this._nodeSortMenu = new ui.MenuButton({
79                                 label: i18n.text( "Preference.SortCluster" ),
80                                 menu: new ui.SelectMenuPanel({
81                                         value: nodeSortPref,
82                                         items: Object.keys( NODE_SORT_TYPES ).map( function( k ) {
83                                                 return { text: i18n.text( k ), value: k };
84                                         }),
85                                         onSelect: function( panel, event ) {
86                                                 this._nodeSort = NODE_SORT_TYPES[ event.value ];
87                                                 this.prefs.set("clusterOverview-nodeSort", event.value );
88                                                 this.draw_handler();
89                                         }.bind(this)
90                                 })
91                         });
92                         this._indicesSort = this.prefs.get( "clusterOverview-indicesSort") || "desc";
93                         this._indicesSortMenu = new ui.MenuButton({
94                                 label: i18n.text( "Preference.SortIndices" ),
95                                 menu: new ui.SelectMenuPanel({
96                                         value: this._indicesSort,
97                                         items: [
98                                                 { value: "desc", text: i18n.text( "SortIndices.Descending" ) },
99                                                 { value: "asc", text: i18n.text( "SortIndices.Ascending" ) } ],
100                                         onSelect: function( panel, event ) {
101                                                 this._indicesSort = event.value;
102                                                 this.prefs.set( "clusterOverview-indicesSort", this._indicesSort );
103                                                 this.draw_handler();
104                                         }.bind(this)
105                                 })
106                         });
107                         this._aliasRenderer = this.prefs.get( "clusterOverview-aliasRender" ) || "full";
108                         this._aliasMenu = new ui.MenuButton({
109                                 label: i18n.text( "Preference.ViewAliases" ),
110                                 menu: new ui.SelectMenuPanel({
111                                         value: this._aliasRenderer,
112                                         items: [
113                                                 { value: "full", text: i18n.text( "ViewAliases.Grouped" ) },
114                                                 { value: "list", text: i18n.text( "ViewAliases.List" ) },
115                                                 { value: "none", text: i18n.text( "ViewAliases.None" ) } ],
116                                         onSelect: function( panel, event ) {
117                                                 this._aliasRenderer = event.value;
118                                                 this.prefs.set( "clusterOverview-aliasRender", this._aliasRenderer );
119                                                 this.draw_handler();
120                                         }.bind(this)
121                                 })
122                         });
123                         this._indexFilter = new ui.TextField({
124                                 value: this.prefs.get("clusterOverview-indexFilter"),
125                                 placeholder: i18n.text( "Overview.IndexFilter" ),
126                                 onchange: function( indexFilter ) {
127                                         this.prefs.set("clusterOverview-indexFilter", indexFilter.val() );
128                                         this.draw_handler();
129                                 }.bind(this)
130                         });
131                         this.el = $(this._main_template());
132                         this.tablEl = this.el.find(".uiClusterOverview-table");
133                         this.refresh();
134                 },
135                 remove: function() {
136                         this._clusterState.removeObserver( "data", this.draw_handler );
137                 },
138                 refresh: function() {
139                         this._refreshButton.disable();
140                         this._clusterState.refresh();
141                 },
142                 draw_handler: function() {
143                         var data = this._clusterState;
144                         var indexFilter;
145                         try {
146                                 var indexFilterRe = new RegExp( this._indexFilter.val() );
147                                 indexFilter = function(s) { return indexFilterRe.test(s); };
148                         } catch(e) {
149                                 indexFilter = function() { return true; };
150                         }
151                         var clusterState = data.clusterState;
152                         var status = data.status;
153                         var nodeStats = data.nodeStats;
154                         var clusterNodes = data.clusterNodes;
155                         var nodes = [];
156                         var indices = [];
157                         var cluster = {};
158                         var nodeIndices = {};
159                         var indexIndices = {}, indexIndicesIndex = 0;
160                         function newNode(n) {
161                                 return {
162                                         name: n,
163                                         routings: [],
164                                         master_node: clusterState.master_node === n
165                                 };
166                         }
167                         function newIndex(i) {
168                                 return {
169                                         name: i,
170                                         replicas: []
171                                 };
172                         }
173                         function getIndexForNode(n) {
174                                 return nodeIndices[n] = (n in nodeIndices) ? nodeIndices[n] : nodes.push(newNode(n)) - 1;
175                         }
176                         function getIndexForIndex(routings, i) {
177                                 var index = indexIndices[i] = (i in indexIndices) ?
178                                                 (routings[indexIndices[i]] = routings[indexIndices[i]] || newIndex(i)) && indexIndices[i]
179                                                 : ( ( routings[indexIndicesIndex] = newIndex(i) )  && indexIndicesIndex++ );
180                                 indices[index] = i;
181                                 return index;
182                         }
183                         $.each(clusterNodes.nodes, function(name, node) {
184                                 getIndexForNode(name);
185                         });
186
187                         var indexNames = [];
188                         $.each(clusterState.routing_table.indices, function(name, index){
189                                 indexNames.push(name);
190                         });
191                         indexNames.sort();
192                         if (this._indicesSort === "desc") indexNames.reverse();
193                         indexNames.filter( indexFilter ).forEach(function(name) {
194                                 var indexObject = clusterState.routing_table.indices[name];
195                                 $.each(indexObject.shards, function(name, shard) {
196                                         shard.forEach(function(replica){
197                                                 var node = replica.node;
198                                                 if(node === null) { node = "Unassigned"; }
199                                                 var index = replica.index;
200                                                 var shard = replica.shard;
201                                                 var routings = nodes[getIndexForNode(node)].routings;
202                                                 var indexIndex = getIndexForIndex(routings, index);
203                                                 var replicas = routings[indexIndex].replicas;
204                                                 if(node === "Unassigned" || !indexObject.shards[shard]) {
205                                                         replicas.push({ replica: replica });
206                                                 } else {
207                                                         replicas[shard] = {
208                                                                 replica: replica,
209                                                                 status: indexObject.shards[shard].filter(function(replica) {
210                                                                         return replica.node === node;
211                                                                 })[0]
212                                                         };
213                                                 }
214                                         });
215                                 });
216                         });
217                         indices = indices.map(function(index){
218                                 return {
219                                         name: index,
220                                         state: "open",
221                                         metadata: clusterState.metadata.indices[index],
222                                         status: status.indices[index]
223                                 };
224                         }, this);
225                         $.each(clusterState.metadata.indices, function(name, index) {
226                                 if(index.state === "close" && indexFilter( name )) {
227                                         indices.push({
228                                                 name: name,
229                                                 state: "close",
230                                                 metadata: index,
231                                                 status: null
232                                         });
233                                 }
234                         });
235                         nodes.forEach(function(node) {
236                                 node.stats = nodeStats.nodes[node.name];
237                                 var cluster = clusterNodes.nodes[node.name];
238                                 node.cluster = cluster || { name: "<unknown>" };
239                                 node.data_node = !( cluster && cluster.attributes && cluster.attributes.data === "false" );
240                                 for(var i = 0; i < indices.length; i++) {
241                                         node.routings[i] = node.routings[i] || { name: indices[i].name, replicas: [] };
242                                         node.routings[i].max_number_of_shards = indices[i].metadata.settings["index.number_of_shards"];
243                                         node.routings[i].open = indices[i].state === "open";
244                                 }
245                         });
246                         var aliasesIndex = {};
247                         var aliases = [];
248                         var indexClone = indices.map(function() { return false; });
249                         $.each(clusterState.metadata.indices, function(name, index) {
250                                 index.aliases.forEach(function(alias) {
251                                         var aliasIndex = aliasesIndex[alias] = (alias in aliasesIndex) ? aliasesIndex[alias] : aliases.push( { name: alias, max: -1, min: 999, indices: [].concat(indexClone) }) - 1;
252                                         var indexIndex = indexIndices[name];
253                                         var aliasRow = aliases[aliasIndex];
254                                         aliasRow.min = Math.min(aliasRow.min, indexIndex);
255                                         aliasRow.max = Math.max(aliasRow.max, indexIndex);
256                                         aliasRow.indices[indexIndex] = indices[indexIndex];
257                                 });
258                         });
259                         cluster.aliases = aliases;
260                         cluster.nodes = nodes
261                                 .filter( nodeFilter_none )
262                                 .sort( this._nodeSort );
263                         indices.unshift({ name: null });
264                         this._drawNodesView( cluster, indices );
265                         this._refreshButton.enable();
266                 },
267                 _drawNodesView: function( cluster, indices ) {
268                         this._nodesView && this._nodesView.remove();
269                         this._nodesView = new ui.NodesView({
270                                 onRedraw: function() {
271                                         this.refresh();
272                                 }.bind(this),
273                                 interactive: ( this._refreshButton.value === -1 ),
274                                 aliasRenderer: this._aliasRenderer,
275                                 cluster: this.cluster,
276                                 data: {
277                                         cluster: cluster,
278                                         indices: indices
279                                 }
280                         });
281                         this._nodesView.attach( this.tablEl );
282                 },
283                 _main_template: function() {
284                         return { tag: "DIV", id: this.id(), cls: "uiClusterOverview", children: [
285                                 new ui.Toolbar({
286                                         label: i18n.text("Overview.PageTitle"),
287                                         left: [
288                                                 this._nodeSortMenu,
289                                                 this._indicesSortMenu,
290                                                 this._aliasMenu,
291                                                 this._indexFilter
292                                         ],
293                                         right: [
294                                                 this._refreshButton
295                                         ]
296                                 }),
297                                 { tag: "DIV", cls: "uiClusterOverview-table" }
298                         ] };
299                 }
300         });
301
302 })( this.jQuery, this.app, this.i18n );