/* * RHQ Management Platform * Copyright 2012, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.scheduler.jobs; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.alert.AlertConditionOperator; import org.rhq.core.domain.criteria.AvailabilityCriteria; import org.rhq.core.domain.measurement.Availability; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.util.PageOrdering; import org.rhq.enterprise.server.alert.engine.AlertConditionCacheStats; import org.rhq.enterprise.server.alert.engine.model.AvailabilityDurationComposite; import org.rhq.enterprise.server.util.LookupUtil; /** * This was once a quartz job but now supports an EJB Timer. It could have been merged into the EJB class with the * Timer code but I left it here since it calls out the fact that it is still a scheduled job. * * @author Jay Shaughnessy */ public class AlertAvailabilityDurationJob { private static final Log LOG = LogFactory.getLog(AlertAvailabilityDurationJob.class); public static final String DATAMAP_CONDITION_ID = "alertConditionId"; public static final String DATAMAP_DURATION = "duration"; public static final String DATAMAP_OPERATOR = "alertConditionOperator"; public static final String DATAMAP_RESOURCE_ID = "resourceId"; public static final String DATAMAP_START_TIME = "startTime"; static public void execute(Map<String, String> infoMap) throws Exception { int conditionId = Integer.valueOf(infoMap.get(DATAMAP_CONDITION_ID)); int resourceId = Integer.valueOf(infoMap.get(DATAMAP_RESOURCE_ID)); long duration = Long.valueOf(infoMap.get(DATAMAP_DURATION)); // in seconds long durationStart = Long.valueOf(infoMap.get(DATAMAP_START_TIME)); // in milliseconds AlertConditionOperator operator = AlertConditionOperator.valueOf(infoMap.get(DATAMAP_OPERATOR)); // get the availabilities for the duration period, one consistent duration will indicate a duration condition AvailabilityCriteria criteria = new AvailabilityCriteria(); criteria.addFilterResourceId(resourceId); long durationEnd = durationStart + (duration * 1000); criteria.addFilterInterval((durationStart + 1), (durationEnd - 1)); // reduced 1ms to fake exclusive interval filter. criteria.addSortStartTime(PageOrdering.ASC); List<Availability> avails = LookupUtil.getAvailabilityManager().findAvailabilityByCriteria( LookupUtil.getSubjectManager().getOverlord(), criteria); // Although unlikely, it's possible the resource has actually gone away while we waited out the duration period. // If we can't find any resource avail assume the resource is gone and just end the job. if (avails.isEmpty()) { if (LOG.isDebugEnabled()) { LOG.debug("AlertAvailabilityDurationJob: No alert. Assuming resource has been uninventoried [" + resourceId + "]"); } return; } // If there are multiple duration records for the duration period then the avail did not stay constant. // Therefore, the alert should not fire as the semantics are "goes down and stays down". if (avails.size() > 1) { if (LOG.isDebugEnabled()) { LOG.debug("AlertAvailabilityDurationJob: No alert. Resource avail for [" + resourceId + "] has fluctuated. " + avails); } return; } // At this point we should be able to just checkConditions because if there is only one avail record for the // duration period it means nothing has changed. But, we'll perform a sanity check just to ensure the avail // type is what we think it should be... Availability avail = avails.get(0); AvailabilityType availType = avail.getAvailabilityType(); boolean checkConditions = false; switch (operator) { case AVAIL_DURATION_DOWN: checkConditions = (AvailabilityType.DOWN == availType); break; case AVAIL_DURATION_NOT_UP: checkConditions = (AvailabilityType.UP != availType); break; default: LOG.error("AlertAvailabilityDurationJob: unexpected operator [" + operator.name() + "]"); } // the call to checkConditions will probably result in an alert, as the actual condition satisfaction was // just done. but we need to actually hook into the alerting chassis to ensure any other conditions are // still satisfied and to make sure all the alert processing is performed. if (checkConditions) { AvailabilityDurationComposite composite = new AvailabilityDurationComposite(conditionId, operator, resourceId, availType, duration); AlertConditionCacheStats stats = LookupUtil.getAlertConditionCacheManager().checkConditions(composite); if (LOG.isDebugEnabled()) { LOG.debug("AlertAvailabilityDurationJob: " + stats.toString()); } } else { LOG.warn("AlertAvailabilityDurationJob: unexpected availability for resource [" + resourceId + "]. " + avail); } } }