package com.sequenceiq.periscope.monitor.evaluator; import java.net.URLEncoder; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.ws.rs.client.Client; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import com.sequenceiq.cloudbreak.client.RestClientUtil; import com.sequenceiq.cloudbreak.util.JaxRSUtil; import com.sequenceiq.periscope.domain.BaseAlert; import com.sequenceiq.periscope.domain.Cluster; import com.sequenceiq.periscope.domain.PrometheusAlert; import com.sequenceiq.periscope.log.MDCBuilder; import com.sequenceiq.periscope.model.PrometheusResponse; import com.sequenceiq.periscope.model.TlsConfiguration; import com.sequenceiq.periscope.monitor.event.ScalingEvent; import com.sequenceiq.periscope.monitor.event.UpdateFailedEvent; import com.sequenceiq.periscope.repository.PrometheusAlertRepository; import com.sequenceiq.periscope.service.ClusterService; import com.sequenceiq.periscope.service.security.TlsSecurityService; @Component("PrometheusEvaluator") @Scope("prototype") public class PrometheusEvaluator extends AbstractEventPublisher implements EvaluatorExecutor { private static final Logger LOGGER = LoggerFactory.getLogger(PrometheusEvaluator.class); @Autowired private ClusterService clusterService; @Autowired private PrometheusAlertRepository alertRepository; @Inject private TlsSecurityService tlsSecurityService; private long clusterId; @Override public void setContext(Map<String, Object> context) { this.clusterId = (long) context.get(EvaluatorContext.CLUSTER_ID.name()); } @Override public void run() { try { Cluster cluster = clusterService.find(clusterId); MDCBuilder.buildMdcContext(cluster); TlsConfiguration tlsConfig = tlsSecurityService.getConfiguration(cluster); Client client = RestClientUtil.createClient(tlsConfig.getServerCertPath(), tlsConfig.getClientCertPath(), tlsConfig.getClientKeyPath(), true, PrometheusEvaluator.class); String prometheusAddress = String.format("https://%s:%s/prometheus", cluster.getAmbari().getHost(), cluster.getPort()); WebTarget target = client.target(prometheusAddress); for (PrometheusAlert alert : alertRepository.findAllByCluster(clusterId)) { String alertName = alert.getName(); LOGGER.info("Checking Prometheus based alert: '{}'", alertName); String query = URLEncoder.encode(String.format("ALERTS{alertname=\"%s\"}[%dm]", alert.getName(), alert.getPeriod()), "UTF-8"); Response response = target .path("/api/v1/query") .queryParam("query", query) .request() .header("Accept", MediaType.APPLICATION_JSON_VALUE) .get(); PrometheusResponse prometheusResponse = JaxRSUtil.response(response, PrometheusResponse.class); boolean triggerScale = false; switch (alert.getAlertState()) { case OK: triggerScale = prometheusResponse.getData().getResult().isEmpty(); break; case CRITICAL: for (PrometheusResponse.Result alertResult : prometheusResponse.getData().getResult()) { if ("firing".equals(alertResult.getMetric().getAlertstate())) { List<Object> lastSample = alertResult.getValues().get(alertResult.getValues().size() - 1); Object alertValue = lastSample.get(1); if (alertValue instanceof String) { if ("0".equals(alertValue)) { break; } triggerScale = true; } } } break; default: triggerScale = false; break; } if (triggerScale && isPolicyAttached(alert)) { publishEvent(new ScalingEvent(alert)); } } } catch (Exception e) { LOGGER.error("Failed to retrieve alerts from Prometheus", e); publishEvent(new UpdateFailedEvent(clusterId)); } } private boolean isPolicyAttached(BaseAlert alert) { return alert.getScalingPolicy() != null; } }