瀏覽代碼

AMBARI-1059. Refactor cluster management. (yusaku)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/branches/AMBARI-666@1419007 13f79535-47bb-0310-9956-ffa450edef68
Yusaku Sako 12 年之前
父節點
當前提交
2327f56fb2
共有 33 個文件被更改,包括 1047 次插入458 次删除
  1. 0 0
      ambari-web/app/assets/data/wizard/deploy/slave_failure/poll_3.json
  2. 0 0
      ambari-web/app/assets/data/wizard/deploy/slave_failure/poll_4.json
  3. 11 0
      ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_10.json
  4. 47 0
      ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_5.json
  5. 405 0
      ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_6.json
  6. 11 0
      ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_7.json
  7. 11 0
      ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_8.json
  8. 11 0
      ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_9.json
  9. 2 106
      ambari-web/app/controllers/installer.js
  10. 1 1
      ambari-web/app/controllers/main/host.js
  11. 96 143
      ambari-web/app/controllers/main/host/add_controller.js
  12. 7 110
      ambari-web/app/controllers/main/service/add_controller.js
  13. 106 1
      ambari-web/app/controllers/wizard.js
  14. 7 12
      ambari-web/app/controllers/wizard/step10_controller.js
  15. 11 2
      ambari-web/app/controllers/wizard/step3_controller.js
  16. 3 1
      ambari-web/app/controllers/wizard/step5_controller.js
  17. 1 1
      ambari-web/app/controllers/wizard/step8_controller.js
  18. 47 18
      ambari-web/app/controllers/wizard/step9_controller.js
  19. 1 0
      ambari-web/app/initialize.js
  20. 1 1
      ambari-web/app/mappers/users_mapper.js
  21. 3 2
      ambari-web/app/messages.js
  22. 1 1
      ambari-web/app/templates/main/host/summary.hbs
  23. 6 0
      ambari-web/app/templates/main/service/info/summary.hbs
  24. 4 1
      ambari-web/app/templates/wizard/step2.hbs
  25. 26 2
      ambari-web/app/utils/data_table.js
  26. 2 1
      ambari-web/app/views/common/modal_popup.js
  27. 2 2
      ambari-web/app/views/main/host.js
  28. 10 3
      ambari-web/app/views/main/host/summary.js
  29. 11 2
      ambari-web/app/views/main/service/info/summary.js
  30. 74 47
      ambari-web/app/views/wizard/step9_view.js
  31. 2 1
      ambari-web/config.coffee
  32. 3 0
      ambari-web/vendor/scripts/jquery.dataTables.js
  33. 124 0
      ambari-web/vendor/scripts/jquery.flexibleArea.js

File diff suppressed because it is too large
+ 0 - 0
ambari-web/app/assets/data/wizard/deploy/slave_failure/poll_3.json


File diff suppressed because it is too large
+ 0 - 0
ambari-web/app/assets/data/wizard/deploy/slave_failure/poll_4.json


File diff suppressed because it is too large
+ 11 - 0
ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_10.json


File diff suppressed because it is too large
+ 47 - 0
ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_5.json


+ 405 - 0
ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_6.json

@@ -0,0 +1,405 @@
+{
+  "href" : "http://ambari:8080/api/clusters/mycluster/requests/2?fields=tasks/*",
+  "Requests" : {
+    "id" : 2,
+    "cluster_name" : "mycluster"
+  },
+  "tasks" : [
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/37",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host4",
+        "id" : 37,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "TASKTRACKER",
+        "start_time" : -1,
+        "stage_id" : 2
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/25",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host1",
+        "id" : 25,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "GANGLIA_MONITOR",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/42",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 42,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "EXECUTE",
+        "role" : "PIG_SERVICE_CHECK",
+        "start_time" : -1,
+        "stage_id" : 3
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/32",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 32,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "DATANODE",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/31",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host4",
+        "id" : 31,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "GANGLIA_MONITOR",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/33",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 33,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "GANGLIA_MONITOR",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/26",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host5",
+        "id" : 26,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "GANGLIA_MONITOR",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/44",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 44,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "EXECUTE",
+        "role" : "OOZIE_SERVICE_CHECK",
+        "start_time" : -1,
+        "stage_id" : 4
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/36",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host1",
+        "id" : 36,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "TASKTRACKER",
+        "start_time" : -1,
+        "stage_id" : 2
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/34",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host3",
+        "id" : 34,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "JOBTRACKER",
+        "start_time" : -1,
+        "stage_id" : 2
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/35",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host3",
+        "id" : 35,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "SECONDARY_NAMENODE",
+        "start_time" : -1,
+        "stage_id" : 2
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/38",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 38,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "EXECUTE",
+        "role" : "HDFS_SERVICE_CHECK",
+        "start_time" : -1,
+        "stage_id" : 2
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/29",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host5",
+        "id" : 29,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "NAMENODE",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/28",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host5",
+        "id" : 28,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "NAGIOS_SERVER",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/24",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host1",
+        "id" : 24,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "DATANODE",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/40",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host3",
+        "id" : 40,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "OOZIE_SERVER",
+        "start_time" : -1,
+        "stage_id" : 3
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/39",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 39,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "TASKTRACKER",
+        "start_time" : -1,
+        "stage_id" : 2
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/23",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host3",
+        "id" : 23,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "GANGLIA_MONITOR",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/27",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host5",
+        "id" : 27,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "GANGLIA_SERVER",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/30",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host4",
+        "id" : 30,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "START",
+        "role" : "DATANODE",
+        "start_time" : -1,
+        "stage_id" : 1
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/43",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 43,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "EXECUTE",
+        "role" : "SQOOP_SERVICE_CHECK",
+        "start_time" : -1,
+        "stage_id" : 3
+      }
+    },
+    {
+      "href" : "http://ambari:8080/api/clusters/mycluster/requests/2/tasks/41",
+      "Tasks" : {
+        "exit_code" : 999,
+        "stdout" : "",
+        "status" : "PENDING",
+        "stderr" : "",
+        "host_name" : "host2",
+        "id" : 41,
+        "cluster_name" : "mycluster",
+        "attempt_cnt" : 0,
+        "request_id" : 2,
+        "command" : "EXECUTE",
+        "role" : "MAPREDUCE_SERVICE_CHECK",
+        "start_time" : -1,
+        "stage_id" : 3
+      }
+    }
+  ]
+}

File diff suppressed because it is too large
+ 11 - 0
ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_7.json


File diff suppressed because it is too large
+ 11 - 0
ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_8.json


File diff suppressed because it is too large
+ 11 - 0
ambari-web/app/assets/data/wizard/deploy/slave_warning/poll_9.json


+ 2 - 106
ambari-web/app/controllers/installer.js

