host_progress_popup.js 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  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("hosts", null);
  786. this.get("controller").setBackgroundOperationHeader(false);
  787. this.switchLevel("REQUESTS_LIST");
  788. },
  789. /**
  790. * Onclick handler for Show more ..
  791. */
  792. requestMoreOperations: function () {
  793. var BGOController = App.router.get('backgroundOperationsController');
  794. var count = BGOController.get('operationsCount');
  795. BGOController.set('operationsCount', (count + 10));
  796. BGOController.requestMostRecent();
  797. },
  798. setShowMoreAvailable: function () {
  799. if (this.get('parentView.isOpen')) {
  800. this.set('isShowMore', App.router.get("backgroundOperationsController.isShowMoreAvailable"));
  801. }
  802. }.observes('parentView.isOpen', 'App.router.backgroundOperationsController.isShowMoreAvailable'),
  803. isShowMore: true,
  804. /**
  805. * Onclick handler for selected Service
  806. * @param {Object} event
  807. */
  808. gotoHosts: function (event) {
  809. this.get("controller").set("serviceName", event.context.get("name"));
  810. this.get("controller").set("currentServiceId", event.context.get("id"));
  811. this.get("controller").set("currentHostName", null);
  812. this.get("controller").onHostUpdate();
  813. this.switchLevel("HOSTS_LIST");
  814. var servicesInfo = this.get("controller.hosts");
  815. if (servicesInfo.length) {
  816. this.get("controller").set("popupHeaderName", event.context.get("name"));
  817. }
  818. //apply lazy loading on cluster with more than 100 nodes
  819. if (servicesInfo.length > 100) {
  820. this.set('hosts', servicesInfo.slice(0, 50));
  821. } else {
  822. this.set('hosts', servicesInfo);
  823. }
  824. this.set("isServiceListHidden", true);
  825. this.set("isHostListHidden", false);
  826. $(".modal").scrollTop(0);
  827. $(".modal-body").scrollTop(0);
  828. if (servicesInfo.length > 100) {
  829. Em.run.next(this, function(){
  830. this.set('hosts', this.get('hosts').concat(servicesInfo.slice(50, servicesInfo.length)));
  831. });
  832. }
  833. // Determine if source request schedule is present
  834. this.set('sourceRequestScheduleId', event.context.get("sourceRequestScheduleId"));
  835. this.set('sourceRequestScheduleCommand', event.context.get('contextCommand'));
  836. this.refreshRequestScheduleInfo();
  837. },
  838. isRequestSchedule : function() {
  839. var id = this.get('sourceRequestScheduleId');
  840. return id != null && !isNaN(id) && id > -1;
  841. }.property('sourceRequestScheduleId'),
  842. refreshRequestScheduleInfo : function() {
  843. var self = this;
  844. var id = this.get('sourceRequestScheduleId');
  845. batchUtils.getRequestSchedule(id, function(data) {
  846. if (data != null && data.RequestSchedule != null &&
  847. data.RequestSchedule.status != null) {
  848. switch (data.RequestSchedule.status) {
  849. case 'DISABLED':
  850. self.set('sourceRequestScheduleRunning', false);
  851. self.set('sourceRequestScheduleAborted', true);
  852. break;
  853. case 'COMPLETED':
  854. self.set('sourceRequestScheduleRunning', false);
  855. self.set('sourceRequestScheduleAborted', false);
  856. break;
  857. case 'SCHEDULED':
  858. self.set('sourceRequestScheduleRunning', true);
  859. self.set('sourceRequestScheduleAborted', false);
  860. break;
  861. }
  862. } else {
  863. self.set('sourceRequestScheduleRunning', false);
  864. self.set('sourceRequestScheduleAborted', false);
  865. }
  866. }, function(xhr, textStatus, error, opt) {
  867. console.log("Error getting request schedule information: ", textStatus, error, opt);
  868. self.set('sourceRequestScheduleRunning', false);
  869. self.set('sourceRequestScheduleAborted', false);
  870. });
  871. }.observes('sourceRequestScheduleId'),
  872. /**
  873. * Attempts to abort the current request schedule
  874. */
  875. doAbortRequestSchedule: function(event){
  876. var self = this;
  877. var id = event.context;
  878. console.log("Aborting request schedule: ", id);
  879. batchUtils.doAbortRequestSchedule(id, function(){
  880. self.refreshRequestScheduleInfo();
  881. });
  882. },
  883. requestScheduleAbortLabel : function() {
  884. var label = Em.I18n.t("common.abort");
  885. var command = this.get('sourceRequestScheduleCommand');
  886. if (command != null && "ROLLING-RESTART" == command) {
  887. label = Em.I18n.t("hostPopup.bgop.abort.rollingRestart");
  888. }
  889. return label;
  890. }.property('sourceRequestScheduleCommand'),
  891. /**
  892. * Onclick handler for selected Host
  893. * @param {Object} event
  894. */
  895. gotoTasks: function (event) {
  896. var tasksInfo = [];
  897. event.context.logTasks.forEach(function (_task) {
  898. tasksInfo.pushObject(this.get("controller").createTask(_task));
  899. }, this);
  900. if (tasksInfo.length) {
  901. this.get("controller").set("popupHeaderName", event.context.publicName);
  902. this.get("controller").set("currentHostName", event.context.publicName);
  903. }
  904. this.switchLevel("TASKS_LIST");
  905. this.set('currentHost.tasks', tasksInfo);
  906. this.set("isHostListHidden", true);
  907. this.set("isTaskListHidden", false);
  908. $(".modal").scrollTop(0);
  909. $(".modal-body").scrollTop(0);
  910. },
  911. stopRebalanceHDFS: function () {
  912. var hostPopup = this;
  913. return App.showConfirmationPopup(function () {
  914. App.ajax.send({
  915. name : 'cancel.background.operation',
  916. sender : hostPopup,
  917. data : {
  918. requestId : hostPopup.get('controller.currentServiceId')
  919. }
  920. });
  921. hostPopup.backToServiceList();
  922. });
  923. },
  924. /**
  925. * Onclick handler for selected Task
  926. */
  927. openTaskLogInDialog: function () {
  928. if ($(".task-detail-log-clipboard").length > 0) {
  929. this.destroyClipBoard();
  930. }
  931. var newWindow = window.open();
  932. var newDocument = newWindow.document;
  933. newDocument.write($(".task-detail-log-info").html());
  934. newDocument.close();
  935. },
  936. openedTaskId: 0,
  937. /**
  938. * Return task detail info of opened task
  939. */
  940. openedTask: function () {
  941. if (!(this.get('openedTaskId') && this.get('tasks'))) {
  942. return Ember.Object.create();
  943. }
  944. return this.get('tasks').findProperty('id', this.get('openedTaskId'));
  945. }.property('tasks', 'tasks.@each.stderr', 'tasks.@each.stdout', 'openedTaskId'),
  946. /**
  947. * Onclick event for show task detail info
  948. * @param {Object} event
  949. */
  950. toggleTaskLog: function (event) {
  951. var taskInfo = event.context;
  952. this.set("isLogWrapHidden", false);
  953. if ($(".task-detail-log-clipboard").length > 0) {
  954. this.destroyClipBoard();
  955. }
  956. this.set("isHostListHidden", true);
  957. this.set("isTaskListHidden", true);
  958. this.set('openedTaskId', taskInfo.id);
  959. this.switchLevel("TASK_DETAILS");
  960. $(".modal").scrollTop(0);
  961. $(".modal-body").scrollTop(0);
  962. },
  963. /**
  964. * Send request to abort operation
  965. */
  966. abortRequest: function (event) {
  967. var requestName = event.context.get('name');
  968. var self = this;
  969. App.showConfirmationPopup(function () {
  970. var requestId = event.context.get('id');
  971. self.get('controller.abortedRequests').push(requestId);
  972. App.ajax.send({
  973. name: 'background_operations.abort_request',
  974. sender: self,
  975. data: {
  976. requestId: event.context.get('id'),
  977. requestName: requestName
  978. },
  979. success: 'abortRequestSuccessCallback',
  980. error: 'abortRequestErrorCallback'
  981. });
  982. }, Em.I18n.t('hostPopup.bgop.abortRequest.confirmation.body').format(requestName));
  983. return false;
  984. },
  985. /**
  986. * Method called on successful sending request to abort operation
  987. */
  988. abortRequestSuccessCallback: function (response, request, data) {
  989. App.showAlertPopup(Em.I18n.t('hostPopup.bgop.abortRequest.modal.header'), Em.I18n.t('hostPopup.bgop.abortRequest.modal.body').format(data.requestName));
  990. },
  991. /**
  992. * Method called on unsuccessful sending request to abort operation
  993. */
  994. abortRequestErrorCallback: function (xhr, textStatus, error, opt, data) {
  995. var abortedRequests = this.get('controller.abortedRequests');
  996. this.set('controller.abortedRequests', abortedRequests.without(data.requestId));
  997. App.ajax.defaultErrorHandler(xhr, opt.url, 'PUT', xhr.status);
  998. },
  999. /**
  1000. * Onclick event for copy to clipboard button
  1001. */
  1002. textTrigger: function () {
  1003. $(".task-detail-log-clipboard").length > 0 ? this.destroyClipBoard() : this.createClipBoard();
  1004. },
  1005. /**
  1006. * Create Clip Board
  1007. */
  1008. createClipBoard: function () {
  1009. var logElement = $(".task-detail-log-maintext");
  1010. $(".task-detail-log-clipboard-wrap").html('<textarea class="task-detail-log-clipboard"></textarea>');
  1011. $(".task-detail-log-clipboard")
  1012. .html("stderr: \n" + $(".stderr").html() + "\n stdout:\n" + $(".stdout").html())
  1013. .css("display", "block")
  1014. .width(logElement.width())
  1015. .height(logElement.height())
  1016. .select();
  1017. logElement.css("display", "none")
  1018. },
  1019. /**
  1020. * Destroy Clip Board
  1021. */
  1022. destroyClipBoard: function () {
  1023. $(".task-detail-log-clipboard").remove();
  1024. $(".task-detail-log-maintext").css("display", "block");
  1025. }
  1026. })
  1027. }));
  1028. return self.get('isPopup');
  1029. }
  1030. });