You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2012/10/18 02:17:20 UTC

svn commit: r1399489 [1/2] - in /incubator/ambari/branches/AMBARI-666: ./ ambari-web/app/ ambari-web/app/controllers/installer/ ambari-web/app/controllers/main/host/ ambari-web/app/controllers/wizard/ ambari-web/app/routes/ ambari-web/app/styles/ ambar...

Author: yusaku
Date: Thu Oct 18 00:17:19 2012
New Revision: 1399489

URL: http://svn.apache.org/viewvc?rev=1399489&view=rev
Log:
AMBARI-881. Implement Add Hosts Wizard. (yusaku)

Added:
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/main/host/add_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step2_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step3_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step4_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step5_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/add_host_routes.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host/add.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2ManualInstallPopup.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3HostLogPopup.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step4.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step5.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/main/host/add_view.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/wizard/
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/wizard/step2_view.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/wizard/step3_view.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/wizard/step4_view.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/wizard/step5_view.js
Modified:
    incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step5_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step7_controller.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/app.css
    incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/application.less
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step7.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host.hbs
    incubator/ambari/branches/AMBARI-666/ambari-web/app/utils/db.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step5_view.js
    incubator/ambari/branches/AMBARI-666/ambari-web/app/views/installer/step7_view.js

Modified: incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt (original)
+++ incubator/ambari/branches/AMBARI-666/AMBARI-666-CHANGES.txt Thu Oct 18 00:17:19 2012
@@ -12,6 +12,8 @@ AMBARI-666 branch (unreleased changes)
 
   NEW FEATURES
 
+  AMBARI-881. Implement Add Hosts Wizard. (yusaku)
+
   AMBARI-869. Util to deserialize ExecutionCommand. (jitendra)
 
   AMBARI-874. Fix hostinfo reporting at the server and add a unit test for

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers.js Thu Oct 18 00:17:19 2012
@@ -49,9 +49,14 @@ require('controllers/main/service/info/a
 require('controllers/main/alert');
 require('controllers/main/host');
 require('controllers/main/host/details');
+require('controllers/main/host/add_controller');
 require('controllers/main/dashboard');
 require('controllers/main/charts');
 require('controllers/main/charts/heatmap');
 require('controllers/main/charts/horizon_chart');
 require('controllers/main/charts/horizon_chart');
 require('controllers/main/rack');
+require('controllers/wizard/step2_controller');
+require('controllers/wizard/step3_controller');
+require('controllers/wizard/step4_controller');
+require('controllers/wizard/step5_controller');
\ No newline at end of file

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step5_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step5_controller.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step5_controller.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step5_controller.js Thu Oct 18 00:17:19 2012
@@ -404,21 +404,19 @@ App.InstallerStep5Controller = Em.Contro
       return this.get("hosts");
     }
   },
-  /*
 
    assignHostToMaster: function (masterService, selectedHost, zId) {
-   if (selectedHost && masterService) {
-   if ((masterService === "ZooKeeper") && zId) {
-   this.get('selectedServicesMasters').findProperty("zId", zId).set("selectedHost", selectedHost);
-   this.rebalanceZookeeperHosts();
-   }
-   else {
-   this.get('selectedServicesMasters').findProperty("component_name", masterService).set("selectedHost", selectedHost);
-   }
+     if (selectedHost && masterService) {
+       if ((masterService === "ZooKeeper") && zId) {
+         this.get('selectedServicesMasters').findProperty("zId", zId).set("selectedHost", selectedHost);
+         this.rebalanceZookeeperHosts();
+       }
+       else {
+         this.get('selectedServicesMasters').findProperty("component_name", masterService).set("selectedHost", selectedHost);
+       }
 
-   }
+     }
    },
-   */
 
   lastZooKeeper: function () {
     var currentZooKeepers = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper");

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step7_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step7_controller.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step7_controller.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/installer/step7_controller.js Thu Oct 18 00:17:19 2012
@@ -187,6 +187,8 @@ App.SlaveComponentGroupsController = Emb
 
   contentBinding: 'App.router.installerStep7Controller.slaveComponentHosts',
 
+  slaveComponentGroups: [],
+
   selectedComponentName: function () {
     switch (App.router.get('installerStep7Controller.selectedService.serviceName')) {
       case 'HDFS':
@@ -214,6 +216,22 @@ App.SlaveComponentGroupsController = Emb
     });
   },
 
+  addSlaveComponentGroup: function (event) {
+    var componentName = event.context;
+    var component = this.findProperty('componentName', componentName);
+    var slaveGroups = this.get('slaveComponentGroups');
+    var newGroupName;
+    console.log(slaveGroups);
+    slaveGroups.forEach(function(group) {
+
+    });
+    var newGroup = {
+      groupName: "New Group"
+    };
+    slaveGroups.pushObject(newGroup);
+    console.log(slaveGroups);
+  },
+
   showEditSlaveComponentGroups: function (event) {
     this.showAddSlaveComponentGroup(event);
   },
@@ -234,6 +252,18 @@ App.SlaveComponentGroupsController = Emb
         return component.hosts.mapProperty('group').uniq();
       }
     }
