module.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*
  2. ## bbuzz
  3. A special panel for my Berlin Buzzwords talk
  4. ### Parameters
  5. * None
  6. ### Group Events
  7. #### Sends
  8. * get_time :: On panel initialization get time range to query
  9. #### Receives
  10. * time :: An object containing the time range to use and the index(es) to query
  11. */
  12. angular.module('kibana.bbuzz', [])
  13. .controller('bbuzz', function($scope, eventBus, $http, bbuzz) {
  14. // Set and populate defaults
  15. var _d = {
  16. group : "default",
  17. }
  18. _.defaults($scope.panel,_d)
  19. $scope.init = function () {
  20. $scope.nodes = {};
  21. $scope.settings = {};
  22. $scope.indices = [];
  23. $scope.bbuzz = bbuzz
  24. $scope.colors = bbuzz.colors(20)
  25. eventBus.register($scope,'time', function(event,time){
  26. set_time(time)
  27. });
  28. // Now that we're all setup, request the time from our group
  29. eventBus.broadcast($scope.$id,$scope.panel.group,'get_time')
  30. }
  31. $scope.set_replicas = function(replicas) {
  32. $http.put(config.elasticsearch+'/_settings', {
  33. "index" : {"number_of_replicas" : replicas}
  34. }).success(function (data) {
  35. $scope.get_data();
  36. });
  37. }
  38. $scope.status = function(ip) {
  39. var something = $http({
  40. url: "http://"+ip+':4567/status',
  41. method: "GET"
  42. }).error(function(data, status, headers, config) {
  43. $scope.error = status;
  44. });
  45. return something.then(function(p) {
  46. return p.data
  47. });
  48. }
  49. $scope.node_mode = function(ip,mode) {
  50. $http({method: 'GET', url: "http://"+ip+':4567/'+mode}).
  51. success(function(data, status, headers, config) {
  52. control.log(data)
  53. $scope.get_data();
  54. }).
  55. error(function(data, status, headers, config) {
  56. console.log(data, status)
  57. $scope.get_data();
  58. });
  59. }
  60. $scope.get_data = function() {
  61. // Get cluster health
  62. if (!_.isNumber($scope.settings.replicas)) {
  63. $http({method: 'GET', url: config.elasticsearch+'/_settings'}).
  64. success(function(data, status, headers, config) {
  65. $scope.settings.replicas = parseInt(_.pairs(data)[0][1].settings['index.number_of_replicas'])
  66. }).
  67. error(function(data, status, headers, config) {
  68. console.log('Could not contact elasticsearch at: '+config.elasticsearch)
  69. });
  70. }
  71. // Get cluster health
  72. $http({method: 'GET', url: config.elasticsearch+'/_cluster/health'}).
  73. success(function(data, status, headers, config) {
  74. $scope.cluster = data
  75. }).
  76. error(function(data, status, headers, config) {
  77. console.log('Could not contact elasticsearch at: '+config.elasticsearch)
  78. });
  79. // And nodes list
  80. $http({method: 'GET', url: config.elasticsearch+'/_cluster/state'}).
  81. success(function(data, status, headers, config) {
  82. var i = []
  83. _.each(data.routing_nodes.nodes, function(v,node) {
  84. i[node] = _.groupBy(v,'index')
  85. })
  86. $scope.nodes.routing = i;
  87. $scope.nodes.info = data.nodes
  88. $scope.nodes.live = _.pluck(data.nodes,'transport_address'),
  89. $scope.nodes.dead = _.difference(bbuzz.get_nodes(),_.pluck(data.nodes,'transport_address'))
  90. //$scope.nodes.dead = ['inet[/10.126.115.79:9300]'];
  91. $scope.indices = _.union($scope.indices,_.keys(i))
  92. _.each($scope.nodes.dead,function(node) {
  93. $http({
  94. url: "http://"+bbuzz.ip_address(node)+':4567/status',
  95. method: "GET"
  96. }).success(function(data, status, headers, config) {
  97. if(_.isUndefined($scope.nodes.status))
  98. $scope.nodes.status = {};
  99. $scope.nodes.status[node] = 'data';
  100. })
  101. })
  102. }).
  103. error(function(data, status, headers, config) {
  104. console.log('Could not contact elasticsearch at: '+config.elasticsearch)
  105. });
  106. }
  107. // returns list of shards sorted by index
  108. $scope.sorted_shards = function(shards) {
  109. return _.sortBy(shards, function(shard) {
  110. return shard.index
  111. })
  112. }
  113. $scope.primary = function(shards,primary) {
  114. return _.filter(shards, function(shard) {
  115. return shard.primary === primary ? true: false;
  116. })
  117. }
  118. $scope.shard_class = function(state) {
  119. switch(state)
  120. {
  121. case 'INITIALIZING':
  122. return ['animated','flash','infinite']
  123. case 'RELOCATING':
  124. return ['faded']
  125. default:
  126. return ''
  127. }
  128. }
  129. $scope.cluster_class = function(state) {
  130. switch(state)
  131. {
  132. case 'green':
  133. return 'btn-success'
  134. case 'yellow':
  135. return 'btn-warning'
  136. case 'red':
  137. return 'btn-danger'
  138. default:
  139. return 'btn-inverse'
  140. }
  141. }
  142. $scope.cluster_color = function(state) {
  143. switch(state)
  144. {
  145. case 'green':
  146. var style = {color: '#FFF', bg: '#5BB75B', light: '#62C462', dark: '#51A351'}
  147. break;
  148. case 'yellow':
  149. var style = {color: '#FFF', bg: '#FAA732', light: '#FBB450', dark: '#F89406'}
  150. break;
  151. case 'red':
  152. var style = {color: '#FFF', bg: "#DA4F49", light: '#EE5F5B', dark: '#BD362F'}
  153. break;
  154. default:
  155. var style = {color: '#000', bg: "#F5F5F5", light: '#FFFFFF', dark: '#E6E6E6'}
  156. break;
  157. }
  158. return {
  159. 'color': style.color,
  160. 'margin-bottom': '0px',
  161. 'font-weight': 200,
  162. 'background-color': style.bg,
  163. 'background-image': 'linear-gradient(to bottom, '+style.light+', '+style.dark+')',
  164. 'background-repeat': 'repeat-x',
  165. 'border-color': 'rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25)',
  166. 'border-style': 'solid',
  167. 'border-width': '1px',
  168. 'box-shadow': '0 1px 0 rgba(255, 255, 255, 0.2) inset, 0 1px 2px rgba(0, 0, 0, 0.05)',
  169. 'padding': '10px'
  170. };
  171. }
  172. function set_time(time) {
  173. $scope.time = time;
  174. $scope.get_data();
  175. }
  176. }).directive('started', function(eventBus) {
  177. return {
  178. restrict: 'C',
  179. link: function(scope, elem, attrs, ctrl) {
  180. console.log('shard')
  181. // Receive render events
  182. scope.$on('render',function(){
  183. render_panel();
  184. });
  185. // Re-render if the window is resized
  186. angular.element(window).bind('resize', function(){
  187. render_panel();
  188. });
  189. // Function for rendering panel
  190. function render_panel() {
  191. var scripts = $LAB.script("common/lib/panels/jquery.flot.js")
  192. // Populate element.
  193. scripts.wait(function(){
  194. try {
  195. } catch(e) {
  196. elem.text(e)
  197. }
  198. })
  199. }
  200. }
  201. };
  202. }).service('bbuzz', function($timeout) {
  203. var nodes = [];
  204. var indices = [];
  205. this.index_id = function(id) {
  206. if (!_.contains(indices,id))
  207. indices.push(id)
  208. return _.indexOf(indices,id)
  209. }
  210. this.index_color = function(id) {
  211. var i = this.index_id(id)
  212. var colors = this.colors(indices.length)
  213. return colors[i];
  214. }
  215. this.ip_address = function(transport_address) {
  216. return transport_address.split(/[\/:]/)[1]
  217. }
  218. this.node_id = function(id) {
  219. if (!_.contains(nodes,id))
  220. nodes.push(id)
  221. return _.indexOf(nodes,id)
  222. }
  223. this.get_nodes = function() {
  224. return nodes;
  225. }
  226. this.picture = function(id) {
  227. return 'panels/bbuzz/img/'+this.node_id(id)+'.jpg'
  228. }
  229. this.colors = function(count) {
  230. // produce colors as needed
  231. var seed = ['#86B22D','#BF6730','#1D7373','#BFB930','#BF3030','#77207D']
  232. var colors = [], variation = 0;
  233. i = 0;
  234. while (colors.length < count) {
  235. var c;
  236. if (seed.length == i) // check degenerate case
  237. c = new Color(100, 100, 100);
  238. else
  239. c = parseColor(seed[i]);
  240. // vary color if needed
  241. var sign = variation % 2 == 1 ? -1 : 1;
  242. var factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
  243. c.scale(factor, factor, factor);
  244. // FIXME: if we're getting to close to something else,
  245. // we should probably skip this one
  246. colors.push(c.toString());
  247. ++i;
  248. if (i >= seed.length) {
  249. i = 0;
  250. ++variation;
  251. }
  252. }
  253. return colors;
  254. }
  255. function parseColor(str) {
  256. var result;
  257. // Look for #a0b1c2
  258. if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))
  259. return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));
  260. // Look for #fff
  261. if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))
  262. return new Color(parseInt(result[1]+result[1], 16), parseInt(result[2]+result[2], 16), parseInt(result[3]+result[3], 16));
  263. }
  264. // color helpers, inspiration from the jquery color animation
  265. // plugin by John Resig
  266. function Color (r, g, b, a) {
  267. var rgba = ['r','g','b','a'];
  268. var x = 4; //rgba.length
  269. while (-1<--x) {
  270. this[rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);
  271. }
  272. this.toString = function() {
  273. if (this.a >= 1.0) {
  274. return "rgb("+[this.r,this.g,this.b].join(",")+")";
  275. } else {
  276. return "rgba("+[this.r,this.g,this.b,this.a].join(",")+")";
  277. }
  278. };
  279. this.scale = function(rf, gf, bf, af) {
  280. x = 4; //rgba.length
  281. while (-1<--x) {
  282. if (arguments[x] != null)
  283. this[rgba[x]] *= arguments[x];
  284. }
  285. return this.normalize();
  286. };
  287. this.adjust = function(rd, gd, bd, ad) {
  288. x = 4; //rgba.length
  289. while (-1<--x) {
  290. if (arguments[x] != null)
  291. this[rgba[x]] += arguments[x];
  292. }
  293. return this.normalize();
  294. };
  295. this.clone = function() {
  296. return new Color(this.r, this.b, this.g, this.a);
  297. };
  298. var limit = function(val,minVal,maxVal) {
  299. return Math.max(Math.min(val, maxVal), minVal);
  300. };
  301. this.normalize = function() {
  302. this.r = clamp(0, parseInt(this.r), 255);
  303. this.g = clamp(0, parseInt(this.g), 255);
  304. this.b = clamp(0, parseInt(this.b), 255);
  305. this.a = clamp(0, this.a, 1);
  306. return this;
  307. };
  308. this.normalize();
  309. }
  310. function clamp(min, value, max) {
  311. if (value < min)
  312. return min;
  313. else if (value > max)
  314. return max;
  315. else
  316. return value;
  317. }
  318. })