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.service; 020 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.util.StringUtils; 023import org.apache.oozie.action.control.EndActionExecutor; 024import org.apache.oozie.action.control.ForkActionExecutor; 025import org.apache.oozie.action.control.JoinActionExecutor; 026import org.apache.oozie.action.control.KillActionExecutor; 027import org.apache.oozie.action.control.StartActionExecutor; 028import org.apache.oozie.command.wf.ReRunXCommand; 029 030import org.apache.oozie.client.WorkflowAction; 031import org.apache.oozie.WorkflowActionBean; 032import org.apache.oozie.WorkflowJobBean; 033import org.apache.oozie.ErrorCode; 034import org.apache.oozie.workflow.WorkflowException; 035import org.apache.oozie.workflow.WorkflowInstance; 036import org.apache.oozie.workflow.lite.ActionNodeHandler; 037import org.apache.oozie.workflow.lite.ControlNodeHandler; 038import org.apache.oozie.workflow.lite.DecisionNodeHandler; 039import org.apache.oozie.workflow.lite.EndNodeDef; 040import org.apache.oozie.workflow.lite.ForkNodeDef; 041import org.apache.oozie.workflow.lite.JoinNodeDef; 042import org.apache.oozie.workflow.lite.KillNodeDef; 043import org.apache.oozie.workflow.lite.NodeDef; 044import org.apache.oozie.workflow.lite.NodeHandler; 045import org.apache.oozie.util.XLog; 046import org.apache.oozie.util.XmlUtils; 047import org.apache.oozie.workflow.lite.StartNodeDef; 048import org.jdom.Element; 049import org.jdom.JDOMException; 050 051import java.util.ArrayList; 052import java.util.Collection; 053import java.util.HashSet; 054import java.util.List; 055import java.util.Set; 056 057public abstract class LiteWorkflowStoreService extends WorkflowStoreService { 058 059 public static final String CONF_PREFIX = Service.CONF_PREFIX + "LiteWorkflowStoreService."; 060 public static final String CONF_PREFIX_USER_RETRY = CONF_PREFIX + "user.retry."; 061 public static final String CONF_USER_RETRY_MAX = CONF_PREFIX_USER_RETRY + "max"; 062 public static final String CONF_USER_RETRY_INTEVAL = CONF_PREFIX_USER_RETRY + "inteval"; 063 public static final String CONF_USER_RETRY_ERROR_CODE = CONF_PREFIX_USER_RETRY + "error.code"; 064 public static final String CONF_USER_RETRY_ERROR_CODE_EXT = CONF_PREFIX_USER_RETRY + "error.code.ext"; 065 066 public static final String NODE_DEF_VERSION_0 = "_oozie_inst_v_0"; 067 public static final String NODE_DEF_VERSION_1 = "_oozie_inst_v_1"; 068 public static final String CONF_NODE_DEF_VERSION = CONF_PREFIX + "node.def.version"; 069 070 public static final String USER_ERROR_CODE_ALL = "ALL"; 071 072 /** 073 * Delegation method used by the Action and Decision {@link NodeHandler} on start. <p/> This method provides the 074 * necessary information to create ActionExecutors. 075 * 076 * @param context NodeHandler context. 077 * @param actionType the action type. 078 * @throws WorkflowException thrown if there was an error parsing the action configuration. 079 */ 080 @SuppressWarnings("unchecked") 081 protected static void liteExecute(NodeHandler.Context context, String actionType) throws WorkflowException { 082 XLog log = XLog.getLog(LiteWorkflowStoreService.class); 083 String jobId = context.getProcessInstance().getId(); 084 String nodeName = context.getNodeDef().getName(); 085 String skipVar = context.getProcessInstance().getVar(context.getNodeDef().getName() 086 + WorkflowInstance.NODE_VAR_SEPARATOR + ReRunXCommand.TO_SKIP); 087 boolean skipAction = false; 088 if (skipVar != null) { 089 skipAction = skipVar.equals("true"); 090 } 091 WorkflowActionBean action = new WorkflowActionBean(); 092 String actionId = Services.get().get(UUIDService.class).generateChildId(jobId, nodeName); 093 094 if (!skipAction) { 095 String nodeConf = context.getNodeDef().getConf(); 096 097 if (actionType == null) { 098 try { 099 Element element = XmlUtils.parseXml(nodeConf); 100 actionType = element.getName(); 101 nodeConf = XmlUtils.prettyPrint(element).toString(); 102 } 103 catch (JDOMException ex) { 104 throw new WorkflowException(ErrorCode.E0700, ex.getMessage(), ex); 105 } 106 } 107 log.debug(" Creating action for node [{0}]", nodeName); 108 action.setType(actionType); 109 action.setConf(nodeConf); 110 action.setLogToken(((WorkflowJobBean) context.getTransientVar(WORKFLOW_BEAN)).getLogToken()); 111 action.setStatus(WorkflowAction.Status.PREP); 112 action.setJobId(jobId); 113 } 114 115 String executionPath = context.getExecutionPath(); 116 action.setExecutionPath(executionPath); 117 action.setCred(context.getNodeDef().getCred()); 118 log.debug("Setting action for cred: '"+context.getNodeDef().getCred() + 119 "', name: '"+ context.getNodeDef().getName() + "'"); 120 121 action.setUserRetryCount(0); 122 int userRetryMax = getUserRetryMax(context); 123 int userRetryInterval = getUserRetryInterval(context); 124 action.setUserRetryMax(userRetryMax); 125 action.setUserRetryInterval(userRetryInterval); 126 log.debug("Setting action for userRetryMax: '"+ userRetryMax + 127 "', userRetryInterval: '" + userRetryInterval + 128 "', name: '"+ context.getNodeDef().getName() + "'"); 129 130 action.setName(nodeName); 131 action.setId(actionId); 132 context.setVar(nodeName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_ID, actionId); 133 List list = (List) context.getTransientVar(ACTIONS_TO_START); 134 if (list == null) { 135 list = new ArrayList(); 136 context.setTransientVar(ACTIONS_TO_START, list); 137 } 138 list.add(action); 139 } 140 141 private static int getUserRetryInterval(NodeHandler.Context context) throws WorkflowException { 142 int ret = ConfigurationService.getInt(CONF_USER_RETRY_INTEVAL); 143 String userRetryInterval = context.getNodeDef().getUserRetryInterval(); 144 145 if (!userRetryInterval.equals("null")) { 146 try { 147 ret = Integer.parseInt(userRetryInterval); 148 } 149 catch (NumberFormatException nfe) { 150 throw new WorkflowException(ErrorCode.E0700, nfe.getMessage(), nfe); 151 } 152 } 153 return ret; 154 } 155 156 private static int getUserRetryMax(NodeHandler.Context context) throws WorkflowException { 157 XLog log = XLog.getLog(LiteWorkflowStoreService.class); 158 int ret = ConfigurationService.getInt(CONF_USER_RETRY_MAX); 159 int max = ret; 160 String userRetryMax = context.getNodeDef().getUserRetryMax(); 161 162 if (!userRetryMax.equals("null")) { 163 try { 164 ret = Integer.parseInt(userRetryMax); 165 if (ret > max) { 166 ret = max; 167 log.warn(ErrorCode.E0820.getTemplate(), ret, max); 168 } 169 } 170 catch (NumberFormatException nfe) { 171 throw new WorkflowException(ErrorCode.E0700, nfe.getMessage(), nfe); 172 } 173 } 174 else { 175 ret = 0; 176 } 177 return ret; 178 } 179 180 /** 181 * Get system defined and instance defined error codes for which USER_RETRY is allowed 182 * 183 * @return set of error code user-retry is allowed for 184 */ 185 public static Set<String> getUserRetryErrorCode() { 186 // eliminating whitespaces in the error codes value specification 187 String errorCodeString = ConfigurationService.get(CONF_USER_RETRY_ERROR_CODE).replaceAll("\\s+", ""); 188 Collection<String> strings = StringUtils.getStringCollection(errorCodeString); 189 String errorCodeExtString = ConfigurationService.get(CONF_USER_RETRY_ERROR_CODE_EXT).replaceAll("\\s+", ""); 190 Collection<String> extra = StringUtils.getStringCollection(errorCodeExtString); 191 Set<String> set = new HashSet<String>(); 192 set.addAll(strings); 193 set.addAll(extra); 194 return set; 195 } 196 197 /** 198 * Get NodeDef default version, _oozie_inst_v_0 or _oozie_inst_v_1 199 * 200 * @return nodedef default version 201 * @throws WorkflowException thrown if there was an error parsing the action configuration. 202 */ 203 public static String getNodeDefDefaultVersion() throws WorkflowException { 204 String ret = ConfigurationService.get(CONF_NODE_DEF_VERSION); 205 if (ret == null) { 206 ret = NODE_DEF_VERSION_1; 207 } 208 return ret; 209 } 210 211 /** 212 * Delegation method used when failing actions. <p/> 213 * 214 * @param context NodeHandler context. 215 */ 216 @SuppressWarnings("unchecked") 217 protected static void liteFail(NodeHandler.Context context) { 218 liteTerminate(context, ACTIONS_TO_FAIL); 219 } 220 221 /** 222 * Delegation method used when killing actions. <p/> 223 * 224 * @param context NodeHandler context. 225 */ 226 @SuppressWarnings("unchecked") 227 protected static void liteKill(NodeHandler.Context context) { 228 liteTerminate(context, ACTIONS_TO_KILL); 229 } 230 231 /** 232 * Used to terminate jobs - FAIL or KILL. <p/> 233 * 234 * @param context NodeHandler context. 235 * @param transientVar The transient variable name. 236 */ 237 @SuppressWarnings("unchecked") 238 private static void liteTerminate(NodeHandler.Context context, String transientVar) { 239 List<String> list = (List<String>) context.getTransientVar(transientVar); 240 if (list == null) { 241 list = new ArrayList<String>(); 242 context.setTransientVar(transientVar, list); 243 } 244 list.add(context.getVar(context.getNodeDef().getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_ID)); 245 } 246 247 // wires workflow lib action execution with Oozie Dag 248 public static class LiteActionHandler extends ActionNodeHandler { 249 250 @Override 251 public void start(Context context) throws WorkflowException { 252 liteExecute(context, null); 253 } 254 255 @Override 256 public void end(Context context) { 257 } 258 259 @Override 260 public void kill(Context context) { 261 liteKill(context); 262 } 263 264 @Override 265 public void fail(Context context) { 266 liteFail(context); 267 } 268 } 269 270 // wires workflow lib decision execution with Oozie Dag 271 public static class LiteDecisionHandler extends DecisionNodeHandler { 272 273 @Override 274 public void start(Context context) throws WorkflowException { 275 liteExecute(context, null); 276 } 277 278 @Override 279 public void end(Context context) { 280 } 281 282 @Override 283 public void kill(Context context) { 284 liteKill(context); 285 } 286 287 @Override 288 public void fail(Context context) { 289 liteFail(context); 290 } 291 } 292 293 // wires workflow lib control nodes with Oozie Dag 294 public static class LiteControlNodeHandler extends ControlNodeHandler { 295 296 @Override 297 public void touch(Context context) throws WorkflowException { 298 Class<? extends NodeDef> nodeClass = context.getNodeDef().getClass(); 299 String nodeType; 300 if (nodeClass.equals(StartNodeDef.class)) { 301 nodeType = StartActionExecutor.TYPE; 302 } 303 else if (nodeClass.equals(EndNodeDef.class)) { 304 nodeType = EndActionExecutor.TYPE; 305 } 306 else if (nodeClass.equals(KillNodeDef.class)) { 307 nodeType = KillActionExecutor.TYPE; 308 } 309 else if (nodeClass.equals(ForkNodeDef.class)) { 310 nodeType = ForkActionExecutor.TYPE; 311 } 312 else if (nodeClass.equals(JoinNodeDef.class)) { 313 nodeType = JoinActionExecutor.TYPE; 314 } else { 315 throw new IllegalStateException("Invalid node type: " + nodeClass); 316 } 317 318 liteExecute(context, nodeType); 319 } 320 321 } 322}