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}} &rarr;
     </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() {

Reply via email to