host_component_view.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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.HostComponentView = Em.View.extend({
  21. templateName: require('templates/main/host/details/host_component'),
  22. /**
  23. * @type {App.HostComponent}
  24. */
  25. content: null,
  26. excludedMasterCommands: ['DECOMMISSION', 'RECOMMISSION'],
  27. /**
  28. * @type {App.HostComponent}
  29. */
  30. hostComponent: function () {
  31. var hostComponent = null;
  32. var serviceComponent = this.get('content');
  33. var host = App.router.get('mainHostDetailsController.content');
  34. if (host) {
  35. hostComponent = host.get('hostComponents').findProperty('componentName', serviceComponent.get('componentName'));
  36. }
  37. return hostComponent;
  38. }.property('content', 'App.router.mainHostDetailsController.content'),
  39. /**
  40. * @type {String}
  41. */
  42. workStatus: function () {
  43. var workStatus = this.get('content.workStatus');
  44. var hostComponent = this.get('hostComponent');
  45. if (hostComponent) {
  46. workStatus = hostComponent.get('workStatus');
  47. }
  48. return workStatus;
  49. }.property('content.workStatus', 'hostComponent.workStatus'),
  50. /**
  51. * Return host component text status
  52. * @type {String}
  53. */
  54. componentTextStatus: function () {
  55. var componentTextStatus = this.get('content.componentTextStatus');
  56. var hostComponent = this.get('hostComponent');
  57. if (hostComponent) {
  58. componentTextStatus = hostComponent.get('componentTextStatus');
  59. }
  60. return componentTextStatus;
  61. }.property('content.passiveState','workStatus'),
  62. /**
  63. * CSS-class for host component status
  64. * @type {String}
  65. */
  66. statusClass: function () {
  67. //Class when install failed
  68. if (this.get('workStatus') === App.HostComponentStatus.install_failed) {
  69. return 'health-status-color-red icon-cog';
  70. }
  71. //Class when installing
  72. if (this.get('workStatus') === App.HostComponentStatus.installing) {
  73. return 'health-status-color-blue icon-cog';
  74. }
  75. //For all other cases
  76. return 'health-status-' + App.HostComponentStatus.getKeyName(this.get('workStatus'));
  77. }.property('workStatus'),
  78. /**
  79. * CSS-icon-class for host component status
  80. * @type {String}
  81. */
  82. statusIconClass: function () {
  83. return Em.getWithDefault({
  84. 'health-status-started': App.healthIconClassGreen,
  85. 'health-status-starting': App.healthIconClassGreen,
  86. 'health-status-installed': App.healthIconClassRed,
  87. 'health-status-stopping': App.healthIconClassRed,
  88. 'health-status-unknown': App.healthIconClassYellow,
  89. 'health-status-DEAD-ORANGE': App.healthIconClassOrange
  90. }, this.get('statusClass'), '');
  91. }.property('statusClass'),
  92. /**
  93. * CSS-class for disabling drop-down menu with list of host component actions
  94. * Disabled if host's <code>healthClass</code> is health-status-DEAD-YELLOW (lost heartbeat)
  95. * Disabled if component's action list is empty
  96. * @type {String}
  97. */
  98. disabled: function () {
  99. return ( (this.get('parentView.content.healthClass') === "health-status-DEAD-YELLOW") || (this.get('noActionAvailable') === 'hidden' && this.get('isRestartComponentDisabled'))) ? 'disabled' : '';
  100. }.property('parentView.content.healthClass', 'noActionAvailable', 'isRestartComponentDisabled'),
  101. /**
  102. * For Upgrade failed state
  103. * @type {bool}
  104. */
  105. isUpgradeFailed: function () {
  106. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "upgrade_failed";
  107. }.property("workStatus"),
  108. /**
  109. * For Install failed state
  110. * @type {bool}
  111. */
  112. isInstallFailed: function () {
  113. return App.HostComponentStatus.getKeyName(this.get('workStatus')) === "install_failed";
  114. }.property("workStatus"),
  115. /**
  116. * For Started and Starting states
  117. * @type {bool}
  118. */
  119. isStart: function () {
  120. return [App.HostComponentStatus.started, App.HostComponentStatus.starting].contains(this.get('workStatus'));
  121. }.property('workStatus'),
  122. /**
  123. * For Installed state
  124. * @type {bool}
  125. */
  126. isStop: function () {
  127. return (this.get('workStatus') == App.HostComponentStatus.stopped);
  128. }.property('workStatus'),
  129. /**
  130. * For Installing state
  131. * @type {bool}
  132. */
  133. isInstalling: function () {
  134. return (this.get('workStatus') == App.HostComponentStatus.installing);
  135. }.property('workStatus'),
  136. /**
  137. * For Init state
  138. * @type {bool}
  139. */
  140. isInit: function() {
  141. return this.get('workStatus') == App.HostComponentStatus.init;
  142. }.property('workStatus'),
  143. /**
  144. * No action available while component is starting/stopping/unknown
  145. * @type {String}
  146. */
  147. noActionAvailable: function () {
  148. var workStatus = this.get('workStatus');
  149. return [App.HostComponentStatus.starting, App.HostComponentStatus.stopping,
  150. App.HostComponentStatus.unknown, App.HostComponentStatus.disabled].contains(workStatus) ? "hidden" : '';
  151. }.property('workStatus'),
  152. /**
  153. * For Stopping or Starting states
  154. * @type {bool}
  155. */
  156. isInProgress: function () {
  157. return (this.get('workStatus') === App.HostComponentStatus.stopping ||
  158. this.get('workStatus') === App.HostComponentStatus.starting);
  159. }.property('workStatus'),
  160. /**
  161. * For OFF <code>passiveState</code> of host component
  162. * @type {bool}
  163. */
  164. isActive: function () {
  165. return (this.get('content.passiveState') == "OFF");
  166. }.property('content.passiveState'),
  167. /**
  168. * Shows whether we need to show Delete button
  169. * @type {bool}
  170. */
  171. isDeletableComponent: function () {
  172. return App.get('components.deletable').contains(this.get('content.componentName'));
  173. }.property('content'),
  174. /**
  175. * Host component with some <code>workStatus</code> can't be moved (so, disable such action in the dropdown list)
  176. * @type {bool}
  177. */
  178. isMoveComponentDisabled: function () {
  179. return App.allHostNames.length === App.HostComponent.find().filterProperty('componentName', this.get('content.componentName')).mapProperty('hostName').length;
  180. }.property('content'),
  181. /**
  182. * Host component with some <code>workStatus</code> can't be deleted (so, disable such action in the dropdown list)
  183. * @type {bool}
  184. */
  185. isDeleteComponentDisabled: function () {
  186. var stackComponentCount = App.StackServiceComponent.find(this.get('hostComponent.componentName')).get('minToInstall');
  187. var installedCount = this.get('componentCounter');
  188. return (installedCount <= stackComponentCount)
  189. || ![App.HostComponentStatus.stopped, App.HostComponentStatus.unknown, App.HostComponentStatus.install_failed, App.HostComponentStatus.upgrade_failed, App.HostComponentStatus.init].contains(this.get('workStatus'));
  190. }.property('workStatus'),
  191. /**
  192. * gets number of current component that are applied to the cluster;
  193. * @returns {Number}
  194. */
  195. componentCounter: function() {
  196. var componentCounter = 0;
  197. var stackServiceComponent = App.StackServiceComponent.find(this.get('hostComponent.componentName'));
  198. if (stackServiceComponent && App.get('router.clusterController.isHostContentLoaded')) {
  199. if (stackServiceComponent.get('isMaster')) {
  200. componentCounter = App.HostComponent.find().filterProperty('componentName', this.get('content.componentName')).length
  201. } else {
  202. var slaveComponent = App.SlaveComponent.find().findProperty('componentName', this.get('content.componentName'));
  203. if (slaveComponent) {
  204. componentCounter = slaveComponent.get('totalCount');
  205. }
  206. }
  207. }
  208. return componentCounter;
  209. }.property('App.router.clusterController.isHostContentLoaded'),
  210. /**
  211. * Gets number of current running components that are applied to the cluster
  212. * @returns {Number}
  213. */
  214. runningComponentCounter: function () {
  215. var runningComponents;
  216. var self = this;
  217. runningComponents = App.HostComponent.find().filter(function (component) {
  218. return (component.get('componentName') === self.get('content.componentName') && [App.HostComponentStatus.started, App.HostComponentStatus.starting].contains(component.get('workStatus')))
  219. });
  220. return runningComponents ? runningComponents.length : 0;
  221. },
  222. /**
  223. * Check if component may be reassinged to another host
  224. * @type {bool}
  225. */
  226. isReassignable: function () {
  227. return App.get('components.reassignable').contains(this.get('content.componentName')) && App.router.get('mainHostController.hostsCountMap')['TOTAL'] > 1;
  228. }.property('content.componentName'),
  229. /**
  230. * Check if component is restartable
  231. * @type {bool}
  232. */
  233. isRestartableComponent: function() {
  234. return App.get('components.restartable').contains(this.get('content.componentName'));
  235. }.property('content'),
  236. /**
  237. * Host component with some <code>workStatus</code> can't be restarted (so, disable such action in the dropdown list)
  238. * @type {bool}
  239. */
  240. isRestartComponentDisabled: function() {
  241. return ![App.HostComponentStatus.started].contains(this.get('workStatus'));
  242. }.property('workStatus'),
  243. /**
  244. * Check if component configs can be refreshed
  245. * @type {bool}
  246. */
  247. isRefreshConfigsAllowed: function() {
  248. return App.get('components.refreshConfigsAllowed').contains(this.get('content.componentName'));
  249. }.property('content'),
  250. willInsertElement: function() {
  251. //make link to view instance to get decommission state
  252. this.set('content.view', this);
  253. },
  254. didInsertElement: function () {
  255. App.tooltip($('[rel=componentHealthTooltip]'));
  256. App.tooltip($('[rel=passiveTooltip]'));
  257. if (this.get('isInProgress')) {
  258. this.doBlinking();
  259. }
  260. },
  261. /**
  262. * Do blinking for 1 minute
  263. */
  264. doBlinking: function () {
  265. var workStatus = this.get('workStatus');
  266. var self = this;
  267. var pulsate = [ App.HostComponentStatus.starting, App.HostComponentStatus.stopping, App.HostComponentStatus.installing].contains(workStatus);
  268. if (pulsate && !self.get('isBlinking')) {
  269. self.set('isBlinking', true);
  270. uiEffects.pulsate(self.$('.components-health'), 1000, function () {
  271. self.set('isBlinking', false);
  272. self.doBlinking();
  273. });
  274. }
  275. },
  276. /**
  277. * Start blinking when host component is starting/stopping
  278. */
  279. startBlinking: function () {
  280. this.$('.components-health').stop(true, true);
  281. this.$('.components-health').css({opacity: 1.0});
  282. this.doBlinking();
  283. }.observes('workStatus'),
  284. /**
  285. * Get custom commands for slave components
  286. */
  287. customCommands: function() {
  288. var customCommands;
  289. var hostComponent = this.get('content');
  290. var component = App.StackServiceComponent.find(hostComponent.get('componentName'));
  291. customCommands = this.getCustomCommands(component, hostComponent, component.get('isSlave'));
  292. return customCommands;
  293. }.property('content', 'workStatus'),
  294. /**
  295. * Get a list of custom commands
  296. *
  297. * @param component
  298. * @param hostComponent
  299. * @param isSlave
  300. * @returns {Array}
  301. */
  302. getCustomCommands: function (component, hostComponent, isSlave) {
  303. isSlave = isSlave || false;
  304. if (!component || !hostComponent) {
  305. return [];
  306. }
  307. var self = this;
  308. var commands = component.get('customCommands');
  309. var customCommands = [];
  310. commands.forEach(function(command) {
  311. if (!isSlave && !self.meetsCustomCommandReq(component, command)) {
  312. return;
  313. }
  314. customCommands.push({
  315. label: self.getCustomCommandLabel(command, isSlave),
  316. service: component.get('serviceName'),
  317. hosts: hostComponent.get('hostName'),
  318. context: isSlave ? null : App.HostComponentActionMap.getMap(self)[command].context,
  319. component: component.get('componentName'),
  320. command: command
  321. });
  322. });
  323. return customCommands;
  324. },
  325. /**
  326. * Get the Label of the custom command
  327. *
  328. * @param command
  329. * @returns {String}
  330. */
  331. getCustomCommandLabel: function (command, isSlave) {
  332. if (isSlave) {
  333. return Em.I18n.t('services.service.actions.run.executeCustomCommand.menu').format(command)
  334. }
  335. return App.HostComponentActionMap.getMap(this)[command].label;
  336. },
  337. /**
  338. * The custom command meets the requirements to be active on master
  339. *
  340. * @param component
  341. * @param command
  342. *
  343. * @return {Boolean}
  344. */
  345. meetsCustomCommandReq: function (component, command) {
  346. var excludedMasterCommands = this.get('excludedMasterCommands');
  347. if (excludedMasterCommands.indexOf(command) >= 0) {
  348. return false;
  349. }
  350. if (component.get('cardinality') !== '1') {
  351. if (!this.get('isStart')) {
  352. if (this.get('componentCounter') > 1) {
  353. if (this.runningComponentCounter()) {
  354. return false;
  355. }
  356. } else {
  357. return false;
  358. }
  359. }
  360. }
  361. return true;
  362. }
  363. });