summary.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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. noTemplateService: function () {
  66. var serviceName = this.get("service.serviceName");
  67. //services with only master components
  68. return serviceName == "NAGIOS";
  69. }.property('controller.content'),
  70. hasManyServers: function () {
  71. return this.get('servers').length > 1;
  72. }.property('servers'),
  73. clientsHostText: function () {
  74. if (this.get('controller.content.installedClients').length == 0) {
  75. return '';
  76. } else if (this.get("hasManyClients")) {
  77. return Em.I18n.t('services.service.summary.viewHosts');
  78. } else {
  79. return Em.I18n.t('services.service.summary.viewHost');
  80. }
  81. }.property("hasManyClients"),
  82. hasManyClients: function () {
  83. return this.get('controller.content.installedClients').length > 1;
  84. }.property('service.installedClients'),
  85. servers: function () {
  86. var result = [];
  87. var service = this.get('controller.content');
  88. if (service.get("id") == "ZOOKEEPER" || service.get("id") == "FLUME") {
  89. var servers = service.get('hostComponents').filterProperty('isMaster');
  90. if (servers.length > 0) {
  91. result = [
  92. {
  93. 'host': servers[0].get('displayName'),
  94. 'isComma': false,
  95. 'isAnd': false
  96. }
  97. ];
  98. }
  99. if (servers.length > 1) {
  100. result[0].isComma = true;
  101. result.push({
  102. 'host': servers[1].get('displayName'),
  103. 'isComma': false,
  104. 'isAnd': false
  105. });
  106. }
  107. if (servers.length > 2) {
  108. result[1].isAnd = true;
  109. result.push({
  110. 'host': Em.I18n.t('services.service.info.summary.serversHostCount').format(servers.length - 2),
  111. 'isComma': false,
  112. 'isAnd': false
  113. });
  114. }
  115. }
  116. return result;
  117. }.property('controller.content'),
  118. historyServerUI: function(){
  119. var service=this.get('controller.content');
  120. return (App.singleNodeInstall ? "http://" + App.singleNodeAlias + ":19888" : "http://" + service.get("hostComponents").findProperty('isMaster', true).get("host").get("publicHostName")+":19888");
  121. }.property('controller.content'),
  122. /**
  123. * Property related to ZOOKEEPER service, is unused for other services
  124. * @return {Object}
  125. */
  126. serversHost: function() {
  127. var service = this.get('controller.content');
  128. if (service.get("id") == "ZOOKEEPER" || service.get("id") == "FLUME") {
  129. var servers = service.get('hostComponents').filterProperty('isMaster');
  130. if (servers.length > 0) {
  131. return servers[0];
  132. }
  133. }
  134. return {};
  135. }.property('controller.content'),
  136. mastersObj: function() {
  137. return this.get('service.hostComponents').filterProperty('isMaster', true);
  138. }.property('service'),
  139. /**
  140. * Contain array with list of client components models <code>App.ClientComponent</code>.
  141. * @type {Array}
  142. */
  143. clientObj: function () {
  144. var clientComponents = this.get('controller.content.clientComponents').toArray();
  145. return clientComponents.get('length') ? clientComponents : [];
  146. }.property('service.clientComponents.@each.totalCount'),
  147. /**
  148. * Contain array with list of slave components models <code>App.SlaveComponent</code>.
  149. * @type {Array}
  150. */
  151. slavesObj: function() {
  152. var slaveComponents = this.get('controller.content.slaveComponents').toArray();
  153. return slaveComponents.get('length') ? slaveComponents : [];
  154. }.property('service.slaveComponents.@each.totalCount', 'service.slaveComponents.@each.startedCount'),
  155. data:{
  156. hive:{
  157. "database":"PostgreSQL",
  158. "databaseName":"hive",
  159. "user":"hive"
  160. }
  161. },
  162. /**
  163. * Wrapper for displayName. used to render correct display name for mysql_server
  164. */
  165. componentNameView: Ember.View.extend({
  166. template: Ember.Handlebars.compile('{{view.displayName}}'),
  167. comp : null,
  168. displayName: function(){
  169. if(this.get('comp.componentName') == 'MYSQL_SERVER'){
  170. return this.t('services.hive.databaseComponent');
  171. }
  172. return this.get('comp.displayName');
  173. }.property('comp')
  174. }),
  175. service:function () {
  176. var svc = this.get('controller.content');
  177. var svcName = svc.get('serviceName');
  178. if (svcName) {
  179. switch (svcName.toLowerCase()) {
  180. case 'hdfs':
  181. svc = App.HDFSService.find().objectAt(0);
  182. break;
  183. case 'yarn':
  184. svc = App.YARNService.find().objectAt(0);
  185. break;
  186. case 'hbase':
  187. svc = App.HBaseService.find().objectAt(0);
  188. break;
  189. case 'flume':
  190. svc = App.FlumeService.find().objectAt(0);
  191. break;
  192. case 'storm':
  193. svc = App.StormService.find().objectAt(0);
  194. break;
  195. default:
  196. break;
  197. }
  198. }
  199. return svc;
  200. }.property('controller.content.serviceName').volatile(),
  201. isHide:true,
  202. moreStatsView:Em.View.extend({
  203. tagName:"a",
  204. template:Ember.Handlebars.compile('{{t services.service.summary.moreStats}}'),
  205. attributeBindings:[ 'href' ],
  206. classNames:[ 'more-stats' ],
  207. click:function (event) {
  208. this._parentView._parentView.set('isHide', false);
  209. this.remove();
  210. },
  211. href:'javascript:void(null)'
  212. }),
  213. serviceName:function () {
  214. return this.get('service.serviceName');
  215. }.property('service'),
  216. oldServiceName:'',
  217. /*
  218. * 'Restart Required bar' start
  219. */
  220. componentsCount: null,
  221. hostsCount: null,
  222. /*
  223. * alerts label on summary box header. no alerts/ {cnt} alerts
  224. */
  225. alertsCountLabel: function () {
  226. var cnt = this.get('controller.content.criticalAlertsCount');
  227. return cnt? Em.I18n.t('services.service.summary.alerts.alertsExist').format(cnt) :
  228. Em.I18n.t('services.service.summary.alerts.noAlerts');
  229. }.property('controller.content.criticalAlertsCount'),
  230. alertsCount: function () {
  231. return !!this.get('controller.content.criticalAlertsCount');
  232. }.property('controller.content.criticalAlertsCount'),
  233. /**
  234. * Define if service has alert definitions defined
  235. * @type {Boolean}
  236. */
  237. hasAlertDefinitions: function () {
  238. return App.AlertDefinition.getAllDefinitions().someProperty('serviceName', this.get('controller.content.serviceName'));
  239. }.property('controller.content.serviceName'),
  240. restartRequiredHostsAndComponents:function () {
  241. return this.get('controller.content.restartRequiredHostsAndComponents');
  242. }.property('controller.content.restartRequiredHostsAndComponents'),
  243. updateComponentInformation: function() {
  244. var hc = this.get('restartRequiredHostsAndComponents');
  245. var hostsCount = 0;
  246. var componentsCount = 0;
  247. for (var host in hc) {
  248. hostsCount++;
  249. componentsCount += hc[host].length;
  250. }
  251. this.set('componentsCount', componentsCount);
  252. this.set('hostsCount', hostsCount);
  253. }.observes('restartRequiredHostsAndComponents'),
  254. rollingRestartSlaveComponentName : function() {
  255. return batchUtils.getRollingRestartComponentName(this.get('serviceName'));
  256. }.property('serviceName'),
  257. rollingRestartActionName : function() {
  258. var label = null;
  259. var componentName = this.get('rollingRestartSlaveComponentName');
  260. if (componentName) {
  261. label = Em.I18n.t('rollingrestart.dialog.title').format(App.format.role(componentName));
  262. }
  263. return label;
  264. }.property('rollingRestartSlaveComponentName'),
  265. showComponentsShouldBeRestarted: function () {
  266. var rhc = this.get('restartRequiredHostsAndComponents');
  267. App.router.get('mainServiceInfoConfigsController').showComponentsShouldBeRestarted(rhc);
  268. },
  269. showHostsShouldBeRestarted: function () {
  270. var rhc = this.get('restartRequiredHostsAndComponents');
  271. App.router.get('mainServiceInfoConfigsController').showHostsShouldBeRestarted(rhc);
  272. },
  273. restartAllStaleConfigComponents: function () {
  274. var self = this;
  275. var serviceDisplayName = this.get('service.displayName');
  276. var bodyMessage = Em.Object.create({
  277. confirmMsg: Em.I18n.t('services.service.restartAll.confirmMsg').format(serviceDisplayName),
  278. confirmButton: Em.I18n.t('services.service.restartAll.confirmButton'),
  279. additionalWarningMsg: this.get('service.passiveState') === 'OFF' ? Em.I18n.t('services.service.restartAll.warningMsg.turnOnMM').format(serviceDisplayName) : null
  280. });
  281. return App.showConfirmationFeedBackPopup(function (query) {
  282. var selectedService = self.get('service.id');
  283. batchUtils.restartAllServiceHostComponents(selectedService, true, query);
  284. }, bodyMessage);
  285. },
  286. rollingRestartStaleConfigSlaveComponents: function (componentName) {
  287. batchUtils.launchHostComponentRollingRestart(componentName.context, this.get('service.displayName'), this.get('service.passiveState') === "ON", true);
  288. },
  289. /*
  290. * 'Restart Required bar' ended
  291. */
  292. /*
  293. * Find the graph class associated with the graph name, and split
  294. * the array into sections of 2 for displaying on the page
  295. * (will only display rows with 2 items)
  296. */
  297. constructGraphObjects: function(graphNames) {
  298. var result = [], graphObjects = [], chunkSize = 2;
  299. var self = this;
  300. if (!graphNames) {
  301. self.set('serviceMetricGraphs', []);
  302. self.set('isServiceMetricLoaded', true);
  303. return;
  304. }
  305. // load time range for current service from server
  306. self.getUserPref(self.get('persistKey')).complete(function () {
  307. var index = self.get('currentTimeRangeIndex');
  308. graphNames.forEach(function(graphName) {
  309. graphObjects.push(App["ChartServiceMetrics" + graphName].extend({
  310. currentTimeIndex : index
  311. }));
  312. });
  313. while(graphObjects.length) {
  314. result.push(graphObjects.splice(0, chunkSize));
  315. }
  316. self.set('serviceMetricGraphs', result);
  317. self.set('isServiceMetricLoaded', true);
  318. });
  319. },
  320. /**
  321. * Contains graphs for this particular service
  322. */
  323. serviceMetricGraphs: [],
  324. isServiceMetricLoaded: false,
  325. /**
  326. * Key-name to store time range in Persist
  327. * @type {string}
  328. */
  329. persistKey: function () {
  330. return 'time-range-service-' + this.get('service.serviceName');
  331. }.property(),
  332. getUserPrefSuccessCallback: function (response, request, data) {
  333. if (response) {
  334. console.log('Got persist value from server with key ' + data.key + '. Value is: ' + response);
  335. this.set('currentTimeRangeIndex', response);
  336. }
  337. },
  338. getUserPrefErrorCallback: function (request) {
  339. if (request.status == 404) {
  340. console.log('Persist did NOT find the key');
  341. this.postUserPref(this.get('persistKey'), 0);
  342. this.set('currentTimeRangeIndex', 0);
  343. }
  344. },
  345. /**
  346. * time range options for service metrics, a dropdown will list all options
  347. */
  348. timeRangeOptions: [
  349. {index: 0, name: Em.I18n.t('graphs.timeRange.hour'), seconds: 3600},
  350. {index: 1, name: Em.I18n.t('graphs.timeRange.twoHours'), seconds: 7200},
  351. {index: 2, name: Em.I18n.t('graphs.timeRange.fourHours'), seconds: 14400},
  352. {index: 3, name: Em.I18n.t('graphs.timeRange.twelveHours'), seconds: 43200},
  353. {index: 4, name: Em.I18n.t('graphs.timeRange.day'), seconds: 86400},
  354. {index: 5, name: Em.I18n.t('graphs.timeRange.week'), seconds: 604800},
  355. {index: 6, name: Em.I18n.t('graphs.timeRange.month'), seconds: 2592000},
  356. {index: 7, name: Em.I18n.t('graphs.timeRange.year'), seconds: 31104000}
  357. ],
  358. currentTimeRangeIndex: 0,
  359. currentTimeRange: function() {
  360. return this.get('timeRangeOptions').objectAt(this.get('currentTimeRangeIndex'));
  361. }.property('currentTimeRangeIndex'),
  362. /**
  363. * onclick handler for a time range option
  364. */
  365. setTimeRange: function (event) {
  366. var self = this;
  367. if (event && event.context) {
  368. self.postUserPref(self.get('persistKey'), event.context.index);
  369. self.set('currentTimeRangeIndex', event.context.index);
  370. var svcName = self.get('service.serviceName');
  371. if (svcName) {
  372. var result = [], graphObjects = [], chunkSize = 2;
  373. App.service_graph_config[svcName.toLowerCase()].forEach(function(graphName) {
  374. graphObjects.push(App["ChartServiceMetrics" + graphName].extend({
  375. currentTimeIndex : event.context.index
  376. }));
  377. });
  378. while(graphObjects.length) {
  379. result.push(graphObjects.splice(0, chunkSize));
  380. }
  381. self.set('serviceMetricGraphs', result);
  382. self.set('isServiceMetricLoaded', true);
  383. }
  384. }
  385. },
  386. loadServiceSummary: function () {
  387. var serviceName = this.get('serviceName');
  388. var serviceSummaryView = null;
  389. if (!serviceName) {
  390. return;
  391. }
  392. if (this.get('oldServiceName')) {
  393. // do not delete it!
  394. return;
  395. }
  396. var customServiceView = this.get('serviceCustomViewsMap')[serviceName];
  397. if (customServiceView) {
  398. serviceSummaryView = customServiceView.extend({
  399. service: this.get('service')
  400. });
  401. } else {
  402. serviceSummaryView = Em.View.extend({
  403. templateName: this.get('templatePathPrefix') + 'base',
  404. content: this
  405. });
  406. }
  407. this.set('serviceSummaryView', serviceSummaryView);
  408. this.set('oldServiceName', serviceName);
  409. }.observes('serviceName'),
  410. /**
  411. * Service metrics panel not displayed when metrics service (ex:Ganglia) is not in stack definition.
  412. */
  413. isNoServiceMetricsService: function() {
  414. return !App.get('services.serviceMetrics').length;
  415. }.property('App.services.serviceMetrics'),
  416. gangliaUrl:function () {
  417. var gangliaUrl = App.router.get('clusterController.gangliaUrl');
  418. if (!gangliaUrl) return null;
  419. var svcName = this.get('service.serviceName');
  420. if (svcName) {
  421. switch (svcName.toLowerCase()) {
  422. case 'hdfs':
  423. gangliaUrl += "/?r=hour&cs=&ce=&m=&s=by+name&c=HDPSlaves&tab=m&vn=";
  424. break;
  425. case 'hbase':
  426. gangliaUrl += "?r=hour&cs=&ce=&m=&s=by+name&c=HDPHBaseMaster&tab=m&vn=";
  427. break;
  428. default:
  429. break;
  430. }
  431. }
  432. return gangliaUrl;
  433. }.property('App.router.clusterController.gangliaUrl', 'service.serviceName'),
  434. didInsertElement:function () {
  435. var svcName = this.get('service.serviceName');
  436. if (svcName) {
  437. this.constructGraphObjects(App.service_graph_config[svcName.toLowerCase()]);
  438. }
  439. // adjust the summary table height
  440. var summaryTable = document.getElementById('summary-info');
  441. if (summaryTable) {
  442. var rows = $(summaryTable).find('tr');
  443. if (rows != null && rows.length > 0) {
  444. var minimumHeightSum = 20;
  445. var summaryActualHeight = summaryTable.clientHeight;
  446. // for summary window
  447. if (summaryActualHeight <= minimumHeightSum) {
  448. $(summaryTable).attr('style', "height:" + minimumHeightSum + "px;");
  449. }
  450. }
  451. }
  452. }
  453. });