step3_controller.js 16 KB

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