package com.sequenceiq.periscope.service; import static org.springframework.ui.freemarker.FreeMarkerTemplateUtils.processTemplateIntoString; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import com.sequenceiq.ambari.client.AmbariClient; import com.sequenceiq.periscope.domain.BaseAlert; import com.sequenceiq.periscope.domain.Cluster; import com.sequenceiq.periscope.domain.MetricAlert; import com.sequenceiq.periscope.domain.PrometheusAlert; import com.sequenceiq.periscope.domain.TimeAlert; import com.sequenceiq.periscope.log.MDCBuilder; import com.sequenceiq.periscope.api.model.AlertRuleDefinitionEntry; import com.sequenceiq.periscope.repository.ClusterRepository; import com.sequenceiq.periscope.repository.MetricAlertRepository; import com.sequenceiq.periscope.repository.PrometheusAlertRepository; import com.sequenceiq.periscope.repository.TimeAlertRepository; import com.sequenceiq.periscope.utils.AmbariClientProvider; import freemarker.template.Configuration; @Service public class AlertService { private static final Logger LOGGER = LoggerFactory.getLogger(AlertService.class); private static final String ALERT_PATH = "alerts/"; private static final String CONTAINER_ALERT = "pending_containers.ftl"; private static final String APP_ALERT = "pending_apps.ftl"; @Inject private ClusterRepository clusterRepository; @Inject private MetricAlertRepository metricAlertRepository; @Inject private TimeAlertRepository timeAlertRepository; @Inject private PrometheusAlertRepository prometheusAlertRepository; @Inject private ClusterService clusterService; @Inject private Configuration freemarkerConfiguration; @Inject private AmbariClientProvider ambariClientProvider; @Inject private ConsulKeyValueService consulKeyValueService; @Inject private PrometheusAlertTemplateService prometheusAlertService; public MetricAlert createMetricAlert(long clusterId, MetricAlert alert) { Cluster cluster = clusterService.findOneById(clusterId); alert.setCluster(cluster); MetricAlert metricAlert = metricAlertRepository.save(alert); cluster.addMetricAlert(metricAlert); clusterRepository.save(cluster); return metricAlert; } public MetricAlert updateMetricAlert(long clusterId, long alertId, MetricAlert metricAlert) { MetricAlert alert = findMetricAlertByCluster(clusterId, alertId); alert.setName(metricAlert.getName()); alert.setDefinitionName(metricAlert.getDefinitionName()); alert.setPeriod(metricAlert.getPeriod()); alert.setDescription(metricAlert.getDescription()); alert.setAlertState(metricAlert.getAlertState()); return metricAlertRepository.save(alert); } public MetricAlert findMetricAlertByCluster(long clusterId, long alertId) { return metricAlertRepository.findByCluster(alertId, clusterId); } public void deleteMetricAlert(long clusterId, long alertId) { metricAlertRepository.findByCluster(alertId, clusterId); Cluster cluster = clusterRepository.find(clusterId); cluster.setMetricAlerts(removeMetricAlert(cluster, alertId)); metricAlertRepository.delete(alertId); clusterRepository.save(cluster); } public Set<MetricAlert> removeMetricAlert(Cluster cluster, long alertId) { return cluster.getMetricAlerts().stream().filter(a -> a.getId() != alertId).collect(Collectors.toSet()); } public Set<MetricAlert> getMetricAlerts(long clusterId) { Cluster cluster = clusterService.findOneById(clusterId); return cluster.getMetricAlerts(); } public TimeAlert createTimeAlert(long clusterId, TimeAlert alert) { Cluster cluster = clusterService.findOneById(clusterId); alert.setCluster(cluster); alert = timeAlertRepository.save(alert); cluster.addTimeAlert(alert); clusterRepository.save(cluster); return alert; } public TimeAlert findTimeAlertByCluster(long clusterId, long alertId) { return timeAlertRepository.findByCluster(alertId, clusterId); } public TimeAlert updateTimeAlert(long clusterId, long alertId, TimeAlert timeAlert) { TimeAlert alert = timeAlertRepository.findByCluster(alertId, clusterId); alert.setDescription(timeAlert.getDescription()); alert.setCron(timeAlert.getCron()); alert.setTimeZone(timeAlert.getTimeZone()); alert.setName(timeAlert.getName()); return timeAlertRepository.save(alert); } public Set<TimeAlert> getTimeAlerts(long clusterId) { Cluster cluster = clusterService.findOneById(clusterId); return cluster.getTimeAlerts(); } public void deleteTimeAlert(long clusterId, long alertId) { Cluster cluster = clusterService.findOneById(clusterId); timeAlertRepository.findByCluster(alertId, clusterId); cluster.setTimeAlerts(removeTimeAlert(cluster, alertId)); timeAlertRepository.delete(alertId); clusterRepository.save(cluster); } public Set<TimeAlert> removeTimeAlert(Cluster cluster, long alertId) { return cluster.getTimeAlerts().stream().filter(a -> a.getId() != alertId).collect(Collectors.toSet()); } public BaseAlert getBaseAlert(long clusterId, long alertId) { try { return findMetricAlertByCluster(clusterId, alertId); } catch (Exception e) { LOGGER.info("Could not found Metric alert with id: '{}', for cluster: '{}'!", alertId, clusterId); } try { return findTimeAlertByCluster(clusterId, alertId); } catch (Exception e) { LOGGER.info("Could not found Time alert with id: '{}', for cluster: '{}'!", alertId, clusterId); } try { return findPrometheusAlertByCluster(clusterId, alertId); } catch (Exception e) { LOGGER.info("Could not found Prometheus alert with id: '{}', for cluster: '{}'!", alertId, clusterId); } throw new NotFoundException(String.format("Could not found alert with id: '%s', for cluster: '%s'!", alertId, clusterId)); } public void save(BaseAlert alert) { if (alert instanceof MetricAlert) { metricAlertRepository.save((MetricAlert) alert); } else if (alert instanceof TimeAlert) { timeAlertRepository.save((TimeAlert) alert); } else if (alert instanceof PrometheusAlert) { prometheusAlertRepository.save((PrometheusAlert) alert); } } public List<Map<String, Object>> getAlertDefinitions(long clusterId) { Cluster cluster = clusterService.findOneById(clusterId); List<Map<String, Object>> ret = new ArrayList<>(); List<Map<String, String>> alertDefinitions = ambariClientProvider.createAmbariClient(cluster).getAlertDefinitions(); for (Map<String, String> alertDefinition : alertDefinitions) { Map<String, Object> tmp = new HashMap<>(); for (Map.Entry<String, String> stringStringEntry : alertDefinition.entrySet()) { tmp.put(stringStringEntry.getKey(), stringStringEntry.getValue()); } ret.add(tmp); } return ret; } public void addPeriscopeAlerts(Cluster cluster) { MDCBuilder.buildMdcContext(cluster); if (cluster.getSecurityConfig() != null) { try { AmbariClient client = ambariClientProvider.createAmbariClient(cluster); createAlert(client, getAlertDefinition(client, CONTAINER_ALERT), CONTAINER_ALERT); createAlert(client, getAlertDefinition(client, APP_ALERT), APP_ALERT); } catch (Exception e) { LOGGER.error("Cannot create alert definitions", e); } } } public PrometheusAlert createPrometheusAlert(long clusterId, PrometheusAlert alert) { Cluster cluster = clusterService.findOneById(clusterId); alert.setCluster(cluster); PrometheusAlert savedAlert = prometheusAlertRepository.save(alert); cluster.addPrometheusAlert(savedAlert); clusterRepository.save(cluster); consulKeyValueService.addAlert(cluster, savedAlert); LOGGER.info("Prometheus alert '{}' has been created for cluster 'ID:{}'", alert.getName(), cluster.getId()); return savedAlert; } public PrometheusAlert updatePrometheusAlert(long clusterId, long alertId, PrometheusAlert prometheusAlert) { PrometheusAlert alert = findPrometheusAlertByCluster(clusterId, alertId); alert.setName(prometheusAlert.getName()); alert.setAlertRule(prometheusAlert.getAlertRule()); alert.setPeriod(prometheusAlert.getPeriod()); alert.setDescription(prometheusAlert.getDescription()); alert.setAlertState(prometheusAlert.getAlertState()); PrometheusAlert savedAlert = prometheusAlertRepository.save(alert); Cluster cluster = clusterService.find(clusterId); consulKeyValueService.addAlert(cluster, savedAlert); LOGGER.info("Prometheus alert '{}' has been updated for cluster 'ID:{}'", alert.getName(), cluster.getId()); return savedAlert; } public PrometheusAlert findPrometheusAlertByCluster(long clusterId, long alertId) { return prometheusAlertRepository.findByCluster(alertId, clusterId); } public void deletePrometheusAlert(long clusterId, long alertId) { PrometheusAlert alert = prometheusAlertRepository.findByCluster(alertId, clusterId); Cluster cluster = clusterRepository.find(clusterId); consulKeyValueService.deleteAlert(cluster, alert); Set<PrometheusAlert> alerts = cluster.getPrometheusAlerts().stream().filter(a -> a.getId() != alertId).collect(Collectors.toSet()); cluster.setPrometheusAlerts(alerts); prometheusAlertRepository.delete(alertId); clusterRepository.save(cluster); LOGGER.info("Prometheus alert '{}' has been deleted for cluster 'ID:{}'", alert.getName(), cluster.getId()); } public void addPrometheusAlertsToConsul(Cluster cluster) { Set<PrometheusAlert> alerts = prometheusAlertRepository.findAllByCluster(cluster.getId()); alerts.stream().forEach(alert -> consulKeyValueService.addAlert(cluster, alert)); } public List<AlertRuleDefinitionEntry> getPrometheusAlertDefinitions() { return prometheusAlertService.getAlertDefinitions(); } public Set<PrometheusAlert> getPrometheusAlerts(long clusterId) { return prometheusAlertRepository.findAllByCluster(clusterId); } private String getAlertDefinition(AmbariClient client, String name) throws Exception { Map<String, String> model = Collections.singletonMap("clusterName", client.getClusterName()); return processTemplateIntoString(freemarkerConfiguration.getTemplate(ALERT_PATH + name, "UTF-8"), model); } private void createAlert(AmbariClient client, String json, String alertName) { try { client.createAlert(json); LOGGER.info("Alert: {} added to the cluster", alertName); } catch (Exception e) { LOGGER.info("Cannot add '{}' to the cluster", alertName); } } }