-  }.property('@each.hosts', 'selectedComponentName')
+  }.property('@each.hosts', 'selectedComponentName'),
+
+  getHostsGroups: function () {
+    var slaveGroups = this.get('slaveComponentGroups');
+    if (slaveGroups.length == 0){
+      var defaultGroup = {
+        groupName: "Default",
+        label: "default"
+      };
+      slaveGroups.pushObject(defaultGroup);
+    }
+    return slaveGroups;
+  }.property('slaveComponentGroups')
 
 });

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/main/host/add_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/main/host/add_controller.js?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/main/host/add_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/main/host/add_controller.js Thu Oct 18 00:17:19 2012
@@ -0,0 +1,364 @@
+/**
+ * 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.AddHostController = Em.Controller.extend({
+
+  name: 'addHostController',
+
+  /**
+   * All wizards data will be stored in this variable
+   */
+  content: Em.Object.create(),
+
+  /**
+   * Used for hiding back button in wizard
+   */
+  hideBackButton: true,
+
+  isStepDisabled: [],
+
+  totalSteps: 9,
+
+  init: function () {
+    this.isStepDisabled.pushObject(Ember.Object.create({
+      step: 1,
+      value: false
+    }));
+    for (var i = 2; i <= this.totalSteps; i++) {
+      this.isStepDisabled.pushObject(Ember.Object.create({
+        step: i,
+        value: true
+      }));
+    }
+  },
+
+  setStepsEnable: function () {
+    for (var i = 2; i <= this.totalSteps; i++) {
+      var step = this.get('isStepDisabled').findProperty('step', i);
+      if (i <= this.get('currentStep')) {
+        step.set('value', false);
+      } else {
+        step.set('value', true);
+      }
+    }
+  }.observes('currentStep'),
+
+  /**
+   * Return current step of Add Host Wizard
+   */
+  currentStep: function () {
+    return App.get('router').getWizardCurrentStep('addHost');
+  }.property(),
+
+  /**
+   * Set current step to new value.
+   * Method moved from App.router.setInstallerCurrentStep
+   * @param currentStep
+   * @param completed
+   */
+  setCurrentStep: function (currentStep, completed) {
+    App.db.setWizardCurrentStep('addHost', currentStep, completed);
+    this.set('currentStep', currentStep);
+  },
+
+  isStep1: function () {
+    return this.get('currentStep') == 1;
+  }.property('currentStep'),
+
+  isStep2: function () {
+    return this.get('currentStep') == 2;
+  }.property('currentStep'),
+
+  isStep3: function () {
+    return this.get('currentStep') == 3;
+  }.property('currentStep'),
+
+  isStep4: function () {
+    return this.get('currentStep') == 4;
+  }.property('currentStep'),
+
+  isStep5: function () {
+    return this.get('currentStep') == 5;
+  }.property('currentStep'),
+
+  isStep6: function () {
+    return this.get('currentStep') == 6;
+  }.property('currentStep'),
+
+  isStep7: function () {
+    return this.get('currentStep') == 7;
+  }.property('currentStep'),
+
+  isStep8: function () {
+    return this.get('currentStep') == 8;
+  }.property('currentStep'),
+
+  isStep9: function () {
+    return this.get('currentStep') == 9;
+  }.property('currentStep'),
+
+  isStep10: function () {
+    return this.get('currentStep') == 10;
+  }.property('currentStep'),
+
+  gotoStep: function (step) {
+    if (this.get('isStepDisabled').findProperty('step', step).get('value') === false) {
+      App.router.send('gotoStep' + step);
+    }
+  },
+
+  gotoStep1: function () {
+    this.gotoStep(1);
+  },
+
+  gotoStep2: function () {
+    this.gotoStep(2);
+  },
+
+  gotoStep3: function () {
+    this.gotoStep(3);
+  },
+
+  gotoStep4: function () {
+    this.gotoStep(4);
+  },
+
+  gotoStep5: function () {
+    this.gotoStep(5);
+  },
+
+  gotoStep6: function () {
+    this.gotoStep(6);
+  },
+
+  gotoStep7: function () {
+    this.gotoStep(7);
+  },
+
+  gotoStep8: function () {
+    this.gotoStep(8);
+  },
+
+  gotoStep9: function () {
+    this.gotoStep(9);
+  },
+
+  gotoStep10: function () {
+    this.gotoStep(10);
+  },
+
+  /**
+   * Load all data for <code>Specify Host(install step2)</code> step
+   * Data Example:
+   * {
+   *   hostNames: '',
+   *   manualInstall: false,
+   *   sshKey: '',
+   *   passphrase: '',
+   *   confirmPassphrase: '',
+   *   localRepo: false,
+   *   localRepoPath: ''
+   * }
+   */
+  loadHosts: function () {
+
+    if (!this.content.hosts) {
+      this.content.hosts = Em.Object.create();
+    }
+
+    //TODO : rewire it as model. or not :)
+    var hostsInfo = Em.Object.create();
+
+    hostsInfo.hostNames = App.db.getAllHostNames() || ''; //empty string if undefined
+
+    //TODO : should we check installType for add host wizard????
+    var installType = App.db.getInstallType();
+    //false if installType not equals 'manual'
+    hostsInfo.manualInstall = installType && installType.installType === 'manual' || false;
+
+    var softRepo = App.db.getSoftRepo();
+    if (softRepo && softRepo.repoType === 'local') {
+      hostsInfo.localRepo = true;
+      hostsInfo.localRepopath = softRepo.repoPath;
+    } else {
+      hostsInfo.localRepo = false;
+      hostsInfo.localRepoPath = '';
+    }
+
+    hostsInfo.sshKey = 'random';
+    hostsInfo.passphrase = '';
+    hostsInfo.confirmPassphrase = '';
+
+    this.set('content.hosts', hostsInfo);
+    console.log("AddHostController:loadHosts: loaded data ", hostsInfo);
+  },
+
+  /**
+   * Save data, which user filled, to main controller
+   * @param stepController App.WizardStep2Controller
+   */
+  saveHosts: function (stepController) {
+    //TODO: put data to content.hosts and only then save it)
+
+    //App.db.setBootStatus(false);
+    App.db.setAllHostNames(stepController.get('hostNames'));
+    App.db.setHosts(stepController.getHostInfo());
+    if (stepController.get('manualInstall') === false) {
+      App.db.setInstallType({installType: 'ambari' });
+    } else {
+      App.db.setInstallType({installType: 'manual' });
+    }
+    if (stepController.get('localRepo') === false) {
+      App.db.setSoftRepo({ 'repoType': 'remote', 'repoPath': null});
+    } else {
+      App.db.setSoftRepo({ 'repoType': 'local', 'repoPath': stepController.get('localRepoPath') });
+    }
+  },
+
+  /**
+   * Return hosts, which were add at <code>Specify Host(step2)</code> step
+   * @paramm isNew whether return all hosts or only new ones
+   */
+  getHostList: function (isNew) {
+    var hosts = [];
+    var hostArray = App.db.getHosts()
+    console.log('in addHostController.getHostList: host names is ', hostArray);
+
+    for (var i in hostArray) {
+      var hostInfo = App.HostInfo.create({
+        name: hostArray[i].name,
+        bootStatus: hostArray[i].bootStatus
+      });
+
+      hosts.pushObject(hostInfo);
+    }
+    ;
+
+    console.log('TRACE: pushing ' + hosts);
+    return hosts;
+  },
+
+  /**
+   * Remove host from model. Used at <code>Confirm hosts(step2)</code> step
+   * @param hosts Array of hosts, which we want to delete
+   */
+  removeHosts: function (hosts) {
+    //todo Replace this code with real logic
+    App.db.removeHosts(hosts);
+  },
+
+  /**
+   * Save data, which user filled, to main controller
+   * @param stepController App.WizardStep3Controller
+   */
+  saveConfirmedHosts: function (stepController) {
+    var hostInfo = {};
+    stepController.get('content').forEach(function (_host) {
+      hostInfo[_host.name] = {
+        name: _host.name,
+        cpu: _host.cpu,
+        memory: _host.memory,
+        bootStatus: _host.bootStatus
+      };
+    });
+    console.log('addHostController:saveConfirmedHosts: save hosts ', hostInfo);
+    App.db.setHosts(hostInfo);
+  },
+
+  /**
+   * Remove all data for hosts
+   */
+  clearHosts: function () {
+    var hosts = this.get('content').get('hosts');
+    if (hosts) {
+      hosts.hostNames = '';
+      hosts.manualInstall = false;
+      hosts.localRepo = '';
+      hosts.localRepopath = '';
+      hosts.sshKey = '';
+      hosts.passphrase = '';
+      hosts.confirmPassphrase = '';
+    }
+  },
+
+  /**
+   * Load services data. Will be used at <code>Select services(step4)</code> step
+   */
+  loadServices: function () {
+    var servicesInfo = App.db.getService();
+    servicesInfo.forEach(function (item, index) {
+      servicesInfo[index] = Em.Object.create(item);
+    });
+    this.set('content.services', servicesInfo);
+    console.log('addHostController.loadServices: loaded data ', servicesInfo);
+  },
+
+  /**
+   * Save data to model
+   * @param stepController App.WizardStep4Controller
+   */
+  saveServices: function (stepController) {
+    var serviceNames = [];
+    App.db.setService(stepController.get('content'));
+    stepController.filterProperty('isSelected', true).forEach(function (item) {
+      serviceNames.push(item.serviceName);
+    });
+    App.db.setSelectedServiceNames(serviceNames);
+    console.log('addHostController.saveServices: saved data ', serviceNames);
+  },
+
+  /**
+   * Load data for all steps until <code>current step</code>
+   */
+  loadAllPriorSteps: function () {
+    var step = this.get('currentStep');
+    switch (step) {
+      /*case '10':
+       this.get('installerStep9Controller').loadStep();
+       case '9':
+       this.get('installerStep8Controller').loadStep();
+       case '8':
+       this.get('installerStep7Controller').loadStep();
+       case '7':
+       this.get('installerStep6Controller').loadStep();
+       case '6':
+       this.get('installerStep5Controller').loadStep();
+       case '5':
+       this.get('installerStep4Controller').loadStep();*/
+      case '4':
+      //this.get('installerStep3Controller').loadStep();
+      case '3':
+        this.loadServices();
+      case '2':
+      case '1':
+        this.loadHosts();
+    }
+  },
+
+  /**
+   * Remove all loaded data.
+   * Created as copy for App.router.clearAllSteps
+   */
+  clearAllSteps: function () {
+    this.clearHosts();
+  }
+
+});

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step2_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step2_controller.js?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step2_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step2_controller.js Thu Oct 18 00:17:19 2012
@@ -0,0 +1,185 @@
+/**
+ * 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.WizardStep2Controller = Em.Controller.extend({
+  name: 'wizardStep2Controller',
+  hostNameArr: [],
+  hasSubmitted: false,
+
+  hostNames: function () {
+    return this.get('content.hostNames');
+  }.property('content.hostNames'),
+
+  manualInstall: function () {
+    return this.get('content.manualInstall');
+  }.property('content.manualInstall'),
+
+  localRepo: function () {
+    return this.get('content.localRepo');
+  }.property('content.localRepo'),
+
+  localRepoPath: function () {
+    return this.get('content.localRepoPath');
+  }.property('content.localRepoPath'),
+
+  sshKey: function () {
+    return this.get('content.sshKey');
+  }.property('content.sshKey'),
+
+  passphrase: function () {
+    return this.get('content.passphrase');
+  }.property('content.passphrase'),
+
+  confirmPassphrase: function () {
+    return this.get('content.confirmPassphrase');
+  }.property('content.confirmPassphrase'),
+
+  installType: function () {
+    if (this.get('manualInstall') === true) {
+      return 'manualDriven';
+    } else {
+      return 'ambariDriven';
+    }
+  }.property('manualInstall'),
+
+  isHostNameValid: function (hostname) {
+    // For now hostnames that start or end with '-' are not allowed
+    return !(/^\-/.test(hostname) || /\-$/.test(hostname));
+  },
+
+  isAllHostNamesValid: function () {
+    this.hostNameArr = this.get('hostNames').trim().split(new RegExp("\\s+", "g"));
+    for (var index in this.hostNameArr) {
+      if (!this.isHostNameValid(this.hostNameArr[index])) {
+        return false;
+      }
+    }
+    return true;
+  },
+
+  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');
+    }
+    return null;
+  }.property('hostNames', 'manualInstall', 'hasSubmitted'),
+
+  sshKeyError: function () {
+    if (this.get('hasSubmitted') && this.get('manualInstall') === false && this.get('sshKey').trim() === '') {
+      return Em.I18n.t('installer.step2.sshKey.error.required');
+    }
+    return null;
+  }.property('sshKey', 'manualInstall', 'hasSubmitted'),
+
+  localRepoError: function () {
+    if (this.get('hasSubmitted') && this.get('localRepo') && this.get('localRepoPath').trim() === '') {
+      return Em.I18n.t('installer.step2.localRepo.error.required');
+    }
+    return null;
+  }.property('localRepo', 'localRepoPath', 'hasSubmitted'),
+
+  /**
+   * Get host info, which will be saved in parent controller
+   */
+  getHostInfo: function () {
+
+    var hostNameArr = this.get('hostNameArr');
+    var hostInfo = {};
+    for (var i = 0; i < hostNameArr.length; i++) {
+      hostInfo[hostNameArr[i]] = {
+        name: hostNameArr[i],
+        installType: this.get('installType'),
+        bootStatus: 'pending'
+      };
+    }
+
+    return hostInfo;
+  },
+
+  /**
+   * Onclick handler for <code>next button</code>. Do all UI work except data saving.
+   * This work is doing by router.
+   * @return {Boolean}
+   */
+  evaluateStep: function () {
+    console.log('TRACE: Entering controller:WizardStep2:evaluateStep function');
+
+    if (this.get('isSubmitDisabled')) {
+      return false;
+    }
+
+    if (this.get('manualInstall') === true) {
+      this.manualInstallPopup();
+      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.send('next');
+      },
+      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");
+          return false;
+        }
+      },
+      dataType: 'application/json'
+    });
+  },
+
+  manualInstallPopup: function (event) {
+    App.ModalPopup.show({
+      header: Em.I18n.t('installer.step2.manualInstall.popup.header'),
+      onPrimary: function () {
+        this.hide();
+        App.router.send('next');
+      },
+      bodyClass: Ember.View.extend({
+        templateName: require('templates/wizard/step2ManualInstallPopup')
+      })
+    });
+  },
+
+  isSubmitDisabled: function () {
+    return (this.get('hostsError') || this.get('sshKeyError') || this.get('localRepoError'));
+  }.property('hostsError', 'sshKeyError', 'localRepoError')
+
+});
\ No newline at end of file

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step3_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step3_controller.js?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step3_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step3_controller.js Thu Oct 18 00:17:19 2012
@@ -0,0 +1,223 @@
+/**
+ * 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.WizardStep3Controller = Em.ArrayController.extend({
+  name: 'wizardStep3Controller',
+  content: [],
+  bootHosts: [],
+  isSubmitDisabled: false,
+  categories: ['Hosts', 'Succeeded', 'Failed'],
+  category: 'Hosts',
+  allChecked: true,
+
+  onAllChecked: function () {
+    var hosts = this.visibleHosts();
+    if (this.get('allChecked') === true) {
+      hosts.setEach('isChecked', true);
+    } else {
+      hosts.setEach('isChecked', false);
+    }
+  }.observes('allChecked'),
+
+  mockData: require('data/mock/step3_hosts'),
+  mockRetryData: require('data/mock/step3_pollData'),
+
+  /**
+   * Provide some initialisation work. Start bootstrap if needed
+   */
+  navigateStep: function () {
+    if (App.db.getBootStatus() === false) {
+      this.startBootstrap();
+    }
+  },
+
+  /**
+   * Onclick handler for <code>Retry</code> button.
+   */
+  retry: function () {
+    if (this.get('isSubmitDisabled')) {
+      return;
+    }
+    var hosts = this.visibleHosts();
+    var selectedHosts = hosts.filterProperty('isChecked', true);
+    selectedHosts.forEach(function (_host) {
+      console.log('Retrying:  ' + _host.name);
+    });
+
+    //TODO: uncomment below code to hookup with @GET bootstrap API
+    /*
+     this.set('bootHosts',selectedHosts);
+     this.doBootstrap();
+     */
+  },
+
+  /**
+   * Below function returns the current set of visible hosts on view (All, succeded, failed)
+   */
+  visibleHosts: function () {
+    if (this.get('category') === 'Succeeded') {
+      return (this.filterProperty('bootStatus', 'success'));
+    } else if (this.get('category') === 'Failed') {
+      return (this.filterProperty('bootStatus', 'error'));
+    } else if (this.get('category') === 'Hosts') {
+      return this.content;
+    }
+  },
+
+  /**
+   * Onclick handler for <code>Remove</code> button
+   */
+  removeBtn: function () {
+    if (this.get('isSubmitDisabled')) {
+      return;
+    }
+    var hostResult = this.visibleHosts();
+    var selectedHosts = hostResult.filterProperty('isChecked', true);
+    selectedHosts.forEach(function (_hostInfo) {
+      console.log('Removing:  ' + _hostInfo.name);
+    });
+
+    this.removeHosts(selectedHosts);
+  },
+
+  /**
+   * Do remove hosts logic: remove host info from UI and save it to model
+   * @param hosts
+   */
+  removeHosts: function (hosts) {
+    this.removeObjects(hosts);
+    App.router.send('removeHosts', hosts);
+  },
+
+  startBootstrap: function () {
+    this.set('isSubmitDisabled', true);
+    this.set('bootHosts', this.get('content'));
+    this.doBootstrap();
+  },
+
+  /**
+   * Below function parses and updates the content, and governs
+   * the possibility of the next doBootstrap (polling) call
+   *
+   * @param hostsFrmServer
+   * @param hostsFrmContent
+   * @return {Boolean}
+   */
+  parseHostInfo: function (hostsFrmServer, hostsFrmContent) {
+    var result = true;                    // default value as true implies if the data rendered by REST API has no hosts, polling will stop
+    hostsFrmServer.forEach(function (_hostFrmServer) {
+      var host = hostsFrmContent.findProperty('name', _hostFrmServer.name);
+      if (host !== null && host !== undefined) { // check if hostname extracted from REST API data matches any hostname in content
+        host.set('bootStatus', _hostFrmServer.status);
+        host.set('cpu', _hostFrmServer.cpu);
+        host.set('memory', _hostFrmServer.memory);
+      }
+    });
+    result = !this.content.someProperty('bootStatus', 'pending');
+    return result;
+  },
+
+  doBootstrap: function () {
+    var self = this;
+    $.ajax({
+      type: 'GET',
+      url: '/ambari_server/api/bootstrap',
+      async: false,
+      timeout: 5000,
+      success: function (data) {
+        console.log("TRACE: In success function for the GET bootstrap call");
+        var result = self.parseHostInfo(data, this.get('bootHosts'));
+        if (result !== true && App.router.getInstallerCurrentStep() === '3') {
+          window.setTimeout(self.doBootstrap, 3000);
+        } else {
+          self.stopBootstrap();
+        }
+      },
+
+      error: function () {
+        console.log("ERROR");
+        self.stopBootstrap();
+      },
+
+      statusCode: {
+        404: function () {
+          console.log("URI not found.");
+        }
+      },
+
+      dataType: 'application/json'
+    });
+
+  },
+
+  stopBootstrap: function () {
+    //TODO: uncomment following line after the hook up with the API call
+    // this.set('isSubmitDisabled',false);
+  },
+
+  hostLogPopup: function (event) {
+    App.ModalPopup.show({
+      header: Em.I18n.t('installer.step3.hostLog.popup.header'),
+      onPrimary: function () {
+        this.hide();
+      },
+      bodyClass: Ember.View.extend({
+        templateName: require('templates/installer/step3HostLogPopup')
+      })
+    });
+  },
+
+  // TODO: dummy button. Remove this after the hook up with actual REST API.
+  mockBtn: function () {
+    this.set('isSubmitDisabled', false);
+    this.clear();
+    var hostInfo = this.mockData;
+    this.renderHosts(hostInfo);
+  },
+
+  renderHosts: function (hostsInfo) {
+    var self = this;
+    hostsInfo.forEach(function (_hostInfo) {
+      var hostInfo = App.HostInfo.create({
+        name: _hostInfo.name,
+        bootStatus: _hostInfo.bootStatus
+      });
+
+      console.log('pushing ' + hostInfo.name);
+      self.content.pushObject(hostInfo);
+    });
+  },
+
+  pollBtn: function () {
+    if (this.get('isSubmitDisabled')) {
+      return;
+    }
+    var hosts = this.visibleHosts();
+    var selectedHosts = hosts.filterProperty('isChecked', true);
+
+    var mockHosts = this.mockRetryData;
+
+    if (this.parseHostInfo(mockHosts, selectedHosts)) {
+      // this.saveHostInfoToDb();
+    }
+  }
+
+});
+

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step4_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step4_controller.js?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step4_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step4_controller.js Thu Oct 18 00:17:19 2012
@@ -0,0 +1,136 @@
+/**
+ * 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.WizardStep4Controller = Em.ArrayController.extend({
+
+  name: 'wizardStep4Controller',
+  content: [],
+
+  /**
+   * Check whether all properties are selected
+   */
+  isAll: function () {
+    return this.everyProperty('isSelected', true);
+  }.property('@each.isSelected'),
+
+  /**
+   * Check whether none properties(minimum) are selected
+   */
+  isMinimum: function () {
+    return this.filterProperty('isDisabled', false).everyProperty('isSelected', false);
+  }.property('@each.isSelected'),
+
+  /**
+   * Update hidden services. Make them to have the same status as master ones.
+   */
+  checkDependencies: function () {
+    var hbase = this.findProperty('serviceName', 'HBASE');
+    var zookeeper = this.findProperty('serviceName', 'ZOOKEEPER');
+    if (hbase && zookeeper) {
+      zookeeper.set('isSelected', hbase.get('isSelected'));
+    }
+    var hive = this.findProperty('serviceName', 'HIVE');
+    var hcatalog = this.findProperty('serviceName', 'HCATALOG');
+    if (hive && hcatalog) {
+      hcatalog.set('isSelected', hive.get('isSelected'));
+    }
+  }.observes('@each.isSelected'),
+
+  /**
+   * Onclick handler for <code>select all</code> link
+   */
+  selectAll: function () {
+    this.setEach('isSelected', true);
+  },
+
+  /**
+   * onclick handler for <code>select minimum</code> link
+   */
+  selectMinimum: function () {
+    this.filterProperty('isDisabled', false).setEach('isSelected', false);
+  },
+
+  /**
+   * Check whether we should turn on <code>MapReduce</code> service
+   * @return {Boolean}
+   */
+  needToAddMapReduce: function () {
+    if (this.findProperty('serviceName', 'MAPREDUCE').get('isSelected') === false) {
+      var mapreduceDependentServices = this.filter(function (item) {
+        return ['PIG', 'OOZIE', 'HIVE'].contains(item.get('serviceName')) && item.get('isSelected', true);
+      });
+      return (mapreduceDependentServices.get('length') > 0);
+    }
+
+    return false;
+  },
+
+  /**
+   * Check do we have any monitoring service turned on
+   * @return {Boolean}
+   */
+  gangliaOrNagiosNotSelected: function () {
+    return (this.findProperty('serviceName', 'GANGLIA').get('isSelected') === false || this.findProperty('serviceName', 'NAGIOS').get('isSelected') === false);
+  },
+
+  /**
+   * Check whether user turned on monitoring service and go to next step
+   */
+  validateMonitoring: function () {
+    if (this.gangliaOrNagiosNotSelected()) {
+      App.ModalPopup.show({
+        header: Em.I18n.t('installer.step4.monitoringCheck.popup.header'),
+        body: Em.I18n.t('installer.step4.monitoringCheck.popup.body'),
+        onPrimary: function () {
+          this.hide();
+          App.router.send('next');
+        },
+        onSecondary: function () {
+          this.hide();
+        }
+      });
+    } else {
+      App.router.send('next');
+    }
+  },
+
+  /**
+   * Onlick handler for <code>Next</code> button
+   */
+  submit: function () {
+    var self = this;
+    if (this.needToAddMapReduce()) {
+      App.ModalPopup.show({
+        header: Em.I18n.t('installer.step4.mapreduceCheck.popup.header'),
+        body: Em.I18n.t('installer.step4.mapreduceCheck.popup.body'),
+        onPrimary: function () {
+          self.findProperty('serviceName', 'MAPREDUCE').set('isSelected', true);
+          this.hide();
+          self.validateMonitoring();
+        },
+        onSecondary: function () {
+          this.hide();
+        }
+      });
+    } else {
+      self.validateMonitoring();
+    }
+  }
+})
\ No newline at end of file

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step5_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step5_controller.js?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step5_controller.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/controllers/wizard/step5_controller.js Thu Oct 18 00:17:19 2012
@@ -0,0 +1,592 @@
+/**
+ * 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.WizardStep5Controller = Em.Controller.extend({
+  //properties
+  name: "wizardStep5Controller",
+  hosts: [],
+  selectedServices: [],
+  selectedServicesMasters: [],
+  zId: 0,
+  components: require('data/service_components'),
+
+  /*
+   Below function retrieves host information from local storage
+   */
+
+  clearStep: function () {
+    this.set('hosts', []);
+    this.set('selectedServices', []);
+    this.set('selectedServicesMasters', []);
+    this.set('zId', 0);
+  },
+
+  loadStep: function () {
+    console.log("TRACE: Loading step5: Assign Masters");
+    this.clearStep();
+    this.renderHostInfo(this.loadHostInfo());
+    this.renderComponents(this.loadComponents(this.loadServices()));
+  },
+
+  loadHostInfo: function () {
+    var hostInfo = [];
+    hostInfo = App.db.getHosts();
+    var hosts = new Ember.Set();
+    for (var index in hostInfo) {
+      hosts.add(hostInfo[index]);
+      console.log("TRACE: host name is: " + hostInfo[index].name);
+    }
+    return hosts.filterProperty('bootStatus', 'success');
+  },
+
+
+  renderHostInfo: function (hostsInfo) {
+
+    //wrap the model data into
+
+    hostsInfo.forEach(function (_host) {
+      var hostObj = Ember.Object.create({
+        host_name: _host.name,
+        cpu: _host.cpu,
+        memory: _host.memory
+      });
+      console.log('pushing ' + hostObj.host_name);
+      hostObj.set("host_info", "" + hostObj.get("host_name") + " ( " + hostObj.get("memory") + "GB" + " " + hostObj.get("cpu") + "cores )");
+      this.get("hosts").pushObject(hostObj);
+    }, this);
+
+
+  },
+
+  loadServices: function () {
+    var serviceInfo = App.db.getService();
+    var services = serviceInfo.filterProperty('isSelected', true).mapProperty('serviceName');
+    services.forEach(function (item) {
+      console.log("TRACE: service name is: " + item);
+      this.get("selectedServices").pushObject(Ember.Object.create({service_name: item}));
+    }, this);
+
+    return services;
+
+  },
+
+  loadComponents: function (services) {
+    var components = new Ember.Set();
+    if (App.db.getMasterComponentHosts() === undefined) {
+      var masterComponents = this.components.filterProperty('isMaster', true);
+      for (var index in services) {
+        var componentInfo = masterComponents.filterProperty('service_name', services[index]);
+        componentInfo.forEach(function (_componentInfo) {
+          console.log("TRACE: master component name is: " + _componentInfo.display_name);
+          var componentObj = {};
+          componentObj.component_name = _componentInfo.display_name;
+          componentObj.selectedHost = this.selectHost(_componentInfo.component_name);   // call the method that plays selectNode algorithm or fetches from server
+          componentObj.availableHosts = [];
+          components.add(componentObj);
+        }, this);
+      }
+    } else {
+      var masterComponentHosts = App.db.getMasterComponentHosts();
+      masterComponentHosts.forEach(function (_masterComponentHost) {
+        var componentObj = {};
+        componentObj.component_name = _masterComponentHost.component;
+        componentObj.selectedHost = _masterComponentHost.hostName;   // call the method that plays selectNode algorithm or fetches from server
+        componentObj.availableHosts = [];
+        components.add(componentObj);
+      }, this);
+    }
+    return components;
+  },
+
+  getMasterComponents: function () {
+    return (this.get('selectedServicesMasters').slice(0));
+  },
+
+  renderComponents: function (masterComponents) {
+    var zookeeperComponent = null, componentObj = null;
+    var services = [];
+    services = this.getMasterComponents();
+    if (services.length) {
+      this.set('selectedServicesMasters', []);
+    }
+
+
+    masterComponents.forEach(function (item) {
+      //add the zookeeper component at the end if exists
+      if (item.component_name === "ZooKeeper") {
+        if (services.length) {
+          services.forEach(function (_service) {
+            this.get('selectedServicesMasters').pushObject(_service);
+          }, this);
+        }
+        this.set('zId', parseInt(this.get('zId')) + 1);
+        zookeeperComponent = Ember.Object.create(item);
+        zookeeperComponent.set('zId', this.get('zId'));
+        zookeeperComponent.set("showRemoveControl", true);
+        zookeeperComponent.set("availableHosts", this.get("hosts").slice(0));
+        this.get("selectedServicesMasters").pushObject(Ember.Object.create(zookeeperComponent));
+
+      } else {
+        componentObj = Ember.Object.create(item);
+        componentObj.set("availableHosts", this.get("hosts").slice(0));
+        this.get("selectedServicesMasters").pushObject(componentObj);
+      }
+    }, this);
+  },
+
+  getKerberosServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[1];
+    } else if (noOfHosts <= 5) {
+      return hosts[1];
+    } else if (noOfHosts <= 30) {
+      return hosts[3];
+    } else {
+      return hosts[5];
+    }
+  },
+
+  getNameNode: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    return hosts[0];
+  },
+
+  getSNameNode: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else {
+      return hosts[1];
+    }
+  },
+
+  getJobTracker: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[1];
+    } else if (noOfHosts <= 5) {
+      return hosts[1];
+    } else if (noOfHosts <= 30) {
+      return hosts[1];
+    } else {
+      return hosts[2];
+    }
+  },
+
+  getHBaseMaster: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[0];
+    } else if (noOfHosts <= 5) {
+      return hosts[0];
+    } else if (noOfHosts <= 30) {
+      return hosts[2];
+    } else {
+      return hosts[3];
+    }
+  },
+
+  getOozieServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[1];
+    } else if (noOfHosts <= 5) {
+      return hosts[1];
+    } else if (noOfHosts <= 30) {
+      return hosts[2];
+    } else {
+      return hosts[3];
+    }
+  },
+
+  getOozieServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[1];
+    } else if (noOfHosts <= 5) {
+      return hosts[1];
+    } else if (noOfHosts <= 30) {
+      return hosts[2];
+    } else {
+      return hosts[3];
+    }
+  },
+
+  getHiveServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[1];
+    } else if (noOfHosts <= 5) {
+      return hosts[1];
+    } else if (noOfHosts <= 30) {
+      return hosts[2];
+    } else {
+      return hosts[4];
+    }
+  },
+
+  getTempletonServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts === 1) {
+      return hosts[0];
+    } else if (noOfHosts < 3) {
+      return hosts[1];
+    } else if (noOfHosts <= 5) {
+      return hosts[1];
+    } else if (noOfHosts <= 30) {
+      return hosts[2];
+    } else {
+      return hosts[4];
+    }
+  },
+
+  getZooKeeperServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    if (noOfHosts < 3) {
+      return [hosts[0].host_name];
+    } else {
+      return [hosts[0].host_name, hosts[1].host_name, hosts[2].host_name];
+    }
+  },
+
+  getGangliaServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    var hostnames = [];
+    var inc = 0;
+    hosts.forEach(function (_hostname) {
+      hostnames[inc] = _hostname.host_name;
+      inc++;
+    });
+    var hostExcAmbari = hostnames.without(location.hostname);
+    if (hostExcAmbari !== null || hostExcAmbari !== undefined || hostExcAmbari.length !== 0) {
+      return hostExcAmbari[0];
+    } else {
+      return hostnames[0];
+    }
+  },
+
+  getNagiosServer: function (noOfHosts) {
+    var hosts = this.get('hosts');
+    var hostnames = [];
+    var inc = 0;
+    hosts.forEach(function (_hostname) {
+      hostnames[inc] = _hostname.host_name;
+      inc++;
+    });
+    var hostExcAmbari = hostnames.without(location.hostname);
+    if (hostExcAmbari !== null || hostExcAmbari !== undefined || hostExcAmbari.length !== 0) {
+      return hostExcAmbari[0];
+    } else {
+      return hostnames[0];
+    }
+  },
+
+
+  selectHost: function (componentName) {
+    var noOfHosts = this.get('hosts').length;
+    if (componentName === 'KERBEROS_SERVER') {
+      return this.getKerberosServer(noOfHosts).host_name;
+    } else if (componentName === 'NAMENODE') {
+      return this.getNameNode(noOfHosts).host_name;
+    } else if (componentName === 'SNAMENODE') {
+      return this.getSNameNode(noOfHosts).host_name;
+    } else if (componentName === 'JOBTRACKER') {
+      return this.getJobTracker(noOfHosts).host_name;
+    } else if (componentName === 'HBASE_MASTER') {
+      return this.getHBaseMaster(noOfHosts).host_name;
+    } else if (componentName === 'OOZIE_SERVER') {
+      return this.getOozieServer(noOfHosts).host_name;
+    } else if (componentName === 'HIVE_SERVER') {
+      return this.getHiveServer(noOfHosts).host_name;
+    } else if (componentName === 'TEMPLETON_SERVER') {
+      return this.getTempletonServer(noOfHosts).host_name;
+    } else if (componentName === 'ZOOKEEPER_SERVER') {
+      var zhosts = this.getZooKeeperServer(noOfHosts);
+      var extraHosts = zhosts.slice(0, zhosts.length - 1);
+      var zooKeeperHosts = new Ember.Set();
+      extraHosts.forEach(function (_host) {
+        var zooKeeperHost = {};
+        zooKeeperHost.component_name = 'ZooKeeper';
+        zooKeeperHost.selectedHost = _host;
+        zooKeeperHost.availableHosts = [];
+        zooKeeperHosts.add(zooKeeperHost);
+      });
+      this.renderComponents(zooKeeperHosts);
+      var lastHost = zhosts[zhosts.length - 1];
+      return lastHost;
+    } else if (componentName === 'GANGLIA_MONITOR_SERVER') {
+      return this.getGangliaServer(noOfHosts);
+    } else if (componentName === 'NAGIOS_SERVER') {
+      return this.getNagiosServer(noOfHosts);
+    }
+  },
+
+
+  masterHostMapping: function () {
+    var mapping = [], mappingObject, self = this, mappedHosts, hostObj, hostInfo;
+    //get the unique assigned hosts and find the master services assigned to them
+
+    mappedHosts = this.get("selectedServicesMasters").mapProperty("selectedHost").uniq();
+
+    mappedHosts.forEach(function (item) {
+      hostObj = self.get("hosts").findProperty("host_name", item);
+      console.log("Name of the host is: " + hostObj.host_name);
+      hostInfo = " ( " + hostObj.get("memory") + "GB" + " " + hostObj.get("cpu") + "cores )";
+
+      mappingObject = Ember.Object.create({
+        host_name: item,
+        hostInfo: hostInfo,
+        masterServices: self.get("selectedServicesMasters").filterProperty("selectedHost", item)
+      });
+
+      mapping.pushObject(mappingObject);
+    }, this);
+
+    mapping.sort(this.sortHostsByName);
+
+    return mapping;
+
+  }.property("selectedServicesMasters.@each.selectedHost"),
+
+  remainingHosts: function () {
+    return (this.get("hosts.length") - this.get("masterHostMapping.length"));
+  }.property("selectedServicesMasters.@each.selectedHost"),
+
+  hasZookeeper: function () {
+    return this.selectedServices.findProperty("service_name", "ZooKeeper");
+  }.property("selectedServices"),
+
+  //methods
+  getAvailableHosts: function (componentName) {
+    var assignableHosts = [],
+      zookeeperHosts = null;
+
+    if (componentName === "ZooKeeper") {
+      zookeeperHosts = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper").mapProperty("selectedHost").uniq();
+      this.get("hosts").forEach(function (item) {
+        if (!(zookeeperHosts.contains(item.get("host_name")))) {
+          assignableHosts.pushObject(item);
+        }
+      }, this);
+      return assignableHosts;
+
+    } else {
+      return this.get("hosts");
+    }
+  },
+
+  assignHostToMaster: function (masterService, selectedHost, zId) {
+    if (selectedHost && masterService) {
+      if ((masterService === "ZooKeeper") && zId) {
+        this.get('selectedServicesMasters').findProperty("zId", zId).set("selectedHost", selectedHost);
+        this.rebalanceZookeeperHosts();
+      }
+      else {
+        this.get('selectedServicesMasters').findProperty("component_name", masterService).set("selectedHost", selectedHost);
+      }
+
+    }
+  },
+
+  lastZooKeeper: function () {
+    var currentZooKeepers = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper");
+    var lastZooKeeper = currentZooKeepers.get("lastObject");
+    return lastZooKeeper;
+  },
+
+  addZookeepers: function () {
+    /*
+     *Logic: If ZooKeeper service is selected then there can be
+     * minimum 1 ZooKeeper master in total, and
+     * maximum 1 ZooKeeper on every host
+     */
+
+    var maxNumZooKeepers = this.get("hosts.length"),
+      currentZooKeepers = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper"),
+      newZookeeper = null,
+      zookeeperHosts = null,
+      suggestedHost = null,
+      i = 0,
+      lastZoo = null;
+    console.log('hosts legth is: ' + maxNumZooKeepers);
+    //work only if the Zookeeper service is selected in previous step
+    if (!this.get("selectedServices").mapProperty("service_name").contains("ZOOKEEPER")) {
+      console.log('ALERT: Zookeeper service was not selected');
+      return false;
+    }
+
+    if (currentZooKeepers.get("length") < maxNumZooKeepers) {
+      console.log('currentZookeeper length less than maximum. Its: ' + currentZooKeepers.get("length"))
+      currentZooKeepers.set("lastObject.showAddControl", false);
+      if (currentZooKeepers.get("length") >= 1) {
+        currentZooKeepers.set("lastObject.showRemoveControl", true);
+      }
+
+      //create a new zookeeper based on an existing one
+      newZookeeper = Ember.Object.create({});
+      lastZoo = currentZooKeepers.get("lastObject");
+      newZookeeper.set("component_name", lastZoo.get("component_name"));
+      newZookeeper.set("selectedHost", lastZoo.get("selectedHost"));
+      newZookeeper.set("availableHosts", this.getAvailableHosts("ZooKeeper"));
+
+      if (currentZooKeepers.get("length") === (maxNumZooKeepers - 1)) {
+        newZookeeper.set("showAddControl", false);
+      } else {
+        newZookeeper.set("showAddControl", true);
+      }
+      newZookeeper.set("showRemoveControl", true);
+
+      //get recommended host for the new Zookeeper server
+      zookeeperHosts = currentZooKeepers.mapProperty("selectedHost").uniq();
+
+      for (i = 0; i < this.get("hosts.length"); i++) {
+        if (!(zookeeperHosts.contains(this.get("hosts")[i].get("host_name")))) {
+          suggestedHost = this.get("hosts")[i].get("host_name");
+          break;
+        }
+      }
+
+      newZookeeper.set("selectedHost", suggestedHost);
+      newZookeeper.set("zId", (currentZooKeepers.get("lastObject.zId") + 1));
+      this.set('zId', parseInt(this.get('zId')) + 1);
+
+      this.get("selectedServicesMasters").pushObject(newZookeeper);
+
+      this.rebalanceZookeeperHosts();
+
+      return true;
+    }
+    return false;//if no more zookeepers can be added
+  },
+
+  removeZookeepers: function (zId) {
+    var currentZooKeepers;
+
+    //work only if the Zookeeper service is selected in previous step
+    if (!this.get("selectedServices").mapProperty("service_name").contains("ZOOKEEPER")) {
+      return false;
+    }
+
+    currentZooKeepers = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper");
+
+    if (currentZooKeepers.get("length") > 1) {
+      this.get("selectedServicesMasters").removeAt(this.get("selectedServicesMasters").indexOf(this.get("selectedServicesMasters").findProperty("zId", zId)));
+
+      currentZooKeepers = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper");
+      if (currentZooKeepers.get("length") < this.get("hosts.length")) {
+        currentZooKeepers.set("lastObject.showAddControl", true);
+      }
+
+      if (currentZooKeepers.get("length") === 1) {
+        currentZooKeepers.set("lastObject.showRemoveControl", false);
+      }
+      this.set('zId', parseInt(this.get('zId')) - 1);
+      this.rebalanceZookeeperHosts();
+
+      return true;
+    }
+
+    return false;
+
+  },
+
+  rebalanceZookeeperHosts: function () {
+    //for a zookeeper update the available hosts for the other zookeepers
+
+    var currentZooKeepers = this.get("selectedServicesMasters").filterProperty("component_name", "ZooKeeper"),
+      zooHosts = currentZooKeepers.mapProperty("selectedHost"),
+      availableZooHosts = [],
+      preparedAvailableHosts = null;
+
+    //get all hosts available for zookeepers
+    this.get("hosts").forEach(function (item) {
+      if (!zooHosts.contains(item.get("host_name"))) {
+        availableZooHosts.pushObject(item);
+      }
+    }, this);
+
+    currentZooKeepers.forEach(function (item) {
+      preparedAvailableHosts = availableZooHosts.slice(0);
+      preparedAvailableHosts.pushObject(this.get("hosts").findProperty("host_name", item.get("selectedHost")))
+      preparedAvailableHosts.sort(this.sortHostsByConfig, this);
+      item.set("availableHosts", preparedAvailableHosts);
+    }, this);
+
+  },
+
+  sortHostsByConfig: function (a, b) {
+    //currently handling only total memory on the host
+    if (a.memory < b.memory) {
+      return 1;
+    }
+    else {
+      return -1;
+    }
+  },
+
+  sortHostsByName: function (a, b) {
+    if (a.host_name > b.host_name) {
+      return 1;
+    }
+    else {
+      return -1;
+    }
+  },
+
+  saveComponentHostsToDb: function () {
+    var obj = this.get('selectedServicesMasters');
+    var masterComponentHosts = [];
+    var inc = 0;
+    var array = [];
+    obj.forEach(function (_component) {
+      var hostArr = [];
+      masterComponentHosts.push({
+        component: _component.component_name,
+        hostName: _component.selectedHost
+      });
+    });
+
+    App.db.setMasterComponentHosts(masterComponentHosts);
+
+  },
+
+  submit: function () {
+    this.saveComponentHostsToDb();
+    App.router.send('next');
+  }
+
+
+});
+
+
+

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/messages.js Thu Oct 18 00:17:19 2012
@@ -221,5 +221,7 @@ Em.I18n.translations = {
   'metric.cpu': 'cpu',
   'metric.memory': 'disk used',
   'metric.network': 'network',
-  'metric.io': 'io'
+  'metric.io': 'io',
+  'hosts.add.header' : 'Add Host Wizard',
+  'hosts.add.step2.warning' : 'Hosts are already part of the cluster and will be ignored'
 };
