Ver código fonte

AMBARI-723. Implement Installer Welcome page and Install Options page (Contributed by Jaimin Jetly)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/branches/AMBARI-666@1384154 13f79535-47bb-0310-9956-ffa450edef68
Yusaku Sako 12 anos atrás
pai
commit
044f32e627

+ 3 - 0
AMBARI-666-CHANGES.txt

@@ -12,6 +12,9 @@ AMBARI-666 branch (unreleased changes)
 
   NEW FEATURES
 
+  AMBARI-723. Implement Installer Welcome page and Install Options page
+ (Jaimin Jetly via yusaku)
+
   AMBARI-726. ORM-based data access layer for new design (Jaimin Jetly via hitesh)
 
   AMBARI-728. Initial work on ServiceComponentNode FSM. (hitesh)

+ 3 - 0
ambari-web/app/controllers.js

@@ -22,4 +22,7 @@
 require('controllers/application');
 require('controllers/login');
 require('controllers/installer');
+require('controllers/installer/step1');
+require('controllers/installer/step2');
+require('controllers/installer/step3');
 require('controllers/installer/step7');

+ 0 - 187
ambari-web/app/controllers/installer.js

@@ -23,193 +23,6 @@ App.InstallerController = Em.Controller.extend({
 
   name: 'installerController',
 
-  clusterName: '',
-  validClusterName: true,
-  hostNames: '',
-  hostNameArr: [],
-  errorMsg_clusterName: '',
-  hostNameEmptyError: false,
-
-  hostNameErr: false,
-  manualInstall: false,
-  hostNameNotRequireErr: false,
-  InstallType: 'ambariDriven',
-  sshKey: '',
-  passphrase: '',
-  confirmPassphrase: '',
-  sshKeyNullErr: false,
-  passphraseNullErr: false,
-  passphraseMatchErr: false,
-  localRepo: false,
-  softRepo: 'remote',
-  localRepoPath: '',
-  softRepoLocalPathNullErr: false,
-
-  hideRepoErrMsg: function () {
-    if (this.get('localRepo') === false) {
-      this.set('softRepoLocalPathNullErr', false);
-    }
-  }.observes('localRepo'),
-
-  hostManageErr: function () {
-    if (this.get('hostNameEmptyError') || this.get('hostNameNotRequireErr') || this.get('hostNameErr') || this.get('sshKeyNullErr') || this.get('passphraseMatchErr')) {
-      return true;
-    } else {
-      return false
-    }
-  }.property('hostNameEmptyError', 'hostNameNotRequireErr', 'hostNameErr', 'sshKeyNullErr', 'passphraseMatchErr'),
-
-  advOptErr: function () {
-    if (this.get('softRepoLocalPathNullErr')) {
-      return true;
-    } else {
-      return false
-    }
-  }.property('softRepoLocalPathNullErr'),
-
-  evaluateStep1: function () {
-    //TODO: Done
-    //task1 =  checks on valid cluster name
-    //task2 (prereq(task1 says it's a valid cluster name)) =  storing cluster name in localstorage
-    var result;
-    console.log('TRACE: Entering controller:Installer:evaluateStep1 function');
-    if (this.get('clusterName') == '') {
-      this.set('errorMsg_clusterName', App.messages.step1_clusterName_error_null);
-      this.set('validClusterName', false);
-      result = false;
-    } else if (/\s/.test(this.get('clusterName'))) {
-      console.log('White spaces not allowed for cluster name');
-      this.set('errorMsg_clusterName', App.messages.step1_clusterName_error_Whitespaces);
-      this.set('validClusterName', false);
-      result = false;
-    } else if (/[^\w\s]/gi.test(this.get('clusterName'))) {
-      console.log('Special characters are not allowed for the cluster name');
-      this.set('errorMsg_clusterName', App.messages.step1_clusterName_error_specialChar);
-      this.set('validClusterName', false);
-      result = false;
-    } else {
-      console.log('value of clusterNmae is: ' + this.get('clusterName'));
-      this.set('validClusterName', true);
-      result = true;
-    }
-    if (result === true) {
-      App.db.setClusterName(this.get('clusterName'));
-    }
-    console.log('Exiting the evaluatestep1 function');
-    return result;
-  },
-
-  evaluateStep2: function () {
-    // TODO: evaluation/manipulation at the end of step2
-    //task1 = do primary validations on whole step before executing any further steps
-    //task2 = parsing hostnames string to hostnames json array
-    //task3 = check validation for every hostname and store it in localstorage
-    //task4 = Storing ambari agent Install type in localStorage (InstallType maps at host level and so every host will have this as an property)
-    //task5 = Storing path of software repository(remote/local repo) to localStorage
-    //task6 = call to rest API: @Post http://ambari_server/api/bootstrap
-    //task7 =  On faliure of the previous call, show 'error injecting host information in server db'
-    //task8 =  On success of the previous call, go to step 3(awesome....)
-
-    console.log('TRACE: Entering controller:Installer:evaluateStep2 function');
-    /**                 task1                **/
-    console.log('value of manual install is: ' + this.get('manualInstall'));
-    if (this.get('hostNames') === '' && this.get('manualInstall') === false) {
-      this.set('hostNameEmptyError', true);
-      this.set('hostNameNotRequireErr', false);
-      return false;
-    } else if (this.get('hostNames') !== '' && this.get('manualInstall') === true) {
-      this.set('hostNameNotRequireErr', true);
-      this.set('hostNameEmptyError', false);
-      return false;
-    } else {
-      this.set('hostNameEmptyError', false);
-      this.set('hostNameNotRequireErr', false);
-    }
-
-    if (this.get('manualInstall') === false) {
-      if (this.get('sshKey') === '') {
-        this.set('sshKeyNullErr', true);
-        return false;
-      }
-      else {
-        this.set('sshKeyNullErr', false);
-      }
-      if (this.get('passphrase') !== this.get('confirmPassphrase')) {
-        this.set('passphraseMatchErr', true);
-        return false;
-      } else {
-        this.set('passphraseMatchErr', false);
-      }
-    }
-
-    if (this.get('localRepo') === true) {
-      if (this.get('localRepoPath') === '') {
-        this.set('softRepoLocalPathNullErr', true);
-        return false;
-      } else {
-        this.set('softRepoLocalPathNullErr', false);
-      }
-    } else {
-      this.set('softRepoLocalPathNullErr', false);
-    }
-
-
-    /**                 task2  task3 task4                      **/
-    this.hostNameArr = this.get('hostNames').split('\s');
-    for (var i = 0; i < this.hostNameArr.length; i++) {
-      //TODO: other validation for hostnames will be covered over here
-      // For now hostname that are starting or ending with '-' are not allowed
-      if (/^\-/.test(this.hostNameArr[i]) || /\-$/.test(this.hostNameArr[i])) {
-        console.log('Invalide host name' + this.hostNameArr[i]);
-        alert('Invalide host name: ' + this.hostNameArr[i]);
-        this.set('hostNameErr', true);
-        return false;
-      } else {
-        this.set('hostNameErr', false);
-      }
-    }
-    var hostInfo = {};
-    for (var i = 0; i < this.hostNameArr.length; i++) {
-      hostInfo[this.hostNameArr[i]] = {'name': this.hostNameArr[i]};
-      // hostInfo[this.hostNameArr[i]].name =  this.hostNameArr[i];
-      hostInfo[this.hostNameArr[i]].installType = this.get('InstallType');
-    }
-    App.db.setHosts(hostInfo);
-
-
-    /**                     task4                    **/
-    var softRepoInfo = {'type': this.get('softRepo'), 'path': ''};
-
-    if ('success' == 'success') {
-      return true;
-    } else {
-      return false;
-    }
-
-  },
-  evaluateStep3: function () {
-    // TODO: evaluation at the end of step3
-    /* Not sure if below tasks are to be covered over here
-     * as these functions are meant to be called at the end of a step
-     * and the following tasks are interactive to the page and not on clicking next button.
-     *
-     * task1 will be a function called on entering step3 from step3 connectoutlet or init function in InstallerStep3 View.
-     * task2 will be a parsing function that on reaching a particular condition(all hosts are in success or faliue status)  will stop task1
-     * task3 will be a function binded to remove button
-     * task4 will be a function binded to retry button
-     *
-     *
-     * keeping it over here for now
-     */
-
-
-    //task1 = start polling with rest API @Get http://ambari_server/api/bootstrap.
-    //task2 = stop polling when all the hosts have either success or failure status.
-    //task3(prerequisite = remove) = Remove set of selected hosts from the localStorage
-    //task4(prerequisite = retry) = temporarily store list of checked host and call to rest API: @Post http://ambari_server/api/bootstrap
-
-
-  },
   evaluateStep4: function () {
     // TODO: evaluation at the end of step4
 

+ 60 - 0
ambari-web/app/controllers/installer/step1.js

@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.InstallerStep1Controller = Em.Controller.extend({
+  name: 'installerStep1Controller',
+  content: [],
+  clusterName: '',
+  validClusterName: true,
+  clusterNameError: '',
+
+  evaluateStep1: function () {
+    //TODO: Done
+    //task1 =  checks on valid cluster name
+    //task2 (prereq(task1 says it's a valid cluster name)) =  storing cluster name in localstorage
+    var result;
+    console.log('TRACE: Entering controller:InstallerStep1:evaluateStep1 function');
+    if (this.get('clusterName') == '') {
+      this.set('clusterNameError', App.messages.step1_clusterName_error_required);
+      this.set('validClusterName', false);
+      result = false;
+    } else if (/\s/.test(this.get('clusterName'))) {
+      console.log('White spaces not allowed for cluster name');
+      this.set('clusterNameError', App.messages.step1_clusterName_error_whitespaces);
+      this.set('validClusterName', false);
+      result = false;
+    } else if (/[^\w\s]/gi.test(this.get('clusterName'))) {
+      console.log('Special characters are not allowed for the cluster name');
+      this.set('clusterNameError', App.messages.step1_clusterName_error_specialChar);
+      this.set('validClusterName', false);
+      result = false;
+    } else {
+      console.log('value of clusterNmae is: ' + this.get('clusterName'));
+      this.set('clusterNameError', '');
+      this.set('validClusterName', true);
+      result = true;
+    }
+    if (result === true) {
+      App.db.setClusterName(this.get('clusterName'));
+    }
+    console.log('Exiting the evaluatestep1 function');
+    return result;
+  }.observes('clusterName')
+})

+ 246 - 0
ambari-web/app/controllers/installer/step2.js

@@ -0,0 +1,246 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.InstallerStep2Controller = Em.Controller.extend({
+  name: 'installerStep2Controller',
+  content: [],
+  hostNames: '',
+  hostNameArr: [],
+  hostNameEmptyError: false,
+  hostNameErr: false,
+  manualInstall: false,
+  hostNameNotRequireErr: false,
+  sshKey: '',
+  passphrase: '',
+  confirmPassphrase: '',
+  sshKeyNullErr: false,
+  passphraseNullErr: false,
+  passphraseMatchErr: false,
+  localRepo: false,
+  localRepoPath: '',
+  softRepoLocalPathNullErr: false,
+  showPopup: false,
+
+  installType: function () {
+    if (this.get('manualInstall') === true) {
+      return 'manualDriven';
+    } else {
+      return 'ambariDriven';
+    }
+  }.observes('manualInstall'),
+
+  hideRepoErrMsg: function () {
+    if (this.get('localRepo') === false) {
+      this.set('softRepoLocalPathNullErr', false);
+    }
+  }.observes('localRepo'),
+
+  hostNamesErr: function () {
+    if (this.get('hostNameEmptyError') || this.get('hostNameNotRequireErr') || this.get('hostNameErr')) {
+      this.set('sshKeyNullErr', false);
+      this.set('passphraseMatchErr', false);
+      this.set('softRepoLocalPathNullErr', false);
+      return true;
+    } else {
+      return false;
+    }
+  }.property('hostNameEmptyError', 'hostNameNotRequireErr', 'hostNameErr'),
+
+  hostManageErr: function () {
+    if (this.get('hostNameEmptyError') || this.get('hostNameNotRequireErr') || this.get('hostNameErr') || this.get('sshKeyNullErr') || this.get('passphraseMatchErr')) {
+      return true;
+    } else {
+      return false
+    }
+  }.property('hostNameEmptyError', 'hostNameNotRequireErr', 'hostNameErr', 'sshKeyNullErr', 'passphraseMatchErr'),
+
+  sshKeyErr: function () {
+    if (this.get('sshKeyNullErr') === true) {
+      this.set('passphraseMatchErr', false);
+    }
+
+  }.observes('sshKeyNullErr'),
+
+  sshLessInstall: function () {
+    if (this.get('manualInstall') === true) {
+      this.set('hostManageErr', false);
+      this.set('hostNameEmptyError', false);
+      this.set('hostNameNotRequireErr', false);
+      this.set('sshKeyNullErr', false);
+      this.set('passphraseMatchErr', false);
+    }
+  }.observes('manualInstall'),
+
+  advOptErr: function () {
+    if (this.get('softRepoLocalPathNullErr')) {
+      return true;
+    } else {
+      return false
+    }
+  }.property('softRepoLocalPathNullErr'),
+
+  softRepo: function () {
+    if (this.get('localRepo') === false) {
+      this.set('localRepoPath', '');
+    }
+  }.observes('localRepo'),
+
+
+  evaluateStep2: function () {
+    // TODO:DONE
+    //task1 = do primary validations on whole step before executing any further steps
+    //task2 = parsing hostnames string to hostnames json array
+    //task3 = check validation for every hostname and store it in localstorage
+    //task4 = Storing ambari agent Install type in localStorage (installType maps at host level and so every host will have this as an property)
+    //task5 = Storing path of software repository(remote/local repo) to localStorage
+    //task6 = call to rest API: @Post http://ambari_server/api/bootstrap
+    //task7 = On manual Install, next button click pops up a warning with "proceed" and "close" buttons
+    //task8 =  On faliure of the previous call, show 'error injecting host information in server db'
+    //task9 =  On success of the previous call, go to step 3(awesome....)
+
+    console.log('TRACE: Entering controller:InstallerStep2:evaluateStep2 function');
+    /**                 task1                **/
+    console.log('value of manual install is: ' + this.get('manualInstall'));
+    if (this.get('hostNames') === '' && this.get('manualInstall') === false) {
+      this.set('hostNameEmptyError', true);
+      this.set('hostNameNotRequireErr', false);
+      return false;
+    } else if (this.get('hostNames') !== '' && this.get('manualInstall') === true) {
+      this.set('hostNameNotRequireErr', true);
+      this.set('hostNameEmptyError', false);
+      return false;
+    } else {
+      this.set('hostNameEmptyError', false);
+      this.set('hostNameNotRequireErr', false);
+    }
+
+    if (this.get('manualInstall') === false) {
+      if (this.get('sshKey') === '') {
+        this.set('sshKeyNullErr', true);
+        return false;
+      }
+      else {
+        this.set('sshKeyNullErr', false);
+      }
+      if (this.get('passphrase') !== this.get('confirmPassphrase')) {
+        this.set('passphraseMatchErr', true);
+        return false;
+      } else {
+        this.set('passphraseMatchErr', false);
+      }
+    }
+
+    if (this.get('localRepo') === true) {
+      if (this.get('localRepoPath') === '') {
+        this.set('softRepoLocalPathNullErr', true);
+        return false;
+      } else {
+        this.set('softRepoLocalPathNullErr', false);
+      }
+    } else {
+      this.set('softRepoLocalPathNullErr', false);
+    }
+
+
+    /**                 task2  task3 task4                      **/
+    this.hostNameArr = this.get('hostNames').split('\s');
+    for (var i = 0; i < this.hostNameArr.length; i++) {
+      //TODO: other validation for hostnames will be covered over here
+      // For now hostname that are starting or ending with '-' are not allowed
+      if (/^\-/.test(this.hostNameArr[i]) || /\-$/.test(this.hostNameArr[i])) {
+        console.log('Invalide host name' + this.hostNameArr[i]);
+        alert('Invalide host name: ' + this.hostNameArr[i]);
+        this.set('hostNameErr', true);
+        return false;
+      } else {
+        this.set('hostNameErr', false);
+      }
+    }
+    var hostInfo = {};
+    for (var i = 0; i < this.hostNameArr.length; i++) {
+      hostInfo[this.hostNameArr[i]] = {'name': this.hostNameArr[i]};
+      // hostInfo[this.hostNameArr[i]].name =  this.hostNameArr[i];
+      hostInfo[this.hostNameArr[i]].installType = this.get('installType');
+    }
+    App.db.setHosts(hostInfo);
+
+
+    /**                     task5                    **/
+    var repoType;
+    var repoPath;
+    if (this.get('localRepo') === false) {
+      repoType = 'remote';
+      repoPath = null;
+    } else {
+      repoType = 'local';
+      repoPath = this.get('localRepoPath');
+    }
+    var softRepoInfo = {'type': repoType, 'path': repoPath};
+    App.db.setSoftRepo(softRepoInfo);
+
+
+    /**                      task6                  **/
+
+
+    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");
+          return true;
+        },
+        error: function () {
+          console.log("ERRORRORR");
+          return false;
+        },
+        statusCode: {
+          404: function () {
+            console.log("URI not found.");
+            alert("URI not found");
+            //After the bootstrap call hook up change the below return statement to "return false"
+            return true;
+          }
+        },
+        dataType: 'application/json'
+      });
+    } else {
+      //popup window for "manual install" caution. if "OK" button is hit return true else return false
+      console.log('In showpopup function');
+      this.set('showPopup', true);
+
+      return true;
+    }
+
+    console.log("TRACE: program should never reach over here!!!:( ");
+
+    if ('success' == 'success') {
+      return true;
+    } else {
+      return false;
+    }
+  }
+});

