step3_controller.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  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. isUpgradeStarted: false,
  24. servicesOrder: [
  25. 'HDFS',
  26. 'MAPREDUCE',
  27. 'ZOOKEEPER',
  28. 'HBASE',
  29. 'HIVE',
  30. 'OOZIE',
  31. 'NAGIOS',
  32. 'GANGLIA',
  33. 'PIG',
  34. 'SQOOP'
  35. ],
  36. /**
  37. * overall status of Upgrade
  38. * FAILED - some service is FAILED
  39. * SUCCESS - every services are SUCCESS
  40. * WARNING - some service is WARNING and all the rest are SUCCESS
  41. * IN_PROGRESS - when all services is stopped
  42. */
  43. status: 'PENDING',
  44. onStatus: function () {
  45. var services = this.get('services');
  46. var status = this.get('isServicesStopped') ? 'IN_PROGRESS' : 'PENDING';
  47. var withoutWarning = [];
  48. if (services.someProperty('status', 'FAILED')) {
  49. this.set('isPolling', false);
  50. status = 'FAILED';
  51. this.setClusterStatus('STACK_UPGRADE_FAILED');
  52. }
  53. if (services.someProperty('status', 'WARNING')) {
  54. withoutWarning = services.filter(function(service){
  55. if(service.get('status') !== "WARNING"){
  56. return true;
  57. }
  58. });
  59. if(withoutWarning.everyProperty('status', 'SUCCESS')){
  60. this.set('isPolling', false);
  61. status = "WARNING";
  62. this.setClusterStatus('STACK_UPGRADED');
  63. }
  64. }
  65. if (services.everyProperty('status', 'SUCCESS')) {
  66. this.set('isPolling', false);
  67. status = 'SUCCESS';
  68. this.set('content.cluster.isCompleted', true);
  69. App.router.get(this.get('content.controllerName')).save('cluster');
  70. this.setClusterStatus('STACK_UPGRADED');
  71. }
  72. this.set('status', status);
  73. }.observes('services.@each.status'),
  74. setClusterStatus: function(state){
  75. if(!App.testMode){
  76. App.clusterStatus.setClusterStatus({
  77. clusterName: this.get('content.cluster.name'),
  78. clusterState: state,
  79. wizardControllerName: 'stackUpgradeController',
  80. localdb: App.db.data
  81. });
  82. }
  83. },
  84. // provide binding for Host Popup data
  85. serviceTimestamp: null,
  86. /**
  87. * The dependence of the status of service to status of the tasks
  88. * FAILED - any task is TIMEDOUT, ABORTED, FAILED (depends on component is master)
  89. * WARNING - any task is TIMEDOUT, ABORTED, FAILED (depends on component is slave or client)
  90. * SUCCESS - every tasks are COMPLETED
  91. * IN_PROGRESS - any task is UPGRADING(IN_PROGRESS)
  92. * PENDING - every tasks are QUEUED or PENDING
  93. */
  94. services: [],
  95. /**
  96. * load services, which installed on cluster
  97. */
  98. loadServices: function(){
  99. var installedServices = App.testMode ? this.get('mockServices') : this.get('content.servicesInfo');
  100. var services = [];
  101. var order = this.get('servicesOrder');
  102. installedServices.sort(function(a, b){
  103. return order.indexOf(a.get('serviceName')) - order.indexOf(b.get('serviceName'));
  104. });
  105. installedServices.forEach(function(_service){
  106. services.push(Em.Object.create({
  107. name: _service.get('serviceName'),
  108. displayName: _service.get('displayName'),
  109. hosts: this.loadHosts(_service),
  110. progress: 0,
  111. message: function(){
  112. switch(this.get('status')){
  113. case "FAILED":
  114. return Em.I18n.t('installer.stackUpgrade.step3.service.failedUpgrade').format(this.get('name'));
  115. break;
  116. case "WARNING":
  117. return Em.I18n.t('installer.stackUpgrade.step3.service.upgraded').format(this.get('name'));
  118. break;
  119. case "SUCCESS":
  120. return Em.I18n.t('installer.stackUpgrade.step3.service.upgraded').format(this.get('name'));
  121. break;
  122. case "IN_PROGRESS":
  123. return Em.I18n.t('installer.stackUpgrade.step3.service.upgrading').format(this.get('name'));
  124. break;
  125. case "PENDING":
  126. default:
  127. return Em.I18n.t('installer.stackUpgrade.step3.service.pending').format(this.get('name'));
  128. break;
  129. }
  130. }.property('status'),
  131. status: "PENDING",
  132. detailMessage:''
  133. }));
  134. }, this);
  135. this.set('services', services);
  136. }.observes('content.servicesInfo'),
  137. /**
  138. * load hosts as services property
  139. * @param service
  140. * @return {Array}
  141. */
  142. loadHosts: function(service){
  143. var hostComponents = App.HostComponent.find().filterProperty('service.serviceName', service.get('serviceName'));
  144. var hosts = hostComponents.mapProperty('host').uniq();
  145. var result = [];
  146. hosts.forEach(function(host){
  147. result.push(Em.Object.create({
  148. name: host.get('hostName'),
  149. publicName: host.get('publicHostName'),
  150. logTasks: [],
  151. components: hostComponents.filterProperty('host.hostName', host.get('hostName')).mapProperty('componentName')
  152. }));
  153. });
  154. return result;
  155. },
  156. /**
  157. * upgrade status SUCCESS - submit button enabled with label "Done"
  158. * upgrade status WARNING - submit button enabled with label "Proceed with Warning"
  159. * upgrade status FAILED or IN_PROGRESS - submit button disabled
  160. */
  161. submitButton: function(){
  162. if(this.get('status') == 'SUCCESS'){
  163. return Em.I18n.t('common.done');
  164. } else if(this.get('status') == 'WARNING'){
  165. return Em.I18n.t('installer.stackUpgrade.step3.ProceedWithWarning');
  166. } else {
  167. return false;
  168. }
  169. }.property('status'),
  170. showRetry: function () {
  171. return (this.get('status') === 'FAILED' || this.get('status') === 'WARNING');
  172. }.property('status'),
  173. isServicesStopped: function(){
  174. return this.get('servicesStopProgress') === 100;
  175. }.property('servicesStopProgress'),
  176. isServicesStopFailed: function(){
  177. return this.get('servicesStopProgress') === false;
  178. }.property('servicesStopProgress'),
  179. installedServices: App.Service.find(),
  180. /**
  181. * progress of stopping services process
  182. * check whether service stop fails
  183. */
  184. servicesStopProgress: function(){
  185. var services = App.testMode ? this.get('mockServices') : this.get('installedServices').toArray();
  186. var progress = 0;
  187. var stopFailed = false;
  188. services.forEach(function(service){
  189. if(!stopFailed){
  190. stopFailed = service.get('hostComponents').filterProperty('isMaster').someProperty('workStatus', 'STOP_FAILED');
  191. }
  192. });
  193. if(stopFailed){
  194. return false;
  195. } else {
  196. progress = (services.filterProperty('workStatus', 'STOPPING').length / services.length) * 0.2;
  197. return Math.round((progress + services.filterProperty('workStatus', 'INSTALLED').length / services.length) * 100);
  198. }
  199. }.property('installedServices.@each.workStatus', 'mockServices.@each.workStatus'),
  200. retryStopService: function(){
  201. App.router.get(this.get('content.controllerName')).stopServices();
  202. },
  203. /**
  204. * restart upgrade if fail or warning occurred
  205. * @param event
  206. */
  207. retry: function(event){
  208. this.set('isUpgradeStarted', false);
  209. this.resetMockConfig(true);
  210. this.loadServices();
  211. this.runUpgrade();
  212. },
  213. /**
  214. * send request to run upgrade all services
  215. */
  216. runUpgrade: function(){
  217. // call to run upgrade on server
  218. var method = App.testMode ? "GET" : "PUT";
  219. var url = '';
  220. var data = '';
  221. var self = this;
  222. if(this.get('isServicesStopped') && !this.get('isUpgradeStarted')){
  223. //TODO remove assignment isUpgradeStarted true to Ajax success callback
  224. this.set('isUpgradeStarted', true);
  225. /* $.ajax({
  226. type: method,
  227. url: url,
  228. data: data,
  229. async: false,
  230. dataType: 'text',
  231. timeout: App.timeout,
  232. success: function (data) {
  233. },
  234. error: function (request, ajaxOptions, error) {
  235. },
  236. statusCode: require('data/statusCodes')
  237. });*/
  238. /*App.clusterStatus.setClusterStatus({
  239. clusterName: this.get('clusterName'),
  240. clusterState: 'UPGRADING_STACK',
  241. wizardControllerName: 'stackUpgradeController',
  242. localdb: App.db.data
  243. });*/
  244. this.startPolling();
  245. }
  246. }.observes('isServicesStopped'),
  247. /**
  248. * start polling on upgrade progress
  249. */
  250. startPolling: function(){
  251. //TODO set actual URL to poll upgrade progress
  252. var url = '';
  253. if(!this.get('isPolling')){
  254. this.set('isPolling', true);
  255. if (App.testMode) {
  256. this.simulatePolling();
  257. } else {
  258. //pass an interval "1" to start poll immediately first time
  259. this.doPoll(url, 1);
  260. }
  261. }
  262. },
  263. mockServices: [
  264. Em.Object.create({
  265. serviceName: 'GANGLIA',
  266. displayName: 'Ganglia',
  267. workStatus: 'STARTED',
  268. hostComponents: []
  269. }),
  270. Em.Object.create({
  271. serviceName: 'HDFS',
  272. displayName: 'HDFS',
  273. workStatus: 'STARTED',
  274. hostComponents: []
  275. })
  276. ],
  277. simulateAttempt:0,
  278. /**
  279. * simulate actual poll, using mock data
  280. */
  281. simulatePolling: function(){
  282. var simulateAttempt = this.get('simulateAttempt');
  283. var URLs = [
  284. '/data/wizard/upgrade/poll_1.json',
  285. '/data/wizard/upgrade/poll_2.json',
  286. '/data/wizard/upgrade/poll_3.json',
  287. '/data/wizard/upgrade/poll_4.json',
  288. '/data/wizard/upgrade/poll_5.json'
  289. ];
  290. if(simulateAttempt < 5){
  291. this.doPoll(URLs[simulateAttempt]);
  292. this.set('simulateAttempt', ++simulateAttempt);
  293. }
  294. },
  295. /**
  296. * simulate stopping services before upgrade,
  297. * using mockServices data
  298. */
  299. simulateStopService: function(){
  300. var services = this.get('mockServices');
  301. var self = this;
  302. setTimeout(function(){
  303. services[0].set('workStatus', 'STOPPING');
  304. }, 4000);
  305. setTimeout(function(){
  306. services[0].set('workStatus', 'INSTALLED');
  307. }, 8000);
  308. setTimeout(function(){
  309. services[1].set('workStatus', 'STOPPING');
  310. }, 12000);
  311. setTimeout(function(){
  312. services[1].set('workStatus', 'INSTALLED');
  313. services.setEach('workStatus', 'INSTALLED');
  314. }, 16000);
  315. },
  316. /**
  317. * poll server for tasks, which contain upgrade progress data
  318. * @param url
  319. * @param interval
  320. */
  321. doPoll: function(url, interval){
  322. var self = this;
  323. var pollInterval = interval || self.POLL_INTERVAL;
  324. if (self.get('isPolling')) {
  325. setTimeout(function () {
  326. $.ajax({
  327. utype: 'GET',
  328. url: url,
  329. async: true,
  330. timeout: App.timeout,
  331. dataType: 'json',
  332. success: function (data) {
  333. var result = self.parseTasks(data);
  334. if (App.testMode) {
  335. self.simulatePolling();
  336. } else {
  337. self.doPoll(url);
  338. }
  339. },
  340. error: function () {
  341. },
  342. statusCode: require('data/statusCodes')
  343. }).retry({times: App.maxRetries, timeout: App.timeout}).then(null,
  344. function () {
  345. App.showReloadPopup();
  346. console.log('Install services all retries failed');
  347. }
  348. );
  349. }, pollInterval);
  350. }
  351. },
  352. /**
  353. * parse tasks from poll
  354. * change status, message, progress on services according to tasks
  355. * @param data
  356. * @return {Boolean}
  357. */
  358. parseTasks: function(data){
  359. var tasks = data.tasks || [];
  360. this.get('services').forEach(function (service) {
  361. var hosts = service.get('hosts');
  362. var tasksPerService = [];
  363. if(hosts.length){
  364. hosts.forEach(function (host) {
  365. var tasksPerHost = tasks.filter(function(task){
  366. if(task.Tasks.host_name == host.name && host.get('components').contains(task.Tasks.role)){
  367. return true;
  368. }
  369. });
  370. if (tasksPerHost.length) {
  371. this.setLogTasksStatePerHost(tasksPerHost, host);
  372. tasksPerService = tasksPerService.concat(tasksPerHost);
  373. }
  374. }, this);
  375. this.progressOnService(service, tasksPerService);
  376. this.statusOnService(service, tasksPerService);
  377. } else {
  378. service.set('status', 'PENDING');
  379. service.set('detailedMessage', Em.I18n.t('installer.stackUpgrade.step3.host.nothingToUpgrade'));
  380. console.log('None tasks matched to service ' + service);
  381. }
  382. }, this);
  383. this.set('serviceTimestamp', new Date().getTime());
  384. return true;
  385. },
  386. /**
  387. * evaluate status of service depending on the tasks
  388. * also set detailMessage that show currently running process
  389. * @param service
  390. * @param actions
  391. */
  392. statusOnService: function(service, actions){
  393. var status;
  394. var errorActions = actions.filter(function(action){
  395. if(action.Tasks.status == 'FAILED' || action.Tasks.status == 'ABORTED' || action.Tasks.status == 'TIMEDOUT'){
  396. return true;
  397. }
  398. });
  399. var masterComponents = ['NAMENODE', 'SECONDARY_NAMENODE', 'SNAMENODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER',
  400. 'HIVE_METASTORE', 'MYSQL_SERVER', 'HBASE_MASTER', 'NAGIOS_SERVER', 'GANGLIA_SERVER', 'OOZIE_SERVER','WEBHCAT_SERVER'];
  401. var failedComponents = errorActions.mapProperty('Tasks.role');
  402. if(failedComponents.length){
  403. for(var i = 0; i < failedComponents.length; i++){
  404. if(masterComponents.contains(failedComponents[i])){
  405. status = "FAILED";
  406. break;
  407. } else {
  408. status = "WARNING";
  409. }
  410. }
  411. } else if(actions.everyProperty('Tasks.status', 'COMPLETED')){
  412. status = 'SUCCESS';
  413. } else {
  414. var activeAction = actions.findProperty('Tasks.status', 'UPGRADING');
  415. status = 'IN_PROGRESS';
  416. if (activeAction === undefined || activeAction === null) {
  417. activeAction = actions.findProperty('Tasks.status', 'QUEUED');
  418. status = 'PENDING';
  419. }
  420. if (activeAction === undefined || activeAction === null) {
  421. activeAction = actions.findProperty('Tasks.status', 'PENDING');
  422. status = 'PENDING';
  423. }
  424. if(activeAction){
  425. service.set('detailMessage', this.displayMessage(activeAction.Tasks));
  426. }
  427. }
  428. service.set('status', status);
  429. },
  430. /**
  431. * calculate progress of service depending on the tasks
  432. * @param service
  433. * @param actions
  434. */
  435. progressOnService: function(service, actions){
  436. var progress = 0;
  437. var actionsNumber = actions.length;
  438. var completedActions = actions.filterProperty('Tasks.status', 'COMPLETED').length
  439. + actions.filterProperty('Tasks.status', 'FAILED').length
  440. + actions.filterProperty('Tasks.status', 'ABORTED').length
  441. + actions.filterProperty('Tasks.status', 'TIMEDOUT').length;
  442. var queuedActions = actions.filterProperty('Tasks.status', 'QUEUED').length;
  443. var inProgressActions = actions.filterProperty('Tasks.status', 'UPGRADING').length;
  444. progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsNumber * 100);
  445. console.log('INFO: progressPerService is: ' + progress);
  446. service.set('progress', progress);
  447. },
  448. /**
  449. * determine description of current running process
  450. * @param task
  451. * @return {*}
  452. */
  453. displayMessage: function (task) {
  454. var role = App.format.role(task.role);
  455. // accept only default command - "UPGRADE"
  456. console.log("In display message with task command value: " + task.command);
  457. switch (task.status) {
  458. case 'PENDING':
  459. return Em.I18n.t('installer.step9.serviceStatus.upgrade.pending') + role;
  460. case 'QUEUED' :
  461. return Em.I18n.t('installer.step9.serviceStatus.upgrade.queued') + role;
  462. case 'UPGRADING':
  463. return Em.I18n.t('installer.step9.serviceStatus.upgrade.inProgress') + role;
  464. case 'COMPLETED' :
  465. return Em.I18n.t('installer.step9.serviceStatus.upgrade.completed') + role;
  466. case 'FAILED':
  467. return Em.I18n.t('installer.step9.serviceStatus.upgrade.failed') + role;
  468. }
  469. },
  470. /**
  471. * set and update logTasks to each host
  472. * @param tasksPerHost
  473. * @param host
  474. */
  475. setLogTasksStatePerHost: function (tasksPerHost, host) {
  476. console.log('In step3 setTasksStatePerHost function.');
  477. tasksPerHost.forEach(function (_task) {
  478. console.log('In step3 _taskPerHost function.');
  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. * clear config and data after completion of upgrade
  489. */
  490. clearStep: function(){
  491. this.get('services').clear();
  492. this.set('isUpgradeStarted', false);
  493. this.resetMockConfig(false);
  494. },
  495. /**
  496. * reset mock configs to run upgrade simulation again
  497. */
  498. resetMockConfig: function(retry){
  499. if(!retry){
  500. this.get('mockServices').setEach('workStatus', 'STARTED');
  501. }
  502. this.set('simulateAttempt', 0);
  503. },
  504. /**
  505. * navigate to show current process depending on cluster status
  506. */
  507. navigateStep: function(){
  508. var clusterStatus = this.get('content.cluster.status');
  509. var status = 'PENDING';
  510. if (this.get('content.cluster.isCompleted') === false) {
  511. if (this.get('isServicesStopped')){
  512. this.startPolling();
  513. if (clusterStatus === 'STACK_UPGRADING'){
  514. // IN_PROGRESS
  515. status = 'IN_PROGRESS';
  516. } else if (clusterStatus === 'STACK_UPGRADE_FAILED'){
  517. // FAILED
  518. status = 'FAILED';
  519. // poll only one time
  520. this.set('isPolling', false);
  521. } else {
  522. // WARNING
  523. status = 'WARNING';
  524. // poll only one time
  525. this.set('isPolling', false);
  526. }
  527. } else {
  528. // services are stopping yet
  529. }
  530. } else {
  531. status = 'SUCCESS';
  532. }
  533. if (App.testMode) {
  534. if(!this.get('isServicesStopped')){
  535. this.simulateStopService();
  536. }
  537. } else {
  538. this.set('status', status);
  539. }
  540. }
  541. });