wizardProgressPageController.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  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. /**
  20. * Mixin for wizard controller for showing command progress on wizard pages
  21. * This should
  22. * @type {Ember.Mixin}
  23. */
  24. App.wizardProgressPageControllerMixin = Em.Mixin.create({
  25. controllerName: '',
  26. clusterDeployState: 'WIZARD_DEPLOY',
  27. status: 'IN_PROGRESS',
  28. tasks: [],
  29. commands: [],
  30. currentRequestIds: [], //todo: replace with using requestIds from tasks
  31. logs: [],
  32. currentTaskId: null,
  33. POLL_INTERVAL: 4000,
  34. isSubmitDisabled: true,
  35. isBackButtonDisabled: true,
  36. stages: [],
  37. /**
  38. * List of statuses that inform about the end of request progress.
  39. * @type {String[]}
  40. */
  41. completedStatuses: ['COMPLETED', 'FAILED', 'TIMEDOUT', 'ABORTED'],
  42. currentPageRequestId: null,
  43. isSingleRequestPage: false,
  44. isCommandLevelRetry: function () {
  45. return !this.get('isSingleRequestPage');
  46. }.property('isSingleRequestPage'),
  47. showRetry: false,
  48. /**
  49. * Show whether tasks data was loaded
  50. * @type {Boolean}
  51. */
  52. isLoading: false,
  53. k: Em.K,
  54. /**
  55. * tasksMessagesPrefix should be overloaded by any controller including the mixin
  56. */
  57. tasksMessagesPrefix: '',
  58. loadStep: function () {
  59. this.clearStep();
  60. var self = this;
  61. if (!self.isSingleRequestPage) {
  62. this.initStep();
  63. } else {
  64. var requestIds = this.get('content.tasksRequestIds');
  65. var currentRequestId = requestIds && requestIds[0][0];
  66. if (!currentRequestId) {
  67. this.set('isLoaded', false);
  68. this.submitRequest();
  69. } else {
  70. self.set('currentPageRequestId', currentRequestId);
  71. self.doPollingForPageRequest();
  72. }
  73. }
  74. },
  75. initStep: function () {
  76. this.initializeTasks();
  77. if (!this.isSingleRequestPage) {
  78. this.loadTasks();
  79. }
  80. this.addObserver('tasks.@each.status', this, 'onTaskStatusChange');
  81. if (this.isSingleRequestPage) {
  82. var dfd = $.Deferred();
  83. var dfdObject = {
  84. deferred: dfd,
  85. isJqueryPromise: true
  86. };
  87. this.onTaskStatusChange(dfdObject);
  88. return dfd.promise();
  89. } else {
  90. this.onTaskStatusChange();
  91. }
  92. },
  93. clearStep: function () {
  94. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  95. this.set('isSubmitDisabled', true);
  96. this.set('isBackButtonDisabled', true);
  97. this.set('tasks', []);
  98. this.set('currentRequestIds', []);
  99. this.set('isLoaded', false);
  100. },
  101. /**
  102. * Clear stages info for single page request.
  103. */
  104. clearStage: function() {
  105. this.setDBProperty('tasksRequestIds', null);
  106. this.setDBProperty('tasksStatuses', null);
  107. this.set('showRetry', false);
  108. this.set('content.tasksRequestIds', null);
  109. this.set('content.tasksStatuses', null);
  110. this.set('content.currentTaskId', null);
  111. this.get('stages').clear();
  112. },
  113. retry: function () {
  114. this.set('showRetry', false);
  115. this.get('tasks').setEach('status','PENDING');
  116. this.loadStep();
  117. },
  118. submitRequest: function () {
  119. return App.ajax.send({
  120. name: this.get('request.ajaxName'),
  121. data: this.get('request.ajaxData'),
  122. sender: this,
  123. error: 'onSingleRequestError',
  124. success: 'submitRequestSuccess',
  125. kdcCancelHandler: 'failTaskOnKdcCheck'
  126. });
  127. },
  128. submitRequestSuccess: function(data, result, request) {
  129. if (data) {
  130. this.set('currentPageRequestId', data.Requests.id);
  131. this.doPollingForPageRequest();
  132. } else {
  133. //Step has been successfully completed
  134. if (request.status === 200) {
  135. this.set('status', 'COMPLETED');
  136. this.set('isSubmitDisabled', false);
  137. this.set('isLoaded', true);
  138. }
  139. }
  140. },
  141. failTaskOnKdcCheck: function() {
  142. this.set('status', 'FAILED');
  143. this.set('isLoaded', true);
  144. this.set('showRetry', true);
  145. },
  146. doPollingForPageRequest: function () {
  147. App.ajax.send({
  148. name: 'admin.poll.kerberize.cluster.request',
  149. sender: this,
  150. data: {
  151. requestId: this.get('currentPageRequestId')
  152. },
  153. success: 'initializeStages'
  154. });
  155. },
  156. initializeStages: function (data) {
  157. var self = this;
  158. var stages = [];
  159. this.set('logs', []);
  160. data.stages.forEach(function (_stage) {
  161. stages.pushObject(Em.Object.create(_stage.Stage));
  162. }, this);
  163. if (!this.get('stages').length) {
  164. this.get('stages').pushObjects(stages);
  165. this.initStep().done(function(){
  166. self.updatePageWithPolledData(data);
  167. });
  168. } else {
  169. this.updatePageWithPolledData(data);
  170. }
  171. },
  172. updatePageWithPolledData: function(data) {
  173. // If all tasks completed no need to update each task status.
  174. // Preferable to skip polling of data for completed tasks after page refresh.
  175. if (this.get('status') === 'COMPLETED') return;
  176. var self = this;
  177. var tasks = [];
  178. var currentPageRequestId = this.get('currentPageRequestId');
  179. var currentTaskId = this.get('currentTaskId');
  180. var currentTask = this.get('tasks').findProperty('id', currentTaskId);
  181. var currentStage = data.stages.findProperty('Stage.stage_id', currentTask.get('stageId'));
  182. var tasksInCurrentStage = currentStage.tasks;
  183. this.set('logs',tasksInCurrentStage);
  184. this.setRequestIds(this.get('currentTaskId'), [this.get('currentPageRequestId')]);
  185. if (!tasksInCurrentStage.someProperty('Tasks.status', 'PENDING') && !tasksInCurrentStage.someProperty('Tasks.status', 'QUEUED') && !tasksInCurrentStage.someProperty('Tasks.status', 'IN_PROGRESS')) {
  186. this.set('currentRequestIds', []);
  187. if (tasksInCurrentStage.someProperty('Tasks.status', 'FAILED') || tasksInCurrentStage.someProperty('Tasks.status', 'TIMEDOUT') || tasksInCurrentStage.someProperty('Tasks.status', 'ABORTED')) {
  188. this.setTaskStatus(currentTaskId, 'FAILED');
  189. } else {
  190. this.setTaskStatus(currentTaskId, 'COMPLETED');
  191. }
  192. } else {
  193. var completedActions = tasksInCurrentStage.filterProperty('Tasks.status', 'COMPLETED').length
  194. + tasksInCurrentStage.filterProperty('Tasks.status', 'FAILED').length
  195. + tasksInCurrentStage.filterProperty('Tasks.status', 'ABORTED').length
  196. + tasksInCurrentStage.filterProperty('Tasks.status', 'TIMEDOUT').length;
  197. var queuedActions = tasksInCurrentStage.filterProperty('Tasks.status', 'QUEUED').length;
  198. var inProgressActions = tasksInCurrentStage.filterProperty('Tasks.status', 'IN_PROGRESS').length;
  199. var progress = Math.floor(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / tasksInCurrentStage.length * 100);
  200. this.get('tasks').findProperty('id', currentTaskId).set('progress', progress);
  201. }
  202. // start polling if current request not completed
  203. if (!(this.get('completedStatuses').contains(this.get('status')))) {
  204. window.setTimeout(function () {
  205. self.doPollingForPageRequest();
  206. }, self.POLL_INTERVAL);
  207. }
  208. },
  209. initializeTasks: function () {
  210. var self = this;
  211. var commands = this.isSingleRequestPage ? this.get('stages') : this.get('commands');
  212. var currentStep = App.router.get(this.get('content.controllerName') + '.currentStep');
  213. var tasksMessagesPrefix = this.get('tasksMessagesPrefix');
  214. // check that all stages have been completed for single request type
  215. var allStagesCompleted = commands.everyProperty('status', 'COMPLETED');
  216. for (var i = 0; i < commands.length; i++) {
  217. this.get('tasks').pushObject(Ember.Object.create({
  218. title: self.isSingleRequestPage ? commands[i].get('context') : Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
  219. // set COMPLETED status for task if all stages completed successfully
  220. status: allStagesCompleted ? 'COMPLETED' : 'PENDING',
  221. id: i,
  222. stageId: self.isSingleRequestPage ? commands[i].get('stage_id') : null,
  223. command: self.isSingleRequestPage ? 'k' : commands[i],
  224. showRetry: false,
  225. showRollback: false,
  226. name: self.isSingleRequestPage ? commands[i].get('context') : Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
  227. displayName: self.isSingleRequestPage ? commands[i].get('context') : Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
  228. progress: 0,
  229. isRunning: false,
  230. requestIds: self.isSingleRequestPage ? [this.get('stages')[0].request_id] : []
  231. }));
  232. }
  233. this.set('isLoaded', true);
  234. },
  235. loadTasks: function () {
  236. var self = this;
  237. var loadedStatuses = this.get('content.tasksStatuses');
  238. var loadedRequestIds = this.get('content.tasksRequestIds');
  239. if (loadedStatuses && loadedStatuses.length === this.get('tasks').length) {
  240. this.get('tasks').forEach(function (task, i) {
  241. self.setTaskStatus(task.get('id'), loadedStatuses[i]);
  242. self.setRequestIds(task.get('id'), loadedRequestIds[i]);
  243. });
  244. if (loadedStatuses.contains('IN_PROGRESS')) {
  245. var curTaskId = this.get('tasks')[loadedStatuses.indexOf('IN_PROGRESS')].get('id');
  246. this.set('currentRequestIds', this.get('content.requestIds'));
  247. this.set('currentTaskId', curTaskId);
  248. this.doPolling();
  249. } else if (loadedStatuses.contains('QUEUED')) {
  250. var curTaskId = this.get('tasks')[loadedStatuses.indexOf('QUEUED')].get('id');
  251. this.set('currentTaskId', curTaskId);
  252. this.runTask(curTaskId);
  253. }
  254. }
  255. },
  256. setTaskStatus: function (taskId, status) {
  257. this.get('tasks').findProperty('id', taskId).set('status', status);
  258. },
  259. setTaskCanSkip: function (taskId, canSkip) {
  260. this.get('tasks').findProperty('id', taskId).set('canSkip', true);
  261. },
  262. setRequestIds: function (taskId, requestIds) {
  263. this.get('tasks').findProperty('id', taskId).set('requestIds', requestIds);
  264. },
  265. retryTask: function () {
  266. var task = this.get('tasks').findProperty('status', 'FAILED');
  267. task.set('showRetry', false);
  268. task.set('showRollback', false);
  269. task.set('status', 'PENDING');
  270. },
  271. onTaskStatusChange: function (dfdObject) {
  272. var statuses = this.get('tasks').mapProperty('status');
  273. var tasksRequestIds = this.get('tasks').mapProperty('requestIds');
  274. var requestIds = this.get('currentRequestIds');
  275. // save task info
  276. App.router.get(this.get('content.controllerName')).saveTasksStatuses(statuses);
  277. App.router.get(this.get('content.controllerName')).saveTasksRequestIds(tasksRequestIds);
  278. App.router.get(this.get('content.controllerName')).saveRequestIds(requestIds);
  279. // call saving of cluster status asynchronous
  280. // synchronous executing cause problems in Firefox
  281. var successCallbackData;
  282. if (dfdObject && dfdObject.isJqueryPromise) {
  283. successCallbackData = {deferred: dfdObject.deferred};
  284. }
  285. App.clusterStatus.setClusterStatus({
  286. clusterName: App.router.getClusterName(),
  287. clusterState: this.get('clusterDeployState'),
  288. wizardControllerName: this.get('content.controllerName'),
  289. localdb: App.db.data
  290. }, {successCallback: this.statusChangeCallback, sender: this, successCallbackData: successCallbackData});
  291. },
  292. /**
  293. * Method that called after saving persist data to server.
  294. * Switch task according its status.
  295. */
  296. statusChangeCallback: function (data) {
  297. if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
  298. var nextTask = this.get('tasks').findProperty('status', 'PENDING');
  299. if (nextTask) {
  300. this.set('status', 'IN_PROGRESS');
  301. var taskStatus = this.isSingleRequestPage ? 'IN_PROGRESS' : 'QUEUED';
  302. this.setTaskStatus(nextTask.get('id'), taskStatus);
  303. this.set('currentTaskId', nextTask.get('id'));
  304. this.runTask(nextTask.get('id'));
  305. } else {
  306. this.set('status', 'COMPLETED');
  307. this.set('isSubmitDisabled', false);
  308. this.set('isBackButtonDisabled', false);
  309. }
  310. } else if (this.get('tasks').someProperty('status', 'FAILED')) {
  311. this.set('status', 'FAILED');
  312. this.set('isBackButtonDisabled', false);
  313. if (this.get('isCommandLevelRetry')) {
  314. this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
  315. } else {
  316. this.set('showRetry', true);
  317. }
  318. if (this.get('tasks').someProperty('canSkip', true)) {
  319. this.get('tasks').findProperty('canSkip', true).set('showSkip', true);
  320. }
  321. if (App.supports.autoRollbackHA) {
  322. this.get('tasks').findProperty('status', 'FAILED').set('showRollback', true);
  323. }
  324. }
  325. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRetry', false);
  326. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRollback', false);
  327. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showSkip', false);
  328. this.get('tasks').filterProperty('status', 'IN_PROGRESS').setEach('showSkip', false);
  329. if (data && data.deferred) {
  330. data.deferred.resolve();
  331. }
  332. },
  333. /**
  334. * Run command of appropriate task
  335. */
  336. runTask: function (taskId) {
  337. this[this.get('tasks').findProperty('id', taskId).get('command')]();
  338. },
  339. onTaskError: function () {
  340. this.setTaskStatus(this.get('currentTaskId'), 'FAILED');
  341. },
  342. onTaskErrorWithSkip: function () {
  343. this.onTaskError();
  344. this.setTaskCanSkip(this.get('currentTaskId'), true);
  345. },
  346. onSingleRequestError: function (jqXHR, ajaxOptions, error, opt) {
  347. App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status);
  348. this.set('status', 'FAILED');
  349. this.set('isLoaded', true);
  350. this.set('showRetry', true);
  351. },
  352. onTaskCompleted: function () {
  353. this.setTaskStatus(this.get('currentTaskId'), 'COMPLETED');
  354. },
  355. /**
  356. * check whether component installed on specified hosts
  357. * @param {string} componentName
  358. * @param {string[]} hostNames
  359. * @return {$.ajax}
  360. */
  361. checkInstalledComponents: function (componentName, hostNames) {
  362. return App.ajax.send({
  363. name: 'host_component.installed.on_hosts',
  364. sender: this,
  365. data: {
  366. componentName: componentName,
  367. hostNames: hostNames.join(',')
  368. }
  369. });
  370. },
  371. /**
  372. * make server call to stop all services, except <code>excludedServices</code>
  373. * @param excludedServices
  374. * @returns {$.ajax}
  375. */
  376. stopServices: function (excludedServices) {
  377. var data = {
  378. 'ServiceInfo': {
  379. 'state': 'INSTALLED'
  380. }
  381. };
  382. if (excludedServices && excludedServices.length) {
  383. var servicesList = App.Service.find().mapProperty("serviceName").filter(function (s) {
  384. return !excludedServices.contains(s)
  385. }).join(',');
  386. data.context = "Stop required services";
  387. data.urlParams = "ServiceInfo/service_name.in(" + servicesList + ")";
  388. } else {
  389. data.context = "Stop all services";
  390. }
  391. return App.ajax.send({
  392. name: 'common.services.update',
  393. sender: this,
  394. data: data,
  395. success: 'startPolling',
  396. error: 'onTaskError'
  397. });
  398. },
  399. /**
  400. * make server call to start all services, except <code>excludedServices</code>
  401. * and run smoke tests if <code>runSmokeTest</code> is true
  402. * @param runSmokeTest
  403. * @param excludedServices
  404. * @returns {$.ajax}
  405. */
  406. startServices: function (runSmokeTest, excludedServices) {
  407. var skipServiceCheck = App.router.get('clusterController.ambariProperties')['skip.service.checks'] === "true";
  408. var data = {
  409. 'ServiceInfo': {
  410. 'state': 'STARTED'
  411. }
  412. };
  413. if (excludedServices && excludedServices.length) {
  414. var servicesList = App.Service.find().mapProperty("serviceName").filter(function (s) {
  415. return !excludedServices.contains(s)
  416. }).join(',');
  417. data.context = "Start required services";
  418. data.urlParams = "ServiceInfo/service_name.in(" + servicesList + ")";
  419. } else {
  420. data.context = "Start all services";
  421. }
  422. if (runSmokeTest) {
  423. data.urlParams = data.urlParams ? data.urlParams + '&' : '';
  424. data.urlParams += 'params/run_smoke_test=' + !skipServiceCheck;
  425. }
  426. return App.ajax.send({
  427. name: 'common.services.update',
  428. sender: this,
  429. data: data,
  430. success: 'startPolling',
  431. error: 'onTaskError'
  432. });
  433. },
  434. /**
  435. * Create component on single or multiple hosts.
  436. *
  437. * @method createComponent
  438. * @param {string} componentName - name of the component
  439. * @param {(string|string[])} hostName - host/hosts where components should be installed
  440. * @param {string} serviceName - name of the services
  441. */
  442. createComponent: function (componentName, hostName, serviceName) {
  443. var hostNames = (Array.isArray(hostName)) ? hostName : [hostName];
  444. var self = this;
  445. this.set('showRetry', false);
  446. this.checkInstalledComponents(componentName, hostNames).then(function (data) {
  447. var hostsWithComponents = data.items.mapProperty('HostRoles.host_name');
  448. var result = hostNames.map(function(item) {
  449. return {
  450. componentName: componentName,
  451. hostName: item,
  452. hasComponent: hostsWithComponents.contains(item)
  453. };
  454. });
  455. var hostsWithoutComponents = result.filterProperty('hasComponent', false).mapProperty('hostName');
  456. var taskNum = 1;
  457. var requestData = {
  458. "RequestInfo": {
  459. "query": hostsWithoutComponents.map(function(item) {
  460. return 'Hosts/host_name=' + item;
  461. }).join('|')
  462. },
  463. "Body": {
  464. "host_components": [
  465. {
  466. "HostRoles": {
  467. "component_name": componentName
  468. }
  469. }
  470. ]
  471. }
  472. };
  473. if (!!hostsWithoutComponents.length) {
  474. App.ajax.send({
  475. name: 'wizard.step8.register_host_to_component',
  476. sender: self,
  477. data: {
  478. data: JSON.stringify(requestData),
  479. hostName: result.mapProperty('hostName'),
  480. componentName: componentName,
  481. serviceName: serviceName,
  482. taskNum: taskNum,
  483. cluster: App.get('clusterName')
  484. },
  485. success: 'onCreateComponent',
  486. error: 'onCreateComponent'
  487. });
  488. } else {
  489. self.onCreateComponent(null, null, {
  490. hostName: result.mapProperty('hostName'),
  491. componentName: componentName,
  492. serviceName: serviceName,
  493. taskNum: taskNum
  494. }, self);
  495. }
  496. });
  497. },
  498. onCreateComponent: function () {
  499. var hostName = arguments[2].hostName;
  500. var componentName = arguments[2].componentName;
  501. var taskNum = arguments[2].taskNum;
  502. var serviceName = arguments[2].serviceName;
  503. this.updateComponent(componentName, hostName, serviceName, "Install", taskNum);
  504. },
  505. onCreateComponentError: function (error) {
  506. if (error.responseText.indexOf('org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException') !== -1) {
  507. this.onCreateComponent();
  508. } else {
  509. this.onTaskError();
  510. }
  511. },
  512. /**
  513. * Update component status on selected hosts.
  514. *
  515. * @param {string} componentName
  516. * @param {(string|string[])} hostName
  517. * @param {string} serviceName
  518. * @param {string} context
  519. * @param {number} taskNum
  520. * @returns {$.ajax}
  521. */
  522. updateComponent: function (componentName, hostName, serviceName, context, taskNum) {
  523. if (!(hostName instanceof Array)) {
  524. hostName = [hostName];
  525. }
  526. var state = context.toLowerCase() == "start" ? "STARTED" : "INSTALLED";
  527. return App.ajax.send({
  528. name: 'common.host_components.update',
  529. sender: this,
  530. data: {
  531. HostRoles: {
  532. state: state
  533. },
  534. query: 'HostRoles/component_name=' + componentName + '&HostRoles/host_name.in(' + hostName.join(',') + ')&HostRoles/maintenance_state=OFF',
  535. context: context + " " + App.format.role(componentName),
  536. hostName: hostName,
  537. taskNum: taskNum || 1,
  538. componentName: componentName,
  539. serviceName: serviceName
  540. },
  541. success: 'startPolling',
  542. error: 'onTaskError'
  543. });
  544. },
  545. startPolling: function (data) {
  546. if (data) {
  547. this.get('currentRequestIds').push(data.Requests.id);
  548. var tasksCount = arguments[2].taskNum || 1;
  549. if (tasksCount === this.get('currentRequestIds').length) {
  550. this.setRequestIds(this.get('currentTaskId'), this.get('currentRequestIds'));
  551. this.doPolling();
  552. }
  553. } else {
  554. this.onTaskCompleted();
  555. }
  556. },
  557. doPolling: function () {
  558. this.setTaskStatus(this.get('currentTaskId'), 'IN_PROGRESS');
  559. var requestIds = this.get('currentRequestIds');
  560. this.set('logs', []);
  561. for (var i = 0; i < requestIds.length; i++) {
  562. App.ajax.send({
  563. name: 'background_operations.get_by_request',
  564. sender: this,
  565. data: {
  566. requestId: requestIds[i]
  567. },
  568. success: 'parseLogs',
  569. error: 'onTaskError'
  570. });
  571. }
  572. },
  573. parseLogs: function (logs) {
  574. this.get('logs').pushObject(logs.tasks);
  575. if (this.get('currentRequestIds').length === this.get('logs').length) {
  576. var tasks = [];
  577. this.get('logs').forEach(function (logs) {
  578. tasks.pushObjects(logs);
  579. }, this);
  580. var self = this;
  581. var currentTaskId = this.get('currentTaskId');
  582. if (!tasks.someProperty('Tasks.status', 'PENDING') && !tasks.someProperty('Tasks.status', 'QUEUED') && !tasks.someProperty('Tasks.status', 'IN_PROGRESS')) {
  583. this.set('currentRequestIds', []);
  584. if (tasks.someProperty('Tasks.status', 'FAILED') || tasks.someProperty('Tasks.status', 'TIMEDOUT') || tasks.someProperty('Tasks.status', 'ABORTED')) {
  585. this.setTaskStatus(currentTaskId, 'FAILED');
  586. } else {
  587. this.setTaskStatus(currentTaskId, 'COMPLETED');
  588. }
  589. } else {
  590. var actionsPerHost = tasks.length;
  591. var completedActions = tasks.filterProperty('Tasks.status', 'COMPLETED').length
  592. + tasks.filterProperty('Tasks.status', 'FAILED').length
  593. + tasks.filterProperty('Tasks.status', 'ABORTED').length
  594. + tasks.filterProperty('Tasks.status', 'TIMEDOUT').length;
  595. var queuedActions = tasks.filterProperty('Tasks.status', 'QUEUED').length;
  596. var inProgressActions = tasks.filterProperty('Tasks.status', 'IN_PROGRESS').length;
  597. var progress = Math.floor(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 100);
  598. this.get('tasks').findProperty('id', currentTaskId).set('progress', progress);
  599. window.setTimeout(function () {
  600. self.doPolling();
  601. }, self.POLL_INTERVAL);
  602. }
  603. }
  604. },
  605. showHostProgressPopup: function (event) {
  606. var popupTitle = event.contexts[0].title;
  607. var requestIds = event.contexts[0].requestIds;
  608. var stageId = event.contexts[0].stageId;
  609. var hostProgressPopupController = App.router.get('highAvailabilityProgressPopupController');
  610. hostProgressPopupController.initPopup(popupTitle, requestIds, this, true, stageId);
  611. },
  612. done: function () {
  613. if (!this.get('isSubmitDisabled')) {
  614. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  615. App.router.send('next');
  616. }
  617. },
  618. back: function () {
  619. if (!this.get('isBackButtonDisabled')) {
  620. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  621. App.router.send('back');
  622. }
  623. }
  624. });