summary.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. App.MainHostSummaryView = Em.View.extend({
  20. templateName: require('templates/main/host/summary'),
  21. /**
  22. * List of custom view for some host components
  23. * @type {Em.Object}
  24. * Format:
  25. * <code>
  26. * {
  27. * COMPONENT_NAME1: VIEW1,
  28. * COMPONENT_NAME2: VIEW2
  29. * ....
  30. * }
  31. * </code>
  32. */
  33. hostComponentViewMap: Em.Object.create({
  34. 'DATANODE': App.DataNodeComponentView,
  35. 'NODEMANAGER': App.NodeManagerComponentView,
  36. 'HBASE_REGIONSERVER': App.RegionServerComponentView,
  37. 'TASKTRACKER': App.TaskTrackerComponentView
  38. }),
  39. /**
  40. * @type {bool}
  41. */
  42. isStopCommand:true,
  43. /**
  44. * @type {App.Host}
  45. */
  46. content: function () {
  47. return App.router.get('mainHostDetailsController.content');
  48. }.property('App.router.mainHostDetailsController.content'),
  49. showGangliaCharts: function () {
  50. var name = this.get('content.hostName');
  51. var gangliaMobileUrl = App.router.get('clusterController.gangliaUrl') + "/mobile_helper.php?show_host_metrics=1&h=" + name + "&c=HDPNameNode&r=hour&cs=&ce=";
  52. window.open(gangliaMobileUrl);
  53. },
  54. /**
  55. * Message for "restart" block
  56. * @type {String}
  57. */
  58. needToRestartMessage: function() {
  59. var componentsCount, word;
  60. componentsCount = this.get('content.componentsWithStaleConfigsCount');
  61. if (componentsCount > 1) {
  62. word = Em.I18n.t('common.components').toLowerCase();
  63. } else {
  64. word = Em.I18n.t('common.component').toLowerCase();
  65. }
  66. return Em.I18n.t('hosts.host.details.needToRestart').format(this.get('content.componentsWithStaleConfigsCount'), word);
  67. }.property('content.componentsWithStaleConfigsCount'),
  68. /**
  69. * Reset <code>sortedComponents</code>
  70. * Used when some component was deleted from host
  71. */
  72. redrawComponents: function() {
  73. if (App.router.get('mainHostDetailsController.redrawComponents')) {
  74. this.set('sortedComponents', []);
  75. this.sortedComponentsFormatter();
  76. App.router.set('mainHostDetailsController.redrawComponents', false);
  77. }
  78. }.observes('App.router.mainHostDetailsController.redrawComponents'),
  79. willInsertElement: function() {
  80. this.set('sortedComponents', []);
  81. this.sortedComponentsFormatter();
  82. },
  83. didInsertElement: function () {
  84. this.addToolTip();
  85. },
  86. /**
  87. * Create tooltip for "Add" button if nothing to add to the current host
  88. */
  89. addToolTip: function() {
  90. if (this.get('addComponentDisabled')) {
  91. App.tooltip($('#add_component'), {title: Em.I18n.t('services.nothingToAdd')});
  92. }
  93. }.observes('addComponentDisabled'),
  94. /**
  95. * List of installed services
  96. * @type {String[]}
  97. */
  98. installedServices: function () {
  99. return App.Service.find().mapProperty('serviceName');
  100. }.property('App.router.clusterController.dataLoadList.serviceMetrics'),
  101. /**
  102. * List of installed masters and slaves
  103. * Masters first, then slaves
  104. * @type {App.HostComponent[]}
  105. */
  106. sortedComponents: [],
  107. /**
  108. * Update <code>sortedComponents</code>
  109. * Master components first, then slaves
  110. */
  111. sortedComponentsFormatter: function() {
  112. var updatebleProperties = Em.A(['workStatus', 'passiveState', 'staleConfigs', 'haStatus']);
  113. var self = this;
  114. var hostComponentViewMap = this.get('hostComponentViewMap');
  115. // Remove deleted components
  116. this.get('sortedComponents').forEach(function(sortedComponent, index) {
  117. if (!self.get('content.hostComponents').findProperty('id', sortedComponent.get('id'))) {
  118. self.get('sortedComponents').removeAt(index, 1);
  119. }
  120. });
  121. this.get('content.hostComponents').forEach(function (component) {
  122. if (component.get('isMaster') || component.get('isSlave')) {
  123. var obj = this.get('sortedComponents').findProperty('id', component.get('id'));
  124. if (obj) {
  125. // Update existing component
  126. updatebleProperties.forEach(function(property) {
  127. obj.set(property, component.get(property));
  128. });
  129. }
  130. else {
  131. // Add new component
  132. component.set('view', hostComponentViewMap[component.get('componentName')] ? hostComponentViewMap[component.get('componentName')] : App.HostComponentView);
  133. if (component.get('isMaster')) {
  134. // Masters should be before slaves
  135. var lastMasterIndex = 0, atLeastOneMasterExists = false;
  136. this.get('sortedComponents').forEach(function(sortedComponent, index) {
  137. if (sortedComponent.get('isMaster')) {
  138. lastMasterIndex = index;
  139. atLeastOneMasterExists = true;
  140. }
  141. });
  142. this.get('sortedComponents').insertAt(atLeastOneMasterExists ? lastMasterIndex + 1 : 0, component);
  143. }
  144. else {
  145. // it is slave 100%
  146. this.get('sortedComponents').pushObject(component);
  147. }
  148. }
  149. }
  150. }, this);
  151. }.observes('content.hostComponents.length'),
  152. /**
  153. * List of installed clients
  154. * @type {App.HostComponent[]}
  155. */
  156. clients: function () {
  157. var clients = [];
  158. this.get('content.hostComponents').forEach(function (component) {
  159. if (!component.get('componentName')) {
  160. //temporary fix because of different data in hostComponents and serviceComponents
  161. return;
  162. }
  163. if (!component.get('isSlave') && !component.get('isMaster')) {
  164. if (clients.length) {
  165. clients[clients.length - 1].set('isLast', false);
  166. }
  167. component.set('isLast', true);
  168. clients.push(component);
  169. }
  170. }, this);
  171. return clients;
  172. }.property('content.hostComponents.length'),
  173. /**
  174. * Check if some clients have stale configs
  175. * @type {bool}
  176. */
  177. areClientWithStaleConfigs: function() {
  178. return !!this.get('clients').filter(function(component) {
  179. return component.get('staleConfigs');
  180. }).length;
  181. }.property('clients.@each.staleConfigs'),
  182. /**
  183. * Template for addable component
  184. * @type {Em.Object}
  185. */
  186. addableComponentObject: Em.Object.extend({
  187. componentName: '',
  188. subComponentNames: null,
  189. displayName: function () {
  190. if (this.get('componentName') === 'CLIENTS') {
  191. return this.t('common.clients');
  192. }
  193. return App.format.role(this.get('componentName'));
  194. }.property('componentName')
  195. }),
  196. /**
  197. * If host lost heartbeat, components can't be added on it
  198. * @type {bool}
  199. */
  200. isAddComponent: function () {
  201. return this.get('content.healthClass') !== 'health-status-DEAD-YELLOW';
  202. }.property('content.healthClass'),
  203. /**
  204. * Disable "Add" button if components can't be added to the current host
  205. * @type {bool}
  206. */
  207. addComponentDisabled: function() {
  208. return (!this.get('isAddComponent')) || (this.get('addableComponents.length') == 0);
  209. }.property('isAddComponent', 'addableComponents.length'),
  210. /**
  211. * List of client's that may be installed to the current host
  212. * @type {String[]}
  213. */
  214. installableClientComponents: function() {
  215. if (!App.supports.deleteHost) {
  216. return [];
  217. }
  218. var componentServiceMap = App.QuickDataMapper.componentServiceMap();
  219. var allClients = App.StackServiceComponent.find().filterProperty('isClient',true).mapProperty('componentName');
  220. var installedServices = this.get('installedServices');
  221. var installedClients = this.get('clients').mapProperty('componentName');
  222. return allClients.filter(function(componentName) {
  223. // service for current client is installed but client isn't installed on current host
  224. return installedServices.contains(componentServiceMap[componentName]) && !installedClients.contains(componentName);
  225. });
  226. }.property('content.hostComponents.length', 'installedServices.length', 'App.supports.deleteHost'),
  227. /**
  228. * List of components that may be added to the current host
  229. * @type {Em.Object[]}
  230. */
  231. addableComponents: function () {
  232. var components = [];
  233. var self = this;
  234. var installableClients = this.get('installableClientComponents');
  235. var installedComponents = this.get('content.hostComponents').mapProperty('componentName');
  236. var addableToHostComponents = App.get('components.addableToHost');
  237. var installedServices = this.get('installedServices');
  238. var componentServiceMap = App.QuickDataMapper.componentServiceMap();
  239. addableToHostComponents.forEach(function(addableComponent) {
  240. if(installedServices.contains(componentServiceMap[addableComponent]) && !installedComponents.contains(addableComponent)) {
  241. components.pushObject(self.addableComponentObject.create({'componentName': addableComponent}));
  242. }
  243. });
  244. if (installableClients.length > 0) {
  245. components.pushObject(this.addableComponentObject.create({ 'componentName': 'CLIENTS', subComponentNames: installableClients }));
  246. }
  247. return components;
  248. }.property('content.hostComponents.length', 'installableClientComponents'),
  249. /**
  250. * Formatted with <code>$.timeago</code> value of host's last heartbeat
  251. * @type {String}
  252. */
  253. timeSinceHeartBeat: function () {
  254. var d = this.get('content.lastHeartBeatTime');
  255. if (d) {
  256. return $.timeago(d);
  257. }
  258. return "";
  259. }.property('content.lastHeartBeatTime')
  260. });