/** * 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'); var lazyloading = require('utils/lazy_loading'); var numberUtils = require('utils/number_utils'); App.WizardStep3Controller = Em.Controller.extend({ name: 'wizardStep3Controller', hosts: [], content: [], bootHosts: [], registeredHosts: [], hostCheckWarnings: [], repoCategoryWarnings: [], diskCategoryWarnings: [], thpCategoryWarnings: [], jdkCategoryWarnings: null, jdkRequestIndex: null, registrationStartedAt: null, requestId: 0, /** * Timeout for registration * Based on installOptions.manualInstall * @type {number} */ registrationTimeoutSecs: function () { return this.get('content.installOptions.manualInstall') ? 15 : 120; }.property('content.installOptions.manualInstall'), /** * Bootstrap calls are stopped * @type {bool} */ stopBootstrap: false, /** * is Submit button disabled * @type {bool} */ isSubmitDisabled: true, /** * is Retry button disabled * @type {bool} */ isRetryDisabled: true, /** * @type {bool} */ isLoaded: false, /** * Polls count * @type {number} */ numPolls: 0, /** * Is hosts registration in progress * @type {bool} */ isRegistrationInProgress: true, /** * Are some registered hosts which are not added by user * @type {bool} */ hasMoreRegisteredHosts: false, /** * List of installed hostnames * @type {string[]} */ hostsInCluster: function () { var installedHostsName = []; var hosts = this.get('content.hosts'); for (var hostName in hosts) { if (hosts[hostName].isInstalled) { installedHostsName.push(hostName); } } return installedHostsName; }.property('content.hosts'), /** * All hosts warnings * @type {object[]} */ warnings: [], /** * Warnings grouped by host * @type {Ember.Enumerable} */ warningsByHost: [], /** * Timeout for "warning"-requests * @type {number} */ warningsTimeInterval: 60000, /** * Are hosts warnings loaded * @type {bool} */ isWarningsLoaded: function () { return this.get('isJDKWarningsLoaded') && this.get('isHostsWarningsLoaded'); }.property('isJDKWarningsLoaded', 'isHostsWarningsLoaded'), /** * Check are hosts have any warnings * @type {bool} */ isHostHaveWarnings: function () { return this.get('warnings.length') > 0; }.property('warnings'), /** * Should warnings-box be visible * @type {bool} */ isWarningsBoxVisible: function () { return (App.get('testMode')) ? true : !this.get('isRegistrationInProgress'); }.property('isRegistrationInProgress'), /** * Progress value for "update hosts status" process * @type {number} */ checksUpdateProgress: 0, /** * * @type {object} */ checksUpdateStatus: null, /** * * @method navigateStep */ navigateStep: function () { if (this.get('isLoaded')) { if (!this.get('content.installOptions.manualInstall')) { if (!this.get('wizardController').getDBProperty('bootStatus')) { this.startBootstrap(); } } else { this.set('bootHosts', this.get('hosts')); if (App.get('testMode')) { this.startHostcheck(); this.get('bootHosts').setEach('cpu', '2'); this.get('bootHosts').setEach('memory', '2000000'); this.set('isSubmitDisabled', false); } else { this.set('registrationStartedAt', null); this.startRegistration(); } } } }.observes('isLoaded'), /** * Clear controller data * @method clearStep */ clearStep: function () { this.set('stopBootstrap', false); this.set('hosts', []); this.get('bootHosts').clear(); this.get('wizardController').setDBProperty('bootStatus', false); this.set('isHostsWarningsLoaded', false); this.set('isJDKWarningsLoaded', false); this.set('registrationStartedAt', null); this.set('isLoaded', false); this.set('isSubmitDisabled', true); this.set('isRetryDisabled', true); }, /** * Make basic init steps * @method loadStep */ loadStep: function () { console.log("TRACE: Loading step3: Confirm Hosts"); this.disablePreviousSteps(); this.clearStep(); App.router.get('clusterController').loadAmbariProperties(); this.loadHosts(); }, /** * Loads the hostinfo from localStorage on the insertion of view. It's being called from view * @method loadHosts */ loadHosts: function () { var hostsInfo = this.get('content.hosts'); var hosts = []; var bootStatus = (this.get('content.installOptions.manualInstall')) ? 'DONE' : 'PENDING'; if (App.get('testMode')) { bootStatus = 'REGISTERED'; } for (var index in hostsInfo) { if (hostsInfo.hasOwnProperty(index) && !hostsInfo[index].isInstalled) { hosts.pushObject(App.HostInfo.create({ name: hostsInfo[index].name, bootStatus: bootStatus, isChecked: false })); } } this.set('hosts', hosts); this.set('isLoaded', true); }, /** * Parses and updates the content based on bootstrap API response. * @return {bool} true if polling should continue (some hosts are in "RUNNING" state); false otherwise * @method parseHostInfo */ parseHostInfo: function (hostsStatusFromServer) { hostsStatusFromServer.forEach(function (_hostStatus) { var host = this.get('bootHosts').findProperty('name', _hostStatus.hostName); // check if hostname extracted from REST API data matches any hostname in content // also, make sure that bootStatus modified by isHostsRegistered call does not get overwritten // since these calls are being made in parallel if (host && !['REGISTERED', 'REGISTERING'].contains(host.get('bootStatus'))) { host.set('bootStatus', _hostStatus.status); host.set('bootLog', _hostStatus.log); } }, this); // if the data rendered by REST API has hosts in "RUNNING" state, polling will continue return this.get('bootHosts').length != 0 && this.get('bootHosts').someProperty('bootStatus', 'RUNNING'); }, /** * Remove list of hosts * @param {Ember.Enumerable} hosts * @return {App.ModalPopup} * @method removeHosts */ removeHosts: function (hosts) { var self = this; return App.showConfirmationPopup(function () { App.router.send('removeHosts', hosts); self.hosts.removeObjects(hosts); if (!self.hosts.length) { self.set('isSubmitDisabled', true); } }, Em.I18n.t('installer.step3.hosts.remove.popup.body')); }, /** * Removes a single element on the trash icon click. Called from View * @param {object} hostInfo * @method removeHost */ removeHost: function (hostInfo) { this.removeHosts([hostInfo]); }, /** * Remove selected hosts (click-handler) * @return App.ModalPopup * @method removeSelectedHosts */ removeSelectedHosts: function () { var selectedHosts = this.get('hosts').filterProperty('isChecked', true); selectedHosts.forEach(function (_hostInfo) { console.log('Removing: ' + _hostInfo.name); }); return this.removeHosts(selectedHosts); }, /** * Show popup with the list of hosts which are selected * @return App.ModalPopup * @method selectedHostsPopup */ selectedHostsPopup: function () { var selectedHosts = this.get('hosts').filterProperty('isChecked').mapProperty('name'); return App.ModalPopup.show({ header: Em.I18n.t('installer.step3.selectedHosts.popup.header'), secondary: null, bodyClass: Em.View.extend({ templateName: require('templates/common/items_list_popup'), items: selectedHosts, insertedItems: [], didInsertElement: function () { lazyloading.run({ destination: this.get('insertedItems'), source: this.get('items'), context: this, initSize: 100, chunkSize: 500, delay: 100 }); } }) }); }, /** * Retry one host {click-handler} * @param {object} hostInfo * @method retryHost */ retryHost: function (hostInfo) { this.retryHosts([hostInfo]); }, /** * Retry list of hosts * @param {object[]} hosts * @method retryHosts */ retryHosts: function (hosts) { var self = this; var bootStrapData = JSON.stringify({ 'verbose': true, 'sshKey': this.get('content.installOptions.sshKey'), 'hosts': hosts.mapProperty('name'), 'user': this.get('content.installOptions.sshUser'), 'userRunAs': this.get('content.installOptions.agentUser')} ); this.set('numPolls', 0); this.set('registrationStartedAt', null); if (this.get('content.installOptions.manualInstall')) { this.get('bootHosts').setEach('bootStatus', 'DONE'); this.startRegistration(); } else { App.router.get(this.get('content.controllerName')).launchBootstrap(bootStrapData, function (requestId) { self.set('content.installOptions.bootRequestId', requestId); self.doBootstrap(); }); } }, /** * Retry selected hosts (click-handler) * @method retrySelectedHosts */ retrySelectedHosts: function () { if (!this.get('isRetryDisabled')) { this.set('isRetryDisabled', true); var selectedHosts = this.get('bootHosts').filterProperty('bootStatus', 'FAILED'); selectedHosts.forEach(function (_host) { _host.set('bootStatus', 'RUNNING'); _host.set('bootLog', 'Retrying ...'); }, this); this.retryHosts(selectedHosts); } }, /** * Init bootstrap settings and start it * @method startBootstrap */ startBootstrap: function () { //this.set('isSubmitDisabled', true); //TODO: uncomment after actual hookup this.set('numPolls', 0); this.set('registrationStartedAt', null); this.set('bootHosts', this.get('hosts')); this.doBootstrap(); }, /** * Update isRegistrationInProgress once * @method setRegistrationInProgressOnce */ setRegistrationInProgressOnce: function () { Em.run.once(this, 'setRegistrationInProgress'); }.observes('bootHosts.@each.bootStatus'), /** * Set isRegistrationInProgress value based on each host boot status * @method setRegistrationInProgress */ setRegistrationInProgress: function () { var bootHosts = this.get('bootHosts'); //if hosts aren't loaded yet then registration should be in progress var result = (bootHosts.length === 0 && !this.get('isLoaded')); for (var i = 0, l = bootHosts.length; i < l; i++) { if (bootHosts[i].get('bootStatus') !== 'REGISTERED' && bootHosts[i].get('bootStatus') !== 'FAILED') { result = true; break; } } this.set('isRegistrationInProgress', result); }, /** * Disable wizard's previous steps (while registering) * @method disablePreviousSteps */ disablePreviousSteps: function () { App.router.get('installerController.isStepDisabled').filter(function (step) { return step.step >= 0 && step.step <= 2; }).setEach('value', this.get('isRegistrationInProgress')); if (this.get('isRegistrationInProgress')) { this.set('isSubmitDisabled', true); } }.observes('isRegistrationInProgress'), /** * Do bootstrap calls * @method doBootstrap * @return {$.ajax|null} */ doBootstrap: function () { if (this.get('stopBootstrap')) { return null; } this.incrementProperty('numPolls'); return App.ajax.send({ name: 'wizard.step3.bootstrap', sender: this, data: { bootRequestId: this.get('content.installOptions.bootRequestId'), numPolls: this.get('numPolls') }, success: 'doBootstrapSuccessCallback' }). retry({ times: App.maxRetries, timeout: App.timeout }). then( null, function () { App.showReloadPopup(); console.log('Bootstrap failed'); } ); }, /** * Success-callback for each boostrap request * @param {object} data * @method doBootstrapSuccessCallback */ doBootstrapSuccessCallback: function (data) { var self = this; var pollingInterval = 3000; if (Em.isNone(data.hostsStatus)) { console.log('Invalid response, setting timeout'); window.setTimeout(function () { self.doBootstrap() }, pollingInterval); } else { // in case of bootstrapping just one host, the server returns an object rather than an array, so // force into an array if (!(data.hostsStatus instanceof Array)) { data.hostsStatus = [ data.hostsStatus ]; } console.log("TRACE: In success function for the GET bootstrap call"); var keepPolling = this.parseHostInfo(data.hostsStatus); // Single host : if the only hostname is invalid (data.status == 'ERROR') // Multiple hosts : if one or more hostnames are invalid // following check will mark the bootStatus as 'FAILED' for the invalid hostname if (data.status == 'ERROR' || data.hostsStatus.length != this.get('bootHosts').length) { var hosts = this.get('bootHosts'); for (var i = 0; i < hosts.length; i++) { var isValidHost = data.hostsStatus.someProperty('hostName', hosts[i].get('name')); if (hosts[i].get('bootStatus') !== 'REGISTERED') { if (!isValidHost) { hosts[i].set('bootStatus', 'FAILED'); hosts[i].set('bootLog', Em.I18n.t('installer.step3.hosts.bootLog.failed')); } } } } if (data.status == 'ERROR' || data.hostsStatus.someProperty('status', 'DONE') || data.hostsStatus.someProperty('status', 'FAILED')) { // kicking off registration polls after at least one host has succeeded this.startRegistration(); } if (keepPolling) { window.setTimeout(function () { self.doBootstrap() }, pollingInterval); } } }, /** * Start hosts registration * @method startRegistration */ startRegistration: function () { if (Em.isNone(this.get('registrationStartedAt'))) { this.set('registrationStartedAt', App.dateTime()); console.log('registration started at ' + this.get('registrationStartedAt')); this.isHostsRegistered(); } }, /** * Do requests to check if hosts are already registered * @return {$.ajax|null} * @method isHostsRegistered */ isHostsRegistered: function () { if (this.get('stopBootstrap')) { return null; } return App.ajax.send({ name: 'wizard.step3.is_hosts_registered', sender: this, success: 'isHostsRegisteredSuccessCallback' }). retry({ times: App.maxRetries, timeout: App.timeout }). then( null, function () { App.showReloadPopup(); console.log('Error: Getting registered host information from the server'); } ); }, /** * Success-callback for registered hosts request * @param {object} data * @method isHostsRegisteredSuccessCallback */ isHostsRegisteredSuccessCallback: function (data) { console.log('registration attempt...'); var hosts = this.get('bootHosts'); var jsonData = data; if (!jsonData) { console.warn("Error: jsonData is null"); return; } // keep polling until all hosts have registered/failed, or registrationTimeout seconds after the last host finished bootstrapping var stopPolling = true; hosts.forEach(function (_host, index) { // Change name of first host for test mode. if (App.get('testMode')) { if (index == 0) { _host.set('name', 'localhost.localdomain'); } } // actions to take depending on the host's current bootStatus // RUNNING - bootstrap is running; leave it alone // DONE - bootstrap is done; transition to REGISTERING // REGISTERING - bootstrap is done but has not registered; transition to REGISTERED if host found in polling API result // REGISTERED - bootstrap and registration is done; leave it alone // FAILED - either bootstrap or registration failed; leave it alone switch (_host.get('bootStatus')) { case 'DONE': _host.set('bootStatus', 'REGISTERING'); _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + Em.I18n.t('installer.step3.hosts.bootLog.registering')); // update registration timestamp so that the timeout is computed from the last host that finished bootstrapping this.set('registrationStartedAt', App.dateTime()); stopPolling = false; break; case 'REGISTERING': if (jsonData.items.someProperty('Hosts.host_name', _host.name)) { _host.set('bootStatus', 'REGISTERED'); _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + Em.I18n.t('installer.step3.hosts.bootLog.registering')); } else { stopPolling = false; } break; case 'RUNNING': stopPolling = false; break; case 'REGISTERED': case 'FAILED': default: break; } }, this); if (stopPolling) { this.startHostcheck(); } else { if (hosts.someProperty('bootStatus', 'RUNNING') || App.dateTime() - this.get('registrationStartedAt') < this.get('registrationTimeoutSecs') * 1000) { // we want to keep polling for registration status if any of the hosts are still bootstrapping (so we check for RUNNING). var self = this; window.setTimeout(function () { self.isHostsRegistered(); }, 3000); } else { // registration timed out. mark all REGISTERING hosts to FAILED console.log('registration timed out'); hosts.filterProperty('bootStatus', 'REGISTERING').forEach(function (_host) { _host.set('bootStatus', 'FAILED'); _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + Em.I18n.t('installer.step3.hosts.bootLog.failed')); }); this.startHostcheck(); } } }, /** * Do request for all registered hosts * @return {$.ajax} * @method getAllRegisteredHosts */ getAllRegisteredHosts: function () { return App.ajax.send({ name: 'wizard.step3.is_hosts_registered', sender: this, success: 'getAllRegisteredHostsCallback' }); }.observes('bootHosts'), /** * Success-callback for all registered hosts request * @param {object} hosts * @method getAllRegisteredHostsCallback */ getAllRegisteredHostsCallback: function (hosts) { var registeredHosts = []; var hostsInCluster = this.get('hostsInCluster'); var addedHosts = this.get('bootHosts').getEach('name'); hosts.items.forEach(function (host) { if (!hostsInCluster.contains(host.Hosts.host_name) && !addedHosts.contains(host.Hosts.host_name)) { registeredHosts.push(host.Hosts.host_name); } }); if (registeredHosts.length) { this.set('hasMoreRegisteredHosts', true); this.set('registeredHosts', registeredHosts); } else { this.set('hasMoreRegisteredHosts', false); this.set('registeredHosts', ''); } }, /** * Show popup with regitration error-message * @param {string} header * @param {string} message * @return {App.ModalPopup} * @method registerErrPopup */ registerErrPopup: function (header, message) { return App.ModalPopup.show({ header: header, secondary: false, bodyClass: Em.View.extend({ template: Em.Handlebars.compile('

{{view.message}}

'), message: message }) }); }, /** * Get JDK name from server to determine if user had setup a customized JDK path when doing 'ambari-server setup'. * The Ambari properties are different from default ambari-server setup, property 'jdk.name' will be missing if a customized jdk path is applied. * @return {$.ajax} * @method getJDKName */ getJDKName: function () { return App.ajax.send({ name: 'ambari.service.load_jdk_name', sender: this, success: 'getJDKNameSuccessCallback' }); }, /** * Success callback for JDK name, property 'jdk.name' will be missing if a customized jdk path is applied * @param {object} data * @method getJDKNameSuccessCallback */ getJDKNameSuccessCallback: function (data) { this.set('needJDKCheckOnHosts', !data.RootServiceComponents.properties["jdk.name"]); this.set('jdkLocation', Em.get(data, "RootServiceComponents.properties.jdk_location")); this.set('javaHome', data.RootServiceComponents.properties["java.home"]); }, doCheckJDK: function () { var hostsNames = this.get('bootHosts').getEach('name').join(","); var javaHome = this.get('javaHome'); var jdkLocation = this.get('jdkLocation'); App.ajax.send({ name: 'wizard.step3.jdk_check', sender: this, data: { host_names: hostsNames, java_home: javaHome, jdk_location: jdkLocation }, success: 'doCheckJDKsuccessCallback', error: 'doCheckJDKerrorCallback' }); }, doCheckJDKsuccessCallback: function (data) { if(data){ this.set('jdkRequestIndex', data.href.split('/')[data.href.split('/').length - 1]); } if (this.get('jdkCategoryWarnings') == null) { // get jdk check results for all hosts App.ajax.send({ name: 'wizard.step3.jdk_check.get_results', sender: this, data: { requestIndex: this.get('jdkRequestIndex') }, success: 'parseJDKCheckResults' }) } else { this.set('isJDKWarningsLoaded', true); } }, doCheckJDKerrorCallback: function () { console.log('INFO: Doing JDK check for host failed'); this.set('isJDKWarningsLoaded', true); }, parseJDKCheckResults: function (data) { var jdkWarnings = [], hostsJDKContext = [], hostsJDKNames = []; // check if the request ended if (data.Requests.end_time > 0 && data.tasks) { data.tasks.forEach( function(task) { // generate warning context if (Em.get(task, "Tasks.structured_out.java_home_check.exit_code") == 1){ var jdkContext = Em.I18n.t('installer.step3.hostWarningsPopup.jdk.context').format(task.Tasks.host_name); hostsJDKContext.push(jdkContext); hostsJDKNames.push(task.Tasks.host_name); } }); if (hostsJDKContext.length > 0) { // java jdk warning exist var invalidJavaHome = this.get('javaHome'); jdkWarnings.push({ name: Em.I18n.t('installer.step3.hostWarningsPopup.jdk.name').format(invalidJavaHome), hosts: hostsJDKContext, hostsNames: hostsJDKNames, category: 'jdk', onSingleHost: false }); } this.set('jdkCategoryWarnings', jdkWarnings); } else { // still doing JDK check, data not ready to be parsed this.set('jdkCategoryWarnings', null); } this.doCheckJDKsuccessCallback(); }, /** * Check JDK issues on registered hosts. */ checkHostJDK: function () { this.set('isJDKWarningsLoaded', false); this.set('jdkCategoryWarnings', null); var self = this; this.getJDKName().done( function() { if (self.get('needJDKCheckOnHosts')) { // need to do JDK check on each host self.doCheckJDK(); } else { // no customized JDK path, so no need to check jdk self.set('jdkCategoryWarnings', []); self.set('isJDKWarningsLoaded', true); } }); }, /** * Get disk info and cpu count of booted hosts from server * @return {$.ajax} * @method getHostInfo */ getHostInfo: function () { this.set('isHostsWarningsLoaded', false); // begin JDK check for each host return App.ajax.send({ name: 'wizard.step3.host_info', sender: this, success: 'getHostInfoSuccessCallback', error: 'getHostInfoErrorCallback' }); }, startHostcheck: function() { this.set('isWarningsLoaded', false); this.getHostNameResolution(); this.checkHostJDK(); }, getHostNameResolution: function () { var hosts = this.get('bootHosts').getEach('name').join(","); var jdk_location = App.router.get('clusterController.ambariProperties.jdk_location'); var RequestInfo = { "action": "check_host", "context": "Check host", "parameters": { "check_execute_list": "host_resolution_check", "jdk_location" : jdk_location, "threshold": "20", "hosts": hosts } }; var resource_filters = { "hosts": hosts }; if (App.get('testMode')) { this.getHostNameResolutionSuccess(); } else { return App.ajax.send({ name: 'preinstalled.checks', sender: this, data: { RequestInfo: RequestInfo, resource_filters: resource_filters }, success: 'getHostNameResolutionSuccess', error: 'getHostNameResolutionError' }); } }, getHostNameResolutionSuccess: function(response) { if (!App.get('testMode')) { this.set("requestId", response.Requests.id); } this.getHostCheckTasks(); }, getHostNameResolutionError: function() { this.getHostInfo(); }, /** * send ajax request to get all tasks * @method getHostCheckTasks */ getHostCheckTasks: function () { var self = this; var requestId = this.get("requestId"); var checker = setTimeout(function () { if (self.get('stopChecking') == true) { clearInterval(checker); self.getHostInfo(); } else { App.ajax.send({ name: 'preinstalled.checks.tasks', sender: self, data: { requestId: requestId }, success: 'getHostCheckTasksSuccess', error: 'getHostCheckTasksError' }); } }, 1000); }, /** * add warnings to host warning popup if needed * @param data {Object} - json * @method getHostCheckTasksSuccess */ getHostCheckTasksSuccess: function (data) { console.log('checking attempt...'); if (!data) { console.warn("Error: jsonData is null"); return; } this.set('stopChecking', true); data.tasks.forEach(function (task) { var name = Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.error'); var hostInfo = this.get("hostCheckWarnings").findProperty('name', name); if (task.Tasks.status == "FAILED" || task.Tasks.status == "COMPLETED" || task.Tasks.status == "TIMEDOUT") { if (task.Tasks.status == "COMPLETED") { if (Em.get(task, "Tasks.structured_out.host_resolution_check.failed_count") == 0) { return; } } var targetHostName = Em.get(task, "Tasks.host_name"); var relatedHostNames = Em.get(task, "Tasks.structured_out.host_resolution_check.failures") ? Em.get(task, "Tasks.structured_out.host_resolution_check.failures").mapProperty('host') : []; var contextMessage = Em.I18n.t('installer.step3.hostWarningsPopup.resolution.validation.context').format(targetHostName, relatedHostNames.join(', ')); if (!hostInfo) { hostInfo = { name: name, hosts: [contextMessage], hostsNames: [targetHostName], onSingleHost: true }; this.get("hostCheckWarnings").push(hostInfo); } else { if (!hostInfo.hostsNames.contains(targetHostName)) { hostInfo.hosts.push(contextMessage); hostInfo.hostsNames.push(targetHostName); } } } else { this.set('stopChecking', false); } }, this); this.getHostCheckTasks(); }, stopChecking: false, /** * @method getHostCheckTasksError */ getHostCheckTasksError: function() { console.warn("failed to cheek hostName resolution"); this.set('stopChecking', true); }, /** * Success-callback for hosts info request * @param {object} jsonData * @method getHostInfoSuccessCallback */ getHostInfoSuccessCallback: function (jsonData) { var hosts = this.get('bootHosts'), self = this, repoWarnings = [], hostsRepoNames = [], hostsContext = [], diskWarnings = [], hostsDiskContext = [], hostsDiskNames = [], thpWarnings = [], thpContext = [], thpHostsNames = []; // parse host checks warning this.parseWarnings(jsonData); hosts.forEach(function (_host) { var host = (App.get('testMode')) ? jsonData.items[0] : jsonData.items.findProperty('Hosts.host_name', _host.name); if (App.get('skipBootstrap')) { self._setHostDataWithSkipBootstrap(_host); } else { if (host) { self._setHostDataFromLoadedHostInfo(_host, host); var host_name = Em.get(host, 'Hosts.host_name'); var context = self.checkHostOSType(host.Hosts.os_type, host_name); if (context) { hostsContext.push(context); hostsRepoNames.push(host_name); } var diskContext = self.checkHostDiskSpace(host_name, host.Hosts.disk_info); if (diskContext) { hostsDiskContext.push(diskContext); hostsDiskNames.push(host_name); } // "Transparent Huge Pages" check context = self.checkTHP(host_name, Em.get(host, 'Hosts.last_agent_env.transparentHugePage')); if (context) { thpContext.push(context); thpHostsNames.push(host_name); } } } }); if (hostsContext.length > 0) { // repository warning exist repoWarnings.push({ name: Em.I18n.t('installer.step3.hostWarningsPopup.repositories.name'), hosts: hostsContext, hostsNames: hostsRepoNames, category: 'repositories', onSingleHost: false }); } if (hostsDiskContext.length > 0) { // disk space warning exist diskWarnings.push({ name: Em.I18n.t('installer.step3.hostWarningsPopup.disk.name'), hosts: hostsDiskContext, hostsNames: hostsDiskNames, category: 'disk', onSingleHost: false }); } if (thpContext.length > 0) { // THP warning existed thpWarnings.push({ name: Em.I18n.t('installer.step3.hostWarningsPopup.thp.name'), hosts: thpContext, hostsNames: thpHostsNames, category: 'thp', onSingleHost: false }); } this.set('repoCategoryWarnings', repoWarnings); this.set('diskCategoryWarnings', diskWarnings); this.set('thpCategoryWarnings', thpWarnings); this.stopRegistration(); }, /** * Set metrics to host object * Used when App.skipBootstrap is true * @param {Ember.Object} host * @returns {object} * @private * @methos _setHostDataWithSkipBootstrap */ _setHostDataWithSkipBootstrap: function(host) { host.set('cpu', 2); host.set('memory', ((parseInt(2000000))).toFixed(2)); host.set('disk_info', [ {"mountpoint": "/", "type": "ext4"}, {"mountpoint": "/grid/0", "type": "ext4"}, {"mountpoint": "/grid/1", "type": "ext4"}, {"mountpoint": "/grid/2", "type": "ext4"} ]); return host; }, /** * Set loaded metrics to host object * @param {object} host * @param {object} hostInfo * @returns {object} * @method _setHostDataFromLoadedHostInfo * @private */ _setHostDataFromLoadedHostInfo: function(host, hostInfo) { host.set('cpu', Em.get(hostInfo, 'Hosts.cpu_count')); host.set('memory', ((parseInt(Em.get(hostInfo, 'Hosts.total_mem')))).toFixed(2)); host.set('disk_info', Em.get(hostInfo, 'Hosts.disk_info').filter(function (h) { return h.mountpoint != "/boot" })); host.set('os_type', Em.get(hostInfo, 'Hosts.os_type')); host.set('os_arch', Em.get(hostInfo, 'Hosts.os_arch')); host.set('ip', Em.get(hostInfo, 'Hosts.ip')); return host; }, /** * Error-callback for hosts info request * @method getHostInfoErrorCallback */ getHostInfoErrorCallback: function () { console.log('INFO: Getting host information(cpu_count and total_mem) from the server failed'); this.set('isHostsWarningsLoaded', true); this.registerErrPopup(Em.I18n.t('installer.step3.hostInformation.popup.header'), Em.I18n.t('installer.step3.hostInformation.popup.body')); }, /** * Enable or disable submit/retry buttons according to hosts boot statuses * @method stopRegistration */ stopRegistration: function () { this.set('isSubmitDisabled', !this.get('bootHosts').someProperty('bootStatus', 'REGISTERED')); this.set('isRetryDisabled', !this.get('bootHosts').someProperty('bootStatus', 'FAILED')); }, /** * Check if the 'Transparent Huge Pages' enabled. * @param {string} transparentHugePage * @param {string} hostName * @return {string} error-message or empty string * @method checkTHP */ checkTHP: function (hostName, transparentHugePage) { if (transparentHugePage == "always") { console.log('WARNING: Transparent Huge Page enabled on host: '+ hostName); return Em.I18n.t('installer.step3.hostWarningsPopup.thp.context').format(hostName); } else { return ''; } }, /** * Check if the customized os group contains the registered host os type. If not the repo on that host is invalid. * @param {string} osType * @param {string} hostName * @return {string} error-message or empty string * @method checkHostOSType */ checkHostOSType: function (osType, hostName) { if (this.get('content.stacks')) { var selectedStack = this.get('content.stacks').findProperty('isSelected', true); var selectedOS = []; var self = this; var isValid = false; if (selectedStack && selectedStack.get('operatingSystems')) { selectedStack.get('operatingSystems').filterProperty('isSelected', true).forEach(function (os) { selectedOS.pushObject(os.get('osType')); if (self.repoToAgentOsType(os.get('osType')).indexOf(osType) >= 0) { isValid = true; } }); } if (isValid) { return ''; } else { console.log('WARNING: Getting host os type does NOT match the user selected os group in step1. ' + 'Host Name: ' + hostName + '. Host os type:' + osType + '. Selected group:' + selectedOS.uniq()); return Em.I18n.t('installer.step3.hostWarningsPopup.repositories.context').format(hostName, osType, selectedOS.uniq()); } } else { return ''; } }, /** * return the supported agent os types for a repo os type * @param {String} repoType * @return {Array} supported agent os type array * @method repoToAgentOsType */ repoToAgentOsType : function (repoType) { /* istanbul ignore next */ switch (repoType) { case "redhat6": return ["redhat6", "centos6", "oraclelinux6", "rhel6"]; case "redhat5": return ["redhat5", "centos5", "oraclelinux5", "rhel5"]; case "suse11": return ["suse11", "sles11", "opensuse11"]; case "ubuntu12": return ["debian12", "ubuntu12"]; default: return []; } }, /** * Check if current host has enough free disk usage. * @param {string} hostName * @param {object} diskInfo * @return {string} error-message or empty string * @method checkHostDiskSpace */ checkHostDiskSpace: function (hostName, diskInfo) { var minFreeRootSpace = App.minDiskSpace * 1024 * 1024; //in kilobyte var minFreeUsrLibSpace = App.minDiskSpaceUsrLib * 1024 * 1024; //in kilobyte var warningString = ''; diskInfo.forEach(function (info) { switch (info.mountpoint) { case '/': warningString = info.available < minFreeRootSpace ? Em.I18n.t('installer.step3.hostWarningsPopup.disk.context2').format(App.minDiskSpace + 'GB', info.mountpoint) + ' ' + warningString : warningString; break; case '/usr': case '/usr/lib': warningString = info.available < minFreeUsrLibSpace ? Em.I18n.t('installer.step3.hostWarningsPopup.disk.context2').format(App.minDiskSpaceUsrLib + 'GB', info.mountpoint) + ' ' + warningString : warningString; break; default: break; } }); if (warningString) { console.log('WARNING: Getting host free disk space. ' + 'Host Name: ' + hostName); return Em.I18n.t('installer.step3.hostWarningsPopup.disk.context1').format(hostName) + ' ' + warningString; } else { return ''; } }, /** * Submit-click handler * @return {App.ModalPopup|null} * @method submit */ submit: function () { var self = this; if (this.get('isHostHaveWarnings')) { return App.showConfirmationPopup( function () { self.set('confirmedHosts', self.get('bootHosts')); App.router.send('next'); }, Em.I18n.t('installer.step3.hostWarningsPopup.hostHasWarnings')); } else { this.set('confirmedHosts', this.get('bootHosts')); App.router.send('next'); } return null; }, /** * Show popup with host log * @param {object} event * @return {App.ModalPopup} */ hostLogPopup: function (event) { var host = event.context; return App.ModalPopup.show({ header: Em.I18n.t('installer.step3.hostLog.popup.header').format(host.get('name')), secondary: null, host: host, bodyClass: App.WizardStep3HostLogPopupBody }); }, /** * Check warnings from server and put it in parsing * @method rerunChecks */ rerunChecks: function () { var self = this; var currentProgress = 0; this.getHostNameResolution(); this.checkHostJDK(); var interval = setInterval(function () { currentProgress += 100000 / self.get('warningsTimeInterval'); if (currentProgress < 100) { self.set('checksUpdateProgress', currentProgress); } else { clearInterval(interval); App.ajax.send({ name: 'wizard.step3.rerun_checks', sender: self, success: 'rerunChecksSuccessCallback', error: 'rerunChecksErrorCallback' }); } }, 1000); }, /** * Success-callback for rerun request * @param {object} data * @method rerunChecksSuccessCallback */ rerunChecksSuccessCallback: function (data) { this.set('checksUpdateProgress', 100); this.set('checksUpdateStatus', 'SUCCESS'); this.parseWarnings(data); }, /** * Error-callback for rerun request * @method rerunChecksErrorCallback */ rerunChecksErrorCallback: function () { this.set('checksUpdateProgress', 100); this.set('checksUpdateStatus', 'FAILED'); console.log('INFO: Getting host information(last_agent_env) from the server failed'); }, /** * Filter data for warnings parse * is data from host in bootStrap * @param {object} data * @return {Object} * @method filterBootHosts */ filterBootHosts: function (data) { var bootHostNames = {}; this.get('bootHosts').forEach(function (bootHost) { bootHostNames[bootHost.get('name')] = true; }); var filteredData = { href: data.href, items: [] }; data.items.forEach(function (host) { if (bootHostNames[host.Hosts.host_name]) { filteredData.items.push(host); } }); return filteredData; }, /** * Parse warnings data for each host and total * @param {object} data * @method parseWarnings */ parseWarnings: function (data) { data = App.get('testMode') ? data : this.filterBootHosts(data); var warnings = []; var warning; var hosts = []; var warningCategories = { fileFoldersWarnings: {}, packagesWarnings: {}, processesWarnings: {}, servicesWarnings: {}, usersWarnings: {}, alternativeWarnings: {} }; data.items.sortPropertyLight('Hosts.host_name').forEach(function (_host) { var host = { name: _host.Hosts.host_name, warnings: [] }; if (!_host.Hosts.last_agent_env) { // in some unusual circumstances when last_agent_env is not available from the _host, // skip the _host and proceed to process the rest of the hosts. console.log("last_agent_env is missing for " + _host.Hosts.host_name + ". Skipping _host check."); return; } //parse all directories and files warnings for host //todo: to be removed after check in new API var stackFoldersAndFiles = _host.Hosts.last_agent_env.stackFoldersAndFiles || []; stackFoldersAndFiles.forEach(function (path) { warning = warningCategories.fileFoldersWarnings[path.name]; if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warningCategories.fileFoldersWarnings[path.name] = warning = { name: path.name, hosts: [_host.Hosts.host_name], category: 'fileFolders', onSingleHost: true }; } host.warnings.push(warning); }, this); //parse all package warnings for host if (_host.Hosts.last_agent_env.installedPackages) { _host.Hosts.last_agent_env.installedPackages.forEach(function (_package) { warning = warningCategories.packagesWarnings[_package.name]; if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.version = _package.version; warning.onSingleHost = false; } else { warningCategories.packagesWarnings[_package.name] = warning = { name: _package.name, version: _package.version, hosts: [_host.Hosts.host_name], category: 'packages', onSingleHost: true }; } host.warnings.push(warning); }, this); } //parse all process warnings for host //todo: to be removed after check in new API var javaProcs = _host.Hosts.last_agent_env.hostHealth ? _host.Hosts.last_agent_env.hostHealth.activeJavaProcs : _host.Hosts.last_agent_env.javaProcs; if (javaProcs) { javaProcs.forEach(function (process) { warning = warningCategories.processesWarnings[process.pid]; if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warningCategories.processesWarnings[process.pid] = warning = { name: (process.command.substr(0, 35) + '...'), hosts: [_host.Hosts.host_name], category: 'processes', user: process.user, pid: process.pid, command: '
' + ((process.command.length < 500) ? process.command : process.command.substr(0, 230) + '...' + '

................

' + '...' + process.command.substr(-230)) + '
', onSingleHost: true }; } host.warnings.push(warning); }, this); } //parse all service warnings for host //todo: to be removed after check in new API if (_host.Hosts.last_agent_env.hostHealth && _host.Hosts.last_agent_env.hostHealth.liveServices) { _host.Hosts.last_agent_env.hostHealth.liveServices.forEach(function (service) { if (service.status === 'Unhealthy') { warning = warningCategories.servicesWarnings[service.name]; if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warningCategories.servicesWarnings[service.name] = warning = { name: service.name, hosts: [_host.Hosts.host_name], category: 'services', onSingleHost: true }; } host.warnings.push(warning); } }, this); } //parse all user warnings for host //todo: to be removed after check in new API if (_host.Hosts.last_agent_env.existingUsers) { _host.Hosts.last_agent_env.existingUsers.forEach(function (user) { warning = warningCategories.usersWarnings[user.userName]; if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warningCategories.usersWarnings[user.userName] = warning = { name: user.userName, hosts: [_host.Hosts.host_name], category: 'users', onSingleHost: true }; } host.warnings.push(warning); }, this); } //parse misc warnings for host var umask = _host.Hosts.last_agent_env.umask; if (umask && umask !== 18) { warning = warnings.filterProperty('category', 'misc').findProperty('name', umask); if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warning = { name: umask, hosts: [_host.Hosts.host_name], category: 'misc', onSingleHost: true }; warnings.push(warning); } host.warnings.push(warning); } var firewallRunning = _host.Hosts.last_agent_env.iptablesIsRunning; if (firewallRunning !== null && firewallRunning) { var name = Em.I18n.t('installer.step3.hostWarningsPopup.firewall.name'); warning = warnings.filterProperty('category', 'firewall').findProperty('name', name); if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warning = { name: name, hosts: [_host.Hosts.host_name], category: 'firewall', onSingleHost: true }; warnings.push(warning); } host.warnings.push(warning); } if (_host.Hosts.last_agent_env.alternatives) { _host.Hosts.last_agent_env.alternatives.forEach(function (alternative) { warning = warningCategories.alternativeWarnings[alternative.name]; if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warningCategories.alternativeWarnings[alternative.name] = warning = { name: alternative.name, target: alternative.target, hosts: [_host.Hosts.host_name], category: 'alternatives', onSingleHost: true }; } host.warnings.push(warning); }, this); } if (_host.Hosts.last_agent_env.reverseLookup === false) { var name = Em.I18n.t('installer.step3.hostWarningsPopup.reverseLookup.name'); warning = warnings.filterProperty('category', 'reverseLookup').findProperty('name', name); if (warning) { warning.hosts.push(_host.Hosts.host_name); warning.onSingleHost = false; } else { warning = { name: name, hosts: [_host.Hosts.host_name], category: 'reverseLookup', onSingleHost: true }; warnings.push(warning); } host.warnings.push(warning); } hosts.push(host); }, this); for (var categoryId in warningCategories) { var category = warningCategories[categoryId] for (var warningId in category) { warnings.push(category[warningId]); } } warnings.forEach(function (warn) { if (warn.hosts.length < 11) { warn.hostsList = warn.hosts.join('
') } else { warn.hostsList = warn.hosts.slice(0, 10).join('
') + '
' + Em.I18n.t('installer.step3.hostWarningsPopup.moreHosts').format(warn.hosts.length - 10); } }); hosts.unshift({ name: 'All Hosts', warnings: warnings }); this.set('warnings', warnings); this.set('warningsByHost', hosts); this.set('isHostsWarningsLoaded', true); }, /** * Open popup that contain hosts' warnings * @return {App.ModalPopup} * @method hostWarningsPopup */ hostWarningsPopup: function () { var self = this; return App.ModalPopup.show({ header: Em.I18n.t('installer.step3.warnings.popup.header'), secondary: Em.I18n.t('installer.step3.hostWarningsPopup.rerunChecks'), primary: Em.I18n.t('common.close'), onPrimary: function () { self.set('checksUpdateStatus', null); this.hide(); }, onClose: function () { self.set('checksUpdateStatus', null); this.hide(); }, onSecondary: function () { self.rerunChecks(); }, didInsertElement: function () { this.fitHeight(); }, footerClass: App.WizardStep3HostWarningPopupFooter, bodyClass: App.WizardStep3HostWarningPopupBody }); }, /** * Show popup with registered hosts * @return {App.ModalPopup} * @method registeredHostsPopup */ registeredHostsPopup: function () { var self = this; return App.ModalPopup.show({ header: Em.I18n.t('installer.step3.warning.registeredHosts').format(this.get('registeredHosts').length), secondary: null, bodyClass: Em.View.extend({ templateName: require('templates/wizard/step3/step3_registered_hosts_popup'), message: Em.I18n.t('installer.step3.registeredHostsPopup'), registeredHosts: self.get('registeredHosts') }) }) } });