summary.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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(App.TimeRangeMixin, {
  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: Em.computed.alias('App.router.mainHostDetailsController.content'),
  47. /**
  48. * Host metrics panel not displayed when Metrics service (ex:Ganglia) is not in stack definition.
  49. */
  50. isNoHostMetricsService: Em.computed.equal('App.services.hostMetrics.length', 0),
  51. /**
  52. * Message for "restart" block
  53. * @type {String}
  54. */
  55. needToRestartMessage: function() {
  56. var componentsCount, word;
  57. componentsCount = this.get('content.componentsWithStaleConfigsCount');
  58. if (componentsCount > 1) {
  59. word = Em.I18n.t('common.components').toLowerCase();
  60. } else {
  61. word = Em.I18n.t('common.component').toLowerCase();
  62. }
  63. return Em.I18n.t('hosts.host.details.needToRestart').format(this.get('content.componentsWithStaleConfigsCount'), word);
  64. }.property('content.componentsWithStaleConfigsCount'),
  65. /**
  66. * Reset <code>sortedComponents</code>
  67. * Used when some component was deleted from host
  68. */
  69. redrawComponents: function() {
  70. if (App.router.get('mainHostDetailsController.redrawComponents')) {
  71. this.set('sortedComponents', []);
  72. this.sortedComponentsFormatter();
  73. App.router.set('mainHostDetailsController.redrawComponents', false);
  74. }
  75. }.observes('App.router.mainHostDetailsController.redrawComponents'),
  76. willInsertElement: function() {
  77. this.set('sortedComponents', []);
  78. this.sortedComponentsFormatter();
  79. this.addObserver('content.hostComponents.length', this, 'sortedComponentsFormatter');
  80. },
  81. didInsertElement: function () {
  82. this._super();
  83. this.addToolTip();
  84. },
  85. /**
  86. * Create tooltip for "Add" button if nothing to add to the current host
  87. */
  88. addToolTip: function() {
  89. if (this.get('addComponentDisabled')) {
  90. App.tooltip($('#add_component'), {title: Em.I18n.t('services.nothingToAdd')});
  91. }
  92. }.observes('addComponentDisabled'),
  93. /**
  94. * List of installed services
  95. * @type {String[]}
  96. */
  97. installedServices: function () {
  98. return App.Service.find().mapProperty('serviceName');
  99. }.property('App.router.clusterController.dataLoadList.services'),
  100. /**
  101. * List of installed masters and slaves
  102. * Masters first, then slaves
  103. * @type {App.HostComponent[]}
  104. */
  105. sortedComponents: [],
  106. /**
  107. * Update <code>sortedComponents</code>
  108. * Master components first, then slaves
  109. */
  110. sortedComponentsFormatter: function() {
  111. var updatebleProperties = Em.A(['workStatus', 'passiveState', 'staleConfigs', 'haStatus']);
  112. var self = this;
  113. var hostComponentViewMap = this.get('hostComponentViewMap');
  114. // Remove deleted components
  115. this.get('sortedComponents').forEach(function(sortedComponent, index) {
  116. if (!self.get('content.hostComponents').findProperty('id', sortedComponent.get('id'))) {
  117. self.get('sortedComponents').removeAt(index, 1);
  118. }
  119. });
  120. this.get('content.hostComponents').forEach(function (component) {
  121. if (component.get('isMaster') || component.get('isSlave')) {
  122. var obj = this.get('sortedComponents').findProperty('id', component.get('id'));
  123. if (obj) {
  124. // Update existing component
  125. updatebleProperties.forEach(function(property) {
  126. obj.set(property, component.get(property));
  127. });
  128. }
  129. else {
  130. // Add new component
  131. component.set('viewClass', hostComponentViewMap[component.get('componentName')] ? hostComponentViewMap[component.get('componentName')] : App.HostComponentView);
  132. if (component.get('isMaster')) {
  133. // Masters should be before slaves
  134. var lastMasterIndex = 0, atLeastOneMasterExists = false;
  135. this.get('sortedComponents').forEach(function(sortedComponent, index) {
  136. if (sortedComponent.get('isMaster')) {
  137. lastMasterIndex = index;
  138. atLeastOneMasterExists = true;
  139. }
  140. });
  141. this.get('sortedComponents').insertAt(atLeastOneMasterExists ? lastMasterIndex + 1 : 0, component);
  142. }
  143. else {
  144. // it is slave 100%
  145. this.get('sortedComponents').pushObject(component);
  146. }
  147. }
  148. }
  149. }, this);
  150. },
  151. /**
  152. * List of installed clients
  153. * @type {App.HostComponent[]}
  154. */
  155. clients: function () {
  156. var clients = [];
  157. this.get('content.hostComponents').forEach(function (component) {
  158. if (!component.get('componentName')) {
  159. //temporary fix because of different data in hostComponents and serviceComponents
  160. return;
  161. }
  162. if (!component.get('isSlave') && !component.get('isMaster')) {
  163. if (clients.length) {
  164. clients[clients.length - 1].set('isLast', false);
  165. }
  166. component.set('isLast', true);
  167. if (['INSTALL_FAILED', 'INIT'].contains(component.get('workStatus'))) {
  168. component.set('isInstallFailed', true);
  169. }
  170. clients.push(component);
  171. }
  172. }, this);
  173. return clients;
  174. }.property('content.hostComponents.length'),
  175. anyClientFailedToInstall: Em.computed.someBy('clients', 'isInstallFailed', true),
  176. /**
  177. * Check if some clients not installed or started
  178. *
  179. * @type {bool}
  180. **/
  181. areClientsNotInstalled: Em.computed.or('anyClientFailedToInstall', 'installableClientComponents.length'),
  182. /**
  183. * Check if some clients have stale configs
  184. * @type {bool}
  185. */
  186. areClientWithStaleConfigs: Em.computed.someBy('clients', 'staleConfigs', true),
  187. /**
  188. * Template for addable component
  189. * @type {Em.Object}
  190. */
  191. addableComponentObject: Em.Object.extend({
  192. componentName: '',
  193. subComponentNames: null,
  194. displayName: function () {
  195. if (this.get('componentName') === 'CLIENTS') {
  196. return this.t('common.clients');
  197. }
  198. return App.format.role(this.get('componentName'));
  199. }.property('componentName')
  200. }),
  201. /**
  202. * If host lost heartbeat, components can't be added on it
  203. * @type {bool}
  204. */
  205. isAddComponent: Em.computed.notEqual('content.healthClass', 'health-status-DEAD-YELLOW'),
  206. /**
  207. * Disable "Add" button if components can't be added to the current host
  208. * @type {bool}
  209. */
  210. addComponentDisabled: Em.computed.or('!isAddComponent', '!addableComponents.length'),
  211. /**
  212. * List of client's that may be installed to the current host
  213. * @type {String[]}
  214. */
  215. installableClientComponents: function() {
  216. var clientComponents = App.StackServiceComponent.find().filterProperty('isClient');
  217. var installedServices = this.get('installedServices');
  218. var installedClients = this.get('clients').mapProperty('componentName');
  219. return clientComponents.filter(function(component) {
  220. // service for current client is installed but client isn't installed on current host
  221. return installedServices.contains(component.get('serviceName')) && !installedClients.contains(component.get('componentName'));
  222. });
  223. }.property('content.hostComponents.length', 'installedServices.length'),
  224. notInstalledClientComponents: function () {
  225. return this.get('clients').filter(function(component) {
  226. return ['INIT', 'INSTALL_FAILED'].contains(component.get('workStatus'));
  227. }).concat(this.get('installableClientComponents'));
  228. }.property('installableClientComponents.length', 'clients.length'),
  229. /**
  230. * List of components that may be added to the current host
  231. * @type {Em.Object[]}
  232. */
  233. addableComponents: function () {
  234. var components = [];
  235. var self = this;
  236. if (this.get('content.hostComponents')) {
  237. var installedComponents = this.get('content.hostComponents').mapProperty('componentName');
  238. var addableToHostComponents = App.StackServiceComponent.find().filterProperty('isAddableToHost');
  239. var installedServices = this.get('installedServices');
  240. addableToHostComponents.forEach(function (addableComponent) {
  241. if (installedServices.contains(addableComponent.get('serviceName')) && !installedComponents.contains(addableComponent.get('componentName'))) {
  242. if ((addableComponent.get('componentName') === 'OOZIE_SERVER') && !App.router.get('mainHostDetailsController.isOozieServerAddable')) {
  243. return;
  244. }
  245. components.pushObject(self.addableComponentObject.create({
  246. 'componentName': addableComponent.get('componentName'),
  247. 'serviceName': addableComponent.get('serviceName')
  248. }));
  249. }
  250. });
  251. }
  252. return components;
  253. }.property('content.hostComponents.length', 'App.components.addableToHost.@each'),
  254. /**
  255. * Formatted with <code>$.timeago</code> value of host's last heartbeat
  256. * @type {String}
  257. */
  258. timeSinceHeartBeat: function () {
  259. var d = this.get('content.rawLastHeartBeatTime');
  260. return d ? $.timeago(d) : '';
  261. }.property('content.rawLastHeartBeatTime'),
  262. /**
  263. * Get clients with custom commands
  264. */
  265. clientsWithCustomCommands: function() {
  266. var clients = this.get('clients').rejectProperty('componentName', 'KERBEROS_CLIENT');
  267. var options = [];
  268. var clientWithCommands;
  269. clients.forEach(function(client) {
  270. var componentName = client.get('componentName');
  271. var customCommands = App.StackServiceComponent.find(componentName).get('customCommands');
  272. if (customCommands.length) {
  273. clientWithCommands = {
  274. label: client.get('displayName'),
  275. commands: []
  276. };
  277. customCommands.forEach(function(command) {
  278. clientWithCommands.commands.push({
  279. label: Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command),
  280. service: client.get('service.serviceName'),
  281. hosts: client.get('hostName'),
  282. component: componentName,
  283. command: command
  284. });
  285. });
  286. options.push(clientWithCommands);
  287. }
  288. });
  289. return options;
  290. }.property('controller')
  291. });