001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.oozie.sla; 020 021import java.text.ParseException; 022import java.util.Date; 023 024import org.apache.oozie.AppType; 025import org.apache.oozie.ErrorCode; 026import org.apache.oozie.client.OozieClient; 027import org.apache.oozie.client.event.SLAEvent.EventStatus; 028import org.apache.oozie.command.CommandException; 029import org.apache.oozie.executor.jpa.JPAExecutorException; 030import org.apache.oozie.executor.jpa.SLARegistrationQueryExecutor; 031import org.apache.oozie.executor.jpa.SLARegistrationQueryExecutor.SLARegQuery; 032import org.apache.oozie.service.ServiceException; 033import org.apache.oozie.service.Services; 034import org.apache.oozie.sla.service.SLAService; 035import org.apache.oozie.util.DateUtils; 036import org.apache.oozie.util.XLog; 037import org.apache.oozie.util.XmlUtils; 038import org.jdom.Element; 039 040public class SLAOperations { 041 042 public static final String NOMINAL_TIME = "nominal-time"; 043 public static final String SHOULD_START = "should-start"; 044 public static final String SHOULD_END = "should-end"; 045 public static final String MAX_DURATION = "max-duration"; 046 public static final String ALERT_EVENTS = "alert-events"; 047 public static final String ALL_VALUE = "ALL"; 048 049 050 static public XLog LOG = XLog.getLog(SLAOperations.class); 051 052 053 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, String parentId, 054 AppType appType, String user, String appName, XLog log, boolean rerun, boolean disableAlert) 055 throws CommandException { 056 if (eSla == null || !SLAService.isEnabled()) { 057 log.debug("Not registering SLA for job [{0}]. Sla-Xml null OR SLAService not enabled", jobId); 058 return null; 059 } 060 SLARegistrationBean sla = new SLARegistrationBean(); 061 062 // Setting nominal time 063 String strNominalTime = getTagElement(eSla, NOMINAL_TIME); 064 Date nominalTime = setNominalTime(strNominalTime, sla); 065 066 // Setting expected start time 067 String strExpectedStart = getTagElement(eSla, SHOULD_START); 068 setExpectedStart(strExpectedStart, nominalTime, sla); 069 070 // Setting expected end time 071 String strExpectedEnd = getTagElement(eSla, SHOULD_END); 072 setExpectedEnd(strExpectedEnd, nominalTime, sla); 073 074 // Setting expected duration in milliseconds 075 String expectedDurationStr = getTagElement(eSla, MAX_DURATION); 076 setExpectedDuration(expectedDurationStr, sla); 077 078 // Parse desired alert-types i.e. start-miss, end-miss, start-met etc.. 079 String alertEvents = getTagElement(eSla, ALERT_EVENTS); 080 if (alertEvents != null) { 081 String events[] = alertEvents.split(","); 082 StringBuilder alertsStr = new StringBuilder(); 083 for (int i = 0; i < events.length; i++) { 084 String event = events[i].trim().toUpperCase(); 085 try { 086 EventStatus.valueOf(event); 087 } 088 catch (IllegalArgumentException iae) { 089 XLog.getLog(SLAService.class).warn( 090 "Invalid value: [" + event + "]" + " for SLA Alert-event. Should be one of " 091 + EventStatus.values() + ". Setting it to default [" + EventStatus.END_MISS.name() 092 + "]"); 093 event = EventStatus.END_MISS.name(); 094 } 095 alertsStr.append(event).append(","); 096 } 097 sla.setAlertEvents(alertsStr.toString().substring(0, alertsStr.lastIndexOf(","))); 098 } 099 100 // Other sla config 101 sla.setNotificationMsg(getTagElement(eSla, "notification-msg")); 102 sla.setAlertContact(getTagElement(eSla, "alert-contact")); 103 sla.setUpstreamApps(getTagElement(eSla, "upstream-apps")); 104 105 //disable Alert flag in slaConfig 106 if (disableAlert) { 107 sla.addToSLAConfigMap(OozieClient.SLA_DISABLE_ALERT, Boolean.toString(disableAlert)); 108 } 109 // Oozie defined 110 sla.setId(jobId); 111 sla.setAppType(appType); 112 sla.setAppName(appName); 113 sla.setUser(user); 114 sla.setParentId(parentId); 115 116 SLAService slaService = Services.get().get(SLAService.class); 117 try { 118 if (!rerun) { 119 slaService.addRegistrationEvent(sla); 120 } 121 else { 122 slaService.updateRegistrationEvent(sla); 123 } 124 } 125 catch (ServiceException e) { 126 throw new CommandException(ErrorCode.E1007, " id " + jobId, e.getMessage(), e); 127 } 128 129 log.debug("Job [{0}] reg for SLA. Size of Sla Xml = [{1}]", jobId, XmlUtils.prettyPrint(eSla).toString().length()); 130 return sla; 131 } 132 133 public static Date setNominalTime(String strNominalTime, SLARegistrationBean sla) throws CommandException { 134 if (strNominalTime == null || strNominalTime.length() == 0) { 135 return sla.getNominalTime(); 136 } 137 Date nominalTime; 138 try { 139 nominalTime = DateUtils.parseDateOozieTZ(strNominalTime); 140 sla.setNominalTime(nominalTime); 141 } 142 catch (ParseException pex) { 143 throw new CommandException(ErrorCode.E0302, strNominalTime, pex); 144 } 145 return nominalTime; 146 } 147 148 public static void setExpectedStart(String strExpectedStart, Date nominalTime, SLARegistrationBean sla) 149 throws CommandException { 150 if (strExpectedStart != null) { 151 float expectedStart = Float.parseFloat(strExpectedStart); 152 if (expectedStart < 0) { 153 throw new CommandException(ErrorCode.E0302, strExpectedStart, "for SLA Expected start time"); 154 } 155 else { 156 Date expectedStartTime = new Date(nominalTime.getTime() + (long) (expectedStart * 60 * 1000)); 157 sla.setExpectedStart(expectedStartTime); 158 LOG.debug("Setting expected start to " + expectedStartTime + " for job " + sla.getId()); 159 } 160 } 161 } 162 163 public static void setExpectedEnd(String strExpectedEnd, Date nominalTime, SLARegistrationBean sla) 164 throws CommandException { 165 if (strExpectedEnd != null) { 166 float expectedEnd = Float.parseFloat(strExpectedEnd); 167 if (expectedEnd < 0) { 168 throw new CommandException(ErrorCode.E0302, strExpectedEnd, "for SLA Expected end time"); 169 } 170 else { 171 Date expectedEndTime = new Date(nominalTime.getTime() + (long) (expectedEnd * 60 * 1000)); 172 sla.setExpectedEnd(expectedEndTime); 173 LOG.debug("Setting expected end to " + expectedEndTime + " for job " + sla.getId()); 174 175 } 176 } 177 } 178 179 public static void setExpectedDuration(String expectedDurationStr, SLARegistrationBean sla) { 180 if (expectedDurationStr != null && expectedDurationStr.length() > 0) { 181 float expectedDuration = Float.parseFloat(expectedDurationStr); 182 if (expectedDuration > 0) { 183 long duration = (long) (expectedDuration * 60 * 1000); 184 LOG.debug("Setting expected duration to " + duration + " for job " + sla.getId()); 185 sla.setExpectedDuration(duration); 186 } 187 } 188 else if (sla.getExpectedStart() != null) { 189 long duration = sla.getExpectedEnd().getTime() - sla.getExpectedStart().getTime(); 190 LOG.debug("Setting expected duration to " + duration + " for job " + sla.getId()); 191 sla.setExpectedDuration(sla.getExpectedEnd().getTime() - sla.getExpectedStart().getTime()); 192 } 193 } 194 195 /** 196 * Retrieve registration event 197 * @param jobId the jobId 198 * @throws CommandException 199 * @throws JPAExecutorException 200 */ 201 public static void updateRegistrationEvent(String jobId) throws CommandException, JPAExecutorException { 202 SLAService slaService = Services.get().get(SLAService.class); 203 try { 204 SLARegistrationBean reg = SLARegistrationQueryExecutor.getInstance().get(SLARegQuery.GET_SLA_REG_ALL, jobId); 205 if (reg != null) { //handle coord rerun with different config without sla 206 slaService.updateRegistrationEvent(reg); 207 } 208 } 209 catch (ServiceException e) { 210 throw new CommandException(ErrorCode.E1007, " id " + jobId, e.getMessage(), e); 211 } 212 213 } 214 215 /* 216 * parentId null 217 */ 218 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, AppType appType, 219 String user, String appName, XLog log) throws CommandException { 220 return createSlaRegistrationEvent(eSla, jobId, null, appType, user, appName, log, false); 221 } 222 223 /* 224 * appName null 225 */ 226 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, String parentId, 227 AppType appType, String user, XLog log) throws CommandException { 228 return createSlaRegistrationEvent(eSla, jobId, parentId, appType, user, null, log, false); 229 } 230 231 /* 232 * parentId + appName null 233 */ 234 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, AppType appType, 235 String user, XLog log) throws CommandException { 236 return createSlaRegistrationEvent(eSla, jobId, null, appType, user, null, log, false); 237 } 238 239 /* 240 * default disableAlert flag 241 */ 242 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, String parentId, 243 AppType appType, String user, String appName, XLog log, boolean rerun) throws CommandException { 244 return createSlaRegistrationEvent(eSla, jobId, null, appType, user, appName, log, rerun, false); 245 } 246 247 public static String getTagElement(Element elem, String tagName) { 248 if (elem != null && elem.getChild(tagName, elem.getNamespace("sla")) != null) { 249 return elem.getChild(tagName, elem.getNamespace("sla")).getText().trim(); 250 } 251 else { 252 return null; 253 } 254 } 255 256}