step3_controller.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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. App.StackUpgradeStep3Controller = Em.Controller.extend({
  20. name: 'stackUpgradeStep3Controller',
  21. POLL_INTERVAL: 4000,
  22. isPolling: false,
  23. /**
  24. * STOP_SERVICES internal statuses:
  25. * - PENDING
  26. * - IN_PROGRESS
  27. * - SUCCESS
  28. * - FAILED
  29. * UPGRADE_SERVICES internal statuses:
  30. * - PENDING
  31. * - IN_PROGRESS
  32. * - SUCCESS
  33. * - FAILED
  34. * - WARNING
  35. */
  36. processes:[
  37. Em.Object.create({
  38. name: 'STOP_SERVICES',
  39. displayName: Em.I18n.t('installer.stackUpgrade.step3.stop.header'),
  40. progress:0,
  41. status: 'PENDING',
  42. message: null,
  43. isRunning: false,
  44. hosts: [],
  45. isRetry: false
  46. }),
  47. Em.Object.create({
  48. name: 'UPGRADE_SERVICES',
  49. displayName: Em.I18n.t('installer.stackUpgrade.step3.upgrade.header'),
  50. progress: 0,
  51. status: 'PENDING',
  52. message:'',
  53. isRunning: false,
  54. hosts: [],
  55. isRetry: false
  56. })
  57. ],
  58. /**
  59. * pass processes as services to popup
  60. */
  61. services: function(){
  62. return this.get('processes');
  63. }.property('processes'),
  64. /**
  65. * save current requestId and clusterState
  66. * to localStorage and put it to server
  67. *
  68. * STOP_SERVICES cluster status:
  69. * - STOPPING_SERVICES,
  70. * UPGRADE_SERVICES cluster status:
  71. * - STACK_UPGRADING,
  72. * - STACK_UPGRADE_FAILED,
  73. * - STACK_UPGRADED,
  74. * - DEFAULT = STACK UPGRADE COMPLETED
  75. */
  76. saveClusterStatus: function(clusterStatus){
  77. var oldStatus = this.get('content.cluster');
  78. clusterStatus = jQuery.extend(oldStatus, clusterStatus);
  79. this.set('content.cluster', clusterStatus);
  80. App.router.get(this.get('content.controllerName')).save('cluster');
  81. if(!App.testMode){
  82. App.clusterStatus.setClusterStatus({
  83. clusterName: this.get('content.cluster.name'),
  84. clusterState: clusterStatus.status,
  85. wizardControllerName: 'stackUpgradeController',
  86. localdb: App.db.data
  87. });
  88. }
  89. },
  90. // provide binding for Host Popup data
  91. serviceTimestamp: null,
  92. /**
  93. * load hosts for each process
  94. */
  95. loadHosts: function () {
  96. var hosts = [];
  97. var installedHosts = App.Host.find();
  98. this.get('processes').forEach(function(process){
  99. var hosts = [];
  100. installedHosts.forEach(function (host) {
  101. hosts.push(Em.Object.create({
  102. name: host.get('hostName'),
  103. publicName: host.get('publicHostName'),
  104. logTasks: []
  105. }));
  106. });
  107. process.set('hosts', hosts);
  108. });
  109. }.observes('content.servicesInfo'),
  110. submitButton: null,
  111. /**
  112. * restart upgrade
  113. * restart stop services
  114. * @param event
  115. */
  116. retry: function(event){
  117. var processName = event.context;
  118. var process = this.get('processes').findProperty('name', processName);
  119. this.resetProgress(process);
  120. this.resetMockConfig();
  121. if(processName == 'STOP_SERVICES'){
  122. this.stopServices();
  123. } else {
  124. this.set('submitButton', false);
  125. this.runUpgrade();
  126. }
  127. },
  128. /**
  129. * reset progress and status to retry
  130. * @param process
  131. */
  132. resetProgress: function(process){
  133. process.set('isRetry', false);
  134. process.set('status', 'PENDING');
  135. process.set('progress', 0);
  136. process.get('hosts').forEach(function(host){host.get('logTasks').clear()});
  137. },
  138. /**
  139. * run stop services
  140. */
  141. stopServices: function () {
  142. var process = this.get('processes').findProperty('name', 'STOP_SERVICES');
  143. process.set('isRunning', true);
  144. if (App.testMode) {
  145. this.startPolling();
  146. this.saveClusterStatus({
  147. requestId: 1,
  148. status: 'STOPPING_SERVICES',
  149. isCompleted: false
  150. });
  151. }
  152. else {
  153. var data = '{"RequestInfo": {"context": "'+ Em.I18n.t("requestInfo.stopAllServices") +'"}, "Body": {"ServiceInfo": {"state": "INSTALLED"}}}';
  154. App.ajax.send({
  155. name: 'admin.stack_upgrade.stop_services',
  156. sender: this,
  157. data: {
  158. data: data
  159. },
  160. success: 'stopServicesSuccessCallback',
  161. error: 'stopServicesErrorCallback'
  162. });
  163. }
  164. },
  165. stopServicesSuccessCallback: function (data) {
  166. var process = this.get('processes').findProperty('name', 'STOP_SERVICES');
  167. var requestId = data.Requests.id;
  168. var clusterStatus = {
  169. requestId: requestId,
  170. status: 'STOPPING_SERVICES',
  171. isCompleted: false
  172. };
  173. process.set('status', 'IN_PROGRESS');
  174. this.saveClusterStatus(clusterStatus);
  175. this.startPolling();
  176. console.log('Call to stop service successful')
  177. },
  178. stopServicesErrorCallback: function () {
  179. var process = this.get('processes').findProperty('name', 'STOP_SERVICES');
  180. this.finishProcess(process, 'FAILED');
  181. process.set('status', 'FAILED');
  182. console.log("Call to stop services failed");
  183. },
  184. /**
  185. * send request to run upgrade all services
  186. */
  187. runUpgrade: function () {
  188. var process = this.get('processes').findProperty('name', 'UPGRADE_SERVICES');
  189. process.set('isRunning', true);
  190. if (App.testMode) {
  191. this.startPolling();
  192. this.saveClusterStatus({
  193. requestId: 1,
  194. status: 'STACK_UPGRADING',
  195. isCompleted: false
  196. });
  197. }
  198. else {
  199. var data = '{"Clusters": {"version" : "' + this.get('content.upgradeVersion') + '"}}';
  200. App.ajax.send({
  201. name: 'admin.stack_upgrade.run_upgrade',
  202. sender: this,
  203. data: {
  204. data: data
  205. },
  206. success: 'runUpgradeSuccessCallback',
  207. error: 'runUpgradeErrorCallback'
  208. });
  209. }
  210. },
  211. runUpgradeSuccessCallback: function (jsonData) {
  212. var process = this.get('processes').findProperty('name', 'UPGRADE_SERVICES');
  213. var requestId = jsonData.Requests.id;
  214. var clusterStatus = {
  215. status: 'STACK_UPGRADING',
  216. requestId: requestId,
  217. isCompleted: false
  218. };
  219. process.set('status', 'IN_PROGRESS');
  220. this.saveClusterStatus(clusterStatus);
  221. this.startPolling();
  222. },
  223. runUpgradeErrorCallback: function (request, ajaxOptions, error) {
  224. var process = this.get('processes').findProperty('name', 'UPGRADE_SERVICES');
  225. this.finishProcess(process, 'FAILED');
  226. process.set('status', 'FAILED');
  227. },
  228. /**
  229. * start polling tasks for current process
  230. */
  231. startPolling: function(){
  232. if(!this.get('isPolling')){
  233. this.set('isPolling', true);
  234. if (App.testMode) {
  235. this.simulatePolling();
  236. } else {
  237. //pass an interval "1" to start poll immediately first time
  238. this.doPoll(1);
  239. }
  240. }
  241. },
  242. simulateAttempt:0,
  243. mockUrl:'',
  244. /**
  245. * simulate actual poll, using mock data
  246. */
  247. simulatePolling: function(){
  248. var simulateAttempt = this.get('simulateAttempt');
  249. var process = this.get('processes').findProperty('isRunning', true);
  250. var upgradeURLs = [
  251. '/upgrade/poll_1.json',
  252. '/upgrade/poll_2.json',
  253. '/upgrade/poll_3.json',
  254. '/upgrade/poll_4.json',
  255. '/upgrade/poll_5.json'
  256. ];
  257. var stopURLs = [
  258. '/stop_services/poll_1.json',
  259. '/stop_services/poll_2.json',
  260. '/stop_services/poll_3.json',
  261. '/stop_services/poll_4.json'
  262. ];
  263. if(process.get('name') == 'STOP_SERVICES'){
  264. if(simulateAttempt < 4){
  265. this.set('mockUrl', stopURLs[simulateAttempt]);
  266. this.doPoll();
  267. this.set('simulateAttempt', ++simulateAttempt);
  268. }
  269. } else {
  270. if(simulateAttempt < 5){
  271. this.set('mockUrl', upgradeURLs[simulateAttempt]);
  272. this.doPoll();
  273. this.set('simulateAttempt', ++simulateAttempt);
  274. }
  275. }
  276. },
  277. getUrl:function(){
  278. var requestId = this.get('content.cluster.requestId');
  279. var clusterName = this.get('content.cluster.name');
  280. if(App.testMode){
  281. return this.get('mockUrl');
  282. }
  283. return App.apiPrefix + '/clusters/' + clusterName + '/requests/' + requestId + '?fields=tasks/*';
  284. },
  285. /**
  286. * poll server for tasks, which contain process progress data
  287. * @param interval
  288. */
  289. doPoll: function(interval) {
  290. var self = this;
  291. var pollInterval = interval || self.POLL_INTERVAL;
  292. if (self.get('isPolling')) {
  293. setTimeout(function () {
  294. App.ajax.send({
  295. name: 'admin.stack_upgrade.do_poll',
  296. sender: self,
  297. data: {
  298. cluster: self.get('content.cluster.name'),
  299. requestId: self.get('content.cluster.requestId'),
  300. mock: self.get('mockUrl')
  301. },
  302. success: 'doPollSuccessCallback',
  303. error: 'doPollErrorCallback'
  304. }).retry({
  305. times: App.maxRetries,
  306. timeout: App.timeout
  307. }).then(
  308. null,
  309. function () {
  310. App.showReloadPopup();
  311. console.log('Install services all retries failed');
  312. });
  313. }, pollInterval);
  314. }
  315. },
  316. doPollSuccessCallback: function (data) {
  317. var result = this.parseTasks(data);
  318. if(result){
  319. if (App.testMode) {
  320. this.simulatePolling();
  321. }
  322. else {
  323. this.doPoll();
  324. }
  325. }
  326. },
  327. doPollErrorCallback: function () {
  328. console.log('ERROR: poll request failed')
  329. },
  330. /**
  331. * parse tasks from poll
  332. * change status, message, progress on services according to tasks
  333. * @param data
  334. * @return {Boolean}
  335. */
  336. parseTasks: function(data){
  337. var tasks = data.tasks || [];
  338. var process = this.get('processes').findProperty('isRunning', true);
  339. // if process was finished then it terminates next poll
  340. var continuePolling = true;
  341. this.progressOnProcess(tasks, process);
  342. continuePolling = this.statusOnProcess(tasks, process);
  343. if(process.get('hosts').length && tasks.length){
  344. process.get('hosts').forEach(function (host) {
  345. var tasksPerHost = tasks.filterProperty('Tasks.host_name', host.name);
  346. if (tasksPerHost.length) {
  347. this.setLogTasksStatePerHost(tasksPerHost, host);
  348. }
  349. }, this);
  350. }
  351. this.set('serviceTimestamp', new Date().getTime());
  352. return continuePolling;
  353. },
  354. /**
  355. * calculate progress according to tasks status
  356. * @param actions
  357. * @param process
  358. */
  359. progressOnProcess: function(actions, process){
  360. var progress = 0;
  361. var actionsNumber = actions.length;
  362. var completedActions = actions.filterProperty('Tasks.status', 'COMPLETED').length
  363. + actions.filterProperty('Tasks.status', 'FAILED').length
  364. + actions.filterProperty('Tasks.status', 'ABORTED').length
  365. + actions.filterProperty('Tasks.status', 'TIMEDOUT').length;
  366. var queuedActions = actions.filterProperty('Tasks.status', 'QUEUED').length;
  367. var inProgressActions = actions.filterProperty('Tasks.status', 'IN_PROGRESS').length;
  368. progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsNumber * 100);
  369. console.log('INFO: progress is: ' + progress);
  370. process.set('progress', progress);
  371. },
  372. /**
  373. * evaluate status of process according to task status
  374. * @param actions
  375. * @param process
  376. */
  377. statusOnProcess: function(actions, process){
  378. var status = null;
  379. var message = '';
  380. var continuePolling = true;
  381. var errorActions = actions.filter(function (action) {
  382. if (action.Tasks.status == 'FAILED' || action.Tasks.status == 'ABORTED' || action.Tasks.status == 'TIMEDOUT') {
  383. return true;
  384. }
  385. });
  386. var masterComponents = ['NAMENODE', 'SECONDARY_NAMENODE', 'SNAMENODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER',
  387. 'HIVE_METASTORE', 'MYSQL_SERVER', 'HBASE_MASTER', 'NAGIOS_SERVER', 'GANGLIA_SERVER', 'OOZIE_SERVER', 'WEBHCAT_SERVER'];
  388. var failedComponents = errorActions.mapProperty('Tasks.role');
  389. if (failedComponents.length) {
  390. for (var i = 0; i < failedComponents.length; i++) {
  391. if (masterComponents.contains(failedComponents[i])) {
  392. status = "FAILED";
  393. continuePolling = false;
  394. this.finishProcess(process, status);
  395. break;
  396. } else if(process.get('progress') == 100){
  397. status = "WARNING";
  398. if(process.get('name') == 'UPGRADE_SERVICES'){
  399. continuePolling = false;
  400. this.finishProcess(process, status);
  401. }
  402. }
  403. }
  404. }
  405. if(!status || ((status == 'WARNING') && (process.get('name') == 'STOP_SERVICES'))){
  406. if (actions.everyProperty('Tasks.status', 'COMPLETED')) {
  407. status = 'SUCCESS';
  408. continuePolling = false;
  409. this.finishProcess(process, status);
  410. } else {
  411. var activeAction = actions.findProperty('Tasks.status', 'IN_PROGRESS');
  412. status = 'IN_PROGRESS';
  413. if (activeAction === undefined || activeAction === null) {
  414. activeAction = actions.findProperty('Tasks.status', 'QUEUED');
  415. status = 'PENDING';
  416. }
  417. if (activeAction === undefined || activeAction === null) {
  418. activeAction = actions.findProperty('Tasks.status', 'PENDING');
  419. status = 'PENDING';
  420. }
  421. if (activeAction) {
  422. message = this.displayMessage(activeAction.Tasks);
  423. }
  424. }
  425. }
  426. console.log('INFO: status is: ' + status);
  427. process.set('status', status);
  428. process.set('message', message);
  429. return continuePolling;
  430. },
  431. /**
  432. * complete process phase
  433. * accept FAILED, SUCCESS, WARNING process status
  434. * @param process
  435. * @param status
  436. */
  437. finishProcess: function(process, status){
  438. this.set('isPolling', false);
  439. if(process.get('name') == 'STOP_SERVICES'){
  440. if(status == 'SUCCESS'){
  441. process.set('isRunning', false);
  442. this.resetMockConfig();
  443. this.runUpgrade();
  444. } else {
  445. process.set('isRetry', true);
  446. }
  447. }
  448. if(process.get('name') == 'UPGRADE_SERVICES'){
  449. if(status == 'SUCCESS'){
  450. this.set('submitButton', Em.I18n.t('common.done'));
  451. this.saveClusterStatus({
  452. status: 'STACK_UPGRADED',
  453. isCompleted: true
  454. })
  455. } else if(status == 'FAILED') {
  456. process.set('isRetry', true);
  457. this.set('submitButton', false);
  458. this.saveClusterStatus({
  459. status: 'STACK_UPGRADE_FAILED',
  460. isCompleted: false
  461. })
  462. } else if(status == 'WARNING'){
  463. this.set('submitButton', Em.I18n.t('installer.stackUpgrade.step3.ProceedWithWarning'));
  464. process.set('isRetry', true);
  465. this.saveClusterStatus({
  466. status: 'STACK_UPGRADED',
  467. isCompleted: true
  468. })
  469. }
  470. }
  471. },
  472. /**
  473. * set and update logTasks to each host
  474. * @param tasksPerHost
  475. * @param host
  476. */
  477. setLogTasksStatePerHost: function (tasksPerHost, host) {
  478. tasksPerHost.forEach(function (_task) {
  479. var task = host.get('logTasks').findProperty('Tasks.id', _task.Tasks.id);
  480. if (task) {
  481. host.get('logTasks').removeObject(task);
  482. }
  483. host.get('logTasks').pushObject(_task);
  484. //}
  485. }, this);
  486. },
  487. /**
  488. * reset mock configs to run upgrade simulation again
  489. */
  490. resetMockConfig: function(retry){
  491. this.set('simulateAttempt', 0);
  492. },
  493. /**
  494. * resume wizard on last operation
  495. */
  496. resumeStep: function () {
  497. var clusterStatus = this.get('content.cluster.status');
  498. var upgrade = this.get('processes').findProperty('name', 'UPGRADE_SERVICES');
  499. var stop = this.get('processes').findProperty('name', 'STOP_SERVICES');
  500. if(App.testMode){
  501. if(this.get('processes').everyProperty('isRunning', false)){
  502. stop.set('isRunning', true);
  503. }
  504. clusterStatus = (this.get('processes').findProperty('name', 'UPGRADE_SERVICES').get('isRunning'))?
  505. 'STACK_UPGRADING':
  506. 'STOPPING_SERVICES';
  507. upgrade.set('isRetry', false);
  508. stop.set('isRetry', false);
  509. }
  510. if (clusterStatus == 'STOPPING_SERVICES') {
  511. this.startPolling();
  512. stop.set('isRunning', true);
  513. upgrade.set('isRunning', false);
  514. } else if(clusterStatus != 'PENDING'){
  515. stop.set('status', 'SUCCESS');
  516. stop.set('progress', 100);
  517. stop.set('isRunning', false);
  518. upgrade.set('isRunning', true);
  519. if (clusterStatus == 'STACK_UPGRADING') {
  520. upgrade.set('status', 'IN_PROGRESS');
  521. this.startPolling();
  522. } else if (clusterStatus == 'STACK_UPGRADE_FAILED') {
  523. upgrade.set('status', 'FAILED');
  524. upgrade.set('isRetry', true);
  525. } else if (clusterStatus == 'STACK_UPGRADED') {
  526. upgrade.set('status', 'SUCCESS');
  527. upgrade.set('progress', 100);
  528. this.startPolling();
  529. this.set('isPolling', false);
  530. }
  531. }
  532. },
  533. /**
  534. * determine description of current running process
  535. * @param task
  536. * @return {*}
  537. */
  538. displayMessage: function (task) {
  539. var role = App.format.role(task.role);
  540. switch (task.command){
  541. case 'UPGRADE':
  542. switch (task.status) {
  543. case 'PENDING':
  544. return Em.I18n.t('installer.step9.serviceStatus.upgrade.pending') + role;
  545. case 'QUEUED' :
  546. return Em.I18n.t('installer.step9.serviceStatus.upgrade.queued') + role;
  547. case 'IN_PROGRESS':
  548. return Em.I18n.t('installer.step9.serviceStatus.upgrade.inProgress') + role;
  549. case 'COMPLETED' :
  550. return Em.I18n.t('installer.step9.serviceStatus.upgrade.completed') + role;
  551. case 'FAILED':
  552. return Em.I18n.t('installer.step9.serviceStatus.upgrade.failed') + role;
  553. }
  554. break;
  555. case 'STOP' :
  556. switch (task.status) {
  557. case 'PENDING':
  558. return Em.I18n.t('installer.step9.serviceStatus.stop.pending') + role;
  559. case 'QUEUED' :
  560. return Em.I18n.t('installer.step9.serviceStatus.stop.queued') + role;
  561. case 'IN_PROGRESS':
  562. return Em.I18n.t('installer.step9.serviceStatus.stop.inProgress') + role;
  563. case 'COMPLETED' :
  564. return role + Em.I18n.t('installer.step9.serviceStatus.stop.completed');
  565. case 'FAILED':
  566. return role + Em.I18n.t('installer.step9.serviceStatus.stop.failed');
  567. }
  568. }
  569. }
  570. });