summary.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var uiEffects = require('utils/ui_effects');
  20. App.MainHostSummaryView = Em.View.extend({
  21. templateName: require('templates/main/host/summary'),
  22. isStopCommand:true,
  23. content: function () {
  24. return App.router.get('mainHostDetailsController.content');
  25. }.property('App.router.mainHostDetailsController.content'),
  26. showGangliaCharts: function () {
  27. var name = this.get('content.hostName');
  28. var gangliaMobileUrl = App.router.get('clusterController.gangliaUrl') + "/mobile_helper.php?show_host_metrics=1&h=" + name + "&c=HDPNameNode&r=hour&cs=&ce=";
  29. window.open(gangliaMobileUrl);
  30. },
  31. stopComponentsIsDisabled: function () {
  32. var staleComponents = this.get('content.hostComponents').filterProperty('staleConfigs', true);
  33. if(!staleComponents.findProperty('workStatus','STARTED')){
  34. return true;
  35. } else {
  36. return false;
  37. }
  38. }.property('content.hostComponents.@each.workStatus', 'content.hostComponents.@each.staleConfigs'),
  39. startComponentsIsDisabled:function () {
  40. var staleComponents = this.get('content.hostComponents').filterProperty('staleConfigs', true);
  41. if(!staleComponents.findProperty('workStatus','INSTALLED')){
  42. return true;
  43. } else {
  44. return false;
  45. }
  46. }.property('content.hostComponents.@each.workStatus', 'content.hostComponents.@each.staleConfigs'),
  47. needToRestartMessage: function() {
  48. var componentsCount, word;
  49. componentsCount = this.get('content.componentsWithStaleConfigsCount');
  50. if (componentsCount > 1) {
  51. word = Em.I18n.t('common.components').toLowerCase();
  52. } else {
  53. word = Em.I18n.t('common.component').toLowerCase();
  54. }
  55. return Em.I18n.t('hosts.host.details.needToRestart').format(this.get('content.componentsWithStaleConfigsCount'), word);
  56. }.property('content.componentsWithStaleConfigsCount'),
  57. /**
  58. * @type: [{String}]
  59. */
  60. decommissionDataNodeHostNames: null,
  61. loadDecommissionNodesList: function () {
  62. var self = this;
  63. var clusterName = App.router.get('clusterController.clusterName');
  64. var persistUrl = App.apiPrefix + '/persist/decommissionDataNodesTag';
  65. var clusterUrl = App.apiPrefix + '/clusters/' + clusterName;
  66. var getConfigAjax = {
  67. type: 'GET',
  68. url: persistUrl,
  69. dataType: 'json',
  70. timeout: App.timeout,
  71. success: function (decommissionDataNodesTag) {
  72. if (decommissionDataNodesTag) {
  73. // We know the tag which contains the decommisioned nodes.
  74. var configsUrl = clusterUrl + '/configurations?type=hdfs-exclude-file&tag=' + decommissionDataNodesTag;
  75. var decomNodesAjax = {
  76. type: 'GET',
  77. url: configsUrl,
  78. dataType: 'json',
  79. timeout: App.timeout,
  80. success: function (data) {
  81. if (data && data.items) {
  82. var csv = data.items[0].properties.datanodes;
  83. if (csv!==null && csv.length>0) {
  84. self.set('decommissionDataNodeHostNames', csv.split(','));
  85. } else {
  86. self.set('decommissionDataNodeHostNames', null);
  87. }
  88. }
  89. },
  90. error: function (xhr, textStatus, errorThrown) {
  91. console.log(textStatus);
  92. console.log(errorThrown);
  93. }
  94. };
  95. jQuery.ajax(decomNodesAjax);
  96. }
  97. },
  98. error: function (xhr, textStatus, errorThrown) {
  99. // No tag pointer in persist. Rely on service's decomNodes.
  100. var hdfsSvcs = App.HDFSService.find();
  101. if (hdfsSvcs && hdfsSvcs.get('length') > 0) {
  102. var hdfsSvc = hdfsSvcs.objectAt(0);
  103. if (hdfsSvc) {
  104. var hostNames = [];
  105. var decomNodes = hdfsSvc.get('decommissionDataNodes');
  106. decomNodes.forEach(function (decomNode) {
  107. hostNames.push(decomNode.get('hostName'));
  108. });
  109. self.set('decommissionDataNodeHostNames', hostNames);
  110. }
  111. }
  112. }
  113. };
  114. jQuery.ajax(getConfigAjax);
  115. },
  116. didInsertElement: function () {
  117. if (this.get('content.hostComponents').someProperty('componentName', 'DATANODE')) {
  118. this.loadDecommissionNodesList();
  119. }
  120. this.addToolTip();
  121. },
  122. addToolTip: function() {
  123. if (this.get('addComponentDisabled')) {
  124. App.tooltip($('#add_component'), {title: Em.I18n.t('services.nothingToAdd')});
  125. }
  126. }.observes('addComponentDisabled'),
  127. sortedComponents: function () {
  128. var slaveComponents = [];
  129. var masterComponents = [];
  130. this.get('content.hostComponents').forEach(function (component) {
  131. if (component.get('isMaster')) {
  132. masterComponents.push(component);
  133. } else if (component.get('isSlave')) {
  134. slaveComponents.push(component);
  135. }
  136. }, this);
  137. return masterComponents.concat(slaveComponents);
  138. }.property('content', 'content.hostComponents.length'),
  139. clients: function () {
  140. var clients = [];
  141. this.get('content.hostComponents').forEach(function (component) {
  142. if (!component.get('componentName')) {
  143. //temporary fix because of different data in hostComponents and serviceComponents
  144. return;
  145. }
  146. if (!component.get('isSlave') && !component.get('isMaster')) {
  147. if (clients.length) {
  148. clients[clients.length - 1].set('isLast', false);
  149. }
  150. component.set('isLast', true);
  151. clients.push(component);
  152. }
  153. }, this);
  154. return clients;
  155. }.property('content'),
  156. addableComponentObject: Em.Object.extend({
  157. componentName: '',
  158. subComponentNames: null,
  159. displayName: function () {
  160. if (this.get('componentName') === 'CLIENTS') {
  161. return this.t('common.clients');
  162. }
  163. return App.format.role(this.get('componentName'));
  164. }.property('componentName')
  165. }),
  166. isAddComponent: function () {
  167. return this.get('content.healthClass') !== 'health-status-DEAD-YELLOW';
  168. }.property('content.healthClass'),
  169. addComponentDisabled: function() {
  170. return (!this.get('isAddComponent')) || (this.get('addableComponents.length') == 0);
  171. }.property('isAddComponent', 'addableComponents.length'),
  172. installableClientComponents: function() {
  173. var installableClients = [];
  174. if (!App.supports.deleteHost) {
  175. return installableClients;
  176. }
  177. App.Service.find().forEach(function(svc){
  178. switch(svc.get('serviceName')){
  179. case 'PIG':
  180. installableClients.push('PIG');
  181. break;
  182. case 'SQOOP':
  183. installableClients.push('SQOOP');
  184. break;
  185. case 'HCATALOG':
  186. installableClients.push('HCAT');
  187. break;
  188. case 'HDFS':
  189. installableClients.push('HDFS_CLIENT');
  190. break;
  191. case 'OOZIE':
  192. installableClients.push('OOZIE_CLIENT');
  193. break;
  194. case 'ZOOKEEPER':
  195. installableClients.push('ZOOKEEPER_CLIENT');
  196. break;
  197. case 'HIVE':
  198. installableClients.push('HIVE_CLIENT');
  199. break;
  200. case 'HBASE':
  201. installableClients.push('HBASE_CLIENT');
  202. break;
  203. case 'YARN':
  204. installableClients.push('YARN_CLIENT');
  205. break;
  206. case 'MAPREDUCE':
  207. installableClients.push('MAPREDUCE_CLIENT');
  208. break;
  209. case 'MAPREDUCE2':
  210. installableClients.push('MAPREDUCE2_CLIENT');
  211. break;
  212. }
  213. });
  214. this.get('content.hostComponents').forEach(function (component) {
  215. var index = installableClients.indexOf(component.get('componentName'));
  216. if (index > -1) {
  217. installableClients.splice(index, 1);
  218. }
  219. }, this);
  220. return installableClients;
  221. }.property('content', 'content.hostComponents.length', 'App.Service', 'App.supports.deleteHost'),
  222. addableComponents: function () {
  223. var components = [];
  224. var services = App.Service.find();
  225. var dataNodeExists = false;
  226. var taskTrackerExists = false;
  227. var regionServerExists = false;
  228. var zookeeperServerExists = false;
  229. var nodeManagerExists = false;
  230. var hbaseMasterExists = false;
  231. var installableClients = this.get('installableClientComponents');
  232. this.get('content.hostComponents').forEach(function (component) {
  233. switch (component.get('componentName')) {
  234. case 'DATANODE':
  235. dataNodeExists = true;
  236. break;
  237. case 'TASKTRACKER':
  238. taskTrackerExists = true;
  239. break;
  240. case 'HBASE_REGIONSERVER':
  241. regionServerExists = true;
  242. break;
  243. case 'ZOOKEEPER_SERVER':
  244. zookeeperServerExists = true;
  245. break;
  246. case 'NODEMANAGER':
  247. nodeManagerExists = true;
  248. break;
  249. case 'HBASE_MASTER':
  250. hbaseMasterExists = true;
  251. break;
  252. }
  253. }, this);
  254. if (!dataNodeExists) {
  255. components.pushObject(this.addableComponentObject.create({ 'componentName': 'DATANODE' }));
  256. }
  257. if (!taskTrackerExists && services.findProperty('serviceName', 'MAPREDUCE')) {
  258. components.pushObject(this.addableComponentObject.create({ 'componentName': 'TASKTRACKER' }));
  259. }
  260. if (!regionServerExists && services.findProperty('serviceName', 'HBASE')) {
  261. components.pushObject(this.addableComponentObject.create({ 'componentName': 'HBASE_REGIONSERVER' }));
  262. }
  263. if (!hbaseMasterExists && services.findProperty('serviceName', 'HBASE')) {
  264. components.pushObject(this.addableComponentObject.create({ 'componentName': 'HBASE_MASTER' }));
  265. }
  266. if (!zookeeperServerExists && services.findProperty('serviceName', 'ZOOKEEPER')) {
  267. components.pushObject(this.addableComponentObject.create({ 'componentName': 'ZOOKEEPER_SERVER' }));
  268. }
  269. if (!nodeManagerExists && services.findProperty('serviceName', 'YARN')) {
  270. components.pushObject(this.addableComponentObject.create({ 'componentName': 'NODEMANAGER' }));
  271. }
  272. if (installableClients.length > 0) {
  273. components.pushObject(this.addableComponentObject.create({ 'componentName': 'CLIENTS', subComponentNames: installableClients }));
  274. }
  275. return components;
  276. }.property('content', 'content.hostComponents.length', 'installableClientComponents'),
  277. ComponentView: Em.View.extend({
  278. content: null,
  279. didInsertElement: function () {
  280. if (this.get('isInProgress')) {
  281. this.doBlinking();
  282. }
  283. },
  284. hostComponent: function () {
  285. var hostComponent = null;
  286. var serviceComponent = this.get('content');
  287. var host = App.router.get('mainHostDetailsController.content');
  288. if (host) {
  289. hostComponent = host.get('hostComponents').findProperty('componentName', serviceComponent.get('componentName'));
  290. }
  291. return hostComponent;
  292. }.property('content', 'App.router.mainHostDetailsController.content'),
  293. workStatus: function () {
  294. var workStatus = this.get('content.workStatus');
  295. var hostComponent = this.get('hostComponent');
  296. if (hostComponent) {
  297. workStatus = hostComponent.get('workStatus');
  298. }
  299. return workStatus;
  300. }.property('content.workStatus', 'hostComponent.workStatus'),
  301. /**
  302. * Return host component text status
  303. */
  304. componentTextStatus: function () {
  305. var workStatus = this.get("workStatus");
  306. var componentTextStatus = this.get('content.componentTextStatus');
  307. var hostComponent = this.get('hostComponent');
  308. if (hostComponent) {
  309. componentTextStatus = hostComponent.get('componentTextStatus');
  310. if(this.get("isDataNode"))
  311. if(this.get('isDataNodeRecommissionAvailable')){
  312. if(hostComponent.get('isDecommissioning')){
  313. componentTextStatus = "Decommissioning...";
  314. } else {
  315. componentTextStatus = "Decommissioned";
  316. }
  317. }
  318. }
  319. return componentTextStatus;
  320. }.property('workStatus','isDataNodeRecommissionAvailable'),
  321. statusClass: function () {
  322. //If the component is DataNode
  323. if (this.get('isDataNode')) {
  324. if (this.get('isDataNodeRecommissionAvailable') && (this.get('isStart') || this.get('workStatus') == 'INSTALLED')) {
  325. return 'health-status-DEAD-ORANGE';
  326. }
  327. }
  328. //Class when install failed
  329. if (this.get('workStatus') === App.HostComponentStatus.install_failed) {
  330. return 'health-status-color-red icon-cog';
  331. }
  332. //Class when installing
  333. if (this.get('workStatus') === App.HostComponentStatus.installing) {
  334. return 'health-status-color-blue icon-cog';
  335. }
  336. //For all other cases
  337. return 'health-status-' + App.HostComponentStatus.getKeyName(this.get('workStatus'));
  338. }.property('workStatus', 'isDataNodeRecommissionAvailable', 'this.content.isDecommissioning'),
  339. disabled: function() {
  340. return this.get('parentView.content.isNotHeartBeating')?'disabled':'';
  341. }.property('parentView.content.isNotHeartBeating'),
  342. /**
  343. * For Upgrade failed state
  344. */
  345. isUpgradeFailed: function () {
  346. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "upgrade_failed";
  347. }.property("workStatus"),
  348. /**
  349. * For Install failed state
  350. */
  351. isInstallFailed: function () {
  352. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "install_failed";
  353. }.property("workStatus"),
  354. /**
  355. * Do blinking for 1 minute
  356. */
  357. doBlinking: function () {
  358. var workStatus = this.get('workStatus');
  359. var self = this;
  360. var pulsate = [ App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.installing].contains(workStatus);
  361. if (!pulsate && this.get('isDataNode')) {
  362. var dataNodeComponent = this.get('content');
  363. if (dataNodeComponent && workStatus != "INSTALLED") {
  364. pulsate = this.get('isDecommissioning');
  365. }
  366. }
  367. if (pulsate && !self.get('isBlinking')) {
  368. self.set('isBlinking', true);
  369. uiEffects.pulsate(self.$('.components-health'), 1000, function () {
  370. self.set('isBlinking', false);
  371. self.doBlinking();
  372. });
  373. }
  374. },
  375. /**
  376. * Start blinking when host component is starting/stopping
  377. */
  378. startBlinking: function () {
  379. this.$('.components-health').stop(true, true);
  380. this.$('.components-health').css({opacity: 1.0});
  381. this.doBlinking();
  382. }.observes('workStatus','isDataNodeRecommissionAvailable'),
  383. isStart: function () {
  384. return (this.get('workStatus') == App.HostComponentStatus.started || this.get('workStatus') == App.HostComponentStatus.starting);
  385. }.property('workStatus'),
  386. isInstalling: function () {
  387. return (this.get('workStatus') == App.HostComponentStatus.installing);
  388. }.property('workStatus'),
  389. /**
  390. * No action available while component is starting/stopping/unknown
  391. */
  392. noActionAvailable: function () {
  393. var workStatus = this.get('workStatus');
  394. if ([App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.unknown].contains(workStatus)) {
  395. return "hidden";
  396. }else{
  397. return "";
  398. }
  399. }.property('workStatus'),
  400. isInProgress: function () {
  401. return (this.get('workStatus') === App.HostComponentStatus.stopping ||
  402. this.get('workStatus') === App.HostComponentStatus.starting) ||
  403. this.get('isDecommissioning');
  404. }.property('workStatus', 'isDataNodeRecommissionAvailable'),
  405. /**
  406. * Shows whether we need to show Decommision/Recomission buttons
  407. */
  408. isDataNode: function () {
  409. return this.get('content.componentName') === 'DATANODE';
  410. }.property('content'),
  411. isDecommissioning: function () {
  412. var hostComponentDecommissioning = this.get('hostComponent.isDecommissioning');
  413. return this.get('isDataNode') && this.get("isDataNodeRecommissionAvailable") && hostComponentDecommissioning;
  414. }.property("workStatus", "isDataNodeRecommissionAvailable", "hostComponent.isDecommissioning"),
  415. /**
  416. * Set in template via binding from parent view
  417. */
  418. decommissionDataNodeHostNames: null,
  419. /**
  420. * Decommission is available whenever the service is started.
  421. */
  422. isDataNodeDecommissionAvailable: function () {
  423. return this.get('isStart') && !this.get('isDataNodeRecommissionAvailable');
  424. }.property('isStart', 'isDataNodeRecommissionAvailable'),
  425. /**
  426. * Recommission is available only when this hostname shows up in the
  427. * 'decommissionDataNodeHostNames'
  428. */
  429. isDataNodeRecommissionAvailable: function () {
  430. var decommissionHostNames = this.get('decommissionDataNodeHostNames');
  431. var hostName = App.router.get('mainHostDetailsController.content.hostName');
  432. return decommissionHostNames != null && decommissionHostNames.contains(hostName);
  433. }.property('App.router.mainHostDetailsController.content', 'decommissionDataNodeHostNames'),
  434. /**
  435. * Shows whether we need to show Delete button
  436. */
  437. isHBaseMaster: function () {
  438. return this.get('content.componentName') === 'HBASE_MASTER';
  439. }.property('content'),
  440. isDeleteHBaseMasterDisabled: function () {
  441. return !(this.get('workStatus') == App.HostComponentStatus.stopped || this.get('workStatus') == App.HostComponentStatus.unknown ||
  442. this.get('workStatus') == App.HostComponentStatus.install_failed || this.get('workStatus') == App.HostComponentStatus.upgrade_failed);
  443. }.property('workStatus'),
  444. isReassignable: function () {
  445. return App.supports.reassignMaster && App.reassignableComponents.contains(this.get('content.componentName')) && App.Host.find().content.length > 1;
  446. }.property('content.componentName')
  447. }),
  448. timeSinceHeartBeat: function () {
  449. var d = this.get('content.lastHeartBeatTime');
  450. if (d) {
  451. return $.timeago(d);
  452. }
  453. return "";
  454. }.property('content.lastHeartBeatTime')
  455. });