package com.thinkbiganalytics.metadata.sla.spi.core;
/*-
* #%L
* thinkbig-sla-core
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed 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.
* #L%
*/
import com.thinkbiganalytics.alerts.api.Alert;
import com.thinkbiganalytics.alerts.sla.AssessmentAlerts;
import com.thinkbiganalytics.alerts.spi.AlertManager;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAssessment;
import com.thinkbiganalytics.metadata.sla.spi.AssessorNotFoundException;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAgreementChecker;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAgreementProvider;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAssessmentProvider;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAssessor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
/**
*/
public class DefaultServiceLevelAgreementChecker implements ServiceLevelAgreementChecker {
private static final Logger LOG = LoggerFactory.getLogger(DefaultServiceLevelAgreementChecker.class);
@Inject
protected ServiceLevelAgreementProvider slaProvider;
@Inject
protected ServiceLevelAssessmentProvider assessmentProvider;
@Inject
protected ServiceLevelAssessor assessor;
@Inject
@Named("kyloAlertManager")
protected AlertManager alertManager;
//store a ref to the last Assessment ID that was alerted
protected Map<ServiceLevelAgreement.ID, ServiceLevelAssessment.ID> alertedAssessments;
public DefaultServiceLevelAgreementChecker() {
this.alertedAssessments = Collections
.synchronizedMap(new LinkedHashMap<ServiceLevelAgreement.ID, ServiceLevelAssessment.ID>());
}
/**
* Caller should wrap this in commit
*/
public void checkAgreements() {
List<? extends ServiceLevelAgreement> list = slaProvider.getAgreements();
LOG.info("Checking {} service level agreements", list.size());
for (ServiceLevelAgreement agreement : list) {
checkAgreement(agreement);
}
LOG.info("Completed checking SLAs");
}
/**
* Check the Agreement. Caller needs to wrap this in MetadataAccesss transcation
*/
public void checkAgreement(ServiceLevelAgreement agreement) {
if (agreement != null) {
Alert newAlert = null;
if (isAssessable(agreement)) {
LOG.info("Assessing SLA : " + agreement.getName());
try {
ServiceLevelAssessment assessment = assessor.assess(agreement);
if (shouldAlert(agreement, assessment)) {
newAlert = alertManager.create(AssessmentAlerts.VIOLATION_ALERT_TYPE,
Alert.Level.FATAL,
"Violation of SLA: " + agreement.getName(), assessment.getId());
}
} catch (AssessorNotFoundException e) {
LOG.info("SLA assessment failed. Assessor Not found: {} - Exception: {}", agreement.getName(), e);
}
}
if (newAlert != null) {
// Record this assessment as the latest for this SLA.
alertedAssessments.put(agreement.getId(), (ServiceLevelAssessment.ID) newAlert.getContent());
LOG.info("SLA assessment failed: {} - generated alert: {}", agreement.getName(), newAlert.getId());
}
}
}
/**
* Determine whether an alert should be generated for this assessment by comparing is to the last one for the same SLA.
*
* @return true if the alert should be generated
*/
protected boolean shouldAlert(ServiceLevelAgreement agreement, ServiceLevelAssessment assessment) {
boolean shouldAlert = false;
try {
// Get the last assessment that was created for this SLA (if any).
ServiceLevelAssessment previous = null;
ServiceLevelAssessment.ID previousId = this.alertedAssessments.get(agreement.getId());
if (previousId != null) {
previous = this.assessmentProvider.findServiceLevelAssessment(previousId);
} else {
previous = this.assessmentProvider.findLatestAssessment(agreement.getId());
}
if (previous != null) {
if (previous.getAgreement() == null && StringUtils.isNotBlank(assessment.getServiceLevelAgreementId())) {
ServiceLevelAgreement previousAgreement = slaProvider.getAgreement(slaProvider.resolve(assessment.getServiceLevelAgreementId()));
}
shouldAlert = assessment.compareTo(previous) != 0;
} else {
shouldAlert = true;
}
} catch (Exception e) {
LOG.error("Error checking shouldAlert for {}. {} ", agreement.getName(), e.getMessage(), e);
}
return shouldAlert;
}
private boolean isAssessable(ServiceLevelAgreement agreement) {
// TODO: validate that this is a kind of agreement that we assess. Assume we assess all SLAs for now.
return true;
}
}