summary.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with this
  4. * work for additional information regarding copyright ownership. The ASF
  5. * licenses this file to you under the Apache License, Version 2.0 (the
  6. * "License"); you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. * License for the specific language governing permissions and limitations under
  15. * the License.
  16. */
  17. var App = require('app');
  18. var batchUtils = require('utils/batch_scheduled_requests');
  19. require('views/main/service/service');
  20. require('data/service_graph_config');
  21. App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, {
  22. templateName: require('templates/main/service/info/summary'),
  23. attributes:null,
  24. /**
  25. * @property {String} templatePathPrefix - base path for custom templates
  26. * if you want to add custom template, add <service_name>.hbs file to
  27. * templates/main/service/info/summary folder.
  28. */
  29. templatePathPrefix: 'templates/main/service/info/summary/',
  30. /** @property {Ember.View} serviceSummaryView - view to embed, computed in
  31. * <code>loadServiceSummary()</code>
  32. */
  33. serviceSummaryView: null,
  34. /**
  35. * @property {Object} serviceCustomViewsMap - custom views to embed
  36. *
  37. */
  38. serviceCustomViewsMap: function() {
  39. return {
  40. HBASE: App.MainDashboardServiceHbaseView,
  41. HDFS: App.MainDashboardServiceHdfsView,
  42. STORM: App.MainDashboardServiceStormView,
  43. YARN: App.MainDashboardServiceYARNView,
  44. FLUME: Em.View.extend({
  45. template: Em.Handlebars.compile('' +
  46. '<tr>' +
  47. '<td>' +
  48. '{{view App.MainDashboardServiceFlumeView serviceBinding="view.service"}}' +
  49. '</td>' +
  50. '</tr>')
  51. })
  52. }
  53. }.property('serviceName'),
  54. /** @property collapsedMetrics {object[]} - metrics list for collapsed section
  55. * structure of element from list:
  56. * @property {string} header - title for section
  57. * @property {string} id - id of section for toggling, like: metric1
  58. * @property {string} toggleIndex - passed to `data-parent` attribute, like: #metric1
  59. * @property {Em.View} metricView - metric view class
  60. */
  61. collapsedSections: null,
  62. servicesHaveClients: function() {
  63. return App.get('services.hasClient');
  64. }.property('App.services.hasClient'),
  65. hasManyServers: function () {
  66. return this.get('servers').length > 1;
  67. }.property('servers'),
  68. clientsHostText: function () {
  69. if (this.get('controller.content.installedClients').length == 0) {
  70. return '';
  71. } else if (this.get("hasManyClients")) {
  72. return Em.I18n.t('services.service.summary.viewHosts');
  73. } else {
  74. return Em.I18n.t('services.service.summary.viewHost');
  75. }
  76. }.property("hasManyClients"),
  77. hasManyClients: function () {
  78. return this.get('controller.content.installedClients').length > 1;
  79. }.property('service.installedClients'),
  80. servers: function () {
  81. var result = [];
  82. var service = this.get('controller.content');
  83. if (service.get("id") == "ZOOKEEPER" || service.get("id") == "FLUME") {
  84. var servers = service.get('hostComponents').filterProperty('isMaster');
  85. if (servers.length > 0) {
  86. result = [
  87. {
  88. 'host': servers[0].get('displayName'),
  89. 'isComma': false,
  90. 'isAnd': false
  91. }
  92. ];
  93. }
  94. if (servers.length > 1) {
  95. result[0].isComma = true;
  96. result.push({
  97. 'host': servers[1].get('displayName'),
  98. 'isComma': false,
  99. 'isAnd': false
  100. });
  101. }
  102. if (servers.length > 2) {
  103. result[1].isAnd = true;
  104. result.push({
  105. 'host': Em.I18n.t('services.service.info.summary.serversHostCount').format(servers.length - 2),
  106. 'isComma': false,
  107. 'isAnd': false
  108. });
  109. }
  110. }
  111. return result;
  112. }.property('controller.content'),
  113. historyServerUI: function(){
  114. var service=this.get('controller.content');
  115. return (App.singleNodeInstall ? "http://" + App.singleNodeAlias + ":19888" : "http://" + service.get("hostComponents").findProperty('isMaster', true).get("host").get("publicHostName")+":19888");
  116. }.property('controller.content'),
  117. /**
  118. * Property related to ZOOKEEPER service, is unused for other services
  119. * @return {Object}
  120. */
  121. serversHost: function() {
  122. var service = this.get('controller.content');
  123. if (service.get("id") == "ZOOKEEPER" || service.get("id") == "FLUME") {
  124. var servers = service.get('hostComponents').filterProperty('isMaster');
  125. if (servers.length > 0) {
  126. return servers[0];
  127. }
  128. }
  129. return {};
  130. }.property('controller.content'),
  131. mastersObj: function() {
  132. return this.get('service.hostComponents').filterProperty('isMaster', true);
  133. }.property('service'),
  134. /**
  135. * Contain array with list of client components models <code>App.ClientComponent</code>.
  136. * @type {Array}
  137. */
  138. clientObj: function () {
  139. var clientComponents = this.get('controller.content.clientComponents').toArray();
  140. return clientComponents.get('length') ? clientComponents : [];
  141. }.property('service.clientComponents.@each.totalCount'),
  142. /**
  143. * Contain array with list of slave components models <code>App.SlaveComponent</code>.
  144. * @type {Array}
  145. */
  146. slavesObj: function() {
  147. var slaveComponents = this.get('controller.content.slaveComponents').toArray();
  148. return slaveComponents.get('length') ? slaveComponents : [];
  149. }.property('service.slaveComponents.@each.totalCount', 'service.slaveComponents.@each.startedCount'),
  150. data:{
  151. hive:{
  152. "database":"PostgreSQL",
  153. "databaseName":"hive",
  154. "user":"hive"
  155. }
  156. },
  157. /**
  158. * Wrapper for displayName. used to render correct display name for mysql_server
  159. */
  160. componentNameView: Ember.View.extend({
  161. template: Ember.Handlebars.compile('{{view.displayName}}'),
  162. comp : null,
  163. displayName: function(){
  164. if(this.get('comp.componentName') == 'MYSQL_SERVER'){
  165. return this.t('services.hive.databaseComponent');
  166. }
  167. return this.get('comp.displayName');
  168. }.property('comp')
  169. }),
  170. service:function () {
  171. var svc = this.get('controller.content');
  172. var svcName = svc.get('serviceName');
  173. if (svcName) {
  174. switch (svcName.toLowerCase()) {
  175. case 'hdfs':
  176. svc = App.HDFSService.find().objectAt(0);
  177. break;
  178. case 'yarn':
  179. svc = App.YARNService.find().objectAt(0);
  180. break;
  181. case 'hbase':
  182. svc = App.HBaseService.find().objectAt(0);
  183. break;
  184. case 'flume':
  185. svc = App.FlumeService.find().objectAt(0);
  186. break;
  187. case 'storm':
  188. svc = App.StormService.find().objectAt(0);
  189. break;
  190. default:
  191. break;
  192. }
  193. }
  194. return svc;
  195. }.property('controller.content.serviceName').volatile(),
  196. isHide:true,
  197. moreStatsView:Em.View.extend({
  198. tagName:"a",
  199. template:Ember.Handlebars.compile('{{t services.service.summary.moreStats}}'),
  200. attributeBindings:[ 'href' ],
  201. classNames:[ 'more-stats' ],
  202. click:function (event) {
  203. this._parentView._parentView.set('isHide', false);
  204. this.remove();
  205. },
  206. href:'javascript:void(null)'
  207. }),
  208. serviceName:function () {
  209. return this.get('service.serviceName');
  210. }.property('service'),
  211. oldServiceName:'',
  212. /*
  213. * 'Restart Required bar' start
  214. */
  215. componentsCount: null,
  216. hostsCount: null,
  217. alertsCount: function () {
  218. return this.get('controller.content.alertsCount');
  219. }.property('controller.content.alertsCount'),
  220. hasCriticalAlerts: function () {
  221. return this.get('controller.content.hasCriticalAlerts');
  222. }.property('controller.content.alertsCount'),
  223. /**
  224. * Define if service has alert definitions defined
  225. * @type {Boolean}
  226. */
  227. hasAlertDefinitions: function () {
  228. return App.AlertDefinition.find().someProperty('serviceName', this.get('controller.content.serviceName'));
  229. }.property('controller.content.serviceName'),
  230. restartRequiredHostsAndComponents:function () {
  231. return this.get('controller.content.restartRequiredHostsAndComponents');
  232. }.property('controller.content.restartRequiredHostsAndComponents'),
  233. updateComponentInformation: function() {
  234. var hc = this.get('restartRequiredHostsAndComponents');
  235. var hostsCount = 0;
  236. var componentsCount = 0;
  237. for (var host in hc) {
  238. hostsCount++;
  239. componentsCount += hc[host].length;
  240. }
  241. this.set('componentsCount', componentsCount);
  242. this.set('hostsCount', hostsCount);
  243. }.observes('restartRequiredHostsAndComponents'),
  244. rollingRestartSlaveComponentName : function() {
  245. return batchUtils.getRollingRestartComponentName(this.get('serviceName'));
  246. }.property('serviceName'),
  247. rollingRestartActionName : function() {
  248. var label = null;
  249. var componentName = this.get('rollingRestartSlaveComponentName');
  250. if (componentName) {
  251. label = Em.I18n.t('rollingrestart.dialog.title').format(App.format.role(componentName));
  252. }
  253. return label;
  254. }.property('rollingRestartSlaveComponentName'),
  255. showComponentsShouldBeRestarted: function () {
  256. var rhc = this.get('restartRequiredHostsAndComponents');
  257. App.router.get('mainServiceInfoConfigsController').showComponentsShouldBeRestarted(rhc);
  258. },
  259. showHostsShouldBeRestarted: function () {
  260. var rhc = this.get('restartRequiredHostsAndComponents');
  261. App.router.get('mainServiceInfoConfigsController').showHostsShouldBeRestarted(rhc);
  262. },
  263. restartAllStaleConfigComponents: function () {
  264. var self = this;
  265. var serviceDisplayName = this.get('service.displayName');
  266. var bodyMessage = Em.Object.create({
  267. confirmMsg: Em.I18n.t('services.service.restartAll.confirmMsg').format(serviceDisplayName),
  268. confirmButton: Em.I18n.t('services.service.restartAll.confirmButton'),
  269. additionalWarningMsg: this.get('service.passiveState') === 'OFF' ? Em.I18n.t('services.service.restartAll.warningMsg.turnOnMM').format(serviceDisplayName) : null
  270. });
  271. return App.showConfirmationFeedBackPopup(function (query) {
  272. var selectedService = self.get('service.id');
  273. batchUtils.restartAllServiceHostComponents(selectedService, true, query);
  274. }, bodyMessage);
  275. },
  276. rollingRestartStaleConfigSlaveComponents: function (componentName) {
  277. batchUtils.launchHostComponentRollingRestart(componentName.context, this.get('service.displayName'), this.get('service.passiveState') === "ON", true);
  278. },
  279. /*
  280. * 'Restart Required bar' ended
  281. */
  282. /*
  283. * Find the graph class associated with the graph name, and split
  284. * the array into sections of 2 for displaying on the page
  285. * (will only display rows with 2 items)
  286. */
  287. constructGraphObjects: function(graphNames) {
  288. var result = [], graphObjects = [], chunkSize = 2;
  289. var self = this;
  290. if (!graphNames) {
  291. self.set('serviceMetricGraphs', []);
  292. self.set('isServiceMetricLoaded', true);
  293. return;
  294. }
  295. // load time range for current service from server
  296. self.getUserPref(self.get('persistKey')).complete(function () {
  297. var index = self.get('currentTimeRangeIndex');
  298. graphNames.forEach(function(graphName) {
  299. graphObjects.push(App["ChartServiceMetrics" + graphName].extend({
  300. currentTimeIndex : index
  301. }));
  302. });
  303. while(graphObjects.length) {
  304. result.push(graphObjects.splice(0, chunkSize));
  305. }
  306. self.set('serviceMetricGraphs', result);
  307. self.set('isServiceMetricLoaded', true);
  308. });
  309. },
  310. /**
  311. * Contains graphs for this particular service
  312. */
  313. serviceMetricGraphs: [],
  314. isServiceMetricLoaded: false,
  315. /**
  316. * Key-name to store time range in Persist
  317. * @type {string}
  318. */
  319. persistKey: function () {
  320. return 'time-range-service-' + this.get('service.serviceName');
  321. }.property(),
  322. getUserPrefSuccessCallback: function (response, request, data) {
  323. if (response) {
  324. console.log('Got persist value from server with key ' + data.key + '. Value is: ' + response);
  325. this.set('currentTimeRangeIndex', response);
  326. }
  327. },
  328. getUserPrefErrorCallback: function (request) {
  329. if (request.status == 404) {
  330. console.log('Persist did NOT find the key');
  331. this.postUserPref(this.get('persistKey'), 0);
  332. this.set('currentTimeRangeIndex', 0);
  333. }
  334. },
  335. /**
  336. * time range options for service metrics, a dropdown will list all options
  337. */
  338. timeRangeOptions: [
  339. {index: 0, name: Em.I18n.t('graphs.timeRange.hour'), seconds: 3600},
  340. {index: 1, name: Em.I18n.t('graphs.timeRange.twoHours'), seconds: 7200},
  341. {index: 2, name: Em.I18n.t('graphs.timeRange.fourHours'), seconds: 14400},
  342. {index: 3, name: Em.I18n.t('graphs.timeRange.twelveHours'), seconds: 43200},
  343. {index: 4, name: Em.I18n.t('graphs.timeRange.day'), seconds: 86400},
  344. {index: 5, name: Em.I18n.t('graphs.timeRange.week'), seconds: 604800},
  345. {index: 6, name: Em.I18n.t('graphs.timeRange.month'), seconds: 2592000},
  346. {index: 7, name: Em.I18n.t('graphs.timeRange.year'), seconds: 31104000}
  347. ],
  348. currentTimeRangeIndex: 0,
  349. currentTimeRange: function() {
  350. return this.get('timeRangeOptions').objectAt(this.get('currentTimeRangeIndex'));
  351. }.property('currentTimeRangeIndex'),
  352. /**
  353. * onclick handler for a time range option
  354. */
  355. setTimeRange: function (event) {
  356. var self = this;
  357. if (event && event.context) {
  358. self.postUserPref(self.get('persistKey'), event.context.index);
  359. self.set('currentTimeRangeIndex', event.context.index);
  360. var svcName = self.get('service.serviceName');
  361. if (svcName) {
  362. var result = [], graphObjects = [], chunkSize = 2;
  363. App.service_graph_config[svcName.toLowerCase()].forEach(function(graphName) {
  364. graphObjects.push(App["ChartServiceMetrics" + graphName].extend({
  365. currentTimeIndex : event.context.index
  366. }));
  367. });
  368. while(graphObjects.length) {
  369. result.push(graphObjects.splice(0, chunkSize));
  370. }
  371. self.set('serviceMetricGraphs', result);
  372. self.set('isServiceMetricLoaded', true);
  373. }
  374. }
  375. },
  376. loadServiceSummary: function () {
  377. var serviceName = this.get('serviceName');
  378. var serviceSummaryView = null;
  379. if (!serviceName) {
  380. return;
  381. }
  382. if (this.get('oldServiceName')) {
  383. // do not delete it!
  384. return;
  385. }
  386. var customServiceView = this.get('serviceCustomViewsMap')[serviceName];
  387. if (customServiceView) {
  388. serviceSummaryView = customServiceView.extend({
  389. service: this.get('service')
  390. });
  391. } else {
  392. serviceSummaryView = Em.View.extend({
  393. templateName: this.get('templatePathPrefix') + 'base',
  394. content: this
  395. });
  396. }
  397. this.set('serviceSummaryView', serviceSummaryView);
  398. this.set('oldServiceName', serviceName);
  399. }.observes('serviceName'),
  400. /**
  401. * Service metrics panel not displayed when metrics service (ex:Ganglia) is not in stack definition.
  402. */
  403. isNoServiceMetricsService: function() {
  404. return !App.get('services.serviceMetrics').length;
  405. }.property('App.services.serviceMetrics'),
  406. gangliaUrl:function () {
  407. var gangliaUrl = App.router.get('clusterController.gangliaUrl');
  408. if (!gangliaUrl) return null;
  409. var svcName = this.get('service.serviceName');
  410. if (svcName) {
  411. switch (svcName.toLowerCase()) {
  412. case 'hdfs':
  413. gangliaUrl += "/?r=hour&cs=&ce=&m=&s=by+name&c=HDPSlaves&tab=m&vn=";
  414. break;
  415. case 'hbase':
  416. gangliaUrl += "?r=hour&cs=&ce=&m=&s=by+name&c=HDPHBaseMaster&tab=m&vn=";
  417. break;
  418. default:
  419. break;
  420. }
  421. }
  422. return gangliaUrl;
  423. }.property('App.router.clusterController.gangliaUrl', 'service.serviceName'),
  424. willInsertElement: function () {
  425. App.router.get('updateController').updateServiceMetric(Em.K);
  426. },
  427. didInsertElement: function () {
  428. var svcName = this.get('service.serviceName');
  429. if (svcName) {
  430. this.constructGraphObjects(App.service_graph_config[svcName.toLowerCase()]);
  431. }
  432. // adjust the summary table height
  433. var summaryTable = document.getElementById('summary-info');
  434. if (summaryTable) {
  435. var rows = $(summaryTable).find('tr');
  436. if (rows != null && rows.length > 0) {
  437. var minimumHeightSum = 20;
  438. var summaryActualHeight = summaryTable.clientHeight;
  439. // for summary window
  440. if (summaryActualHeight <= minimumHeightSum) {
  441. $(summaryTable).attr('style', "height:" + minimumHeightSum + "px;");
  442. }
  443. }
  444. }
  445. }
  446. });