You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2014/01/15 13:29:08 UTC

git commit: AMBARI-4296 Integrate updated Alert API to improve performance on Ambari Web. (atkach)

Updated Branches:
  refs/heads/trunk d8d308e6a -> 391f1242c


AMBARI-4296 Integrate updated Alert API to improve performance on Ambari Web. (atkach)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/391f1242
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/391f1242
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/391f1242

Branch: refs/heads/trunk
Commit: 391f1242c836e210f982896a1ffe0afcb13e1105
Parents: d8d308e
Author: atkach <at...@hortonworks.com>
Authored: Wed Jan 15 14:29:02 2014 +0200
Committer: atkach <at...@hortonworks.com>
Committed: Wed Jan 15 14:29:02 2014 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers.js                   |   1 +
 .../controllers/global/cluster_controller.js    |  84 +---------
 .../app/controllers/global/update_controller.js |   6 +-
 .../app/controllers/main/alerts_controller.js   | 158 +++++++++++++++++++
 ambari-web/app/controllers/main/host.js         |  21 +--
 .../controllers/main/service/info/summary.js    |  13 --
 ambari-web/app/initialize.js                    |   1 -
 ambari-web/app/mappers/alerts_mapper.js         | 107 -------------
 ambari-web/app/mappers/hosts_mapper.js          |   7 +-
 ambari-web/app/mappers/service_mapper.js        |   9 +-
 .../app/mappers/service_metrics_mapper.js       |   3 +-
 ambari-web/app/models/alert.js                  |  43 ++---
 ambari-web/app/models/host.js                   |   9 +-
 ambari-web/app/models/service.js                |   2 +-
 .../main/dashboard/alert_notification_popup.hbs |  28 ++--
 .../app/templates/main/host/alerts_popup.hbs    |  18 ++-
 .../app/templates/main/service/info/summary.hbs |  28 ++--
 ambari-web/app/utils/ajax.js                    |   8 +
 ambari-web/app/views/main/dashboard.js          |  20 ++-
 ambari-web/app/views/main/dashboard/service.js  |   4 +-
 ambari-web/app/views/main/menu.js               |   5 +-
 .../app/views/main/service/info/summary.js      |  17 +-
 ambari-web/app/views/main/service/menu.js       |   9 +-
 23 files changed, 278 insertions(+), 323 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index fd894c0..a978646 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -60,6 +60,7 @@ require('controllers/main/admin/security/add/step2');
 require('controllers/main/admin/security/add/step3');
 require('controllers/main/admin/security/add/step4');
 require('controllers/main/admin/authentication');
