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