/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var App = require('app'); App.WizardStep9Controller = Em.Controller.extend({ name: 'wizardStep9Controller', hosts: [], progress: '0', isStepCompleted: false, isSubmitDisabled: function () { return !this.get('isStepCompleted'); }.property('isStepCompleted'), mockHostData: require('data/mock/step9_hosts'), mockDataPrefix: '/data/wizard/deploy/slave_warning', pollDataCounter: 0, polledData: [], status: function () { if (this.hosts.length && this.hosts.everyProperty('status', 'success')) { return 'success'; } else if (this.hosts.someProperty('status', 'failed')) { return 'failed'; } else if (this.hosts.someProperty('status', 'warning')) { return 'warning'; } else { return 'info'; } }.property('hosts.@each.status'), showRetry: function(){ return this.get('status') == 'failed'; }.property('status'), // called by App.WizardStep9View's didInsertElement and "retry" from router. navigateStep: function () { if (App.testMode) { // this is for repeatedly testing out installs in test mode this.set('content.cluster.status', 'PENDING'); this.set('content.cluster.isCompleted', false); } if (this.get('content.cluster.isCompleted') === false) { if (this.get('content.cluster.status') === 'INSTALL FAILED') { this.loadStep(); this.loadLogData(this.get('content.cluster.requestId')); this.hosts.setEach('status', 'failed'); this.set('progress', '100'); this.set('isStepCompleted', true); //this.set('status', 'failed'); } else if (this.get('content.cluster.status') === 'START FAILED') { this.loadStep(); this.loadLogData(this.get('content.cluster.requestId')); this.hosts.setEach('status', 'info'); this.set('isStepCompleted', false); this.launchStartServices(); } else { this.loadStep(); this.loadLogData(this.get('content.cluster.requestId')); this.startPolling(); } } else { this.loadStep(); this.loadLogData(this.get('content.cluster.requestId')); this.set('isStepCompleted', true); this.set('progress', '100'); } }, clearStep: function () { this.hosts.clear(); this.set('status', 'info'); this.set('progress', '0'); this.set('isStepCompleted', false); this.numPolls = 0; }, loadStep: function () { console.log("TRACE: Loading step9: Install, Start and Test"); this.clearStep(); this.renderHosts(this.loadHosts()); }, loadHosts: function () { var hostInfo = this.get('content.hostsInfo'); var hosts = new Ember.Set(); for (var index in hostInfo) { var obj = Em.Object.create(hostInfo[index]); obj.tasks = []; obj.logTasks = []; hosts.add(obj); console.log("TRACE: host name is: " + hostInfo[index].name); } // return hosts; return hosts.filterProperty('bootStatus', 'REGISTERED'); }, renderHosts: function (hostsInfo) { hostsInfo.forEach(function (_hostInfo) { var hostInfo = App.HostInfo.create({ name: _hostInfo.name, status: _hostInfo.status, tasks: _hostInfo.tasks, logTasks: _hostInfo.logTasks, message: _hostInfo.message, progress: _hostInfo.progress }); console.log('pushing ' + hostInfo.name); this.hosts.pushObject(hostInfo); }, this); }, replacePolledData: function (polledData) { this.polledData.clear(); this.set('polledData', polledData); }, displayMessage: function (task) { var role = App.format.role(task.role); console.log("In display message with task command value: " + task.command); switch (task.command) { case 'INSTALL': switch (task.status) { case 'PENDING': return 'Preparing to install ' + role; case 'QUEUED' : return 'Waiting to install ' + role; case 'IN_PROGRESS': return 'Installing ' + role; case 'COMPLETED' : return 'Successfully installed ' + role; case 'FAILED': return 'Failed to install ' + role; } case 'UNINSTALL': switch (task.status) { case 'PENDING': return 'Preparing to uninstall ' + role; case 'QUEUED' : return 'Waiting to uninstall ' + role; case 'IN_PROGRESS': return 'Uninstalling ' + role; case 'COMPLETED' : return 'Successfully uninstalled ' + role; case 'FAILED': return 'Failed to uninstall ' + role; } case 'START' : switch (task.status) { case 'PENDING': return 'Preparing to start ' + role; case 'QUEUED' : return 'Waiting to start ' + role; case 'IN_PROGRESS': return 'Starting ' + role; case 'COMPLETED' : return role + ' started successfully'; case 'FAILED': return role + ' failed to start'; } case 'STOP' : switch (task.status) { case 'PENDING': return 'Preparing to stop ' + role; case 'QUEUED' : return 'Waiting to stop ' + role; case 'IN_PROGRESS': return 'Stopping ' + role; case 'COMPLETED' : return role + ' stopped successfully'; case 'FAILED': return role + ' failed to stop'; } case 'EXECUTE' : switch (task.status) { case 'PENDING': return 'Preparing to execute ' + role; case 'QUEUED' : return 'Waiting to execute ' + role; case 'IN_PROGRESS': return 'Executing ' + role; case 'COMPLETED' : return role + ' executed successfully'; case 'FAILED': return role + ' failed to execute'; } case 'ABORT' : switch (task.status) { case 'PENDING': return 'Preparing to abort ' + role; case 'QUEUED' : return 'Waiting to abort ' + role; case 'IN_PROGRESS': return 'Aborting ' + role; case 'COMPLETED' : return role + ' aborted successfully'; case 'FAILED': return role + ' failed to abort'; } } }, launchStartServices: function () { var self = this; var clusterName = this.get('content.cluster.name'); var url = App.apiPrefix + '/clusters/' + clusterName + '/services?ServiceInfo/state=INSTALLED'; var data = '{"ServiceInfo": {"state": "STARTED"}}'; var method = 'PUT'; if (App.testMode) { url = this.get('mockDataPrefix') + '/poll_6.json'; method = 'GET'; this.numPolls = 6; } $.ajax({ type: method, url: url, async: false, data: data, dataType: 'text', timeout: App.timeout, success: function (data) { var jsonData = jQuery.parseJSON(data); console.log("TRACE: Step9 -> In success function for the startService call"); console.log("TRACE: Step9 -> value of the url is: " + url); console.log("TRACE: Step9 -> value of the received data is: " + jsonData); var requestId = jsonData.Requests.id; console.log('requestId is: ' + requestId); var clusterStatus = { status: 'INSTALLED', requestId: requestId, isStartError: false, isCompleted: false }; App.router.get(self.get('content.controllerName')).saveClusterStatus(clusterStatus); self.startPolling(); }, error: function () { console.log("ERROR"); var clusterStatus = { status: 'START FAILED', isStartError: true, isCompleted: false }; App.router.get(self.get('content.controllerName')).saveClusterStatus(clusterStatus); }, statusCode: require('data/statusCodes') }); }, onSuccessPerHost: function (actions, contentHost) { if (actions.everyProperty('Tasks.status', 'COMPLETED') && this.get('content.cluster.status') === 'INSTALLED') { contentHost.set('status', 'success'); } }, onWarningPerHost: function (actions, contentHost) { if (actions.someProperty('Tasks.status', 'FAILED') || actions.someProperty('Tasks.status', 'ABORTED') || actions.someProperty('Tasks.status', 'TIMEDOUT')) { console.log('step9: In warning'); contentHost.set('status', 'warning'); this.set('status', 'warning'); } }, onInProgressPerHost: function (tasks, contentHost) { var runningAction = tasks.findProperty('Tasks.status', 'IN_PROGRESS'); if (runningAction === undefined || runningAction === null) { runningAction = tasks.findProperty('Tasks.status', 'QUEUED'); } if (runningAction === undefined || runningAction === null) { runningAction = tasks.findProperty('Tasks.status', 'PENDING'); } if (runningAction !== null && runningAction !== undefined) { contentHost.set('message', this.displayMessage(runningAction.Tasks)); } }, progressPerHost: function (actions, contentHost) { var progress = 0; var actionsPerHost = actions.length; var completedActions = actions.filterProperty('Tasks.status', 'COMPLETED').length + actions.filterProperty('Tasks.status', 'FAILED').length + actions.filterProperty('Tasks.status', 'ABORTED').length + actions.filterProperty('Tasks.status', 'TIMEDOUT').length; if (this.get('content.cluster.status') === 'PENDING') { progress = Math.floor(((completedActions / actionsPerHost) * 100) / 3); } else if (this.get('content.cluster.status') === 'INSTALLED') { progress = 34 + Math.floor(((completedActions / actionsPerHost) * 100 * 2) / 3); } console.log('INFO: progressPerHost is: ' + progress); contentHost.set('progress', progress.toString()); return progress; }, isSuccess: function (polledData) { return polledData.everyProperty('Tasks.status', 'COMPLETED'); }, // for DATANODE, JOBTRACKER, HBASE_REGIONSERVER, and GANGLIA_MONITOR, if more than 50% fail, then it's a fatal error; // otherwise, it's only a warning and installation/start can continue getSuccessFactor: function (role) { return ['DATANODE','JOBTRACKER','HBASE_REGIONSERVER','GANGLIA_MONITOR'].contains(role) ? 50 : 100; }, isStepFailed: function (polledData) { var self = this; var result = false; polledData.forEach(function (_polledData) { var successFactor = this.getSuccessFactor(_polledData.Tasks.role); console.log("Step9: isStepFailed sf value: " + successFactor); var actionsPerRole = polledData.filterProperty('Tasks.role', _polledData.Tasks.role); var actionsFailed = actionsPerRole.filterProperty('Tasks.status', 'FAILED'); var actionsAborted = actionsPerRole.filterProperty('Tasks.status', 'ABORTED'); var actionsTimedOut = actionsPerRole.filterProperty('Tasks.status', 'TIMEDOUT'); if ((((actionsFailed.length + actionsAborted.length + actionsTimedOut.length) / actionsPerRole.length) * 100) > (100 - successFactor)) { console.log('TRACE: Entering success factor and result is failed'); result = true; } }, this); return result; }, getFailedHostsForFailedRoles: function (polledData) { var hostArr = new Ember.Set(); polledData.forEach(function (_polledData) { var successFactor = this.getSuccessFactor(_polledData.Tasks.role); var actionsPerRole = polledData.filterProperty('Tasks.role', _polledData.Tasks.role); var actionsFailed = actionsPerRole.filterProperty('Tasks.status', 'FAILED'); var actionsAborted = actionsPerRole.filterProperty('Tasks.status', 'ABORTED'); var actionsTimedOut = actionsPerRole.filterProperty('Tasks.status', 'TIMEDOUT'); if ((((actionsFailed.length + actionsAborted.length + actionsTimedOut.length) / actionsPerRole.length) * 100) > (100 - successFactor)) { actionsFailed.forEach(function (_actionFailed) { hostArr.add(_actionFailed.Tasks.host_name); }); actionsAborted.forEach(function (_actionFailed) { hostArr.add(_actionFailed.Tasks.host_name); }); actionsTimedOut.forEach(function (_actionFailed) { hostArr.add(_actionFailed.Tasks.host_name); }); } }, this); return hostArr; }, setHostsStatus: function (hostNames, status) { hostNames.forEach(function (_hostName) { var host = this.hosts.findProperty('name', _hostName); if (host) { host.set('status', status) .set('progress', '100'); } }, this); }, // polling from ui stops only when no action has 'PENDING', 'QUEUED' or 'IN_PROGRESS' status finishState: function (polledData) { var clusterStatus = {}; var requestId = this.get('content.cluster.requestId'); if (this.get('content.cluster.status') === 'INSTALLED') { if (!polledData.someProperty('Tasks.status', 'PENDING') && !polledData.someProperty('Tasks.status', 'QUEUED') && !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) { this.set('progress', '100'); clusterStatus = { status: 'INSTALLED', requestId: requestId, isCompleted: true } if (this.isSuccess(polledData)) { clusterStatus.status = 'STARTED'; var serviceStartTime = new Date().getTime(); var timeToStart = ((parseInt(serviceStartTime) - parseInt(this.get('content.cluster.installStartTime'))) / 60000).toFixed(2); clusterStatus.installTime = timeToStart; this.set('status', 'success'); } else { if (this.isStepFailed(polledData)) { clusterStatus.status = 'START FAILED'; // 'START FAILED' implies to step10 that installation was successful but start failed this.set('status', 'failed'); this.setHostsStatus(this.getFailedHostsForFailedRoles(polledData), 'failed'); } } App.router.get(this.get('content.controllerName')).saveClusterStatus(clusterStatus); this.set('isStepCompleted', true); this.setTasksPerHost(); App.router.get(this.get('content.controllerName')).saveInstalledHosts(this); return true; } } else if (this.get('content.cluster.status') === 'PENDING') { if (!polledData.someProperty('Tasks.status', 'PENDING') && !polledData.someProperty('Tasks.status', 'QUEUED') && !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) { clusterStatus = { status: 'PENDING', requestId: requestId, isCompleted: false } if (this.isStepFailed(polledData)) { console.log("In installation failure"); clusterStatus.status = 'INSTALL FAILED'; this.set('progress', '100'); this.set('status', 'failed'); this.setHostsStatus(this.getFailedHostsForFailedRoles(polledData), 'failed'); App.router.get(this.get('content.controllerName')).saveClusterStatus(clusterStatus); this.set('isStepCompleted', true); } else { clusterStatus.status = 'INSTALLED'; this.set('progress', '34'); this.launchStartServices(); } this.setTasksPerHost(); App.router.get(this.get('content.controllerName')).saveInstalledHosts(this); return true; } } return false; }, setTasksPerHost: function () { var tasksData = this.get('polledData'); this.get('hosts').forEach(function (_host) { var tasksPerHost = tasksData.filterProperty('Tasks.host_name', _host.name); // retrieved from polled Data if (tasksPerHost.length === 0) { //alert('For testing with mockData follow the sequence: hit referesh,"mockData btn", "pollData btn", again "pollData btn"'); //exit(); } if (tasksPerHost !== null && tasksPerHost !== undefined && tasksPerHost.length !== 0) { tasksPerHost.forEach(function (_taskPerHost) { console.log('In step9 _taskPerHost function.'); //if (_taskPerHost.Tasks.status !== 'PENDING' && _taskPerHost.Tasks.status !== 'QUEUED' && _taskPerHost.Tasks.status !== 'IN_PROGRESS') { _host.tasks.pushObject(_taskPerHost); //} }, this); } }, this); }, // This is done at HostRole level. setLogTasksStatePerHost: function (tasksPerHost, host) { console.log('In step9 setTasksStatePerHost function.'); tasksPerHost.forEach(function (_task) { console.log('In step9 _taskPerHost function.'); if (_task.Tasks.status !== 'PENDING' && _task.Tasks.status !== 'QUEUED') { var task = host.logTasks.findProperty('Tasks.id', _task.Tasks.id); if (task) { host.logTasks.removeObject(task); } host.logTasks.pushObject(_task); } }, this); }, parseHostInfo: function (polledData) { console.log('TRACE: Entering host info function'); var self = this; var totalProgress = 0; /* if (this.get('content.cluster.status') === 'INSTALLED') { totalProgress = 34; } else { totalProgress = 0; } */ var tasksData = polledData.tasks; console.log("The value of tasksData is: ", tasksData); if (!tasksData) { console.log("Step9: ERROR: NO tasks available to process"); } this.replacePolledData(tasksData); this.hosts.forEach(function (_host) { var actionsPerHost = tasksData.filterProperty('Tasks.host_name', _host.name); // retrieved from polled Data if (actionsPerHost.length === 0) { console.log("Error: No task is hosted on the host"); } if (actionsPerHost !== null && actionsPerHost !== undefined && actionsPerHost.length !== 0) { this.setLogTasksStatePerHost(actionsPerHost, _host); this.onSuccessPerHost(actionsPerHost, _host); // every action should be a success this.onWarningPerHost(actionsPerHost, _host); // any action should be a failure this.onInProgressPerHost(actionsPerHost, _host); // current running action for a host totalProgress += self.progressPerHost(actionsPerHost, _host); } }, this); totalProgress = Math.floor(totalProgress / this.hosts.length); this.set('progress', totalProgress.toString()); console.log("INFO: right now the progress is: " + this.get('progress')); return this.finishState(tasksData); }, startPolling: function () { this.set('isSubmitDisabled', true); this.doPolling(); }, numPolls: 0, getUrl: function (requestId) { var clusterName = this.get('content.cluster.name'); var requestId = requestId || this.get('content.cluster.requestId'); var url = App.apiPrefix + '/clusters/' + clusterName + '/requests/' + requestId + '?fields=tasks/*'; console.log("URL for step9 is: " + url); return url; }, POLL_INTERVAL: 4000, loadLogData:function(requestId){ var url = this.getUrl(requestId); var requestsId = App.db.getCluster().oldRequestsId; if (App.testMode) { this.POLL_INTERVAL = 1; this.numPolls++; } requestsId.forEach(function(requestId) { url = this.getUrl(requestId); if (App.testMode) { this.POLL_INTERVAL = 1; if (requestId == 1) { url = this.get('mockDataPrefix') + '/poll_' + this.numPolls + '.json'; // url = this.get('mockDataPrefix') + '/poll_5_failed.json'; } else { url = this.get('mockDataPrefix') + '/poll_9.json'; } } this.getLogsByRequest(url, false); }, this); }, getLogsByRequest: function(url, polling){ var self = this; $.ajax({ type: 'GET', url: url, async: true, timeout: App.timeout, dataType: 'text', success: function (data) { console.log("TRACE: In success function for the GET logs data"); console.log("TRACE: STep9 -> The value is: ", jQuery.parseJSON(data)); var result = self.parseHostInfo(jQuery.parseJSON(data)); if(!polling){ return; } if (result !== true) { window.setTimeout(function () { self.doPolling(); }, self.POLL_INTERVAL); } else { self.stopPolling(); } }, error: function (request, ajaxOptions, error) { console.log("TRACE: STep9 -> In error function for the GET logs data"); console.log("TRACE: STep9 -> value of the url is: " + url); console.log("TRACE: STep9 -> error code status is: " + request.status); self.stopPolling(); }, statusCode: require('data/statusCodes') }); }, doPolling: function () { var url = this.getUrl(); if (App.testMode) { this.numPolls++; url = this.get('mockDataPrefix') + '/poll_' + this.get('numPolls') + '.json'; } this.getLogsByRequest(url, true); }, stopPolling: function () { //TODO: uncomment following line after the hook up with the API call // this.set('isStepCompleted',true); }, submit: function () { if (!this.get('isSubmitDisabled')) { App.router.send('next'); } }, back: function () { if (!this.get('isSubmitDisabled')) { App.router.send('back'); } }, mockBtn: function () { this.set('isSubmitDisabled', false); this.hosts.clear(); var hostInfo = this.mockHostData; this.renderHosts(hostInfo); }, pollBtn: function () { this.set('isSubmitDisabled', false); var data1 = require('data/mock/step9PolledData/pollData_1'); var data2 = require('data/mock/step9PolledData/pollData_2'); var data3 = require('data/mock/step9PolledData/pollData_3'); var data4 = require('data/mock/step9PolledData/pollData_4'); var data5 = require('data/mock/step9PolledData/pollData_5'); var data6 = require('data/mock/step9PolledData/pollData_6'); var data7 = require('data/mock/step9PolledData/pollData_7'); var data8 = require('data/mock/step9PolledData/pollData_8'); var data9 = require('data/mock/step9PolledData/pollData_9'); console.log("TRACE: In pollBtn function data1"); var counter = parseInt(this.get('pollDataCounter')) + 1; this.set('pollDataCounter', counter.toString()); switch (this.get('pollDataCounter')) { case '1': this.parseHostInfo(data1); break; case '2': this.parseHostInfo(data2); break; case '3': this.parseHostInfo(data3); break; case '4': this.parseHostInfo(data4); break; case '5': this.parseHostInfo(data5); break; case '6': this.set('content.cluster.status', 'INSTALLED'); this.parseHostInfo(data6); break; case '7': this.parseHostInfo(data7); break; case '8': this.parseHostInfo(data8); break; case '9': this.parseHostInfo(data9); break; default: break; } } });