wizardProgressPageController.js 27 KB

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