| /** |
| * 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'); |
| |
| App.WizardStep3Controller = Em.Controller.extend({ |
| name: 'wizardStep3Controller', |
| hosts: [], |
| content: [], |
| bootHosts: [], |
| registeredHosts: [], |
| registrationStartedAt: null, |
| registrationTimeoutSecs: function(){ |
| if(this.get('content.installOptions.manualInstall')){ |
| return 15; |
| } |
| return 120; |
| }.property('content.installOptions.manualInstall'), |
| stopBootstrap: false, |
| isSubmitDisabled: true, |
| |
| categoryObject: Em.Object.extend({ |
| hostsCount: function () { |
| var category = this; |
| var hosts = this.get('controller.hosts').filter(function(_host) { |
| if (_host.get('bootStatus') == category.get('hostsBootStatus')) { |
| return true; |
| } else { |
| return (_host.get('bootStatus') == 'DONE' && category.get('hostsBootStatus') == 'REGISTERING'); |
| } |
| }, this); |
| return hosts.get('length'); |
| }.property('controller.hosts.@each.bootStatus'), // 'hosts.@each.bootStatus' |
| label: function () { |
| return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount')); |
| }.property('value', 'hostsCount') |
| }), |
| getCategory: function(field, value){ |
| return this.get('categories').find(function(item){ |
| return item.get(field) == value; |
| }); |
| }, |
| |
| categories: function () { |
| var self = this; |
| self.categoryObject.reopen({ |
| controller: self, |
| isActive: function(){ |
| return this.get('controller.category') == this; |
| }.property('controller.category'), |
| itemClass: function(){ |
| return this.get('isActive') ? 'active' : ''; |
| }.property('isActive') |
| }); |
| |
| var categories = [ |
| self.categoryObject.create({value: Em.I18n.t('common.all'), hostsCount: function () { |
| return this.get('controller.hosts.length'); |
| }.property('controller.hosts.length') }), |
| self.categoryObject.create({value: Em.I18n.t('installer.step3.hosts.status.installing'), hostsBootStatus: 'RUNNING'}), |
| self.categoryObject.create({value: Em.I18n.t('installer.step3.hosts.status.registering'), hostsBootStatus: 'REGISTERING'}), |
| self.categoryObject.create({value: Em.I18n.t('common.success'), hostsBootStatus: 'REGISTERED' }), |
| self.categoryObject.create({value: Em.I18n.t('common.fail'), hostsBootStatus: 'FAILED', last: true }) |
| ]; |
| |
| this.set('category', categories.get('firstObject')); |
| |
| return categories; |
| }.property(), |
| |
| category: false, |
| |
| allChecked: false, |
| |
| onAllChecked: function () { |
| var hosts = this.get('visibleHosts'); |
| hosts.setEach('isChecked', this.get('allChecked')); |
| }.observes('allChecked'), |
| |
| noHostsSelected: function () { |
| return !(this.hosts.someProperty('isChecked', true)); |
| }.property('hosts.@each.isChecked'), |
| |
| isRetryDisabled: true, |
| isLoaded: false, |
| |
| navigateStep: function () { |
| if(this.get('isLoaded')){ |
| if (this.get('content.installOptions.manualInstall') !== true) { |
| if (!this.get('wizardController').getDBProperty('bootStatus')) { |
| this.startBootstrap(); |
| } |
| } else { |
| this.set('bootHosts', this.get('hosts')); |
| if (App.testMode) { |
| this.getHostInfo(); |
| this.get('bootHosts').setEach('bootStatus', 'REGISTERED'); |
| this.get('bootHosts').setEach('cpu', '2'); |
| this.get('bootHosts').setEach('memory', '2000000'); |
| this.set('isSubmitDisabled', false); |
| } else { |
| this.set('registrationStartedAt', null); |
| this.get('bootHosts').setEach('bootStatus', 'DONE'); |
| this.startRegistration(); |
| } |
| } |
| } |
| }.observes('isLoaded'), |
| |
| clearStep: function () { |
| this.set('stopBootstrap', false); |
| this.set('hosts', []); |
| this.get('bootHosts').clear(); |
| this.get('wizardController').setDBProperty('bootStatus', false); |
| this.set('isSubmitDisabled', true); |
| this.set('isRetryDisabled', true); |
| }, |
| |
| loadStep: function () { |
| console.log("TRACE: Loading step3: Confirm Hosts"); |
| this.set('registrationStartedAt', null); |
| this.set('isLoaded', false); |
| |
| this.clearStep(); |
| this.loadHosts(); |
| // hosts.setEach('bootStatus', 'RUNNING'); |
| }, |
| |
| /* Loads the hostinfo from localStorage on the insertion of view. It's being called from view */ |
| loadHosts: function () { |
| var hostsInfo = this.get('content.hosts'); |
| var hosts = []; |
| |
| for (var index in hostsInfo) { |
| var hostInfo = App.HostInfo.create({ |
| name: hostsInfo[index].name, |
| bootStatus: hostsInfo[index].bootStatus, |
| isChecked: false |
| }); |
| |
| console.log('pushing ' + hostInfo.name); |
| hosts.pushObject(hostInfo); |
| } |
| |
| if(hosts.length > 100) { |
| lazyloading.run({ |
| destination: this.get('hosts'), |
| source: hosts, |
| context: this, |
| initSize: 20, |
| chunkSize: 100, |
| delay: 300 |
| }); |
| } else { |
| this.set('hosts', hosts); |
| this.set('isLoaded', true); |
| } |
| }, |
| |
| /** |
| * Parses and updates the content based on bootstrap API response. |
| * Returns true if polling should continue (some hosts are in "RUNNING" state); false otherwise |
| */ |
| 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'); |
| }, |
| |
| /* Returns the current set of visible hosts on view (All, Succeeded, Failed) */ |
| visibleHosts: function () { |
| if (this.get('category.hostsBootStatus')) { |
| return this.hosts.filterProperty('bootStatus', this.get('category.hostsBootStatus')); |
| } else { // if (this.get('category') === 'All Hosts') |
| return this.hosts; |
| } |
| }.property('category', 'hosts.@each.bootStatus'), |
| |
| removeHosts: function (hosts) { |
| var self = this; |
| 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 */ |
| removeHost: function (hostInfo) { |
| this.removeHosts([hostInfo]); |
| }, |
| |
| removeSelectedHosts: function () { |
| if (!this.get('noHostsSelected')) { |
| var selectedHosts = this.get('visibleHosts').filterProperty('isChecked', true); |
| selectedHosts.forEach(function (_hostInfo) { |
| console.log('Removing: ' + _hostInfo.name); |
| }); |
| this.removeHosts(selectedHosts); |
| } |
| }, |
| |
| retryHost: function (hostInfo) { |
| this.retryHosts([hostInfo]); |
| }, |
| |
| retryHosts: function (hosts) { |
| var bootStrapData = JSON.stringify({'verbose': true, 'sshKey': this.get('content.installOptions.sshKey'), 'hosts': hosts.mapProperty('name'), 'user': this.get('content.installOptions.sshUser')}); |
| this.numPolls = 0; |
| if (this.get('content.installOptions.manualInstall') !== true) { |
| var requestId = App.router.get('installerController').launchBootstrap(bootStrapData); |
| this.set('content.installOptions.bootRequestId', requestId); |
| this.set('registrationStartedAt', null); |
| this.doBootstrap(); |
| } else { |
| this.set('registrationStartedAt', null); |
| this.get('bootHosts').setEach('bootStatus', 'DONE'); |
| this.startRegistration(); |
| } |
| }, |
| |
| retrySelectedHosts: function () { |
| //to display all hosts |
| this.set('category', 'All'); |
| 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); |
| } |
| }, |
| |
| numPolls: 0, |
| |
| startBootstrap: function () { |
| //this.set('isSubmitDisabled', true); //TODO: uncomment after actual hookup |
| this.numPolls = 0; |
| this.set('registrationStartedAt', null); |
| this.set('bootHosts', this.get('hosts')); |
| this.get('bootHosts').setEach('bootStatus', 'PENDING'); |
| this.doBootstrap(); |
| }, |
| |
| isInstallInProgress: function(){ |
| var bootStatuses = this.get('bootHosts').getEach('bootStatus'); |
| if(bootStatuses.length && |
| (bootStatuses.contains('REGISTERING') || |
| bootStatuses.contains('DONE') || |
| bootStatuses.contains('RUNNING') || |
| bootStatuses.contains('PENDING'))){ |
| return true; |
| } |
| return false; |
| }.property('bootHosts.@each.bootStatus'), |
| |
| disablePreviousSteps: function(){ |
| if(this.get('isInstallInProgress')){ |
| App.router.get('installerController').setLowerStepsDisable(3); |
| this.set('isSubmitDisabled', true); |
| } else { |
| App.router.get('installerController.isStepDisabled').filter(function(step){ |
| if(step.step >= 0 && step.step <= 2) return true; |
| }).setEach('value', false); |
| } |
| }.observes('isInstallInProgress'), |
| |
| doBootstrap: function () { |
| if (this.get('stopBootstrap')) { |
| return; |
| } |
| this.numPolls++; |
| |
| App.ajax.send({ |
| name: 'wizard.step3.bootstrap', |
| sender: this, |
| data: { |
| bootRequestId: this.get('content.installOptions.bootRequestId'), |
| numPolls: this.numPolls |
| }, |
| success: 'doBootstrapSuccessCallback' |
| }). |
| retry({ |
| times: App.maxRetries, |
| timeout: App.timeout |
| }). |
| then( |
| null, |
| function () { |
| App.showReloadPopup(); |
| console.log('Bootstrap failed'); |
| } |
| ); |
| }, |
| |
| doBootstrapSuccessCallback: function (data) { |
| if (data.hostsStatus !== null) { |
| // 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.hostsStatus.someProperty('status', 'DONE') || data.hostsStatus.someProperty('status', 'FAILED')) { |
| // kicking off registration polls after at least one host has succeeded |
| this.startRegistration(); |
| } |
| if (keepPolling) { |
| var self = this; |
| window.setTimeout(function () { |
| self.doBootstrap() |
| }, 3000); |
| } |
| } |
| }, |
| |
| startRegistration: function () { |
| if (this.get('registrationStartedAt') == null) { |
| this.set('registrationStartedAt', new Date().getTime()); |
| console.log('registration started at ' + this.get('registrationStartedAt')); |
| this.isHostsRegistered(); |
| } |
| }, |
| |
| isHostsRegistered: function () { |
| if (this.get('stopBootstrap')) { |
| 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'); |
| } |
| ); |
| }, |
| |
| 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.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 |
| console.log(_host.name + ' bootStatus=' + _host.get('bootStatus')); |
| 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', new Date().getTime()); |
| stopPolling = false; |
| break; |
| case 'REGISTERING': |
| if (jsonData.items.someProperty('Hosts.host_name', _host.name)) { |
| console.log(_host.name + ' has been registered'); |
| _host.set('bootStatus', 'REGISTERED'); |
| _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + Em.I18n.t('installer.step3.hosts.bootLog.registering')); |
| } else { |
| console.log(_host.name + ' is registering...'); |
| stopPolling = false; |
| } |
| break; |
| case 'RUNNING': |
| stopPolling = false; |
| break; |
| case 'REGISTERED': |
| case 'FAILED': |
| default: |
| break; |
| } |
| }, this); |
| |
| if (stopPolling) { |
| this.getHostInfo(); |
| } else if (hosts.someProperty('bootStatus', 'RUNNING') || new Date().getTime() - 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.getHostInfo(); |
| } |
| }, |
| |
| hasMoreRegisteredHosts: false, |
| |
| getAllRegisteredHosts: function() { |
| App.ajax.send({ |
| name: 'wizard.step3.is_hosts_registered', |
| sender: this, |
| success: 'getAllRegisteredHostsCallback' |
| }); |
| }.observes('bootHosts'), |
| |
| hostsInCluster: function() { |
| return App.Host.find().getEach('hostName'); |
| }.property().volatile(), |
| |
| 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',''); |
| } |
| }, |
| |
| allHostsComplete: function() { |
| var result = true; |
| this.get('bootHosts').forEach(function(host) { |
| var status = host.get('bootStatus'); |
| if (status != 'REGISTERED' && status != 'FAILED') { |
| result = false; |
| } |
| }); |
| return result; |
| }.property('bootHosts.@each.bootStatus'), |
| |
| registerErrPopup: function (header, message) { |
| App.ModalPopup.show({ |
| header: header, |
| secondary: false, |
| onPrimary: function () { |
| this.hide(); |
| }, |
| bodyClass: Ember.View.extend({ |
| template: Ember.Handlebars.compile(['<p>{{view.message}}</p>'].join('\n')), |
| message: message |
| }) |
| }); |
| }, |
| |
| /** |
| * Get disk info and cpu count of booted hosts from server |
| */ |
| getHostInfo: function () { |
| App.ajax.send({ |
| name: 'wizard.step3.host_info', |
| sender: this, |
| success: 'getHostInfoSuccessCallback', |
| error: 'getHostInfoErrorCallback' |
| }); |
| }, |
| |
| getHostInfoSuccessCallback: function (jsonData) { |
| var hosts = this.get('bootHosts'); |
| var self = this; |
| this.parseWarnings(jsonData); |
| var repoWarnings = []; |
| var hostsContext = []; |
| hosts.forEach(function (_host) { |
| var host = (App.testMode) ? jsonData.items[0] : jsonData.items.findProperty('Hosts.host_name', _host.name); |
| if (App.skipBootstrap) { |
| _host.cpu = 2; |
| _host.memory = ((parseInt(2000000))).toFixed(2); |
| _host.disk_info = [{"mountpoint": "/", "type":"ext4"},{"mountpoint": "/grid/0", "type":"ext4"}, {"mountpoint": "/grid/1", "type":"ext4"}, {"mountpoint": "/grid/2", "type":"ext4"}]; |
| } else if (host) { |
| _host.cpu = host.Hosts.cpu_count; |
| _host.memory = ((parseInt(host.Hosts.total_mem))).toFixed(2); |
| _host.disk_info = host.Hosts.disk_info; |
| _host.os_type = host.Hosts.os_type; |
| |
| var context = self.checkHostOSType(host.Hosts.os_type, host.Hosts.host_name); |
| if(context) { |
| hostsContext.push(context); |
| } |
| console.log("The value of memory is: " + _host.memory); |
| } |
| }); |
| if (hostsContext.length > 0) { // warning exist |
| var repoWarning = { |
| name: Em.I18n.t('installer.step3.hostWarningsPopup.repositories.name'), |
| hosts: hostsContext, |
| category: 'repositories', |
| onSingleHost: false |
| }; |
| repoWarnings.push(repoWarning); |
| } |
| this.set('repoCategoryWarnings', repoWarnings); |
| this.set('bootHosts', hosts); |
| console.log("The value of hosts: " + JSON.stringify(hosts)); |
| this.stopRegistration(); |
| }, |
| |
| getHostInfoErrorCallback: function () { |
| console.log('INFO: Getting host information(cpu_count and total_mem) from the server failed'); |
| this.registerErrPopup(Em.I18n.t('installer.step3.hostInformation.popup.header'), Em.I18n.t('installer.step3.hostInformation.popup.body')); |
| }, |
| |
| stopRegistration: function () { |
| this.set('isSubmitDisabled', !this.get('bootHosts').someProperty('bootStatus', 'REGISTERED')); |
| this.set('isRetryDisabled', !this.get('bootHosts').someProperty('bootStatus', 'FAILED')); |
| }, |
| |
| /** |
| * Check if the customized os group contains the registered host os type. If not the repo on that host is invalid. |
| */ |
| checkHostOSType: function (osType, hostName) { |
| if(this.get('content.stacks')){ |
| var selectedStack = this.get('content.stacks').findProperty('isSelected', true); |
| var selectedOS = []; |
| var isValid = false; |
| if (selectedStack && selectedStack.operatingSystems) { |
| selectedStack.get('operatingSystems').filterProperty('selected', true).forEach( function(os) { |
| selectedOS.pushObject(os.osType); |
| if ( os.osType == osType) { |
| isValid = true; |
| } |
| }); |
| } |
| |
| if (!isValid) { |
| 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); |
| return Em.I18n.t('installer.step3.hostWarningsPopup.repositories.context').format(hostName, osType, selectedOS); |
| } else { |
| return null; |
| } |
| }else{ |
| return null; |
| } |
| }, |
| |
| selectCategory: function(event, context){ |
| this.set('category', event.context); |
| }, |
| |
| submit: function () { |
| if (!this.get('isSubmitDisabled')) { |
| if(this.get('isHostHaveWarnings')) { |
| var self = this; |
| App.showConfirmationPopup( |
| function(){ |
| self.set('content.hosts', self.get('bootHosts')); |
| App.router.send('next'); |
| }, |
| Em.I18n.t('installer.step3.hostWarningsPopup.hostHasWarnings')); |
| } |
| else { |
| this.set('content.hosts', this.get('bootHosts')); |
| App.router.send('next'); |
| } |
| } |
| }, |
| |
| hostLogPopup: function (event, context) { |
| var host = event.context; |
| |
| App.ModalPopup.show({ |
| |
| header: Em.I18n.t('installer.step3.hostLog.popup.header').format(host.get('name')), |
| secondary: null, |
| |
| onPrimary: function () { |
| this.hide(); |
| }, |
| |
| bodyClass: Ember.View.extend({ |
| templateName: require('templates/wizard/step3_host_log_popup'), |
| host: host, |
| didInsertElement: function () { |
| var self = this; |
| var button = $(this.get('element')).find('.textTrigger'); |
| button.click(function () { |
| if (self.get('isTextArea')) { |
| $(this).text(Em.I18n.t('installer.step3.hostLogPopup.highlight')); |
| } else { |
| $(this).text(Em.I18n.t('installer.step3.hostLogPopup.copy')); |
| } |
| self.set('isTextArea', !self.get('isTextArea')); |
| }); |
| $(this.get('element')).find('.content-area').mouseenter( |
| function () { |
| var element = $(this); |
| element.css('border', '1px solid #dcdcdc'); |
| button.css('visibility', 'visible'); |
| }).mouseleave( |
| function () { |
| var element = $(this); |
| element.css('border', 'none'); |
| button.css('visibility', 'hidden'); |
| }) |
| }, |
| isTextArea: false, |
| textArea: Em.TextArea.extend({ |
| didInsertElement: function () { |
| var element = $(this.get('element')); |
| element.width($(this.get('parentView').get('element')).width() - 10); |
| element.height($(this.get('parentView').get('element')).height()); |
| element.select(); |
| element.css('resize', 'none'); |
| }, |
| readOnly: true, |
| value: function () { |
| return this.get('content'); |
| }.property('content') |
| }) |
| }) |
| }); |
| }, |
| /** |
| * check warnings from server and put it in parsing |
| */ |
| rerunChecks: function () { |
| var self = this; |
| var currentProgress = 0; |
| 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); |
| }, |
| |
| rerunChecksSuccessCallback: function (data) { |
| this.set('checksUpdateProgress', 100); |
| this.set('checksUpdateStatus', 'SUCCESS'); |
| this.parseWarnings(data); |
| }, |
| |
| rerunChecksErrorCallback: function () { |
| this.set('checksUpdateProgress', 100); |
| this.set('checksUpdateStatus', 'FAILED'); |
| console.log('INFO: Getting host information(last_agent_env) from the server failed'); |
| }, |
| |
| warnings: [], |
| warningsByHost: [], |
| warningsTimeInterval: 60000, |
| /** |
| * check are hosts have any warnings |
| */ |
| isHostHaveWarnings: function(){ |
| return this.get('warnings.length') > 0; |
| }.property('warnings'), |
| |
| isWarningsBoxVisible: function(){ |
| return (App.testMode) ? true : this.get('allHostsComplete'); |
| }.property('allHostsComplete'), |
| |
| checksUpdateProgress:0, |
| checksUpdateStatus: null, |
| /** |
| * filter data for warnings parse |
| * is data from host in bootStrap |
| * @param data |
| * @return {Object} |
| */ |
| filterBootHosts: function (data) { |
| var bootHostNames = this.get('bootHosts').mapProperty('name'); |
| var filteredData = { |
| href: data.href, |
| items: [] |
| }; |
| data.items.forEach(function (host) { |
| if (bootHostNames.contains(host.Hosts.host_name)) { |
| filteredData.items.push(host); |
| } |
| }); |
| return filteredData; |
| }, |
| /** |
| * parse warnings data for each host and total |
| * @param data |
| */ |
| parseWarnings: function (data) { |
| data = App.testMode ? data : this.filterBootHosts(data); |
| var warnings = []; |
| var warning; |
| var hosts = []; |
| data.items.sort(function (a, b) { |
| if (a.Hosts.host_name > b.Hosts.host_name) { |
| return 1; |
| } |
| if (a.Hosts.host_name < b.Hosts.host_name) { |
| return -1; |
| } |
| return 0; |
| }); |
| data.items.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 || _host.Hosts.last_agent_env.paths; |
| |
| stackFoldersAndFiles.forEach(function (path) { |
| warning = warnings.filterProperty('category', 'fileFolders').findProperty('name', path.name); |
| if (warning) { |
| warning.hosts.push(_host.Hosts.host_name); |
| warning.onSingleHost = false; |
| } else { |
| warning = { |
| name: path.name, |
| hosts: [_host.Hosts.host_name], |
| category: 'fileFolders', |
| onSingleHost: true |
| } |
| warnings.push(warning); |
| } |
| host.warnings.push(warning); |
| }, this); |
| |
| //parse all package warnings for host |
| _host.Hosts.last_agent_env.installedPackages.forEach(function (_package) { |
| warning = warnings.filterProperty('category', 'packages').findProperty('name', _package.name); |
| if (warning) { |
| warning.hosts.push(_host.Hosts.host_name); |
| warning.version = _package.version, |
| warning.onSingleHost = false; |
| } else { |
| warning = { |
| name: _package.name, |
| version: _package.version, |
| hosts: [_host.Hosts.host_name], |
| category: 'packages', |
| onSingleHost: true |
| } |
| warnings.push(warning); |
| } |
| 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; |
| |
| javaProcs.forEach(function (process) { |
| warning = warnings.filterProperty('category', 'processes').findProperty('pid', process.pid); |
| if (warning) { |
| warning.hosts.push(_host.Hosts.host_name); |
| warning.onSingleHost = false; |
| } else { |
| warning = { |
| name: (process.command.substr(0, 35) + '...'), |
| hosts: [_host.Hosts.host_name], |
| category: 'processes', |
| user: process.user, |
| pid: process.pid, |
| command: '<table><tr><td style="word-break: break-all;">' + |
| ((process.command.length < 500) ? process.command : process.command.substr(0, 230) + '...' + |
| '<p style="text-align: center">................</p>' + |
| '...' + process.command.substr(-230)) + '</td></tr></table>', |
| onSingleHost: true |
| } |
| warnings.push(warning); |
| } |
| 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 = warnings.filterProperty('category', 'services').findProperty('name', service.name); |
| if (warning) { |
| warning.hosts.push(_host.Hosts.host_name); |
| warning.onSingleHost = false; |
| } else { |
| warning = { |
| name: service.name, |
| hosts: [_host.Hosts.host_name], |
| category: 'services', |
| onSingleHost: true |
| } |
| warnings.push(warning); |
| } |
| 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 = warnings.filterProperty('category', 'users').findProperty('name', user.userName); |
| if (warning) { |
| warning.hosts.push(_host.Hosts.host_name); |
| warning.onSingleHost = false; |
| } else { |
| warning = { |
| name: user.userName, |
| hosts: [_host.Hosts.host_name], |
| category: 'users', |
| onSingleHost: true |
| } |
| warnings.push(warning); |
| } |
| 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); |
| } |
| |
| hosts.push(host); |
| }, this); |
| warnings.forEach(function (warn) { |
| if (warn.hosts.length < 11) { |
| warn.hostsList = warn.hosts.join('<br>') |
| } else { |
| warn.hostsList = warn.hosts.slice(0,10).join('<br>') + '<br> ' + 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); |
| }, |
| /** |
| * open popup that contain hosts' warnings |
| * @param event |
| */ |
| hostWarningsPopup: function(event){ |
| var self = this; |
| var repoCategoryWarnings = this.get('repoCategoryWarnings'); |
| 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: Ember.View.extend({ |
| template: Ember.Handlebars.compile([ |
| '<div class="update-progress pull-left">', |
| '{{#if view.isUpdateInProgress}}', |
| '<div class="progress-info active progress">', |
| '<div class="bar" {{bindAttr style="view.progressWidth"}}></div></div>', |
| '{{else}}<label {{bindAttr class="view.updateStatusClass"}}>{{view.updateStatus}}</label>', |
| '{{/if}}</div>', |
| '{{#if view.parentView.secondary}}<button type="button" class="btn btn-info" {{bindAttr disabled="view.isUpdateInProgress"}} {{action onSecondary target="view.parentView"}}><i class="icon-repeat"></i> {{view.parentView.secondary}}</button>{{/if}}', |
| '{{#if view.parentView.primary}}<button type="button" class="btn" {{action onPrimary target="view.parentView"}}>{{view.parentView.primary}}</button>{{/if}}' |
| ].join('')), |
| classNames: ['modal-footer', 'host-checks-update'], |
| progressWidth: function(){ |
| return 'width:'+App.router.get('wizardStep3Controller.checksUpdateProgress')+'%'; |
| }.property('App.router.wizardStep3Controller.checksUpdateProgress'), |
| isUpdateInProgress: function(){ |
| if((App.router.get('wizardStep3Controller.checksUpdateProgress') > 0) && |
| (App.router.get('wizardStep3Controller.checksUpdateProgress') < 100)){ |
| return true; |
| } |
| }.property('App.router.wizardStep3Controller.checksUpdateProgress'), |
| updateStatusClass:function(){ |
| var status = App.router.get('wizardStep3Controller.checksUpdateStatus'); |
| if(status === 'SUCCESS'){ |
| return 'text-success'; |
| } else if(status === 'FAILED'){ |
| return 'text-error'; |
| } else { |
| return null; |
| } |
| }.property('App.router.wizardStep3Controller.checksUpdateStatus'), |
| updateStatus:function(){ |
| var status = App.router.get('wizardStep3Controller.checksUpdateStatus'); |
| if(status === 'SUCCESS'){ |
| return Em.I18n.t('installer.step3.warnings.updateChecks.success'); |
| } else if(status === 'FAILED'){ |
| return Em.I18n.t('installer.step3.warnings.updateChecks.failed'); |
| } else { |
| return null; |
| } |
| }.property('App.router.wizardStep3Controller.checksUpdateStatus') |
| }), |
| |
| bodyClass: Ember.View.extend({ |
| templateName: require('templates/wizard/step3_host_warnings_popup'), |
| classNames: ['host-check'], |
| didInsertElement: function () { |
| Ember.run.next(this, function () { |
| this.$("[rel='HostsListTooltip']").tooltip({html: true, placement: "right"}); |
| this.$('#process .warning-name').tooltip({html: true, placement: "top"}); |
| }) |
| }.observes('content'), |
| warningsByHost: function () { |
| return App.router.get('wizardStep3Controller.warningsByHost'); |
| }.property('App.router.wizardStep3Controller.warningsByHost'), |
| warnings: function () { |
| return App.router.get('wizardStep3Controller.warnings'); |
| }.property('App.router.wizardStep3Controller.warnings'), |
| categories: function () { |
| return this.get('warningsByHost').mapProperty('name'); |
| }.property('warningsByHost'), |
| category: 'All Hosts', |
| categoryWarnings: function () { |
| return this.get('warningsByHost').findProperty('name', this.get('category')).warnings |
| }.property('warningsByHost', 'category'), |
| content: function () { |
| var categoryWarnings = this.get('categoryWarnings'); |
| return [ |
| Ember.Object.create({ |
| warnings: repoCategoryWarnings, |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.repositories'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.repositories.message'), |
| type: Em.I18n.t('common.issues'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.repositories'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.invalid'), |
| category: 'repositories' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'firewall'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.firewall'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.firewall.message'), |
| type: Em.I18n.t('common.issues'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.firewall'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.running'), |
| category: 'firewall' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'processes'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.process'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.processes.message'), |
| type: Em.I18n.t('common.process'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.processes'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.running'), |
| category: 'process' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'packages'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.package'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.packages.message'), |
| type: Em.I18n.t('common.package'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.packages'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.installed'), |
| category: 'package' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'fileFolders'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.fileAndFolder'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.fileFolders.message'), |
| type: Em.I18n.t('common.path'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.filesAndFolders'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.exists'), |
| category: 'fileFolders' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'services'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.service'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.services.message'), |
| type: Em.I18n.t('common.service'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.services'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.notRunning'), |
| category: 'service' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'users'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.user'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.users.message'), |
| type: Em.I18n.t('common.user'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.users'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.exists'), |
| category: 'user' |
| }), |
| Ember.Object.create({ |
| warnings: categoryWarnings.filterProperty('category', 'misc'), |
| title: Em.I18n.t('installer.step3.hostWarningsPopup.misc'), |
| message: Em.I18n.t('installer.step3.hostWarningsPopup.misc.message'), |
| type: Em.I18n.t('installer.step3.hostWarningsPopup.misc.umask'), |
| emptyName: Em.I18n.t('installer.step3.hostWarningsPopup.empty.misc'), |
| action: Em.I18n.t('installer.step3.hostWarningsPopup.action.exists'), |
| category: 'misc' |
| }) |
| ] |
| }.property('category', 'warningsByHost'), |
| |
| showHostsPopup: function (hosts) { |
| $('.tooltip').hide(); |
| App.ModalPopup.show({ |
| header: Em.I18n.t('installer.step3.hostWarningsPopup.allHosts'), |
| bodyClass: Ember.View.extend({ |
| hosts: hosts.context, |
| template: Ember.Handlebars.compile('<ul>{{#each host in view.hosts}}<li>{{host}}</li>{{/each}}</ul>') |
| }), |
| onPrimary: function () { |
| this.hide(); |
| }, |
| secondary: null |
| }); |
| }, |
| |
| onToggleBlock: function (category) { |
| this.$('#' + category.context.category).toggle('blind', 500); |
| }, |
| warningsNotice: function () { |
| var warnings = this.get('warnings'); |
| var warningsByHost = self.get('warningsByHost').slice(); |
| warningsByHost.shift(); |
| var issues = warnings.length + ' ' + (warnings.length === 1 ? Em.I18n.t('installer.step3.hostWarningsPopup.issue') : Em.I18n.t('installer.step3.hostWarningsPopup.issues')); |
| var hostsNumber = warningsByHost.length - warningsByHost.filterProperty('warnings.length', 0).length; |
| var hosts = hostsNumber + ' ' + (hostsNumber === 1 ? Em.I18n.t('installer.step3.hostWarningsPopup.host') : Em.I18n.t('installer.step3.hostWarningsPopup.hosts')); |
| return Em.I18n.t('installer.step3.hostWarningsPopup.summary').format(issues, hosts); |
| }.property('warnings', 'warningsByHost'), |
| /** |
| * generate detailed content to show it in new window |
| */ |
| contentInDetails: function () { |
| var content = this.get('content'); |
| var warningsByHost = this.get('warningsByHost').slice(); |
| warningsByHost.shift(); |
| var newContent = ''; |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.header') + new Date; |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.hosts'); |
| newContent += warningsByHost.filterProperty('warnings.length').mapProperty('name').join(' '); |
| if (content.findProperty('category', 'fileFolders').warnings.length) { |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.fileFolders'); |
| newContent += content.findProperty('category', 'fileFolders').warnings.mapProperty('name').join(' '); |
| } |
| if (content.findProperty('category', 'process').warnings.length) { |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.process'); |
| content.findProperty('category', 'process').warnings.forEach(function (process, i) { |
| process.hosts.forEach(function (host, j) { |
| if (!!i || !!j) { |
| newContent += ','; |
| } |
| newContent += '(' + host + ',' + process.user + ',' + process.pid + ')'; |
| }); |
| }); |
| } |
| if (content.findProperty('category', 'package').warnings.length) { |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.package'); |
| newContent += content.findProperty('category', 'package').warnings.mapProperty('name').join(' '); |
| } |
| if (content.findProperty('category', 'service').warnings.length) { |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.service'); |
| newContent += content.findProperty('category', 'service').warnings.mapProperty('name').join(' '); |
| } |
| if (content.findProperty('category', 'user').warnings.length) { |
| newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.user'); |
| newContent += content.findProperty('category', 'user').warnings.mapProperty('name').join(' '); |
| } |
| newContent += '</p>'; |
| return newContent; |
| }.property('content', 'warningsByHost'), |
| /** |
| * open new browser tab with detailed content |
| */ |
| openWarningsInDialog: function(){ |
| var newWindow = window.open(''); |
| var newDocument = newWindow.document; |
| newDocument.write(this.get('contentInDetails')); |
| newWindow.focus(); |
| } |
| }) |
| }) |
| }, |
| |
| registeredHostsPopup: function(){ |
| var self = this; |
| App.ModalPopup.show({ |
| header: Em.I18n.t('installer.step3.warning.registeredHosts').format(this.get('registeredHosts').length), |
| secondary: null, |
| bodyClass: Ember.View.extend({ |
| template: Ember.Handlebars.compile([ |
| '<p>{{view.message}}</p>', |
| '<ul>{{#each host in view.registeredHosts}}', |
| '<li>{{host}}</li>', |
| '{{/each}}</ul>' |
| ].join('')), |
| message: Em.I18n.t('installer.step3.registeredHostsPopup'), |
| registeredHosts: self.get('registeredHosts') |
| }) |
| }) |
| }, |
| |
| back: function () { |
| if (this.get('isInstallInProgress')) { |
| return; |
| } |
| App.router.send('back'); |
| } |
| |
| }); |
| |