host_progress_popup.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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/date');
  21. var dataUtils = require('utils/data_manipulation');
  22. /**
  23. * Host information shown in the operations popup
  24. * @typedef {Em.Object} wrappedHost
  25. * @property {string} name
  26. * @property {string} publicName
  27. * @property {string} displayName
  28. * @property {number} progress
  29. * @property {boolean} isInProgress
  30. * @property {string} serviceName
  31. * @property {string} status
  32. * @property {number} isVisible
  33. * @property {string} icon
  34. * @property {string} barColor
  35. * @property {string} barWidth
  36. */
  37. /**
  38. * Task information shown in the operations popup
  39. * @typedef {Em.Object} wrappedTask
  40. * @property {string} id
  41. * @property {string} hostName
  42. * @property {string} command
  43. * @property {string} commandDetail
  44. * @property {string} status
  45. * @property {string} role
  46. * @property {string} stderr
  47. * @property {string} stdout
  48. * @property {number} request_id
  49. * @property {boolean} isVisible
  50. * @property {string} startTime
  51. * @property {string} duration
  52. * @property {string} icon
  53. */
  54. /**
  55. * Service information shown in the operations popup
  56. * @typedef {Em.Object} wrappedService
  57. * @property {string} id
  58. * @property {string} displayName
  59. * @property {string} progress
  60. * @property {string} status
  61. * @property {boolean} isRunning
  62. * @property {string} name
  63. * @property {boolean} isVisible
  64. * @property {string} startTime
  65. * @property {string} duration
  66. * @property {string} icon
  67. * @property {string} barColor
  68. * @property {boolean} isInProgress
  69. * @property {string} barWidth
  70. * @property {number} sourceRequestScheduleId
  71. * @property {string} contextCommand
  72. */
  73. /**
  74. * App.HostPopup is for the popup that shows up upon clicking already-performed or currently-in-progress operations
  75. * Allows to abort executing operations
  76. *
  77. * @type {Em.Object}
  78. * @class {HostPopup}
  79. */
  80. App.HostPopup = Em.Object.create({
  81. name: 'hostPopup',
  82. /**
  83. * @type {object[]}
  84. */
  85. servicesInfo: [],
  86. /**
  87. * @type {?wrappedHost[]}
  88. */
  89. hosts: null,
  90. /**
  91. * @type {?object[]}
  92. */
  93. inputData: null,
  94. /**
  95. * @type {string}
  96. */
  97. serviceName: '',
  98. /**
  99. * @type {?Number}
  100. */
  101. currentServiceId: null,
  102. /**
  103. * @type {?Number}
  104. */
  105. previousServiceId: null,
  106. /**
  107. * @type {string}
  108. */
  109. popupHeaderName: '',
  110. operationInfo: null,
  111. /**
  112. * @type {?App.Controller}
  113. */
  114. dataSourceController: null,
  115. /**
  116. * @type {bool}
  117. */
  118. isBackgroundOperations: false,
  119. /**
  120. * @type {?string}
  121. */
  122. currentHostName: null,
  123. /**
  124. * @type {?App.ModalPopup}
  125. */
  126. isPopup: null,
  127. /**
  128. * @type {object}
  129. */
  130. detailedProperties: {
  131. stdout: 'stdout',
  132. stderr: 'stderr',
  133. outputLog: 'output_log',
  134. errorLog: 'error_log'
  135. },
  136. /**
  137. * @type {object}
  138. */
  139. barColorMap: {
  140. 'FAILED': 'progress-danger',
  141. 'ABORTED': 'progress-warning',
  142. 'TIMEDOUT': 'progress-warning',
  143. 'IN_PROGRESS': 'progress-info',
  144. 'COMPLETED': 'progress-success'
  145. },
  146. /**
  147. * map to get css class with styles by service status
  148. *
  149. * @type {object}
  150. */
  151. statusesStyleMap: {
  152. 'FAILED': ['FAILED', 'icon-exclamation-sign', 'progress-danger', false],
  153. 'ABORTED': ['ABORTED', 'icon-minus', 'progress-warning', false],
  154. 'TIMEDOUT': ['TIMEDOUT', 'icon-time', 'progress-warning', false],
  155. 'IN_PROGRESS': ['IN_PROGRESS', 'icon-cogs', 'progress-info', true],
  156. 'COMPLETED': ['SUCCESS', 'icon-ok', 'progress-success', false]
  157. },
  158. /**
  159. * View with "Abort Request"-button
  160. *
  161. * @type {Em.View}
  162. */
  163. abortIcon: Em.View.extend({
  164. tagName: 'i',
  165. classNames: ['abort-icon', 'icon-remove-circle', 'pointer'],
  166. click: function () {
  167. this.get('controller').abortRequest(this.get('servicesInfo'));
  168. return false;
  169. },
  170. didInsertElement: function () {
  171. App.tooltip($(this.get('element')), {
  172. placement: "top",
  173. title: Em.I18n.t('hostPopup.bgop.abortRequest.title')
  174. });
  175. },
  176. willDestroyElement: function () {
  177. $(this.get('element')).tooltip('destroy');
  178. }
  179. }),
  180. /**
  181. * View with status icon (and tooltip on it)
  182. *
  183. * @type {Em.View}
  184. */
  185. statusIcon: Em.View.extend({
  186. tagName: 'i',
  187. classNames: ["service-status"],
  188. classNameBindings: ['servicesInfo.status', 'servicesInfo.icon', 'additionalClass'],
  189. attributeBindings: ['data-original-title'],
  190. 'data-original-title': function () {
  191. return this.get('servicesInfo.status');
  192. }.property('servicesInfo.status'),
  193. didInsertElement: function () {
  194. App.tooltip($(this.get('element')));
  195. },
  196. willDestroyElement: function () {
  197. $(this.get('element')).tooltip('destroy');
  198. }
  199. }),
  200. /**
  201. * Determines if background operation can be aborted depending on its status
  202. *
  203. * @param status
  204. * @returns {boolean}
  205. */
  206. isAbortableByStatus: function (status) {
  207. var statuses = this.get('statusesStyleMap');
  208. return !Em.keys(statuses).contains(status) || status == 'IN_PROGRESS';
  209. },
  210. /**
  211. * Send request to abort operation
  212. *
  213. * @method abortRequest
  214. */
  215. abortRequest: function (serviceInfo) {
  216. var requestName = serviceInfo.get('name');
  217. var self = this;
  218. App.showConfirmationPopup(function () {
  219. serviceInfo.set('isAbortable', false);
  220. return App.ajax.send({
  221. name: 'background_operations.abort_request',
  222. sender: self,
  223. data: {
  224. requestId: serviceInfo.get('id'),
  225. requestName: requestName,
  226. serviceInfo: serviceInfo
  227. },
  228. success: 'abortRequestSuccessCallback',
  229. error: 'abortRequestErrorCallback'
  230. });
  231. }, Em.I18n.t('hostPopup.bgop.abortRequest.confirmation.body').format(requestName));
  232. return false;
  233. },
  234. /**
  235. * Method called on successful sending request to abort operation
  236. *
  237. * @return {App.ModalPopup}
  238. * @method abortRequestSuccessCallback
  239. */
  240. abortRequestSuccessCallback: function (response, request, data) {
  241. return App.ModalPopup.show({
  242. header: Em.I18n.t('hostPopup.bgop.abortRequest.modal.header'),
  243. body: Em.I18n.t('hostPopup.bgop.abortRequest.modal.body').format(data.requestName),
  244. secondary: null
  245. });
  246. },
  247. /**
  248. * Method called on unsuccessful sending request to abort operation
  249. *
  250. * @method abortRequestErrorCallback
  251. */
  252. abortRequestErrorCallback: function (xhr, textStatus, error, opt, data) {
  253. data.serviceInfo.set('isAbortable', this.isAbortableByStatus(data.serviceInfo.status));
  254. App.ajax.defaultErrorHandler(xhr, opt.url, 'PUT', xhr.status);
  255. },
  256. /**
  257. * Entering point of this component
  258. *
  259. * @param {String} serviceName
  260. * @param {Object} controller
  261. * @param {Boolean} isBackgroundOperations
  262. * @param {Integer} requestId
  263. * @method initPopup
  264. */
  265. initPopup: function (serviceName, controller, isBackgroundOperations, requestId) {
  266. if (!isBackgroundOperations) {
  267. this.clearHostPopup();
  268. this.set("popupHeaderName", serviceName);
  269. }
  270. this.setProperties({
  271. currentServiceId: requestId,
  272. serviceName: serviceName,
  273. dataSourceController: controller,
  274. isBackgroundOperations: isBackgroundOperations,
  275. inputData: this.get("dataSourceController.services")
  276. });
  277. if (isBackgroundOperations) {
  278. this.onServiceUpdate();
  279. } else {
  280. this.onHostUpdate();
  281. }
  282. return this.createPopup();
  283. },
  284. /**
  285. * clear info popup data
  286. *
  287. * @method clearHostPopup
  288. */
  289. clearHostPopup: function () {
  290. this.setProperties({
  291. servicesInfo: [],
  292. host: null,
  293. inputData: null,
  294. serviceName: '',
  295. currentServiceId: null,
  296. previousServiceId: null,
  297. popupHeaderName: '',
  298. dataSourceController: null,
  299. currentHostName: null
  300. });
  301. this.get('isPopup') ? this.get('isPopup').remove() : null;
  302. },
  303. /**
  304. * Depending on tasks status
  305. *
  306. * @param {object[]} tasks
  307. * @return {*[]} [Status, Icon type, Progressbar color, is IN_PROGRESS]
  308. * @method getStatus
  309. */
  310. getStatus: function (tasks) {
  311. var isCompleted = true;
  312. var tasksLength = tasks.length;
  313. for (var i = 0; i < tasksLength; i++) {
  314. var taskStatus = tasks[i].Tasks.status;
  315. if (taskStatus !== 'COMPLETED') {
  316. isCompleted = false;
  317. }
  318. if (taskStatus === 'FAILED') {
  319. return ['FAILED', 'icon-exclamation-sign', 'progress-danger', false];
  320. }
  321. if (taskStatus === 'ABORTED') {
  322. return ['ABORTED', 'icon-minus', 'progress-warning', false];
  323. }
  324. if (taskStatus === 'TIMEDOUT') {
  325. return ['TIMEDOUT', 'icon-time', 'progress-warning', false];
  326. }
  327. if (taskStatus === 'IN_PROGRESS') {
  328. return ['IN_PROGRESS', 'icon-cogs', 'progress-info', true]
  329. }
  330. }
  331. if (isCompleted) {
  332. return ['SUCCESS', 'icon-ok', 'progress-success', false];
  333. }
  334. return ['PENDING', 'icon-cog', 'progress-info', true];
  335. },
  336. /**
  337. * Progress of host or service depending on tasks status
  338. * If no tasks, progress is 0
  339. *
  340. * @param {?object[]} tasks
  341. * @return {Number} percent of completion
  342. * @method getProgress
  343. */
  344. getProgress: function (tasks) {
  345. if (!tasks || !tasks.length) {
  346. return 0;
  347. }
  348. var groupedByStatus = dataUtils.groupPropertyValues(tasks, 'Tasks.status');
  349. var completedActions = Em.getWithDefault(groupedByStatus, 'COMPLETED.length', 0) +
  350. Em.getWithDefault(groupedByStatus, 'FAILED.length', 0) +
  351. Em.getWithDefault(groupedByStatus, 'ABORTED.length', 0) +
  352. Em.getWithDefault(groupedByStatus, 'TIMEDOUT.length', 0);
  353. var queuedActions = Em.getWithDefault(groupedByStatus, 'QUEUED.length', 0);
  354. var inProgressActions = Em.getWithDefault(groupedByStatus, 'IN_PROGRESS.length', 0);
  355. return Math.ceil((queuedActions * 0.09 + inProgressActions * 0.35 + completedActions ) / tasks.length * 100);
  356. },
  357. /**
  358. * Count number of operations for select box options
  359. *
  360. * @param {?Object[]} obj
  361. * @param {progressPopupCategoryObject[]} categories
  362. * @method setSelectCount
  363. */
  364. setSelectCount: function (obj, categories) {
  365. if (!obj) {
  366. return;
  367. }
  368. var groupedByStatus = dataUtils.groupPropertyValues(obj, 'status');
  369. categories.findProperty("value", 'all').set("count", obj.length);
  370. categories.findProperty("value", 'pending').set("count", Em.getWithDefault(groupedByStatus, 'pending.length', 0) + Em.getWithDefault(groupedByStatus, 'queued.length', 0));
  371. categories.findProperty("value", 'in_progress').set("count", Em.getWithDefault(groupedByStatus, 'in_progress.length', 0));
  372. categories.findProperty("value", 'failed').set("count", Em.getWithDefault(groupedByStatus, 'failed.length', 0));
  373. categories.findProperty("value", 'completed').set("count", Em.getWithDefault(groupedByStatus, 'success.length', 0) + Em.getWithDefault(groupedByStatus, 'completed.length', 0));
  374. categories.findProperty("value", 'aborted').set("count", Em.getWithDefault(groupedByStatus, 'aborted.length', 0));
  375. categories.findProperty("value", 'timedout').set("count", Em.getWithDefault(groupedByStatus, 'timedout.length', 0));
  376. },
  377. /**
  378. * For Background operation popup calculate number of running Operations, and set popup header
  379. *
  380. * @param {bool} isServiceListHidden
  381. * @method setBackgroundOperationHeader
  382. */
  383. setBackgroundOperationHeader: function (isServiceListHidden) {
  384. if (this.get('isBackgroundOperations') && !isServiceListHidden) {
  385. var numRunning = App.router.get('backgroundOperationsController.allOperationsCount');
  386. this.set("popupHeaderName", numRunning + Em.I18n.t('hostPopup.header.postFix').format(numRunning == 1 ? "" : "s"));
  387. }
  388. },
  389. /**
  390. * Create services obj data structure for popup
  391. * Set data for services
  392. *
  393. * @param {bool} isServiceListHidden
  394. * @method onServiceUpdate
  395. */
  396. onServiceUpdate: function (isServiceListHidden) {
  397. if (this.get('isBackgroundOperations') && this.get("inputData")) {
  398. var servicesInfo = this.get("servicesInfo");
  399. var currentServices = [];
  400. this.get("inputData").forEach(function (service, index) {
  401. var updatedService;
  402. var id = service.id;
  403. currentServices.push(id);
  404. var existedService = servicesInfo.findProperty('id', id);
  405. updatedService = existedService;
  406. if (existedService) {
  407. updatedService = this.updateService(existedService, service);
  408. }
  409. else {
  410. updatedService = this.createService(service);
  411. servicesInfo.insertAt(index, updatedService);
  412. }
  413. updatedService.set('isAbortable', App.isAuthorized('SERVICE.START_STOP') && this.isAbortableByStatus(service.status));
  414. }, this);
  415. this.removeOldServices(servicesInfo, currentServices);
  416. this.setBackgroundOperationHeader(isServiceListHidden);
  417. }
  418. },
  419. /**
  420. * Create service object from transmitted data
  421. *
  422. * @param {object} service
  423. * @return {wrappedService}
  424. * @method createService
  425. */
  426. createService: function (service) {
  427. var statuses = this.get('statusesStyleMap');
  428. var pendingStatus = ['PENDING', 'icon-cog', 'progress-info', true];
  429. var status = statuses[service.status] || pendingStatus;
  430. return Em.Object.create({
  431. id: service.id,
  432. displayName: service.displayName,
  433. progress: service.progress,
  434. status: App.format.taskStatus(status[0]),
  435. isRunning: service.isRunning,
  436. name: service.name,
  437. isVisible: true,
  438. startTime: date.startTime(service.startTime),
  439. duration: date.durationSummary(service.startTime, service.endTime),
  440. icon: status[1],
  441. barColor: status[2],
  442. isInProgress: status[3],
  443. barWidth: "width:" + service.progress + "%;",
  444. sourceRequestScheduleId: service.sourceRequestScheduleId,
  445. contextCommand: service.contextCommand
  446. });
  447. },
  448. /**
  449. * Update properties of existed service with new data
  450. *
  451. * @param {wrappedService} service
  452. * @param {object} newData
  453. * @returns {wrappedService}
  454. * @method updateService
  455. */
  456. updateService: function (service, newData) {
  457. var statuses = this.get('statusesStyleMap');
  458. var pendingStatus = ['PENDING', 'icon-cog', 'progress-info', true];
  459. var status = statuses[newData.status] || pendingStatus;
  460. return service.setProperties({
  461. progress: newData.progress,
  462. status: App.format.taskStatus(status[0]),
  463. isRunning: newData.isRunning,
  464. startTime: date.startTime(newData.startTime),
  465. duration: date.durationSummary(newData.startTime, newData.endTime),
  466. icon: status[1],
  467. barColor: status[2],
  468. isInProgress: status[3],
  469. barWidth: "width:" + newData.progress + "%;",
  470. sourceRequestScheduleId: newData.get('sourceRequestScheduleId'),
  471. contextCommand: newData.get('contextCommand')
  472. });
  473. },
  474. /**
  475. * remove old requests
  476. * as API returns 10, or 20 , or 30 ...etc latest request, the requests that absent in response should be removed
  477. *
  478. * @param {wrappedService[]} services
  479. * @param {number[]} currentServicesIds
  480. * @method removeOldServices
  481. */
  482. removeOldServices: function (services, currentServicesIds) {
  483. services.forEach(function (service, index, services) {
  484. if (!currentServicesIds.contains(service.id)) {
  485. services.removeAt(index, 1);
  486. }
  487. });
  488. },
  489. /**
  490. * Wrap task as Ember-object
  491. *
  492. * @param {Object} _task
  493. * @return {wrappedTask}
  494. * @method createTask
  495. */
  496. createTask: function (_task) {
  497. return Em.Object.create({
  498. id: _task.Tasks.id,
  499. hostName: _task.Tasks.host_name,
  500. command: _task.Tasks.command.toLowerCase() == 'service_check' ? '' : _task.Tasks.command.toLowerCase(),
  501. commandDetail: App.format.commandDetail(_task.Tasks.command_detail, _task.Tasks.request_inputs),
  502. status: App.format.taskStatus(_task.Tasks.status),
  503. role: App.format.role(_task.Tasks.role),
  504. stderr: _task.Tasks.stderr,
  505. stdout: _task.Tasks.stdout,
  506. request_id: _task.Tasks.request_id,
  507. isVisible: true,
  508. startTime: date.startTime(_task.Tasks.start_time),
  509. duration: date.durationSummary(_task.Tasks.start_time, _task.Tasks.end_time),
  510. icon: function () {
  511. var statusIconMap = {
  512. 'pending': 'icon-cog',
  513. 'queued': 'icon-cog',
  514. 'in_progress': 'icon-cogs',
  515. 'completed': 'icon-ok',
  516. 'failed': 'icon-exclamation-sign',
  517. 'aborted': 'icon-minus',
  518. 'timedout': 'icon-time'
  519. };
  520. return statusIconMap[this.get('status')] || 'icon-cog';
  521. }.property('status')
  522. });
  523. },
  524. /**
  525. * Create hosts and tasks data structure for popup
  526. * Set data for hosts and tasks
  527. *
  528. * @method onHostUpdate
  529. */
  530. onHostUpdate: function () {
  531. var inputData = this.get('inputData');
  532. var self = this;
  533. if (this.get("inputData")) {
  534. var hostsMap = this._getHostsMap();
  535. var existedHosts = self.get('hosts');
  536. if (existedHosts && existedHosts.length && this.get('currentServiceId') === this.get('previousServiceId')) {
  537. this._processingExistingHostsWithSameService(hostsMap);
  538. }
  539. else {
  540. var hostsArr = this._hostMapProcessing(hostsMap);
  541. hostsArr = hostsArr.sortProperty('name');
  542. hostsArr.setEach("serviceName", this.get("serviceName"));
  543. self.set("hosts", hostsArr);
  544. self.set('previousServiceId', this.get('currentServiceId'));
  545. }
  546. }
  547. var operation = this.get('servicesInfo').findProperty('name', this.get('serviceName'));
  548. this.set('operationInfo', !operation || (operation && operation.get('progress') == 100) ? null : operation);
  549. },
  550. /**
  551. * Generate hosts map for further processing <code>inputData</code>
  552. *
  553. * @returns {object}
  554. * @private
  555. * @method _getHostsMap
  556. */
  557. _getHostsMap: function () {
  558. var hostsData;
  559. var hostsMap = {};
  560. var inputData = this.get('inputData');
  561. if (this.get('isBackgroundOperations') && this.get("currentServiceId")) {
  562. //hosts popup for Background Operations
  563. hostsData = inputData.findProperty("id", this.get("currentServiceId"));
  564. }
  565. else {
  566. if (this.get("serviceName")) {
  567. //hosts popup for Wizards
  568. hostsData = inputData.findProperty("name", this.get("serviceName"));
  569. }
  570. }
  571. if (hostsData) {
  572. if (hostsData.hostsMap) {
  573. //hosts data come from Background Operations as object map
  574. hostsMap = hostsData.hostsMap;
  575. }
  576. else {
  577. if (hostsData.hosts) {
  578. //hosts data come from Wizard as array
  579. hostsMap = hostsData.hosts.toMapByProperty('name');
  580. }
  581. }
  582. }
  583. return hostsMap;
  584. },
  585. /**
  586. *
  587. * @param {object} hostsMap
  588. * @returns {wrappedHost[]}
  589. * @private
  590. * @method _hostMapProcessing
  591. */
  592. _hostMapProcessing: function (hostsMap) {
  593. var self = this;
  594. var hostsArr = [];
  595. for (var hostName in hostsMap) {
  596. if (!hostsMap.hasOwnProperty(hostName)) {
  597. continue;
  598. }
  599. var _host = hostsMap[hostName];
  600. var tasks = _host.logTasks;
  601. var hostInfo = Em.Object.create({
  602. name: hostName,
  603. publicName: _host.publicName,
  604. displayName: function () {
  605. return this.get('name').length < 43 ? this.get('name') : (this.get('name').substr(0, 40) + '...');
  606. }.property('name'),
  607. progress: 0,
  608. status: App.format.taskStatus("PENDING"),
  609. serviceName: _host.serviceName,
  610. isVisible: true,
  611. icon: "icon-cog",
  612. barColor: "progress-info",
  613. barWidth: "width:0%;"
  614. });
  615. if (tasks.length) {
  616. tasks = tasks.sortProperty('Tasks.id');
  617. var hostStatus = self.getStatus(tasks);
  618. var hostProgress = self.getProgress(tasks);
  619. hostInfo.setProperties({
  620. status: App.format.taskStatus(hostStatus[0]),
  621. icon: hostStatus[1],
  622. barColor: hostStatus[2],
  623. isInProgress: hostStatus[3],
  624. progress: hostProgress,
  625. barWidth: "width:" + hostProgress + "%;"
  626. });
  627. }
  628. hostInfo.set('logTasks', tasks);
  629. hostsArr.push(hostInfo);
  630. }
  631. return hostsArr;
  632. },
  633. /**
  634. *
  635. * @param {object} hostsMap
  636. * @private
  637. * @method _processingExistingHostsWithSameService
  638. */
  639. _processingExistingHostsWithSameService: function (hostsMap) {
  640. var self = this;
  641. var barColorMap = this.get('barColorMap');
  642. var existedHosts = self.get('hosts');
  643. var detailedProperties = this.get('detailedProperties');
  644. var detailedPropertiesKeys = Em.keys(detailedProperties);
  645. existedHosts.forEach(function (host) {
  646. var newHostInfo = hostsMap[host.get('name')];
  647. //update only hosts with changed tasks or currently opened tasks of host
  648. var hostShouldBeUpdated = !this.get('isBackgroundOperations') || newHostInfo.isModified || this.get('currentHostName') === host.get('name');
  649. if (newHostInfo && hostShouldBeUpdated) {
  650. var hostStatus = self.getStatus(newHostInfo.logTasks);
  651. var hostProgress = self.getProgress(newHostInfo.logTasks);
  652. host.setProperties({
  653. status: App.format.taskStatus(hostStatus[0]),
  654. icon: hostStatus[1],
  655. barColor: hostStatus[2],
  656. isInProgress: hostStatus[3],
  657. progress: hostProgress,
  658. barWidth: "width:" + hostProgress + "%;",
  659. logTasks: newHostInfo.logTasks
  660. });
  661. var existTasks = host.get('tasks');
  662. if (existTasks) {
  663. newHostInfo.logTasks.forEach(function (_task) {
  664. var existTask = existTasks.findProperty('id', _task.Tasks.id);
  665. if (existTask) {
  666. var status = _task.Tasks.status;
  667. detailedPropertiesKeys.forEach(function (key) {
  668. var name = detailedProperties[key];
  669. var value = _task.Tasks[name];
  670. if (!Em.isNone(value)) {
  671. existTask.set(key, value);
  672. }
  673. }, this);
  674. existTask.setProperties({
  675. status: App.format.taskStatus(status),
  676. startTime: date.startTime(_task.Tasks.start_time),
  677. duration: date.durationSummary(_task.Tasks.start_time, _task.Tasks.end_time)
  678. });
  679. existTask = self._handleRebalanceHDFS(_task, existTask);
  680. }
  681. else {
  682. existTasks.pushObject(this.createTask(_task));
  683. }
  684. }, this);
  685. }
  686. }
  687. }, this);
  688. },
  689. /**
  690. * Custom processing for "Rebalance HDFS"-task
  691. *
  692. * @param {object} task
  693. * @param {object} existTask
  694. * @returns {object}
  695. * @private
  696. * @method _handleRebalanceHDFS
  697. */
  698. _handleRebalanceHDFS: function (task, existTask) {
  699. var barColorMap = this.get('barColorMap');
  700. var isRebalanceHDFSTask = task.Tasks.command === 'CUSTOM_COMMAND' && task.Tasks.custom_command_name === 'REBALANCEHDFS';
  701. existTask.set('isRebalanceHDFSTask', isRebalanceHDFSTask);
  702. if (isRebalanceHDFSTask) {
  703. var structuredOut = task.Tasks.structured_out || {};
  704. var status = task.Tasks.status;
  705. existTask.setProperties({
  706. dataMoved: structuredOut['dataMoved'] || '0',
  707. dataLeft: structuredOut['dataLeft'] || '0',
  708. dataBeingMoved: structuredOut['dataBeingMoved'] || '0',
  709. barColor: barColorMap[status],
  710. isInProgress: status == 'IN_PROGRESS',
  711. isNotComplete: ['QUEUED', 'IN_PROGRESS'].contains(status),
  712. completionProgressStyle: 'width:' + (structuredOut['completePercent'] || 0) * 100 + '%;',
  713. command: task.Tasks.command,
  714. custom_command_name: task.Tasks.custom_command_name
  715. });
  716. }
  717. return existTask;
  718. },
  719. /**
  720. * Show popup
  721. *
  722. * @return {App.ModalPopup} PopupObject For testing purposes
  723. */
  724. createPopup: function () {
  725. var self = this;
  726. var servicesInfo = this.get("servicesInfo");
  727. var isBackgroundOperations = this.get('isBackgroundOperations');
  728. this.set('isPopup', App.ModalPopup.show({
  729. /**
  730. * @type {boolean}
  731. */
  732. isLogWrapHidden: true,
  733. /**
  734. * @type {boolean}
  735. */
  736. isTaskListHidden: true,
  737. /**
  738. * @type {boolean}
  739. */
  740. isHostListHidden: true,
  741. /**
  742. * @type {boolean}
  743. */
  744. isServiceListHidden: false,
  745. /**
  746. * @type {boolean}
  747. */
  748. isHideBodyScroll: true,
  749. /**
  750. * no need to track is it loaded when popup contain only list of hosts
  751. * @type {bool}
  752. */
  753. isLoaded: !isBackgroundOperations,
  754. /**
  755. * is BG-popup opened
  756. * @type {bool}
  757. */
  758. isOpen: false,
  759. /**
  760. * @type {object}
  761. */
  762. detailedProperties: self.get('detailedProperties'),
  763. didInsertElement: function () {
  764. this._super();
  765. this.set('isOpen', true);
  766. },
  767. /**
  768. * @type {Em.View}
  769. */
  770. headerClass: Em.View.extend({
  771. controller: this,
  772. template: Em.Handlebars.compile('{{popupHeaderName}} ' +
  773. '{{#unless view.parentView.isHostListHidden}}{{#if controller.operationInfo.isAbortable}}' +
  774. '{{view controller.abortIcon servicesInfoBinding="controller.operationInfo"}}' +
  775. '{{/if}}{{/unless}}')
  776. }),
  777. /**
  778. * @type {String[]}
  779. */
  780. classNames: ['sixty-percent-width-modal', 'host-progress-popup'],
  781. /**
  782. * for the checkbox: do not show this dialog again
  783. *
  784. * @type {bool}
  785. */
  786. hasFooterCheckbox: true,
  787. /**
  788. * Auto-display BG-popup
  789. *
  790. * @type {bool}
  791. */
  792. isNotShowBgChecked: null,
  793. /**
  794. * Save user pref about auto-display BG-popup
  795. *
  796. * @method updateNotShowBgChecked
  797. */
  798. updateNotShowBgChecked: function () {
  799. var curVal = !this.get('isNotShowBgChecked');
  800. if (!App.get('testMode')) {
  801. App.router.get('userSettingsController').postUserPref('show_bg', curVal);
  802. }
  803. }.observes('isNotShowBgChecked'),
  804. autoHeight: false,
  805. /**
  806. * @method closeModelPopup
  807. */
  808. closeModelPopup: function () {
  809. this.set('isOpen', false);
  810. if (isBackgroundOperations) {
  811. $(this.get('element')).detach();
  812. App.router.get('backgroundOperationsController').set('levelInfo.name', 'REQUESTS_LIST');
  813. } else {
  814. this.hide();
  815. self.set('isPopup', null);
  816. }
  817. },
  818. onPrimary: function () {
  819. this.closeModelPopup();
  820. },
  821. onClose: function () {
  822. this.closeModelPopup();
  823. },
  824. secondary: null,
  825. bodyClass: App.HostProgressPopupBodyView.extend({
  826. controller: self
  827. })
  828. }));
  829. return this.get('isPopup');
  830. }
  831. });