Browse Source

AMBARI-1258. Display host check status results given by the agent as part of host registration. (yusaku)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1438325 13f79535-47bb-0310-9956-ffa450edef68
Yusaku Sako 12 years ago
parent
commit
6622212140

+ 3 - 0
CHANGES.txt

@@ -12,6 +12,9 @@ Trunk (unreleased changes):
 
  NEW FEATURES
 
+ AMBARI-1180. Display host check status results given by the agent as part
+ of host registration. (yusaku)
+
  AMBARI-1252. Fetch Nagios alerts through Ambari Server and not directly
  from Nagios Server. (srimanth via yusaku)
 

+ 512 - 0
ambari-web/app/assets/data/wizard/bootstrap/two_hosts_information.json

@@ -0,0 +1,512 @@
+{
+  "href" : "http://ec2-107-20-107-224.compute-1.amazonaws.com:8080/api/v1/hosts?fields=*",
+  "items" : [
+    {
+      "href" : "http://ec2-107-20-107-224.compute-1.amazonaws.com:8080/api/v1/hosts/ip-10-190-153-220.ec2.internal",
+      "Hosts" : {
+        "host_status" : "HEALTHY",
+        "public_host_name" : "ec2-50-19-188-43.compute-1.amazonaws.com",
+        "cpu_count" : 2,
+        "rack_info" : "/default-rack",
+        "host_health_report" : "",
+        "os_arch" : "x86_64",
+        "host_name" : "ip-10-190-153-220.ec2.internal",
+        "disk_info" : [
+          {
+            "available" : "3822572",
+            "used" : "2022188",
+            "percent" : "35%",
+            "size" : "5904748",
+            "type" : "ext3",
+            "mountpoint" : "/"
+          },
+          {
+            "available" : "3932160",
+            "used" : "0",
+            "percent" : "0%",
+            "size" : "3932160",
+            "type" : "tmpfs",
+            "mountpoint" : "/dev/shm"
+          },
+          {
+            "available" : "411234588",
+            "used" : "203012",
+            "percent" : "1%",
+            "size" : "433455904",
+            "type" : "ext3",
+            "mountpoint" : "/grid/0"
+          },
+          {
+            "available" : "411234588",
+            "used" : "203012",
+            "percent" : "1%",
+            "size" : "433455904",
+            "type" : "ext3",
+            "mountpoint" : "/grid/1"
+          }
+        ],
+        "ip" : "10.190.153.220",
+        "os_type" : "redhat5",
+        "last_heartbeat_time" : 1358871154566,
+        "host_state" : "HEALTHY",
+        "last_agent_env" : {
+          "paths" : [
+            {
+              "name" : "/etc/hadoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/hadoop/conf",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/hbase",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/hcatalog",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/hive",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/oozie",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/sqoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/ganglia",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/nagios",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/hadoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/zookeeper",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/hbase",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/templeton",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/oozie",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/hadoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/zookeeper",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/hbase",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/templeton",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/hive",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/nagios",
+              "type" : "not_exist"
+            }
+          ],
+          "javaProcs" : [ ],
+          "rpms" : [
+            {
+              "name" : "yum",
+              "installed" : true,
+              "version" : "yum-3.2.22-39.el5"
+            },
+            {
+              "name" : "rpm",
+              "installed" : true,
+              "version" : "rpm-4.4.2.3-27.el5"
+            },
+            {
+              "name" : "openssl",
+              "installed" : true,
+              "version" : "openssl-0.9.8e-22.el5\nopenssl-0.9.8e-22.el5"
+            },
+            {
+              "name" : "curl",
+              "installed" : true,
+              "version" : "curl-7.15.5-15.el5\ncurl-7.15.5-15.el5"
+            },
+            {
+              "name" : "wget",
+              "installed" : false
+            },
+            {
+              "name" : "net-snmp",
+              "installed" : true,
+              "version" : "net-snmp-5.3.2.2-17.el5"
+            },
+            {
+              "name" : "ntpd",
+              "installed" : false
+            },
+            {
+              "name" : "ruby",
+              "installed" : true,
+              "version" : "ruby-1.8.5-24.el5"
+            },
+            {
+              "name" : "puppet",
+              "installed" : false
+            },
+            {
+              "name" : "nagios",
+              "installed" : false
+            },
+            {
+              "name" : "ganglia",
+              "installed" : false
+            },
+            {
+              "name" : "passenger",
+              "installed" : false
+            },
+            {
+              "name" : "hadoop",
+              "installed" : false
+            },
+            {
+              "name" : "hbase",
+              "installed" : false
+            },
+            {
+              "name" : "oozie",
+              "installed" : false
+            },
+            {
+              "name" : "sqoop",
+              "installed" : false
+            },
+            {
+              "name" : "pig",
+              "installed" : false
+            },
+            {
+              "name" : "zookeeper",
+              "installed" : false
+            },
+            {
+              "name" : "hive",
+              "installed" : false
+            },
+            {
+              "name" : "libconfuse",
+              "installed" : false
+            },
+            {
+              "name" : "postgresql",
+              "installed" : true,
+              "version" : "postgresql-8.1.23-1.el5_7.3"
+            },
+            {
+              "name" : "httpd",
+              "installed" : true,
+              "version" : "httpd-2.2.3-63.el5"
+            },
+            {
+              "name" : "apache2",
+              "installed" : false
+            },
+            {
+              "name" : "http-server",
+              "installed" : false
+            }
+          ],
+          "varRunHadoopPidCount" : 0,
+          "varLogHadoopLogCount" : 0,
+          "etcAlternativesConf" : [ ],
+          "repoInfo" : "Loaded plugins: amazon-id, fastestmirror, rhui-lb, security\nrepo id                             repo name                             status\nAMBARI.dev-1.x                      Ambari 1.x                                6\nHDP-UTILS-1.1.0.15                  Hortonworks Data Platform Utils Versi    51\nepel                                Extra Packages for Enterprise Linux 5  7243\nrhui-us-east-client-config-server-5 Red Hat Update Infrastructure 2.0 Cli     1\nrhui-us-east-rhel-server            Red Hat Enterprise Linux Server 5 (RP 14819\nrepolist: 22120\n"
+        },
+        "last_registration_time" : 1358871040696,
+        "total_mem" : 7864320
+      }
+    },
+    {
+      "href" : "http://ec2-107-20-107-224.compute-1.amazonaws.com:8080/api/v1/hosts/domU-12-31-39-14-04-91.compute-1.internal",
+      "Hosts" : {
+        "host_status" : "HEALTHY",
+        "public_host_name" : "ec2-107-20-107-224.compute-1.amazonaws.com",
+        "cpu_count" : 2,
+        "rack_info" : "/default-rack",
+        "host_health_report" : "",
+        "os_arch" : "x86_64",
+        "host_name" : "domU-12-31-39-14-04-91.compute-1.internal",
+        "disk_info" : [
+          {
+            "available" : "3400492",
+            "used" : "2444268",
+            "percent" : "42%",
+            "size" : "5904748",
+            "type" : "ext3",
+            "mountpoint" : "/"
+          },
+          {
+            "available" : "3932160",
+            "used" : "0",
+            "percent" : "0%",
+            "size" : "3932160",
+            "type" : "tmpfs",
+            "mountpoint" : "/dev/shm"
+          },
+          {
+            "available" : "411234588",
+            "used" : "203012",
+            "percent" : "1%",
+            "size" : "433455904",
+            "type" : "ext3",
+            "mountpoint" : "/grid/0"
+          },
+          {
+            "available" : "411234588",
+            "used" : "203012",
+            "percent" : "1%",
+            "size" : "433455904",
+            "type" : "ext3",
+            "mountpoint" : "/grid/1"
+          }
+        ],
+        "ip" : "10.206.7.95",
+        "os_type" : "redhat5",
+        "last_heartbeat_time" : 1358871154070,
+        "host_state" : "HEALTHY",
+        "last_agent_env" : {
+          "paths" : [
+            {
+              "name" : "/etc/hadoop",
+              "type" : "directory"
+            },
+            {
+              "name" : "/etc/hadoop/conf",
+              "type" : "file"
+            },
+            {
+              "name" : "/etc/hbase",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/hcatalog",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/hive",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/oozie",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/sqoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/ganglia",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/etc/nagios",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/hadoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/zookeeper",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/hbase",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/templeton",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/oozie",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/hadoop",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/zookeeper",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/hbase",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/run/templeton",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/hive",
+              "type" : "not_exist"
+            },
+            {
+              "name" : "/var/log/nagios",
+              "type" : "not_exist"
+            }
+          ],
+          "javaProcs" : [
+            {
+              "user" : "root",
+              "pid" : 2283,
+              "command" : "/bin/sh -c /usr/jdk64/jdk1.6.0_31/bin/java -server -XX:NewRatio=2 -XX:+UseConcMarkSweepGC -Xms512m -Xmx2048m -cp /etc/ambari-server/conf:/usr/lib/ambari-server/*:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/lib/ambari-server/* org.apache.ambari.server.controller.AmbariServer >/var/log/ambari-server/ambari-server.out 2>&1",
+              "hadoop" : true
+            },
+            {
+              "user" : "root",
+              "pid" : 2284,
+              "command" : "/usr/jdk64/jdk1.6.0_31/bin/java -server -XX:NewRatio=2 -XX:+UseConcMarkSweepGC -Xms512m -Xmx2048m -cp /etc/ambari-server/conf:/usr/lib/ambari-server/*:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/lib/ambari-server/* org.apache.ambari.server.controller.AmbariServer",
+              "hadoop" : false
+            }
+          ],
+          "rpms" : [
+            {
+              "name" : "yum",
+              "installed" : true,
+              "version" : "yum-3.2.22-39.el5"
+            },
+            {
+              "name" : "rpm",
+              "installed" : true,
+              "version" : "rpm-4.4.2.3-27.el5"
+            },
+            {
+              "name" : "openssl",
+              "installed" : true,
+              "version" : "openssl-0.9.8e-22.el5\nopenssl-0.9.8e-22.el5"
+            },
+            {
+              "name" : "curl",
+              "installed" : true,
+              "version" : "curl-7.15.5-15.el5\ncurl-7.15.5-15.el5"
+            },
+            {
+              "name" : "wget",
+              "installed" : false
+            },
+            {
+              "name" : "net-snmp",
+              "installed" : true,
+              "version" : "net-snmp-5.3.2.2-17.el5"
+            },
+            {
+              "name" : "ntpd",
+              "installed" : false
+            },
+            {
+              "name" : "ruby",
+              "installed" : true,
+              "version" : "ruby-1.8.5-24.el5"
+            },
+            {
+              "name" : "puppet",
+              "installed" : false
+            },
+            {
+              "name" : "nagios",
+              "installed" : false
+            },
+            {
+              "name" : "ganglia",
+              "installed" : false
+            },
+            {
+              "name" : "passenger",
+              "installed" : false
+            },
+            {
+              "name" : "hadoop",
+              "installed" : false
+            },
+            {
+              "name" : "hbase",
+              "installed" : false
+            },
+            {
+              "name" : "oozie",
+              "installed" : false
+            },
+            {
+              "name" : "sqoop",
+              "installed" : false
+            },
+            {
+              "name" : "pig",
+              "installed" : false
+            },
+            {
+              "name" : "zookeeper",
+              "installed" : false
+            },
+            {
+              "name" : "hive",
+              "installed" : false
+            },
+            {
+              "name" : "libconfuse",
+              "installed" : false
+            },
+            {
+              "name" : "postgresql",
+              "installed" : true,
+              "version" : "postgresql-8.1.23-6.el5_8"
+            },
+            {
+              "name" : "httpd",
+              "installed" : true,
+              "version" : "httpd-2.2.3-63.el5"
+            },
+            {
+              "name" : "apache2",
+              "installed" : false
+            },
+            {
+              "name" : "http-server",
+              "installed" : false
+            }
+          ],
+          "varRunHadoopPidCount" : 0,
+          "varLogHadoopLogCount" : 0,
+          "etcAlternativesConf" : [ ],
+          "repoInfo" : "Loaded plugins: amazon-id, fastestmirror, rhui-lb, security\nrepo id                             repo name                             status\nAMBARI.dev-1.x                      Ambari 1.x                                6\nHDP-UTILS-1.1.0.15                  Hortonworks Data Platform Utils Versi    51\nepel                                Extra Packages for Enterprise Linux 5  7243\nrhui-us-east-client-config-server-5 Red Hat Update Infrastructure 2.0 Cli     1\nrhui-us-east-rhel-server            Red Hat Enterprise Linux Server 5 (RP 14819\nrepolist: 22120\n"
+        },
+        "last_registration_time" : 1358870784262,
+        "total_mem" : 7864320
+      }
+    }
+  ]
+}

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

