Repository: ambari Updated Branches: refs/heads/branch-feature-AMBARI-21674 daa1b7961 -> eb84fd2c4
AMBARI-22406. UI for verifying if repo exist for new OS family and user prompt for entering HDP and HDP-UTILs repo URLs (Sonia Garudi via ncole) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/eb84fd2c Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/eb84fd2c Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/eb84fd2c Branch: refs/heads/branch-feature-AMBARI-21674 Commit: eb84fd2c4ef42bd0c2b8d4d5e17e769a1c621cd2 Parents: daa1b79 Author: Nate Cole <nc...@hortonworks.com> Authored: Mon Jan 8 10:35:02 2018 -0500 Committer: Nate Cole <nc...@hortonworks.com> Committed: Mon Jan 8 10:35:02 2018 -0500 ---------------------------------------------------------------------- .../app/controllers/wizard/step3_controller.js | 440 ++++++++++++++++++- ambari-web/app/messages.js | 1 + ambari-web/app/styles/wizard.less | 43 ++ ambari-web/app/templates/wizard/step3.hbs | 75 +++- ambari-web/app/utils/ajax/ajax.js | 5 +- .../wizard/step3/hostWarningPopupBody_view.js | 2 +- ambari-web/app/views/wizard/step3_view.js | 113 +++++ .../test/controllers/wizard/step3_test.js | 243 +++++++++- 8 files changed, 894 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/controllers/wizard/step3_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step3_controller.js b/ambari-web/app/controllers/wizard/step3_controller.js index 55f4323..86f17ef 100644 --- a/ambari-web/app/controllers/wizard/step3_controller.js +++ b/ambari-web/app/controllers/wizard/step3_controller.js @@ -35,6 +35,13 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check registrationStartedAt: null, /** + * Skip repo-validation + * + * @type {bool} + */ + skipValidationChecked: false, + + /** * Timeout for registration * Based on <code>installOptions.manualInstall</code> * @type {number} @@ -140,7 +147,7 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check return (App.get('testMode')) ? true : !this.get('isRegistrationInProgress'); }.property('isRegistrationInProgress'), - isNextButtonDisabled: Em.computed.or('App.router.btnClickInProgress', 'isSubmitDisabled'), + isNextButtonDisabled: Em.computed.or('App.router.btnClickInProgress', 'isSubmitDisabled', 'invalidFormatUrlExist'), isBackButtonDisabled: Em.computed.or('App.router.btnClickInProgress', 'isBackDisabled'), @@ -184,6 +191,10 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check this.set('isLoaded', false); this.set('isSubmitDisabled', true); this.set('stopChecking', false); + this.set('allRepos', []); + this.set('newSupportedOsList', []); + this.set('promptRepoInfo', false); + this.set('isPublicRepo', true); }, /** @@ -301,6 +312,27 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check return App.showConfirmationPopup(function () { App.router.send('removeHosts', hosts); self.hosts.removeObjects(hosts); + hosts.forEach(function (_host) { + var contains = self.hosts.some(function (host) { + return host.os_family == _host.os_family; + }); + if (contains) { + return; + } + if (self.newSupportedOsList) { + var newSupportedOsListIndex = -1; + self.newSupportedOsList.some(function (os, index) { + if (os.os_family == _host.os_family) { + newSupportedOsListIndex = index; + return true; + } + }); + if (newSupportedOsListIndex != -1) { + self.newSupportedOsList.removeAt(newSupportedOsListIndex); + } + self.set('promptRepoInfo', self.newSupportedOsList.length > 0); + } + }); self.stopRegistration(); if (!self.hosts.length) { self.set('isSubmitDisabled', true); @@ -371,6 +403,8 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check * @method retryHosts */ retryHosts: function (hosts) { + this.set('newSupportedOsList', []); + this.set('promptRepoInfo', false); var self = this; var bootStrapData = JSON.stringify({ 'verbose': true, @@ -615,6 +649,7 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check switch (_host.get('bootStatus')) { case 'DONE': _host.set('bootStatus', 'REGISTERING'); + _host.set('os_family', jsonData.items.findProperty('Hosts.host_name', _host.name).Hosts.os_family); _host.set('bootLog', (_host.get('bootLog') != null ? _host.get('bootLog') : '') + Em.I18n.t('installer.step3.hosts.bootLog.registering')); // update registration timestamp so that the timeout is computed from the last host that finished bootstrapping this.set('registrationStartedAt', App.dateTime()); @@ -703,11 +738,17 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check * @method getJDKName */ getJDKName: function () { + var javaHomeOsField = ""; + this.get('bootHosts').forEach(function (host) { + if (javaHomeOsField.indexOf(host.os_family) == -1) { + javaHomeOsField = javaHomeOsField.concat(",RootServiceComponents/properties/java.home.", host.os_family); + } + }, this); return App.ajax.send({ name: 'ambari.service', sender: this, data: { - fields : '?fields=RootServiceComponents/properties/jdk.name,RootServiceComponents/properties/java.home,RootServiceComponents/properties/jdk_location' + fields: '?fields=RootServiceComponents/properties/jdk.name,RootServiceComponents/properties/java.home,RootServiceComponents/properties/jdk_location' + javaHomeOsField }, success: 'getJDKNameSuccessCallback' }); @@ -719,9 +760,20 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check * @method getJDKNameSuccessCallback */ getJDKNameSuccessCallback: function (data) { + var javaHomeHostInfo = {}; this.set('needJDKCheckOnHosts', !data.RootServiceComponents.properties["jdk.name"]); this.set('jdkLocation', Em.get(data, "RootServiceComponents.properties.jdk_location")); this.set('javaHome', data.RootServiceComponents.properties["java.home"]); + this.get('bootHosts').forEach(function (host) { + if (!(host.os_family in javaHomeHostInfo)) { + javaHomeHostInfo[host.os_family] = { + "jdk_path": data.RootServiceComponents.properties["java.home." + host.os_family], + "hosts": [], + "host_jdk_context": [] + }; + } + }, this); + this.set('javaHomeHostInfo', javaHomeHostInfo); }, doCheckJDK: function () { @@ -733,7 +785,6 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check sender: this, data: { host_names: hostsNames, - java_home: javaHome, jdk_location: jdkLocation }, success: 'doCheckJDKsuccessCallback', @@ -763,26 +814,38 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check this.set('isJDKWarningsLoaded', true); }, parseJDKCheckResults: function (data) { - var jdkWarnings = [], hostsJDKContext = [], hostsJDKNames = []; + var invalidJavaHomeName; + var jdkWarnings = [], hostsJDKContext = []; // check if the request ended if (data.Requests.end_time > 0 && data.tasks) { data.tasks.forEach( function(task) { // generate warning context if (Em.get(task, "Tasks.structured_out.java_home_check.exit_code") == 1){ + var warnedHost = this.get('bootHosts').findProperty('name', task.Tasks.host_name); var jdkContext = Em.I18n.t('installer.step3.hostWarningsPopup.jdk.context').format(task.Tasks.host_name); hostsJDKContext.push(jdkContext); - hostsJDKNames.push(task.Tasks.host_name); + this.javaHomeHostInfo[warnedHost.os_family].hosts.push(task.Tasks.host_name); + this.javaHomeHostInfo[warnedHost.os_family].host_jdk_context.push(jdkContext); } - }); + }, this); if (hostsJDKContext.length > 0) { // java jdk warning exist - var invalidJavaHome = this.get('javaHome'); - jdkWarnings.push({ - name: Em.I18n.t('installer.step3.hostWarningsPopup.jdk.name').format(invalidJavaHome), - hosts: hostsJDKContext, - hostsLong: hostsJDKContext, - hostsNames: hostsJDKNames, - category: 'jdk' - }); + for (var osFamily in this.javaHomeHostInfo) { + var invalidJavaHome = this.javaHomeHostInfo[osFamily].jdk_path; + if (invalidJavaHome) { + invalidJavaHomeName = Em.I18n.t('installer.step3.hostWarningsPopup.jdk.name').format(invalidJavaHome); + } else { + invalidJavaHomeName = Em.I18n.t('installer.step3.hostWarningsPopup.jdk.name.empty').format(osFamily); + } + if (this.javaHomeHostInfo[osFamily].hosts.length) { + jdkWarnings.push({ + name: invalidJavaHomeName, + hosts: this.javaHomeHostInfo[osFamily].host_jdk_context, + hostsLong: this.javaHomeHostInfo[osFamily].host_jdk_context, + hostsNames: this.javaHomeHostInfo[osFamily].hosts, + category: 'jdk' + }); + } + } } this.set('jdkCategoryWarnings', jdkWarnings); } else { @@ -791,7 +854,6 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check } this.doCheckJDKsuccessCallback(); }, - /** * Check JDK issues on registered hosts. */ @@ -816,11 +878,359 @@ App.WizardStep3Controller = Em.Controller.extend(App.ReloadPopupMixin, App.Check this.set('isWarningsLoaded', false); this.getHostNameResolution(); this.checkHostJDK(); + this.doCheckRepoInfo(); } else { this.stopHostCheck(); } }, + /** + * Calls respective methods for fetching allRepos for installer and addHost flow + * @method doCheckRepoInfo + */ + doCheckRepoInfo : function () { + var isInstaller = this.get('content.controllerName') == 'installerController'; + if (isInstaller) { + if (App.Stack.find().findProperty('isSelected', true).get('useRedhatSatellite') == true) { + this.set('promptRepoInfo', false); + return; + } + this.generateAllReposForInstaller(); + } else { + if (App.StackVersion.find().get('content.length') == 0) { + this.set('promptRepoInfo', false); + return; + } + } + + var self = this; + this.getSupportedOSList().done( function() { + if (!isInstaller) { + self.loadRepoInfo().done( function(isAmbariManagedRepositories) { + if(isAmbariManagedRepositories){ + self.checkRepoForNewOs(); + } + }); + } else { + self.checkRepoForNewOs(); + } + }, this); + }, + + /** + * Generate all repos for Installer Flow + * @method generateAllReposForInstaller + */ + generateAllReposForInstaller: function () { + var selectedStack = App.Stack.find().findProperty('isSelected'); + if (selectedStack && selectedStack.get('operatingSystems')) { + selectedStack.get('operatingSystems').forEach(function (os) { + if (os.get('isSelected')) { + os.get('repositories').forEach(function (repo) { + this.allRepos.push(Em.Object.create({ + base_url : repo.get('baseUrl'), + os_family : repo.get('osType'), + repo_id : repo.get('repoId') + })); + }, this); + } + }, this); + } + }, + + /** + * Gets the list of all supported Oses from version definition + * @method getSupportedOSList + */ + getSupportedOSList : function () { + var dfd = $.Deferred(); + var isInstaller = this.get('content.controllerName') == 'installerController'; + var version_definition_id; + if (isInstaller) { + version_definition_id = App.Stack.find().findProperty('isSelected', true).get('id'); + } else { + var stackName = App.get('currentStackName'); + var stackVersion = App.get('currentStackVersionNumber'); + var stackId = App.StackVersion.find().filterProperty('stack', stackName).findProperty('version', stackVersion).get('repositoryVersion.displayName').split('-')[1]; + if (stackVersion == stackId) {//check for default stack + version_definition_id = stackName + "-" + stackId; + } else { + version_definition_id = stackName + "-" + stackVersion + "-" + stackId; + } + } + App.ajax.send({ + name : 'wizard.get_version_definition', + sender : this, + data : { + version_definition_id : version_definition_id, + dfd : dfd + }, + success : 'getSupportedOSListSuccessCallback', + }); + return dfd.promise(); + }, + + /** + * onSuccess callback for getSupportedOSList. + * @method getSupportedOSListSuccessCallback + */ + getSupportedOSListSuccessCallback : function (data, opt, params) { + this.allSupportedOSList = data; + params.dfd.resolve(); + }, + + /** + * Load repo info for addHost flow + * @method loadRepoInfo + */ + loadRepoInfo: function () { + var stackName = App.get('currentStackName'); + var currentStackVersionNumber = App.get('currentStackVersionNumber'); + var currentStackVersion = App.StackVersion.find().filterProperty('stack', stackName).findProperty('version', currentStackVersionNumber); + var currentRepoVersion = currentStackVersion.get('repositoryVersion.repositoryVersion'); + var currentRepoVersionId = currentStackVersion.get('repositoryVersion.id'); + var dfd = $.Deferred(); + App.ajax.send({ + name: 'cluster.load_repo_version', + //name: 'wizard.step1.get_repo_version_by_id', + sender: this, + data: { + stackName: stackName, + repositoryVersion: currentRepoVersion, + repositoryVersionId: currentRepoVersionId, + dfd: dfd + }, + success: 'loadRepoInfoSuccessCallback', + error: 'loadRepoInfoErrorCallback' + }); + return dfd.promise(); + }, + + /** + * Success callback for loadRepoInfo + * @method loadRepoInfoSuccessCallback + */ + loadRepoInfoSuccessCallback : function (data, opt, params) { + var isAmbariManagedRepositories = true; + if (data.items.length) { + data.items[0].repository_versions.forEach(function (repo_version) { + if (repo_version.RepositoryVersions.id == params.repositoryVersionId) { + if (repo_version.operating_systems[0].OperatingSystems.ambari_managed_repositories) { + this.localRepoVersion = repo_version; + this.allRepos = this.generateAllReposForAddhost(Em.getWithDefault(repo_version, 'operating_systems', [])); + isAmbariManagedRepositories = true; + } else { + this.set('promptRepoInfo', false); + isAmbariManagedRepositories = false; + } + } + }, this); + } else { + this.loadDefaultRepoInfo(); + } + params.dfd.resolve(isAmbariManagedRepositories); + }, + + /** + * Generate all repos for Add Host Flow + * @method generateAllReposForAddhost + */ + generateAllReposForAddhost: function (oses) { + return oses.map(function (os) { + return os.repositories.map(function (repository) { + return Em.Object.create({ + base_url: repository.Repositories.base_url, + os_family: 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 + * @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' + }); + }, + + /** + * Success callback for loadDefaultRepoInfo + * @method loadDefaultRepoInfoSuccessCallback + */ + loadDefaultRepoInfoSuccessCallback: function (data) { + this.allRepos = this.generateAllReposForAddhost(Em.getWithDefault(data, 'items', [])); + }, + + /** + * Error callback for loadRepoInfo + * @method loadRepoInfoErrorCallback + */ + loadRepoInfoErrorCallback: function (request, ajaxOptions, error, opt, params) { + this.allRepos = []; + params.dfd.reject(); + }, + + /** + * Checks allRepos if repository exists for os_family and sets promptRepoInfo accordingly + * @method checkRepoForNewOs + */ + checkRepoForNewOs : function () { + var hosts = this.get('bootHosts').filterProperty('bootStatus', "REGISTERED"); + var newOsTypes = []; + var newSupportedOsList = Em.A([]); + hosts.forEach(function (_host) { + var found = false; + for (var i = 0; i < this.allRepos.length; i++) { + if (_host.os_family.contains(this.allRepos[i].os_family)) { + found = true; + break; + } + } + if (!found) { + this.set('promptRepoInfo', true); + newOsTypes.push(_host.os_family); + } + }, this); + + if (this.get('promptRepoInfo')) { + this.allSupportedOSList.operating_systems.forEach(function (os) { + if (newOsTypes.indexOf(os.OperatingSystems.os_type) != -1) { + var os_tmp = { + "os_family" : os.OperatingSystems.os_type, + "repositories" : [] + }; + os.repositories.forEach(function (repository) { + repository.Repositories.validation = ""; + repository.Repositories.errorTitle= ""; + repository.Repositories.errorContent = ""; + repository.Repositories.last_base_url = ""; + repository.Repositories.latest_base_url = repository.Repositories.base_url; + os_tmp.repositories.pushObject(repository.Repositories); + }, this); + newSupportedOsList.pushObject(os_tmp); + } + }, this); + } + this.set('newSupportedOsList', newSupportedOsList); + this.set('promptRepoInfo', this.newSupportedOsList.length > 0); + }, + + /** + * This will return the list of repositories when called by method editLocalRepository + */ + repositories: function () { + var repositories = []; + if (this.newSupportedOsList) { + this.newSupportedOsList.forEach(function (os) { + os.repositories.forEach(function (repo) { + repositories.pushObject(repo); + }, this); + }, this); + } + return repositories; + }.property('newSupportedOsList.@each.repositories'), + + /** + * Handler when editing any repository base_url on step 3 + * + * @method editLocalRepository + */ + editLocalRepository: function () { + var repositories = this.get('repositories'); + if (!repositories) { + return; + } + repositories.forEach(function (repository) { + if (repository.last_base_url !== repository.base_url) { + Em.set(repository, 'last_base_url', repository.base_url); + Em.set(repository, 'validation', 'PENDING'); + Em.set(repository, 'invalidFormatError', !this.isValidBaseUrl(repository.base_url)); + if (!repository.base_url) { + Em.set(repository, 'invalidFormatError', true); + } + } + }, this); + }.observes('repositories.@each.base_url'), + + /** + * Validate base URL + * @param {string} value + * @returns {boolean} + */ + isValidBaseUrl: function (value) { + var remotePattern = /^$|^(?:(?:https?|ftp):\/{2})(?:\S+(?::\S*)?@)?(?:(?:(?:[\w\-.]))*)(?::[0-9]+)?(?:\/\S*)?$/; + return remotePattern.test(value); + }, + + /** + * Returns true if 1 or more repository URLs on UI have invalidFormatError + * @returns {boolean} + */ + invalidFormatUrlExist: function () { + var repositories = this.get('repositories'); + if (!repositories) { + return false; + } + return repositories.someProperty('invalidFormatError', true); + }.property('repositories.@each.invalidFormatError'), + + onNetworkIssuesExist: function () { + if (this.get('networkIssuesExist')) { + this.set('isPublicRepo', false); + this.set('isLocalRepo', true); + this.newSupportedOsList.forEach(function (os) { + os.repositories.forEach(function (repo) { + Em.set(repo, 'base_url', ''); + }); + }); + } + }.observes('networkIssuesExist'), + + /** + * Restore base urls for selected stack when user select to use public + * repository + */ + usePublicRepo : function () { + this.set('isPublicRepo', true); + this.set('isLocalRepo', false); + this.set('useRedhatSatellite', false); + this.newSupportedOsList.forEach(function (repo) { + repo.repositories.forEach(function (repos) { + Em.set(repos, 'base_url', repos.latest_base_url); + }, this); + }, this); + }, + + /** + * Clean base urls for selected stack when user select to use local + * repository + */ + useLocalRepo : function () { + this.set('isPublicRepo', false); + this.set('isLocalRepo', true); + this.newSupportedOsList.forEach(function (repo) { + repo.repositories.forEach(function (repos) { + Em.set(repos, 'base_url', ''); + Em.set(repos, 'last_base_url', ''); + }, this); + }, this); + }, + _submitProceed: function () { this.set('confirmedHosts', this.get('bootHosts')); App.get('router').send('next'); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 6da0368..7992ace 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -773,6 +773,7 @@ Em.I18n.translations = { 'installer.step3.hostWarningsPopup.summary':'{0} on {1}', 'installer.step3.hostWarningsPopup.jdk':'JDK Issues', 'installer.step3.hostWarningsPopup.jdk.name':'JDK not found at <i>{0}</i>', + 'installer.step3.hostWarningsPopup.jdk.name.empty': 'JDK not found for OS family <i>{0}</i>', 'installer.step3.hostWarningsPopup.jdk.context':'{0}', 'installer.step3.hostWarningsPopup.jdk.message':'The following registered hosts have issues related to JDK', 'installer.step3.hostWarningsPopup.repositories':'Repository Issues', http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/styles/wizard.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/wizard.less b/ambari-web/app/styles/wizard.less index 4e680ca..f0fcec7 100644 --- a/ambari-web/app/styles/wizard.less +++ b/ambari-web/app/styles/wizard.less @@ -192,6 +192,49 @@ #warningsSection { margin: 0px 10px; } + .repos-panel { + input { + width:85%; + } + .version-contents-body { + padding: 0px 10px; + .radio-group { + padding-bottom: 10px; + margin-top: 0px; + color: #666; + } + } + .radio { + margin-top: 0px; + } + .big-radio { + &.disabled>span{ + opacity: 0.7; + } + } + #public-disabled-link { + margin-left: 10px; + font-weight: normal; + cursor: pointer; + } + .textfield-error { + .ember-text-field { + color: #666; + border: 1px solid #EF6162; + } + } + #skip-validation { + padding-top: 20px; + label { + color: #666; + font-weight: normal; + margin-top: -2px; + &.disabled { + opacity: 0.7; + } + } + } + } } #step4, #step5, #step6 { a.selected { http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/templates/wizard/step3.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/wizard/step3.hbs b/ambari-web/app/templates/wizard/step3.hbs index ff436a8..eb2733a 100644 --- a/ambari-web/app/templates/wizard/step3.hbs +++ b/ambari-web/app/templates/wizard/step3.hbs @@ -140,6 +140,79 @@ {{/unless}} </div> {{/unless}} + + {{#if promptRepoInfo}} + <div class="panel panel-default repos-panel"> + <div class="step-title"> + <p>{{t common.repositories}}</p> + </div> + <p class="step-description">{{t installer.step1.repo.body}}</p> + <div class="panel-body version-contents-body"> + <div class="row radio-group"> + {{! Public Repository radio }} + <div {{bindAttr class=":col-sm-4 :radio :big-radio :public-radio :wizard-plain-text"}}> + {{view view.usePublicRepoRadioButton classNames="display-inline-block" labelIdentifier="use-public-repo"}} + {{#if networkIssuesExist}} + <a id="public-disabled-link" + class="display-inline-block" {{action "openPublicOptionDisabledWindow" target="view"}}>{{t installer.step1.selectUseRepoOptions.public.networkLost}}</a> + {{/if}} + </div> + {{! Public Repository radio END }} + {{!--Local repo radio--}} + {{view view.useLocalRepoRadioButton classNames="radio big-radio col-sm-4" labelIdentifier="use-local-repo"}} + </div> + <div class="alert alert-info" + role="alert">{{t installer.step1.useLocalRepo.infoForm.alert.baseUrl}}</div> + + {{#if view.showWarning}} + <div + class="alert alert-warning" {{QAAttr "step1-warning"}}>{{t installer.step1.attentionNeeded}}</div> + {{/if}} + </div> + <table class="table table-hover"> + <thead> + <tr> + <th class="col-sm-2">{{t common.os}}</th> + <th class="col-sm-3">{{t common.name}}</th> + <th class="col-sm-6">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</th> + <th class="col-sm-1"></th> + </tr> + </thead> + <tbody> + {{#each operatingSystem in controller.newSupportedOsList}} + <tr {{QAAttr "os-wrapper"}}> + <td class="col-sm-2" {{QAAttr "os-type-label"}}>{{operatingSystem.os_family}}</td> + <td class="col-sm-9" colspan="2"> + <table class="table table-condensed no-borders inner-table" {{QAAttr "{operatingSystem.os_family}"}}> + <tbody> + {{#each repository in operatingSystem.repositories}} + <tr {{QAAttr "{repository.repo_name}"}}> + <td class="col-sm-3">{{repository.repo_id}}</td> + <td class="col-sm-8" {{bindAttr class="repository.invalidFormatError:textfield-error"}}> + {{view App.WizardStep3ViewRepoUrlInput valueBinding="repository.base_url" }} + </td> + </tr> + {{/each}} + </tbody> + </table> + </td> + </tr> + {{/each}} + </tbody> + </table> + {{! OSes and Repositories END }} + {{! Skip Repository Base URL validation }} + <div id="skip-validation"> + {{#view App.CheckboxView labelTranslate="installer.step1.advancedRepo.skipValidation.message" checkedBinding="skipValidationChecked" labelIdentifier="skip-validation"}} + <i class="glyphicon glyphicon-question-sign" rel="skip-validation-tooltip" + data-toggle="tooltip" {{translateAttr data-original-title="installer.step1.advancedRepo.skipValidation.tooltip"}}> + </i> + {{/view}} + <div class="clearfix"></div> + </div> + {{! Skip Repository Base URL validation END }} + </div> + {{/if}} </div> </div> </div> @@ -160,4 +233,4 @@ {{t common.next}} → </button> </div> -</div> \ No newline at end of file +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index 483be5e..7441b41 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -1959,6 +1959,9 @@ var urls = { } } }, + 'wizard.get_version_definition': { + 'real': '/version_definitions/{version_definition_id}?fields=operating_systems/repositories/Repositories/*', + }, 'wizard.step1.get_repo_version_by_id': { 'real': '/stacks/{stackName}/versions?fields=repository_versions/operating_systems/repositories/*' + ',repository_versions/RepositoryVersions/*' + @@ -2256,7 +2259,7 @@ var urls = { 'mock': '/data/wizard/bootstrap/poll_{numPolls}.json' }, 'wizard.step3.is_hosts_registered': { - 'real': '/hosts?fields=Hosts/host_status', + 'real': '/hosts?fields=Hosts/host_status,Hosts/os_family', 'mock': '/data/wizard/bootstrap/single_host_registration.json' }, 'wizard.stacks': { http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js b/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js index 786c4f7..1c61146 100644 --- a/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js +++ b/ambari-web/app/views/wizard/step3/hostWarningPopupBody_view.js @@ -317,7 +317,7 @@ App.WizardStep3HostWarningPopupBody = Em.View.extend({ } if (content.findProperty('category', 'jdk').warnings.length) { newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.jdk'); - newContent += content.findProperty('category', 'jdk').warnings[0].hostsLong.join('<br>'); + newContent += content.findProperty('category', 'jdk').warnings.mapProperty('hostsLong').join('<br>'); } if (content.findProperty('category', 'disk').warnings.length) { newContent += Em.I18n.t('installer.step3.hostWarningsPopup.report.disk'); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/app/views/wizard/step3_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/wizard/step3_view.js b/ambari-web/app/views/wizard/step3_view.js index 3249b24..d788a61 100644 --- a/ambari-web/app/views/wizard/step3_view.js +++ b/ambari-web/app/views/wizard/step3_view.js @@ -202,6 +202,70 @@ App.WizardStep3View = App.TableView.extend({ }, this); }, + /** + * Show warning message flag + * + * @type {bool} + */ + warningExist: Em.computed.or('controller.invalidFormatUrlExist', 'isNoOsFilled'), + + skipVerifyBaseUrl: Em.computed.or('controller.skipValidationChecked', 'controller.useRedhatSatellite'), + + verifyBaseUrl: Em.computed.not('skipVerifyBaseUrl'), + + showWarning: Em.computed.and('warningExist', 'verifyBaseUrl'), + + /** + * If all OSes are empty + * @type {bool} + */ + isNoOsFilled: function () { + var operatingSystems = this.get('controller.operatingSystems'); + if (this.get('controller.useRedhatSatellite') || Em.isNone(operatingSystems)) { + return false; + } + var selectedOS = operatingSystems.filterProperty('isSelected', true); + return selectedOS.everyProperty('isNotFilled', true); + }.property('controller.operatingSystems.@each.isSelected', 'controller.operatingSystems.@each.isNotFilled', 'controller.useRedhatSatellite'), + + + /** + * Radio button for use Public repo + * + * @type {App.RadioButtonView} + */ + usePublicRepoRadioButton: App.RadioButtonView.extend({ + labelTranslate: 'installer.step1.selectUseRepoOptions.public', + checked: Em.computed.alias('controller.isPublicRepo'), + + change: function () { + this.get('controller').usePublicRepo(); + } + }), + + /** + * Checkbox for use Public repo + * + * @type {App.RadioButtonView} + */ + useLocalRepoRadioButton: App.RadioButtonView.extend({ + labelTranslate: 'installer.step1.selectUseRepoOptions.local', + checked: Em.computed.alias('controller.isLocalRepo'), + + change: function () { + this.get('controller').useLocalRepo(); + } + }), + + openPublicOptionDisabledWindow: function () { + return App.ModalPopup.show({ + header: Em.I18n.t('installer.step1.selectUseRepoOptions.public.networkLost.popup.title'), + bodyClass: Ember.View.extend({ + templateName: require('templates/wizard/step1/public_option_disabled_window_body') + }), + secondary: false + }); + }, /** * Filter hosts by category @@ -337,4 +401,53 @@ App.WizardHostView = Em.View.extend({ }); +/** + * Field for Repo url + */ +App.WizardStep3ViewRepoUrlInput = Em.TextField.extend({ + layout : Ember.Handlebars.compile('<div class="pull-left">{{yield}}</div> {{#if view.valueWasChanged}}<div class="pull-right"><a class="btn-small" {{action "restoreValue" target="view"}}><i class="icon-undo"></i></a></div>{{/if}}'), + + /** + * Submit form if "Enter" pressed + */ + keyPress : function (event) { + if (event.keyCode == 13) { + this.get('parentView.controller').submit(); + return false; + } + return true; + }, + + defaultValue : '', + + /** + * Determines if user have put some new value + */ + valueWasChanged : function () { + if(this.get('controller.isLocalRepo') && !this.get('value')) { + return false; + } + else { + return this.get('value') !== this.get('defaultValue'); + } + }.property('value', 'defaultValue'), + + didInsertElement : function () { + $("[rel=skip-validation-tooltip]").tooltip({ placement: 'right'}); + this.set('defaultValue', this.get('value')); + }, + + /** + * Restore value and unset error-flag + * @method restoreValue + */ + restoreValue : function () { + if(this.get('controller.isPublicRepo')) { + this.set('value', this.get('defaultValue')); + } + else if (this.get('controller.isLocalRepo')) { + this.set('value', ''); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb84fd2c/ambari-web/test/controllers/wizard/step3_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/wizard/step3_test.js b/ambari-web/test/controllers/wizard/step3_test.js index b8bc794..4fbcd2d 100644 --- a/ambari-web/test/controllers/wizard/step3_test.js +++ b/ambari-web/test/controllers/wizard/step3_test.js @@ -378,6 +378,48 @@ describe('App.WizardStep3Controller', function () { expect(c.get('isSubmitDisabled')).to.equal(true); }); + it('should remove hdp url prompt if no host of os_family exist', function () { + var host1 = Em.Object.create({name: 'host1', os_family: 'os1'}); + var host2 = Em.Object.create({name: 'host2', os_family: 'os2'}); + var hosts = [ + host1, + host2 + ]; + c.reopen({ + hosts: hosts, + newAmbariOsTypes: [], + promptAmbariRepoUrl: false, + promptRepoInfo: true, + newSupportedOsList : [ + Em.Object.create({os_family : 'os2'}) + ] + }); + c.removeHosts([host2]).onPrimary(); + expect(c.get('promptRepoInfo')).to.equal(false); + }); + + it('should not remove hdp url prompt if a host of os_family exist', function () { + var host1 = Em.Object.create({name: 'host1', os_family: 'os1'}); + var host2 = Em.Object.create({name: 'host2', os_family: 'os2'}); + var host3 = Em.Object.create({name: 'host3', os_family: 'os2'}); + var hosts = [ + host1, + host2, + host3 + ]; + c.reopen({ + hosts: hosts, + newAmbariOsTypes: [], + promptAmbariRepoUrl: false, + promptRepoInfo: true, + newSupportedOsList : [ + Em.Object.create({os_family : 'os2'}) + ] + }); + c.removeHosts([host2]).onPrimary();; + expect(c.get('promptRepoInfo')).to.equal(true); + }); + }); describe('#removeSelectedHosts', function () { @@ -771,9 +813,11 @@ describe('App.WizardStep3Controller', function () { var tests = Em.A([ { bootHosts: Em.A([ - Em.Object.create({bootStatus: 'DONE'}) + Em.Object.create({bootStatus: 'DONE', name: 'c1'}) ]), - data: {items: []}, + data: {items: [ + {Hosts: {host_name: 'c1', os_family: 'os1'}} + ]}, registrationStartedAt: 1000000, m: 'one host DONE', e: { @@ -840,11 +884,13 @@ describe('App.WizardStep3Controller', function () { beforeEach(function () { sinon.spy(c, 'getHostInfo'); sinon.stub(App, 'dateTime').returns(1000000); + sinon.stub(c, 'startHostcheck', Em.K); }); afterEach(function () { c.getHostInfo.restore(); App.dateTime.restore(); + c.startHostcheck.restore(); }); tests.forEach(function (test) { @@ -2567,22 +2613,29 @@ describe('App.WizardStep3Controller', function () { var expected = { name: 'name', home: 'home', - location: 'location' - }, - data = { + location: 'location', + os_family_java_home: 'ab' + }, + data = { RootServiceComponents: { properties: { 'jdk.name': expected.name, 'java.home': expected.home, - 'jdk_location': expected.location + 'jdk_location': expected.location, + 'java.home.aa': expected.os_family_java_home } } - }; - + }; + var bootHosts = [ + Em.Object.create({name: 'h1', bootStatus: 'REGISTERED', os_family: 'aa'}) + ]; + c.set('bootHosts', bootHosts); c.getJDKNameSuccessCallback(data); expect(c.get('needJDKCheckOnHosts')).to.equal(false); expect(c.get('jdkLocation')).to.equal(expected.location); expect(c.get('javaHome')).to.equal(expected.home); + var javaHomeHostInfo = c.get('javaHomeHostInfo'); + expect(javaHomeHostInfo['aa'].jdk_path).to.equal('ab'); }); }); @@ -2595,11 +2648,9 @@ describe('App.WizardStep3Controller', function () { Em.Object.create({name: 'n1', bootStatus: 'REGISTERED'}), Em.Object.create({name: 'n2', bootStatus: 'REGISTERED'}) ], - javaHome = '/java', jdkLocation = '/jdk'; c.reopen({ bootHosts: bootHosts, - javaHome: javaHome, jdkLocation: jdkLocation }); c.doCheckJDK(); @@ -2719,14 +2770,186 @@ describe('App.WizardStep3Controller', function () { ] }; + var bootHosts = [ + Em.Object.create({name: 'h1', bootStatus: 'REGISTERED', os_family: 'os1'}), + Em.Object.create({name: 'h2', bootStatus: 'REGISTERED', os_family: 'os2'}) + ]; + var javaHomeHostInfo = {}; + javaHomeHostInfo['os1'] = {jdk_path: "/abc", hosts: [], host_jdk_context: []}; + javaHomeHostInfo['os2'] = {jdk_path: "/abc", hosts: [], host_jdk_context: []}; + + c.reopen({ + bootHosts: bootHosts, + javaHomeHostInfo: javaHomeHostInfo, + }); + c.set('jdkCategoryWarnings', {}); c.parseJDKCheckResults(data); var result = c.get('jdkCategoryWarnings'); expect(result.length).to.equal(1); expect(result[0].hostsNames).to.eql(['h1']); + }); + + }); + + describe('#checkRepoForNewOs', function () { + it('should show prompt if repos dont exist for os_family in allRepos', function () { + var bootHosts = [ + Em.Object.create({name: 'host1', bootStatus: 'REGISTERED', os_family: 'os1'}), + Em.Object.create({name: 'host2', bootStatus: 'REGISTERED', os_family: 'os2'}) + ]; + var allRepos = [ + {os_family: 'os1'} + ]; + var allSupportedOSList = {operating_systems: [ + { + OperatingSystems: { os_type : 'os2'}, + repositories: [ + { + Repositories: { + base_url: 'baseurl1' + } + }, + { + Repositories: { + base_url: 'baseurl2' + } + } + ] + } + ] + }; + c.reopen({ + bootHosts: bootHosts, + allRepos: allRepos, + promptRepoInfo: false, + allSupportedOSList: allSupportedOSList + }); + c.checkRepoForNewOs(); + expect(c.get('promptRepoInfo')).to.equal(true); + }); + }); + describe('#editLocalRepository', function () { + it('should set invalidFormatError to true for invalid base url', function() { + var repositories = [{ + base_url: 'invalid url', + last_base_url: 'http://last_base_url' + }]; + c.reopen({ + repositories : repositories + }); + c.editLocalRepository(); + expect(c.get('repositories')[0].invalidFormatError).to.equal(true); + }); + + it('should set invalidFormatError to false and update the last_base_url to base_url', function() { + var repositories = [{ + base_url: 'http://base_url', + last_base_url: 'http://last_base_url' + }]; + c.reopen({ + repositories : repositories + }); + c.editLocalRepository(); + expect(c.get('repositories')[0].invalidFormatError).to.equal(false); + expect(c.get('repositories')[0].last_base_url).to.equal('http://base_url'); + }); + }); + + describe('onNetworkIssuesExist', function () { + it('should remove base_url if networkIssueExist', function() { + var newSupportedOsList = [{ + os_family : 'os1', + repositories: [ + { + base_url: 'http://base_url', + last_base_url: 'http://last_base_url' + } + ] + }]; + c.reopen({ + newSupportedOsList : newSupportedOsList, + networkIssuesExist : true + }); + c.onNetworkIssuesExist(); + expect(c.get('newSupportedOsList')[0].repositories[0].base_url).to.equal(""); + }); + }); + + describe('#usePublicRepo', function () { + beforeEach(function () { + var newSupportedOsList = [{ + os_family : 'os1', + repositories: [ + { + base_url: 'invalid_url', + last_base_url: 'http://last_base_url', + latest_base_url: 'http://latest_base_url' + } + ] + }]; + c.reopen({ + useRedhatSatellite: true, + isPublicRepo: false, + isLocalRepo: true, + newSupportedOsList : newSupportedOsList + }); + c.usePublicRepo(); + }); + + it('base_url is set to latest_base_url', function () { + expect(c.get('newSupportedOsList')[0].repositories[0].base_url).to.be.equal('http://latest_base_url'); }); + it('`useRedhatSatellite` is set `false`', function () { + expect(c.get('useRedhatSatellite')).to.be.false; + }); + + it('`usePublicRepo` is set `true`', function () { + expect(c.get('isPublicRepo')).to.be.true; + }); + + it('`useLocalRepo` is set `false`', function () { + expect(c.get('isLocalRepo')).to.be.false; + }); + }); + + describe('#useLocalRepo', function () { + beforeEach( function () { + var newSupportedOsList = [{ + os_family : 'os1', + repositories: [ + { + base_url: 'invalid_url', + last_base_url: 'http://last_base_url', + latest_base_url: 'http://latest_base_url' + } + ] + }]; + c.reopen({ + isPublicRepo: true, + isLocalRepo: false, + newSupportedOsList : newSupportedOsList + }); + c.useLocalRepo(); + }); + + it('base_url is set to blank', function () { + expect(c.get('newSupportedOsList')[0].repositories[0].base_url).to.be.equal(''); + }); + + it('last_base_url is set to blank', function () { + expect(c.get('newSupportedOsList')[0].repositories[0].last_base_url).to.be.equal(''); + }); + + it('`isPublicRepo` is set `false`', function () { + expect(c.get('isPublicRepo')).to.be.false; + }); + + it('`isLocalRepo` is set `true`', function () { + expect(c.get('isLocalRepo')).to.be.true; + }); }); describe('#getHostCheckTasksSuccess', function() {