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.event.SLAEvent.EventStatus; 027import org.apache.oozie.command.CommandException; 028import org.apache.oozie.executor.jpa.JPAExecutorException; 029import org.apache.oozie.executor.jpa.SLARegistrationQueryExecutor; 030import org.apache.oozie.executor.jpa.SLARegistrationQueryExecutor.SLARegQuery; 031import org.apache.oozie.service.JPAService; 032import org.apache.oozie.service.ServiceException; 033import org.apache.oozie.service.Services; 034import org.apache.oozie.sla.SLARegistrationBean; 035import org.apache.oozie.sla.service.SLAService; 036import org.apache.oozie.util.DateUtils; 037import org.apache.oozie.util.XLog; 038import org.apache.oozie.util.XmlUtils; 039import org.jdom.Element; 040 041public class SLAOperations { 042 043 private static final String NOMINAL_TIME = "nominal-time"; 044 private static final String SHOULD_START = "should-start"; 045 private static final String SHOULD_END = "should-end"; 046 private static final String MAX_DURATION = "max-duration"; 047 private static final String ALERT_EVENTS = "alert-events"; 048 049 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, String parentId, 050 AppType appType, String user, String appName, XLog log, boolean rerun) throws CommandException { 051 if (eSla == null || !SLAService.isEnabled()) { 052 log.debug("Not registering SLA for job [{0}]. Sla-Xml null OR SLAService not enabled", jobId); 053 return null; 054 } 055 SLARegistrationBean sla = new SLARegistrationBean(); 056 057 // Setting nominal time 058 String strNominalTime = getTagElement(eSla, NOMINAL_TIME); 059 if (strNominalTime == null || strNominalTime.length() == 0) { 060 throw new CommandException(ErrorCode.E1101, NOMINAL_TIME); 061 } 062 Date nominalTime; 063 try { 064 nominalTime = DateUtils.parseDateOozieTZ(strNominalTime); 065 sla.setNominalTime(nominalTime); 066 } 067 catch (ParseException pex) { 068 throw new CommandException(ErrorCode.E0302, strNominalTime, pex); 069 } 070 071 // Setting expected start time 072 String strExpectedStart = getTagElement(eSla, SHOULD_START); 073 if (strExpectedStart != null) { 074 float expectedStart = Float.parseFloat(strExpectedStart); 075 if (expectedStart < 0) { 076 throw new CommandException(ErrorCode.E0302, strExpectedStart, "for SLA Expected start time"); 077 } 078 else { 079 Date expectedStartTime = new Date(nominalTime.getTime() + (long) (expectedStart * 60 * 1000)); 080 sla.setExpectedStart(expectedStartTime); 081 } 082 } 083 084 // Setting expected end time 085 String strExpectedEnd = getTagElement(eSla, SHOULD_END); 086 if (strExpectedEnd == null || strExpectedEnd.length() == 0) { 087 throw new CommandException(ErrorCode.E1101, SHOULD_END); 088 } 089 float expectedEnd = Float.parseFloat(strExpectedEnd); 090 if (expectedEnd < 0) { 091 throw new CommandException(ErrorCode.E0302, strExpectedEnd, "for SLA Expected end time"); 092 } 093 else { 094 Date expectedEndTime = new Date(nominalTime.getTime() + (long) (expectedEnd * 60 * 1000)); 095 sla.setExpectedEnd(expectedEndTime); 096 } 097 098 // Setting expected duration in milliseconds 099 String expectedDurationStr = getTagElement(eSla, MAX_DURATION); 100 if (expectedDurationStr != null && expectedDurationStr.length() > 0) { 101 float expectedDuration = Float.parseFloat(expectedDurationStr); 102 if (expectedDuration > 0) { 103 sla.setExpectedDuration((long) (expectedDuration * 60 * 1000)); 104 } 105 } 106 else if (sla.getExpectedStart() != null) { 107 sla.setExpectedDuration(sla.getExpectedEnd().getTime() - sla.getExpectedStart().getTime()); 108 } 109 110 // Parse desired alert-types i.e. start-miss, end-miss, start-met etc.. 111 String alertEvents = getTagElement(eSla, ALERT_EVENTS); 112 if (alertEvents != null) { 113 String events[] = alertEvents.split(","); 114 StringBuilder alertsStr = new StringBuilder(); 115 for (int i = 0; i < events.length; i++) { 116 String event = events[i].trim().toUpperCase(); 117 try { 118 EventStatus.valueOf(event); 119 } 120 catch (IllegalArgumentException iae) { 121 XLog.getLog(SLAService.class).warn( 122 "Invalid value: [" + event + "]" + " for SLA Alert-event. Should be one of " 123 + EventStatus.values() + ". Setting it to default [" + EventStatus.END_MISS.name() 124 + "]"); 125 event = EventStatus.END_MISS.name(); 126 } 127 alertsStr.append(event).append(","); 128 } 129 sla.setAlertEvents(alertsStr.toString().substring(0, alertsStr.lastIndexOf(","))); 130 } 131 132 // Other sla config 133 sla.setNotificationMsg(getTagElement(eSla, "notification-msg")); 134 sla.setAlertContact(getTagElement(eSla, "alert-contact")); 135 sla.setUpstreamApps(getTagElement(eSla, "upstream-apps")); 136 137 // Oozie defined 138 sla.setId(jobId); 139 sla.setAppType(appType); 140 sla.setAppName(appName); 141 sla.setUser(user); 142 sla.setParentId(parentId); 143 144 SLAService slaService = Services.get().get(SLAService.class); 145 try { 146 if (!rerun) { 147 slaService.addRegistrationEvent(sla); 148 } 149 else { 150 slaService.updateRegistrationEvent(sla); 151 } 152 } 153 catch (ServiceException e) { 154 throw new CommandException(ErrorCode.E1007, " id " + jobId, e.getMessage(), e); 155 } 156 157 log.debug("Job [{0}] reg for SLA. Size of Sla Xml = [{1}]", jobId, XmlUtils.prettyPrint(eSla).toString().length()); 158 return sla; 159 } 160 161 /** 162 * Retrieve registration event 163 * @param jobId the jobId 164 * @throws CommandException 165 * @throws JPAExecutorException 166 */ 167 public static void updateRegistrationEvent(String jobId) throws CommandException, JPAExecutorException { 168 JPAService jpaService = Services.get().get(JPAService.class); 169 SLAService slaService = Services.get().get(SLAService.class); 170 try { 171 SLARegistrationBean reg = SLARegistrationQueryExecutor.getInstance().get(SLARegQuery.GET_SLA_REG_ALL, jobId); 172 if (reg != null) { //handle coord rerun with different config without sla 173 slaService.updateRegistrationEvent(reg); 174 } 175 } 176 catch (ServiceException e) { 177 throw new CommandException(ErrorCode.E1007, " id " + jobId, e.getMessage(), e); 178 } 179 180 } 181 182 /* 183 * parentId null 184 */ 185 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, AppType appType, 186 String user, String appName, XLog log) throws CommandException { 187 return createSlaRegistrationEvent(eSla, jobId, null, appType, user, appName, log, false); 188 } 189 190 /* 191 * appName null 192 */ 193 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, String parentId, 194 AppType appType, String user, XLog log) throws CommandException { 195 return createSlaRegistrationEvent(eSla, jobId, parentId, appType, user, null, log, false); 196 } 197 198 /* 199 * parentId + appName null 200 */ 201 public static SLARegistrationBean createSlaRegistrationEvent(Element eSla, String jobId, AppType appType, 202 String user, XLog log) throws CommandException { 203 return createSlaRegistrationEvent(eSla, jobId, null, appType, user, null, log, false); 204 } 205 206 private static String getTagElement(Element elem, String tagName) { 207 if (elem != null && elem.getChild(tagName, elem.getNamespace("sla")) != null) { 208 return elem.getChild(tagName, elem.getNamespace("sla")).getText().trim(); 209 } 210 else { 211 return null; 212 } 213 } 214 215}