@@ -99,6 +99,9 @@ App.WizardStep3Controller = Em.Controller.extend({
 
   navigateStep: function () {
     this.loadStep();
+    if(App.testMode){
+      this.getHostInfo();
+    }
     if (this.get('content.installOptions.manualInstall') !== true) {
       if (!App.db.getBootStatus()) {
         this.startBootstrap();
@@ -109,7 +112,6 @@ App.WizardStep3Controller = Em.Controller.extend({
         this.get('bootHosts').setEach('bootStatus', 'REGISTERED');
         this.get('bootHosts').setEach('cpu', '2');
         this.get('bootHosts').setEach('memory', '2000000');
-        this.getHostInfo();
       } else {
         this.set('registrationStartedAt', null);
         this.get('bootHosts').setEach('bootStatus', 'DONE');
@@ -479,7 +481,7 @@ App.WizardStep3Controller = Em.Controller.extend({
     var self = this;
     var kbPerGb = 1024;
     var hosts = this.get('bootHosts');
-    var url = App.testMode ? '/data/wizard/bootstrap/single_host_information.json' : App.apiPrefix + '/hosts?fields=Hosts/total_mem,Hosts/cpu_count,Hosts/disk_info';
+    var url = App.testMode ? '/data/wizard/bootstrap/two_hosts_information.json' : App.apiPrefix + '/hosts?fields=Hosts/total_mem,Hosts/cpu_count,Hosts/disk_info,Hosts/last_agent_env';
     var method = 'GET';
     $.ajax({
       type: 'GET',
@@ -488,6 +490,7 @@ App.WizardStep3Controller = Em.Controller.extend({
       timeout: App.timeout,
       success: function (data) {
         var jsonData = (App.testMode) ? data : jQuery.parseJSON(data);
+        self.parseWarnings(jsonData);
         hosts.forEach(function (_host) {
           var host = (App.testMode) ? jsonData.items[0] : jsonData.items.findProperty('Hosts.host_name', _host.name);
           if (App.skipBootstrap) {
@@ -586,6 +589,308 @@ App.WizardStep3Controller = Em.Controller.extend({
       })
     });
   },
+  /**
+   * check warnings from server and put it in parsing
+    */
+  rerunChecks: function(){
+    var self = this;
+    var url = App.testMode ? '/data/wizard/bootstrap/two_hosts_information.json' : App.apiPrefix + '/hosts?fields=Hosts/last_agent_env';
+    var currentProgress = 0;
+    var interval = setInterval(function(){
+      self.set('checksUpdateProgress', Math.ceil((++currentProgress/60)*100))
+    }, 1000);
+    setTimeout(function(){
+      clearInterval(interval);
+      $.ajax({
+        type: 'GET',
+        url: url,
+        contentType: 'application/json',
+        timeout: App.timeout,
+        success: function (data) {
+          var jsonData = (App.testMode) ? data : jQuery.parseJSON(data);
+          self.set('checksUpdateProgress', 100);
+          self.set('checksUpdateStatus', 'SUCCESS');
+          self.parseWarnings(jsonData);
+        },
+        error: function () {
+          self.set('checksUpdateProgress', 100);
+          self.set('checksUpdateStatus', 'FAILED');
+          console.log('INFO: Getting host information(last_agent_env) from the server failed');
+        },
+        statusCode: require('data/statusCodes')
+      })
+    }, this.get('warningsTimeInterval'));
+
+  },
+  warnings: [],
+  warningsTimeInterval: 60000,
+  /**
+   * check are hosts have any warnings
+   */
+  isHostHaveWarnings: function(){
+    var isWarning = false;
+    this.get('warnings').forEach(function(warning){
+      if(!isWarning && (warning.directoriesFiles.someProperty('isWarn', true) ||
+      warning.packages.someProperty('isWarn', true) ||
+      warning.processes.someProperty('isWarn', true))){
+        isWarning = true;
+      }
+    }, this);
+    return isWarning;
+  }.property('warnings'),
+  isWarningsBoxVisible: function(){
+    return (App.testMode) ? true : !this.get('isSubmitDisabled');
+  }.property('isSubmitDisabled'),
+  checksUpdateProgress:0,
+  checksUpdateStatus: null,
+  /**
+   * parse warnings data for each host and total
+   * @param data
+   */
+  parseWarnings: function(data){
+    var warnings = [];
+    var totalWarnings = {
+      hostName: 'All Hosts',
+      directoriesFiles: [],
+      packages: [],
+      processes: []
+    }
+    //alphabetical sorting
+    var sortingFunc = function(a, b){
+      var a1= a.name, b1= b.name;
+      if(a1== b1) return 0;
+      return a1> b1? 1: -1;
+    }
+    data.items.forEach(function(host){
+      var warningsByHost = {
+        hostName: host.Hosts.host_name,
+        directoriesFiles: [],
+        packages: [],
+        processes: []
+      };
+
+      //render all directories and files for each host
+      host.Hosts.last_agent_env.paths.forEach(function(path){
+        var parsedPath = {
+          name: path.name,
+          isWarn: (path.type == 'not_exist') ? false : true,
+          message: (path.type == 'not_exist') ? 'OK' : 'WARN: already exists on host'
+        }
+        warningsByHost.directoriesFiles.push(parsedPath);
+        // parsing total warnings
+        if(!totalWarnings.directoriesFiles.someProperty('name', parsedPath.name)){
+          totalWarnings.directoriesFiles.push({
+            name:parsedPath.name,
+            isWarn: parsedPath.isWarn,
+            message: (parsedPath.isWarn) ? 'WARN: already exists on 1 host': 'OK',
+            warnCount: (parsedPath.isWarn) ? 1 : 0
+          })
+        } else if(parsedPath.isWarn){
+            totalWarnings.directoriesFiles.forEach(function(item, index){
+              if(item.name == parsedPath.name){
+                totalWarnings.directoriesFiles[index].isWarn = true;
+                totalWarnings.directoriesFiles[index].warnCount++;
+                totalWarnings.directoriesFiles[index].message = 'WARN: already exists on '+ totalWarnings.directoriesFiles[index].warnCount +' hosts';
+              }
+            });
+        }
+      }, this);
+
+      //render all packages for each host
+      host.Hosts.last_agent_env.rpms.forEach(function(_package){
+        var parsedPackage = {
+          name: _package.name,
+          isWarn: _package.installed,
+          message: (_package.installed) ? 'WARN: already installed on host' : 'OK'
+        }
+        warningsByHost.packages.push(parsedPackage);
+        // parsing total warnings
+        if(!totalWarnings.packages.someProperty('name', parsedPackage.name)){
+          totalWarnings.packages.push({
+            name:parsedPackage.name,
+            isWarn: parsedPackage.isWarn,
+            message: (parsedPackage.isWarn) ? 'WARN: already exists on 1 host': 'OK',
+            warnCount: (parsedPackage.isWarn) ? 1 : 0
+          })
+        } else if(parsedPackage.isWarn){
+          totalWarnings.packages.forEach(function(item, index){
+            if(item.name == parsedPackage.name){
+              totalWarnings.packages[index].isWarn = true;
+              totalWarnings.packages[index].warnCount++;
+              totalWarnings.packages[index].message = 'WARN: already exists on '+ totalWarnings.packages[index].warnCount +' hosts';
+            }
+          });
+        }
+      }, this);
+
+      // render all process for each host
+      host.Hosts.last_agent_env.javaProcs.forEach(function(process){
+          var parsedProcess = {
+            user: process.user,
+            isWarn: process.hadoop,
+            pid: process.pid,
+            command: process.command,
+            shortCommand: (process.command.substr(0, 15)+'...'),
+            message: (process.hadoop) ? 'WARN: running on host' : 'OK'
+          }
+          warningsByHost.processes.push(parsedProcess);
+          // parsing total warnings
+          if(!totalWarnings.processes.someProperty('pid', parsedProcess.name)){
+            totalWarnings.processes.push({
+              user: process.user,
+              pid: process.pid,
+              command: process.command,
+              shortCommand: (process.command.substr(0, 15)+'...'),
+              isWarn: parsedProcess.isWarn,
+              message: (parsedProcess.isWarn) ? 'WARN: running on 1 host': 'OK',
+              warnCount: (parsedProcess.isWarn) ? 1 : 0
+            })
+          } else if(parsedProcess.isWarn){
+            totalWarnings.processes.forEach(function(item, index){
+              if(item.pid == parsedProcess.pid){
+                totalWarnings.processes[index].isWarn = true;
+                totalWarnings.processes[index].warnCount++;
+                totalWarnings.processes[index].message = 'WARN: running on '+ totalWarnings.processes[index].warnCount +' hosts';
+              }
+            });
+          }
+      }, this);
+      warningsByHost.directoriesFiles.sort(sortingFunc);
+      warningsByHost.packages.sort(sortingFunc);
+      warnings.push(warningsByHost);
+    }, this);
+
+    totalWarnings.directoriesFiles.sort(sortingFunc);
+    totalWarnings.packages.sort(sortingFunc);
+    warnings.unshift(totalWarnings);
+    this.set('warnings', warnings);
+  },
+  /**
+   * open popup that contain hosts' warnings
+   * @param event
+   */
+  hostWarningsPopup: function(event){
+    var self = this;
+    App.ModalPopup.show({
+
+      header: Em.I18n.t('installer.step3.warnings.popup.header'),
+      secondary: 'Rerun Checks',
+      primary: 'Close',
+      onPrimary: function () {
+        self.set('checksUpdateStatus', null);
+        this.hide();
+      },
+      onClose: function(){
+        self.set('checksUpdateStatus', null);
+        this.hide();
+      },
+      onSecondary: function() {
+        self.rerunChecks();
+      },
+
+      footerClass: Ember.View.extend({
+        template: Ember.Handlebars.compile([
+          '<div class="update-progress pull-left">',
+          '{{#if view.isUpdateInProgress}}',
+          '<div class="progress-info active progress">',
+          '<div class="bar" {{bindAttr style="view.progressWidth"}}></div></div>',
+          '{{else}}<label {{bindAttr class="view.updateStatusClass"}}>{{view.updateStatus}}</label>',
+          '{{/if}}</div>',
+          '{{#if view.parentView.secondary}}<button type="button" class="btn btn-info" {{bindAttr disabled="view.isUpdateInProgress"}} {{action onSecondary target="view.parentView"}}><i class="icon-repeat"></i>&nbsp;{{view.parentView.secondary}}</button>{{/if}}',
+          '{{#if view.parentView.primary}}<button type="button" class="btn" {{action onPrimary target="view.parentView"}}>{{view.parentView.primary}}</button>{{/if}}'
+        ].join('')),
+        classNames: ['modal-footer', 'host-checks-update'],
+        progressWidth: function(){
+          return 'width:'+App.router.get('wizardStep3Controller.checksUpdateProgress')+'%';
+        }.property('App.router.wizardStep3Controller.checksUpdateProgress'),
+        isUpdateInProgress: function(){
+          if((App.router.get('wizardStep3Controller.checksUpdateProgress') > 0) &&
+             (App.router.get('wizardStep3Controller.checksUpdateProgress') < 100)){
+            return true;
+          }
+        }.property('App.router.wizardStep3Controller.checksUpdateProgress'),
+        updateStatusClass:function(){
+          var status = App.router.get('wizardStep3Controller.checksUpdateStatus');
+          if(status === 'SUCCESS'){
+            return 'text-success';
+          } else if(status === 'FAILED'){
+            return 'text-error';
+          } else {
+            return null;
+          }
+        }.property('App.router.wizardStep3Controller.checksUpdateStatus'),
+        updateStatus:function(){
+          var status = App.router.get('wizardStep3Controller.checksUpdateStatus');
+          if(status === 'SUCCESS'){
+            return Em.I18n.t('installer.step3.warnings.updateChecks.success');
+          } else if(status === 'FAILED'){
+            return Em.I18n.t('installer.step3.warnings.updateChecks.failed');
+          } else {
+            return null;
+          }
+        }.property('App.router.wizardStep3Controller.checksUpdateStatus')
+      }),
+
+      bodyClass: Ember.View.extend({
+        templateName: require('templates/wizard/step3_host_warnings_popup'),
+        warnings: function(){
+          return App.router.get('wizardStep3Controller.warnings');
+        }.property('App.router.wizardStep3Controller.warnings'),
+        categories: function(){
+          var categories = this.get('warnings').getEach('hostName');
+          return categories;
+        }.property('warnings'),
+        category: 'All Hosts',
+        content: function(){
+          return this.get('warnings').findProperty('hostName', this.get('category'));
+        }.property('category', 'warnings'),
+        /**
+         * generate detailed content to show it in new window
+         */
+        contentInDetails: function(){
+          var content = this.get('content');
+          var newContent = '';
+          if(content.hostName == 'All Hosts'){
+            newContent += '<h4>Warnings across all hosts</h4>';
+          } else {
+            newContent += '<h4>Warnings on ' + content.hostName + '</h4>';
+          }
+          newContent += '<div>DIRECTORIES AND FILES</div><div>';
+          content.directoriesFiles.filterProperty('isWarn', true).forEach(function(path){
+              newContent += path.name + '&nbsp;'
+          });
+          if(content.directoriesFiles.filterProperty('isWarn', true).length == 0){
+            newContent += 'No warnings';
+          }
+          newContent += '</div><br/><div>PACKAGES</div><div>';
+          content.packages.filterProperty('isWarn', true).forEach(function(_package){
+              newContent += _package.name + '&nbsp;'
+          });
+          if(content.packages.filterProperty('isWarn', true).length == 0){
+            newContent += 'No warnings';
+          }
+          newContent += '</div><br/><div>PROCESSES</div><div>';
+          content.processes.filterProperty('isWarn', true).forEach(function(process, index){
+              newContent += '(' + content.hostName + ',' + process.pid + ',' + process.user + ')';
+              newContent += (index != (content.processes.filterProperty('isWarn', true).length-1)) ? ',' : '';
+          })
+          if(content.processes.filterProperty('isWarn', true).length == 0){
+            newContent += 'No warnings';
+          }
+          return newContent;
+        }.property('content'),
+        /**
+         * open new browser tab with detailed content
+         */
+        openWarningsInDialog: function(){
+          var newWindow = window.open('', this.get('category')+' warnings');
+          var newDocument = newWindow.document;
+          newDocument.write(this.get('contentInDetails'));
+          newWindow.focus();
+        }
+      })
+    })
+  },
 
   // TODO: dummy button. Remove this after the hook up with actual REST API.
   mockBtn: function () {

+ 6 - 0
ambari-web/app/messages.js

@@ -122,6 +122,12 @@ Em.I18n.translations = {
   'installer.step3.hostInformation.popup.header':'Error in retrieving host Information',
   'installer.step3.hostInformation.popup.body' : 'All bootstrapped hosts registered but unable to retrieve cpu and memory related information',
   'installer.step3.hosts.noHosts':'No hosts to display',
+  'installer.step3.warnings.popup.header':'Host Checks',
+  'installer.step3.warnings.description':'Some warnings were encountered while performing checks against the above hosts.',
+  'installer.step3.warnings.linkText':'Click here to see the warnings.',
+  'installer.step3.warnings.noWarnings':'All host checks were successful.',
+  'installer.step3.warnings.updateChecks.success':'Host Checks successfully updated',
+  'installer.step3.warnings.updateChecks.failed':'Host Checks update failed',
 
   'installer.step4.header':'Choose Services',
   'installer.step4.body':'Choose which services you want to install on your cluster.',

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

@@ -1414,6 +1414,38 @@ a:focus {
   }
 }
 
+#host-warnings {
+  .warnings-list{
+    table {
+      margin-bottom: 0;
+      margin-top: 5px;
+      td {
+        width: 50%;
+        i {
+          font-size:16px;
+          margin: 2px;
+        }
+      }
+    }
+    .category-title {
+      padding: 3px;
+      text-align: left;
+      background-color: rgb(196, 193, 193);
+    }
+  }
+}
+.host-checks-update {
+  button {
+    margin-left: 5px;
+  }
+  .update-progress {
+    width: 230px;
+    .progress {
+      margin-bottom: 0;
+    }
+  }
+}
+
 #host-details {
 
   margin-top: 27px;

+ 12 - 0
ambari-web/app/templates/wizard/step3.hbs

@@ -124,6 +124,18 @@
       </div>
     </div>
   </div>
+    {{#if isWarningsBoxVisible}}
+      {{#if isHostHaveWarnings}}
+      <div class="alert alert-warn">
+        {{t installer.step3.warnings.description}}<br>
+        <a href="javascript:void(0)" {{action hostWarningsPopup warnings target="controller"}}>{{t installer.step3.warnings.linkText}}</a>
+      </div>
+      {{else}}
+      <div class="alert alert-success">
+        {{t installer.step3.warnings.noWarnings}}
+      </div>
+      {{/if}}
+    {{/if}}
   <div class="btn-area">
     <a class="btn pull-left" {{bindAttr disabled="isInstallInProgress"}} {{action back}}>&larr; Back</a>
     <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action submit target="controller"}}>Next &rarr;</a>

+ 112 - 0
ambari-web/app/templates/wizard/step3_host_warnings_popup.hbs

@@ -0,0 +1,112 @@
+{{!
+* 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="host-warnings">
+    <div class="row-fluid">
+            <div class="span6">
+              {{view Ember.Select
+              contentBinding="view.categories"
+              selectionBinding="view.category"
+              }}
+            </div>
+        <div class="span3 offset3">
+            <a href="javascript.void(0)" title="Show Details" {{action openWarningsInDialog target="view"}} class="task-detail-open-dialog"><i class="icon-external-link"></i> Show Details</a>
+        </div>
+    </div>
+    <div class="content-area">
+          <div class="warnings-list">
+              <table class="table">
+                  <thead>
+                  <tr>
+                      <th class="category-title" colspan="2">DIRECTORIES & FILES</th>
+                  </tr>
+                  </thead>
+                  <tbody>
+                  {{#each path in view.content.directoriesFiles}}
+                  <tr>
+                      <td>{{path.name}}</td>
+                      <td>
+                        <span>
+                        {{#if path.isWarn}}
+                          <i class="icon-warning-sign"></i>
+                        {{else}}
+                          <i class="icon-ok"></i>
+                        {{/if}}
+                        {{path.message}}
+                        </span>
+                      </td>
+                  </tr>
+                  {{/each}}
+                  </tbody>
+              </table>
+              <table class="table">
+                  <thead>
+                  <tr>
+                      <th class="category-title" colspan="2">PACKAGES</th>
+                  </tr>
+                  </thead>
+                  <tbody>
+                    {{#each package in view.content.packages}}
+                    <tr>
+                        <td>{{package.name}}</td>
+                        <td>
+                          <span>
+                          {{#if package.isWarn}}
+                            <i class="icon-warning-sign"></i>
+                          {{else}}
+                            <i class="icon-ok"></i>
+                          {{/if}}
+                          {{package.message}}
+                          </span>
+                        </td>
+                    </tr>
+                    {{/each}}
+                  </tbody>
+              </table>
+              <table class="table">
+                  <thead>
+                  <tr>
+                      <th class="category-title" colspan="2">PROCESSES</th>
+                  </tr>
+                  </thead>
+                  <tbody>
+                  {{#if view.content.processes.length}}
+                    {{#each process in view.content.processes}}
+                    <tr>
+                        <td {{bindAttr title="process.command"}}>{{process.shortCommand}}}</td>
+                        <td>
+                          <span>
+                          {{#if process.isWarn}}
+                            <i class="icon-warning-sign"></i>
+                          {{else}}
+                            <i class="icon-ok"></i>
+                          {{/if}}
+                          {{process.message}}
+                          </span>
+                        </td>
+                    </tr>
+                    {{/each}}
+                  {{else}}
+                  <tr><td colspan="2">No processes to display</td></tr>
+                  {{/if}}
+                  </tbody>
+              </table>
+          </div>
+    </div>
+</div>

+ 4 - 0
ambari-web/app/views/common/modal_popup.js

@@ -34,11 +34,15 @@ App.ModalPopup = Ember.View.extend({
     '{{else}}{{#if encodeBody}}{{body}}{{else}}{{{body}}}{{/if}}{{/if}}',
     '</div>',
     '{{#if showFooter}}',
+    '{{#if footerClass}}{{view footerClass}}',
+    '{{else}}',
     '<div class="modal-footer">',
     '{{#if view.secondary}}<a class="btn" {{action onSecondary target="view"}}>{{view.secondary}}</a>{{/if}}',
     '{{#if view.primary}}<a class="btn btn-success" {{action onPrimary target="view"}}>{{view.primary}}</a>{{/if}}',
     '</div>',
     '{{/if}}',
+    '{{/if}}',
+
     '</div>'
   ].join('\n')),