Browse Source

AMBARI-857. Refactor Install Options page for the Install Wizard. (yusaku)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/branches/AMBARI-666@1397995 13f79535-47bb-0310-9956-ffa450edef68
Yusaku Sako 12 years ago
parent
commit
92c38ca432

+ 2 - 0
AMBARI-666-CHANGES.txt

@@ -251,6 +251,8 @@ AMBARI-666 branch (unreleased changes)
 
   IMPROVEMENTS
 
+  AMBARI-857. Refactor Install Options page for the Install Wizard. (yusaku)
+
   OPTIMIZATIONS
 
   BUG FIXES

+ 77 - 163
ambari-web/app/controllers/installer/step2_controller.js

@@ -23,21 +23,13 @@ App.InstallerStep2Controller = Em.Controller.extend({
   content: [],
   hostNames: '',
   hostNameArr: [],
-  hostNameEmptyError: false,
-  hostNameErr: false,
   manualInstall: false,
-  hostNameNotRequiredErr: false,
-  hostNameErrMsg: '',
   sshKey: '',
   passphrase: '',
   confirmPassphrase: '',
-  sshKeyNullErr: false,
-  passphraseMatchErr: false,
   localRepo: false,
   localRepoPath: '',
-  softRepoLocalPathNullErr: false,
-  isSubmitDisabled: false,
-
+  hasSubmitted: false,
 
   clearStep: function () {
     this.set('hostNames', '');
@@ -56,7 +48,7 @@ App.InstallerStep2Controller = Em.Controller.extend({
   loadStep: function () {
     console.log("TRACE: Loading step2: Install Options");
     var hostNames = App.db.getAllHostNames();
-    var softrepo = App.db.getSoftRepo();
+    var softRepo = App.db.getSoftRepo();
     var installType = App.db.getInstallType();
     if (hostNames !== undefined) {
       this.set('hostNames', hostNames);
@@ -70,9 +62,9 @@ App.InstallerStep2Controller = Em.Controller.extend({
       this.set('manualInstall', false);
     }
 
-    if (softrepo !== undefined && softrepo.repoType === 'local') {
+    if (softRepo !== undefined && softRepo.repoType === 'local') {
       this.set('localRepo', true);
-      this.set('localRepoPath', softrepo.repoPath);
+      this.set('localRepoPath', softRepo.repoPath);
     } else {
       this.set('localRepo', false);
       this.set('localRepoPath', '');
@@ -85,145 +77,67 @@ App.InstallerStep2Controller = Em.Controller.extend({
     } else {
       return 'ambariDriven';
     }
-  }.observes('manualInstall'),
+  }.property('manualInstall'),
 
-  hideRepoErrMsg: function () {
-    if (this.get('localRepo') === false) {
-      this.set('softRepoLocalPathNullErr', false);
-    }
-  }.observes('localRepo'),
+  isHostNameValid: function (hostname) {
+    // For now hostnames that start or end with '-' are not allowed
+    return !(/^\-/.test(hostname) || /\-$/.test(hostname));
+  },
 
-  validateHostNames: function () {
+  isAllHostNamesValid: function () {
     this.hostNameArr = this.get('hostNames').trim().split(new RegExp("\\s+", "g"));
     for (var index in this.hostNameArr) {
-      console.log("host name is: " + this.hostNameArr[index]);
-      //TODO: other validation for hostnames will be covered over here
-      // For now hostnames that start or end with '-' are not allowed
-      if (/^\-/.test(this.hostNameArr[index]) || /\-$/.test(this.hostNameArr[index])) {
-        console.log('Invalid host name: ' + this.hostNameArr[index]);
-        this.set('hostNameErr', true);
-        this.set('hostNameErrMsg', Em.I18n.t('installer.step2.hostName.error.invalid'));
-        this.set('hostNameEmptyError', false);
-        this.set('hostNameNotRequiredErr', false);
+      if (!this.isHostNameValid(this.hostNameArr[index])) {
         return false;
       }
     }
     return true;
   },
 
-  validateHosts: function () {
-    if (this.get('hostNames') === '' && this.get('manualInstall') === false) {
-      this.set('hostNameEmptyError', true);
-      this.set('hostNameNotRequiredErr', false);
-      this.set('hostNameErr', false);
-      this.set('hostNameErrMsg', Em.I18n.t('installer.step2.hostName.error.required'));
-    } else if (this.get('hostNames') !== '' && this.get('manualInstall') === true) {
-      this.set('hostNameNotRequiredErr', true);
-      this.set('hostNameEmptyError', false);
-      this.set('hostNameErr', false);
-      this.set('hostNameErrMsg', Em.I18n.t('installer.step2.hostName.error.notRequired'));
-    } else {
-      this.set('hostNameErr', false);
-      this.set('hostNameEmptyError', false);
-      this.set('hostNameNotRequiredErr', false);
-      this.set('hostNameErrMsg', '');
+  hostsError: function () {
+    if (this.get('hasSubmitted') && this.get('hostNames').trim() === '') {
+      return Em.I18n.t('installer.step2.hostName.error.required');
+    } else if (this.isAllHostNamesValid() === false) {
+      return Em.I18n.t('installer.step2.hostName.error.invalid');
     }
-  }.observes('hostNames', 'manualInstall'),
+    return null;
+  }.property('hostNames', 'manualInstall', 'hasSubmitted'),
 
-  validateSSHKey: function () {
-    if (this.get('manualInstall') === false) {
-      if (this.get('sshKey') === '') {
-        this.set('sshKeyNullErr', true);
-      }
-      else {
-        this.set('sshKeyNullErr', false);
-      }
+  sshKeyError: function () {
+    if (this.get('hasSubmitted') && this.get('manualInstall') === false && this.get('sshKey').trim() === '') {
+      return Em.I18n.t('installer.step2.sshKey.error.required');
     }
-  }.observes('manualInstall', 'sshKey'),
+    return null;
+  }.property('sshKey', 'manualInstall', 'hasSubmitted'),
 
-  validatePassphrase: function () {
-    if (this.get('manualInstall') === false) {
-      if (this.get('passphrase') !== this.get('confirmPassphrase')) {
-        this.set('passphraseMatchErr', true);
-      } else {
-        this.set('passphraseMatchErr', false);
-      }
+  localRepoError: function () {
+    if (this.get('hasSubmitted') && this.get('localRepo') && this.get('localRepoPath').trim() === '') {
+      return Em.I18n.t('installer.step2.localRepo.error.required');
     }
-  }.observes('manualInstall', 'passphrase', 'confirmPassphrase'),
+    return null;
+  }.property('localRepo', 'localRepoPath', 'hasSubmitted'),
 
-  validateLocalRepo: function () {
-    if (this.get('localRepo') === true) {
-      if (this.get('localRepoPath') === '') {
-        this.set('softRepoLocalPathNullErr', true);
-      } else {
-        this.set('softRepoLocalPathNullErr', false);
-      }
-    } else {
-      this.set('softRepoLocalPathNullErr', false);
-    }
-  }.observes('localRepoPath'),
-
-  validateStep2: function () {
-    this.validateHosts();
-    this.validateSSHKey();
-    this.validatePassphrase();
-    this.validateLocalRepo();
-    return this.validateHostNames();
-  },
-
-  hostManageErr: function () {
-    return (this.get('hostNameEmptyError') || this.get('hostNameNotRequiredErr') ||
-      this.get('hostNameErr') || this.get('sshKeyNullErr') || this.get('passphraseMatchErr'));
-  }.property('hostNameErrMsg', 'sshKeyNullErr', 'passphraseMatchErr'),
-
-  sshLessInstall: function () {
-    if (this.get('manualInstall') === true) {
-      this.set('hostManageErr', false);
-      this.set('hostNameEmptyError', false);
-      this.set('sshKeyNullErr', false);
-      this.set('passphraseMatchErr', false);
-    }
-  }.observes('manualInstall'),
-
-  advOptErr: function () {
-    return this.get('softRepoLocalPathNullErr');
-  }.property('softRepoLocalPathNullErr'),
+  evaluateStep2: function () {
+    console.log('TRACE: Entering controller:InstallerStep2:evaluateStep2 function');
 
-  step2Err: function () {
-    if (this.get('hostManageErr') === true || this.get('advOptErr') === true) {
-      this.set('isSubmitDisabled', true);
-    } else {
-      this.set('isSubmitDisabled', false);
-    }
-  }.observes('hostManageErr', 'advOptErr'),
+    this.set('hasSubmitted', true);
 
-  softRepo: function () {
-    if (this.get('localRepo') === false) {
-      this.set('localRepoPath', '');
+    if (this.get('hostsError') || this.get('sshKeyError') || this.get('localRepoError')) {
+      return false;
     }
-  }.observes('localRepo'),
-
-
-  evaluateStep2: function () {
-
-    console.log('TRACE: Entering controller:InstallerStep2:evaluateStep2 function');
-    console.log('value of manual install is: ' + this.get('manualInstall'));
 
     if (this.get('isSubmitDisabled') === true) {
-      console.log("ERROR: error in validation");
       return false;
     }
 
-    var validateResult = !this.validateStep2();
-
     var hostInfo = {};
-    for (var i = 0; i < this.hostNameArr.length; i++) {
-      hostInfo[this.hostNameArr[i]] = {
-        name: this.hostNameArr[i],
+    this.hostNameArr.forEach(function (hostName) {
+      hostInfo[hostName] = {
+        name: hostName,
         installType: this.get('installType'),
         bootStatus: 'pending'
       };
-    }
+    }, this);
     App.db.setAllHostNames(this.get('hostNames'));
     App.db.setHosts(hostInfo);
     if (this.get('manualInstall') === false) {
@@ -237,48 +151,44 @@ App.InstallerStep2Controller = Em.Controller.extend({
       App.db.setSoftRepo({ 'repoType': 'local', 'repoPath': this.get('localRepoPath') });
     }
 
-
     if (this.get('manualInstall') === true) {
       this.manualInstallPopup();
-      return true;
-    }
-
-
-    if (this.get('manualInstall') === false) {
-      // For now using mock jquery call
-      //TODO: hook up with bootstrap call
-      var bootStrapData = {'sshKey': this.get('sshKey'), 'sshKeyPassphrase': this.get('passphrase'), hosts: this.get('hostNameArr')}.stringify;
-      $.ajax({
-        type: 'POST',
-        url: '/ambari_server/api/bootstrap',
-        data: bootStrapData,
-        async: false,
-        timeout: 2000,
-        success: function () {
-          console.log("TRACE: In success function for the post bootstrap function");
-          App.router.transitionTo('step3');
-        },
-        error: function () {
-          console.log("ERROR: bootstrap post call failed");
-          return false;
-        },
-        statusCode: {
-          404: function () {
-            console.log("URI not found.");
-            alert("URI not found,. This needs to be hooked up with a @POST bootstrap call");
-            //After the bootstrap call hook up change the below return statement to "return false"
-            console.log("TRACE: In faliure function for the post bootstrap function");
-            //Remove below line, once bootstrap has been implemented
-            App.router.send('next');
-            return true;
-          }
-        },
-        dataType: 'application/json'
-      });
-    } else {
-      console.log("ERROR: ASSERTION FAILED -> program should have never reached over here");
+      return false;
     }
 
+    // For now using mock jquery call
+    //TODO: hook up with bootstrap call
+    var bootStrapData = {'sshKey': this.get('sshKey'), hosts: this.get('hostNameArr')}.stringify;
+    $.ajax({
+      type: 'POST',
+      url: '/api/bootstrap',
+      data: bootStrapData,
+      async: false,
+      timeout: 2000,
+      success: function () {
+        console.log("TRACE: In success function for the post bootstrap function");
+        App.router.transitionTo('step3');
+      },
+      error: function () {
+        console.log("ERROR: bootstrap post call failed");
+        return false;
+      },
+      complete: function() {
+        // TODO: remove this function.  this is just to force navigating to the next step before bootstrap integration
+        App.router.send('next');
+      },
+      statusCode: {
+        404: function () {
+          console.log("URI not found.");
+          //After the bootstrap call hook up change the below return statement to "return false"
+          console.log("TRACE: In faliure function for the post bootstrap function");
+          //Remove below line, once bootstrap has been implemented
+          App.router.send('next');
+          return true;
+        }
+      },
+      dataType: 'application/json'
+    });
   },
 
   manualInstallPopup: function (event) {
@@ -287,12 +197,16 @@ App.InstallerStep2Controller = Em.Controller.extend({
       onPrimary: function () {
         this.hide();
         App.router.send('next');
-        //App.router.transitionTo('step3');
+        // App.router.transitionTo('step3');
       },
       bodyClass: Ember.View.extend({
         templateName: require('templates/installer/step2ManualInstallPopup')
       })
     });
-  }
+  },
+
+  isSubmitDisabled: function() {
+    return (this.get('hostNameError') || this.get('sshKeyError') || this.get('localRepoError'));
+  }.property('hostNameError', 'sshKeyError', 'localRepoError')
 
 });

+ 1 - 1
ambari-web/app/controllers/installer/step3_controller.js

@@ -172,7 +172,7 @@ App.InstallerStep3Controller = Em.ArrayController.extend({
     var self = this;
     $.ajax({
       type: 'GET',
-      url: '/ambari_server/api/bootstrap',
+      url: '/api/bootstrap',
       async: false,
       timeout: 5000,
       success: function (data) {

+ 14 - 9
ambari-web/app/messages.js

@@ -52,31 +52,36 @@ Em.I18n.translations = {
   'installer.step1.clusterName.error.specialChar': 'Cluster Name cannot contain special characters',
 
   'installer.step2.header': 'Install Options',
-  'installer.step2.targetHosts': 'Specify Hosts to Manage',
+  'installer.step2.body': 'Enter the list of hosts to be included in the cluster, provide your SSH key, and optionally specify a local repository.',
+  'installer.step2.targetHosts': 'Target Hosts',
   'installer.step2.targetHosts.info': 'Enter a list of host names, one per line',
   'installer.step2.hostPattern.tooltip.title': 'Pattern Expressions',
   'installer.step2.hostPattern.tooltip.content': 'You can use pattern expressions to specify a number of target hosts.  Explain brackets.',
   'installer.step2.hostName.error.required': 'Host Names cannot be left empty',
   'installer.step2.hostName.error.notRequired': 'Host Names will be ignored if not using SSH to automatically configure hosts',
   'installer.step2.hostName.error.invalid': 'Invalid Host Name(s) - cannot start or end with a hyphen',
+  'installer.step2.sshKey': 'Host Connectivity Information',
+  'installer.step2.sshKey.info': 'Provide your SSH Private Key (<b>id_rsa</b> for <b>root</b>)',
   'installer.step2.sshKey.error.required': 'SSH Private Key is required',
   'installer.step2.passphrase.error.match': 'Passphrases do not match',
-  'installer.step2.manualInstallOption': 'Do not use SSH to automatically configure hosts ',
+  'installer.step2.manualInstall.label': 'Do not use SSH to automatically configure hosts ',
+  'installer.step2.manualInstall.info': 'By not using SSH to connect to the target hosts, you must manually install and start the ' +
+    'Ambari Agent on each host in order for the wizard to perform the necessary configurations and software installs.',
   'installer.step2.advancedOption': 'Advanced Options',
   'installer.step2.repoConf': 'Software Repository Configuration File Path',
-  'installer.step2.localRepoOption': 'Use a local software repository',
+  'installer.step2.localRepo.header': 'Software repository',
+  'installer.step2.localRepo.label': 'Use a local software repository',
   'installer.step2.localRepo.error.required': 'Local repository file path is required',
-  'installer.step2.localRepo.info': '<p class=\"text-info\">The repository configuration file should be installed on each host in your cluster. ' +
-    'This file instructs package manager to use your local software repository to retrieve software packages, instead of ' +
-    'downloading from the internet.</p>',
+  'installer.step2.localRepo.info': 'The repository configuration file should be installed on each host in your cluster. ' +
+    'This file instructs the package manager to use your local software repository to retrieve software packages, instead of ' +
+    'downloading them from the internet.',
   'installer.step2.localRepo.tooltip.title': 'Local Software Repository',
   'installer.step2.localRepo.tooltip.content': 'The repository configuration file should be installed on each host ' +
     'in your cluster. This file instructs package manager to use your local' +
     'software repository to retrieve software packages, instead of using the internet.',
   'installer.step2.manualInstall.tooltip.title': 'Not Using SSH (Manual Install)',
-  'installer.step2.manualInstall.tooltip.content': 'Ambari agents will not be installed ' +
-    'automatically. You need to install it manually on each host that you want to manage as part of ' +
-    'your cluster. Agents should be started before you move to the next stage.',
+  'installer.step2.manualInstall.tooltip.content': 'If you do not wish Ambari to automatically configure the target hosts via SSH,' +
+    ' you have the option of configuring them yourself.  This involves installing and starting Ambari Agent on each of your target hosts.',
   'installer.step2.manualInstall.popup.header': 'Before You Proceed',
   'installer.step2.manualInstall.popup.body': 'You must install Ambari Agents on each host you want to manage before you proceed.  <a href="#" target="_blank">Learn more</a>',
 

+ 2 - 0
ambari-web/app/routes/installer.js

@@ -15,7 +15,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 var App = require('app');
+
 module.exports = Em.Route.extend({
   route: '/installer',
   App: require('app'),

+ 15 - 0
ambari-web/app/styles/application.less

@@ -183,6 +183,21 @@ h1 {
     font-size: 13px;
     padding-left: 0;
   }
+  #installOptions {
+    #targetHosts {
+
+    }
+    #hostConnectivity {
+      margin-top: 20px;
+      .control-group {
+        margin-bottom: 0;
+      }
+    }
+    #localRepo {
+      margin-top: 20px;
+      margin-bottom: 30px;
+    }
+  }
   #step4, #step6 {
     a.selected {
       color: #333;

+ 70 - 63
ambari-web/app/templates/installer/step2.hbs

@@ -15,41 +15,61 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 -->
-
+<div id="installOptions">
 <h2>{{t installer.step2.header}}</h2>
-
-<h5>{{t installer.step2.targetHosts}}</h5>
-
-<div {{bindAttr class="view.hostNameErr:error :control-group"}}>
-  <p>{{t installer.step2.targetHosts.info}}. Or use
-    <a href="javascript:void(null)"
-       rel="popover"
-      {{translateAttr title="installer.step2.hostPattern.tooltip.title" data-content="installer.step2.hostPattern.tooltip.content"}}>
-      {{t installer.step2.hostPattern.tooltip.title}}
-    </a>
-  </p>
-
-  <div class="controls">
-    {{view Ember.TextArea class="span6" valueBinding="hostNames" rows="5" placeholder="host names"}}
-    {{#if view.hostNameErr}}
-    <p class="help-inline">{{hostNameErrMsg}}</p>
-    {{/if}}
+<p class="alert alert-info">{{t installer.step2.body}}</p>
+
+<div id="targetHosts">
+  <h5>{{t installer.step2.targetHosts}}</h5>
+
+  <div {{bindAttr class="hostsError:error :control-group"}}>
+    <p>{{t installer.step2.targetHosts.info}}. Or use
+      <a href="javascript:void(null)"
+         rel="popover"
+        {{translateAttr title="installer.step2.hostPattern.tooltip.title" data-content="installer.step2.hostPattern.tooltip.content"}}>
+        {{t installer.step2.hostPattern.tooltip.title}}
+      </a>
+    </p>
+
+    <div class="controls">
+      {{view Ember.TextArea class="span6" valueBinding="hostNames" rows="5" placeholder="host names"}}
+      {{#if hostsError}}
+      <p class="help-inline">{{hostsError}}</p>
+      {{/if}}
+    </div>
   </div>
 </div>
 
-<div id="hostConnectId">
+<div id="hostConnectivity">
   <div class="ambari-agents">
-
-    <div {{bindAttr class="sshKeyNullErr:error :control-group"}}>
+    <h5>{{t installer.step2.sshKey}}</h5>
+    <p>{{t installer.step2.sshKey.info}}</p>
+    <div {{bindAttr class="sshKeyError:error :control-group"}}>
       <div class="controls">
         {{view Ember.TextArea class="span6" rows="4" placeholder="ssh private key" valueBinding="sshKey"}}
-        {{#if sshKeyNullErr}}
+        {{#if sshKeyError}}
         <span
-          class="help-inline">{{t installer.step2.sshKey.error.required}}</span>
+          class="help-inline">{{sshKeyError}}</span>
         {{/if}}
       </div>
     </div>
 
+    <label class="checkbox">
+      {{t installer.step2.manualInstall.label}}
+      <a href="javascript:void(null)"
+         rel="popover"
+        {{translateAttr title="installer.step2.manualInstall.tooltip.title" data-content="installer.step2.manualInstall.tooltip.content"}}>
+        Learn more</a>
+      {{view Ember.Checkbox checkedBinding="manualInstall"}}
+    </label>
+
+    {{#if "manualInstall"}}
+    <div class="alert">
+      {{t installer.step2.manualInstall.info}}
+    </div>
+    {{/if}}
+
+    <!--
     {{view Ember.TextField type="text" placeholder="passphrase" valueBinding="passphrase"}}
 
     <div {{bindAttr class="passphraseMatchErr:error :control-group :ambari-agents"}}>
@@ -61,52 +81,39 @@
         {{/if}}
       </div>
     </div>
-
+    -->
   </div>
-
 </div>
 
-<h5>{{t installer.step2.advancedOption}}</h5>
-<label class="checkbox">
-  {{t installer.step2.manualInstallOption}}
-  <a href="javascript:void(null)"
-     rel="popover"
-    {{translateAttr title="installer.step2.manualInstall.tooltip.title" data-content="installer.step2.manualInstall.tooltip.content"}}>
-    Learn more</a>
-  {{view Ember.Checkbox checkedBinding="manualInstall"}}
-</label>
-<label class="checkbox">
-  {{t installer.step2.localRepoOption}}
-  <a href="javascript:void(null)"
-     rel="popover"
-    {{translateAttr title="installer.step2.localRepo.tooltip.title" data-content="installer.step2.localRepo.tooltip.content"}}>
-    Learn more</a>
-  {{view Ember.Checkbox checkedBinding="localRepo"}}
-</label>
-
-{{#if "localRepo"}}
-<div {{bindAttr class="softRepoLocalPathNullErr:error :control-group"}}>
-  <div class="alert alert-info">
-    {{t installer.step2.localRepo.info}}
-  </div>
-  <div class="controls">
-    {{view Ember.TextField type="text" class="span6" placeholder="Local repo file path (e.g., /etc/yum/repos.d/hdp)" valueBinding="localRepoPath"}}
-    {{#if softRepoLocalPathNullErr}}
-    <p class="help-inline">{{t installer.step2.localRepo.error.required}}</p>
-    {{/if}}
+<div id="localRepo">
+  <h5>{{t installer.step2.localRepo.header}}</h5>
+  <label class="checkbox">
+    {{t installer.step2.localRepo.label}}
+    <a href="javascript:void(null)"
+       rel="popover"
+      {{translateAttr title="installer.step2.localRepo.tooltip.title" data-content="installer.step2.localRepo.tooltip.content"}}>
+      Learn more</a>
+    {{view Ember.Checkbox checkedBinding="localRepo"}}
+  </label>
+
+  {{#if "localRepo"}}
+  <div {{bindAttr class="localRepoError:error :control-group"}}>
+    <div class="alert alert-info">
+      {{t installer.step2.localRepo.info}}
+    </div>
+    <div class="controls">
+      {{view Ember.TextField type="text" class="span6" placeholder="Local repo file path (e.g., /etc/yum/repos.d/hdp)" valueBinding="localRepoPath"}}
+      {{#if localRepoError}}
+      <p class="help-inline">{{localRepoError}}</p>
+      {{/if}}
+    </div>
   </div>
+  {{/if}}
 </div>
-{{/if}}
-
 <div class="btn-area">
   <a class="btn pull-left" {{action back}}>&larr; Back</a>
-  {{#if manualInstall}}
-  <a role="button" class="btn btn-success pull-right"
-     data-toggle="modal" {{action evaluateStep2 target="controller"}}>Validate &rarr;</a>
-  {{else}}
-  <a class="btn btn-success pull-right" {{action evaluateStep2 target="controller"}}> Discover and
-    Validate &rarr; </a>
-  {{/if}}
+  <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action evaluateStep2 target="controller"}}>Discover and
+    Validate &rarr;</a>
 </div>
 
-
+</div>

+ 0 - 37
ambari-web/app/templates/installer/step8.hbs

@@ -21,43 +21,6 @@
   {{t installer.step8.body}}
 </div>
 
-<div class="accordion">
-
-  {{#each service in controller}}
-  <div class="accordion-group">
-    <div class="accordion-heading">
-      <a class="accordion-toggle">
-        {{service.serviceName}}
-      </a>
-    </div>
-    {{#each category in service.configCategories}}
-
-
-    {{#view App.ServiceConfigsByCategoryView categoryBinding="category" serviceConfigsBinding="service.configs"}}
-    <div class="accordion-body collapse in">
-      <div class="accordion-inner">
-        <form class="form-horizontal">
-          {{#each view.categoryConfigs}}
-          <div {{bindAttr class="errorMessage:error: :control-group"}}>
-            <label class="control-label">{{displayName}}</label>
-
-            <div class="controls">
-              {{view viewClass serviceConfigBinding="this"}}
-            </div>
-          </div>
-          {{/each}}
-        </form>
-      </div>
-    </div>
-    {{/view}}
-    {{/each}}
-  </div>
-  {{/each}}
-
-
-</div>
-
-
 <div class="btn-area">
   <a class="btn pull-left" {{action back}}>&larr; Back</a>
   <a class="btn btn-success pull-right" {{action next}}>Next &rarr;</a>

+ 53 - 73
ambari-web/test/installer/step2_test.js

@@ -17,96 +17,83 @@
  */
 
 var App = require('app');
+var Ember = require('ember');
 require('controllers/installer/step2_controller');
 
 describe('App.InstallerStep2Controller', function () {
 
-  describe('#validateStep2()', function () {
+  describe('#hostsError()', function () {
 
-    it('should set hostNameEmptyError  ' +
-      'hostNameNotRequiredErr and hostNameErr to false, ' +
-      ' if manualInstall is false and hostNames is empty', function () {
+    it('should return t(installer.step2.hostName.error.required) if manualInstall is false, hostNames is empty, and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('manualInstall', false);
       controller.set('hostNames', '');
-      expect(controller.validateStep2()).to.equal(true);
-      expect(controller.get('hostNameEmptyError')).to.equal(true);
-      expect(controller.get('hostNameNotRequiredErr')).to.equal(false);
+      controller.set('hasSubmitted', true);
+      expect(controller.get('hostsError')).to.equal(Ember.I18n.t('installer.step2.hostName.error.required'));
     })
 
-    it('should set hostNameNotRequiredErr ' +
-      'hostNameEmptyError and hostNameErr to false, ' +
-      ' if manualInstall is true and hostNames is not empty', function () {
+    it('should return null if manualInstall is false, hostNames is not empty, and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
-      controller.set('manualInstall', true);
-      controller.set('hostNames', 'apache ambari');
-      expect(controller.validateStep2()).to.equal(true);
-      expect(controller.get('hostNameNotRequiredErr')).to.equal(true);
-      expect(controller.get('hostNameEmptyError')).to.equal(false);
+      controller.set('manualInstall', false);
+      controller.set('hostNames', 'ambari');
+      controller.set('hasSubmitted', true);
+      expect(controller.get('hostsError')).to.equal(null);
     })
 
-    it('should set hostNameErr to true,  ' +
-      'hostNameEmptyError and hostNameNotRequiredErr to false, ' +
-      ' if manualInstall is false and hostNames has an element that starts' +
-      ' with hyphen', function () {
+    it('should return t(installer.step2.hostName.error.invalid) if manualInstall is false and hostNames has an element ' +
+      'that starts with a hyphen', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('manualInstall', false);
       controller.set('hostNames', "-apache");
-      expect(controller.validateStep2()).to.equal(false);
-      expect(controller.get('hostNameEmptyError')).to.equal(false);
-      expect(controller.get('hostNameNotRequiredErr')).to.equal(false);
+      expect(controller.get('hostsError')).to.equal(Ember.I18n.t('installer.step2.hostName.error.invalid'));
     })
 
-    it('should set hostNameErr to true and,  ' +
-      'hostNameEmptyError and hostNameNotRequiredErr to false, ' +
-      ' if manualInstall is false and hostNames has an element that ends' +
-      ' with hyphen', function () {
+    it('should return t(installer.step2.hostName.error.invalid) if manualInstall is false and hostNames has an element ' +
+      'that ends with a hyphen', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('manualInstall', false);
       controller.set('hostNames', 'apache-');
-      expect(controller.validateStep2()).to.equal(false);
-      expect(controller.get('hostNameEmptyError')).to.equal(false);
-      expect(controller.get('hostNameNotRequiredErr')).to.equal(false);
+      expect(controller.get('hostsError')).to.equal(Ember.I18n.t('installer.step2.hostName.error.invalid'));
+    })
+
+    it('should return t(installer.step2.hostName.error.required) if manualInstall is true, hostNames is empty, and ' +
+      'hasSubmitted is true', function () {
+      var controller = App.InstallerStep2Controller.create();
+      controller.set('manualInstall', true);
+      controller.set('hostNames', '');
+      controller.set('hasSubmitted', true);
+      expect(controller.get('hostsError')).to.equal(Ember.I18n.t('installer.step2.hostName.error.required'));
     })
 
-    it('hostNameEmptyError, hostNameNotRequiredErr and hostNameErr to false, ' +
-      'hostNameErrMsg to null if manualInstall is true and hostNames is null',
-      function () {
-        var controller = App.InstallerStep2Controller.create();
-        controller.set('manualInstall', true);
-        controller.set('hostNames', '');
-        controller.validateStep2();
-        expect(controller.validateStep2()).to.equal(true);
-        expect(controller.get('hostNameEmptyError')).to.equal(false);
-        expect(controller.get('hostNameNotRequiredErr')).to.equal(false);
-        expect(controller.get('hostNameErrMsg')).to.equal('');
-      })
-
-
-    it('should set sshKeyNullErr to true if ' +
-      'manualInstall is false and sshKey is empty', function () {
+  })
+
+  describe('#sshKeyError()', function () {
+    it('should return t(installer.step2.sshKey.error.required) to true if manualInstall is false, sshKey is empty, ' +
+      'and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('manualInstall', false);
       controller.set('sshKey', '');
-      controller.validateStep2();
-      expect(controller.get('sshKeyNullErr')).to.equal(true);
+      controller.set('hasSubmitted', true);
+      expect(controller.get('sshKeyError')).to.equal(Ember.I18n.t('installer.step2.sshKey.error.required'));
     })
 
-    it('should set sshKeyNullErr to false if sshKey is null but manualInstall is true', function () {
+    it('should return null if manualInstall is true, sshKey is empty, and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('sshKey', '');
       controller.set('manualInstall', true);
-      controller.validateStep2();
-      expect(controller.get('sshKeyNullErr')).to.equal(false);
+      controller.set('hasSubmitted', true);
+      expect(controller.get('sshKeyError')).to.equal(null);
     })
 
-    it('should set sshKeyNullErr to false if sshKey is not null', function () {
+    it('should return null if sshKey is not null and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('sshKey', 'ambari');
-      controller.validateStep2();
-      expect(controller.get('sshKeyNullErr')).to.equal(false);
+      controller.set('hasSubmitted', true);
+      expect(controller.get('sshKeyError')).to.equal(null);
     })
 
+  })
+    /* Passphrase has been disabled, so commenting out tests
     it('should set passphraseMatchErr to true if ' +
       'passphrase and confirmPassphrase doesn\'t match ', function () {
       var controller = App.InstallerStep2Controller.create();
@@ -135,44 +122,37 @@ describe('App.InstallerStep2Controller', function () {
       controller.validateStep2();
       expect(controller.get('passphraseMatchErr')).to.equal(false);
     })
+    */
+
+  describe('#localRepoError()', function() {
 
-    it('should set softRepoLocalPathNullErr to true if ' +
-      'localRepo is true and localRepoPath is null', function () {
+    it('should return t(installer.step2.localRepo.error.required) localRepo is true, localRepoPath is empty, and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('localRepo', true);
       controller.set('localRepoPath', '');
-      controller.validateStep2();
-      expect(controller.get('softRepoLocalPathNullErr')).to.equal(true);
-
-
+      controller.set('hasSubmitted', true);
+      expect(controller.get('localRepoError')).to.equal(Ember.I18n.t('installer.step2.localRepo.error.required'));
     })
 
-
-    it('should set softRepoLocalPathNullErr to false if localRepo is true and ' +
-      'localRepoPath is not null', function () {
+    it('should return null if localRepo is true, localRepoPath is not empty, and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('localRepo', true);
       controller.set('localRepoPath', '/etc/');
-      controller.validateStep2();
-      expect(controller.get('softRepoLocalPathNullErr')).to.equal(false);
+      controller.set('hasSubmitted', true);
+      expect(controller.get('localRepoError')).to.equal(null);
     })
 
-    it('should set softRepoLocalPathNullErr to false if localRepoPath is null ' +
-      'but localRepo is false', function () {
+    it('should return null if localRepo is false, localRepoPath is empty, and hasSubmitted is true', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('localRepo', false);
       controller.set('localRepoPath', '');
-      controller.validateStep2();
-      expect(controller.get('softRepoLocalPathNullErr')).to.equal(false);
+      controller.set('hasSubmitted', true);
+      expect(controller.get('localRepoError')).to.equal(null);
     })
   })
 
-})
-
-describe('App.InstallerStep2Controller', function () {
-
   describe('#evaluateStep2(): On hitting step2 \"next\" button', function () {
-    it('should return false, if isSubmitDisabled is true ', function () {
+    it('should return false if isSubmitDisabled is true ', function () {
       var controller = App.InstallerStep2Controller.create();
       controller.set('isSubmitDisabled', true);
       expect(controller.evaluateStep2()).to.equal(false);