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('isMaster')) {
  93. masterComponents.push(component);
  94. } else if (component.get('isSlave')) {
  95. slaveComponents.push(component);
  96. }
  97. }, this);
  98. return masterComponents.concat(slaveComponents);
  99. }.property('content', 'content.hostComponents.length'),
  100. clients: function () {
  101. var clients = [];
  102. this.get('content.hostComponents').forEach(function (component) {
  103. if (!component.get('componentName')) {
  104. //temporary fix because of different data in hostComponents and serviceComponents
  105. return;
  106. }
  107. if (!component.get('isSlave') && !component.get('isMaster')) {
  108. if (clients.length) {
  109. clients[clients.length - 1].set('isLast', false);
  110. }
  111. component.set('isLast', true);
  112. clients.push(component);
  113. }
  114. }, this);
  115. return clients;
  116. }.property('content'),
  117. addableComponentObject: Em.Object.extend({
  118. componentName: '',
  119. displayName: function () {
  120. return App.format.role(this.get('componentName'));
  121. }.property('componentName')
  122. }),
  123. isAddComponent: function () {
  124. return this.get('content.healthClass') !== 'health-status-DEAD-YELLOW';
  125. }.property('content.healthClass'),
  126. addableComponents: function () {
  127. var components = [];
  128. var services = App.Service.find();
  129. var dataNodeExists = false;
  130. var taskTrackerExists = false;
  131. var regionServerExists = false;
  132. this.get('content.hostComponents').forEach(function (component) {
  133. switch (component.get('componentName')) {
  134. case 'DATANODE':
  135. dataNodeExists = true;
  136. break;
  137. case 'TASKTRACKER':
  138. taskTrackerExists = true;
  139. break;
  140. case 'HBASE_REGIONSERVER':
  141. regionServerExists = true;
  142. break;
  143. }
  144. }, this);
  145. if (!dataNodeExists) {
  146. components.pushObject(this.addableComponentObject.create({ 'componentName': 'DATANODE' }));
  147. }
  148. if (!taskTrackerExists && services.findProperty('serviceName', 'MAPREDUCE')) {
  149. components.pushObject(this.addableComponentObject.create({ 'componentName': 'TASKTRACKER' }));
  150. }
  151. if (!regionServerExists && services.findProperty('serviceName', 'HBASE')) {
  152. components.pushObject(this.addableComponentObject.create({ 'componentName': 'HBASE_REGIONSERVER' }));
  153. }
  154. return components;
  155. }.property('content', 'content.hostComponents.length'),
  156. ComponentView: Em.View.extend({
  157. content: null,
  158. didInsertElement: function () {
  159. if (this.get('isInProgress')) {
  160. this.doBlinking();
  161. }
  162. },
  163. hostComponent: function () {
  164. var hostComponent = null;
  165. var serviceComponent = this.get('content');
  166. var host = App.router.get('mainHostDetailsController.content');
  167. if (host) {
  168. hostComponent = host.get('hostComponents').findProperty('componentName', serviceComponent.get('componentName'));
  169. }
  170. return hostComponent;
  171. }.property('content', 'App.router.mainHostDetailsController.content'),
  172. workStatus: function () {
  173. var workStatus = this.get('content.workStatus');
  174. var hostComponent = this.get('hostComponent');
  175. if (hostComponent) {
  176. workStatus = hostComponent.get('workStatus');
  177. }
  178. return workStatus;
  179. }.property('content.workStatus', 'hostComponent.workStatus'),
  180. /**
  181. * Return host component text status
  182. */
  183. componentTextStatus: function () {
  184. var workStatus = this.get("workStatus");
  185. var componentTextStatus = this.get('content.componentTextStatus');
  186. var hostComponent = this.get('hostComponent');
  187. if (hostComponent) {
  188. componentTextStatus = hostComponent.get('componentTextStatus');
  189. if(this.get("isDataNode"))
  190. if(this.get('isDataNodeRecommissionAvailable')){
  191. if(App.HostComponentStatus.started == workStatus){
  192. componentTextStatus = "Decommissioning...";
  193. }else if(App.HostComponentStatus.stopped == workStatus){
  194. componentTextStatus = "Decommissioned";
  195. }
  196. }
  197. }
  198. return componentTextStatus;
  199. }.property('workStatus','isDataNodeRecommissionAvailable'),
  200. statusClass: function () {
  201. var statusClass = null;
  202. //If the component is DataNode
  203. if (this.get('isDataNode')) {
  204. if (this.get('isDataNodeRecommissionAvailable') && (this.get('isStart') || this.get('workStatus') == 'INSTALLED')) {
  205. return 'health-status-DEAD-ORANGE';
  206. }
  207. }
  208. //Class when install failed
  209. if (this.get('workStatus') === App.HostComponentStatus.install_failed) {
  210. return 'health-status-color-red icon-cog';
  211. }
  212. //Class when installing
  213. if (this.get('workStatus') === App.HostComponentStatus.installing) {
  214. return 'health-status-color-blue icon-cog';
  215. }
  216. //For all other cases
  217. return 'health-status-' + App.HostComponentStatus.getKeyName(this.get('workStatus'));
  218. }.property('workStatus', 'isDataNodeRecommissionAvailable', 'this.content.isDecommissioning'),
  219. /**
  220. * For Upgrade failed state
  221. */
  222. isUpgradeFailed: function () {
  223. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "upgrade_failed";
  224. }.property("workStatus"),
  225. /**
  226. * For Install failed state
  227. */
  228. isInstallFailed: function () {
  229. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "install_failed";
  230. }.property("workStatus"),
  231. /**
  232. * Do blinking for 1 minute
  233. */
  234. doBlinking: function () {
  235. var workStatus = this.get('workStatus');
  236. var self = this;
  237. var pulsate = [ App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.installing].contains(workStatus);
  238. if (!pulsate && this.get('isDataNode')) {
  239. var dataNodeComponent = this.get('content');
  240. if (dataNodeComponent && workStatus != "INSTALLED") {
  241. pulsate = this.get('isDataNodeRecommissionAvailable');
  242. }
  243. }
  244. if (pulsate && !self.get('isBlinking')) {
  245. self.set('isBlinking', true);
  246. uiEffects.pulsate(self.$('.components-health'), 1000, function () {
  247. !self.get('isDestroyed') && self.set('isBlinking', false);
  248. self.doBlinking();
  249. });
  250. }
  251. },
  252. /**
  253. * Start blinking when host component is starting/stopping
  254. */
  255. startBlinking: function () {
  256. this.$('.components-health').stop(true, true);
  257. this.$('.components-health').css({opacity: 1.0});
  258. this.doBlinking();
  259. }.observes('workStatus','isDataNodeRecommissionAvailable'),
  260. isStart: function () {
  261. return (this.get('workStatus') == App.HostComponentStatus.started || this.get('workStatus') == App.HostComponentStatus.starting);
  262. }.property('workStatus'),
  263. isInstalling: function () {
  264. return (this.get('workStatus') == App.HostComponentStatus.installing);
  265. }.property('workStatus'),
  266. /**
  267. * No action available while component is starting/stopping/unknown
  268. */
  269. noActionAvailable: function () {
  270. var workStatus = this.get('workStatus');
  271. if ([App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.unknown].contains(workStatus)) {
  272. return "hidden";
  273. }else{
  274. return "";
  275. }
  276. }.property('workStatus'),
  277. isInProgress: function () {
  278. return (this.get('workStatus') === App.HostComponentStatus.stopping || this.get('workStatus') === App.HostComponentStatus.starting) || this.get('isDataNodeRecommissionAvailable');
  279. }.property('workStatus', 'isDataNodeRecommissionAvailable'),
  280. /**
  281. * Shows whether we need to show Decommision/Recomission buttons
  282. */
  283. isDataNode: function () {
  284. return this.get('content.componentName') === 'DATANODE';
  285. }.property('content'),
  286. isDecommissioning: function () {
  287. return this.get('isDataNode') && this.get("isDataNodeRecommissionAvailable");
  288. }.property("workStatus", "isDataNodeRecommissionAvailable"),
  289. /**
  290. * Set in template via binding from parent view
  291. */
  292. decommissionDataNodeHostNames: null,
  293. /**
  294. * Decommission is available whenever the service is started.
  295. */
  296. isDataNodeDecommissionAvailable: function () {
  297. return this.get('isStart') && !this.get('isDataNodeRecommissionAvailable');
  298. }.property('isStart', 'isDataNodeRecommissionAvailable'),
  299. /**
  300. * Recommission is available only when this hostname shows up in the
  301. * 'decommissionDataNodeHostNames'
  302. */
  303. isDataNodeRecommissionAvailable: function () {
  304. var decommissionHostNames = this.get('decommissionDataNodeHostNames');
  305. var hostName = App.router.get('mainHostDetailsController.content.hostName');
  306. return decommissionHostNames != null && decommissionHostNames.contains(hostName);
  307. }.property('App.router.mainHostDetailsController.content', 'decommissionDataNodeHostNames')
  308. }),
  309. timeSinceHeartBeat: function () {
  310. var d = this.get('content.lastHeartBeatTime');
  311. if (d) {
  312. return $.timeago(d);
  313. }
  314. return "";
  315. }.property('content.lastHeartBeatTime')
  316. });