blob: 90c6901363f9a19d7be4dbbbcc6ed7a0ddaa676b [file] [log] [blame]
/**
* 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;
}
}
});