+ 46 - 0
ambari-web/app/controllers/installer/step3.js

@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+App.InstallerStep3Controller = Em.Controller.extend({
+  name: 'installerStep3Controller',
+  content: [],
+  evaluateStep3: function () {
+    // TODO: evaluation at the end of step3
+    /* Not sure if below tasks are to be covered over here
+     * as these functions are meant to be called at the end of a step
+     * and the following tasks are interactive to the page and not on clicking next button.
+     *
+     * task1 will be a function called on entering step3 from step3 connectoutlet or init function in InstallerStep3 View.
+     * task2 will be a parsing function that on reaching a particular condition(all hosts are in success or faliue status)  will stop task1
+     * task3 will be a function binded to remove button
+     * task4 will be a function binded to retry button
+     *
+     *
+     * keeping it over here for now
+     */
+
+
+    //task1 = start polling with rest API @Get http://ambari_server/api/bootstrap.
+    //task2 = stop polling when all the hosts have either success or failure status.
+    //task3(prerequisite = remove) = Remove set of selected hosts from the localStorage
+    //task4(prerequisite = retry) = temporarily store list of checked host and call to rest API: @Post http://ambari_server/api/bootstrap
+
+
+  }
+});

+ 58 - 51
ambari-web/app/messages.js

@@ -20,56 +20,63 @@
 var App = require('app');
 
 App.messages = {
-	'app_name': 'Ambari',
-	'page_title': 'Ambari',
-	'installer_welcome': 'Welcome to Ambari installation wizard',
-	'login_error': 'Invalid username/password combination.',
-	'login_header': 'Sign in',
-	'username_label': 'Username',
-	'password_label': 'Password',
-	'login_button': 'Sign in',
-
-  "step1_header": "Welcome",
-  "step2_header": "Install Options",
-  "step3_header": "Confirm Hosts",
-  "step4_header": "Choose Services",
-  "step5_header": "Assign Masters",
-  "step6_header": "Assign Slaves",
-  "step7_header": "Customize Services",
-  "step8_header": "Review",
-  "step9_header": "Install, Start and Test",
-  "step10_header": "Summary",
-	'page_footer_body': '<a href = \"http://www.apache.org/licenses/LICENSE-2.0\" target = \"_blank\">Licensed under the ' +
-		'Apache License, Version 2.0</a>.<br><a href = \"/licenses/NOTICE.txt\" target = \"_blank\">See third-party ' +
-		'tools/resources that Ambari uses and their respective authors</a>',
-	'step1_clusterName_error_null': 'Cluster Name cannot be null value',
-	'step1_clusterName_error_Whitespaces': 'Cluster Name cannot contain white spaces',
-	'step1_clusterName_error_specialChar': 'Cluster Name cannot have hyphen as first or last alphabet',
-	'topnav_help_link': 'http://incubator.apache.org/ambari/install.html',
-	'welcome_header': 'Welcome to Ambari!',
-	'step2_targetHosts': '<p>Enter a list of host names, one per line. Or use <a href=\"javascript:void 0\"> ' +
-		'Pattern expression</a> </p>',
-	'step2_targetHosts_label': 'Specify Hosts to Manage',
-	'step2_hostNameEmptyError': 'host names cannot be left empty',
-	'step2_sshKeyNullErr': 'ssh key cannot be empty' ,
-	'step2_passphraseMatchErr': '\"Confirm passphrase\" doesn\'t matches \"passphrase\" value',
-	'step2_hostNameNotRequireErr' : 'Host names not required for manual install of ambari agents',
-	'step2_softRepo_default_localPath': '/etc/yum/repos.d/hdp',
-	'step2_softRepo_remotePath': '',
-	'step2_advancedOption_label': 'Advanced Options',
-	'step2_repoConf_label': 'Yum Repository Configuration File Path',
-	'step2_localRepoExplan': '<p>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 internet.</p>',
-	'welcome_body': '<p>Ambari makes it easy for you to install, configure, and manage your Hadoop cluster.<br>First, ' +
-		'we will walk you through setting up your cluster with a step-by-step wizard.</p>',
-	'welcome_note': 'Before you proceed, make sure you have performed all the pre-installation steps.',
-	'welcome_submit_label': 'Get started',
-	'installFailed_header': 'Cluster installation failed',
-	'installFailed_body': 'Cluster installation failed.  To continue, you will need to uninstall the cluster first and ' +
-		're-install the cluster.',
-	'installFailed_submit_label': 'Start the uninstall process',
-	'uninstallFailed_header': 'Cluster uninstallation failed',
-	'uninstallFailed_body': 'Failed to uninstall the cluster'
+  'app_name': 'Ambari',
+  'page_title': 'Ambari',
+  'installer_welcome': 'Welcome to Ambari installation wizard',
+  'login_error': 'Invalid username/password combination.',
+  'login_header': 'Sign in',
+  'username_label': 'Username',
+  'password_label': 'Password',
+  'login_button': 'Sign in',
+  'step1_header': 'Ambari Cluster Install Wizard',
+  'step1_body': 'Welcome to Apache Ambari<br>' +
+    'Ambari makes it really easy to install,manage, and monitor Hadoop clusters.<br\>' +
+    'We will walk you through the cluster installation process with this ' +
+    'step-by-step wizard.',
+  'step2_header': 'Install Options',
+  'step3_header': 'Confirm Hosts',
+  'step3_body': 'Here are the results of the host discovery process.<br/> ' +
+    'Please verify and remove the ones that you do not want to be the part of the cluster.',
+  'step4_header': 'Choose Services',
+  'step5_header': 'Assign Masters',
+  'step6_header': 'Assign Slaves',
+  'step7_header': 'Customize Services',
+  'step8_header': 'Review',
+  'step9_header': 'Install, Start and Test',
+  'step10_header': 'Summary',
+  'step1_clusterName_error_required': 'Cluster Name is required',
+  'step1_clusterName_error_whitespaces': 'Cluster Name cannot contain white spaces',
+  'step1_clusterName_error_specialChar': 'Cluster Name cannot contain special character',
+  'topnav_help_link': 'http://incubator.apache.org/ambari/install.html',
+  'welcome_header': 'Welcome to Ambari!',
+  'step2_targetHosts': 'Enter a list of host names, one per line. Or use',
+  'step2_targetHosts_label': 'Specify Hosts to Manage',
+  'step2_hostNameEmptyError': 'host names cannot be left empty',
+  'step2_sshKeyNullErr': 'ssh key cannot be empty',
+  'step2_passphraseMatchErr': '\"Confirm passphrase\" doesn\'t matches \"passphrase\" value',
+  'step2_hostNameNotRequireErr': 'Host names not required for ssh-less install of ambari agents',
+  'step2_manualInstallOpt': 'Do not use SSH to automatically configure the hosts ',
+  'step2_localRepoOpt': '',
+  'step2_softRepo_default_localPath': '/etc/yum/repos.d/hdp',
+  'step2_softRepo_remotePath': '',
+  'step2_advancedOption_label': 'Advanced Options',
+  'step2_repoConf_label': 'Software Repository Configuration File Path',
+  'step2_localRepoOpt': 'use a local software repository',
+  'step2_localRepoExplan': '<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 ' +
+    'using internet.</p>',
+  'step2_manualInstallExplain': 'Ambari agents will not be installed ' +
+    'automatically. You will require to install it manually on each host of ' +
+    'your cluster. Agents should be started before you step to next stage.',
+  'welcome_body': '<p>Ambari makes it easy for you to install, configure, and manage your Hadoop cluster.<br>First, ' +
+    'we will walk you through setting up your cluster with a step-by-step wizard.</p>',
+  'welcome_note': 'Before you proceed, make sure you have performed all the pre-installation steps.',
+  'welcome_submit_label': 'Get started',
+  'installFailed_header': 'Cluster installation failed',
+  'installFailed_body': 'Cluster installation failed.  To continue, you will need to uninstall the cluster first and ' +
+    're-install the cluster.',
+  'installFailed_submit_label': 'Start the uninstall process',
+  'uninstallFailed_header': 'Cluster uninstallation failed',
+  'uninstallFailed_body': 'Failed to uninstall the cluster'
 };
 

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

