summary.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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. content: function () {
  23. return App.router.get('mainHostDetailsController.content');
  24. }.property('App.router.mainHostDetailsController.content'),
  25. showGangliaCharts: function () {
  26. var name = this.get('content.hostName');
  27. var gangliaMobileUrl = App.router.get('clusterController.gangliaUrl') + "/mobile_helper.php?show_host_metrics=1&h=" + name + "&c=HDPNameNode&r=hour&cs=&ce=";
  28. window.open(gangliaMobileUrl);
  29. },
  30. /**
  31. * @type: [{String}]
  32. */
  33. decommissionDataNodeHostNames: null,
  34. loadDecommissionNodesList: function () {
  35. var self = this;
  36. var clusterName = App.router.get('clusterController.clusterName');
  37. var persistUrl = App.apiPrefix + '/persist';
  38. var clusterUrl = App.apiPrefix + '/clusters/' + clusterName;
  39. var getConfigAjax = {
  40. type: 'GET',
  41. url: persistUrl,
  42. dataType: 'json',
  43. timeout: App.timeout,
  44. success: function (data) {
  45. if (data && data.decommissionDataNodesTag) {
  46. // We know the tag which contains the decommisioned nodes.
  47. var configsUrl = clusterUrl + '/configurations?type=hdfs-exclude-file&tag=' + data.decommissionDataNodesTag;
  48. var decomNodesAjax = {
  49. type: 'GET',
  50. url: configsUrl,
  51. dataType: 'json',
  52. timeout: App.timeout,
  53. success: function (data) {
  54. if (data && data.items) {
  55. var csv = data.items[0].properties.datanodes;
  56. self.set('decommissionDataNodeHostNames', csv.split(','));
  57. }
  58. },
  59. error: function (xhr, textStatus, errorThrown) {
  60. console.log(textStatus);
  61. console.log(errorThrown);
  62. }
  63. };
  64. jQuery.ajax(decomNodesAjax);
  65. }
  66. },
  67. error: function (xhr, textStatus, errorThrown) {
  68. // No tag pointer in persist. Rely on service's decomNodes.
  69. var hdfsSvcs = App.HDFSService.find();
  70. if (hdfsSvcs && hdfsSvcs.get('length') > 0) {
  71. var hdfsSvc = hdfsSvcs.objectAt(0);
  72. if (hdfsSvc) {
  73. var hostNames = [];
  74. var decomNodes = hdfsSvc.get('decommissionDataNodes');
  75. decomNodes.forEach(function (decomNode) {
  76. hostNames.push(decomNode.get('hostName'));
  77. });
  78. self.set('decommissionDataNodeHostNames', hostNames);
  79. }
  80. }
  81. }
  82. }
  83. jQuery.ajax(getConfigAjax);
  84. },
  85. didInsertElement: function () {
  86. this.loadDecommissionNodesList();
  87. },
  88. sortedComponents: function () {
  89. var slaveComponents = [];
  90. var masterComponents = [];
  91. this.get('content.hostComponents').forEach(function (component) {
  92. if (component.get('workStatus') != 'INSTALLING') {
  93. if (component.get('isMaster')) {
  94. masterComponents.push(component);
  95. } else if (component.get('isSlave')) {
  96. slaveComponents.push(component);
  97. }
  98. }
  99. }, this);
  100. return masterComponents.concat(slaveComponents);
  101. }.property('content', 'content.hostComponents.length'),
  102. clients: function () {
  103. var clients = [];
  104. this.get('content.hostComponents').forEach(function (component) {
  105. if (!component.get('componentName')) {
  106. //temporary fix because of different data in hostComponents and serviceComponents
  107. return;
  108. }
  109. if (!component.get('isSlave') && !component.get('isMaster')) {
  110. if (clients.length) {
  111. clients[clients.length - 1].set('isLast', false);
  112. }
  113. component.set('isLast', true);
  114. clients.push(component);
  115. }
  116. }, this);
  117. return clients;
  118. }.property('content'),
  119. addableComponentObject: Em.Object.extend({
  120. componentName: '',
  121. displayName: function () {
  122. return App.format.role(this.get('componentName'));
  123. }.property('componentName')
  124. }),
  125. isAddComponent: function () {
  126. return this.get('content.healthClass') !== 'health-status-DEAD-YELLOW';
  127. }.property('content.healthClass'),
  128. addableComponents: function () {
  129. var components = [];
  130. var services = App.Service.find();
  131. var dataNodeExists = false;
  132. var taskTrackerExists = false;
  133. var regionServerExists = false;
  134. this.get('content.hostComponents').forEach(function (component) {
  135. switch (component.get('componentName')) {
  136. case 'DATANODE':
  137. dataNodeExists = true;
  138. break;
  139. case 'TASKTRACKER':
  140. taskTrackerExists = true;
  141. break;
  142. case 'HBASE_REGIONSERVER':
  143. regionServerExists = true;
  144. break;
  145. }
  146. }, this);
  147. if (!dataNodeExists) {
  148. components.pushObject(this.addableComponentObject.create({ 'componentName': 'DATANODE' }));
  149. }
  150. if (!taskTrackerExists && services.findProperty('serviceName', 'MAPREDUCE')) {
  151. components.pushObject(this.addableComponentObject.create({ 'componentName': 'TASKTRACKER' }));
  152. }
  153. if (!regionServerExists && services.findProperty('serviceName', 'HBASE')) {
  154. components.pushObject(this.addableComponentObject.create({ 'componentName': 'HBASE_REGIONSERVER' }));
  155. }
  156. return components;
  157. }.property('content', 'content.hostComponents.length'),
  158. ComponentView: Em.View.extend({
  159. content: null,
  160. didInsertElement: function () {
  161. if (this.get('isInProgress')) {
  162. this.doBlinking();
  163. }
  164. },
  165. hostComponent: function () {
  166. var hostComponent = null;
  167. var serviceComponent = this.get('content');
  168. var host = App.router.get('mainHostDetailsController.content');
  169. if (host) {
  170. hostComponent = host.get('hostComponents').findProperty('componentName', serviceComponent.get('componentName'));
  171. }
  172. return hostComponent;
  173. }.property('content', 'App.router.mainHostDetailsController.content'),
  174. workStatus: function () {
  175. var workStatus = this.get('content.workStatus');
  176. var hostComponent = this.get('hostComponent');
  177. if (hostComponent) {
  178. workStatus = hostComponent.get('workStatus');
  179. }
  180. return workStatus;
  181. }.property('content.workStatus', 'hostComponent.workStatus'),
  182. /**
  183. * Return host component text status
  184. */
  185. componentTextStatus: function () {
  186. var workStatus = this.get("workStatus");
  187. var componentTextStatus = this.get('content.componentTextStatus');
  188. var hostComponent = this.get('hostComponent');
  189. if (hostComponent) {
  190. componentTextStatus = hostComponent.get('componentTextStatus');
  191. if(this.get("isDataNode"))
  192. if(this.get('isDataNodeRecommissionAvailable')){
  193. if(App.HostComponentStatus.started == workStatus){
  194. componentTextStatus = "Decommissioning...";
  195. }else if(App.HostComponentStatus.stopped == workStatus){
  196. componentTextStatus = "Decommissioned";
  197. }
  198. }
  199. }
  200. return componentTextStatus;
  201. }.property('workStatus','isDataNodeRecommissionAvailable'),
  202. statusClass: function () {
  203. var statusClass = null;
  204. //If the component is DataNode
  205. if (this.get('isDataNode')) {
  206. if (this.get('isDataNodeRecommissionAvailable') && (this.get('isStart') || this.get('workStatus') == 'INSTALLED')) {
  207. return 'health-status-DEAD-ORANGE';
  208. }
  209. }
  210. //Class when install failed
  211. if (this.get('workStatus') === App.HostComponentStatus.install_failed) {
  212. return 'health-status-color-red icon-cog';
  213. }
  214. //Class when installing
  215. if (this.get('workStatus') === App.HostComponentStatus.installing) {
  216. return 'health-status-color-blue icon-cog';
  217. }
  218. //For all other cases
  219. return 'health-status-' + App.HostComponentStatus.getKeyName(this.get('workStatus'));
  220. }.property('workStatus', 'isDataNodeRecommissionAvailable', 'this.content.isDecommissioning'),
  221. /**
  222. * For Upgrade failed state
  223. */
  224. isUpgradeFailed: function () {
  225. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "upgrade_failed";
  226. }.property("workStatus"),
  227. /**
  228. * For Install failed state
  229. */
  230. isInstallFailed: function () {
  231. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "install_failed";
  232. }.property("workStatus"),
  233. /**
  234. * Do blinking for 1 minute
  235. */
  236. doBlinking: function () {
  237. var workStatus = this.get('workStatus');
  238. var self = this;
  239. var pulsate = [ App.HostComponentStatus.starting, App.HostComponentStatus.stopping ].contains(workStatus);
  240. if (!pulsate && this.get('isDataNode')) {
  241. var dataNodeComponent = this.get('content');
  242. if (dataNodeComponent && workStatus != "INSTALLED") {
  243. pulsate = this.get('isDataNodeRecommissionAvailable');
  244. }
  245. }
  246. if (pulsate && !self.get('isBlinking')) {
  247. self.set('isBlinking', true);
  248. uiEffects.pulsate(self.$('.components-health'), 1000, function () {
  249. !self.get('isDestroyed') && self.set('isBlinking', false);
  250. self.doBlinking();
  251. });
  252. }
  253. },
  254. /**
  255. * Start blinking when host component is starting/stopping
  256. */
  257. startBlinking: function () {
  258. this.$('.components-health').stop(true, true);
  259. this.$('.components-health').css({opacity: 1.0});
  260. this.doBlinking();
  261. }.observes('workStatus','isDataNodeRecommissionAvailable'),
  262. isStart: function () {
  263. return (this.get('workStatus') == App.HostComponentStatus.started || this.get('workStatus') == App.HostComponentStatus.starting);
  264. }.property('workStatus'),
  265. /**
  266. * No action available while component is starting/stopping/unknown
  267. */
  268. noActionAvailable: function () {
  269. var workStatus = this.get('workStatus');
  270. if ([App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.unknown].contains(workStatus)) {
  271. return "hidden";
  272. }else{
  273. return "";
  274. }
  275. }.property('workStatus'),
  276. isInProgress: function () {
  277. return (this.get('workStatus') === App.HostComponentStatus.stopping || this.get('workStatus') === App.HostComponentStatus.starting) || this.get('isDataNodeRecommissionAvailable');
  278. }.property('workStatus', 'isDataNodeRecommissionAvailable'),
  279. /**
  280. * Shows whether we need to show Decommision/Recomission buttons
  281. */
  282. isDataNode: function () {
  283. return this.get('content.componentName') === 'DATANODE';
  284. }.property('content'),
  285. isDecommissioning: function () {
  286. return this.get('isDataNode') && this.get("isDataNodeRecommissionAvailable");
  287. }.property("workStatus", "isDataNodeRecommissionAvailable"),
  288. /**
  289. * Set in template via binding from parent view
  290. */
  291. decommissionDataNodeHostNames: null,
  292. /**
  293. * Decommission is available whenever the service is started.
  294. */
  295. isDataNodeDecommissionAvailable: function () {
  296. return this.get('isStart') && !this.get('isDataNodeRecommissionAvailable');
  297. }.property('isStart', 'isDataNodeRecommissionAvailable'),
  298. /**
  299. * Recommission is available only when this hostname shows up in the
  300. * 'decommissionDataNodeHostNames'
  301. */
  302. isDataNodeRecommissionAvailable: function () {
  303. var decommissionHostNames = this.get('decommissionDataNodeHostNames');
  304. var hostName = App.router.get('mainHostDetailsController.content.hostName');
  305. return decommissionHostNames != null && decommissionHostNames.contains(hostName);
  306. }.property('App.router.mainHostDetailsController.content', 'decommissionDataNodeHostNames')
  307. }),
  308. timeSinceHeartBeat: function () {
  309. var d = this.get('content.lastHeartBeatTime');
  310. if (d) {
  311. return $.timeago(d);
  312. }
  313. return "";
  314. }.property('content.lastHeartBeatTime')
  315. });