step3_controller.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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. * - 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 clusterName = this.get('content.cluster.name');
  143. var url = App.apiPrefix + '/clusters/' + clusterName + '/services?ServiceInfo/state=STARTED';
  144. var data = '{"RequestInfo": {"context": "'+ Em.I18n.t("requestInfo.stopAllServices") +'"}, "Body": {"ServiceInfo": {"state": "INSTALLED"}}}';
  145. var method = 'PUT';
  146. var process = this.get('processes').findProperty('name', 'STOP_SERVICES');
  147. var self = this;
  148. process.set('isRunning', true);
  149. if (App.testMode) {
  150. this.startPolling();
  151. this.saveClusterStatus({
  152. requestId: 1,
  153. status: 'STOPPING_SERVICES',
  154. isCompleted: false
  155. });
  156. } else {
  157. $.ajax({
  158. type: method,
  159. url: url,
  160. async: false,
  161. data: data,
  162. dataType: 'text',
  163. timeout: App.timeout,
  164. success: function (data) {
  165. var requestId = jQuery.parseJSON(data).Requests.id;
  166. var clusterStatus = {
  167. requestId: requestId,
  168. status: 'STOPPING_SERVICES',
  169. isCompleted: false
  170. };
  171. process.set('status', 'IN_PROGRESS');
  172. self.saveClusterStatus(clusterStatus);
  173. self.startPolling();
  174. console.log('Call to stop service successful')
  175. },
  176. error: function () {
  177. self.finishProcess(process, 'FAILED');
  178. process.set('status', 'FAILED');
  179. console.log("Call to stop services failed");
  180. },
  181. statusCode: require('data/statusCodes')
  182. });
  183. }
  184. },
  185. /**
  186. * send request to run upgrade all services
  187. */
  188. runUpgrade: function () {
  189. var method = "PUT";
  190. var url = App.apiPrefix + '/clusters/' + this.get('content.cluster.name');
  191. var self = this;
  192. var data = '{"Clusters": {"version" : "' + this.get('content.upgradeVersion') + '"}}';
  193. var process = this.get('processes').findProperty('name', 'UPGRADE_SERVICES');
  194. process.set('isRunning', true);
  195. if (App.testMode) {
  196. this.startPolling();
  197. this.saveClusterStatus({
  198. requestId: 1,
  199. status: 'STACK_UPGRADING',
  200. isCompleted: false
  201. });
  202. } else {
  203. $.ajax({
  204. type: method,
  205. url: url,
  206. async: false,
  207. data: data,
  208. dataType: 'text',
  209. timeout: App.timeout,
  210. success: function (data) {
  211. var jsonData = jQuery.parseJSON(data);
  212. var requestId = jsonData.Requests.id;
  213. var clusterStatus = {
  214. status: 'STACK_UPGRADING',
  215. requestId: requestId,
  216. isCompleted: false
  217. };
  218. process.set('status', 'IN_PROGRESS');
  219. self.saveClusterStatus(clusterStatus);
  220. self.startPolling();
  221. },
  222. error: function (request, ajaxOptions, error) {
  223. self.finishProcess(process, 'FAILED');
  224. process.set('status', 'FAILED');
  225. },
  226. statusCode: require('data/statusCodes')
  227. });
  228. }
  229. },
  230. /**
  231. * start polling tasks for current process
  232. */
  233. startPolling: function(){
  234. if(!this.get('isPolling')){
  235. this.set('isPolling', true);
  236. if (App.testMode) {
  237. this.simulatePolling();
  238. } else {
  239. //pass an interval "1" to start poll immediately first time
  240. this.doPoll(1);
  241. }
  242. }
  243. },
  244. simulateAttempt:0,
  245. mockUrl:'',
  246. /**
  247. * simulate actual poll, using mock data
  248. */
  249. simulatePolling: function(){
  250. var simulateAttempt = this.get('simulateAttempt');
  251. var process = this.get('processes').findProperty('isRunning', true);
  252. var upgradeURLs = [
  253. '/data/wizard/upgrade/poll_1.json',
  254. '/data/wizard/upgrade/poll_2.json',
  255. '/data/wizard/upgrade/poll_3.json',
  256. '/data/wizard/upgrade/poll_4.json',
  257. '/data/wizard/upgrade/poll_5.json'
  258. ];
  259. var stopURLs = [
  260. '/data/wizard/stop_services/poll_1.json',
  261. '/data/wizard/stop_services/poll_2.json',
  262. '/data/wizard/stop_services/poll_3.json',
  263. '/data/wizard/stop_services/poll_4.json'
  264. ];
  265. if(process.get('name') == 'STOP_SERVICES'){
  266. if(simulateAttempt < 4){
  267. this.set('mockUrl', stopURLs[simulateAttempt]);
  268. this.doPoll();
  269. this.set('simulateAttempt', ++simulateAttempt);
  270. }
  271. } else {
  272. if(simulateAttempt < 5){
  273. this.set('mockUrl', upgradeURLs[simulateAttempt]);
  274. this.doPoll();
  275. this.set('simulateAttempt', ++simulateAttempt);
  276. }
  277. }
  278. },
  279. getUrl:function(){
  280. var requestId = this.get('content.cluster.requestId');
  281. var clusterName = this.get('content.cluster.name');
  282. if(App.testMode){
  283. return this.get('mockUrl');
  284. }
  285. return App.apiPrefix + '/clusters/' + clusterName + '/requests/' + requestId + '?fields=tasks/*';
  286. },
  287. /**
  288. * poll server for tasks, which contain process progress data
  289. * @param interval
  290. */
  291. doPoll: function(interval){
  292. var url = this.getUrl();
  293. var self = this;
  294. var pollInterval = interval || self.POLL_INTERVAL;
  295. if (self.get('isPolling')) {
  296. setTimeout(function () {
  297. $.ajax({
  298. type: 'GET',
  299. url: url,
  300. async: true,
  301. timeout: App.timeout,
  302. dataType: 'json',
  303. success: function (data) {
  304. var result = self.parseTasks(data);
  305. if(result){
  306. if (App.testMode) {
  307. self.simulatePolling();
  308. } else {
  309. self.doPoll();
  310. }
  311. }
  312. },
  313. error: function () {
  314. console.log('ERROR: poll request failed')
  315. },
  316. statusCode: require('data/statusCodes')
  317. }).retry({times: App.maxRetries, timeout: App.timeout}).then(null,
  318. function () {
  319. App.showReloadPopup();
  320. console.log('Install services all retries failed');
  321. }
  322. );
  323. }, pollInterval);
  324. }
  325. },
  326. /**
  327. * parse tasks from poll
  328. * change status, message, progress on services according to tasks
  329. * @param data
  330. * @return {Boolean}
  331. */
  332. parseTasks: function(data){
  333. var tasks = data.tasks || [];
  334. var process = this.get('processes').findProperty('isRunning', true);
  335. // if process was finished then it terminates next poll
  336. var continuePolling = true;
  337. this.progressOnProcess(tasks, process);
  338. continuePolling = this.statusOnProcess(tasks, process);
  339. if(process.get('hosts').length && tasks.length){
  340. process.get('hosts').forEach(function (host) {
  341. var tasksPerHost = tasks.filterProperty('Tasks.host_name', host.name);
  342. if (tasksPerHost.length) {
  343. this.setLogTasksStatePerHost(tasksPerHost, host);
  344. }
  345. }, this);
  346. }
  347. this.set('serviceTimestamp', new Date().getTime());
  348. return continuePolling;
  349. },
  350. /**
  351. * calculate progress according to tasks status
  352. * @param actions
  353. * @param process
  354. */
  355. progressOnProcess: function(actions, process){
  356. var progress = 0;
  357. var actionsNumber = actions.length;
  358. var completedActions = actions.filterProperty('Tasks.status', 'COMPLETED').length
  359. + actions.filterProperty('Tasks.status', 'FAILED').length
  360. + actions.filterProperty('Tasks.status', 'ABORTED').length
  361. + actions.filterProperty('Tasks.status', 'TIMEDOUT').length;
  362. var queuedActions = actions.filterProperty('Tasks.status', 'QUEUED').length;
  363. var inProgressActions = actions.filterProperty('Tasks.status', 'IN_PROGRESS').length;
  364. progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsNumber * 100);
  365. console.log('INFO: progress is: ' + progress);
  366. process.set('progress', progress);
  367. },
  368. /**
  369. * evaluate status of process according to task status
  370. * @param actions
  371. * @param process
  372. */
  373. statusOnProcess: function(actions, process){
  374. var status = null;
  375. var message = '';
  376. var continuePolling = true;
  377. var errorActions = actions.filter(function (action) {
  378. if (action.Tasks.status == 'FAILED' || action.Tasks.status == 'ABORTED' || action.Tasks.status == 'TIMEDOUT') {
  379. return true;
  380. }
  381. });
  382. var masterComponents = ['NAMENODE', 'SECONDARY_NAMENODE', 'SNAMENODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER',
  383. 'HIVE_METASTORE', 'MYSQL_SERVER', 'HBASE_MASTER', 'NAGIOS_SERVER', 'GANGLIA_SERVER', 'OOZIE_SERVER', 'WEBHCAT_SERVER'];
  384. var failedComponents = errorActions.mapProperty('Tasks.role');
  385. if (failedComponents.length) {
  386. for (var i = 0; i < failedComponents.length; i++) {
  387. if (masterComponents.contains(failedComponents[i])) {
  388. status = "FAILED";
  389. continuePolling = false;
  390. this.finishProcess(process, status);
  391. break;
  392. } else if(process.get('progress') == 100){
  393. status = "WARNING";
  394. if(process.get('name') == 'UPGRADE_SERVICES'){
  395. continuePolling = false;
  396. this.finishProcess(process, status);
  397. }
  398. }
  399. }
  400. }
  401. if(!status || ((status == 'WARNING') && (process.get('name') == 'STOP_SERVICES'))){
  402. if (actions.everyProperty('Tasks.status', 'COMPLETED')) {
  403. status = 'SUCCESS';
  404. continuePolling = false;
  405. this.finishProcess(process, status);
  406. } else {
  407. var activeAction = actions.findProperty('Tasks.status', 'IN_PROGRESS');
  408. status = 'IN_PROGRESS';
  409. if (activeAction === undefined || activeAction === null) {
  410. activeAction = actions.findProperty('Tasks.status', 'QUEUED');
  411. status = 'PENDING';
  412. }
  413. if (activeAction === undefined || activeAction === null) {
  414. activeAction = actions.findProperty('Tasks.status', 'PENDING');
  415. status = 'PENDING';
  416. }
  417. if (activeAction) {
  418. message = this.displayMessage(activeAction.Tasks);
  419. }
  420. }
  421. }
  422. console.log('INFO: status is: ' + status);
  423. process.set('status', status);
  424. process.set('message', message);
  425. return continuePolling;
  426. },
  427. /**
  428. * complete process phase
  429. * accept FAILED, SUCCESS, WARNING process status
  430. * @param process
  431. * @param status
  432. */
  433. finishProcess: function(process, status){
  434. this.set('isPolling', false);
  435. if(process.get('name') == 'STOP_SERVICES'){
  436. if(status == 'SUCCESS'){
  437. process.set('isRunning', false);
  438. this.resetMockConfig();
  439. this.runUpgrade();
  440. } else {
  441. process.set('isRetry', true);
  442. }
  443. }
  444. if(process.get('name') == 'UPGRADE_SERVICES'){
  445. if(status == 'SUCCESS'){
  446. this.set('submitButton', Em.I18n.t('common.done'));
  447. this.saveClusterStatus({
  448. status: 'STACK_UPGRADED',
  449. isCompleted: true
  450. })
  451. } else if(status == 'FAILED') {
  452. process.set('isRetry', true);
  453. this.set('submitButton', false);
  454. this.saveClusterStatus({
  455. status: 'STACK_UPGRADE_FAILED',
  456. isCompleted: false
  457. })
  458. } else if(status == 'WARNING'){
  459. this.set('submitButton', Em.I18n.t('installer.stackUpgrade.step3.ProceedWithWarning'));
  460. process.set('isRetry', true);
  461. this.saveClusterStatus({
  462. status: 'STACK_UPGRADED',
  463. isCompleted: true
  464. })
  465. }
  466. }
  467. },
  468. /**
  469. * set and update logTasks to each host
  470. * @param tasksPerHost
  471. * @param host
  472. */
  473. setLogTasksStatePerHost: function (tasksPerHost, host) {
  474. console.log('In step3 setTasksStatePerHost function.');
  475. tasksPerHost.forEach(function (_task) {
  476. console.log('In step3 _taskPerHost function.');
  477. var task = host.get('logTasks').findProperty('Tasks.id', _task.Tasks.id);
  478. if (task) {
  479. host.get('logTasks').removeObject(task);
  480. }
  481. host.get('logTasks').pushObject(_task);
  482. //}
  483. }, this);
  484. },
  485. /**
  486. * reset mock configs to run upgrade simulation again
  487. */
  488. resetMockConfig: function(retry){
  489. this.set('simulateAttempt', 0);
  490. },
  491. /**
  492. * resume wizard on last operation
  493. */
  494. resumeStep: function () {
  495. var clusterStatus = this.get('content.cluster.status');
  496. var upgrade = this.get('processes').findProperty('name', 'UPGRADE_SERVICES');
  497. var stop = this.get('processes').findProperty('name', 'STOP_SERVICES');
  498. if(App.testMode){
  499. if(this.get('processes').everyProperty('isRunning', false)){
  500. stop.set('isRunning', true);
  501. }
  502. clusterStatus = (this.get('processes').findProperty('name', 'UPGRADE_SERVICES').get('isRunning'))?
  503. 'STACK_UPGRADING':
  504. 'STOPPING_SERVICES';
  505. upgrade.set('isRetry', false);
  506. stop.set('isRetry', false);
  507. }
  508. if (clusterStatus == 'STOPPING_SERVICES') {
  509. this.startPolling();
  510. stop.set('isRunning', true);
  511. upgrade.set('isRunning', false);
  512. } else if(clusterStatus != 'PENDING'){
  513. stop.set('status', 'SUCCESS');
  514. stop.set('progress', 100);
  515. stop.set('isRunning', false);
  516. upgrade.set('isRunning', true);
  517. if (clusterStatus == 'STACK_UPGRADING') {
  518. upgrade.set('status', 'IN_PROGRESS');
  519. this.startPolling();
  520. } else if (clusterStatus == 'STACK_UPGRADE_FAILED') {
  521. upgrade.set('status', 'FAILED');
  522. upgrade.set('isRetry', true);
  523. } else if (clusterStatus == 'STACK_UPGRADED') {
  524. upgrade.set('status', 'SUCCESS');
  525. upgrade.set('progress', 100);
  526. this.startPolling();
  527. this.set('isPolling', false);
  528. }
  529. }
  530. },
  531. /**
  532. * determine description of current running process
  533. * @param task
  534. * @return {*}
  535. */
  536. displayMessage: function (task) {
  537. var role = App.format.role(task.role);
  538. console.log("In display message with task command value: " + task.command);
  539. switch (task.command){
  540. case 'UPGRADE':
  541. switch (task.status) {
  542. case 'PENDING':
  543. return Em.I18n.t('installer.step9.serviceStatus.upgrade.pending') + role;
  544. case 'QUEUED' :
  545. return Em.I18n.t('installer.step9.serviceStatus.upgrade.queued') + role;
  546. case 'IN_PROGRESS':
  547. return Em.I18n.t('installer.step9.serviceStatus.upgrade.inProgress') + role;
  548. case 'COMPLETED' :
  549. return Em.I18n.t('installer.step9.serviceStatus.upgrade.completed') + role;
  550. case 'FAILED':
  551. return Em.I18n.t('installer.step9.serviceStatus.upgrade.failed') + role;
  552. }
  553. break;
  554. case 'STOP' :
  555. switch (task.status) {
  556. case 'PENDING':
  557. return Em.I18n.t('installer.step9.serviceStatus.stop.pending') + role;
  558. case 'QUEUED' :
  559. return Em.I18n.t('installer.step9.serviceStatus.stop.queued') + role;
  560. case 'IN_PROGRESS':
  561. return Em.I18n.t('installer.step9.serviceStatus.stop.inProgress') + role;
  562. case 'COMPLETED' :
  563. return role + Em.I18n.t('installer.step9.serviceStatus.stop.completed');
  564. case 'FAILED':
  565. return role + Em.I18n.t('installer.step9.serviceStatus.stop.failed');
  566. }
  567. }
  568. }
  569. });