@@ -50,7 +50,7 @@ module.exports = Em.Route.extend({
     },
     next: function (router, context) {
       console.log('In step1 transiting to step2');
-      var result = router.get('installerController').evaluateStep1();
+      var result = router.get('installerStep1Controller').evaluateStep1();
       if (result === true) {
         App.InstallerStep1View.remove;
         router.transitionTo('step2');
@@ -69,7 +69,8 @@ module.exports = Em.Route.extend({
     back: Em.Router.transitionTo('step1'),
     next: function (router, context) {
       console.log('In step2 transiting to step3');
-      var result = router.get('installerController').evaluateStep2();
+      $('#myModal').modal('hide');
+      var result = router.get('installerStep2Controller').evaluateStep2();
       if (result) {
         router.transitionTo('step3');
       }

+ 17 - 22
ambari-web/app/templates/installer/step1.hbs

@@ -18,31 +18,26 @@
 
 
 <h2>{{App.messages.step1_header}}</h2>
-{{#view App.Step1ParentView}}
+<p class="alert alert-info">{{{App.messages.step1_body}}}</p>
+<div {{bindAttr class="validClusterName::error :control-group"}}>
+  <label class="control-label" for="cluster-name">Name of Your Cluster
+    <a href="javascript:void(null)"
+       rel="popover"
+       title="Cluster name"
+       data-content="Enter a unique cluster name. Cluster name cannot be changed later.">
+      Learn more</a>
+  </label>
 
-{{#if validClusterName}}
-{{#view App.Step1ChildView}}
-<div>
-    <label><strong>Name of Your Cluster</strong></label>
-    {{view Ember.TextField  valueBinding="clusterName" target="controller"}}
-</div>
-{{/view}}
-
-{{else}}
-{{#view App.Step1ChildErrView}}
-<div class="control-group error">
-    <label class="control-label" for="inputError"><strong>Name of Your Cluster</strong></label>
 
-    <div class="controls">
-        {{view Ember.TextField id="inputError" valueBinding="clusterName" target="controller"}}
-        <p class="help-inline">{{errorMsg_clusterName}}</p>
-    </div>
+  <div class="controls">
+    {{view Ember.TextField id="cluster-name" valueBinding="clusterName" placeholder="cluster name" target="controller"}}
+    <p class="help-inline">{{clusterNameError}}</p>
+  </div>
 </div>
-{{/view}}
-{{/if}}
-
 
 <div class="btn-area">
-    <a class="btn btn-success" {{action next}}>Next</a>
+  <a class="btn btn-success" {{action next}}>Next</a>
 </div>
-{{/view}}
+
+
+

+ 94 - 49
ambari-web/app/templates/installer/step2.hbs

@@ -19,83 +19,128 @@
 <h2>{{App.messages.step2_header}}</h2>
 {{#view App.Step2_parentView}}
 
-
+<h5 {{bindAttr class="hostManageErr:text-error"}}>{{App.messages.step2_targetHosts_label}}</h5>
 {{#view App.Step2_child_HostManageView}}
 
-<h5 {{bindAttr class="hostManageErr:text-error"}}> {{App.messages.step2_targetHosts_label}}</h5>
-{{{App.messages.step2_targetHosts}}}
-{{view Ember.TextArea valueBinding="hostNames" rows="5"}}
-{{#if hostNameEmptyError}}
-<p class="text-error">{{App.messages.step2_hostNameEmptyError}}</p>
-{{/if}}
-{{#if hostNameNotRequireErr}}
-<p class="text-error">{{App.messages.step2_hostNameNotRequireErr}}</p>
-{{/if}}
+<div {{bindAttr class="hostNamesErr:error :control-group"}}>
+  <p>{{App.messages.step2_targetHosts}}
+    <a href="javascript:void(null)"
+       rel="popover"
+       title="Delimiters"
+       data-content="Space, tabs or new line can be used as delimineter">
+      Pattern expressions</a></p>
+
+  <div class="controls">
+    {{view Ember.TextArea class="span6" valueBinding="hostNames" rows="5" placeholder="host names"}}
+    {{#if hostNameEmptyError}}
+    <p class="help-inline">{{App.messages.step2_hostNameEmptyError}}</p>
+    {{/if}}
+    {{#if hostNameNotRequireErr}}
+    <p class="help-inline">{{App.messages.step2_hostNameNotRequireErr}}</p>
+    {{/if}}
+  </div>
+</div>
 
 <div id="hostConnectId">
+  <div class="ambari-agents">
+
+    <!-- <ul class="unstyled"> -->
+    <div {{bindAttr class="sshKeyNullErr:error :control-group"}}>
+      <div class="controls">
+        {{view Ember.TextArea class="span6" rows="4" placeholder="ssh private key" valueBinding="sshKey"}}
+        {{#if sshKeyNullErr}}
+        <span class="help-inline">{{App.messages.step2_sshKeyNullErr}}</span>
+        {{/if}}
+      </div>
+    </div>
 
-    <p>Install Ambari agents automatically via passwordless SSH</p>
-
-    <div class="ambari-agents">
-        <ul class="unstyled">
-            <li>{{view Ember.TextField type="text" placeholder="ssh private key" valueBinding="sshKey"}}</li>
-            {{#if chooseFile}}
-            <form name='hostConnectOption' enctype="multipart/form-data" method="post">
-                <fieldset>
-                    <input type="file" name="clusterDeployUserIdentityFile" id="clusterDeployUserIdentityFileId"
-                           value="">
-                </fieldset>
-            </form>
-            {{/if}}
-
-            {{#if sshKeyNullErr}}
-            <p class="text-error">{{App.messages.step2_sshKeyNullErr}}</p>
-            {{/if}}
-
-            <li>{{view Ember.TextField type="text" placeholder="passphrase" valueBinding="passphrase"}} </li>
-
+    {{view Ember.TextField type="text" placeholder="passphrase" valueBinding="passphrase"}}
 
-            <li>{{view Ember.TextField type="text" placeholder="confirm passphrase" valueBinding="confirmPassphrase"}}</li>
+    <div {{bindAttr class="passphraseMatchErr:error :control-group :ambari-agents"}}>
+      <div class="controls">
+        {{view Ember.TextField type="text" placeholder="confirm passphrase" valueBinding="confirmPassphrase"}}
 
-            {{#if passphraseMatchErr}}
-            <p class="text-error">{{App.messages.step2_passphraseMatchErr}}</p>
-            {{/if}}
-        </ul>
+        {{#if passphraseMatchErr}}
+        <p class="help-inline">{{App.messages.step2_passphraseMatchErr}}</p>
+        {{/if}}
+      </div>
     </div>
 
+    </ul>
+  </div>
+
 </div>
 {{/view}}
 
 
-<!--style="position:relative;"-->
 {{#view App.Step2_child_AdvOpt}}
-
 <h5 {{bindAttr class="advOptErr:text-error"}}>{{App.messages.step2_advancedOption_label}}</h5>
 <label class="checkbox">
-    Manually install Ambari agents on all the hosts <a href="javascript:void 0">Learn more</a>
-    {{view Ember.Checkbox checkedBinding="manualInstall"}}
+  {{App.messages.step2_manualInstallOpt}}
+  <a href="javascript:void(null)"
+     rel="popover"
+     title="Manual Install"
+     data-content="Ambari agents will not be installed automatically. You will require
+     to install it manually on each host of your cluster. Agents should be
+     started before you move to next stage.">
+    Learn more</a>
+  {{view Ember.Checkbox checkedBinding="manualInstall"}}
 </label>
 <label class="checkbox">
-    use a local software repository <a href="javascript:void 0">Learn more</a>
-    {{view Ember.Checkbox checkedBinding="localRepo"}}
+  {{App.messages.step2_localRepoOpt}}
+  <a href="javascript:void(null)"
+     rel="popover"
+     title="Local repository"
+     data-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 internet.">
+    Learn more</a>
+  {{view Ember.Checkbox checkedBinding="localRepo"}}
 </label>
 {{#if localRepo}}
 <div>
-    <label>{{App.messages.step2_repoConf_label}}</label>
-    {{view Ember.TextField type="text" placeholder="/etc/yum/repos.d/hdp" valueBinding="localRepoPath"}}
-    {{#if softRepoLocalPathNullErr}}
-    <p class="text-error">Local repository file path cannot be null</p>
-    {{/if}}
+  <label>{{App.messages.step2_repoConf_label}}</label>
+  {{view Ember.TextField type="text" placeholder="/etc/yum/repos.d/hdp" valueBinding="localRepoPath"}}
+  {{#if softRepoLocalPathNullErr}}
+  <p class="text-error">Local repository file path cannot be null</p>
+  {{/if}}
+  <div class="alert alert-info">
     {{{App.messages.step2_localRepoExplan}}}
+  </div>
 </div>
 {{/if}}
 {{/view}}
 
-{{/view}}
 <div class="btn-area">
-    <a class="btn" {{action back}}>Previous</a>
-    <a class="btn btn-success" {{action next}}>Discover and Validate</a>
+  <a class="btn" {{action back}}>Previous</a>
+  {{#if manualInstall}}
+  <a href="#manualInstallModal" role="button" class="btn btn-success"
+     data-toggle="modal" {{action "clickHandler" target="view"}}>Validate</a>
+  {{else}}
+  <a class="btn btn-success" {{action next}}> Discover and Validate </a>
+  {{/if}}
 </div>
 
+<div class="modal" id="manualInstallModal" tabindex="-1" role="dialog"
+     aria-labelledby="myModalLabel" style="display: none;" aria-hidden="true">
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
+      x
+    </button>
+    <h3 id="manualInstallModalLabel">Manual Install</h3>
+  </div>
+  <div class="modal-body">
+    <p>Ambari agents shoud be manually installed before you proceed ahead.</p>
+  </div>
+  <div class="modal-footer">
+    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
+    <button class="btn btn-primary" data-dismiss="modal"
+            aria-hidden="true" {{action next}} >Proceed
+    </button>
+  </div>
+</div>
+
+{{/view}}
+
 
 

+ 2 - 0
ambari-web/app/templates/installer/step3.hbs

@@ -18,6 +18,8 @@
 
 
 <h2>{{App.messages.step3_header}} </h2>
+<p class="alert alert-info">{{{App.messages.step3_body}}}</p>
+
 <a class="btn" {{action retry}}>Retry</a>
 <a class="btn" {{action remove}}>Remove</a> <br/>
 <div class="btn-area">

+ 4 - 17
ambari-web/app/views/installer/step1.js

@@ -21,21 +21,8 @@ var App = require('app');
 
 App.InstallerStep1View = Em.View.extend({
 
-  templateName: require('templates/installer/step1')
-
-});
-
-App.Step1ParentView = Em.View.extend({
-
+  templateName: require('templates/installer/step1'),
+  didInsertElement: function () {
+    $("[rel=popover]").popover({'placement': 'right', 'trigger': 'hover'});
+  }
 });
-
-App.Step1ChildView = Em.View.extend({
-  classNameBindings: ['isEnabled::disabled'],
-  isEnabled: false
-
-});
-
-App.Step1ChildErrView = Em.View.extend({
-  classNameBindings: ['isEnabled::enabled'],
-  isEnabled: true
-});

+ 6 - 18
ambari-web/app/views/installer/step2.js

@@ -23,15 +23,8 @@ App.InstallerStep2View = Em.View.extend({
 
   templateName: require('templates/installer/step2'),
 
-  doManualInstall: function (router, event) {
-    if (typeof jQuery != 'undefined') {
+  didInsertElement: function () {
 
-      console.log('jQuery library is loaded!');
-
-    }
-    console.log('value is: ' + $('#hostConnectId h2').text());
-    console.log('over here');
-    //alert('value is:' +  $('hostConnectId').('connect-opt').value);
   }
 
 });
@@ -40,16 +33,10 @@ App.Step2_parentView = Em.View.extend({
   isVisible: true,
   click: function () {
     console.log('parent of step2');
-  }
-});
-
-App.Step2_parent_TargetHostView = Em.View.extend({
-  ///
+  },
+  didInsertElement: function () {
+    $("[rel=popover]").popover({'placement': 'right', 'trigger': 'hover'});
 
-  ///
-  isVisible: true,
-  click: function () {
-    console.log('target hosts: child of step2');
   }
 });
 
@@ -64,7 +51,8 @@ App.Step2_child_HostManageView = Em.View.extend({
 
 App.Step2_child_AdvOpt = Em.View.extend({
   isVisible: true,
+
   click: function () {
-    console.log('Soft Repo: parent of step2');
+    console.log('Advance option : child of step2');
   }
 });