\ No newline at end of file

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/router.js Thu Oct 18 00:17:19 2012
@@ -73,7 +73,6 @@ App.Router = Em.Router.extend({
   */
 
   setInstallerCurrentStep: function (currentStep, completed) {
-    var loginName = this.getLoginName();
     App.db.setInstallerCurrentStep(currentStep, completed);
     this.set('installerController.currentStep', currentStep);
   },
@@ -89,6 +88,21 @@ App.Router = Em.Router.extend({
     return currentStep;
   },
 
+  /**
+   * Get current step for <code>wizardType</code> wizard
+   * @param wizardType one of <code>installer</code>, <code>addHost</code>, <code>addServices</code>
+   */
+  getWizardCurrentStep: function (wizardType) {
+    var loginName = this.getLoginName();
+    var currentStep = App.db.getWizardCurrentStep(wizardType);
+    console.log('getInstallerCurrentStep: loginName=' + loginName + ", currentStep=" + currentStep);
+    if (!currentStep) {
+      currentStep = '1';
+    }
+    console.log('returning currentStep=' + currentStep);
+    return currentStep;
+  },
+
   loggedIn: false,
 
   getAuthenticated: function () {
@@ -154,7 +168,7 @@ App.Router = Em.Router.extend({
   authenticated: function () {
     var authenticated = false;
     var controller = this.get('loginController');
-    var hash = window.btoa(controller.get('loginName') + ":" + controller.get('password'));
+    var hash = ''; //window.btoa(controller.get('loginName') + ":" + controller.get('password'));
     $.ajax({
       url : '/api/check',
       dataType : 'json',

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/add_host_routes.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/add_host_routes.js?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/add_host_routes.js (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/add_host_routes.js Thu Oct 18 00:17:19 2012
@@ -0,0 +1,181 @@
+/**
+ * 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.
+ */
+
+module.exports = Em.Route.extend({
+  route: '/hosts/add',
+
+  enter: function (router) {
+    console.log('in /hosts/add:enter');
+
+    Ember.run.next(function () {
+      var addHostController = router.get('addHostController');
+      addHostController.loadAllPriorSteps();
+      router.transitionTo('step' + addHostController.get('currentStep'));
+    });
+
+  },
+
+  connectOutlets: function (router, context) {
+    console.log('in /hosts/add:connectOutlets');
+    router.get('mainController').connectOutlet('addHost');
+  },
+
+  step1: Em.Route.extend({
+    route: '/step1',
+    connectOutlets: function (router) {
+      console.log('in addHost.step1:connectOutlets');
+      var controller = router.get('addHostController');
+      controller.setCurrentStep('1', false);
+      controller.set('hideBackButton', true);
+      controller.loadAllPriorSteps();
+      controller.connectOutlet('wizardStep2', controller.get('content.hosts'));
+    },
+
+    next: Em.Router.transitionTo('step2'),
+    evaluateStep: function (router) {
+      console.log('in addHost.step1:evaluateStep');
+      var addHostController = router.get('addHostController');
+      var wizardStep2Controller = router.get('wizardStep2Controller');
+
+      wizardStep2Controller.set('hasSubmitted', true);
+
+      if (!wizardStep2Controller.get('isSubmitDisabled')) {
+        addHostController.saveHosts(wizardStep2Controller);
+        wizardStep2Controller.evaluateStep();
+      }
+    }
+  }),
+
+  step2: Em.Route.extend({
+    route: '/step2',
+    connectOutlets: function (router) {
+      console.log('in addHost.step2:connectOutlets');
+      var controller = router.get('addHostController');
+      controller.setCurrentStep('2', false);
+      controller.loadAllPriorSteps();
+      router.get('wizardStep3Controller').set('data', controller.getHostList(true)); // workaround
+      controller.connectOutlet('wizardStep3', controller.getHostList(true));
+    },
+    back: Em.Router.transitionTo('step1'),
+    next: function (router) {
+      console.log('in addHost.step2:next');
+      var addHostController = router.get('addHostController');
+      var wizardStep3Controller = router.get('wizardStep3Controller');
+
+      if (wizardStep3Controller.get('isSubmitDisabled') === false) {
+        addHostController.saveConfirmedHosts(wizardStep3Controller);
+        router.transitionTo('step3');
+      }
+    },
+
+    /**
+     * Wrapper for remove host action.
+     * Since saving data stored in addHostController, we should call this from router
+     * @param router
+     * @param context Array of hosts to delete
+     */
+    removeHosts: function (router, context) {
+      console.log('in addHost.step2.removeHosts:hosts to delete ', context);
+      var controller = router.get('addHostController');
+      controller.removeHosts(context);
+    }
+  }),
+
+  step3: Em.Route.extend({
+    route: '/step3',
+    connectOutlets: function (router, context) {
+      console.log('in addHost.step3:connectOutlets');
+      var controller = router.get('addHostController');
+      controller.setCurrentStep('3', false);
+      controller.set('hideBackButton', false);
+      controller.loadAllPriorSteps();
+      controller.connectOutlet('wizardStep4', controller.get('content.services'));
+    },
+    back: Em.Router.transitionTo('step2'),
+    next: function (router, context) {
+      var addHostController = router.get('addHostController');
+      var wizardStep4Controller = router.get('wizardStep4Controller');
+      addHostController.saveServices(wizardStep4Controller);
+      router.transitionTo('step4');
+    }
+  }),
+
+  step4: Em.Route.extend({
+    route: '/step4',
+    connectOutlets: function (router, context) {
+      console.log('in addHost.step4:connectOutlets');
+      var controller = router.get('addHostController');
+      controller.setCurrentStep('4', false);
+      controller.loadAllPriorSteps();
+      controller.connectOutlet('wizardStep5' /*, controller.get('content.services')*/);
+
+    },
+    back: Em.Router.transitionTo('step3'),
+    next: function (router, context) {
+      console.warn('next is not ready now');
+    }
+  }),
+
+//  step5: Em.Route.extend({
+//    route: '/step5',
+//    connectOutlets: function (router, context) {
+//      router.setNavigationFlow('step5');
+//      router.setInstallerCurrentStep('5', false);
+//      router.get('installerController').connectOutlet('installerStep5');
+//    },
+//    back: Em.Router.transitionTo('step4'),
+//    next: Em.Router.transitionTo('step6')
+//  }),
+//
+//  step6: Em.Route.extend({
+//    route: '/step6',
+//    connectOutlets: function (router, context) {
+//      router.setNavigationFlow('step6');
+//      router.setInstallerCurrentStep('6', false);
+//      router.get('installerController').connectOutlet('installerStep6');
+//    },
+//    back: Em.Router.transitionTo('step5'),
+//    next: Em.Router.transitionTo('step7')
+//  }),
+//
+
+  backToHostsList: function (router, event) {
+    router.transitionTo('hosts');
+  },
+
+  gotoStep1: Em.Router.transitionTo('step1'),
+
+  gotoStep2: Em.Router.transitionTo('step2'),
+
+  gotoStep3: Em.Router.transitionTo('step3'),
+
+  gotoStep4: Em.Router.transitionTo('step4'),
+
+  gotoStep5: Em.Router.transitionTo('step5'),
+
+  gotoStep6: Em.Router.transitionTo('step6'),
+
+  gotoStep7: Em.Router.transitionTo('step7'),
+
+  gotoStep8: Em.Router.transitionTo('step8'),
+
+  gotoStep9: Em.Router.transitionTo('step9'),
+
+  gotoStep10: Em.Router.transitionTo('step10')
+
+});

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/installer.js Thu Oct 18 00:17:19 2012
@@ -160,6 +160,14 @@ module.exports = Em.Route.extend({
     },
     back: Em.Router.transitionTo('step6'),
     next: Em.Router.transitionTo('step8')
+//    showSlaveComponentGroup:Em.Router.transitionTo('slaveComponentGroup'),
+//    slaveComponentGroup:Em.Route.extend({
+//      route:'/',
+//      connectOutlets:function (router, group) {
+//        router.get('installerController').connectOutlet('slaveComponentGroup', group);
+//      }
+//    })
+
   }),
 
   step8: Em.Route.extend({

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/routes/main.js Thu Oct 18 00:17:19 2012
@@ -86,10 +86,16 @@ module.exports = Em.Route.extend({
     showDetails:function (router, event) {
       router.get('mainHostDetailsController').setBack(true);
       router.transitionTo('hostDetails.index', event.context)
+    },
+
+    addHost: function (router) {
+      router.transitionTo('hostAdd');
     }
 
   }),
 
+  hostAdd: require('routes/add_host_routes'),
+
   hostDetails:Em.Route.extend({
     route:'/hosts/:host_id',
     connectOutlets:function (router, host) {

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/app.css
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/app.css?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/app.css (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/app.css Thu Oct 18 00:17:19 2012
@@ -163,3 +163,8 @@
 }
 /*End Carousel*//*End Hosts*/
 
+#add-host .back{
+    display: block;
+    width: 105px;
+    margin-bottom: 10px;
+}
\ No newline at end of file

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/application.less
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/application.less?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/application.less (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/styles/application.less Thu Oct 18 00:17:19 2012
@@ -221,6 +221,9 @@ h1 {
     .badge {
       margin-left: 4px;
     }
+    .slave-component-group-menu {
+      float: left;
+    }
     .add-slave-component-group {
       margin-bottom: 20px;
     }

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step7.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step7.hbs?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step7.hbs (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/installer/step7.hbs Thu Oct 18 00:17:19 2012
@@ -42,6 +42,16 @@
       {{#view App.ServiceConfigsByCategoryView categoryBinding="category" serviceConfigsBinding="selectedService.configs"}}
       <div class="accordion-body collapse in">
         <div class="accordion-inner">
+          {{#if category.isForSlaveComponent}}
+          <div class="slave-component-group-menu">
+          {{view App.SlaveComponentGroupsMenu}}
+          </div>
+          {{#view App.AddSlaveComponentGroupButton slaveComponentNameBinding="category.name"}}
+          <a
+            class="btn add-slave-component-group btn-large" {{action addSlaveComponentGroup category.name target="App.router.slaveComponentGroupsController"}}><i
+            class="icon-plus"></i></a>
+          {{/view}}
+          {{/if}}
           <form class="form-horizontal">
             {{#each view.categoryConfigs}}
             <div {{bindAttr class="errorMessage:error: :control-group"}}>
@@ -57,13 +67,6 @@
       </div>
       {{/view}}
     </div>
-    {{#if category.isForSlaveComponent}}
-    {{#view App.AddSlaveComponentGroupButton slaveComponentNameBinding="category.name"}}
-    <a
-      class="btn add-slave-component-group" {{action showAddSlaveComponentGroup category.name target="App.router.slaveComponentGroupsController"}}><i
-      class="icon-plus-sign"></i> Add a {{category.name}} Group</a>
-    {{/view}}
-    {{/if}}
     {{/each}}
   </div>
   {{#if isSubmitDisabled}}

Modified: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host.hbs?rev=1399489&r1=1399488&r2=1399489&view=diff
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host.hbs (original)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host.hbs Thu Oct 18 00:17:19 2012
@@ -39,7 +39,7 @@
       <button {{bindAttr disabled="controller.isDisabled"}} class="btn btn-primary" data-toggle="modal" {{action "deleteButtonPopup" target="controller"}}>
         Delete
       </button>
-      <button class="btn btn-inverse add-host-button" disabled="disabled">
+      <button class="btn btn-inverse add-host-button" {{action addHost}}>
         <i class="icon-plus icon-white"></i>
         Add New Host
       </button>

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host/add.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host/add.hbs?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host/add.hbs (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/main/host/add.hbs Thu Oct 18 00:17:19 2012
@@ -0,0 +1,49 @@
+<!--
+* 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.
+-->
+
+<div id="add-host">
+  <div class="container">
+    <div class="container-fluid">
+
+      <a class="btn back" {{action backToHostsList}}>← Back to Hosts</a>
+
+      <div class="row-fluid">
+        <div class="span3">
+          <!--Sidebar content-->
+          <div class="well">
+            <ul class="nav nav-pills nav-stacked">
+              <li class="nav-header">{{t hosts.add.header}}</li>
+              <li {{bindAttr class="isStep1:active view.isStep1Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep1 target="controller"}}>{{t installer.step2.header}}</a></li>
+              <li {{bindAttr class="isStep2:active view.isStep2Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep2 target="controller"}}>{{t installer.step3.header}}</a></li>
+              <li {{bindAttr class="isStep3:active view.isStep3Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep3 target="controller"}}>{{t installer.step4.header}}</a></li>
+              <li {{bindAttr class="isStep4:active view.isStep4Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep4 target="controller"}}>{{t installer.step5.header}}</a></li>
+              <li {{bindAttr class="isStep5:active view.isStep5Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep5 target="controller"}}>{{t installer.step6.header}}</a></li>
+              <li {{bindAttr class="isStep6:active view.isStep6Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep6 target="controller"}}>{{t installer.step7.header}}</a></li>
+              <li {{bindAttr class="isStep7:active view.isStep7Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep7 target="controller"}}>{{t installer.step8.header}}</a></li>
+              <li {{bindAttr class="isStep8:active view.isStep8Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep8 target="controller"}}>{{t installer.step9.header}}</a></li>
+              <li {{bindAttr class="isStep9:active view.isStep9Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep9 target="controller"}}>{{t installer.step10.header}}</a></li>
+            </ul>
+          </div>
+        </div>
+        <div id="add-host-content" class="well span9">
+          {{outlet}}
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2.hbs?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2.hbs (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2.hbs Thu Oct 18 00:17:19 2012
@@ -0,0 +1,130 @@
+<!--
+* 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.
+-->
+<div id="installOptions">
+  <h2>{{t installer.step2.header}}</h2>
+
+  <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>
+
+      {{#if view.parentView.controller.hideBackButton}}
+      {{#if content.hostNames }}
+      <p class="alert alert-info">{{t hosts.add.step2.warning}}</p>
+      {{/if}}
+      {{/if}}
+
+      <div class="controls">
+        {{view Ember.TextArea class="span6" valueBinding="content.hostNames" rows="5" placeholder="host names"}}
+        {{#if hostsError}}
+        <p class="help-inline">{{hostsError}}</p>
+        {{/if}}
+      </div>
+    </div>
+  </div>
+
+  <div id="hostConnectivity">
+    <div class="ambari-agents">
+      <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="content.sshKey"}}
+          {{#if sshKeyError}}
+        <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="content.manualInstall"}}
+      </label>
+
+      {{#if "manualInstall"}}
+      <div class="alert">
+        {{t installer.step2.manualInstall.info}}
+      </div>
+      {{/if}}
+
+      <!--
+    {{view Ember.TextField type="text" placeholder="passphrase" valueBinding="content.passphrase"}}
+
+    <div {{bindAttr class="passphraseMatchErr:error :control-group :ambari-agents"}}>
+      <div class="controls">
+        {{view Ember.TextField type="text" placeholder="confirm passphrase" valueBinding="content.confirmPassphrase"}}
+
+        {{#if passphraseMatchErr}}
+        <p class="help-inline">{{t installer.step2.passphrase.error.match}}</p>
+        {{/if}}
+      </div>
+    </div>
+    -->
+    </div>
+  </div>
+
+  <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="content.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="content.localRepoPath"}}
+        {{#if localRepoError}}
+        <p class="help-inline">{{localRepoError}}</p>
+        {{/if}}
+      </div>
+    </div>
+    {{/if}}
+  </div>
+  <div class="btn-area">
+    {{#unless view.parentView.controller.hideBackButton }}
+    <a class="btn pull-left" {{action back}}>&larr; Back</a>
+    {{/unless}}
+    <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action evaluateStep}}>
+      Discover and Validate &rarr;</a>
+  </div>
+
+</div>
\ No newline at end of file

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2ManualInstallPopup.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2ManualInstallPopup.hbs?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2ManualInstallPopup.hbs (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step2ManualInstallPopup.hbs Thu Oct 18 00:17:19 2012
@@ -0,0 +1 @@
+<p>{{t installer.step2.manualInstall.popup.body}}</p>

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3.hbs?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3.hbs (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3.hbs Thu Oct 18 00:17:19 2012
@@ -0,0 +1,113 @@
+<!--
+* 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.
+-->
+
+<h2>{{t installer.step3.header}}</h2>
+<p class="alert alert-info">{{t installer.step3.body}}</p>
+<div class="box">
+  <div class="box-header">
+    <div class="button-section">
+      <a class="btn btn-primary decommission" {{bindAttr disabled="isSubmitDisabled"}}
+         href="#" {{action retry target="controller"}}><i
+        class="icon-repeat icon-white"></i>
+        Retry
+      </a>
+      <a class="btn btn-primary" {{bindAttr disabled="isSubmitDisabled"}}
+         href="#" {{action removeBtn target="controller" }}><i
+        class="icon-trash icon-white"></i>
+        Remove
+      </a>
+      <a class="btn btn-info"
+         href="#" {{action mockBtn target="controller" }}>
+        mockData
+      </a>
+      <a class="btn btn-info"
+         href="#" {{action pollBtn target="controller" }}>
+        pollData
+      </a>
+
+      <div class="dropdown pull-right">
+        {{view Ember.Select class="pull-right"
+            contentBinding="controller.categories"
+            selectionBinding="controller.category"}}
+        <h5 class="pull-right text-info">Filter By: &nbsp</h5>
+      </div>
+
+    </div>
+  </div>
+
+
+  <table class="table table-bordered table-striped">
+    <thead>
+    <tr>
+      <th>
+        {{view Ember.Checkbox checkedBinding="allChecked"}}
+      </th>
+      <th>Status</th>
+      <!--  given by the parsing function that parses data from bootstrap call -->
+      <th>Host</th>
+      <!-- retrieved from local storage initially -->
+      <th>Message</th>
+      <!-- given by the parsing function that parses data from bootstrap call, dynamically assign the color -->
+      <th>Action</th>
+      <!-- trash icon -->
+      <!-- retry icon -->
+    </tr>
+    </thead>
+
+    <tbody>
+
+    {{#each host in controller}}
+    {{#view App.HostView categoryBinding="controller.category" hostInfoBinding="host"}}
+    {{#if view.isVisible}}
+    <tr {{bindAttr class = "host.bootStatus"}}>
+      <td>
+        {{view Ember.Checkbox checkedBinding="host.isChecked"}}
+      </td>
+      <td>
+        {{host.bootStatus}}
+      </td>
+
+      <td>
+        {{host.name}}
+      </td>
+      <td>
+        <a href="javascript:void(null)"
+           data-toggle="modal" {{action "hostLogPopup" target="controller"}}>{{host.message}}</a>
+      </td>
+      <td>
+        <a href="javascript:void(null)" {{action removeItem target="view"}}><i
+          class="icon-trash"></i></a>
+      </td>
+    </tr>
+    {{/if}}
+    {{/view}}
+    {{/each}}
+
+    </tbody>
+
+  </table>
+  <div class="box-footer">
+    <hr/>
+    <div class="footer-pagination">
+    </div>
+  </div>
+</div>
+<div class="btn-area">
+  <a class="btn pull-left" {{action back}}>&larr; Back</a>
+  <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action next}}>Next &rarr;</a>
+</div>

Added: incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3HostLogPopup.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3HostLogPopup.hbs?rev=1399489&view=auto
==============================================================================
--- incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3HostLogPopup.hbs (added)
+++ incubator/ambari/branches/AMBARI-666/ambari-web/app/templates/wizard/step3HostLogPopup.hbs Thu Oct 18 00:17:19 2012
@@ -0,0 +1 @@
+<p>{{t installer.step3.hostLog.popup.body}}</p>