/**
* 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.
*/
package org.apache.ambari.server.controller.internal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.StaticallyInject;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.PropertyProvider;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.orm.dao.AlertHostSummaryDTO;
import org.apache.ambari.server.orm.dao.AlertSummaryDTO;
import org.apache.ambari.server.orm.dao.AlertsDAO;
import org.apache.ambari.server.state.AlertState;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* Property provider that adds alert summary information to endpoints.
*/
@StaticallyInject
public class AlertSummaryPropertyProvider extends BaseProvider implements PropertyProvider {
private final static Logger LOG = LoggerFactory.getLogger(AlertSummaryPropertyProvider.class);
/**
* The property ID for a summary of all cluster-wide alerts.
*/
private final static String ALERTS_SUMMARY = "alerts_summary";
/**
* The property ID for a summary of all cluster-wide alerts that have a host
* associated with them.
*/
private final static String ALERTS_SUMMARY_HOSTS = "alerts_summary_hosts";
@Inject
private static Provider<Clusters> s_clusters = null;
@Inject
private static AlertsDAO s_dao = null;
private Resource.Type m_resourceType = null;
private String m_clusterPropertyId = null;
private String m_typeIdPropertyId = null;
/**
* Constructor.
*
* @param type
* @param clusterPropertyId
* @param typeIdPropertyId
*/
AlertSummaryPropertyProvider(Resource.Type type,
String clusterPropertyId, String typeIdPropertyId) {
super(ImmutableSet.of(ALERTS_SUMMARY, ALERTS_SUMMARY_HOSTS));
m_resourceType = type;
m_clusterPropertyId = clusterPropertyId;
m_typeIdPropertyId = typeIdPropertyId;
}
@Override
public Set<Resource> populateResources(Set<Resource> resources,
Request request, Predicate predicate) throws SystemException {
Set<String> propertyIds = getRequestPropertyIds(request, predicate);
try {
// Optimization:
// Some information can be determined more efficiently when requested in bulk
// for an entire cluster at once.
// For Example:
// (1) Cluster level alert-status counts
// (2) Per host alert-status counts
// These can be determined in 1 SQL call per cluster, and results used multiple times.
Map<Long, Map<String, AlertSummaryDTO>> perHostSummaryMap = new HashMap<>();
Map<Long, AlertHostSummaryDTO> hostsSummaryMap = new HashMap<>();
Map<String, Cluster> resourcesClusterMap = new HashMap<>();
for (Resource res : resources) {
String clusterName = (String) res.getPropertyValue(m_clusterPropertyId);
if (clusterName == null || resourcesClusterMap.containsKey(clusterName)) {
continue;
}
Cluster cluster = s_clusters.get().getCluster(clusterName);
resourcesClusterMap.put(clusterName, cluster);
}
for (Cluster cluster : resourcesClusterMap.values()) {
long clusterId = cluster.getClusterId();
switch (m_resourceType.getInternalType()) {
case Cluster:
// only make the calculation if asked
if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY_HOSTS, propertyIds)) {
hostsSummaryMap.put(clusterId, s_dao.findCurrentHostCounts(clusterId));
}
break;
case Host:
if (resources.size() > 1) {
// More efficient to get information for all hosts in 1 call
Map<String, AlertSummaryDTO> perHostCounts = s_dao.findCurrentPerHostCounts(clusterId);
perHostSummaryMap.put(clusterId, perHostCounts);
}
break;
default:
break;
}
}
for (Resource res : resources) {
populateResource(res, propertyIds, perHostSummaryMap, hostsSummaryMap);
}
} catch (AmbariException e) {
LOG.error("Could not load built-in alerts - Executor exception ({})",
e.getMessage());
}
return resources;
}
private void populateResource(Resource resource, Set<String> requestedIds, Map<Long, Map<String,
AlertSummaryDTO>> perHostSummaryMap, Map<Long, AlertHostSummaryDTO> hostsSummaryMap) throws AmbariException {
AlertSummaryDTO summary = null;
AlertHostSummaryDTO hostSummary = null;
String clusterName = (String) resource.getPropertyValue(m_clusterPropertyId);
if (null == clusterName) {
return;
}
String typeId = null == m_typeIdPropertyId ? null : (String) resource.getPropertyValue(m_typeIdPropertyId);
Cluster cluster = s_clusters.get().getCluster(clusterName);
switch (m_resourceType.getInternalType()) {
case Cluster:
long clusterId = cluster.getClusterId();
// only make the calculation if asked
if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY, requestedIds)) {
summary = s_dao.findCurrentCounts(cluster.getClusterId(), null, null);
}
// only make the calculation if asked
if (BaseProvider.isPropertyRequested(ALERTS_SUMMARY_HOSTS,
requestedIds)) {
if (hostsSummaryMap.containsKey(cluster.getClusterId())) {
hostSummary = hostsSummaryMap.get(cluster.getClusterId());
} else {
hostSummary = s_dao.findCurrentHostCounts(clusterId);
}
}
break;
case Service:
summary = s_dao.findCurrentCounts(cluster.getClusterId(), typeId, null);
break;
case Host:
if (perHostSummaryMap.containsKey(cluster.getClusterId()) &&
perHostSummaryMap.get(cluster.getClusterId()).containsKey(typeId)) {
summary = perHostSummaryMap.get(cluster.getClusterId()).get(typeId);
} else {
summary = s_dao.findCurrentCounts(cluster.getClusterId(), null, typeId);
}
break;
default:
break;
}
// all alerts in the cluster, in summary count form
if (null != summary) {
Map<String, Integer> map = new HashMap<>();
map.put(AlertState.OK.name(), Integer.valueOf(summary.getOkCount()));
map.put(AlertState.WARNING.name(), Integer.valueOf(summary.getWarningCount()));
map.put(AlertState.CRITICAL.name(), Integer.valueOf(summary.getCriticalCount()));
map.put(AlertState.UNKNOWN.name(), Integer.valueOf(summary.getUnknownCount()));
map.put("MAINTENANCE", Integer.valueOf(summary.getMaintenanceCount()));
setResourceProperty(resource, ALERTS_SUMMARY, map, requestedIds);
}
// the summary of hosts with warning or critical alerts
if (null != hostSummary) {
Map<AlertState, Integer> map = new HashMap<>();
map.put(AlertState.OK, Integer.valueOf(hostSummary.getOkCount()));
map.put(AlertState.WARNING, Integer.valueOf(hostSummary.getWarningCount()));
map.put(AlertState.CRITICAL, Integer.valueOf(hostSummary.getCriticalCount()));
map.put(AlertState.UNKNOWN, Integer.valueOf(hostSummary.getUnknownCount()));
setResourceProperty(resource, ALERTS_SUMMARY_HOSTS, map, requestedIds);
}
}
@Override
public Set<String> checkPropertyIds(Set<String> propertyIds) {
Set<String> rejects = new HashSet<>();
for (String id : propertyIds) {
if (!id.startsWith(ALERTS_SUMMARY)) {
rejects.add(id);
}
}
return rejects;
}
}