host_progress_popup.js 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  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 batchUtils = require('utils/batch_scheduled_requests');
  20. var date = require('utils/date');
  21. /**
  22. * App.HostPopup is for the popup that shows up upon clicking already-performed or currently-in-progress operations
  23. */
  24. App.HostPopup = Em.Object.create({
  25. name: 'hostPopup',
  26. servicesInfo: null,
  27. hosts: null,
  28. inputData: null,
  29. /**
  30. * @type {string}
  31. */
  32. serviceName: "",
  33. /**
  34. * @type {Number}
  35. */
  36. currentServiceId: null,
  37. previousServiceId: null,
  38. /**
  39. * @type {string}
  40. */
  41. popupHeaderName: "",
  42. /**
  43. * @type {App.Controller}
  44. */
  45. dataSourceController: null,
  46. /**
  47. * @type {bool}
  48. */
  49. isBackgroundOperations: false,
  50. /**
  51. * @type {string}
  52. */
  53. currentHostName: null,
  54. /**
  55. * @type {App.ModalPopup}
  56. */
  57. isPopup: null,
  58. /**
  59. * List of aborted requests
  60. * @type {Array}
  61. */
  62. abortedRequests: [],
  63. /**
  64. * Entering point of this component
  65. * @param {String} serviceName
  66. * @param {Object} controller
  67. * @param {Boolean} isBackgroundOperations
  68. * @param {Integer} requestId
  69. */
  70. initPopup: function (serviceName, controller, isBackgroundOperations, requestId) {
  71. if (!isBackgroundOperations) {
  72. this.clearHostPopup();
  73. this.set("popupHeaderName", serviceName);
  74. }
  75. this.set('currentServiceId', requestId);
  76. this.set("serviceName", serviceName);
  77. this.set("dataSourceController", controller);
  78. this.set("isBackgroundOperations", isBackgroundOperations);
  79. this.set("inputData", this.get("dataSourceController.services"));
  80. if(isBackgroundOperations){
  81. this.onServiceUpdate();
  82. } else {
  83. this.onHostUpdate();
  84. }
  85. return this.createPopup();
  86. },
  87. /**
  88. * clear info popup data
  89. */
  90. clearHostPopup: function () {
  91. this.set('servicesInfo', null);
  92. this.set('hosts', null);
  93. this.set('inputData', null);
  94. this.set('serviceName', "");
  95. this.set('currentServiceId', null);
  96. this.set('previousServiceId', null);
  97. this.set('popupHeaderName', "");
  98. this.set('dataSourceController', null);
  99. this.set('currentHostName', null);
  100. this.get('isPopup') ? this.get('isPopup').remove() : null;
  101. },
  102. /**
  103. * Depending on tasks status
  104. * @param {Array} tasks
  105. * @return {Array} [Status, Icon type, Progressbar color, is IN_PROGRESS]
  106. */
  107. getStatus: function(tasks){
  108. var isCompleted = true;
  109. var status;
  110. var tasksLength = tasks.length;
  111. var isFailed = false;
  112. var isAborted = false;
  113. var isTimedout = false;
  114. var isInProgress = false;
  115. for (var i = 0; i < tasksLength; i++) {
  116. if (tasks[i].Tasks.status !== 'COMPLETED') {
  117. isCompleted = false;
  118. }
  119. if(tasks[i].Tasks.status === 'FAILED'){
  120. isFailed = true;
  121. }
  122. if (tasks[i].Tasks.status === 'ABORTED') {
  123. isAborted = true;
  124. }
  125. if (tasks[i].Tasks.status === 'TIMEDOUT') {
  126. isTimedout = true;
  127. }
  128. if (tasks[i].Tasks.status === 'IN_PROGRESS') {
  129. isInProgress = true;
  130. }
  131. }
  132. if (isFailed) {
  133. status = ['FAILED', 'icon-exclamation-sign', 'progress-danger', false];
  134. } else if (isAborted) {
  135. status = ['ABORTED', 'icon-minus', 'progress-warning', false];
  136. } else if (isTimedout) {
  137. status = ['TIMEDOUT', 'icon-time', 'progress-warning', false];
  138. } else if (isInProgress) {
  139. status = ['IN_PROGRESS', 'icon-cogs', 'progress-info', true];
  140. }
  141. if(status){
  142. return status;
  143. } else if(isCompleted){
  144. return ['SUCCESS', 'icon-ok', 'progress-success', false];
  145. } else {
  146. return ['PENDING', 'icon-cog', 'progress-info', true];
  147. }
  148. },
  149. /**
  150. * Progress of host or service depending on tasks status
  151. * @param {Array} tasks
  152. * @return {Number} percent of completion
  153. */
  154. getProgress: function (tasks) {
  155. if (!tasks || tasks.length === 0) return 0;
  156. var completedActions = 0;
  157. var queuedActions = 0;
  158. var inProgressActions = 0;
  159. tasks.forEach(function (task) {
  160. if (['COMPLETED', 'FAILED', 'ABORTED', 'TIMEDOUT'].contains(task.Tasks.status)) {
  161. completedActions++;
  162. } else if (task.Tasks.status === 'QUEUED') {
  163. queuedActions++;
  164. } else if (task.Tasks.status === 'IN_PROGRESS') {
  165. inProgressActions++;
  166. }
  167. });
  168. return Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / tasks.length * 100);
  169. },
  170. /**
  171. * Count number of operations for select box options
  172. * @param {Object[]} obj
  173. * @param {Object[]} categories
  174. */
  175. setSelectCount: function (obj, categories) {
  176. if (!obj) return;
  177. var countAll = obj.length;
  178. var countPending = 0;
  179. var countInProgress = 0;
  180. var countFailed = 0;
  181. var countCompleted = 0;
  182. var countAborted = 0;
  183. var countTimedout = 0;
  184. obj.forEach(function(item){
  185. switch (item.status){
  186. case 'pending':
  187. countPending++;
  188. break;
  189. case 'queued':
  190. countPending++;
  191. break;
  192. case 'in_progress':
  193. countInProgress++;
  194. break;
  195. case 'failed':
  196. countFailed++;
  197. break;
  198. case 'success':
  199. countCompleted++;
  200. break;
  201. case 'completed':
  202. countCompleted++;
  203. break;
  204. case 'aborted':
  205. countAborted++;
  206. break;
  207. case 'timedout':
  208. countTimedout++;
  209. break;
  210. }
  211. });
  212. categories.findProperty("value", 'all').set("count", countAll);
  213. categories.findProperty("value", 'pending').set("count", countPending);
  214. categories.findProperty("value", 'in_progress').set("count", countInProgress);
  215. categories.findProperty("value", 'failed').set("count", countFailed);
  216. categories.findProperty("value", 'completed').set("count", countCompleted);
  217. categories.findProperty("value", 'aborted').set("count", countAborted);
  218. categories.findProperty("value", 'timedout').set("count", countTimedout);
  219. },
  220. /**
  221. * For Background operation popup calculate number of running Operations, and set popup header
  222. * @param {bool} isServiceListHidden
  223. */
  224. setBackgroundOperationHeader: function (isServiceListHidden) {
  225. if (this.get('isBackgroundOperations') && !isServiceListHidden) {
  226. var numRunning = App.router.get('backgroundOperationsController.allOperationsCount');
  227. this.set("popupHeaderName", numRunning + Em.I18n.t('hostPopup.header.postFix'));
  228. }
  229. },
  230. /**
  231. * Create services obj data structure for popup
  232. * Set data for services
  233. * @param {bool} isServiceListHidden
  234. */
  235. onServiceUpdate: function (isServiceListHidden) {
  236. if (this.get('isBackgroundOperations') && this.get("inputData")) {
  237. var self = this;
  238. var allNewServices = [];
  239. var statuses = {
  240. 'FAILED': ['FAILED', 'icon-exclamation-sign', 'progress-danger', false],
  241. 'ABORTED': ['ABORTED', 'icon-minus', 'progress-warning', false],
  242. 'TIMEDOUT': ['TIMEDOUT', 'icon-time', 'progress-warning', false],
  243. 'IN_PROGRESS': ['IN_PROGRESS', 'icon-cogs', 'progress-info', true],
  244. 'COMPLETED': ['SUCCESS', 'icon-ok', 'progress-success', false]
  245. };
  246. var pendingStatus = ['PENDING', 'icon-cog', 'progress-info', true];
  247. this.set("servicesInfo", null);
  248. this.get("inputData").forEach(function (service) {
  249. var status = statuses[service.status] || pendingStatus;
  250. var id = service.id;
  251. var newService = Ember.Object.create({
  252. id: id,
  253. displayName: service.displayName,
  254. progress: service.progress,
  255. status: App.format.taskStatus(status[0]),
  256. isRunning: service.isRunning,
  257. name: service.name,
  258. isVisible: true,
  259. startTime: date.startTime(service.startTime),
  260. duration: date.durationSummary(service.startTime, service.endTime),
  261. icon: status[1],
  262. barColor: status[2],
  263. isInProgress: status[3],
  264. barWidth: "width:" + service.progress + "%;",
  265. sourceRequestScheduleId: service.get('sourceRequestScheduleId'),
  266. contextCommand: service.get('contextCommand')
  267. });
  268. if (App.get('supports.abortRequests')) {
  269. var abortable = !Em.keys(statuses).contains(service.status) || service.status == 'IN_PROGRESS';
  270. if (!abortable) {
  271. var abortedRequests = this.get('abortedRequests');
  272. this.set('abortedRequests', abortedRequests.without(id));
  273. }
  274. newService.setProperties({
  275. abortable: abortable,
  276. abortClassName: 'abort' + id
  277. });
  278. }
  279. allNewServices.push(newService);
  280. }, this);
  281. self.set('servicesInfo', allNewServices);
  282. this.setBackgroundOperationHeader(isServiceListHidden);
  283. }
  284. },
  285. /**
  286. * create task Ember object
  287. * @param {Object} _task
  288. * @return {Em.Object}
  289. */
  290. createTask: function (_task) {
  291. return Em.Object.create({
  292. id: _task.Tasks.id,
  293. hostName: _task.Tasks.host_name,
  294. command: ( _task.Tasks.command.toLowerCase() != 'service_check') ? _task.Tasks.command.toLowerCase() : '',
  295. commandDetail: App.format.commandDetail(_task.Tasks.command_detail, _task.Tasks.request_inputs),
  296. status: App.format.taskStatus(_task.Tasks.status),
  297. role: App.format.role(_task.Tasks.role),
  298. stderr: _task.Tasks.stderr,
  299. stdout: _task.Tasks.stdout,
  300. isVisible: true,
  301. startTime: date.startTime(_task.Tasks.start_time),
  302. duration: date.durationSummary(_task.Tasks.start_time, _task.Tasks.end_time),
  303. icon: function () {
  304. var statusIconMap = {
  305. 'pending': 'icon-cog',
  306. 'queued': 'icon-cog',
  307. 'in_progress': 'icon-cogs',
  308. 'completed': 'icon-ok',
  309. 'failed': 'icon-exclamation-sign',
  310. 'aborted': 'icon-minus',
  311. 'timedout': 'icon-time'
  312. };
  313. return statusIconMap[this.get('status')] || 'icon-cog';
  314. }.property('status')
  315. });
  316. },
  317. /**
  318. * Create hosts and tasks data structure for popup
  319. * Set data for hosts and tasks
  320. */
  321. onHostUpdate: function () {
  322. var self = this;
  323. var inputData = this.get("inputData");
  324. if (inputData) {
  325. var hostsArr = [];
  326. var hostsData;
  327. var hostsMap = {};
  328. if(this.get('isBackgroundOperations') && this.get("currentServiceId")){
  329. //hosts popup for Background Operations
  330. hostsData = inputData.findProperty("id", this.get("currentServiceId"));
  331. } else if (this.get("serviceName")) {
  332. //hosts popup for Wizards
  333. hostsData = inputData.findProperty("name", this.get("serviceName"));
  334. }
  335. if (hostsData) {
  336. if (hostsData.hostsMap) {
  337. //hosts data come from Background Operations as object map
  338. hostsMap = hostsData.hostsMap;
  339. } else if (hostsData.hosts) {
  340. //hosts data come from Wizard as array
  341. hostsData.hosts.forEach(function (_host) {
  342. hostsMap[_host.name] = _host;
  343. });
  344. }
  345. }
  346. var existedHosts = self.get('hosts');
  347. if (existedHosts && (existedHosts.length > 0) && this.get('currentServiceId') === this.get('previousServiceId')) {
  348. existedHosts.forEach(function (host) {
  349. var newHostInfo = hostsMap[host.get('name')];
  350. //update only hosts with changed tasks or currently opened tasks of host
  351. if (newHostInfo && (!this.get('isBackgroundOperations') || newHostInfo.isModified || this.get('currentHostName') === host.get('name'))) {
  352. var hostStatus = self.getStatus(newHostInfo.logTasks);
  353. var hostProgress = self.getProgress(newHostInfo.logTasks);
  354. host.set('status', App.format.taskStatus(hostStatus[0]));
  355. host.set('icon', hostStatus[1]);
  356. host.set('barColor', hostStatus[2]);
  357. host.set('isInProgress', hostStatus[3]);
  358. host.set('progress', hostProgress);
  359. host.set('barWidth', "width:" + hostProgress + "%;");
  360. host.set('logTasks', newHostInfo.logTasks);
  361. var existTasks = host.get('tasks');
  362. if (existTasks) {
  363. newHostInfo.logTasks.forEach(function (_task) {
  364. var existTask = existTasks.findProperty('id', _task.Tasks.id);
  365. if (existTask) {
  366. existTask.set('status', App.format.taskStatus(_task.Tasks.status));
  367. existTask.set('stdout', _task.Tasks.stdout);
  368. existTask.set('stderr', _task.Tasks.stderr);
  369. // Verified that this is needed.
  370. existTask.set('outputLog', _task.Tasks.output_log);
  371. existTask.set('errorLog', _task.Tasks.error_log);
  372. existTask.set('startTime', date.startTime(_task.Tasks.start_time));
  373. existTask.set('duration', date.durationSummary(_task.Tasks.start_time, _task.Tasks.end_time));
  374. // Puts some command information to render it
  375. var isRebalanceHDFSTask = (_task.Tasks.command === 'CUSTOM_COMMAND' && _task.Tasks.custom_command_name === 'REBALANCEHDFS');
  376. existTask.set('isRebalanceHDFSTask', isRebalanceHDFSTask);
  377. if(isRebalanceHDFSTask){
  378. var structuredOut = _task.Tasks.structured_out;
  379. if (!structuredOut || structuredOut === 'null') {
  380. structuredOut = {};
  381. }
  382. existTask.set('dataMoved', structuredOut['dataMoved'] || '0');
  383. existTask.set('dataLeft', structuredOut['dataLeft'] || '0');
  384. existTask.set('dataBeingMoved', structuredOut['dataBeingMoved'] || '0');
  385. existTask.set('completionProgressStyle', 'width:' + (structuredOut['completePercent'] || 0) * 100 + '%;');
  386. existTask.set('command', _task.Tasks.command);
  387. existTask.set('custom_command_name', _task.Tasks.custom_command_name);
  388. }
  389. } else {
  390. existTasks.pushObject(this.createTask(_task));
  391. }
  392. }, this);
  393. }
  394. }
  395. }, this);
  396. } else {
  397. for (var hostName in hostsMap) {
  398. var _host = hostsMap[hostName];
  399. var tasks = _host.logTasks;
  400. var hostInfo = Ember.Object.create({
  401. name: hostName,
  402. publicName: _host.publicName,
  403. displayName: function () {
  404. return this.get('name').length < 43 ? this.get('name') : (this.get('name').substr(0, 40) + '...');
  405. }.property('name'),
  406. progress: 0,
  407. status: App.format.taskStatus("PENDING"),
  408. serviceName: _host.serviceName,
  409. isVisible: true,
  410. icon: "icon-cog",
  411. barColor: "progress-info",
  412. barWidth: "width:0%;"
  413. });
  414. if (tasks.length) {
  415. tasks = tasks.sortProperty('Tasks.id');
  416. var hostStatus = self.getStatus(tasks);
  417. var hostProgress = self.getProgress(tasks);
  418. hostInfo.set('status', App.format.taskStatus(hostStatus[0]));
  419. hostInfo.set('icon', hostStatus[1]);
  420. hostInfo.set('barColor', hostStatus[2]);
  421. hostInfo.set('isInProgress', hostStatus[3]);
  422. hostInfo.set('progress', hostProgress);
  423. hostInfo.set('barWidth', "width:" + hostProgress + "%;");
  424. }
  425. hostInfo.set('logTasks', tasks);
  426. hostsArr.push(hostInfo);
  427. }
  428. hostsArr = hostsArr.sortProperty('name');
  429. hostsArr.setEach("serviceName", this.get("serviceName"));
  430. self.set("hosts", hostsArr);
  431. self.set('previousServiceId', this.get('currentServiceId'));
  432. }
  433. }
  434. },
  435. /**
  436. * Show popup
  437. * @return {App.ModalPopup} PopupObject For testing purposes
  438. */
  439. createPopup: function () {
  440. var self = this;
  441. var hostsInfo = this.get("hosts");
  442. var servicesInfo = this.get("servicesInfo");
  443. var isBackgroundOperations = this.get('isBackgroundOperations');
  444. var categoryObject = Em.Object.extend({
  445. value: '',
  446. count: 0,
  447. labelPath: '',
  448. label: function(){
  449. return Em.I18n.t(this.get('labelPath')).format(this.get('count'));
  450. }.property('count')
  451. });
  452. self.set('isPopup', App.ModalPopup.show({
  453. isHideBodyScroll: true,
  454. /**
  455. * no need to track is it loaded when popup contain only list of hosts
  456. * @type {bool}
  457. */
  458. isLoaded: !isBackgroundOperations,
  459. /**
  460. * is BG-popup opened
  461. * @type {bool}
  462. */
  463. isOpen: false,
  464. didInsertElement: function(){
  465. if (App.get('supports.abortRequests')) {
  466. $(document).on({
  467. mouseenter: function () {
  468. var statusIcon = $(this).find('.service-status');
  469. var abortIcon = $(this).find('.abort-icon.abortable');
  470. if (abortIcon.length > 0) {
  471. var id = parseInt(abortIcon.attr('class').split(' ')[0].match(/\d+/)[0]);
  472. var abortedRequests = self.get('abortedRequests');
  473. if (!(abortedRequests && abortedRequests.contains(id))) {
  474. App.tooltip($('.abort-icon'));
  475. statusIcon.addClass('hidden');
  476. abortIcon.removeClass('hidden');
  477. }
  478. }
  479. },
  480. mouseleave: function () {
  481. $(this).find('.abort-icon').addClass('hidden');
  482. $(this).find('.service-status').removeClass('hidden');
  483. }
  484. }, '#service-info .log-list-wrap');
  485. }
  486. this._super();
  487. this.set('isOpen', true);
  488. },
  489. /**
  490. * @type {Em.View}
  491. */
  492. headerClass: Em.View.extend({
  493. controller: this,
  494. template: Ember.Handlebars.compile('{{popupHeaderName}}')
  495. }),
  496. /**
  497. * @type {String[]}
  498. */
  499. classNames: ['sixty-percent-width-modal', 'host-progress-popup'],
  500. /**
  501. * for the checkbox: do not show this dialog again
  502. * @type {bool}
  503. */
  504. hasFooterCheckbox: true,
  505. /**
  506. * Auto-display BG-popup
  507. * @type {bool}
  508. */
  509. isNotShowBgChecked : null,
  510. /**
  511. * Save user pref about auto-display BG-popup
  512. */
  513. updateNotShowBgChecked: function () {
  514. var curVal = !this.get('isNotShowBgChecked');
  515. var key = App.router.get('applicationController').persistKey();
  516. if (!App.get('testMode')) {
  517. App.router.get('applicationController').postUserPref(key, curVal);
  518. }
  519. }.observes('isNotShowBgChecked'),
  520. autoHeight: false,
  521. closeModelPopup: function () {
  522. this.set('isOpen', false);
  523. if(isBackgroundOperations){
  524. $(this.get('element')).detach();
  525. App.router.get('backgroundOperationsController').set('levelInfo.name', 'REQUESTS_LIST');
  526. } else {
  527. this.hide();
  528. self.set('isPopup', null);
  529. }
  530. },
  531. onPrimary: function () {
  532. this.closeModelPopup();
  533. },
  534. onClose: function () {
  535. this.closeModelPopup();
  536. },
  537. secondary: null,
  538. bodyClass: App.TableView.extend({
  539. templateName: require('templates/common/host_progress_popup'),
  540. isLogWrapHidden: true,
  541. isTaskListHidden: true,
  542. isHostListHidden: true,
  543. isServiceListHidden: false,
  544. showTextArea: false,
  545. isServiceEmptyList: true,
  546. isTasksEmptyList: true,
  547. controller: this,
  548. sourceRequestScheduleId: -1,
  549. sourceRequestScheduleRunning: false,
  550. sourceRequestScheduleAborted: false,
  551. sourceRequestScheduleCommand: null,
  552. hosts: self.get('hosts'),
  553. services: self.get('servicesInfo'),
  554. filterMap: {
  555. pending: ["pending", "queued"],
  556. in_progress: ["in_progress", "upgrading"],
  557. failed: ["failed"],
  558. completed: ["completed", "success"],
  559. aborted: ["aborted"],
  560. timedout: ["timedout"]
  561. },
  562. pagination: true,
  563. isPaginate: false,
  564. /**
  565. * Select box, display names and values
  566. */
  567. categories: [
  568. categoryObject.create({value: 'all', labelPath: 'hostPopup.status.category.all'}),
  569. categoryObject.create({value: 'pending', labelPath: 'hostPopup.status.category.pending'}),
  570. categoryObject.create({value: 'in_progress', labelPath: 'hostPopup.status.category.inProgress'}),
  571. categoryObject.create({value: 'failed', labelPath: 'hostPopup.status.category.failed'}),
  572. categoryObject.create({value: 'completed', labelPath: 'hostPopup.status.category.success'}),
  573. categoryObject.create({value: 'aborted', labelPath: 'hostPopup.status.category.aborted'}),
  574. categoryObject.create({value: 'timedout', labelPath: 'hostPopup.status.category.timedout'})
  575. ],
  576. /**
  577. * Selected option is bound to this values
  578. */
  579. serviceCategory: null,
  580. hostCategory: null,
  581. taskCategory: null,
  582. /**
  583. * flag to indicate whether level data has already been loaded
  584. * applied only to HOSTS_LIST and TASK_DETAILS levels, whereas async query used to obtain data
  585. */
  586. isLevelLoaded: true,
  587. isHostEmptyList: function() {
  588. return !this.get('pageContent.length');
  589. }.property('pageContent.length'),
  590. currentHost: function () {
  591. return this.get('hosts') && this.get('hosts').findProperty('name', this.get('controller.currentHostName'));
  592. }.property('controller.currentHostName'),
  593. tasks: function () {
  594. var currentHost = this.get('currentHost');
  595. if (currentHost) {
  596. return currentHost.get('tasks');
  597. }
  598. return [];
  599. }.property('currentHost.tasks', 'currentHost.tasks.@each.status'),
  600. /**
  601. * Preset values on init
  602. */
  603. setOnStart: function () {
  604. this.set('serviceCategory', this.get('categories').findProperty('value','all'));
  605. if (this.get("controller.isBackgroundOperations")) {
  606. this.get('controller').setSelectCount(this.get("services"), this.get('categories'));
  607. this.updateHostInfo();
  608. } else {
  609. this.set("isHostListHidden", false);
  610. this.set("isServiceListHidden", true);
  611. }
  612. },
  613. /**
  614. * force popup to show list of operations
  615. */
  616. resetState: function(){
  617. if(this.get('parentView.isOpen')){
  618. this.set('isLogWrapHidden', true);
  619. this.set('isTaskListHidden', true);
  620. this.set('isHostListHidden', true);
  621. this.set('isServiceListHidden', false);
  622. this.get("controller").setBackgroundOperationHeader(false);
  623. this.setOnStart();
  624. }
  625. }.observes('parentView.isOpen'),
  626. /**
  627. * When popup is opened, and data after polling has changed, update this data in component
  628. */
  629. updateHostInfo: function () {
  630. if(!this.get('parentView.isOpen')) return;
  631. this.set('parentView.isLoaded', false);
  632. this.get("controller").set("inputData", this.get("controller.dataSourceController.services"));
  633. this.get("controller").onServiceUpdate(this.get('isServiceListHidden'));
  634. this.get("controller").onHostUpdate();
  635. this.set('parentView.isLoaded', true);
  636. this.set("hosts", this.get("controller.hosts"));
  637. this.set("services", this.get("controller.servicesInfo"));
  638. this.set('isLevelLoaded', true);
  639. }.observes("controller.dataSourceController.serviceTimestamp"),
  640. /**
  641. * Depending on service filter, set which services should be shown
  642. */
  643. visibleServices: function () {
  644. if (this.get("services")) {
  645. this.set("isServiceEmptyList", true);
  646. if (this.get('serviceCategory.value')) {
  647. var filter = this.get('serviceCategory.value');
  648. var services = this.get('services');
  649. this.set("isServiceEmptyList", this.setVisibility(filter, services));
  650. }
  651. }
  652. }.observes('serviceCategory', 'services', 'services.@each.status'),
  653. /**
  654. * Depending on hosts filter, set which hosts should be shown
  655. */
  656. filter: function() {
  657. var _this = this,
  658. filter = this.get('hostCategory.value'),
  659. hosts = this.get('hosts') || [];
  660. if (!filter || !hosts.length) return;
  661. if (filter === 'all') {
  662. this.set('filteredContent', hosts);
  663. } else {
  664. this.set('filteredContent', hosts.filter(function(item) {
  665. return _this.get('filterMap')[filter].contains(item.status);
  666. }));
  667. }
  668. }.observes('hosts.length', 'hostCategory.value'),
  669. /**
  670. * Reset startIndex property back to 1 when filter type has been changed.
  671. */
  672. resetIndex: function() {
  673. if (this.get('hostCategory.value')) this.set('startIndex', 1)
  674. }.observes('hostCategory.value'),
  675. /**
  676. * Depending on tasks filter, set which tasks should be shown
  677. */
  678. visibleTasks: function () {
  679. this.set("isTasksEmptyList", true);
  680. if (this.get('taskCategory.value') && this.get('tasks')) {
  681. var filter = this.get('taskCategory.value');
  682. var tasks = this.get('tasks');
  683. this.set("isTasksEmptyList", this.setVisibility(filter, tasks));
  684. }
  685. }.observes('taskCategory', 'tasks', 'tasks.@each.status'),
  686. /**
  687. * Depending on selected filter type, set object visibility value
  688. * @param filter
  689. * @param obj
  690. * @return {bool} isEmptyList
  691. */
  692. setVisibility: function (filter, obj) {
  693. var isEmptyList = true;
  694. if (filter == "all") {
  695. obj.setEach("isVisible", true);
  696. isEmptyList = !(obj.length > 0);
  697. } else {
  698. obj.forEach(function(item){
  699. item.set('isVisible', this.get('filterMap')[filter].contains(item.status));
  700. isEmptyList = (isEmptyList) ? !item.get('isVisible') : false;
  701. }, this)
  702. }
  703. return isEmptyList;
  704. },
  705. /**
  706. * Depending on currently viewed tab, call setSelectCount function
  707. */
  708. updateSelectView: function () {
  709. var isPaginate;
  710. if (!this.get('isHostListHidden')) {
  711. //since lazy loading used for hosts, we need to get hosts info directly from controller, that always contains entire array of data
  712. this.get('controller').setSelectCount(this.get("controller.hosts"), this.get('categories'));
  713. isPaginate = true;
  714. } else if (!this.get('isTaskListHidden')) {
  715. this.get('controller').setSelectCount(this.get("tasks"), this.get('categories'));
  716. } else if (!this.get('isServiceListHidden')) {
  717. this.get('controller').setSelectCount(this.get("services"), this.get('categories'));
  718. }
  719. this.set('isPaginate', !!isPaginate);
  720. }.observes('tasks.@each.status', 'hosts.@each.status', 'isTaskListHidden', 'isHostListHidden', 'services.length', 'services.@each.status'),
  721. /**
  722. * control data uploading, depending on which display level is showed
  723. * @param levelName
  724. */
  725. switchLevel: function (levelName) {
  726. var dataSourceController = this.get('controller.dataSourceController');
  727. var securityControllers = [
  728. 'mainAdminSecurityDisableController',
  729. 'mainAdminSecurityAddStep4Controller'
  730. ];
  731. if (this.get("controller.isBackgroundOperations")) {
  732. var levelInfo = dataSourceController.get('levelInfo');
  733. levelInfo.set('taskId', this.get('openedTaskId'));
  734. levelInfo.set('requestId', this.get('controller.currentServiceId'));
  735. levelInfo.set('name', levelName);
  736. if (levelName === 'HOSTS_LIST') {
  737. this.set('isLevelLoaded', dataSourceController.requestMostRecent());
  738. this.set('hostCategory', this.get('categories').findProperty('value','all'));
  739. } else if (levelName === 'TASK_DETAILS') {
  740. dataSourceController.requestMostRecent();
  741. this.set('isLevelLoaded', false);
  742. } else if (levelName === 'REQUESTS_LIST') {
  743. this.set('serviceCategory', this.get('categories').findProperty('value','all'));
  744. this.get('controller.hosts').clear();
  745. dataSourceController.requestMostRecent();
  746. } else {
  747. this.set('taskCategory', this.get('categories').findProperty('value','all'));
  748. }
  749. } else if (securityControllers.contains(dataSourceController.get('name'))) {
  750. if (levelName === 'TASK_DETAILS') {
  751. this.set('isLevelLoaded', false);
  752. dataSourceController.startUpdatingTask(this.get('controller.currentServiceId'), this.get('openedTaskId'));
  753. } else {
  754. dataSourceController.stopUpdatingTask(this.get('controller.currentServiceId'));
  755. }
  756. }
  757. },
  758. /**
  759. * Onclick handler for button <-Tasks
  760. */
  761. backToTaskList: function () {
  762. this.destroyClipBoard();
  763. this.set("openedTaskId", 0);
  764. this.set("isLogWrapHidden", true);
  765. this.set("isTaskListHidden", false);
  766. this.switchLevel("TASKS_LIST");
  767. },
  768. /**
  769. * Onclick handler for button <-Hosts
  770. */
  771. backToHostList: function () {
  772. this.set("isHostListHidden", false);
  773. this.set("isTaskListHidden", true);
  774. this.get("controller").set("popupHeaderName", this.get("controller.serviceName"));
  775. this.switchLevel("HOSTS_LIST");
  776. },
  777. /**
  778. * Onclick handler for button <-Services
  779. */
  780. backToServiceList: function () {
  781. this.get("controller").set("serviceName", "");
  782. this.set("isHostListHidden", true);
  783. this.set("isServiceListHidden", false);
  784. this.set("isTaskListHidden", true);
  785. this.set("isLogWrapHidden", true);
  786. this.set("hosts", null);
  787. this.get("controller").setBackgroundOperationHeader(false);
  788. this.switchLevel("REQUESTS_LIST");
  789. },
  790. /**
  791. * Onclick handler for Show more ..
  792. */
  793. requestMoreOperations: function () {
  794. var BGOController = App.router.get('backgroundOperationsController');
  795. var count = BGOController.get('operationsCount');
  796. BGOController.set('operationsCount', (count + 10));
  797. BGOController.requestMostRecent();
  798. },
  799. setShowMoreAvailable: function () {
  800. if (this.get('parentView.isOpen')) {
  801. this.set('isShowMore', App.router.get("backgroundOperationsController.isShowMoreAvailable"));
  802. }
  803. }.observes('parentView.isOpen', 'App.router.backgroundOperationsController.isShowMoreAvailable'),
  804. isShowMore: true,
  805. /**
  806. * Onclick handler for selected Service
  807. * @param {Object} event
  808. */
  809. gotoHosts: function (event) {
  810. this.get("controller").set("serviceName", event.context.get("name"));
  811. this.get("controller").set("currentServiceId", event.context.get("id"));
  812. this.get("controller").set("currentHostName", null);
  813. this.get("controller").onHostUpdate();
  814. this.switchLevel("HOSTS_LIST");
  815. var servicesInfo = this.get("controller.hosts");
  816. if (servicesInfo.length) {
  817. this.get("controller").set("popupHeaderName", event.context.get("name"));
  818. }
  819. //apply lazy loading on cluster with more than 100 nodes
  820. if (servicesInfo.length > 100) {
  821. this.set('hosts', servicesInfo.slice(0, 50));
  822. } else {
  823. this.set('hosts', servicesInfo);
  824. }
  825. this.set("isServiceListHidden", true);
  826. this.set("isHostListHidden", false);
  827. $(".modal").scrollTop(0);
  828. $(".modal-body").scrollTop(0);
  829. if (servicesInfo.length > 100) {
  830. Em.run.next(this, function(){
  831. this.set('hosts', this.get('hosts').concat(servicesInfo.slice(50, servicesInfo.length)));
  832. });
  833. }
  834. // Determine if source request schedule is present
  835. this.set('sourceRequestScheduleId', event.context.get("sourceRequestScheduleId"));
  836. this.set('sourceRequestScheduleCommand', event.context.get('contextCommand'));
  837. this.refreshRequestScheduleInfo();
  838. },
  839. isRequestSchedule : function() {
  840. var id = this.get('sourceRequestScheduleId');
  841. return id != null && !isNaN(id) && id > -1;
  842. }.property('sourceRequestScheduleId'),
  843. refreshRequestScheduleInfo : function() {
  844. var self = this;
  845. var id = this.get('sourceRequestScheduleId');
  846. batchUtils.getRequestSchedule(id, function(data) {
  847. if (data != null && data.RequestSchedule != null &&
  848. data.RequestSchedule.status != null) {
  849. switch (data.RequestSchedule.status) {
  850. case 'DISABLED':
  851. self.set('sourceRequestScheduleRunning', false);
  852. self.set('sourceRequestScheduleAborted', true);
  853. break;
  854. case 'COMPLETED':
  855. self.set('sourceRequestScheduleRunning', false);
  856. self.set('sourceRequestScheduleAborted', false);
  857. break;
  858. case 'SCHEDULED':
  859. self.set('sourceRequestScheduleRunning', true);
  860. self.set('sourceRequestScheduleAborted', false);
  861. break;
  862. }
  863. } else {
  864. self.set('sourceRequestScheduleRunning', false);
  865. self.set('sourceRequestScheduleAborted', false);
  866. }
  867. }, function(xhr, textStatus, error, opt) {
  868. console.log("Error getting request schedule information: ", textStatus, error, opt);
  869. self.set('sourceRequestScheduleRunning', false);
  870. self.set('sourceRequestScheduleAborted', false);
  871. });
  872. }.observes('sourceRequestScheduleId'),
  873. /**
  874. * Attempts to abort the current request schedule
  875. */
  876. doAbortRequestSchedule: function(event){
  877. var self = this;
  878. var id = event.context;
  879. console.log("Aborting request schedule: ", id);
  880. batchUtils.doAbortRequestSchedule(id, function(){
  881. self.refreshRequestScheduleInfo();
  882. });
  883. },
  884. requestScheduleAbortLabel : function() {
  885. var label = Em.I18n.t("common.abort");
  886. var command = this.get('sourceRequestScheduleCommand');
  887. if (command != null && "ROLLING-RESTART" == command) {
  888. label = Em.I18n.t("hostPopup.bgop.abort.rollingRestart");
  889. }
  890. return label;
  891. }.property('sourceRequestScheduleCommand'),
  892. /**
  893. * Onclick handler for selected Host
  894. * @param {Object} event
  895. */
  896. gotoTasks: function (event) {
  897. var tasksInfo = [];
  898. event.context.logTasks.forEach(function (_task) {
  899. tasksInfo.pushObject(this.get("controller").createTask(_task));
  900. }, this);
  901. if (tasksInfo.length) {
  902. this.get("controller").set("popupHeaderName", event.context.publicName);
  903. this.get("controller").set("currentHostName", event.context.publicName);
  904. }
  905. this.switchLevel("TASKS_LIST");
  906. this.set('currentHost.tasks', tasksInfo);
  907. this.set("isHostListHidden", true);
  908. this.set("isTaskListHidden", false);
  909. $(".modal").scrollTop(0);
  910. $(".modal-body").scrollTop(0);
  911. },
  912. stopRebalanceHDFS: function () {
  913. var hostPopup = this;
  914. return App.showConfirmationPopup(function () {
  915. App.ajax.send({
  916. name : 'cancel.background.operation',
  917. sender : hostPopup,
  918. data : {
  919. requestId : hostPopup.get('controller.currentServiceId')
  920. }
  921. });
  922. hostPopup.backToServiceList();
  923. });
  924. },
  925. /**
  926. * Onclick handler for selected Task
  927. */
  928. openTaskLogInDialog: function () {
  929. if ($(".task-detail-log-clipboard").length > 0) {
  930. this.destroyClipBoard();
  931. }
  932. var newWindow = window.open();
  933. var newDocument = newWindow.document;
  934. newDocument.write($(".task-detail-log-info").html());
  935. newDocument.close();
  936. },
  937. openedTaskId: 0,
  938. /**
  939. * Return task detail info of opened task
  940. */
  941. openedTask: function () {
  942. if (!(this.get('openedTaskId') && this.get('tasks'))) {
  943. return Ember.Object.create();
  944. }
  945. return this.get('tasks').findProperty('id', this.get('openedTaskId'));
  946. }.property('tasks', 'tasks.@each.stderr', 'tasks.@each.stdout', 'openedTaskId'),
  947. /**
  948. * Onclick event for show task detail info
  949. * @param {Object} event
  950. */
  951. toggleTaskLog: function (event) {
  952. var taskInfo = event.context;
  953. this.set("isLogWrapHidden", false);
  954. if ($(".task-detail-log-clipboard").length > 0) {
  955. this.destroyClipBoard();
  956. }
  957. this.set("isHostListHidden", true);
  958. this.set("isTaskListHidden", true);
  959. this.set('openedTaskId', taskInfo.id);
  960. this.switchLevel("TASK_DETAILS");
  961. $(".modal").scrollTop(0);
  962. $(".modal-body").scrollTop(0);
  963. },
  964. /**
  965. * Send request to abort operation
  966. */
  967. abortRequest: function (event) {
  968. var requestName = event.context.get('name');
  969. var self = this;
  970. App.showConfirmationPopup(function () {
  971. var requestId = event.context.get('id');
  972. self.get('controller.abortedRequests').push(requestId);
  973. App.ajax.send({
  974. name: 'background_operations.abort_request',
  975. sender: self,
  976. data: {
  977. requestId: event.context.get('id'),
  978. requestName: requestName
  979. },
  980. success: 'abortRequestSuccessCallback',
  981. error: 'abortRequestErrorCallback'
  982. });
  983. }, Em.I18n.t('hostPopup.bgop.abortRequest.confirmation.body').format(requestName));
  984. return false;
  985. },
  986. /**
  987. * Method called on successful sending request to abort operation
  988. */
  989. abortRequestSuccessCallback: function (response, request, data) {
  990. App.showAlertPopup(Em.I18n.t('hostPopup.bgop.abortRequest.modal.header'), Em.I18n.t('hostPopup.bgop.abortRequest.modal.body').format(data.requestName));
  991. },
  992. /**
  993. * Method called on unsuccessful sending request to abort operation
  994. */
  995. abortRequestErrorCallback: function (xhr, textStatus, error, opt, data) {
  996. var abortedRequests = this.get('controller.abortedRequests');
  997. this.set('controller.abortedRequests', abortedRequests.without(data.requestId));
  998. App.ajax.defaultErrorHandler(xhr, opt.url, 'PUT', xhr.status);
  999. },
  1000. /**
  1001. * Onclick event for copy to clipboard button
  1002. */
  1003. textTrigger: function () {
  1004. $(".task-detail-log-clipboard").length > 0 ? this.destroyClipBoard() : this.createClipBoard();
  1005. },
  1006. /**
  1007. * Create Clip Board
  1008. */
  1009. createClipBoard: function () {
  1010. var logElement = $(".task-detail-log-maintext");
  1011. $(".task-detail-log-clipboard-wrap").html('<textarea class="task-detail-log-clipboard"></textarea>');
  1012. $(".task-detail-log-clipboard")
  1013. .html("stderr: \n" + $(".stderr").html() + "\n stdout:\n" + $(".stdout").html())
  1014. .css("display", "block")
  1015. .width(logElement.width())
  1016. .height(logElement.height())
  1017. .select();
  1018. logElement.css("display", "none")
  1019. },
  1020. /**
  1021. * Destroy Clip Board
  1022. */
  1023. destroyClipBoard: function () {
  1024. $(".task-detail-log-clipboard").remove();
  1025. $(".task-detail-log-maintext").css("display", "block");
  1026. }
  1027. })
  1028. }));
  1029. return self.get('isPopup');
  1030. }
  1031. });