summary.js 18 KB

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