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