@@ -72,32 +72,6 @@ App.InstallerController = App.WizardController.extend({
     console.log("InstallerController:saveClusterInfo: saved data ", cluster);
   },
 
-  /**
-   * save status of the cluster. This is called from step8 and step9 to persist install and start requestId
-   * @param clusterStatus object with status, isCompleted, requestId, isInstallError and isStartError field.
-   */
-  saveClusterStatus: function (clusterStatus) {
-    clusterStatus.name = this.get('content.cluster.name');
-    this.set('content.cluster', clusterStatus);
-    console.log('called saveClusterStatus ' + JSON.stringify(clusterStatus));
-    App.db.setClusterStatus(clusterStatus);
-  },
-
-  /**
-   * Temporary function for wizardStep9, before back-end integration
-   */
-  setInfoForStep9: function () {
-    var hostInfo = App.db.getHosts();
-    for (var index in hostInfo) {
-      hostInfo[index].status = "pending";
-      hostInfo[index].message = 'Waiting';
-      hostInfo[index].logTasks = [];
-      hostInfo[index].tasks = [];
-      hostInfo[index].progress = '0';
-    }
-    App.db.setHosts(hostInfo);
-  },
-
   /**
    * Load all data for <code>Specify Host(install step2)</code> step
    * Data Example:
@@ -218,7 +192,8 @@ App.InstallerController = App.WizardController.extend({
       var host = hosts.findProperty('name', hostInfo[index].name);
       if (host) {
         hostInfo[index].status = host.status;
-        hostInfo[index].tasks = host.tasks;
+        //tasks should be empty because they loads from the server
+        //hostInfo[index].tasks = host.tasks;
         hostInfo[index].message = host.message;
         hostInfo[index].progress = host.progress;
       }
@@ -227,24 +202,6 @@ App.InstallerController = App.WizardController.extend({
     this.set('content.hostsInfo', hostInfo);
   },
 
-  /**
-   * Remove all data for hosts
-   */
-  clearHosts: function () {
-    var hosts = this.get('content').get('hosts');
-    if (hosts) {
-      hosts.set('hostNames', '');
-      hosts.set('manualInstall', false);
-      hosts.set('localRepo', '');
-      hosts.set('localRepopath', '');
-      hosts.set('sshKey', '');
-      hosts.set('passphrase', '');
-      hosts.set('confirmPassphrase', '');
-    }
-    App.db.setHosts(null);
-    App.db.setAllHostNames(null);
-  },
-
   /**
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
@@ -650,67 +607,6 @@ App.InstallerController = App.WizardController.extend({
     return serviceComponents;
   },
 
-  /**
-   * Invoke installation of selected services to the server and saves the request id returned by the server.
-   * @param isRetry
-   */
-  installServices: function (isRetry) {
-    if (!isRetry && this.get('content.cluster.requestId')) {
-      return;
-    }
-
-    var self = this;
-    var clusterName = this.get('content.cluster.name');
-    var url = (App.testMode) ? '/data/wizard/deploy/poll_1.json' : App.apiPrefix + '/clusters/' + clusterName + '/services?ServiceInfo/state=INIT';
-    var method = (App.testMode) ? 'GET' : 'PUT';
-    var data = '{"ServiceInfo": {"state": "INSTALLED"}}';
-    $.ajax({
-      type: method,
-      url: url,
-      data: data,
-      async: false,
-      dataType: 'text',
-      timeout: App.timeout,
-      success: function (data) {
-        var jsonData = jQuery.parseJSON(data);
-        var installStartTime = new Date().getTime();
-        console.log("TRACE: In success function for the installService call");
-        console.log("TRACE: value of the url is: " + url);
-        if (jsonData) {
-          var requestId = jsonData.href.match(/.*\/(.*)$/)[1];
-          console.log('requestId is: ' + requestId);
-          var clusterStatus = {
-            status: 'PENDING',
-            requestId: requestId,
-            isInstallError: false,
-            isCompleted: false,
-            installStartTime: installStartTime
-          };
-          self.saveClusterStatus(clusterStatus);
-        } else {
-          console.log('ERROR: Error occurred in parsing JSON data');
-        }
-      },
-
-      error: function (request, ajaxOptions, error) {
-        console.log("TRACE: In error function for the installService call");
-        console.log("TRACE: value of the url is: " + url);
-        console.log("TRACE: error code status is: " + request.status);
-        console.log('Error message is: ' + request.responseText);
-        var clusterStatus = {
-          status: 'PENDING',
-          isInstallError: false,
-          isCompleted: false
-        };
-
-        self.saveClusterStatus(clusterStatus);
-      },
-
-      statusCode: require('data/statusCodes')
-    });
-
-  },
-
   /**
    * Clear all temporary data
    */

+ 1 - 1
ambari-web/app/controllers/main/host.js

@@ -19,7 +19,7 @@
 var App = require('app');
 var validator = require('utils/validator');
 
-App.MainHostController = Em.ArrayController.extend(App.Pagination, {
+App.MainHostController = Em.ArrayController.extend({
   name:'mainHostController',
   content:[],
   fullContent:App.Host.find(),

+ 96 - 143
ambari-web/app/controllers/main/host/add_controller.js

@@ -23,6 +23,13 @@ App.AddHostController = App.WizardController.extend({
 
   name: 'addHostController',
 
+  totalSteps: 7,
+
+  /**
+   * Used for hiding back button in wizard
+   */
+  hideBackButton: true,
+
   /**
    * All wizards data will be stored in this variable
    *
@@ -47,19 +54,12 @@ App.AddHostController = App.WizardController.extend({
     isWizard: true
   }),
 
-  /**
-   * Used for hiding back button in wizard
-   */
-  hideBackButton: true,
-
-  totalSteps: 7,
-
   /**
    * Load clusterInfo(step1) to model
    */
-  loadClusterInfo: function(){
+  loadClusterInfo: function () {
     var cluster = App.db.getClusterStatus();
-    if(!cluster){
+    if (!cluster) {
       cluster = {
         name: App.router.getClusterName(),
         status: undefined,
@@ -74,29 +74,40 @@ App.AddHostController = App.WizardController.extend({
     console.log("AddHostController:loadClusterInfo: loaded data ", cluster);
   },
 
-  /**
-   * save status of the cluster. This is called from step8 and step9 to persist install and start requestId
-   * @param clusterStatus object with status, isCompleted, requestId, isInstallError and isStartError field.
-   */
-  saveClusterStatus: function (clusterStatus) {
-    clusterStatus.name = this.get('content.cluster.name');
-    this.set('content.cluster', clusterStatus);
-    console.log('called saveClusterStatus ' + JSON.stringify(clusterStatus));
-    App.db.setClusterStatus(clusterStatus);
+  showMoreHosts: function () {
+    var self = this;
+    App.ModalPopup.show({
+      header: "Hosts are already part of the cluster and will be ignored",
+      body: self.get('content.hosts.oldHostNamesMore'),
+      encodeBody: false,
+      onPrimary: function () {
+        this.hide();
+      },
+      secondary: null
+    });
   },
 
   /**
-   * Temporary function for wizardStep9, before back-end integration
+   * Config for displaying more hosts
+   * if oldHosts.length more than config.count that configuration will be applied
    */
-  setInfoForStep9: function () {
-    var hostInfo = App.db.getHosts();
-    for (var index in hostInfo) {
-      hostInfo[index].status = "pending";
-      hostInfo[index].message = 'Information';
-      hostInfo[index].progress = '0';
+  hostDisplayConfig: [
+    {
+      count: 0,
+      delimitery: '<br/>',
+      popupDelimitery: '<br />'
+    },
+    {
+      count: 10,
+      delimitery: ', ',
+      popupDelimitery: '<br />'
+    },
+    {
+      count: 50,
+      delimitery: ', ',
+      popupDelimitery: ', '
     }
-    App.db.setHosts(hostInfo);
-  },
+  ],
 
   /**
    * Load all data for <code>Specify Host(install step2)</code> step
@@ -119,8 +130,25 @@ App.AddHostController = App.WizardController.extend({
 
     var hostsInfo = Em.Object.create();
 
+    var oldHostNames = App.Host.find().getEach('id');
+    var k = 10;
+
+    var usedConfig = false;
+    this.get('hostDisplayConfig').forEach(function (config) {
+      if (oldHostNames.length > config.count) {
+        usedConfig = config;
+      }
+    });
+
+    k = usedConfig.count ? usedConfig.count : oldHostNames.length;
+    var displayedHostNames = oldHostNames.slice(0, k);
+    hostsInfo.oldHostNames = displayedHostNames.join(usedConfig.delimitery);
+    if (usedConfig.count) {
+      var moreHostNames = oldHostNames.slice(k + 1);
+      hostsInfo.oldHostNamesMore = moreHostNames.join(usedConfig.popupDelimitery);
+      hostsInfo.showMoreHostsText = "...and %@ more".fmt(moreHostNames.length);
+    }
 
-    hostsInfo.oldHostNames = App.Host.find().getEach('id').join(" <br/>");
     hostsInfo.hostNames = App.db.getAllHostNames() || ''; //empty string if undefined
 
     var installType = App.db.getInstallType();
@@ -202,7 +230,7 @@ App.AddHostController = App.WizardController.extend({
    * Load confirmed hosts.
    * Will be used at <code>Assign Masters(step5)</code> step
    */
-  loadConfirmedHosts: function(){
+  loadConfirmedHosts: function () {
     this.set('content.hostsInfo', App.db.getHosts());
   },
 
@@ -218,7 +246,8 @@ App.AddHostController = App.WizardController.extend({
       var host = hosts.findProperty('name', hostInfo[index].name);
       if (host) {
         hostInfo[index].status = host.status;
-        hostInfo[index].tasks = host.tasks;
+        //tasks should be empty because they loads from the server
+        //hostInfo[index].tasks = host.tasks;
         hostInfo[index].message = host.message;
         hostInfo[index].progress = host.progress;
       }
@@ -228,30 +257,12 @@ App.AddHostController = App.WizardController.extend({
     console.log('addHostController:saveInstalledHosts: save hosts ', 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 = '';
-    }
-    App.db.setHosts(null);
-    App.db.setAllHostNames(null);
-  },
-
   /**
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
   loadServices: function () {
     var servicesInfo = App.db.getService();
-    if(!servicesInfo || !servicesInfo.length){
+    if (!servicesInfo || !servicesInfo.length) {
       servicesInfo = require('data/services').slice(0);
       servicesInfo.forEach(function (item) {
         item.isSelected = App.Service.find().someProperty('id', item.serviceName)
@@ -276,7 +287,7 @@ App.AddHostController = App.WizardController.extend({
     var masterComponentHosts = App.db.getMasterComponentHosts();
     if (!masterComponentHosts) {
       masterComponentHosts = [];
-      App.Component.find().filterProperty('isMaster', true).forEach(function(item){
+      App.Component.find().filterProperty('isMaster', true).forEach(function (item) {
         masterComponentHosts.push({
           component: item.get('componentName'),
           hostName: item.get('host.hostName'),
@@ -373,24 +384,27 @@ App.AddHostController = App.WizardController.extend({
    * @return {Array}
    */
   getSlaveComponentHosts: function () {
-    var components = [{
-      name : 'DATANODE',
-      service : 'HDFS'
-    },
-    {
-      name: 'TASKTRACKER',
-      service: 'MAPREDUCE'
-    },{
-      name: 'HBASE_REGIONSERVER',
-      service: 'HBASE'
-    }];
+    var components = [
+      {
+        name: 'DATANODE',
+        service: 'HDFS'
+      },
+      {
+        name: 'TASKTRACKER',
+        service: 'MAPREDUCE'
+      },
+      {
+        name: 'HBASE_REGIONSERVER',
+        service: 'HBASE'
+      }
+    ];
 
     var result = [];
     var services = App.Service.find();
     var selectedServices = this.get('content.services').filterProperty('isSelected', true).mapProperty('serviceName');
-    for(var index=0; index < components.length; index++){
+    for (var index = 0; index < components.length; index++) {
       var comp = components[index];
-      if(!selectedServices.contains(comp.service)){
+      if (!selectedServices.contains(comp.service)) {
         continue;
       }
 
@@ -399,11 +413,11 @@ App.AddHostController = App.WizardController.extend({
       var hosts = [];
 
       service.get('hostComponents').filterProperty('componentName', comp.name).forEach(function (host_component) {
-          hosts.push({
-            group: "Default",
-            hostName: host_component.get('host.id'),
-            isInstalled: true
-          });
+        hosts.push({
+          group: "Default",
+          hostName: host_component.get('host.id'),
+          isInstalled: true
+        });
       }, this);
 
       result.push({
@@ -418,11 +432,11 @@ App.AddHostController = App.WizardController.extend({
     var hosts = [];
 
     clientsHosts.forEach(function (host_component) {
-        hosts.push({
-          group: "Default",
-          hostName: host_component.get('host.id'),
-          isInstalled: true
-        });
+      hosts.push({
+        group: "Default",
+        hostName: host_component.get('host.id'),
+        isInstalled: true
+      });
     }, this);
 
     result.push({
@@ -439,7 +453,7 @@ App.AddHostController = App.WizardController.extend({
    */
   loadSlaveComponentHosts: function () {
     var slaveComponentHosts = App.db.getSlaveComponentHosts();
-    if(!slaveComponentHosts){
+    if (!slaveComponentHosts) {
       slaveComponentHosts = this.getSlaveComponentHosts();
     }
     this.set("content.slaveComponentHosts", slaveComponentHosts);
@@ -480,32 +494,32 @@ App.AddHostController = App.WizardController.extend({
   /**
    * Load information about hosts with clients components
    */
-  loadClients: function(){
+  loadClients: function () {
     var clients = App.db.getClientsForSelectedServices();
     this.set('content.clients', clients);
     console.log("AddHostController.loadClients: loaded list ", clients);
   },
-  dataLoading: function(){
+  dataLoading: function () {
     var dfd = $.Deferred();
     this.connectOutlet('loading');
-    var interval = setInterval(function(){
-      if (App.router.get('clusterController.isLoaded')){
+    var interval = setInterval(function () {
+      if (App.router.get('clusterController.isLoaded')) {
         dfd.resolve();
         clearInterval(interval);
       }
-    },50);
+    }, 50);
     return dfd.promise();
   },
   /**
    * Generate clients list for selected services and save it to model
    * @param stepController step4WizardController
    */
-  saveClients: function(){
+  saveClients: function () {
     var clients = [];
     var serviceComponents = require('data/service_components');
     var hostComponents = App.HostComponent.find();
 
-    this.get('content.services').filterProperty('isSelected',true).forEach(function (_service) {
+    this.get('content.services').filterProperty('isSelected', true).forEach(function (_service) {
       var client = serviceComponents.filterProperty('service_name', _service.serviceName).findProperty('isClient', true);
       if (client) {
         clients.pushObject({
@@ -598,67 +612,6 @@ App.AddHostController = App.WizardController.extend({
     });
   },
 
-  /**
-   * Invoke installation of selected services to the server and saves the request id returned by the server.
-   * @param isRetry
-   */
-  installServices: function (isRetry) {
-    if(!isRetry && this.get('content.cluster.requestId')){
-      return;
-    }
-
-    var self = this;
-    var clusterName = this.get('content.cluster.name');
-    var url = (App.testMode) ? '/data/wizard/deploy/poll_1.json' : App.apiPrefix + '/clusters/' + clusterName + '/services?ServiceInfo/state=INIT';
-    var method = (App.testMode) ? 'GET' : 'PUT';
-    var data = '{"ServiceInfo": {"state": "INSTALLED"}}';
-    $.ajax({
-      type: method,
-      url: url,
-      data: data,
-      async: false,
-      dataType: 'text',
-      timeout: App.timeout,
-      success: function (data) {
-        var jsonData = jQuery.parseJSON(data);
-        var installSartTime = new Date().getTime();
-        console.log("TRACE: STep8 -> In success function for the installService call");
-        console.log("TRACE: STep8 -> value of the url is: " + url);
-        if (jsonData) {
-          var requestId = jsonData.href.match(/.*\/(.*)$/)[1];
-
-          console.log('requestId is: ' + requestId);
-          var clusterStatus = {
-            status: 'PENDING',
-            requestId: requestId,
-            isInstallError: false,
-            isCompleted: false,
-            installStartTime: installSartTime
-          };
-          self.saveClusterStatus(clusterStatus);
-        } else {
-          console.log('ERROR: Error occurred in parsing JSON data');
-        }
-      },
-
-      error: function (request, ajaxOptions, error) {
-        console.log("TRACE: STep8 -> In error function for the installService call");
-        console.log("TRACE: STep8 -> value of the url is: " + url);
-        console.log("TRACE: STep8 -> error code status is: " + request.status);
-        console.log('Step8: Error message is: ' + request.responseText);
-        var clusterStatus = {
-          status: 'PENDING',
-          isInstallError: true,
-          isCompleted: false
-        };
-        self.saveClusterStatus(clusterStatus);
-      },
-
-      statusCode: require('data/statusCodes')
-    });
-
-  },
-
   /**
    * Remove all loaded data.
    * Created as copy for App.router.clearAllSteps
@@ -671,7 +624,7 @@ App.AddHostController = App.WizardController.extend({
   /**
    * Clear all temporary data
    */
-  finish: function(){
+  finish: function () {
     this.setCurrentStep('1', false);
     App.db.setService(undefined); //not to use this data at AddService page
     App.db.setHosts(undefined);

+ 7 - 110
ambari-web/app/controllers/main/service/add_controller.js

@@ -23,6 +23,13 @@ App.AddServiceController = App.WizardController.extend({
 
   name: 'addServiceController',
 
+  totalSteps: 7,
+
+  /**
+   * Used for hiding back button in wizard
+   */
+  hideBackButton: true,
+
   /**
    * All wizards data will be stored in this variable
    *
@@ -47,13 +54,6 @@ App.AddServiceController = App.WizardController.extend({
     isWizard: true
   }),
 
-  /**
-   * Used for hiding back button in wizard
-   */
-  hideBackButton: true,
-
-  totalSteps: 7,
-
   /**
    * Load clusterInfo(step1) to model
    */
@@ -71,30 +71,6 @@ App.AddServiceController = App.WizardController.extend({
     console.log("AddServiceController:loadClusterInfo: loaded data ", cluster);
   },
 
-  /**
-   * save status of the cluster. This is called from step8 and step9 to persist install and start requestId
-   * @param clusterStatus object with status, isCompleted, requestId, isInstallError and isStartError field.
-   */
-  saveClusterStatus: function (clusterStatus) {
-    clusterStatus.name = this.get('content.cluster.name');
-    this.set('content.cluster', clusterStatus);
-    console.log('called saveClusterStatus ' + JSON.stringify(clusterStatus));
-    App.db.setClusterStatus(clusterStatus);
-  },
-
-  /**
-   * Temporary function for wizardStep9, before back-end integration
-   */
-  setInfoForStep9: function () {
-    var hostInfo = App.db.getHosts();
-    for (var index in hostInfo) {
-      hostInfo[index].status = "pending";
-      hostInfo[index].message = 'Information';
-      hostInfo[index].progress = '0';
-    }
-    App.db.setHosts(hostInfo);
-  },
-
   /**
    * Load confirmed hosts.
    * Will be used at <code>Assign Masters(step5)</code> step
@@ -142,24 +118,6 @@ App.AddServiceController = App.WizardController.extend({
     console.log('AddServiceController:saveInstalledHosts: save hosts ', 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 = '';
-    }
-    App.db.setHosts(null);
-    App.db.setAllHostNames(null);
-  },
-
   /**
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
@@ -568,67 +526,6 @@ App.AddServiceController = App.WizardController.extend({
     });
   },
 
-  /**
-   * Invoke installation of selected services to the server and saves the request id returned by the server.
-   * @param isRetry
-   */
-  installServices: function (isRetry) {
-    if(!isRetry && this.get('content.cluster.requestId')){
-      return;
-    }
-
-    var self = this;
-    var clusterName = this.get('content.cluster.name');
-    var url = (App.testMode) ? '/data/wizard/deploy/poll_1.json' : App.apiPrefix + '/clusters/' + clusterName + '/services?ServiceInfo/state=INIT';
-    var method = (App.testMode) ? 'GET' : 'PUT';
-    var data = '{"ServiceInfo": {"state": "INSTALLED"}}';
-    $.ajax({
-      type: method,
-      url: url,
-      data: data,
-      async: false,
-      dataType: 'text',
-      timeout: App.timeout,
-      success: function (data) {
-        var jsonData = jQuery.parseJSON(data);
-        var installSartTime = new Date().getTime();
-        console.log("TRACE: STep8 -> In success function for the installService call");
-        console.log("TRACE: STep8 -> value of the url is: " + url);
-        if (jsonData) {
-          var requestId = jsonData.href.match(/.*\/(.*)$/)[1];
-
-          console.log('requestId is: ' + requestId);
-          var clusterStatus = {
-            status: 'PENDING',
-            requestId: requestId,
-            isInstallError: false,
-            isCompleted: false,
-            installStartTime: installSartTime
-          };
-          self.saveClusterStatus(clusterStatus);
-        } else {
-          console.log('ERROR: Error occurred in parsing JSON data');
-        }
-      },
-
-      error: function (request, ajaxOptions, error) {
-        console.log("TRACE: STep8 -> In error function for the installService call");
-        console.log("TRACE: STep8 -> value of the url is: " + url);
-        console.log("TRACE: STep8 -> error code status is: " + request.status);
-        console.log('Step8: Error message is: ' + request.responseText);
-        var clusterStatus = {
-          status: 'PENDING',
-          isInstallError: true,
-          isCompleted: false
-        };
-        self.saveClusterStatus(clusterStatus);
-      },
-
-      statusCode: require('data/statusCodes')
-    });
-
-  },
-
   /**
    * Remove all loaded data.
    * Created as copy for App.router.clearAllSteps

+ 106 - 1
ambari-web/app/controllers/wizard.js

@@ -29,7 +29,7 @@ App.WizardController = Em.Controller.extend({
       step: 1,
       value: false
     }));
-    for (var i = 2; i <= this.totalSteps; i++) {
+    for (var i = 2; i <= this.get('totalSteps'); i++) {
       this.isStepDisabled.pushObject(Ember.Object.create({
         step: i,
         value: true
@@ -187,6 +187,111 @@ App.WizardController = Em.Controller.extend({
     this.gotoStep(10);
   },
 
+  /**
+   * Temporary function for wizardStep9, before back-end integration
+   */
+  setInfoForStep9: function () {
+    var hostInfo = App.db.getHosts();
+    for (var index in hostInfo) {
+      hostInfo[index].status = "pending";
+      hostInfo[index].message = 'Waiting';
+      hostInfo[index].logTasks = [];
+      hostInfo[index].tasks = [];
+      hostInfo[index].progress = '0';
+    }
+    App.db.setHosts(hostInfo);
+  },
+
+  /**
+   * Remove all data for hosts
+   */
+  clearHosts: function () {
+    var hosts = this.get('content').get('hosts');
+    if (hosts) {
+      hosts.set('hostNames', '');
+      hosts.set('manualInstall', false);
+      hosts.set('localRepo', '');
+      hosts.set('localRepopath', '');
+      hosts.set('sshKey', '');
+      hosts.set('passphrase', '');
+      hosts.set('confirmPassphrase', '');
+    }
+    App.db.setHosts(null);
+    App.db.setAllHostNames(null);
+  },
+
+  /**
+   * save status of the cluster. This is called from step8 and step9 to persist install and start requestId
+   * @param clusterStatus object with status, isCompleted, requestId, isInstallError and isStartError field.
+   */
+  saveClusterStatus: function (clusterStatus) {
+    clusterStatus.name = this.get('content.cluster.name');
+    this.set('content.cluster', clusterStatus);
+    console.log(this.get('name') + '.saveClusterStatus: ' + JSON.stringify(clusterStatus));
+    App.db.setClusterStatus(clusterStatus);
+  },
+
+  /**
+   * Invoke installation of selected services to the server and saves the request id returned by the server.
+   * @param isRetry
+   */
+  installServices: function (isRetry) {
+    if (!isRetry && this.get('content.cluster.requestId')) {
+      return;
+    }
+
+    var self = this;
+    var clusterName = this.get('content.cluster.name');
+    var url = (App.testMode) ? '/data/wizard/deploy/poll_1.json' : App.apiPrefix + '/clusters/' + clusterName + '/services?ServiceInfo/state=INIT';
+    var method = (App.testMode) ? 'GET' : 'PUT';
+    var data = '{"ServiceInfo": {"state": "INSTALLED"}}';
+    $.ajax({
+      type: method,
+      url: url,
+      data: data,
+      async: false,
+      dataType: 'text',
+      timeout: App.timeout,
+      success: function (data) {
+        var jsonData = jQuery.parseJSON(data);
+        var installStartTime = new Date().getTime();
+        console.log("TRACE: In success function for the installService call");
+        console.log("TRACE: value of the url is: " + url);
+        if (jsonData) {
+          var requestId = jsonData.href.match(/.*\/(.*)$/)[1];
+          console.log('requestId is: ' + requestId);
+          var clusterStatus = {
+            status: 'PENDING',
+            requestId: requestId,
+            isInstallError: false,
+            isCompleted: false,
+            installStartTime: installStartTime
+          };
+          self.saveClusterStatus(clusterStatus);
+        } else {
+          console.log('ERROR: Error occurred in parsing JSON data');
+        }
+      },
+
+      error: function (request, ajaxOptions, error) {
+        console.log("TRACE: In error function for the installService call");
+        console.log("TRACE: value of the url is: " + url);
+        console.log("TRACE: error code status is: " + request.status);
+        console.log('Error message is: ' + request.responseText);
+        var clusterStatus = {
+          status: 'PENDING',
+          isInstallError: false,
+          isCompleted: false
+        };
+
+        self.saveClusterStatus(clusterStatus);
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+
+  },
+
   load: function (name, reload) {
     if (this.get('content.' + name) && !reload) {
       return false;

+ 7 - 12
ambari-web/app/controllers/wizard/step10_controller.js

@@ -64,15 +64,10 @@ App.WizardStep10Controller = Em.Controller.extend({
       hostsInfo.pushObject(hosts[index]);
       console.log('Step10 SUMMARY: value of hosts is: ' + hosts[index].status);
     }
-    var succededHosts = hostsInfo.filterProperty('status', 'success');
+    var succeededHosts = hostsInfo.filterProperty('status', 'success');
     var warnedHosts = hostsInfo.filterProperty('status', 'warning').concat(hostsInfo.filterProperty('status', 'failed'));
-    if (succededHosts.length) {
-      var successStatement;
-      if (succededHosts.length > 1) {
-        successStatement = succededHosts.length + ' nodes succeded completely to install and start all service components assigned to them.';
-      } else {
-        successStatement = succededHosts.length + ' node succeded completely to install and start all service components assigned to it.';
-      }
+    if (succeededHosts.length) {
+      var successStatement = succeededHosts.length + ' ' + ((succeededHosts.length > 1) ? 'hosts' : 'host') + ' installed and started services successfully.';
       this.get('clusterInfo').findProperty('id', 1).get('status').pushObject(Ember.Object.create({
         id: 1,
         color: 'text-success',
@@ -91,7 +86,7 @@ App.WizardStep10Controller = Em.Controller.extend({
 
       warnedHosts.forEach(function (_host) {
         var clusterState;
-        console.log("Content.cluster.staus is: " + this.get('content.cluster.status'));
+        console.log("Content.cluster.status is: " + this.get('content.cluster.status'));
         if (this.get('content.cluster.status') === 'INSTALL FAILED') {
           clusterState = 'Installing ';
         } else if (this.get('content.cluster.status') === 'START FAILED') {
@@ -100,7 +95,7 @@ App.WizardStep10Controller = Em.Controller.extend({
         console.log('host value is: ' + JSON.stringify(_host));
         var failedTasks = _host.tasks.filterProperty('Tasks.status', 'FAILED');
         failedTasks.forEach(function (_task) {
-          var taskStatement = clusterState + _task.Tasks.role + ' failed on ' + _host.name;
+          var taskStatement = clusterState + App.format.role(_task.Tasks.role) + ' failed on ' + _host.name;
           this.get('clusterInfo').findProperty('id', 1).get('status').findProperty('id', 2).get('statements').pushObject(Ember.Object.create({
             status: 'failed',
             color: 'text-info',
@@ -110,7 +105,7 @@ App.WizardStep10Controller = Em.Controller.extend({
 
         var abortedTasks = _host.tasks.filterProperty('Tasks.status', 'ABORTED');
         abortedTasks.forEach(function (_task) {
-          var abortStatement = clusterState + _task.Tasks.role + ' aborted on ' + _host.name;
+          var abortStatement = clusterState + App.format.role(_task.Tasks.role) + ' aborted on ' + _host.name;
           this.get('clusterInfo').findProperty('id', 1).get('status').findProperty('id', 2).get('statements').pushObject(Ember.Object.create({
             status: 'aborted',
             color: 'text-info',
@@ -120,7 +115,7 @@ App.WizardStep10Controller = Em.Controller.extend({
 
         var timedOutTasks = _host.tasks.filterProperty('Tasks.status', 'TIMEDOUT');
         timedOutTasks.forEach(function (_task) {
-          var abortStatement = clusterState + _task.Tasks.role + ' timed out on ' + _host.name;
+          var abortStatement = clusterState + App.format.role(_task.Tasks.role) + ' timed out on ' + _host.name;
           this.get('clusterInfo').findProperty('id', 1).get('status').findProperty('id', 2).get('statements').pushObject(Ember.Object.create({
             status: 'timedout',
             color: 'text-info',

+ 11 - 2
ambari-web/app/controllers/wizard/step3_controller.js

@@ -26,7 +26,7 @@ App.WizardStep3Controller = Em.Controller.extend({
   maxRegistrationAttempts: 20,
   registrationAttempts: null,
   isSubmitDisabled: true,
-  categories: ['All Hosts', 'Success', 'Error'],
+  categories: ['All Hosts', 'Success', 'Installing', 'Registering', 'Failed'],
   category: 'All Hosts',
   allChecked: false,
 
@@ -128,7 +128,13 @@ App.WizardStep3Controller = Em.Controller.extend({
   visibleHosts: function () {
     if (this.get('category') === 'Success') {
       return (this.hosts.filterProperty('bootStatus', 'REGISTERED'));
-    } else if (this.get('category') === 'Error') {
+    } else if (this.get('category') === 'Installing') {
+      return (this.hosts.filterProperty('bootStatus', 'RUNNING'));
+    } else if (this.get('category') === 'Registering') {
+      return (this.hosts.filter(function(host) {
+        return host.bootStatus == 'DONE' || host.bootStatus == 'REGISTERING';
+      }));
+    } else if (this.get('category') === 'Failed') {
       return (this.hosts.filterProperty('bootStatus', 'FAILED'));
     } else { // if (this.get('category') === 'All Hosts')
       return this.hosts;
@@ -143,6 +149,9 @@ App.WizardStep3Controller = Em.Controller.extend({
       onPrimary: function () {
         App.router.send('removeHosts', hosts);
         self.hosts.removeObjects(hosts);
+        if(!self.hosts.length){
+          self.set('isSubmitDisabled', true);
+        }
         this.hide();
       },
       body: Em.I18n.t('installer.step3.hosts.remove.popup.body')

+ 3 - 1
ambari-web/app/controllers/wizard/step5_controller.js

@@ -168,6 +168,8 @@ App.WizardStep5Controller = Em.Controller.extend({
       this.set('selectedServicesMasters', []);
     }
 
+    var countZookeeper = masterComponents.filterProperty('display_name', 'ZooKeeper').length;
+
     masterComponents.forEach(function (item) {
       //add the zookeeper component at the end if exists
       console.log("TRACE: render master component name is: " + item.component_name);
@@ -180,7 +182,7 @@ App.WizardStep5Controller = Em.Controller.extend({
         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("showRemoveControl", countZookeeper > 1);
         zookeeperComponent.set("availableHosts", this.get("hosts").slice(0));
         this.get("selectedServicesMasters").pushObject(zookeeperComponent);
 

+ 1 - 1
ambari-web/app/controllers/wizard/step8_controller.js

@@ -714,7 +714,7 @@ App.WizardStep8Controller = Em.Controller.extend({
 
     var url = App.apiPrefix + '/clusters/' + this.get('clusterName');
 
-    var stackVersion = (App.db.getSoftRepo().repoType == 'local') ? App.defaultStackVersion + '-local' : App.defaultStackVersion;
+    var stackVersion = (App.db.getSoftRepo().repoType == 'local') ? App.defaultLocalStackVersion : App.defaultStackVersion;
 
     $.ajax({
       type: 'POST',

+ 47 - 18
ambari-web/app/controllers/wizard/step9_controller.js

@@ -23,12 +23,11 @@ App.WizardStep9Controller = Em.Controller.extend({
   progress: '0',
   isStepCompleted: false,
   isSubmitDisabled: function () {
-    //return false;
-    return !this.get('isStepCompleted'); //TODO: uncomment after the hook up
+    return !this.get('isStepCompleted');
   }.property('isStepCompleted'),
 
   mockHostData: require('data/mock/step9_hosts'),
-  mockDataPrefix: '/data/wizard/deploy/5_hosts',
+  mockDataPrefix: '/data/wizard/deploy/slave_warning',
   pollDataCounter: 0,
   polledData: [],
 
@@ -58,11 +57,14 @@ App.WizardStep9Controller = Em.Controller.extend({
     if (this.get('content.cluster.isCompleted') === false) {
       if (this.get('content.cluster.status') === 'INSTALL FAILED') {
         this.loadStep();
+        this.loadLogData(this.get('content.cluster.requestId'));
         this.hosts.setEach('status', 'failed');
         this.set('progress', '100');
         this.set('isStepCompleted', true);
         //this.set('status', 'failed');
       } else if (this.get('content.cluster.status') === 'START FAILED') {
+        this.loadStep();
+        this.loadLogData(this.get('content.cluster.requestId'));
         this.hosts.setEach('status', 'info');
         this.set('isStepCompleted', false);
         this.launchStartServices();
@@ -71,8 +73,11 @@ App.WizardStep9Controller = Em.Controller.extend({
         this.startPolling();
       }
     } else {
+      this.loadStep();
+      this.loadLogData(this.get('content.cluster.requestId'));
       this.set('isStepCompleted', true);
       this.set('progress', '100');
+
     }
   },
 
@@ -218,7 +223,6 @@ App.WizardStep9Controller = Em.Controller.extend({
     var method = 'PUT';
 
     if (App.testMode) {
-      debugger;
       url = this.get('mockDataPrefix') + '/poll_6.json';
       method = 'GET';
       this.numPolls = 6;
@@ -246,6 +250,7 @@ App.WizardStep9Controller = Em.Controller.extend({
           isStartError: false,
           isCompleted: false
         };
+
         App.router.get(self.get('content.controllerName')).saveClusterStatus(clusterStatus);
         self.startPolling();
       },
@@ -315,12 +320,17 @@ App.WizardStep9Controller = Em.Controller.extend({
     return polledData.everyProperty('Tasks.status', 'COMPLETED');
   },
 
+  // for DATANODE, JOBTRACKER, HBASE_REGIONSERVER, and GANGLIA_MONITOR, if more than 50% fail, then it's a fatal error;
+  // otherwise, it's only a warning and installation/start can continue
+  getSuccessFactor: function (role) {
+    return ['DATANODE','JOBTRACKER','HBASE_REGIONSERVER','GANGLIA_MONITOR'].contains(role) ? 50 : 100;
+  },
+
   isStepFailed: function (polledData) {
     var self = this;
     var result = false;
     polledData.forEach(function (_polledData) {
-      _polledData.Tasks.sf = 100;  //TODO: Remove this line after hook up with actual success factor
-      var successFactor = _polledData.Tasks.sf;
+      var successFactor = this.getSuccessFactor(_polledData.Tasks.role);
       console.log("Step9: isStepFailed sf value: " + successFactor);
       var actionsPerRole = polledData.filterProperty('Tasks.role', _polledData.Tasks.role);
       var actionsFailed = actionsPerRole.filterProperty('Tasks.status', 'FAILED');
@@ -330,15 +340,14 @@ App.WizardStep9Controller = Em.Controller.extend({
         console.log('TRACE: Entering success factor and result is failed');
         result = true;
       }
-    });
+    }, this);
     return result;
   },
 
   getFailedHostsForFailedRoles: function (polledData) {
     var hostArr = new Ember.Set();
     polledData.forEach(function (_polledData) {
-      _polledData.sf = 100;  //TODO: Remove this line after hook up with actual success factor
-      var successFactor = _polledData.sf;
+      var successFactor = this.getSuccessFactor(_polledData.Tasks.role);
       var actionsPerRole = polledData.filterProperty('Tasks.role', _polledData.Tasks.role);
       var actionsFailed = actionsPerRole.filterProperty('Tasks.status', 'FAILED');
       var actionsAborted = actionsPerRole.filterProperty('Tasks.status', 'ABORTED');
@@ -354,7 +363,7 @@ App.WizardStep9Controller = Em.Controller.extend({
           hostArr.add(_actionFailed.Tasks.host_name);
         });
       }
-    });
+    }, this);
     return hostArr;
   },
 
@@ -504,9 +513,9 @@ App.WizardStep9Controller = Em.Controller.extend({
 
   numPolls: 0,
 
-  getUrl: function () {
+  getUrl: function (requestId) {
     var clusterName = this.get('content.cluster.name');
-    var requestId = this.get('content.cluster.requestId');
+    var requestId = requestId || this.get('content.cluster.requestId');
     var url = App.apiPrefix + '/clusters/' + clusterName + '/requests/' + requestId + '?fields=tasks/*';
     console.log("URL for step9 is: " + url);
     return url;
@@ -514,9 +523,8 @@ App.WizardStep9Controller = Em.Controller.extend({
 
   POLL_INTERVAL: 4000,
 
-  doPolling: function () {
-    var self = this;
-    var url = this.getUrl();
+  loadLogData:function(requestId){
+    var url = this.getUrl(requestId);
 
     if (App.testMode) {
       this.POLL_INTERVAL = 1;
@@ -527,9 +535,16 @@ App.WizardStep9Controller = Em.Controller.extend({
       } else {
         url = this.get('mockDataPrefix') + '/poll_' + this.numPolls + '.json';
       }
-      debugger;
     }
+    this.getLogsByRequest(url);
 
+    if(typeof(requestId) === 'number' && requestId > 1){
+      requestId--;
+      this.loadLogData(requestId);
+    }
+  },
+  getLogsByRequest: function(url){
+    var self = this;
     $.ajax({
       type: 'GET',
       url: url,
@@ -537,7 +552,7 @@ App.WizardStep9Controller = Em.Controller.extend({
       timeout: App.timeout,
       dataType: 'text',
       success: function (data) {
-        console.log("TRACE: In success function for the GET bootstrap call");
+        console.log("TRACE: In success function for the GET logs data");
         console.log("TRACE: STep9 -> The value is: ", jQuery.parseJSON(data));
         var result = self.parseHostInfo(jQuery.parseJSON(data));
         if (result !== true) {
@@ -550,7 +565,7 @@ App.WizardStep9Controller = Em.Controller.extend({
       },
 
       error: function (request, ajaxOptions, error) {
-        console.log("TRACE: STep9 -> In error function for the getService call");
+        console.log("TRACE: STep9 -> In error function for the GET logs data");
         console.log("TRACE: STep9 -> value of the url is: " + url);
         console.log("TRACE: STep9 -> error code status is: " + request.status);
         self.stopPolling();
@@ -558,7 +573,21 @@ App.WizardStep9Controller = Em.Controller.extend({
 
       statusCode: require('data/statusCodes')
     });
+  },
+  doPolling: function () {
+    var url = this.getUrl();
 
+    if (App.testMode) {
+      this.POLL_INTERVAL = 1;
+      this.numPolls++;
+      if (this.numPolls == 5) {
+        url = this.get('mockDataPrefix') + '/poll_5.json';
+        // url = this.get('mockDataPrefix') + '/poll_5_failed.json';
+      } else {
+        url = this.get('mockDataPrefix') + '/poll_' + this.numPolls + '.json';
+      }
+    }
+    this.getLogsByRequest(url);
   },
 
   stopPolling: function () {

+ 1 - 0
ambari-web/app/initialize.js

@@ -24,6 +24,7 @@ App.skipBootstrap = false;
 App.alwaysGoToInstaller = false;
 App.apiPrefix = '/api/v1';
 App.defaultStackVersion = 'HDP-1.2.0';
+App.defaultLocalStackVersion = 'HDPLocal-1.2.0';
 // default AJAX timeout
 App.timeout = 20000;
 App.bgOperationsUpdateInterval = 6000;

+ 1 - 1
ambari-web/app/mappers/users_mapper.js

@@ -27,7 +27,7 @@ App.usersMapper = App.QuickDataMapper.create({
     admin: 'Users.admin'
   },
   map: function (json) {
-    self = this;
+    var self = this;
     json.items.forEach(function (item) {
       var result= [] ;
       if(App.User.find(item.Users.user_name).get("userName") != item.Users.user_name)

+ 3 - 2
ambari-web/app/messages.js

@@ -121,8 +121,9 @@ Em.I18n.translations = {
 
   'installer.step9.header':'Install, Start and Test',
   'installer.step9.body':'Please wait while the selected services are installed, started, and tested on your new cluster.',
-  'installer.step9.status.success':'Successfully installed the cluster',
-  'installer.step9.status.failed':'Failure in installation',
+  'installer.step9.status.success':'Successfully installed the cluster.',
+  'installer.step9.status.warning':'Installed the cluster with some warnings.',
+  'installer.step9.status.failed':'Failed to install the cluster.',
   'installer.step9.host.status.success':'Success',
   'installer.step9.host.status.warning':'Warnings encountered',
   'installer.step9.host.status.failed':'Failures encountered',

+ 1 - 1
ambari-web/app/templates/main/host/summary.hbs

@@ -30,7 +30,7 @@
           <dt>Disk Usage:</dt><dd>&nbsp;{{view.content.diskUsage}}</dd>
           <dt>Memory:</dt><dd>&nbsp;{{view.content.memoryFormatted}}</dd>
 		      <dt>Load Avg:</dt><dd>&nbsp;{{view.content.loadAvg}}</dd>
-		      <dt>Agent:</dt><dd>running</dd>
+		      <dt>Agent:</dt><dd>{{view.timeSinceHeartBeat}}</dd>
 		    </dl>
 		  </div>
 	  </div>

+ 6 - 0
ambari-web/app/templates/main/service/info/summary.hbs

@@ -63,6 +63,12 @@
           <td><a target=_blank href="http://{{unbound view.gangliaServer}}/ganglia">{{view.gangliaServer}}/ganglia</a></td>
         </tr>
       {{/if}}
+      {{#if view.serviceStatus.nagios}}
+        <tr>
+          <td class="summary-label">Nagios Web UI</td>
+          <td><a target=_blank href="http://{{unbound view.nagiosServer}}/nagios">{{view.nagiosServer}}/nagios</a></td>
+        </tr>
+      {{/if}}
       {{/unless}}
       {{/unless}}
       {{/unless}}

+ 4 - 1
ambari-web/app/templates/wizard/step2.hbs

@@ -38,7 +38,10 @@
           <p class="alert alert-info">
             {{t hosts.add.step2.warning}}
             <br/>
-            {{content.oldHostNames}}
+            {{{content.oldHostNames}}}
+              {{#if content.showMoreHostsText}}
+                <a href="" {{action showMoreHosts target="view.parentView.controller"}}>{{content.showMoreHostsText}}</a>
+              {{/if}}
           </p>
         {{/if}}
       {{/if}}

+ 26 - 2
ambari-web/app/utils/data_table.js

@@ -351,8 +351,26 @@ jQuery.extend($.fn.dataTableExt.afnFiltering.push(
 
       function numberFilter(rangeExp, rowValue) {
         var compareChar = rangeExp.charAt(0);
-        var compareValue = parseFloat(rangeExp.substr(1, rangeExp.length - 1));
-        rowValue = (jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue;
+        var compareValue;
+        if (rangeExp.length == 1) {
+          if (isNaN(parseInt(compareChar))) {
+            // User types only '=' or '>' or '<', so don't filter column values
+            match = true;
+            return match;
+          }
+          else {
+            compareValue = parseFloat(parseFloat(rangeExp).toFixed(2));
+          }
+        }
+        else {
+          if (isNaN(parseInt(compareChar))) {
+            compareValue = parseFloat(parseFloat(rangeExp.substr(1, rangeExp.length)).toFixed(2));
+          }
+          else {
+            compareValue = parseFloat(parseFloat(rangeExp.substr(0, rangeExp.length)).toFixed(2));
+          }
+        }
+        rowValue = parseFloat((jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue);
         match = false;
         switch (compareChar) {
           case '<':
@@ -439,6 +457,12 @@ jQuery.fn.dataTableExt.oApi.fnGetColumnData = function ( oSettings, iColumn, bUn
 
   return asResultData;
 };
+jQuery.fn.dataTableExt.ofnSearch['num-html'] = function ( sData ) {
+  return sData.replace(/[\r\n]/g, " ").replace(/<.*?>/g, "");
+}
+jQuery.fn.dataTableExt.ofnSearch['ambari-bandwidth'] = function ( sData ) {
+  return sData.replace(/[\r\n]/g, " ").replace(/<.*?>/g, "");
+}
 
 
 

+ 2 - 1
ambari-web/app/views/common/modal_popup.js

@@ -31,7 +31,7 @@ App.ModalPopup = Ember.View.extend({
     '</div>',
     '<div class="modal-body">',
     '{{#if bodyClass}}{{view bodyClass}}',
-    '{{else}}{{body}}{{/if}}',
+    '{{else}}{{#if encodeBody}}{{body}}{{else}}{{{body}}}{{/if}}{{/if}}',
     '</div>',
     '<div class="modal-footer">',
     '{{#if view.secondary}}<a class="btn" {{action onSecondary target="view"}}>{{view.secondary}}</a>{{/if}}',
@@ -42,6 +42,7 @@ App.ModalPopup = Ember.View.extend({
 
   header: '&nbsp;',
   body: '&nbsp;',
+  encodeBody: true,
   // define bodyClass which extends Ember.View to use an arbitrary Handlebars template as the body
   primary: 'OK',
   secondary: 'Cancel',

+ 2 - 2
ambari-web/app/views/main/host.js

@@ -51,9 +51,9 @@ App.MainHostView = Em.View.extend({
         { "sType":"html" },
         { "sType":"num-html" },
         { "sType":"ambari-bandwidth" },
-        { "sType":"string" },
+        { "sType":"html" },
         { "sType":"num-html" },
-        { "sType":"string", "bSortable": false  }
+        { "sType":"html", "bSortable": false  }
       ]
     });
     this.set('oTable', oTable);

+ 10 - 3
ambari-web/app/views/main/host/summary.js

@@ -21,10 +21,10 @@ var App = require('app');
 App.MainHostSummaryView = Em.View.extend({
   templateName: require('templates/main/host/summary'),
 
-  content:function(){
+  content: function () {
     return App.router.get('mainHostDetailsController.content');
   }.property('App.router.mainHostDetailsController.content'),
-  
+
 
   showGangliaCharts: function () {
     var name = this.get('content.hostName');
@@ -99,6 +99,13 @@ App.MainHostSummaryView = Em.View.extend({
         componentName === 'PIG' ||
         componentName === 'SQOOP';
     }.property('content')
-  })
+  }),
 
+  timeSinceHeartBeat: function () {
+    var d = this.get('content.lastHeartBeatTime');
+    if (d) {
+      return $.timeago(d);
+    }
+    return "";
+  }.property('content.lastHeartBeatTime')
 });

+ 11 - 2
ambari-web/app/views/main/service/info/summary.js

@@ -29,7 +29,8 @@ App.MainServiceInfoSummaryView = Em.View.extend({
     zookeeper:false,
     oozie:false,
     hive:false,
-    ganglia:false
+    ganglia:false,
+    nagios:false
   },
 
   data:{
@@ -42,7 +43,15 @@ App.MainServiceInfoSummaryView = Em.View.extend({
   gangliaServer:function(){
     var tmp=this.get('controller.content');
     if(tmp.get("id") == "GANGLIA"){
-      return tmp.get("components").objectAt(0).get("host").get("id");
+      return tmp.get("components").objectAt(0).get("host").get("publicHostName");
+    }else{
+      return "";
+    }
+  }.property('controller.content'),
+  nagiosServer:function(){
+    var tmp=this.get('controller.content');
+    if(tmp.get("id") == "NAGIOS"){
+      return tmp.get("components").objectAt(0).get("host").get("publicHostName");
     }else{
       return "";
     }

+ 74 - 47
ambari-web/app/views/wizard/step9_view.js

@@ -20,30 +20,32 @@ var App = require('app');
 
 App.WizardStep9View = Em.View.extend({
 
-  templateName: require('templates/wizard/step9'),
-  barColor: '',
-  resultMsg: '',
-  resultMsgColor: '',
+  templateName:require('templates/wizard/step9'),
+  barColor:'',
+  resultMsg:'',
+  resultMsgColor:'',
 
-  didInsertElement: function () {
+  didInsertElement:function () {
     var controller = this.get('controller');
     this.get('controller.hosts').setEach('status', 'info');
     this.onStatus();
     controller.navigateStep();
   },
 
-  barWidth: function () {
+  barWidth:function () {
     var controller = this.get('controller');
     var barWidth = 'width: ' + controller.get('progress') + '%;';
     return barWidth;
   }.property('controller.progress'),
 
-  onStatus: function () {
+  onStatus:function () {
     if (this.get('controller.status') === 'info') {
       this.set('resultMsg', '');
       this.set('barColor', 'progress-info');
     } else if (this.get('controller.status') === 'warning') {
       this.set('barColor', 'progress-warning');
+      this.set('resultMsg', Em.I18n.t('installer.step9.status.warning'));
+      this.set('resultMsgColor', 'alert-warning');
     } else if (this.get('controller.status') === 'failed') {
       this.set('barColor', 'progress-danger');
       console.log('TRACE: Inside error view step9');
@@ -59,21 +61,21 @@ App.WizardStep9View = Em.View.extend({
 });
 
 App.HostStatusView = Em.View.extend({
-  tagName: 'tr',
-  obj: 'null',
-  barColor: '',
+  tagName:'tr',
+  obj:'null',
+  barColor:'',
 
-  didInsertElement: function () {
+  didInsertElement:function () {
     var controller = this.get('controller');
     this.onStatus();
   },
 
-  barWidth: function () {
+  barWidth:function () {
     var barWidth = 'width: ' + this.get('obj.progress') + '%;';
     return barWidth;
   }.property('obj.progress'),
 
-  onStatus: function () {
+  onStatus:function () {
     if (this.get('obj.status') === 'info') {
       this.set('barColor', 'progress-info');
     } else if (this.get('obj.status') === 'warning') {
@@ -94,7 +96,7 @@ App.HostStatusView = Em.View.extend({
     }
   }.observes('obj.status', 'obj.progress'),
 
-  isFailed: function () {
+  isFailed:function () {
     if (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'failed') {
       return true;
     } else {
@@ -102,7 +104,7 @@ App.HostStatusView = Em.View.extend({
     }
   }.property('controller.isStepCompleted', 'controller.status'),
 
-  isSuccess: function () {
+  isSuccess:function () {
     if (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'success') {
       return true;
     } else {
@@ -110,7 +112,7 @@ App.HostStatusView = Em.View.extend({
     }
   }.property('controller.isStepCompleted', 'controller.status'),
 
-  isWarning: function () {
+  isWarning:function () {
     if (this.get('controller.isStepCompleted') === true && this.get('obj.status') === 'warning') {
       return true;
     } else {
@@ -118,34 +120,57 @@ App.HostStatusView = Em.View.extend({
     }
   }.property('controller.isStepCompleted', 'controller.status'),
 
-  isHostCompleted: function () {
+  isHostCompleted:function () {
     return this.get('obj.progress') == 100 || this.get('controller.isStepCompleted');
   }.property('controller.isStepCompleted', 'obj.progress'),
 
-  hostLogPopup: function (event, context) {
+  hostLogPopup:function (event, context) {
     var self = this;
     var host = event.context;
     App.ModalPopup.show({
-      header: Em.I18n.t('installer.step9.hostLog.popup.header') + event.context.get('name'),
-      onPrimary: function () {
+      header:Em.I18n.t('installer.step9.hostLog.popup.header') + event.context.get('name'),
+      onPrimary:function () {
         this.hide();
       },
-      secondary: null,
-      controllerBinding: context,
-      bodyClass: Ember.View.extend({
-        templateName: require('templates/wizard/step9HostTasksLogPopup'),
+      secondary:null,
+      controllerBinding:context,
+      bodyClass:Ember.View.extend({
+        templateName:require('templates/wizard/step9HostTasksLogPopup'),
 
-        hostObj: function () {
+        hostObj:function () {
           return this.get('parentView.obj');
         }.property('parentView.obj'),
 
-        startedTasks: [], // initialized in didInsertElement
+        startedTasks:[], // initialized in didInsertElement
 
         task: null, // set in showTaskLog; contains task info including stdout and stderr
+        /**
+         * sort task array by request Id
+         * @param tasks
+         * @return {Array}
+         */
+        sortTasksByRequest: function(tasks){
+          var result = [];
+          var requestId = 1;
+          for(var i = 0; i < tasks.length; i++){
+            requestId = (tasks[i].Tasks.request_id > requestId) ? tasks[i].Tasks.request_id : requestId;
+          }
+          while(requestId >= 1){
+            for(var j = 0; j < tasks.length; j++){
+              if(requestId == tasks[j].Tasks.request_id){
+                result.push(tasks[j]);
+              }
+            }
+            requestId--;
+          }
+          result.reverse();
+          return result;
+        },
 
-        roles: function () {
+        roles:function () {
           var roleArr = [];
           var tasks = this.getStartedTasks(host);
+          tasks = this.sortTasksByRequest(tasks);
           if (tasks.length) {
             var _roles = tasks.mapProperty('Tasks.role').uniq();
             _roles.forEach(function (_role) {
@@ -154,11 +179,12 @@ App.HostStatusView = Em.View.extend({
               roleObj.roleName = App.format.role(_role);
               tasks.filterProperty('Tasks.role', _role).forEach(function (_task) {
                 var taskInfo = Ember.Object.create({
-                  isTextArea: false,
-                  buttonLabel: function(){
-                    return (this.get('isTextArea')) ? 'Press CTRL+C': 'Click to highlight';
+                  isTextArea:false,
+                  buttonLabel:function () {
+                    return (this.get('isTextArea')) ? 'Press CTRL+C' : 'Click to highlight';
                   }.property('isTextArea')
                 });
+                taskInfo.set('requestId', _task.Tasks.request_id);
                 taskInfo.set('command', _task.Tasks.command.toLowerCase());
                 taskInfo.set('status', App.format.taskStatus(_task.Tasks.status));
                 taskInfo.set('url', _task.href);
@@ -172,14 +198,14 @@ App.HostStatusView = Em.View.extend({
           return roleArr;
         }.property('startedTasks.@each'),
 
-        didInsertElement: function () {
+        didInsertElement: function () {debugger;
           console.log('The value of event context is: ' + host.name);
-          this.get('roles').forEach(function(role){
-            role.taskInfos.forEach(function(task){
+          this.get('roles').forEach(function (role) {
+            role.taskInfos.forEach(function (task) {
               task.set('isLogHidden', true);
             });
           });
-          $(this.get('element')).find('.content-area').each(function(index, value){
+          $(this.get('element')).find('.content-area').each(function (index, value) {
             var button = $(value).find('.textTrigger');
             $(value).mouseenter(
               function () {
@@ -196,29 +222,29 @@ App.HostStatusView = Em.View.extend({
 
         },
 
-        getStartedTasks: function (host) {
+        getStartedTasks:function (host) {
           var startedTasks = host.logTasks.filter(function (task) {
             return task.Tasks.status != 'PENDING' && task.Tasks.status != 'QUEUED';
           });
           return startedTasks;
         },
 
-        toggleTaskLog: function (event, context) {
+        toggleTaskLog:function (event, context) {
           var taskInfo = event.context;
           if (taskInfo.get('isLogHidden')) {
             var url = (App.testMode) ? '/data/wizard/deploy/task_log.json' : taskInfo.url;
             $.ajax({
-              url: url,
-              dataType: 'text',
-              timeout: App.timeout,
-              success: function (data) {
+              url:url,
+              dataType:'text',
+              timeout:App.timeout,
+              success:function (data) {
                 var task = $.parseJSON(data);
                 taskInfo.set('stdout', task.Tasks.stdout);
                 taskInfo.set('stderr', task.Tasks.stderr);
                 taskInfo.set('isLogHidden', false);
                 taskInfo.set('isTextArea', false);
               },
-              error: function () {
+              error:function () {
                 alert('Failed to retrieve task log');
               }
             });
@@ -226,23 +252,24 @@ App.HostStatusView = Em.View.extend({
             taskInfo.set('isLogHidden', true);
           }
         },
-        textTrigger: function(event){
+        textTrigger:function (event) {
           var task = event.context;
           task.set('isTextArea', !task.get('isTextArea'));
         },
-        textArea: Em.TextArea.extend({
-          didInsertElement: function(){
+        textArea:Em.TextArea.extend({
+          didInsertElement:function () {
             var element = $(this.get('element'));
             element.width($(this.get('parentView').get('element')).width() - 10);
             element.height($(this.get('parentView').get('element')).height());
             element.select();
             element.css('resize', 'none');
+            this.$().flexible();
           },
-          readOnly: true,
-          value: function(){
+          readOnly:true,
+          value:function () {
             var taskInfo = this.get('content');
             var content = "";
-            content += this.get('role').role  + " " + taskInfo.command + " log " + taskInfo.status + "\n";
+            content += this.get('role').role + " " + taskInfo.command + " log " + taskInfo.status + "\n";
             content += "stderr: " + taskInfo.stderr + "\n";
             content += "stdout: " + taskInfo.stdout + "\n";
             return content;

+ 2 - 1
ambari-web/config.coffee

@@ -55,7 +55,8 @@ exports.config =
           'vendor/scripts/jquery.timeago.js',
           'vendor/scripts/workflow_visualization.js',
           'vendor/scripts/rickshaw.js',
-          'vendor/scripts/spin.js'
+          'vendor/scripts/spin.js',
+          'vendor/scripts/jquery.flexibleArea.js'
           ]
 
     stylesheets:

+ 3 - 0
ambari-web/vendor/scripts/jquery.dataTables.js

@@ -2088,6 +2088,9 @@
          *  @memberof DataTable#oApi
          */
         function _fnBuildSearchRow(oSettings, aData) {
+          for ( var i=0, len=aData.length ; i<len ; i++ ) {
+             aData[i] = _fnDataToSearch( aData[i], oSettings.aoColumns[i].sType );
+          }
           var sSearch = aData.join('  ');
 
           /* If it looks like there is an HTML entity in the string, attempt to decode it */

+ 124 - 0
ambari-web/vendor/scripts/jquery.flexibleArea.js

@@ -0,0 +1,124 @@
+/*!
+* flexibleArea.js v1.0
+* A jQuery plugin that dynamically updates textarea's height to fit the content.
+* http://flaviusmatis.github.com/flexibleArea.js/
+*
+* Copyright 2012, Flavius Matis
+* Released under the MIT license.
+* http://flaviusmatis.github.com/license.html
+*/
+
+(function($){
+	var methods = {
+		init : function() {
+
+			var styles = [
+				'paddingTop',
+				'paddingRight',
+				'paddingBottom',
+				'paddingLeft',
+				'fontSize',
+				'lineHeight',
+				'fontFamily',
+				'width',
+				'fontWeight',
+				'border-top-width',
+				'border-right-width',
+				'border-bottom-width',
+				'border-left-width'
+			];
+
+			return this.each( function() {
+
+				if (this.type !== 'textarea')	return false;
+					
+				var $textarea = $(this).css({'resize': 'none', overflow: 'hidden'});
+				
+				var	$clone = $('<div></div>').css({
+					'position' : 'absolute',
+					'display' : 'none',
+					'word-wrap' : 'break-word',
+					'white-space' : 'pre-wrap',
+					'border-style' : 'solid'
+				}).appendTo(document.body);
+
+				// Apply textarea styles to clone
+				for (var i=0; i < styles.length; i++) {
+					$clone.css(styles[i],$textarea.css(styles[i]));
+				}
+
+				var textareaHeight = parseInt($textarea.css('height'), 10);
+				var lineHeight = parseInt($textarea.css('line-height'), 10) || parseInt($textarea.css('font-size'), 10);
+				var minheight = lineHeight * 2 > textareaHeight ? lineHeight * 2 : textareaHeight;
+				var maxheight = parseInt($textarea.css('max-height'), 10) > -1 ? parseInt($textarea.css('max-height'), 10) : Number.MAX_VALUE;
+
+				function updateHeight() {
+					var textareaContent = $textarea.val().replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/&/g, '&amp;').replace(/\n/g, '<br/>');
+					// Adding an extra white space to make sure the last line is rendered.
+					$clone.html(textareaContent + '&nbsp;');
+					setHeightAndOverflow();
+				}
+
+				function setHeightAndOverflow(){
+					var cloneHeight = $clone.height() + lineHeight;
+					var overflow = 'hidden';
+					var height = cloneHeight;
+					if (cloneHeight > maxheight) {
+						height = maxheight;
+						overflow = 'auto';
+					} else if (cloneHeight < minheight) {
+						height = minheight;
+					}
+					if ($textarea.height() !== height) {
+						$textarea.css({'overflow': overflow, 'height': height + 'px'});
+					}
+				}
+
+				// Update textarea size on keyup, change, cut and paste
+				$textarea.bind('keyup change cut paste', function(){
+					updateHeight();
+				});
+
+				// Update textarea on window resize
+				$(window).bind('resize', function (){
+					var cleanWidth = parseInt($textarea.width(), 10);
+					if ($clone.width() !== cleanWidth) {
+						$clone.css({'width': cleanWidth + 'px'});
+						updateHeight();
+					}
+				});
+
+				// Update textarea on blur
+				$textarea.bind('blur',function(){
+					setHeightAndOverflow()
+				});
+
+				// Update textarea when needed
+				$textarea.bind('updateHeight', function(){
+					updateHeight();
+				});
+
+				// Wait until DOM is ready to fix IE7+ stupid bug
+				$(function(){
+					updateHeight();
+				});
+				
+			});
+			
+		}
+	};
+
+	$.fn.flexible = function(method) {
+
+		// Method calling logic
+		if (methods[method]) {
+			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+		} else if (typeof method === 'object' || ! method) {
+			return methods.init.apply(this, arguments);
+		} else {
+			$.error('Method ' + method + ' does not exist on jQuery.easyModal');
+		}
+
+	};
+
+})(jQuery);

Some files were not shown because too many files changed in this diff