wizardProgressPageController.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  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(App.InstallComponent, {
  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: Em.computed.not('isSingleRequestPage'),
  45. showRetry: false,
  46. /**
  47. * Show whether tasks data was loaded
  48. * @type {Boolean}
  49. */
  50. isLoading: false,
  51. k: Em.K,
  52. /**
  53. * tasksMessagesPrefix should be overloaded by any controller including the mixin
  54. */
  55. tasksMessagesPrefix: '',
  56. loadStep: function () {
  57. this.clearStep();
  58. var self = this;
  59. if (!self.isSingleRequestPage) {
  60. this.initStep();
  61. } else {
  62. var requestIds = this.get('content.tasksRequestIds');
  63. var currentRequestId = requestIds && requestIds[0][0];
  64. if (!currentRequestId) {
  65. this.set('isLoaded', false);
  66. this.submitRequest();
  67. } else {
  68. self.set('currentPageRequestId', currentRequestId);
  69. self.doPollingForPageRequest();
  70. }
  71. }
  72. },
  73. initStep: function () {
  74. this.initializeTasks();
  75. if (!this.isSingleRequestPage) {
  76. this.loadTasks();
  77. }
  78. this.addObserver('tasks.@each.status', this, 'onTaskStatusChange');
  79. if (this.isSingleRequestPage) {
  80. var dfd = $.Deferred();
  81. var dfdObject = {
  82. deferred: dfd,
  83. isJqueryPromise: true
  84. };
  85. this.onTaskStatusChange(dfdObject);
  86. return dfd.promise();
  87. } else {
  88. this.onTaskStatusChange();
  89. }
  90. },
  91. clearStep: function () {
  92. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  93. this.set('isSubmitDisabled', true);
  94. this.set('isBackButtonDisabled', true);
  95. this.set('tasks', []);
  96. this.set('currentRequestIds', []);
  97. this.set('isLoaded', false);
  98. },
  99. /**
  100. * Clear stages info for single page request.
  101. */
  102. clearStage: function() {
  103. this.setDBProperties({
  104. tasksRequestIds: null,
  105. tasksStatuses: null
  106. });
  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. var self = this;
  120. return App.ajax.send({
  121. name: this.get('request.ajaxName'),
  122. data: this.get('request.ajaxData'),
  123. sender: this,
  124. error: 'onSingleRequestError',
  125. success: 'submitRequestSuccess',
  126. kdcCancelHandler: function() {
  127. self.set('status', 'FAILED');
  128. self.set('isLoaded', true);
  129. self.set('showRetry', true);
  130. }
  131. });
  132. },
  133. submitRequestSuccess: function(data, result, request) {
  134. if (data) {
  135. this.set('currentPageRequestId', data.Requests.id);
  136. this.doPollingForPageRequest();
  137. } else {
  138. //Step has been successfully completed
  139. if (request.status === 200) {
  140. this.set('status', 'COMPLETED');
  141. this.set('isSubmitDisabled', false);
  142. this.set('isLoaded', true);
  143. }
  144. }
  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. this.set('isSubmitDisabled', true);
  270. this.set('isBackButtonDisabled', true);
  271. task.set('status', 'PENDING');
  272. },
  273. onTaskStatusChange: function (dfdObject) {
  274. var statuses = this.get('tasks').mapProperty('status');
  275. var tasksRequestIds = this.get('tasks').mapProperty('requestIds');
  276. var requestIds = this.get('currentRequestIds');
  277. // save task info
  278. App.router.get(this.get('content.controllerName')).saveTasksStatuses(statuses);
  279. App.router.get(this.get('content.controllerName')).saveTasksRequestIds(tasksRequestIds);
  280. App.router.get(this.get('content.controllerName')).saveRequestIds(requestIds);
  281. // call saving of cluster status asynchronous
  282. // synchronous executing cause problems in Firefox
  283. var successCallbackData;
  284. if (dfdObject && dfdObject.isJqueryPromise) {
  285. successCallbackData = {deferred: dfdObject.deferred};
  286. }
  287. App.clusterStatus.setClusterStatus({
  288. clusterName: App.router.getClusterName(),
  289. clusterState: this.get('clusterDeployState'),
  290. wizardControllerName: this.get('content.controllerName'),
  291. localdb: App.db.data
  292. }, {successCallback: this.statusChangeCallback, sender: this, successCallbackData: successCallbackData});
  293. },
  294. /**
  295. * Method that called after saving persist data to server.
  296. * Switch task according its status.
  297. */
  298. statusChangeCallback: function (data) {
  299. if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
  300. var nextTask = this.get('tasks').findProperty('status', 'PENDING');
  301. if (nextTask) {
  302. this.set('status', 'IN_PROGRESS');
  303. var taskStatus = this.isSingleRequestPage ? 'IN_PROGRESS' : 'QUEUED';
  304. this.setTaskStatus(nextTask.get('id'), taskStatus);
  305. this.set('currentTaskId', nextTask.get('id'));
  306. this.runTask(nextTask.get('id'));
  307. } else {
  308. this.set('status', 'COMPLETED');
  309. this.set('isSubmitDisabled', false);
  310. this.set('isBackButtonDisabled', false);
  311. }
  312. } else if (this.get('tasks').someProperty('status', 'FAILED')) {
  313. this.set('status', 'FAILED');
  314. this.set('isBackButtonDisabled', false);
  315. if (this.get('isCommandLevelRetry')) {
  316. this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
  317. } else {
  318. this.set('showRetry', true);
  319. }
  320. if (this.get('tasks').someProperty('canSkip', true)) {
  321. this.get('tasks').findProperty('canSkip', true).set('showSkip', true);
  322. }
  323. if (App.supports.autoRollbackHA) {
  324. this.get('tasks').findProperty('status', 'FAILED').set('showRollback', true);
  325. }
  326. }
  327. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRetry', false);
  328. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRollback', false);
  329. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showSkip', false);
  330. this.get('tasks').filterProperty('status', 'IN_PROGRESS').setEach('showSkip', false);
  331. if (data && data.deferred) {
  332. data.deferred.resolve();
  333. }
  334. },
  335. /**
  336. * Run command of appropriate task
  337. */
  338. runTask: function (taskId) {
  339. this[this.get('tasks').findProperty('id', taskId).get('command')]();
  340. },
  341. onTaskError: function () {
  342. this.setTaskStatus(this.get('currentTaskId'), 'FAILED');
  343. },
  344. onTaskErrorWithSkip: function () {
  345. this.onTaskError();
  346. this.setTaskCanSkip(this.get('currentTaskId'), true);
  347. },
  348. onSingleRequestError: function (jqXHR, ajaxOptions, error, opt) {
  349. App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status);
  350. this.set('status', 'FAILED');
  351. this.set('isLoaded', true);
  352. this.set('showRetry', true);
  353. },
  354. onTaskCompleted: function () {
  355. this.setTaskStatus(this.get('currentTaskId'), 'COMPLETED');
  356. },
  357. /**
  358. * check whether component installed on specified hosts
  359. * @param {string} componentName
  360. * @param {string[]} hostNames
  361. * @return {$.ajax}
  362. */
  363. checkInstalledComponents: function (componentName, hostNames) {
  364. return App.ajax.send({
  365. name: 'host_component.installed.on_hosts',
  366. sender: this,
  367. data: {
  368. componentName: componentName,
  369. hostNames: hostNames.join(',')
  370. }
  371. });
  372. },
  373. /**
  374. * make server call to stop services
  375. * if stopListedServicesFlag == false; stop all services excluding the services passed as parameters
  376. * if stopListedServicesFlag == true; stop only services passed as parameters
  377. * if no parameters are passed; stop all services
  378. * @param services, stopListedServicesFlag
  379. * @returns {$.ajax}
  380. */
  381. stopServices: function (services, stopListedServicesFlag) {
  382. var stopListedServicesFlag = stopListedServicesFlag || false;
  383. var data = {
  384. 'ServiceInfo': {
  385. 'state': 'INSTALLED'
  386. }
  387. };
  388. if (services && services.length) {
  389. var servicesList;
  390. if (stopListedServicesFlag) {
  391. servicesList = services.join(',');
  392. } else {
  393. servicesList = App.Service.find().mapProperty("serviceName").filter(function (s) {
  394. return !services.contains(s)
  395. }).join(',');
  396. }
  397. data.context = "Stop required services";
  398. data.urlParams = "ServiceInfo/service_name.in(" + servicesList + ")";
  399. } else {
  400. data.context = "Stop all services";
  401. }
  402. return App.ajax.send({
  403. name: 'common.services.update',
  404. sender: this,
  405. data: data,
  406. success: 'startPolling',
  407. error: 'onTaskError'
  408. });
  409. },
  410. /*tep4
  411. * make server call to start services
  412. * if startListedServicesFlag == false; start all services excluding the services passed as parameters
  413. * if startListedServicesFlag == true; start only services passed as parameters
  414. * if no parameters are passed; start all services
  415. * and run smoke tests if runSmokeTest is true
  416. * @param runSmokeTest
  417. * @param services
  418. * @param startListedServicesFlag
  419. * @returns {$.ajax}
  420. */
  421. startServices: function (runSmokeTest, services, startListedServicesFlag) {
  422. var startListedServicesFlag = startListedServicesFlag || false;
  423. var skipServiceCheck = App.router.get('clusterController.ambariProperties')['skip.service.checks'] === "true";
  424. var data = {
  425. 'ServiceInfo': {
  426. 'state': 'STARTED'
  427. }
  428. };
  429. var servicesList;
  430. if (services && services.length) {
  431. if (startListedServicesFlag) {
  432. servicesList = services.join(',');
  433. } else {
  434. servicesList = App.Service.find().mapProperty("serviceName").filter(function (s) {
  435. return !services.contains(s)
  436. }).join(',');
  437. }
  438. data.context = "Start required services";
  439. data.urlParams = "ServiceInfo/service_name.in(" + servicesList + ")";
  440. } else {
  441. data.context = "Start all services";
  442. }
  443. if (runSmokeTest) {
  444. data.urlParams = data.urlParams ? data.urlParams + '&' : '';
  445. data.urlParams += 'params/run_smoke_test=' + !skipServiceCheck;
  446. }
  447. return App.ajax.send({
  448. name: 'common.services.update',
  449. sender: this,
  450. data: data,
  451. success: 'startPolling',
  452. error: 'onTaskError'
  453. });
  454. },
  455. /**
  456. * Create component on single or multiple hosts.
  457. *
  458. * @method createComponent
  459. * @param {string} componentName - name of the component
  460. * @param {(string|string[])} hostName - host/hosts where components should be installed
  461. * @param {string} serviceName - name of the services
  462. */
  463. createComponent: function (componentName, hostName, serviceName) {
  464. var hostNames = (Array.isArray(hostName)) ? hostName : [hostName];
  465. var self = this;
  466. this.set('showRetry', false);
  467. this.checkInstalledComponents(componentName, hostNames).then(function (data) {
  468. var hostsWithComponents = data.items.mapProperty('HostRoles.host_name');
  469. var result = hostNames.map(function(item) {
  470. return {
  471. componentName: componentName,
  472. hostName: item,
  473. hasComponent: hostsWithComponents.contains(item)
  474. };
  475. });
  476. var hostsWithoutComponents = result.filterProperty('hasComponent', false).mapProperty('hostName');
  477. var taskNum = 1;
  478. var requestData = {
  479. "RequestInfo": {
  480. "query": hostsWithoutComponents.map(function(item) {
  481. return 'Hosts/host_name=' + item;
  482. }).join('|')
  483. },
  484. "Body": {
  485. "host_components": [
  486. {
  487. "HostRoles": {
  488. "component_name": componentName
  489. }
  490. }
  491. ]
  492. }
  493. };
  494. if (!!hostsWithoutComponents.length) {
  495. self.updateAndCreateServiceComponent(componentName).done(function () {
  496. App.ajax.send({
  497. name: 'wizard.step8.register_host_to_component',
  498. sender: self,
  499. data: {
  500. data: JSON.stringify(requestData),
  501. hostName: result.mapProperty('hostName'),
  502. componentName: componentName,
  503. serviceName: serviceName,
  504. taskNum: taskNum,
  505. cluster: App.get('clusterName')
  506. },
  507. success: 'onCreateComponent',
  508. error: 'onCreateComponent'
  509. });
  510. });
  511. } else {
  512. self.onCreateComponent(null, null, {
  513. hostName: result.mapProperty('hostName'),
  514. componentName: componentName,
  515. serviceName: serviceName,
  516. taskNum: taskNum
  517. }, self);
  518. }
  519. });
  520. },
  521. onCreateComponent: function () {
  522. var hostName = arguments[2].hostName;
  523. var componentName = arguments[2].componentName;
  524. var taskNum = arguments[2].taskNum;
  525. var serviceName = arguments[2].serviceName;
  526. this.updateComponent(componentName, hostName, serviceName, "Install", taskNum);
  527. },
  528. onCreateComponentError: function (error) {
  529. if (error.responseText.indexOf('org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException') !== -1) {
  530. this.onCreateComponent();
  531. } else {
  532. this.onTaskError();
  533. }
  534. },
  535. /**
  536. * Update component status on selected hosts.
  537. *
  538. * @param {string} componentName
  539. * @param {(string|string[])} hostName
  540. * @param {string} serviceName
  541. * @param {string} context
  542. * @param {number} taskNum
  543. * @returns {$.ajax}
  544. */
  545. updateComponent: function (componentName, hostName, serviceName, context, taskNum) {
  546. if (!(hostName instanceof Array)) {
  547. hostName = [hostName];
  548. }
  549. var state = context.toLowerCase() == "start" ? "STARTED" : "INSTALLED";
  550. return App.ajax.send({
  551. name: 'common.host_components.update',
  552. sender: this,
  553. data: {
  554. HostRoles: {
  555. state: state
  556. },
  557. query: 'HostRoles/component_name=' + componentName + '&HostRoles/host_name.in(' + hostName.join(',') + ')&HostRoles/maintenance_state=OFF',
  558. context: context + " " + App.format.role(componentName, false),
  559. hostName: hostName,
  560. taskNum: taskNum || 1,
  561. componentName: componentName,
  562. serviceName: serviceName
  563. },
  564. success: 'startPolling',
  565. error: 'onTaskError'
  566. });
  567. },
  568. /**
  569. * Update state for array of components of different services and on different hosts
  570. *
  571. * @param {Array} components - array of components object with fields serviceName, hostName and componentName
  572. * @param {String} state - new state to update
  573. */
  574. updateComponentsState: function (components, state) {
  575. components.forEach(function (component) {
  576. App.ajax.send({
  577. name: 'common.host.host_component.update',
  578. sender: this,
  579. data: {
  580. hostName: component.hostName,
  581. serviceName: component.serviceName,
  582. componentName: component.componentName,
  583. HostRoles: {
  584. state: state
  585. },
  586. taskNum: components.length
  587. },
  588. success: 'startPolling',
  589. error: 'onTaskError'
  590. });
  591. }, this)
  592. },
  593. startPolling: function (data) {
  594. if (data) {
  595. this.get('currentRequestIds').push(data.Requests.id);
  596. var tasksCount = arguments[2].taskNum || 1;
  597. if (tasksCount === this.get('currentRequestIds').length) {
  598. this.setRequestIds(this.get('currentTaskId'), this.get('currentRequestIds'));
  599. this.doPolling();
  600. }
  601. } else {
  602. this.onTaskCompleted();
  603. }
  604. },
  605. doPolling: function () {
  606. this.setTaskStatus(this.get('currentTaskId'), 'IN_PROGRESS');
  607. var requestIds = this.get('currentRequestIds');
  608. this.set('logs', []);
  609. for (var i = 0; i < requestIds.length; i++) {
  610. App.ajax.send({
  611. name: 'background_operations.get_by_request',
  612. sender: this,
  613. data: {
  614. requestId: requestIds[i]
  615. },
  616. success: 'parseLogs',
  617. error: 'onTaskError'
  618. });
  619. }
  620. },
  621. parseLogs: function (logs) {
  622. this.get('logs').pushObject(logs.tasks);
  623. if (this.get('currentRequestIds').length === this.get('logs').length) {
  624. var tasks = [];
  625. this.get('logs').forEach(function (logs) {
  626. tasks.pushObjects(logs);
  627. }, this);
  628. var self = this;
  629. var currentTaskId = this.get('currentTaskId');
  630. if (!tasks.someProperty('Tasks.status', 'PENDING') && !tasks.someProperty('Tasks.status', 'QUEUED') && !tasks.someProperty('Tasks.status', 'IN_PROGRESS')) {
  631. this.set('currentRequestIds', []);
  632. if (tasks.someProperty('Tasks.status', 'FAILED') || tasks.someProperty('Tasks.status', 'TIMEDOUT') || tasks.someProperty('Tasks.status', 'ABORTED')) {
  633. this.setTaskStatus(currentTaskId, 'FAILED');
  634. } else {
  635. this.setTaskStatus(currentTaskId, 'COMPLETED');
  636. }
  637. } else {
  638. var actionsPerHost = tasks.length;
  639. var completedActions = tasks.filterProperty('Tasks.status', 'COMPLETED').length
  640. + tasks.filterProperty('Tasks.status', 'FAILED').length
  641. + tasks.filterProperty('Tasks.status', 'ABORTED').length
  642. + tasks.filterProperty('Tasks.status', 'TIMEDOUT').length;
  643. var queuedActions = tasks.filterProperty('Tasks.status', 'QUEUED').length;
  644. var inProgressActions = tasks.filterProperty('Tasks.status', 'IN_PROGRESS').length;
  645. var progress = Math.floor(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 100);
  646. this.get('tasks').findProperty('id', currentTaskId).set('progress', progress);
  647. window.setTimeout(function () {
  648. self.doPolling();
  649. }, self.POLL_INTERVAL);
  650. }
  651. }
  652. },
  653. showHostProgressPopup: function (event) {
  654. if (!['IN_PROGRESS', 'FAILED', 'COMPLETED'].contains(Em.get(event.context, 'status')) || !event.contexts[0].requestIds.length) {
  655. return;
  656. }
  657. var popupTitle = event.contexts[0].title,
  658. requestIds = event.contexts[0].requestIds,
  659. stageId = event.contexts[0].stageId,
  660. hostProgressPopupController = App.router.get('highAvailabilityProgressPopupController');
  661. hostProgressPopupController.initPopup(popupTitle, requestIds, this, true, stageId);
  662. },
  663. done: function () {
  664. if (!this.get('isSubmitDisabled')) {
  665. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  666. App.router.send('next');
  667. }
  668. },
  669. back: function () {
  670. if (!this.get('isBackButtonDisabled')) {
  671. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  672. App.router.send('back');
  673. }
  674. },
  675. /**
  676. * Delete component on single hosts.
  677. *
  678. * @method deleteComponent
  679. * @param {string} componentName - name of the component
  680. * @param {string} hostName - host from where components should be deleted
  681. */
  682. deleteComponent: function (componentName, hostName) {
  683. App.ajax.send({
  684. name: 'common.delete.host_component',
  685. sender: this,
  686. data: {
  687. componentName: componentName,
  688. hostName: hostName
  689. },
  690. success: 'onTaskCompleted',
  691. error: 'onDeleteHostComponentsError'
  692. });
  693. },
  694. onDeleteHostComponentsError: function (error) {
  695. // If the component does not exist on the host, NoSuchResourceException is thrown.
  696. // If NoSuchResourceException is thrown, there is no action required and operation should continue.
  697. if (error.responseText.indexOf('org.apache.ambari.server.controller.spi.NoSuchResourceException') !== -1) {
  698. this.onTaskCompleted();
  699. } else {
  700. this.onTaskError();
  701. }
  702. },
  703. /**
  704. * Same as <code>createComponent</code> but with kdc session check and status changes
  705. * when KDC auth dialog dissmised.
  706. *
  707. * @see createComponent
  708. */
  709. createInstallComponentTask: function(componentName, hostName, serviceName, options) {
  710. var self = this;
  711. App.get('router.mainAdminKerberosController').getKDCSessionState(function() {
  712. self.createComponent(componentName, hostName, serviceName);
  713. }, function() {
  714. self.onTaskError();
  715. });
  716. }
  717. });