step3_controller.js 18 KB

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