ambari-web/app/controllers/wizard/step8_controller.js (1,405 lines of code) (raw):

/** * 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 stringUtils = require('utils/string_utils'); var fileUtils = require('utils/file_utils'); App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wizardDeployProgressControllerMixin, App.ConfigOverridable, App.ConfigsSaverMixin, { name: 'wizardStep8Controller', /** * @type {boolean} */ isAddService: Em.computed.equal('content.controllerName', 'addServiceController'), /** * @type {boolean} */ isAddHost: Em.computed.equal('content.controllerName', 'addHostController'), /** * @type {boolean} */ isInstaller: Em.computed.equal('content.controllerName', 'installerController'), /** * List of raw data about cluster that should be displayed * @type {Array} */ rawContent: [ { config_name: 'Admin', display_name: 'Admin Name', config_value: '' }, { config_name: 'cluster', display_name: 'Cluster Name', config_value: '' }, { config_name: 'hosts', display_name: 'Total Hosts', config_value: '' }, { config_name: 'Repo', display_name: 'Local Repository', config_value: '' } ], /** * List of data about cluster (based on formatted <code>rawContent</code>) * @type {Object[]} */ clusterInfo: [], /** * List of services with components assigned to hosts * @type {Object[]} */ services: [], /** * @type {Object[]} */ configs: [], /** * True if Kerberos is installed on the cluster and the kdc_type on the server is set to "none" * @type {Boolean} */ isManualKerberos: Em.computed.equal('App.router.mainAdminKerberosController.kdc_type', 'none'), showDownloadCsv: function () { return !!App.get('router.mainAdminKerberosController.kdc_type') }.property('App.router.mainAdminKerberosController.kdc_type'), /** * Should Submit button be disabled * @type {bool} */ isSubmitDisabled: false, /** * Should Back button be disabled * @type {bool} */ isBackBtnDisabled: false, /** * Is error appears while <code>ajaxQueue</code> executes * @type {bool} */ hasErrorOccurred: false, /** * Are services installed * Used to hide Deploy Progress Bar * @type {bool} */ servicesInstalled: false, /** * List of service config tags * @type {Object[]} */ serviceConfigTags: [], /** * Selected config group * @type {Object} */ selectedConfigGroup: null, /** * List of config groups * @type {Object[]} */ configGroups: [], /** * List of selected but not installed services * @type {Object[]} */ selectedServices: function () { return this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false); }.property('content.services.@each.isSelected','content.services.@each.isInstalled').cacheable(), /** * List of installed services * @type {Object[]} */ installedServices: Em.computed.filterBy('content.services', 'isInstalled', true), /** * Current cluster name * @type {string} */ clusterName: Em.computed.alias('content.cluster.name'), /** * List of existing cluster names * @type {string[]} */ clusterNames: [], /** * Number of completed cluster delete requests * @type {number} */ clusterDeleteRequestsCompleted: 0, /** * Number of existing repo_versions * @type {number} */ existingRepositoryVersions: 0, /** * Indicates if all cluster delete requests are completed * @type {boolean} */ isAllClusterDeleteRequestsCompleted: Em.computed.equalProperties('clusterDeleteRequestsCompleted', 'clusterNames.length'), /** * Error popup body views for clusters that couldn't be deleted * @type {App.AjaxDefaultErrorPopupBodyView[]} */ clusterDeleteErrorViews: [], /** * Clear current step data * @method clearStep */ clearStep: function () { this.get('services').clear(); this.get('configs').clear(); this.get('clusterInfo').clear(); this.get('serviceConfigTags').clear(); this.set('servicesInstalled', false); this.set('ajaxQueueLength', 0); this.set('ajaxRequestsQueue', App.ajaxQueue.create()); this.set('ajaxRequestsQueue.finishedCallback', this.ajaxQueueFinished); this.get('clusterDeleteErrorViews').clear(); this.set('clusterDeleteRequestsCompleted', 0); }, /** * Load current step data * @method loadStep */ loadStep: function () { this.clearStep(); if (this.get('content.serviceConfigProperties')) { this.formatProperties(); this.loadConfigs(); } this.loadClusterInfo(); this.loadServices(); this.set('isSubmitDisabled', false); this.set('isBackBtnDisabled', false); }, /** * replace whitespace character with coma between directories * @method formatProperties */ formatProperties: function () { this.get('content.serviceConfigProperties').forEach(function (_configProperty) { _configProperty.value = typeof _configProperty.value === "boolean" ? _configProperty.value.toString() : App.config.trimProperty(_configProperty, false); }); }, /** * Load all site properties * @method loadConfigs */ loadConfigs: function () { this.set('configs', this.get('content.serviceConfigProperties').filter(function (config) { return !config.group; })); }, /** * Format <code>content.hosts</code> from Object to Array * @returns {Array} * @method getRegisteredHosts */ getRegisteredHosts: function () { var allHosts = this.get('content.hosts'); var hosts = []; for (var hostName in allHosts) { if (allHosts.hasOwnProperty(hostName)) { if (allHosts[hostName].bootStatus === 'REGISTERED') { allHosts[hostName].hostName = allHosts[hostName].name; hosts.pushObject(allHosts[hostName]); } } } return hosts; }, /** * Load all info about cluster to <code>clusterInfo</code> variable * @method loadClusterInfo */ loadClusterInfo: function () { //Admin name var admin = this.rawContent.findProperty('config_name', 'Admin'); admin.config_value = App.db.getLoginName(); if (admin.config_value) { this.get('clusterInfo').pushObject(Ember.Object.create(admin)); } // cluster name var cluster = this.rawContent.findProperty('config_name', 'cluster'); cluster.config_value = this.get('content.cluster.name'); this.get('clusterInfo').pushObject(Ember.Object.create(cluster)); //hosts var newHostsCount = 0; var totalHostsCount = 0; var hosts = this.get('content.hosts'); for (var hostName in hosts) { newHostsCount += ~~!hosts[hostName].isInstalled; totalHostsCount++; } var totalHostsObj = this.rawContent.findProperty('config_name', 'hosts'); totalHostsObj.config_value = totalHostsCount + ' (' + newHostsCount + ' new)'; this.get('clusterInfo').pushObject(Em.Object.create(totalHostsObj)); //repo if (this.get('isAddService') || this.get('isAddHost')) { // For some stacks there is no info regarding stack versions to upgrade, e.g. HDP-2.1 if (App.StackVersion.find().get('content.length')) { this.loadRepoInfo(); } else { this.loadDefaultRepoInfo(); } } else { // from install wizard var selectedStack = App.Stack.find().findProperty('isSelected', true); var allRepos = []; if (selectedStack && selectedStack.get('operatingSystems')) { selectedStack.get('operatingSystems').forEach(function (os) { if (os.get('isSelected')) { os.get('repositories').forEach(function(repo) { if (repo.get('showRepo')) { allRepos.push(Em.Object.create({ base_url: repo.get('baseUrl'), os_type: repo.get('osType'), repo_id: repo.get('repoId') })); } }, this); } }, this); } allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName")); this.get('clusterInfo').set('useRedhatSatellite', selectedStack.get('useRedhatSatellite')); this.get('clusterInfo').set('repoInfo', allRepos); } }, /** * Load repo info for add Service/Host wizard review page * @return {$.ajax|null} * @method loadRepoInfo */ loadRepoInfo: function () { var stackName = App.get('currentStackName'); var currentRepoVersion; App.RepositoryVersion.find().forEach(function (repoVersion) { if (repoVersion.get('stackVersionType') === stackName && repoVersion.get('isCurrent') && repoVersion.get('isStandard')) { currentRepoVersion = repoVersion.get('repositoryVersion'); } }); if (!currentRepoVersion) { console.error('Error while getting current stack repository version'); } return App.ajax.send({ name: 'cluster.load_repo_version', sender: this, data: { stackName: stackName, repositoryVersion: currentRepoVersion }, success: 'loadRepoInfoSuccessCallback', error: 'loadRepoInfoErrorCallback' }); }, /** * Save all repo base URL of all OS type to <code>repoInfo<code> * @param {object} data * @method loadRepoInfoSuccessCallback */ loadRepoInfoSuccessCallback: function (data) { Em.assert('Current repo-version may be only one', data.items.length === 1); if (data.items.length) { var allRepos = this.generateRepoInfo(Em.getWithDefault(data, 'items.0.repository_versions.0.operating_systems', [])); allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName")); this.get('clusterInfo').set('repoInfo', allRepos); //if the property is missing, set as false this.get('clusterInfo').set('useRedhatSatellite', data.items[0].repository_versions[0].operating_systems[0].OperatingSystems.ambari_managed_repositories === false); } else { this.loadDefaultRepoInfo(); } }, /** * Generate list regarding info about OS versions and repositories. * * @param {Object{}} oses - OS array * @returns {Em.Object[]} */ generateRepoInfo: function(oses) { return oses.map(function(os) { return os.repositories.map(function (repository) { return Em.Object.create({ base_url: repository.Repositories.base_url, os_type: repository.Repositories.os_type, repo_id: repository.Repositories.repo_id }); }); }).reduce(function(p, c) { return p.concat(c); }); }, /** * Load repo info from stack. Used if installed stack doesn't have upgrade info. * * @returns {$.Deferred} * @method loadDefaultRepoInfo */ loadDefaultRepoInfo: function() { var nameVersionCombo = App.get('currentStackVersion').split('-'); return App.ajax.send({ name: 'cluster.load_repositories', sender: this, data: { stackName: nameVersionCombo[0], stackVersion: nameVersionCombo[1] }, success: 'loadDefaultRepoInfoSuccessCallback', error: 'loadRepoInfoErrorCallback' }); }, /** * @param {Object} data - JSON data from server * @method loadDefaultRepoInfoSuccessCallback */ loadDefaultRepoInfoSuccessCallback: function (data) { var allRepos = this.generateRepoInfo(Em.getWithDefault(data, 'items', [])); allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName")); this.get('clusterInfo').set('repoInfo', allRepos); //if the property is missing, set as false this.get('clusterInfo').set('useRedhatSatellite', data.items[0].OperatingSystems.ambari_managed_repositories === false); }, /** * @method loadRepoInfoErrorCallback */ loadRepoInfoErrorCallback: function () { var allRepos = []; allRepos.set('display_name', Em.I18n.t("installer.step8.repoInfo.displayName")); this.get('clusterInfo').set('repoInfo', allRepos); }, /** * Load all info about services to <code>services</code> variable * @method loadServices */ loadServices: function () { this.get('selectedServices').filterProperty('isHiddenOnSelectServicePage', false).forEach(function (service) { var serviceObj = Em.Object.create({ service_name: service.get('serviceName'), display_name: service.get('displayNameOnSelectServicePage'), service_components: Em.A([]) }); service.get('serviceComponents').forEach(function (component) { // show clients for services that have only clients components if ((component.get('isClient') || component.get('isRequiredOnAllHosts')) && !service.get('isClientOnlyService')) return; // no HA component if (component.get('isHAComponentOnly')) return; // skip if component is not allowed on single node cluster if (Object.keys(this.get('content.hosts')).length === 1 && component.get('isNotAllowedOnSingleNodeCluster')) return; var displayName; if (component.get('isClient')) { displayName = Em.I18n.t('common.clients') } else { // remove service name from component display name displayName = App.format.role(component.get('componentName'), false).replace(new RegExp('^' + service.get('serviceName') + '\\s', 'i'), ''); } var componentName = component.get('componentName'); var masterComponents = this.get('content.masterComponentHosts'); var isMasterComponentSelected = masterComponents.someProperty('component', componentName); var isMaster = component.get('isMaster'); if (!isMaster || isMasterComponentSelected) { serviceObj.get('service_components').pushObject(Em.Object.create({ component_name: component.get('isClient') ? Em.I18n.t('common.client').toUpperCase() : component.get('componentName'), display_name: displayName, component_value: this.assignComponentHosts(component) })); } }, this); if (service.get('customReviewHandler')) { for (var displayName in service.get('customReviewHandler')) { serviceObj.get('service_components').pushObject(Em.Object.create({ display_name: displayName, component_value: this.assignComponentHosts(Em.Object.create({ customHandler: service.get('customReviewHandler.' + displayName) })) })); } } this.get('services').pushObject(serviceObj); }, this); }, /** * Set <code>component_value</code> property to <code>component</code> * @param {Em.Object} component * @return {String} * @method assignComponentHosts */ assignComponentHosts: function (component) { var componentValue; if (component.get('customHandler')) { componentValue = this[component.get('customHandler')].call(this, component); } else { if (component.get('isMaster')) { componentValue = this.getMasterComponentValue(component.get('componentName')); } else { var componentName = component.get('isClient') ? Em.I18n.t('common.client').toUpperCase() : component.get('componentName'); var hostsLength = this.get('content.slaveComponentHosts') .findProperty('componentName', componentName).hosts.length; componentValue = hostsLength + Em.I18n.t('installer.step8.host' + (hostsLength > 1 ? 's' : '')); } } return componentValue; }, getMasterComponentValue: function (componentName) { var masterComponents = this.get('content.masterComponentHosts'); var hostsCount = masterComponents.filterProperty('component', componentName).length; return stringUtils.pluralize(hostsCount, masterComponents.findProperty('component', componentName).hostName, hostsCount + ' ' + Em.I18n.t('installer.step8.hosts')); }, loadHiveDbValue: function() { return this.loadDbValue('HIVE'); }, loadOozieDbValue: function() { return this.loadDbValue('OOZIE'); }, /** * Set displayed Hive DB value based on DB type * @method loadHiveDbValue */ loadDbValue: function (serviceName) { var serviceConfigProperties = this.get('content.serviceConfigProperties'); var dbFull = serviceConfigProperties.findProperty('name', serviceName.toLowerCase() + '_database'); //db = serviceConfigProperties.findProperty('name', serviceName.toLowerCase() + '_ambari_database'); //since db.value contains the intial default value of <service>_admin_database (MySQL) and not the actual db type selected, //ignore the value when displaying the database name on the summary page return dbFull ? dbFull.value : ''; }, /** * Set displayed HBase master value * @param {Object} hbaseMaster * @method loadHbaseMasterValue */ loadHbaseMasterValue: function (hbaseMaster) { var hbaseHostName = this.get('content.masterComponentHosts').filterProperty('component', hbaseMaster.component_name); if (hbaseHostName.length === 1) { hbaseMaster.set('component_value', hbaseHostName[0].hostName); } else { hbaseMaster.set('component_value', hbaseHostName[0].hostName + " " + Em.I18n.t('installer.step8.other').format(hbaseHostName.length - 1)); } }, /** * Set displayed ZooKeeper Server value * @param {Object} serverComponent * @method loadZkServerValue */ loadZkServerValue: function (serverComponent) { var zkHostNames = this.get('content.masterComponentHosts').filterProperty('component', serverComponent.component_name).length; var hostSuffix; if (zkHostNames === 1) { hostSuffix = Em.I18n.t('installer.step8.host'); } else { hostSuffix = Em.I18n.t('installer.step8.hosts'); } serverComponent.set('component_value', zkHostNames + hostSuffix); }, /** * Onclick handler for <code>next</code> button * @method submit * @return {void} */ submit: function () { var wizardController; if (!this.get('isSubmitDisabled')) { wizardController = App.router.get(this.get('content.controllerName')); wizardController.setLowerStepsDisable(wizardController.get('currentStep')); this.set('isSubmitDisabled', true); this.set('isBackBtnDisabled', true); this.showRestartWarnings() .done(this.checkKDCSession.bind(this)); } }, /** * Warn user about services that will be restarted during installation. * * @returns {$.Deferred} */ showRestartWarnings: function() { var self = this; var dfd = $.Deferred(); var wizardController = App.router.get(this.get('content.controllerName')); var selectedServiceNames = this.get('selectedServices').mapProperty('serviceName'); var installedServiceNames = this.get('installedServices').mapProperty('serviceName'); if (this.get('isAddService') && selectedServiceNames.contains('OOZIE')) { var affectedServices = ['HDFS', 'YARN'].filter(function(serviceName) { return installedServiceNames.contains(serviceName); }); if (affectedServices.length) { var serviceNames = affectedServices.length > 1 ? '<b>{0}</b> {1} <b>{2}</b>'.format(affectedServices[0], Em.I18n.t('and'), affectedServices[1]) : '<b>' + affectedServices[0] + '</b> '; App.ModalPopup.show({ encodeBody: false, header: Em.I18n.t('common.warning'), body: Em.I18n.t('installer.step8.services.restart.required').format(serviceNames, stringUtils.pluralize(affectedServices.length, Em.I18n.t('common.service').toLowerCase())), secondary: Em.I18n.t('common.cancel'), primary: Em.I18n.t('common.proceedAnyway'), onPrimary: function() { this.hide(); dfd.resolve(); }, onClose: function() { this.hide(); self.set('isSubmitDisabled', false); self.set('isBackBtnDisabled', false); wizardController.setStepsEnable(); dfd.reject(); }, onSecondary: function() { this.onClose(); } }); } else { dfd.resolve(); } } else { dfd.resolve(); } return dfd.promise(); }, checkKDCSession: function() { var self = this; var wizardController = App.router.get(this.get('content.controllerName')); if (!this.get('isInstaller')) { App.get('router.mainAdminKerberosController').getKDCSessionState(this.submitProceed.bind(this), function () { self.set('isSubmitDisabled', false); self.set('isBackBtnDisabled', false); wizardController.setStepsEnable(); if (self.get('isAddService')) { wizardController.setSkipSlavesStep(wizardController.getDBProperty('selectedServiceNames'), 3); } }); } else { this.submitProceed(); } }, /** * Prepare <code>ajaxQueue</code> and start to execute it * @method submitProceed */ submitProceed: function () { var self = this; this.set('clusterDeleteRequestsCompleted', 0); this.get('clusterDeleteErrorViews').clear(); if (this.get('isAddHost')) { App.router.get('addHostController').setLowerStepsDisable(4); } // checkpoint the cluster status on the server so that the user can resume from where they left off switch (this.get('content.controllerName')) { case 'installerController': App.clusterStatus.setClusterStatus({ clusterName: this.get('clusterName'), clusterState: 'CLUSTER_DEPLOY_PREP_2', wizardControllerName: this.get('content.controllerName'), localdb: App.db.data }); break; case 'addHostController': App.clusterStatus.setClusterStatus({ clusterName: this.get('clusterName'), clusterState: 'ADD_HOSTS_DEPLOY_PREP_2', wizardControllerName: this.get('content.controllerName'), localdb: App.db.data }); break; case 'addServiceController': App.clusterStatus.setClusterStatus({ clusterName: this.get('clusterName'), clusterState: 'ADD_SERVICES_DEPLOY_PREP_2', wizardControllerName: this.get('content.controllerName'), localdb: App.db.data }); break; default: break; } // delete any existing clusters to start from a clean slate // before creating a new cluster in install wizard // TODO: modify for multi-cluster support this.getExistingClusterNames().then(function () { var clusterNames = self.get('clusterNames'); if (self.get('isInstaller') && !App.get('testMode') && clusterNames.length) { self.deleteClusters(clusterNames); } else { self.getExistingVersions(); } }); }, /** * Get list of existing cluster names * @returns {object|null} * returns an array of existing cluster names. * returns an empty array if there are no existing clusters. * @method getExistingClusterNames */ getExistingClusterNames: function () { return App.ajax.send({ name: 'wizard.step8.existing_cluster_names', sender: this, success: 'getExistingClusterNamesSuccessCallBack', error: 'getExistingClusterNamesErrorCallback' }); }, /** * Save received list to <code>clusterNames</code> * @param {Object} data * @method getExistingClusterNamesSuccessCallBack */ getExistingClusterNamesSuccessCallBack: function (data) { var clusterNames = data.items.mapProperty('Clusters.cluster_name'); this.set('clusterNames', clusterNames); }, /** * If error appears, set <code>clusterNames</code> to <code>[]</code> * @method getExistingClusterNamesErrorCallback */ getExistingClusterNamesErrorCallback: function () { this.set('clusterNames', []); }, /** * Delete cluster by name * One request for one cluster! * @param {string[]} clusterNames * @method deleteClusters */ deleteClusters: function (clusterNames) { this.get('clusterDeleteErrorViews').clear(); clusterNames.forEach(function (clusterName, index) { App.ajax.send({ name: 'common.delete.cluster', sender: this, data: { name: clusterName, isLast: index === clusterNames.length - 1 }, success: 'deleteClusterSuccessCallback', error: 'deleteClusterErrorCallback' }); }, this); }, /** * Method to execute after successful cluster deletion * @method deleteClusterSuccessCallback */ deleteClusterSuccessCallback: function () { this.incrementProperty('clusterDeleteRequestsCompleted'); if (this.get('isAllClusterDeleteRequestsCompleted')) { if (this.get('clusterDeleteErrorViews.length')) { this.showDeleteClustersErrorPopup(); } else { this.getExistingVersions(); } } }, /** * Method to execute after failed cluster deletion * @param {object} request * @param {string} ajaxOptions * @param {string} error * @param {object} opt * @method deleteClusterErrorCallback */ deleteClusterErrorCallback: function (request, ajaxOptions, error, opt) { this.incrementProperty('clusterDeleteRequestsCompleted'); try { var json = JSON.parse(request.responseText); var message = json.message; } catch (err) { } this.get('clusterDeleteErrorViews').pushObject(App.AjaxDefaultErrorPopupBodyView.create({ url: opt.url, type: opt.type, status: request.status, message: message })); if (this.get('isAllClusterDeleteRequestsCompleted')) { this.showDeleteClustersErrorPopup(); } }, /** * Show error popup if cluster deletion failed * @method showDeleteClustersErrorPopup */ showDeleteClustersErrorPopup: function () { var self = this; this.setProperties({ isSubmitDisabled: false, isBackBtnDisabled: false }); App.ModalPopup.show({ header: Em.I18n.t('common.error'), secondary: false, onPrimary: function () { this.hide(); }, bodyClass: Em.ContainerView.extend({ childViews: self.get('clusterDeleteErrorViews') }) }); }, /** * Get existing repo_versions * @method getExistingVersions */ getExistingVersions: function () { return App.ajax.send({ name: 'wizard.get_version_definitions', sender: this, success: 'getExistingVersionsSuccessCallback' }); }, /** * @param {Object} data * @method getExistingVersionsSuccessCallback */ getExistingVersionsSuccessCallback: function (data) { if (this.get('isInstaller') && !App.get('testMode') && data.items.length) { this.set('existingRepositoryVersions', data.items.length); this.deleteExistingVersions(data.items); } else { this.startDeploy(); } }, /** * Delete existing repo_versions * @param {Array} versions * @method deleteExistingVersions */ deleteExistingVersions: function (versions) { versions.forEach(function (version) { App.ajax.send({ name: 'wizard.delete_repository_versions', sender: this, data: { id: version.VersionDefinition.id, stackName: version.VersionDefinition.stack_name, stackVersion: version.VersionDefinition.stack_version }, success: 'deleteExistingVersionsSuccessCallback' }); }, this); }, /** * Method to execute after successful version deletion * @method deleteExistingVersionsSuccessCallback */ deleteExistingVersionsSuccessCallback: function () { this.decrementProperty('existingRepositoryVersions'); if (this.get('existingRepositoryVersions') === 0) { this.startDeploy(); } }, /** * updates kerberosDescriptorConfigs * @method updateKerberosDescriptor */ updateKerberosDescriptor: function(instant) { var kerberosDescriptor = this.get('wizardController').getDBProperty('kerberosDescriptorConfigs'); var descriptorExists = this.get('wizardController').getDBProperty('isClusterDescriptorExists') === true; var ajaxOpts = { name: descriptorExists ? 'admin.kerberos.cluster.artifact.update' : 'admin.kerberos.cluster.artifact.create', dataType:'text', data: { artifactName: 'kerberos_descriptor', data: { artifact_data: this.removeIdentityReferences(kerberosDescriptor) } } }; if (instant) { ajaxOpts.sender = this; App.ajax.send(ajaxOpts); } else { this.addRequestToAjaxQueue(ajaxOpts); } }, /** * To Start deploy process * @method startDeploy */ startDeploy: function () { if (!this.get('isInstaller')) { this._startDeploy(); } else { var installerController = App.router.get('installerController'); var versionData = installerController.getSelectedRepoVersionData(); if (versionData) { var self = this; installerController.postVersionDefinitionFileStep8(versionData.isXMLdata, versionData.data).done(function (versionInfo) { if (versionInfo.id && versionInfo.stackName && versionInfo.stackVersion) { var selectedStack = App.Stack.find().findProperty('isSelected', true); if (selectedStack) { selectedStack.set('versionInfoId', versionInfo.id); } installerController.updateRepoOSInfo(versionInfo, selectedStack).done(function() { self._startDeploy(); }); } }); } else { this._startDeploy(); } } }, /** * Start deploy process * @method startDeploy */ _startDeploy: function () { this.createCluster(); this.createSelectedServices(); if (!this.get('isAddHost')) { if (this.get('isAddService')) { // for manually enabled Kerberos descriptor was updated on transition to this step if (App.get('isKerberosEnabled') && !this.get('isManualKerberos')) { this.updateKerberosDescriptor(); } var fileNamesToUpdate = this.get('wizardController').getDBProperty('fileNamesToUpdate').uniq(); if (fileNamesToUpdate && fileNamesToUpdate.length) { this.applyConfigurationsToCluster(this.generateDesiredConfigsJSON(this.get('configs'), fileNamesToUpdate)); } } this.createConfigurations(); this.applyConfigurationsToCluster(this.get('serviceConfigTags')); } this.createComponents(); this.registerHostsToCluster(); this.createConfigurationGroups(); this.createMasterHostComponents(); this.createSlaveAndClientsHostComponents(); if (this.get('isAddService')) { this.createAdditionalClientComponents(); } this.createAdditionalHostComponents(); this.set('ajaxQueueLength', this.get('ajaxRequestsQueue.queue.length')); this.get('ajaxRequestsQueue').start(); this.showLoadingIndicator(); }, /** * ******************************************************************* * The following create* functions are called upon submitting Step 8. * ******************************************************************* */ /** * Create cluster using selected stack version * Queued request * @method createCluster */ createCluster: function () { if (!this.get('isInstaller')) return; var stackVersion = this.get('content.installOptions.localRepo') ? App.currentStackVersion.replace(/(-\d+(\.\d)*)/ig, "Local$&") : App.currentStackVersion; this.addRequestToAjaxQueue({ name: 'wizard.step8.create_cluster', data: { data: JSON.stringify({ "Clusters": {"version": stackVersion}}) }, success: 'createClusterSuccess' }); }, createClusterSuccess: function (data, xhr, params) { App.set('clusterName', params.cluster); }, /** * Create selected to install services * Queued request * Skipped if no services where selected! * @method createSelectedServices */ createSelectedServices: function () { var data = this.createSelectedServicesData(); if (!data.length) return; this.addRequestToAjaxQueue({ name: 'wizard.step8.create_selected_services', data: { data: JSON.stringify(data) } }); }, /** * Format data for <code>createSelectedServices</code> request * @returns {Object[]} * @method createSelectedServicesData */ createSelectedServicesData: function () { var selectedStack; if (this.get('isInstaller')) { selectedStack = App.Stack.find().findProperty('isSelected', true); } return this.get('selectedServices').map(service => selectedStack ? {"ServiceInfo": { "service_name": service.get('serviceName'), "desired_repository_version_id": selectedStack.get('versionInfoId') }} : {"ServiceInfo": { "service_name": service.get('serviceName') }}); }, /** * Create components for selected services * Queued requests * One request for each service! * @method createComponents */ createComponents: function () { var serviceComponents = App.StackServiceComponent.find().filterProperty('isInstallable'); this.get('selectedServices').forEach(function (_service) { var serviceName = _service.get('serviceName'); var componentsData = serviceComponents.filterProperty('serviceName', serviceName).map(function (_component) { return { "ServiceComponentInfo": { "component_name": _component.get('componentName') } }; }); // Service must be specified in terms of a query for creating multiple components at the same time. // See AMBARI-1018. this.addRequestToCreateComponent(componentsData, serviceName); }, this); if (this.get('isAddHost')) { var allServiceComponents = []; var services = App.Service.find().mapProperty('serviceName'); services.forEach(function(_service){ var _serviceComponents = App.Service.find(_service).get('serviceComponents'); allServiceComponents = allServiceComponents.concat(_serviceComponents); }, this); this.get('content.slaveComponentHosts').forEach(function (component) { if (component.componentName !== 'CLIENT' && !allServiceComponents.contains(component.componentName)) { this.addRequestToCreateComponent( [{"ServiceComponentInfo": {"component_name": component.componentName}}], App.StackServiceComponent.find().findProperty('componentName', component.componentName).get('serviceName') ); } }, this); this.get('content.clients').forEach(function (component) { if (!allServiceComponents.contains(component.component_name)) { this.addRequestToCreateComponent( [{"ServiceComponentInfo": {"component_name": component.component_name}}], App.StackServiceComponent.find().findProperty('componentName', component.component_name).get('serviceName') ); } }, this); } }, /** * Add request to ajax queue to create service component * @param componentsData * @param serviceName */ addRequestToCreateComponent: function (componentsData, serviceName) { this.addRequestToAjaxQueue({ name: 'wizard.step8.create_components', data: { data: JSON.stringify({"components": componentsData}), serviceName: serviceName } }); }, /** * Error callback for new service component request * So, if component doesn't exist we should create it * @param {object} request * @param {object} ajaxOptions * @param {string} error * @param {object} opt * @param {object} params * @method newServiceComponentErrorCallback */ newServiceComponentErrorCallback: function (request, ajaxOptions, error, opt, params) { this.addRequestToAjaxQueue({ name: 'wizard.step8.create_components', data: { serviceName: params.serviceName, data: JSON.stringify({ "components": [ { "ServiceComponentInfo": { "component_name": params.componentName } } ] }) } }); }, /** * Register hosts * Queued request * @method registerHostsToCluster */ registerHostsToCluster: function () { var data = this.createRegisterHostData(); if (!data.length) return; this.addRequestToAjaxQueue({ name: 'wizard.step8.register_host_to_cluster', data: { data: JSON.stringify(data) } }); }, /** * Format request-data for <code>registerHostsToCluster</code> * @returns {Object} * @method createRegisterHostData */ createRegisterHostData: function () { return this.getRegisteredHosts().filterProperty('isInstalled', false).map(function (host) { return {"Hosts": { "host_name": host.hostName}}; }); }, /** * Register new master components * @uses registerHostsToComponent * @method createMasterHostComponents */ createMasterHostComponents: function () { var masterOnAllHosts = []; this.get('content.services').filterProperty('isSelected').forEach(function (service) { service.get('serviceComponents').filterProperty('isRequiredOnAllHosts').forEach(function (component) { if (component.get('isMaster')) { masterOnAllHosts.push(component.get('componentName')); } }, this); }, this); // create master components for only selected services. var selectedMasterComponents = this.get('content.masterComponentHosts').filter(function (_component) { return this.get('selectedServices').mapProperty('serviceName').contains(_component.serviceId) }, this); selectedMasterComponents.mapProperty('component').uniq().forEach(function (component) { var hostNames = []; if (masterOnAllHosts.length > 0) { var compOnAllHosts = false; for (var i=0; i < masterOnAllHosts.length; i++) { if (component === masterOnAllHosts[i]) { compOnAllHosts = true; break; } } if (!compOnAllHosts) { hostNames = selectedMasterComponents.filterProperty('component', component).filterProperty('isInstalled', false).mapProperty('hostName'); this.registerHostsToComponent(hostNames, component); } } else { hostNames = selectedMasterComponents.filterProperty('component', component).filterProperty('isInstalled', false).mapProperty('hostName'); this.registerHostsToComponent(hostNames, component); } }, this); }, getClientsMap: function (flag) { var clients = App.StackServiceComponent.find().filterProperty('isClient'), clientsMap = {}, dependedComponents = flag ? App.StackServiceComponent.find().filterProperty(flag) : App.StackServiceComponent.find(); clients.forEach(function (client) { var clientName = client.get('componentName'); clientsMap[clientName] = Em.A([]); dependedComponents.forEach(function (component) { if (component.dependsOn(client)) clientsMap[clientName].push(component.get('componentName')); }); if (!clientsMap[clientName].length) delete clientsMap[clientName]; }); return clientsMap; }, /** * Register slave components and clients * @uses registerHostsToComponent * @method createSlaveAndClientsHostComponents */ createSlaveAndClientsHostComponents: function () { var masterHosts = this.get('content.masterComponentHosts'); var slaveHosts = this.get('content.slaveComponentHosts'); var clients = this.get('content.clients').filterProperty('isInstalled', false); var slaveOnAllHosts = []; var clientOnAllHosts = []; this.get('content.services').filterProperty('isSelected').forEach(function (service) { service.get('serviceComponents').filterProperty('isRequiredOnAllHosts').forEach(function (component) { if (component.get('isClient')) { clientOnAllHosts.push(component.get('componentName')); } else if (component.get('isSlave')) { slaveOnAllHosts.push(component.get('componentName')); } }, this); }, this); /** * Determines on which hosts client should be installed (based on availability of master components on hosts) * @type {Object} * Format: * <code> * { * CLIENT1: Em.A([MASTER1, MASTER2, ...]), * CLIENT2: Em.A([MASTER3, MASTER1, ...]) * ... * } * </code> */ var clientsToMasterMap = this.getClientsMap('isMaster'), clientsToSlaveMap = this.getClientsMap('isSlave'); slaveHosts.forEach(function (_slave) { var hostNames = []; var compOnAllHosts; if (_slave.componentName !== 'CLIENT') { if (slaveOnAllHosts.length > 0) { compOnAllHosts = false; for (var i=0; i < slaveOnAllHosts.length; i++) { if (_slave.componentName === slaveOnAllHosts[i]) { // component with ALL cardinality should not // registerHostsToComponent in createSlaveAndClientsHostComponents compOnAllHosts = true; break; } } if (!compOnAllHosts) { hostNames = _slave.hosts.filterProperty('isInstalled', false).mapProperty('hostName'); this.registerHostsToComponent(hostNames, _slave.componentName); } } else { hostNames = _slave.hosts.filterProperty('isInstalled', false).mapProperty('hostName'); this.registerHostsToComponent(hostNames, _slave.componentName); } } else { clients.forEach(function (_client) { hostNames = _slave.hosts.mapProperty('hostName'); // The below logic to install clients to existing/New master hosts should not be applied to Add Host wizard. // This is with the presumption that Add Host controller does not add any new Master component to the cluster if (!this.get('isAddHost')) { if (clientsToMasterMap[_client.component_name]) { clientsToMasterMap[_client.component_name].forEach(function (componentName) { masterHosts.filterProperty('component', componentName).forEach(function (_masterHost) { hostNames.pushObject(_masterHost.hostName); }); }); } } if (clientsToSlaveMap[_client.component_name]) { clientsToSlaveMap[_client.component_name].forEach(function (componentName) { slaveHosts.filterProperty('componentName', componentName).forEach(function (slaveHost) { hostNames = hostNames.concat(slaveHost.hosts.mapProperty('hostName')).uniq(); }); }); } if (clientOnAllHosts.length > 0) { compOnAllHosts = false; for (var i=0; i < clientOnAllHosts.length; i++) { if (_client.component_name === clientOnAllHosts[i]) { // component with ALL cardinality should not // registerHostsToComponent in createSlaveAndClientsHostComponents compOnAllHosts = true; break; } } if (!compOnAllHosts) { hostNames = hostNames.uniq(); this.registerHostsToComponent(hostNames, _client.component_name); } } else { hostNames = hostNames.uniq(); this.registerHostsToComponent(hostNames, _client.component_name); } }, this); } }, this); }, /** * This function is specific to addServiceController * Newly introduced master components requires some existing client components to be hosted along with them */ createAdditionalClientComponents: function () { var masterHosts = this.get('content.masterComponentHosts'); var clientHosts = []; if (this.get('content.slaveComponentHosts').someProperty('componentName', 'CLIENT')) { clientHosts = this.get('content.slaveComponentHosts').findProperty('componentName', 'CLIENT').hosts; } var clients = this.get('content.clients').filterProperty('isInstalled', false); var clientsToMasterMap = this.getClientsMap('isMaster'); var clientsToClientMap = this.getClientsMap('isClient'); var installedClients = []; // Get all the installed Client components this.get('content.services').filterProperty('isInstalled').forEach(function (_service) { var serviceClients = App.StackServiceComponent.find().filterProperty('serviceName', _service.get('serviceName')).filterProperty('isClient'); serviceClients.forEach(function (client) { installedClients.push(client.get('componentName')); }, this); }, this); // Check if there is a dependency for being co-hosted between existing client and selected new master installedClients.forEach(function (_clientName) { if (clientsToMasterMap[_clientName] || clientsToClientMap[_clientName]) { var hostNames = []; if (clientsToMasterMap[_clientName]) { clientsToMasterMap[_clientName].forEach(function (componentName) { masterHosts.filterProperty('component', componentName).filterProperty('isInstalled', false).forEach(function (_masterHost) { hostNames.pushObject(_masterHost.hostName); }, this); }, this); } if (clientsToClientMap[_clientName]) { clientsToClientMap[_clientName].forEach(function (componentName) { clientHosts.forEach(function (_clientHost) { var host = this.get('content.hosts')[_clientHost.hostName]; var isClientSelected = clients.someProperty('component_name', componentName); if (host.isInstalled && isClientSelected && !host.hostComponents.someProperty('HostRoles.component_name', componentName)) { hostNames.pushObject(_clientHost.hostName); } }, this); }, this); } hostNames = hostNames.uniq(); if (hostNames.length > 0) { // If a dependency for being co-hosted is derived between existing client and selected new master but that // dependency is already satisfied in the cluster then disregard the derived dependency this.removeClientsFromList(_clientName, hostNames); this.registerHostsToComponent(hostNames, _clientName); if(hostNames.length > 0) { this.get('content.additionalClients').pushObject({hostNames: hostNames, componentName: _clientName}); } } } }, this); }, /** * * @param clientName * @param hostList */ removeClientsFromList: function (clientName, hostList) { var clientHosts = []; var installedHosts = this.get('content.hosts'); for (var hostName in installedHosts) { if (installedHosts[hostName].isInstalled) { if (installedHosts[hostName].hostComponents.mapProperty('HostRoles.component_name').contains(clientName)) { clientHosts.push(hostName); } } } if (clientHosts.length > 0) { clientHosts.forEach(function (hostName) { if (hostList.contains(hostName)) { hostList.splice(hostList.indexOf(hostName), 1); } }, this); } }, /** * Register additional components * Based on availability of some services * @uses registerHostsToComponent * @method createAdditionalHostComponents */ createAdditionalHostComponents: function () { var masterHosts = this.get('content.masterComponentHosts'); // add all components with cardinality == ALL of selected services var registeredHosts = this.getRegisteredHosts(); var notInstalledHosts = registeredHosts.filterProperty('isInstalled', false); this.get('content.services').filterProperty('isSelected').forEach(function (service) { service.get('serviceComponents').filterProperty('isRequiredOnAllHosts').forEach(function (component) { if (service.get('isInstalled') && notInstalledHosts.length) { this.registerHostsToComponent(notInstalledHosts.mapProperty('hostName'), component.get('componentName')); } else if (!service.get('isInstalled') && registeredHosts.length) { this.registerHostsToComponent(registeredHosts.mapProperty('hostName'), component.get('componentName')); } }, this); }, this); // add MySQL Server if Hive is selected var hiveService = this.get('content.services').filterProperty('isSelected', true).filterProperty('isInstalled', false).findProperty('serviceName', 'HIVE'); if (hiveService) { var hiveDb = this.get('content.serviceConfigProperties').findProperty('name', 'hive_database'); if (hiveDb.value === "New MySQL Database") { this.registerHostsToComponent(masterHosts.filterProperty('component', 'HIVE_SERVER').mapProperty('hostName'), 'MYSQL_SERVER'); } else if (hiveDb.value === "New PostgreSQL Database") { this.registerHostsToComponent(masterHosts.filterProperty('component', 'HIVE_SERVER').mapProperty('hostName'), 'POSTGRESQL_SERVER'); } } }, /** * Register component to hosts * Queued request * @param {String[]} hostNames * @param {String} componentName * @method registerHostsToComponent */ registerHostsToComponent: function (hostNames, componentName) { if (!hostNames.length) return; var queryStr = ''; hostNames.forEach(function (hostName) { queryStr += 'Hosts/host_name=' + hostName + '|'; }); //slice off last symbol '|' queryStr = queryStr.slice(0, -1); var data = { "RequestInfo": { "query": queryStr }, "Body": { "host_components": [ { "HostRoles": { "component_name": componentName } } ] } }; this.addRequestToAjaxQueue({ name: 'wizard.step8.register_host_to_component', data: { data: JSON.stringify(data) } }); }, /** * Create config objects for cluster and services * @method createConfigurations */ createConfigurations: function () { if (this.get('isInstaller')) { /** add cluster-env **/ this.get('serviceConfigTags').pushObject(this.createDesiredConfig('cluster-env', this.get('configs').filterProperty('filename', 'cluster-env.xml'))); } this.get('selectedServices').forEach(function (service) { Object.keys(service.get('configTypes')).forEach(function (type) { if (!this.get('serviceConfigTags').someProperty('type', type)) { var configs = this.get('configs').filterProperty('filename', App.config.getOriginalFileName(type)); var serviceConfigNote = this.getServiceConfigNote(type, service.get('displayName')); this.get('serviceConfigTags').pushObject(this.createDesiredConfig(type, configs, serviceConfigNote)); } }, this); }, this); this.createNotification(); }, /** * Get config version message * * @param type * @param serviceDisplayName * @returns {*} */ getServiceConfigNote: function(type, serviceDisplayName) { return this.get('isAddService') && type === 'core-site' ? Em.I18n.t('dashboard.configHistory.table.notes.addService') : Em.I18n.t('dashboard.configHistory.table.notes.default').format(serviceDisplayName); }, /** * Send <code>serviceConfigTags</code> to server * Queued request * One request for each service config tag * @param serviceConfigTags * @method applyConfigurationsToCluster */ applyConfigurationsToCluster: function (serviceConfigTags) { var allServices = this.get('installedServices').concat(this.get('selectedServices')); var allConfigData = []; allServices.forEach(function (service) { var serviceConfigData = []; Object.keys(service.get('configTypesRendered')).forEach(function (type) { var serviceConfigTag = serviceConfigTags.findProperty('type', type); if (serviceConfigTag) { serviceConfigData.pushObject(serviceConfigTag); } }, this); if (serviceConfigData.length) { allConfigData.pushObject(JSON.stringify({ Clusters: { desired_config: serviceConfigData.map(function(item) { var props = {}; Em.keys(item.properties).forEach(function(propName) { if (item.properties[propName] !== null) { props[propName] = item.properties[propName]; } }); item.properties = props; return item; }) } })); } }, this); var clusterConfig = serviceConfigTags.findProperty('type', 'cluster-env'); if (clusterConfig) { allConfigData.pushObject(JSON.stringify({ Clusters: { desired_config: [clusterConfig] } })); } this.addRequestToAjaxQueue({ name: 'common.across.services.configurations', data: { data: '[' + allConfigData.toString() + ']' } }); }, /** * Create and update config groups * @method createConfigurationGroups */ createConfigurationGroups: function () { var configGroups = this.get('content.configGroups').filterProperty('is_default', false); var groupsToDelete = App.router.get(this.get('content.controllerName')).getDBProperty('groupsToDelete'); if (groupsToDelete && groupsToDelete.length > 0) { this.removeInstalledServicesConfigurationGroups(groupsToDelete); } configGroups.forEach(function (configGroup) { if (configGroup.is_for_update || configGroup.is_temporary) { this.saveGroup(configGroup.properties, configGroup, this.getServiceConfigNote('', configGroup.service_id)); } }, this); App.ServiceConfigGroup.deleteTemporaryRecords(); }, /** * add request to create config group to queue * * @param data * @method createConfigGroup */ createConfigGroup: function(data) { this.addRequestToAjaxQueue({ name: 'wizard.step8.apply_configuration_groups', sender: this, data: { data: JSON.stringify(data) } }); }, /** * add request to update config group to queue * * @param data {Object} * @method updateConfigGroup */ updateConfigGroup: function (data) { this.addRequestToAjaxQueue({ name: 'config_groups.update_config_group', sender: this, data: { id: data.ConfigGroup.id, configGroup: data } }); }, /** * Delete selected config groups * @param {Object[]} groupsToDelete * @method removeInstalledServicesConfigurationGroups */ removeInstalledServicesConfigurationGroups: function (groupsToDelete) { var self = this; groupsToDelete.forEach(function (item) { self.deleteConfigurationGroup(Em.Object.create(item)); }); }, /** * Selected and installed services * @override */ currentServices: function() { return this.get('installedServices').concat(this.get('selectedServices')); }.property('installedServices.length', 'selectedServices.length'), /** * Add handling GLUSTREFS properties * @param property * @returns {*} * @override */ formatValueBeforeSave: function(property) { if (this.formatGLUSTERFSProperties(Em.get(property, 'filename'))) { switch (property.name) { case "fs.default.name": return this.get('configs').someProperty('name', 'fs_glusterfs_default_name') ? this.get('configs').findProperty('name', 'fs_glusterfs_default_name').value : null; case "fs.defaultFS": return this.get('configs').someProperty('name', 'glusterfs_defaultFS_name') ? this.get('configs').findProperty('name', 'glusterfs_defaultFS_name').value : null; } } return this._super(property); }, /** * Defines if some GLUSTERFS properties should be changed * * @param {String} type * @returns {boolean} */ formatGLUSTERFSProperties: function(type) { return App.config.getConfigTagFromFileName(type) === 'core-site' && this.get('installedServices').concat(this.get('selectedServices')).someProperty('serviceName', 'GLUSTERFS'); }, /** * Create one Alert Notification (if user select this on step7) * Only for Install Wizard and stack * @method createNotification */ createNotification: function () { if (!this.get('isInstaller')) return; var miscConfigs = this.get('configs').filterProperty('serviceName', 'MISC'), createNotification = miscConfigs.findProperty('name', 'create_notification').value; if (createNotification !== 'yes') return; var predefinedNotificationConfigNames = require('data/configs/alert_notification').mapProperty('name'), configsForNotification = this.get('configs').filterProperty('filename', 'alert_notification'); var properties = {}, names = [ 'ambari.dispatch.recipients', 'mail.smtp.host', 'mail.smtp.port', 'mail.smtp.from', 'mail.smtp.starttls.enable', 'mail.smtp.startssl.enable' ]; if (miscConfigs.findProperty('name', 'smtp_use_auth').value == 'true') { // yes, it's not converted to boolean names.pushObjects(['ambari.dispatch.credential.username', 'ambari.dispatch.credential.password']); } names.forEach(function (name) { properties[name] = miscConfigs.findProperty('name', name).value; }); properties['ambari.dispatch.recipients'] = properties['ambari.dispatch.recipients'].replace(/\s/g, '').split(','); configsForNotification.forEach(function (config) { if (predefinedNotificationConfigNames.contains(config.name)) return; properties[config.name] = config.value; }); var apiObject = { AlertTarget: { name: 'Initial Notification', description: 'Notification created during cluster installing', global: true, notification_type: 'EMAIL', alert_states: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'], properties: properties } }; this.addRequestToAjaxQueue({ name: 'alerts.create_alert_notification', data: { urlParams: 'overwrite_existing=true', data: apiObject } }); }, /** * Should ajax-queue progress bar be displayed * @method showLoadingIndicator */ showLoadingIndicator: function () { return App.ModalPopup.show({ header: Em.I18n.t('installer.step8.deployPopup.header'), showFooter: false, showCloseButton: false, bodyClass: Em.View.extend({ templateName: require('templates/wizard/step8/step8_log_popup'), controllerBinding: 'App.router.wizardStep8Controller', /** * Css-property for progress-bar * @type {string} */ barWidth: '', progressBarClass: 'progress log_popup', /** * Popup-message * @type {string} */ message: '', /** * Set progress bar width and popup message when ajax-queue requests are processed * @method ajaxQueueChangeObs */ ajaxQueueChangeObs: function () { var length = this.get('controller.ajaxQueueLength'); var left = this.get('controller.ajaxRequestsQueue.queue.length'); this.set('barWidth', 'width: ' + (length - left) / length * 100 + '%;'); this.set('message', Em.I18n.t('installer.step8.deployPopup.message').format(length - left, length)); }.observes('controller.ajaxQueueLength', 'controller.ajaxRequestsQueue.queue.length'), /** * Hide popup when ajax-queue is finished * @method autoHide */ autoHide: function () { if (this.get('controller.servicesInstalled')) { this.get('parentView').hide(); } }.observes('controller.servicesInstalled'), ajaxQueueErrorAppears: function () { if (this.get('controller.hasErrorOccurred')) { this.get('parentView').onClose(); } }.observes('controller.hasErrorOccurred') }) }); }, getComponentsForHost: function(host) { if(!host.hostComponents) { App.router.get('installerController').get('allHosts'); } var componentNameDetail = []; host.hostComponents.mapProperty('componentName').forEach(function (componentName) { if(componentName === 'CLIENT') { this.get('content.clients').mapProperty('component_name').forEach(function (clientComponent) { componentNameDetail.push({ name : clientComponent }); }, this); return; } componentNameDetail.push({ name : componentName }); }, this); return componentNameDetail; }, getPropertyAttributesForConfigType : function(configs) { //Currently only looks for final properties, if any var finalProperties = configs.filterProperty('isFinal', 'true'); var propertyAttributes = {}; finalProperties.forEach(function (finalProperty) { propertyAttributes[finalProperty['name']] = "true"; }); var finalPropertyMap = {}; if (!App.isEmptyObject(finalProperties)) { finalPropertyMap = { "isFinal": propertyAttributes }; } return finalPropertyMap; }, getConfigurationDetailsForConfigType: function(configs) { var configDetails = {}; var self = this; configs.forEach(function (propertyObj) { configDetails[propertyObj['name']] = propertyObj['value']; }, this); var configurationsDetails = { "properties_attributes": self.getPropertyAttributesForConfigType(configs), "properties": configDetails }; return configurationsDetails; }, hostInExistingHostGroup: function (newHost, host_groups) { var hostGroupMatched = false; host_groups.some(function (existingHostGroup) { if(!hostGroupMatched) { var fqdnInHostGroup = existingHostGroup.hosts[0].fqdn; var componentsInExistingHostGroup = this.getRegisteredHosts().filterProperty('hostName', fqdnInHostGroup)[0].hostComponents; if(componentsInExistingHostGroup.length !== newHost.hostComponents.length) { return; } else { var componentMismatch = false; componentsInExistingHostGroup.forEach(function (componentInExistingHostGroup, index) { if(!componentMismatch) { if(!newHost.hostComponents.mapProperty('componentName').includes(componentInExistingHostGroup.componentName)) { componentMismatch = true; } } }); if(!componentMismatch) { hostGroupMatched = true; existingHostGroup["cardinality"] = parseInt(existingHostGroup["cardinality"]) + 1; existingHostGroup.hosts.push({"fqdn" : newHost.hostName}); return true; } } } }, this); return hostGroupMatched; }, hostInChildHostGroup: function (presentHostGroup, configGroupName, hostInConfigGroup) { return presentHostGroup['childHostGroups'].some(function (childHostGroup) { //Check if childHostGroup name is same as this configgroupname, if yes, update childHostGroup else, compare with other childhostgroups if(childHostGroup.configGroupName === configGroupName) { childHostGroup.hosts.push( { "fqdn" : hostInConfigGroup } ); childHostGroup['cardinality'] = childHostGroup['cardinality'] + 1; return true; } }); }, /** * Confirmation popup before generate blueprint */ generateBlueprintConfirmation: function () { var self = this; return App.showConfirmationPopup(function () { self.generateBlueprint(); }, Em.I18n.t('installer.step8.generateBlueprint.popup.msg').format(App.clusterStatus.clusterName) ); }, generateBlueprint: function () { console.log("Prepare blueprint for download..."); var self = this; //service configurations var totalConf = []; //Add cluster-env var clusterEnv = this.get('configs').filterProperty('filename', 'cluster-env.xml'); var configurations = {}; configurations["cluster-env"] = self.getConfigurationDetailsForConfigType(clusterEnv); totalConf.push(configurations); //Add configurations for selected services this.get('selectedServices').forEach(function (service) { Object.keys(service.get('configTypes')).forEach(function (type) { if (!this.get('serviceConfigTags').someProperty('type', type)) { var configs = this.get('configs').filterProperty('filename', App.config.getOriginalFileName(type)); var configurations = {}; configurations[type] = self.getConfigurationDetailsForConfigType(configs); totalConf.push(configurations); } }, this); }, this); var host_groups = []; var cluster_template_host_groups = []; var counter = 0; this.getRegisteredHosts().filterProperty('isInstalled', false).map(function (host) { if(self.hostInExistingHostGroup(host, host_groups)) { return; } //Create new host_group if host is not mapped to existing host_groups var hostGroupId = "host_group_" + counter; var hostListForGroup = []; hostListForGroup.push({ "fqdn": host.hostName }); var hostGroupDetail = { "name": hostGroupId, "components": self.getComponentsForHost(host), "hosts": hostListForGroup, "cardinality" : 1 }; hostGroupDetail.toJSON = function () { var hostGroupDetailResult = _.omit(this, [ "hosts", "childHostGroups" ]); hostGroupDetailResult["cardinality"] = this["cardinality"].toString(); return hostGroupDetailResult; }; host_groups.push(hostGroupDetail); var clusterTemplateHostGroupDetail = { "name": hostGroupId, "hosts": hostListForGroup }; cluster_template_host_groups.push(clusterTemplateHostGroupDetail); counter++; }, this); this.get('content.configGroups').filterProperty("is_default", false).forEach(function (configGroup) { if (configGroup.properties.length == 0) { return; } configGroup.hosts.forEach(function (hostInConfigGroup) { return host_groups.some(function (presentHostGroup) { return presentHostGroup.hosts.some(function (hostInPresentHostGroup, index) { if (hostInConfigGroup !== hostInPresentHostGroup.fqdn) { return; } //Check if childHostGroup already created if (presentHostGroup['childHostGroups']) { if (self.hostInChildHostGroup(presentHostGroup, configGroup.name, hostInConfigGroup)) { // Update to remove parentHostGroup as all the hosts are added to childHostGroup/s presentHostGroup.hosts.splice(index, 1); presentHostGroup["cardinality"] = presentHostGroup['cardinality'] - 1; return true; } } //create configuration object var hgConfigurations; if(presentHostGroup.hosts.length === 1 && presentHostGroup["configurations"]) { hgConfigurations = presentHostGroup["configurations"][0]; } else if (presentHostGroup["configurations"]) { //Deep copy hgConfigurations = jQuery.extend(true, {}, presentHostGroup["configurations"][0]); } else { hgConfigurations = {}; } configGroup.properties.forEach(function (hgProperties) { var type = App.config.getConfigTagFromFileName(hgProperties.filename); if (!hgConfigurations[type]) { hgConfigurations[type] = { properties: {} }; } hgConfigurations[type]['properties'][hgProperties.name] = hgProperties.value; }); var totalHgConf = []; totalHgConf.push(hgConfigurations); //If only host in presentHostGroup then merge configuration and return if (presentHostGroup.hosts.length === 1) { //If host_group already has configuration, assigned from previously processed config_group if(!presentHostGroup["configurations"]) { presentHostGroup["configurations"] = totalHgConf; } return true; } //Create new host_group from this host var hostGroupId = "host_group_" + counter; counter++; var hostListForGroup = []; hostListForGroup.push({ "fqdn": hostInPresentHostGroup.fqdn }); var hostGroupDetail = { "name": hostGroupId, "components": presentHostGroup.components, "cardinality": 1, "hosts": hostListForGroup, "configurations": totalHgConf, "configGroupName": configGroup.name }; hostGroupDetail.toJSON = function () { var hostGroupDetailResult = _.omit(this, [ "hosts", "configGroupName", "childHostGroups" ]); hostGroupDetailResult["cardinality"] = this["cardinality"].toString(); return hostGroupDetailResult; }; host_groups.push(hostGroupDetail); //Update for clustertemplate file var clusterTemplateHostGroupDetail = { "name": hostGroupId, "hosts": hostListForGroup }; cluster_template_host_groups.push(clusterTemplateHostGroupDetail); //Add newly created host_group as child to existing host_group if (!presentHostGroup['childHostGroups']) { presentHostGroup['childHostGroups'] = []; } presentHostGroup['childHostGroups'].push(hostGroupDetail); presentHostGroup.hosts.splice(index, 1); presentHostGroup["cardinality"] = presentHostGroup['cardinality'] - 1; //return true to indicate that host has been matched return true; }, this); }, this); }, this); }, this); const selectedStack = App.Stack.find().findProperty('isSelected', true); const blueprint = { 'configurations': totalConf, 'host_groups': host_groups.filter(function (item) { return item.cardinality > 0; }), 'Blueprints': {'blueprint_name' : App.clusterStatus.clusterName, 'stack_name':selectedStack.get('stackName'), 'stack_version':selectedStack.get('stackVersion')} }; const cluster_template = { "blueprint": App.clusterStatus.clusterName, "config_recommendation_strategy" : "NEVER_APPLY", "provision_action" : "INSTALL_AND_START", "configurations": [], "host_groups": cluster_template_host_groups.filter(function (item) { return item.hosts.length > 0; }), "Clusters": {'cluster_name': App.clusterStatus.clusterName} }; fileUtils.downloadFilesInZip([ { data: JSON.stringify(blueprint), type: 'json', name: 'blueprint.json' }, { data: JSON.stringify(cluster_template), type: 'json', name: 'clustertemplate.json' } ]); }, downloadCSV: function() { App.router.get('kerberosWizardStep5Controller').getCSVData(false); } });