+require('controllers/main/alerts_controller');
 require('controllers/main/service');
 require('controllers/main/service/item');
 require('controllers/main/service/info/summary');

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index 98f6b68..9236d23 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -57,7 +57,6 @@ App.ClusterController = Em.Controller.extend({
     'cluster':false,
     'clusterStatus':false,
     'racks':false,
-    'alerts':false,
     'users':false,
     'status': false,
     'componentConfigs': false
@@ -192,81 +191,6 @@ App.ClusterController = Em.Controller.extend({
   }.property('App.router.updateController.isUpdated', 'dataLoadList.serviceMetrics'),
 
   /**
-   * Sorted list of alerts.
-   * Changes whenever alerts are loaded.
-   */
-  alerts:[],
-  alertsHostMap: {},
-  alertsServiceMap: {},
-  updateAlerts: function(){
-    var alerts = App.Alert.find().toArray();
-    var alertsHostMap = {};
-    var alertsServiceMap = {};
-    alerts.forEach(function (alert) {
-      if (!alert.get('isOk')) {
-        if (!alert.get('ignoredForHosts')) {
-          if (alertsHostMap[alert.get('hostName')]) {
-            alertsHostMap[alert.get('hostName')]++;
-          } else {
-            alertsHostMap[alert.get('hostName')] = 1;
-          }
-        }
-        if (!alert.get('ignoredForServices')) {
-          if (alertsServiceMap[alert.get('serviceType')]) {
-            alertsServiceMap[alert.get('serviceType')]++;
-          } else {
-            alertsServiceMap[alert.get('serviceType')] = 1;
-          }
-        }
-      }
-    }, this);
-    this.set('alertsHostMap', alertsHostMap);
-    this.set('alertsServiceMap', alertsServiceMap);
-    this.set('alerts', alerts);
-  },
-
-  /**
-   * Load alerts from server
-   * @param callback Slave function, should be called to fire delayed update.
-   * Look at <code>App.updater.run</code> for more information.
-   * Also used to set <code>dataLoadList.alerts</code> status during app loading
-   */
-  loadAlerts:function (callback) {
-    if (this.get('isNagiosInstalled')) {
-      var testUrl = App.get('isHadoop2Stack') ? '/data/alerts/HDP2/alerts.json':'/data/alerts/alerts.json';
-      var dataUrl = this.getUrl(testUrl, '/host_components?fields=HostRoles/nagios_alerts&HostRoles/component_name=NAGIOS_SERVER');
-      var self = this;
-      var ajaxOptions = {
-        dataType:"json",
-        complete:function () {
-          self.updateAlerts();
-          callback();
-        },
-        error: function(jqXHR, testStatus, error) {
-          console.log('Nagios $.ajax() response:', error);
-        }
-      };
-      App.HttpClient.get(dataUrl, App.alertsMapper, ajaxOptions);
-    } else {
-      console.log("No Nagios URL provided.");
-      callback();
-    }
-  },
-
-  /**
-   * Determination of Nagios presence is known only after App.Service is
-   * loaded from server. When that is done, no one tells alerts to load,
-   * due to which alerts are not loaded & shown till the next polling cycle.
-   * This method immediately loads alerts once Nagios presence is known.
-   */
-  isNagiosInstalledListener: function () {
-    var self = this;
-    self.loadAlerts(function () {
-      self.updateLoadStatus('alerts');
-    });
-  }.observes('isNagiosInstalled'),
-
-  /**
    * Send request to server to load components updated statuses
    * @param callback Slave function, should be called to fire delayed update.
    * Look at <code>App.updater.run</code> for more information
@@ -306,7 +230,6 @@ App.ClusterController = Em.Controller.extend({
       return false;
     }
     App.updater.run(this, 'loadUpdatedStatus', 'isWorking', App.componentsUpdateInterval); //update will not run it immediately
-    App.updater.run(this, 'loadAlerts', 'isWorking'); //update will not run it immediately
     return true;
   }.observes('isWorking'),
   /**
@@ -326,8 +249,8 @@ App.ClusterController = Em.Controller.extend({
     var clusterUrl = this.getUrl('/data/clusters/cluster.json', '?fields=Clusters');
     var hostsRealUrl = '/hosts?fields=Hosts/host_name,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,Hosts/total_mem,' +
       'Hosts/host_status,Hosts/last_heartbeat_time,Hosts/os_arch,Hosts/os_type,Hosts/ip,host_components,Hosts/disk_info,' +
-      'metrics/disk,metrics/load/load_one,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free'+
-      '&minimal_response=true';
+      'metrics/disk,metrics/load/load_one,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free,'+
+      'alerts/summary&minimal_response=true';
     var usersUrl = App.testMode ? '/data/users/users.json' : App.apiPrefix + '/users/?fields=*';
     var racksUrl = "/data/racks/racks.json";
 
@@ -392,9 +315,6 @@ App.ClusterController = Em.Controller.extend({
       });
     });
 
-    this.loadAlerts(function(){
-        self.updateLoadStatus('alerts');
-    });
   },
 
   requestHosts: function(realUrl, callback){

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js
index 66bf2d4..ec190be 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -81,8 +81,8 @@ App.UpdateController = Em.Controller.extend({
   updateHost:function(callback) {
     var testUrl = App.get('isHadoop2Stack') ? '/data/hosts/HDP2/hosts.json' : '/data/hosts/hosts.json';
     var hostsUrl = this.getUrl(testUrl, '/hosts?fields=Hosts/host_name,Hosts/host_status,Hosts/last_heartbeat_time,Hosts/disk_info,' +
-      'metrics/disk,metrics/load/load_one,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free'+
-      '&minimal_response=true');
+      'metrics/disk,metrics/load/load_one,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free,'+
+      'alerts/summary&minimal_response=true');
     App.HttpClient.get(hostsUrl, App.hostsMapper, {
       complete: callback
     });
@@ -184,7 +184,7 @@ App.UpdateController = Em.Controller.extend({
   },
   updateServices: function (callback) {
     var testUrl = '/data/services/HDP2/services.json';
-    var componentConfigUrl = this.getUrl(testUrl, '/services?fields=ServiceInfo/state&minimal_response=true');
+    var componentConfigUrl = this.getUrl(testUrl, '/services?fields=alerts/summary,ServiceInfo/state&minimal_response=true');
     App.HttpClient.get(componentConfigUrl, App.serviceMapper, {
       complete: callback
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/controllers/main/alerts_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/alerts_controller.js b/ambari-web/app/controllers/main/alerts_controller.js
new file mode 100644
index 0000000..d599be1
--- /dev/null
+++ b/ambari-web/app/controllers/main/alerts_controller.js
@@ -0,0 +1,158 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.MainAlertsController = Em.Controller.extend({
+  name: 'mainAlertsController',
+
+  alerts: [],
+  isLoaded: false,
+  isUpdating: false,
+  // name of resource(hostName or ServiceName)
+  resourceName: null,
+  //"HOST" or "SERVICE"
+  resourceType: null,
+
+  /**
+   * load alerts for service or host
+   * @param name
+   * @param type
+   */
+  loadAlerts: function (name, type) {
+    this.set('isLoaded', false);
+    this.set('resourceName', name);
+    this.set('resourceType', type);
+    this.getFromServer();
+  },
+  /**
+   * update alerts
+   */
+  update: function () {
+    var self = this;
+    if (this.get('isUpdating')) {
+      setTimeout(function () {
+        self.getFromServer();
+        self.update();
+      }, App.componentsUpdateInterval);
+    }
+  }.observes('isUpdating'),
+
+  /**
+   * ask alerts from server by type
+   */
+  getFromServer: function () {
+    if (App.router.get('clusterController.isNagiosInstalled')) {
+      if (this.get('resourceType') === "SERVICE") {
+        this.getAlertsByService();
+      } else if (this.get('resourceType') === "HOST") {
+        this.getAlertsByHost();
+      } else {
+        console.warn("GET Alerts error: unknown resourceType");
+      }
+    }
+  },
+
+  getAlertsByHost: function () {
+    if (this.get('resourceName')) {
+      App.ajax.send({
+        name: 'alerts.get_by_host',
+        sender: this,
+        data: {
+          hostName: this.get('resourceName')
+        },
+        success: 'getAlertsSuccessCallback',
+        error: 'getAlertsErrorCallback'
+      })
+    } else {
+      console.warn('GET Alerts error: hostName parameter is missing');
+    }
+  },
+
+  getAlertsByService: function () {
+    if (this.get('resourceName')) {
+      App.ajax.send({
+        name: 'alerts.get_by_service',
+        sender: this,
+        data: {
+          serviceName: this.get('resourceName')
+        },
+        success: 'getAlertsSuccessCallback',
+        error: 'getAlertsErrorCallback'
+      })
+    } else {
+      console.warn('GET Alerts error: serviceName parameter is missing');
+    }
+  },
+
+  /**
+   * map to associate old status format with and maintain sorting
+   */
+  statusNumberMap: {
+    "OK" : "0",
+    "WARNING": "1",
+    "CRITICAL": "2"
+  },
+
+  getAlertsSuccessCallback: function (json) {
+    var alerts = [];
+    if (json && json.alerts && json.alerts.detail) {
+      json.alerts.detail.forEach(function (_alert) {
+        alerts.pushObject(App.Alert.create({
+          title: _alert.description,
+          serviceType: _alert.service_name,
+          lastTime: _alert.status_time,
+          status: this.get('statusNumberMap')[_alert.status] || "3",
+          message: _alert.output,
+          hostName: _alert.host_name,
+          lastCheck: _alert.last_status_time
+        }));
+      }, this);
+    }
+    this.set('alerts', this.sortAlerts(alerts));
+    this.set('isLoaded', true);
+  },
+  /**
+   * alerts sorting
+   * firstly by status
+   * 1. UNKNOWN
+   * 2. CRITICAL
+   * 3. WARNING
+   * 4. OK
+   * secondly by date
+   * @param array
+   * @return {*}
+   */
+  sortAlerts: function (array) {
+    return array.sort(function (left, right) {
+      var statusDiff = right.get('status') - left.get('status');
+      if (statusDiff == 0) { // same error severity - sort by time
+        var rightTime = right.get('date');
+        var leftTime = left.get('date');
+        rightTime = rightTime ? rightTime.getTime() : 0;
+        leftTime = leftTime ? leftTime.getTime() : 0;
+        statusDiff = rightTime - leftTime;
+      }
+      return statusDiff;
+    });
+  },
+
+  getAlertsErrorCallback: function(){
+    this.set('isLoaded', true);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/controllers/main/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host.js b/ambari-web/app/controllers/main/host.js
index 8b094c6..bca67a4 100644
--- a/ambari-web/app/controllers/main/host.js
+++ b/ambari-web/app/controllers/main/host.js
@@ -26,10 +26,6 @@ App.MainHostController = Em.ArrayController.extend({
 
   clearFilters: null,
 
-  alerts: function () {
-    return App.router.get('clusterController.alerts').filterProperty('isOk', false).filterProperty('ignoredForHosts', false);
-  }.property('App.router.clusterController.alerts.length'),
-
   /**
    * Components which will be shown in component filter
    * @returns {Array}
@@ -94,22 +90,19 @@ App.MainHostController = Em.ArrayController.extend({
 
   showAlertsPopup: function (event) {
     var host = event.context;
+    App.router.get('mainAlertsController').loadAlerts(host.get('hostName'), "HOST");
     App.ModalPopup.show({
       header: this.t('services.alerts.headingOfList'),
       bodyClass: Ember.View.extend({
-        hostAlerts: function () {
-          var allAlerts = App.router.get('clusterController.alerts').filterProperty('ignoredForHosts', false);
-          if (host) {
-            return App.Alert.sort(allAlerts.filterProperty('hostName', host.get('hostName')));
-          }
-          return 0;
-        }.property('App.router.clusterController.alerts'),
+        templateName: require('templates/main/host/alerts_popup'),
+        controllerBinding: 'App.router.mainAlertsController',
+        alerts: function () {
+          return this.get('controller.alerts');
+        }.property('controller.alerts'),
 
         closePopup: function () {
           this.get('parentView').hide();
-        },
-
-        templateName: require('templates/main/host/alerts_popup')
+        }
       }),
       primary: Em.I18n.t('common.close'),
       secondary : null,

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/controllers/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/summary.js b/ambari-web/app/controllers/main/service/info/summary.js
index 530a427..0fb5a01 100644
--- a/ambari-web/app/controllers/main/service/info/summary.js
+++ b/ambari-web/app/controllers/main/service/info/summary.js
@@ -19,20 +19,7 @@ var App = require('app');
 
 App.MainServiceInfoSummaryController = Em.Controller.extend({
   name: 'mainServiceInfoSummaryController',
-  allAlerts: function(){
-    return App.router.get('clusterController.alerts');
-  }.property('App.router.clusterController.alerts'),
 
-  alerts: function () {
-    var serviceId = this.get('content.serviceName');
-    if (serviceId) {
-      return App.Alert.sort(this.get('allAlerts').filter(function (item) {
-        return item.get('serviceType').toLowerCase() == serviceId.toLowerCase() && !item.get('ignoredForServices');
-      }));
-    }
-    return [];
-  }.property('allAlerts', 'content.serviceName'),
-  
   nagiosUrl: function(){
     return App.router.get('clusterController.nagiosUrl');
   }.property('App.router.clusterController.nagiosUrl'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/initialize.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/initialize.js b/ambari-web/app/initialize.js
index 229df15..2b09852 100644
--- a/ambari-web/app/initialize.js
+++ b/ambari-web/app/initialize.js
@@ -42,7 +42,6 @@ require('mappers/cluster_mapper');
 require('mappers/jobs_mapper');
 require('mappers/runs_mapper');
 require('mappers/racks_mapper');
-require('mappers/alerts_mapper');
 require('mappers/users_mapper');
 require('mappers/service_mapper');
 require('mappers/service_metrics_mapper');

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/mappers/alerts_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/alerts_mapper.js b/ambari-web/app/mappers/alerts_mapper.js
deleted file mode 100644
index 54466aa..0000000
--- a/ambari-web/app/mappers/alerts_mapper.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-var previousAlertsResponse = [];
-var stringUtils = require('utils/string_utils');
-
-/**
- * Fields, which are not displayed and used only to compute date property, listed below:
- * last_hard_state_change
- * last_hard_state
- * last_time_ok
- * last_time_warning
- * last_time_unknown
- * last_time_critical
- */
-App.alertsMapper = App.QuickDataMapper.create({
-  model: App.Alert,
-  config: {
-    id: 'id',
-    title: "service_description",
-    service_type: "service_type",
-    last_time: "last_time",
-    status: "current_state",
-    message: "plugin_output",
-    host_name: "host_name",
-    current_attempt: "current_attempt",
-    is_flapping: "is_flapping",
-    last_check: "last_check"
-  },
-  map: function (json) {
-    console.time('App.alertsMapper execution time');
-    if (json && json.items && json.items.length > 0 && json.items[0].HostRoles && json.items[0].HostRoles.nagios_alerts) {
-      if (json.items[0].HostRoles.nagios_alerts.alerts.length === 0) {
-        //Clear Alerts model when NAGIOS stopped or doesn't have alerts anymore
-        App.Alert.find().clear();
-        console.log("NAGIOS stopped: all alerts deleted");
-        return;
-      }
-      var alerts = json.items[0].HostRoles.nagios_alerts.alerts;
-      var alertsMap = {};
-      var addAlerts = [];
-      var mutableFields = ['last_time', 'status', 'message', 'current_attempt', 'is_flapping', 'last_check'];
-
-      alerts.forEach(function (item) {
-        //id consists of combination of serviceType, title and hostName
-        item.id = item.service_type + item.service_description + item.host_name;
-        item.last_time = this.computeLastTime(item);
-        var parsedItem = this.parseIt(item, this.config);
-        alertsMap[item.id] = parsedItem;
-        if (!previousAlertsResponse[item.id]) {
-          addAlerts.push(parsedItem);
-        }
-      }, this);
-
-      this.get('model').find().forEach(function (alertRecord) {
-        if (alertRecord) {
-          var existAlert = alertsMap[alertRecord.get('id')];
-          if (existAlert) {
-            existAlert = this.getDiscrepancies(existAlert, previousAlertsResponse[alertRecord.get('id')], mutableFields);
-            if (existAlert) {
-              for (var i in existAlert) {
-                alertRecord.set(stringUtils.underScoreToCamelCase(i), existAlert[i]);
-              }
-            }
-          } else {
-            this.deleteRecord(alertRecord);
-          }
-        }
-      }, this);
-
-      if (addAlerts.length > 0) {
-        App.store.loadMany(this.get('model'), addAlerts);
-      }
-      previousAlertsResponse = alertsMap;
-    }
-    console.timeEnd('App.alertsMapper execution time');
-  },
-  computeLastTime: function (item) {
-    var dateMap = {
-      '0': 'last_time_ok',
-      '1': 'last_time_warning',
-      '2': 'last_time_critical',
-      '3': 'last_time_unknown'
-    };
-    if (item.current_state && item.last_hard_state && item.current_state != item.last_hard_state) {
-      return item[dateMap[item.current_state]] || item['last_hard_state_change'];
-    } else {
-      return item['last_hard_state_change'];
-    }
-  }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/mappers/hosts_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/hosts_mapper.js b/ambari-web/app/mappers/hosts_mapper.js
index 702a5c2..5180342 100644
--- a/ambari-web/app/mappers/hosts_mapper.js
+++ b/ambari-web/app/mappers/hosts_mapper.js
@@ -38,6 +38,7 @@ App.hostsMapper = App.QuickDataMapper.create({
     host_components: {
       item: 'id'
     },
+    critical_alerts_count: 'critical_alerts_count',
     cpu: 'Hosts.cpu_count',
     cpu_physical: 'Hosts.ph_cpu_count',
     memory: 'Hosts.total_mem',
@@ -75,6 +76,10 @@ App.hostsMapper = App.QuickDataMapper.create({
         item.host_components.forEach(function (host_component) {
           host_component.id = host_component.HostRoles.component_name + "_" + hostName;
         }, this);
+        //check whether Nagios installed and started
+        if (item.alerts) {
+          item.critical_alerts_count = item.alerts.summary.CRITICAL + item.alerts.summary.WARNING;
+        }
 
         hostIds[hostName] = true;
         currentHostStatuses[hostName] = item.Hosts.host_status;
@@ -167,7 +172,7 @@ App.hostsMapper = App.QuickDataMapper.create({
    */
   getDiscrepancies: function (current, previous) {
     var result = {};
-    var fields = ['disk_total', 'disk_free', 'health_status', 'load_one', 'cpu_system', 'cpu_user', 'mem_total', 'mem_free'];
+    var fields = ['disk_total', 'disk_free', 'health_status', 'load_one', 'cpu_system', 'cpu_user', 'mem_total', 'mem_free', 'critical_alerts_count'];
     if (previous) {
       fields.forEach(function (field) {
         if (current[field] != previous[field]) result[field] = current[field];

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/mappers/service_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_mapper.js b/ambari-web/app/mappers/service_mapper.js
index a226eca..c6a3512 100644
--- a/ambari-web/app/mappers/service_mapper.js
+++ b/ambari-web/app/mappers/service_mapper.js
@@ -23,14 +23,19 @@ App.serviceMapper = App.QuickDataMapper.create({
 
     var servicesData = [];
     json.items.forEach(function (service) {
-      servicesData.push({
+      var serviceData = {
         ServiceInfo: {
           service_name: service.ServiceInfo.service_name,
           state: service.ServiceInfo.state
         },
         host_components: [],
         components: []
-      });
+      };
+      //check whether Nagios installed and started
+      if (service.alerts) {
+        serviceData.ServiceInfo.critical_alerts_count = service.alerts.summary.CRITICAL + service.alerts.summary.WARNING;
+      }
+      servicesData.push(serviceData);
     });
 
     App.cache['services'] = servicesData;

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/mappers/service_metrics_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_metrics_mapper.js b/ambari-web/app/mappers/service_metrics_mapper.js
index 8cbda14..e08e13f 100644
--- a/ambari-web/app/mappers/service_metrics_mapper.js
+++ b/ambari-web/app/mappers/service_metrics_mapper.js
@@ -27,6 +27,7 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
     id: 'ServiceInfo.service_name',
     service_name: 'ServiceInfo.service_name',
     work_status: 'ServiceInfo.state',
+    critical_alerts_count: 'ServiceInfo.critical_alerts_count',
     $rand: Math.random(),
     $alerts: [ 1, 2, 3 ],
     host_components: 'host_components',
@@ -237,7 +238,7 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({
         App.store.loadMany(this.get('model'), result);
       } else {
         result.forEach(function (serviceJson) {
-          var fields = ['work_status', 'rand', 'alerts', 'quick_links', 'host_components', 'tool_tip_content'];
+          var fields = ['work_status', 'rand', 'alerts', 'quick_links', 'host_components', 'tool_tip_content', 'critical_alerts_count'];
           var service = this.get('model').find(serviceJson.id);
           var modifiedData = this.getDiscrepancies(serviceJson, previousResponse.findProperty('id', serviceJson.id), fields);
           if (modifiedData.isLoadNeeded) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/models/alert.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alert.js b/ambari-web/app/models/alert.js
index a790f66..a9cd3c3 100644
--- a/ambari-web/app/models/alert.js
+++ b/ambari-web/app/models/alert.js
@@ -18,25 +18,18 @@
 
 var App = require('app');
 
-App.AlertStatus = {
-  negative: 'corrupt',
-  positive: 'ok'
-};
-
 /**
  * Defines structure for App.Alert class. Keys mentioned here are for JSON data
  * which comes back from NAGIOS server.
  */
-App.Alert = DS.Model.extend({
-  title: DS.attr('string'),//service_description in ajax response
-  serviceType: DS.attr('string'),
-  status: DS.attr('string'),//current_state in ajax response
-  message: DS.attr('string'),//plugin_output in ajax response
-  hostName: DS.attr('string'),
-  currentAttempt: DS.attr('string'),
-  isFlapping: DS.attr('number'),
-  lastCheck: DS.attr('number'),
-  lastTime: DS.attr('number'),
+App.Alert = Em.Object.extend({
+  title: null,//service_description in ajax response
+  serviceType: null,
+  status: null,//current_state in ajax response
+  message: null,//plugin_output in ajax response
+  hostName: null,
+  lastCheck: null,
+  lastTime: null,
 
   date: function () {
     return DS.attr.transforms.date.from(this.get('lastTime'));
@@ -186,22 +179,4 @@ App.Alert = DS.Model.extend({
     }
     return null;
   }.property('serviceType')
-
-});
-
-App.Alert.sort = function (array) {
-  return array.sort(function (left, right) {
-    var statusDiff = right.get('status') - left.get('status');
-    if (statusDiff == 0) { // same error severity - sort by time
-      var rightTime = right.get('date');
-      var leftTime = left.get('date');
-      rightTime = rightTime ? rightTime.getTime() : 0;
-      leftTime = leftTime ? leftTime.getTime() : 0;
-      statusDiff = rightTime - leftTime;
-    }
-    return statusDiff;
-  });
-};
-
-App.Alert.FIXTURES = [
-];
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/models/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/host.js b/ambari-web/app/models/host.js
index 3cf0962..53475b0 100644
--- a/ambari-web/app/models/host.js
+++ b/ambari-web/app/models/host.js
@@ -44,6 +44,7 @@ App.Host = DS.Model.extend({
   memFree:DS.attr('number'),
   cpuSystem:DS.attr('number'),
   cpuUser:DS.attr('number'),
+  criticalAlertsCount: DS.attr('number'),
 
   /**
    * Is host checked at the main Hosts page
@@ -74,14 +75,6 @@ App.Host = DS.Model.extend({
   }.property('memTotal', 'memFree'),
 
   /**
-   * Get count of critical alerts for current host
-   * @returns {Number}
-   */
-  criticalAlertsCount: function () {
-    return App.router.get('clusterController.alertsHostMap')[this.get('hostName')];
-  }.property('App.router.clusterController.alerts.length'),
-
-  /**
    * Get count of host components with stale configs
    * @returns {Number}
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/models/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service.js b/ambari-web/app/models/service.js
index 8d6a21c..00a7611 100644
--- a/ambari-web/app/models/service.js
+++ b/ambari-web/app/models/service.js
@@ -27,7 +27,7 @@ App.Service = DS.Model.extend({
   workStatus: DS.attr('string'),
   rand: DS.attr('string'),
   toolTipContent: DS.attr('string'),
-  alerts: DS.hasMany('App.Alert'),
+  criticalAlertsCount: DS.attr('number'),
   quickLinks: DS.hasMany('App.QuickLinks'),  // mapped in app/mappers/service_metrics_mapper.js method - mapQuickLinks
   hostComponents: DS.hasMany('App.HostComponent'),
   serviceConfigsTemplate: App.config.get('preDefinedServiceConfigs'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/templates/main/dashboard/alert_notification_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard/alert_notification_popup.hbs b/ambari-web/app/templates/main/dashboard/alert_notification_popup.hbs
index 6ca9b58..8a37e23 100644
--- a/ambari-web/app/templates/main/dashboard/alert_notification_popup.hbs
+++ b/ambari-web/app/templates/main/dashboard/alert_notification_popup.hbs
@@ -16,15 +16,19 @@
 * limitations under the License.
 }}
 
-<p>{{view.warnAlertsMessage}}</p>
-{{#if view.warnAlertsCount}}
-  <ul id='summary-alerts-list' class="alerts">
-    {{#each view.warnAlerts}}
-      {{view App.AlertItemView contentBinding="this"}}
-    {{/each}}
-  </ul>
-{{/if}}
-<p class="alertsPopupLinks">
-    <a href="#" {{action selectService}}>{{t services.alerts.goToService}}</a>
-    <a href="#" {{action "viewNagiosUrl" on="mouseUp"}}>{{t services.alerts.goToNagios}}</a>
-</p>
\ No newline at end of file
+{{#if controller.isLoaded}}
+    <p>{{view.warnAlertsMessage}}</p>
+    {{#if view.warnAlertsCount}}
+        <ul id='summary-alerts-list' class="alerts">
+          {{#each view.warnAlerts}}
+            {{view App.AlertItemView contentBinding="this"}}
+          {{/each}}
+        </ul>
+    {{/if}}
+    <p class="alertsPopupLinks">
+        <a href="#" {{action selectService target="view"}}>{{t services.alerts.goToService}}</a>
+        <a href="#" {{action "viewNagiosUrl" target="view" on="mouseUp"}}>{{t services.alerts.goToNagios}}</a>
+    </p>
+{{else}}
+  <div class="spinner"></div>
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/templates/main/host/alerts_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host/alerts_popup.hbs b/ambari-web/app/templates/main/host/alerts_popup.hbs
index 338a225..247753a 100644
--- a/ambari-web/app/templates/main/host/alerts_popup.hbs
+++ b/ambari-web/app/templates/main/host/alerts_popup.hbs
@@ -16,12 +16,16 @@
 * limitations under the License.
 }}
 
-{{#if view.hostAlerts.length}}
-<ul id='summary-alerts-list' class="alerts">
-  {{#each view.hostAlerts}}
-  {{view App.AlertItemView contentBinding="this"}}
-  {{/each}}
-</ul>
+{{#if controller.isLoaded}}
+  {{#if view.alerts.length}}
+      <ul id='summary-alerts-list' class="alerts">
+        {{#each view.alerts}}
+          {{view App.AlertItemView contentBinding="this"}}
+        {{/each}}
+      </ul>
+  {{else}}
+    {{t hosts.host.alert.noAlerts.message}}
+  {{/if}}
 {{else}}
-  {{t hosts.host.alert.noAlerts.message}}
+    <div class="spinner"></div>
 {{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/templates/main/service/info/summary.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/info/summary.hbs b/ambari-web/app/templates/main/service/info/summary.hbs
index ffb6292..1eac1f8 100644
--- a/ambari-web/app/templates/main/service/info/summary.hbs
+++ b/ambari-web/app/templates/main/service/info/summary.hbs
@@ -84,20 +84,24 @@
         {{/if}}
       </div>
       <ul id='summary-alerts-list' class="alerts">
-        {{#if controller.alerts.length}}
-          {{#each controller.alerts}}
-            {{view App.AlertItemView contentBinding="this"}}
-          {{/each}}
-        {{else}}
-          {{#if controller.isNagiosInstalled}}
-            <div class="alert alert-info">
-              {{t services.service.info.summary.nagios.noAlerts}}
-            </div>
+        {{#if view.alertsController.isLoaded}}
+          {{#if view.alerts.length}}
+            {{#each view.alerts}}
+              {{view App.AlertItemView contentBinding="this"}}
+            {{/each}}
           {{else}}
-            <div class="alert">
-              {{t services.service.info.summary.nagios.alerts}}
-            </div>
+            {{#if controller.isNagiosInstalled}}
+                <div class="alert alert-info">
+                  {{t services.service.info.summary.nagios.noAlerts}}
+                </div>
+            {{else}}
+                <div class="alert">
+                  {{t services.service.info.summary.nagios.alerts}}
+                </div>
+            {{/if}}
           {{/if}}
+        {{else}}
+          <div class="spinner"></div>
         {{/if}}
       </ul>
     </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/utils/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax.js b/ambari-web/app/utils/ajax.js
index fcb0d11..a09499b 100644
--- a/ambari-web/app/utils/ajax.js
+++ b/ambari-web/app/utils/ajax.js
@@ -30,6 +30,14 @@ var App = require('app');
  * @type {Object}
  */
 var urls = {
+  'alerts.get_by_service': {
+    'real': '/clusters/{clusterName}/services/{serviceName}?fields=alerts',
+    'mock': '/data/background_operations/list_on_start.json'
+  },
+  'alerts.get_by_host': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}?fields=alerts',
+    'mock': '/data/background_operations/list_on_start.json'
+  },
   'background_operations.get_most_recent': {
     'real': '/clusters/{clusterName}/requests?to=end&page_size=10&fields=Requests',
     'mock': '/data/background_operations/list_on_start.json',

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/views/main/dashboard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard.js b/ambari-web/app/views/main/dashboard.js
index 30be2f6..61853cb 100644
--- a/ambari-web/app/views/main/dashboard.js
+++ b/ambari-web/app/views/main/dashboard.js
@@ -538,18 +538,17 @@ App.MainDashboardView = Em.View.extend({
   }.property('App.router.clusterController.gangliaUrl'),
 
   showAlertsPopup: function (event) {
+    var service = event.context;
+    App.router.get('mainAlertsController').loadAlerts(service.get('serviceName'), "SERVICE");
     App.ModalPopup.show({
       header: this.t('services.alerts.headingOfList'),
       bodyClass: Ember.View.extend({
-        service: event.context,
+        templateName: require('templates/main/dashboard/alert_notification_popup'),
+        service: service,
+        controllerBinding: 'App.router.mainAlertsController',
         warnAlerts: function () {
-          var allAlerts = App.router.get('clusterController.alerts');
-          var serviceId = this.get('service.serviceName');
-          if (serviceId) {
-            return App.Alert.sort(allAlerts.filterProperty('serviceType', serviceId).filterProperty('isOk', false).filterProperty('ignoredForServices', false));
-          }
-          return 0;
-        }.property('App.router.clusterController.alerts'),
+          return this.get('controller.alerts').filterProperty('isOk', false).filterProperty('ignoredForServices', false);
+        }.property('controller.alerts'),
 
         warnAlertsCount: function () {
           return this.get('warnAlerts').length;
@@ -573,10 +572,9 @@ App.MainDashboardView = Em.View.extend({
         },
 
         selectService: function () {
-          App.router.transitionTo('services.service.summary', event.context)
+          App.router.transitionTo('services.service.summary', service);
           this.closePopup();
-        },
-        templateName: require('templates/main/dashboard/alert_notification_popup')
+        }
       }),
       primary: Em.I18n.t('common.close'),
       secondary : null,

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/views/main/dashboard/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard/service.js b/ambari-web/app/views/main/dashboard/service.js
index 4ae53a8..cf0048e 100644
--- a/ambari-web/app/views/main/dashboard/service.js
+++ b/ambari-web/app/views/main/dashboard/service.js
@@ -123,8 +123,8 @@ App.MainDashboardServiceView = Em.View.extend({
   },
 
   criticalAlertsCount: function () {
-    return App.router.get('clusterController.alertsServiceMap')[this.get('service.id')];
-  }.property('App.router.clusterController.alerts'),
+    return this.get('service.criticalAlertsCount');
+  }.property('service.criticalAlertsCount'),
 
   isCollapsed: false,
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/views/main/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js
index 0664e4d..eba2c16 100644
--- a/ambari-web/app/views/main/menu.js
+++ b/ambari-web/app/views/main/menu.js
@@ -77,9 +77,10 @@ App.MainMenuView = Em.CollectionView.extend({
 
     alertsCount:function () {
       if (this.get('content').routing == 'hosts') {
-        return App.router.get('mainHostController.alerts').length;
+        return App.router.get('mainHostController.content').mapProperty('criticalAlertsCount')
+          .reduce(function(pv, cv) { return pv + parseInt(cv); }, 0);
       }
-    }.property('App.router.mainHostController.alerts.length'),
+    }.property('App.router.mainHostController.content.@each.criticalAlertsCount'),
 
     templateName: require('templates/main/menu_item')
   })

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/views/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js
index 9f6d953..9c42029 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -58,6 +58,11 @@ App.MainServiceInfoSummaryView = Em.View.extend({
     }.property("service")
   }),
 
+  alertsControllerBinding: 'App.router.mainAlertsController',
+  alerts: function () {
+    return this.get('alertsController.alerts');
+  }.property('alertsController.alerts'),
+
   noTemplateService: function () {
     var serviceName = this.get("service.serviceName");
     //services with only master components
@@ -420,6 +425,9 @@ App.MainServiceInfoSummaryView = Em.View.extend({
   }.property('App.router.clusterController.gangliaUrl', 'service.serviceName'),
 
   didInsertElement:function () {
+    var alertsController = this.get('alertsController');
+    alertsController.loadAlerts(this.get('service.serviceName'), "SERVICE");
+    alertsController.set('isUpdating', true);
     //TODO delegate style calculation to css
     // We have to make the height of the Alerts section
     // match the height of the Summary section.
@@ -438,14 +446,17 @@ App.MainServiceInfoSummaryView = Em.View.extend({
         $(summaryTable).append('<tr><td></td></tr>');
         $(summaryTable).attr('style', "height:" + alertsList.clientHeight + "px;");
       }
-      Ember.run.next(this, 'setAlertsWindowSize');
     }
   },
+  willDestroyElement: function(){
+    this.get('alertsController').set('isUpdating', false);
+  },
+
   setAlertsWindowSize: function() {
     // for alerts window
     var summaryTable = document.getElementById('summary-info');
     var alertsList = document.getElementById('summary-alerts-list');
-    var alertsNum = App.router.get('mainServiceInfoSummaryController.alerts.length');
+    var alertsNum = this.get('alerts').length;
     if (summaryTable && alertsList && alertsNum != null) {
       var summaryActualHeight = summaryTable.clientHeight;
       var alertsActualHeight = alertsNum * 60;
@@ -464,7 +475,7 @@ App.MainServiceInfoSummaryView = Em.View.extend({
         $(alertsList).attr('style', "height:" + summaryActualHeight + "px;");
       }
     }
-  }.observes('App.router.mainServiceInfoSummaryController.alerts.length'),
+  }.observes('alertsController.isLoaded'),
 
   clientHosts:App.Host.find(),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/391f1242/ambari-web/app/views/main/service/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/menu.js b/ambari-web/app/views/main/service/menu.js
index fe2b8a4..79dbc71 100644
--- a/ambari-web/app/views/main/service/menu.js
+++ b/ambari-web/app/views/main/service/menu.js
@@ -71,13 +71,8 @@ App.MainServiceMenuView = Em.CollectionView.extend({
     }.property('parentView.activeServiceId'),
 
     alertsCount: function () {
-      var allAlerts = App.router.get('clusterController.alerts');
-      var serviceId = this.get('content.serviceName');
-      if (serviceId) {
-        return allAlerts.filterProperty('serviceType', serviceId).filterProperty('isOk', false).filterProperty('ignoredForServices', false).length;
-      }
-      return 0;
-    }.property('App.router.clusterController.alerts'),
+      return this.get('content.criticalAlertsCount');
+    }.property('content.criticalAlertsCount'),
 
     refreshRestartRequiredMessage: function() {
       var restarted, componentsCount, hostsCount, message, tHosts, tComponents;