progress_controller.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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 installedComponents = [];
  20. App.HighAvailabilityProgressPageController = App.HighAvailabilityWizardController.extend({
  21. name: 'highAvailabilityProgressPageController',
  22. status: 'IN_PROGRESS',
  23. clusterDeployState: 'HIGH_AVAILABILITY_DEPLOY',
  24. tasks: [],
  25. commands: [],
  26. currentRequestIds: [], //todo: replace with using requestIds from tasks
  27. logs: [],
  28. currentTaskId: null,
  29. POLL_INTERVAL: 4000,
  30. isSubmitDisabled: true,
  31. isRollback: false,
  32. tasksMessagesPrefix: 'admin.highAvailability.wizard.step',
  33. loadStep: function () {
  34. console.warn('func: loadStep');
  35. this.clearStep();
  36. this.initializeTasks();
  37. this.loadTasks();
  38. this.addObserver('tasks.@each.status', this, 'onTaskStatusChange');
  39. this.onTaskStatusChange();
  40. },
  41. clearStep: function () {
  42. console.warn('func: clearStep');
  43. this.set('isSubmitDisabled', true);
  44. this.set('tasks', []);
  45. this.set('currentRequestIds', []);
  46. },
  47. initializeTasks: function () {
  48. console.warn('func: initializeTasks');
  49. var commands = this.get('commands');
  50. var currentStep = App.router.get(this.get('content.controllerName') + '.currentStep');
  51. var tasksMessagesPrefix = this.get('tasksMessagesPrefix');
  52. for (var i = 0; i < commands.length; i++) {
  53. this.get('tasks').pushObject(Ember.Object.create({
  54. title: Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
  55. status: 'PENDING',
  56. id: i,
  57. command: commands[i],
  58. showRetry: false,
  59. showRollback: false,
  60. name: Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
  61. displayName: Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
  62. progress: 0,
  63. isRunning: false,
  64. requestIds: []
  65. }));
  66. }
  67. },
  68. loadTasks: function () {
  69. console.warn('func: loadTasks');
  70. var self = this;
  71. var loadedStatuses = this.get('content.tasksStatuses');
  72. var loadedRequestIds = this.get('content.tasksRequestIds');
  73. if (loadedStatuses && loadedStatuses.length === this.get('tasks').length) {
  74. this.get('tasks').forEach(function (task, i) {
  75. self.setTaskStatus(task.get('id'), loadedStatuses[i]);
  76. self.setRequestIds(task.get('id'), loadedRequestIds[i]);
  77. });
  78. if (loadedStatuses.contains('IN_PROGRESS')) {
  79. var curTaskId = this.get('tasks')[loadedStatuses.indexOf('IN_PROGRESS')].get('id');
  80. this.set('currentRequestIds', this.get('content.requestIds'));
  81. this.set('currentTaskId', curTaskId);
  82. this.doPolling();
  83. } else if (loadedStatuses.contains('QUEUED')) {
  84. var curTaskId = this.get('tasks')[loadedStatuses.indexOf('QUEUED')].get('id');
  85. this.set('currentTaskId', curTaskId);
  86. this.runTask(curTaskId);
  87. }
  88. }
  89. },
  90. setTaskStatus: function (taskId, status) {
  91. console.warn('func: setTaskStatus');
  92. this.get('tasks').findProperty('id', taskId).set('status', status);
  93. },
  94. setRequestIds: function (taskId, requestIds) {
  95. this.get('tasks').findProperty('id', taskId).set('requestIds', requestIds);
  96. },
  97. retryTask: function () {
  98. console.warn('func: retryTask');
  99. var task = this.get('tasks').findProperty('status', 'FAILED');
  100. task.set('showRetry', false);
  101. task.set('showRollback', false);
  102. task.set('status', 'PENDING');
  103. },
  104. manualRollback: function () {
  105. console.warn('func: manualRollback');
  106. App.ModalPopup.show({
  107. header: Em.I18n.t('admin.highAvailability.confirmRollbackHeader'),
  108. primary: Em.I18n.t('yes'),
  109. showCloseButton: false,
  110. onPrimary: function () {
  111. var self = this;
  112. var controller = App.router.get('highAvailabilityWizardController');
  113. controller.clearTasksData();
  114. controller.clearStorageData();
  115. controller.finish();
  116. App.router.get('updateController').set('isWorking', true);
  117. App.clusterStatus.setClusterStatus({
  118. clusterName: App.router.get('content.cluster.name'),
  119. clusterState: 'DEFAULT',
  120. localdb: App.db.data
  121. },{alwaysCallback: function() {self.hide();App.router.transitionTo('main.index');location.reload();}});
  122. },
  123. secondary: Em.I18n.t('no'),
  124. onSecondary: function () {
  125. this.hide();
  126. },
  127. bodyClass: Ember.View.extend({
  128. template: Ember.Handlebars.compile(Em.I18n.t('admin.highAvailability.confirmManualRollbackBody'))
  129. })
  130. });
  131. },
  132. rollback: function () {
  133. console.warn('func: rollback');
  134. var task = this.get('tasks').findProperty('status', 'FAILED');
  135. App.router.get(this.get('content.controllerName')).saveFailedTask(task);
  136. App.ModalPopup.show({
  137. header: Em.I18n.t('admin.highAvailability.confirmRollbackHeader'),
  138. primary: Em.I18n.t('common.confirm'),
  139. showCloseButton: false,
  140. onPrimary: function () {
  141. App.router.get('highAvailabilityWizardController').clearTasksData();
  142. App.router.transitionTo('main.admin.highAvailabilityRollback');
  143. this.hide();
  144. },
  145. secondary: Em.I18n.t('common.cancel'),
  146. body: Em.I18n.t('admin.highAvailability.confirmRollbackBody')
  147. });
  148. },
  149. onTaskStatusChange: function () {
  150. console.warn('func: onTaskStatusChange1');
  151. var statuses = this.get('tasks').mapProperty('status');
  152. var tasksRequestIds = this.get('tasks').mapProperty('requestIds');
  153. var requestIds = this.get('currentRequestIds');
  154. console.warn('func: onTaskStatusChange5', statuses, tasksRequestIds, requestIds);
  155. // save task info
  156. App.router.get(this.get('content.controllerName')).saveTasksStatuses(statuses);
  157. App.router.get(this.get('content.controllerName')).saveTasksRequestIds(tasksRequestIds);
  158. App.router.get(this.get('content.controllerName')).saveRequestIds(requestIds);
  159. // call saving of cluster status asynchronous
  160. // synchronous executing cause problems in Firefox
  161. App.clusterStatus.setClusterStatus({
  162. clusterName: this.get('content.cluster.name'),
  163. clusterState: this.get('clusterDeployState'),
  164. wizardControllerName: this.get('content.controllerName'),
  165. localdb: App.db.data
  166. }, {successCallback: this.statusChangeCallback, sender: this});
  167. },
  168. /**
  169. * Method that called after saving persist data to server.
  170. * Switch task according its status.
  171. */
  172. statusChangeCallback: function () {
  173. if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) {
  174. var nextTask = this.get('tasks').findProperty('status', 'PENDING');
  175. if (nextTask) {
  176. console.warn('func: onTaskStatusChange2');
  177. this.set('status', 'IN_PROGRESS');
  178. this.setTaskStatus(nextTask.get('id'), 'QUEUED');
  179. this.set('currentTaskId', nextTask.get('id'));
  180. this.runTask(nextTask.get('id'));
  181. } else {
  182. console.warn('func: onTaskStatusChange3');
  183. this.set('status', 'COMPLETED');
  184. this.set('isSubmitDisabled', false);
  185. }
  186. } else if (this.get('tasks').someProperty('status', 'FAILED')) {
  187. console.warn('func: onTaskStatusChange4');
  188. this.set('status', 'FAILED');
  189. this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
  190. if (App.supports.autoRollbackHA) {
  191. this.get('tasks').findProperty('status', 'FAILED').set('showRollback', true);
  192. }
  193. }
  194. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRetry', false);
  195. this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRollback', false);
  196. },
  197. /**
  198. * Run command of appropriate task
  199. */
  200. runTask: function (taskId) {
  201. console.warn('func: runTask', taskId);
  202. this[this.get('tasks').findProperty('id', taskId).get('command')]();
  203. },
  204. onTaskError: function () {
  205. console.warn('func: onTaskError');
  206. this.setTaskStatus(this.get('currentTaskId'), 'FAILED');
  207. },
  208. onTaskCompleted: function () {
  209. console.warn('func: onTaskCompleted');
  210. this.setTaskStatus(this.get('currentTaskId'), 'COMPLETED');
  211. },
  212. /**
  213. * check whether component installed on specified hosts
  214. * @param componentName
  215. * @param hostNames
  216. * @return {$.ajax}
  217. */
  218. checkInstalledComponents: function (componentName, hostNames) {
  219. return App.ajax.send({
  220. name: 'host_component.installed.on_hosts',
  221. sender: this,
  222. data: {
  223. componentName: componentName,
  224. hostNames: hostNames.join(',')
  225. },
  226. success: 'checkInstalledComponentsSuccessCallback'
  227. });
  228. },
  229. checkInstalledComponentsSuccessCallback: function (data, opt, params) {
  230. installedComponents = data.items;
  231. },
  232. createComponent: function (componentName, hostName, serviceName) {
  233. var hostNames = (Array.isArray(hostName)) ? hostName : [hostName];
  234. var self = this;
  235. this.checkInstalledComponents(componentName, hostNames).complete(function () {
  236. var result = [];
  237. hostNames.forEach(function (hostName) {
  238. result.push({
  239. componentName: componentName,
  240. hostName: hostName,
  241. hasComponent: installedComponents.someProperty('HostRoles.host_name', hostName)
  242. });
  243. });
  244. result.forEach(function (host, index, array) {
  245. if (!host.hasComponent) {
  246. App.ajax.send({
  247. name: 'admin.high_availability.create_component',
  248. sender: this,
  249. data: {
  250. hostName: host.hostName,
  251. componentName: host.componentName,
  252. serviceName: serviceName,
  253. taskNum: array.length
  254. },
  255. success: 'onCreateComponent',
  256. error: 'onCreateComponentError'
  257. });
  258. } else {
  259. // Simulates format returned from ajax.send
  260. this.onCreateComponent(null, null, {hostName: host.hostName, componentName: host.componentName, taskNum: array.length});
  261. }
  262. }, self)
  263. });
  264. },
  265. onCreateComponent: function () {
  266. var hostName = arguments[2].hostName;
  267. var componentName = arguments[2].componentName;
  268. var taskNum = arguments[2].taskNum;
  269. var serviceName = arguments[2].serviceName;
  270. this.updateComponent(componentName, hostName, serviceName, "Install", taskNum);
  271. },
  272. onCreateComponentError: function (error) {
  273. if (error.responseText.indexOf('org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException') !== -1) {
  274. this.onCreateComponent();
  275. } else {
  276. this.onTaskError();
  277. }
  278. },
  279. updateComponent: function (componentName, hostName, serviceName, context, taskNum) {
  280. if (!(hostName instanceof Array)) {
  281. hostName = [hostName];
  282. }
  283. var state = context.toLowerCase() == "start" ? "STARTED" : "INSTALLED";
  284. for (var i = 0; i < hostName.length; i++) {
  285. App.ajax.send({
  286. name: 'common.host.host_component.update',
  287. sender: this,
  288. data: {
  289. context: context + " " + App.format.role(componentName),
  290. hostName: hostName[i],
  291. serviceName: serviceName,
  292. componentName: componentName,
  293. taskNum: taskNum || hostName.length,
  294. HostRoles: {
  295. state: state
  296. }
  297. },
  298. success: 'startPolling',
  299. error: 'onTaskError'
  300. });
  301. }
  302. },
  303. startPolling: function (data) {
  304. if (data) {
  305. console.warn('func: startPolling1');
  306. this.get('currentRequestIds').push(data.Requests.id);
  307. var tasksCount = arguments[2].taskNum || 1;
  308. if (tasksCount === this.get('currentRequestIds').length) {
  309. this.setRequestIds(this.get('currentTaskId'), this.get('currentRequestIds'));
  310. console.warn('func: startPolling2');
  311. this.doPolling();
  312. }
  313. } else {
  314. console.warn('func: startPolling3');
  315. this.onTaskCompleted();
  316. }
  317. },
  318. doPolling: function () {
  319. console.warn('func: doPolling');
  320. this.setTaskStatus(this.get('currentTaskId'), 'IN_PROGRESS');
  321. var requestIds = this.get('currentRequestIds');
  322. this.set('logs', []);
  323. for (var i = 0; i < requestIds.length; i++) {
  324. App.ajax.send({
  325. name: 'admin.high_availability.polling',
  326. sender: this,
  327. data: {
  328. requestId: requestIds[i]
  329. },
  330. success: 'parseLogs',
  331. error: 'onTaskError'
  332. });
  333. }
  334. },
  335. parseLogs: function (logs) {
  336. console.warn('func: parseLogs');
  337. this.get('logs').pushObject(logs.tasks);
  338. if (this.get('currentRequestIds').length === this.get('logs').length) {
  339. var tasks = [];
  340. this.get('logs').forEach(function (logs) {
  341. tasks.pushObjects(logs);
  342. }, this);
  343. var self = this;
  344. var currentTaskId = this.get('currentTaskId');
  345. if (!tasks.someProperty('Tasks.status', 'PENDING') && !tasks.someProperty('Tasks.status', 'QUEUED') && !tasks.someProperty('Tasks.status', 'IN_PROGRESS')) {
  346. this.set('currentRequestIds', []);
  347. if (tasks.someProperty('Tasks.status', 'FAILED') || tasks.someProperty('Tasks.status', 'TIMEDOUT') || tasks.someProperty('Tasks.status', 'ABORTED')) {
  348. this.setTaskStatus(currentTaskId, 'FAILED');
  349. } else {
  350. this.setTaskStatus(currentTaskId, 'COMPLETED');
  351. }
  352. } else {
  353. var actionsPerHost = tasks.length;
  354. var completedActions = tasks.filterProperty('Tasks.status', 'COMPLETED').length
  355. + tasks.filterProperty('Tasks.status', 'FAILED').length
  356. + tasks.filterProperty('Tasks.status', 'ABORTED').length
  357. + tasks.filterProperty('Tasks.status', 'TIMEDOUT').length;
  358. var queuedActions = tasks.filterProperty('Tasks.status', 'QUEUED').length;
  359. var inProgressActions = tasks.filterProperty('Tasks.status', 'IN_PROGRESS').length;
  360. var progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 100);
  361. this.get('tasks').findProperty('id', currentTaskId).set('progress', progress);
  362. window.setTimeout(function () {
  363. self.doPolling()
  364. }, self.POLL_INTERVAL);
  365. }
  366. }
  367. },
  368. showHostProgressPopup: function (event) {
  369. var popupTitle = event.contexts[0].title;
  370. var requestIds = event.contexts[0].requestIds;
  371. var hostProgressPopupController = App.router.get('highAvailabilityProgressPopupController');
  372. hostProgressPopupController.initPopup(popupTitle, requestIds, this, true);
  373. },
  374. done: function () {
  375. if (!this.get('isSubmitDisabled')) {
  376. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  377. App.router.send('next');
  378. }
  379. },
  380. /**
  381. *
  382. * @param siteNames Array
  383. */
  384. reconfigureSites: function(siteNames,data) {
  385. var tagName = 'version' + (new Date).getTime();
  386. var componentName;
  387. switch (this.get('content.controllerName')) {
  388. case 'rMHighAvailabilityWizardController':
  389. componentName = 'RESOURCEMANAGER';
  390. break;
  391. default:
  392. componentName = 'NAMENODE';
  393. }
  394. return siteNames.map(function(_siteName){
  395. return {
  396. type: _siteName,
  397. tag: tagName,
  398. properties: data.items.findProperty('type', _siteName).properties,
  399. service_config_version_note: Em.I18n.t('admin.highAvailability.step4.save.configuration.note').format(App.format.role(componentName))
  400. }
  401. });
  402. }
  403. });