001 /** 002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved. 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. See accompanying LICENSE file. 014 */ 015 package org.apache.oozie.command.wf; 016 017 import org.apache.hadoop.conf.Configuration; 018 import org.apache.hadoop.fs.Path; 019 import org.apache.hadoop.fs.FileSystem; 020 import org.apache.oozie.WorkflowJobBean; 021 import org.apache.oozie.ErrorCode; 022 import org.apache.oozie.service.HadoopAccessorException; 023 import org.apache.oozie.service.WorkflowStoreService; 024 import org.apache.oozie.service.WorkflowAppService; 025 import org.apache.oozie.service.HadoopAccessorService; 026 import org.apache.oozie.service.Services; 027 import org.apache.oozie.service.DagXLogInfoService; 028 import org.apache.oozie.util.XLog; 029 import org.apache.oozie.util.ParamChecker; 030 import org.apache.oozie.util.XConfiguration; 031 import org.apache.oozie.util.XmlUtils; 032 import org.apache.oozie.command.Command; 033 import org.apache.oozie.command.CommandException; 034 import org.apache.oozie.command.coord.CoordSubmitCommand; 035 import org.apache.oozie.coord.CoordELFunctions; 036 import org.apache.oozie.coord.CoordinatorJobException; 037 import org.apache.oozie.service.ELService; 038 import org.apache.oozie.service.SchemaService; 039 import org.apache.oozie.service.WorkflowAppService; 040 import org.apache.oozie.service.DagXLogInfoService; 041 import org.apache.oozie.service.WorkflowStoreService; 042 import org.apache.oozie.store.StoreException; 043 import org.apache.oozie.store.Store; 044 import org.apache.oozie.store.WorkflowStore; 045 import org.apache.oozie.workflow.WorkflowApp; 046 import org.apache.oozie.workflow.WorkflowException; 047 import org.apache.oozie.workflow.WorkflowInstance; 048 import org.apache.oozie.workflow.WorkflowLib; 049 import org.apache.oozie.util.ELEvaluator; 050 import org.apache.oozie.util.ParamChecker; 051 import org.apache.oozie.util.PropertiesUtils; 052 import org.apache.oozie.util.XLog; 053 import org.apache.oozie.util.XmlUtils; 054 import org.apache.oozie.util.XConfiguration; 055 import org.apache.oozie.util.db.SLADbOperations; 056 import org.apache.oozie.service.Services; 057 import org.apache.oozie.service.SchemaService.SchemaName; 058 import org.apache.oozie.client.OozieClient; 059 import org.apache.oozie.client.WorkflowJob; 060 import org.apache.oozie.client.SLAEvent.SlaAppType; 061 import org.jdom.Element; 062 import org.jdom.JDOMException; 063 import org.jdom.Namespace; 064 065 import java.util.Date; 066 import java.util.List; 067 import java.util.Map; 068 import java.util.Set; 069 import java.util.HashSet; 070 import java.util.Map; 071 import java.io.IOException; 072 073 public class SubmitCommand extends WorkflowCommand<String> { 074 public static final String CONFIG_DEFAULT = "config-default.xml"; 075 076 private Configuration conf; 077 private String authToken; 078 079 public SubmitCommand(Configuration conf, String authToken) { 080 super("submit", "submit", 1, XLog.STD); 081 this.conf = ParamChecker.notNull(conf, "conf"); 082 this.authToken = ParamChecker.notEmpty(authToken, "authToken"); 083 } 084 085 private static final Set<String> DISALLOWED_DEFAULT_PROPERTIES = new HashSet<String>(); 086 private static final Set<String> DISALLOWED_USER_PROPERTIES = new HashSet<String>(); 087 088 static { 089 String[] badUserProps = {PropertiesUtils.DAYS, PropertiesUtils.HOURS, PropertiesUtils.MINUTES, 090 PropertiesUtils.KB, PropertiesUtils.MB, PropertiesUtils.GB, PropertiesUtils.TB, PropertiesUtils.PB, 091 PropertiesUtils.RECORDS, PropertiesUtils.MAP_IN, PropertiesUtils.MAP_OUT, PropertiesUtils.REDUCE_IN, 092 PropertiesUtils.REDUCE_OUT, PropertiesUtils.GROUPS}; 093 PropertiesUtils.createPropertySet(badUserProps, DISALLOWED_USER_PROPERTIES); 094 095 String[] badDefaultProps = {PropertiesUtils.HADOOP_USER, PropertiesUtils.HADOOP_UGI, 096 WorkflowAppService.HADOOP_JT_KERBEROS_NAME, WorkflowAppService.HADOOP_NN_KERBEROS_NAME}; 097 PropertiesUtils.createPropertySet(badUserProps, DISALLOWED_DEFAULT_PROPERTIES); 098 PropertiesUtils.createPropertySet(badDefaultProps, DISALLOWED_DEFAULT_PROPERTIES); 099 } 100 101 @Override 102 protected String call(WorkflowStore store) throws StoreException, CommandException { 103 incrJobCounter(1); 104 WorkflowAppService wps = Services.get().get(WorkflowAppService.class); 105 try { 106 XLog.Info.get().setParameter(DagXLogInfoService.TOKEN, conf.get(OozieClient.LOG_TOKEN)); 107 WorkflowApp app = wps.parseDef(conf, authToken); 108 XConfiguration protoActionConf = wps.createProtoActionConf(conf, authToken, true); 109 WorkflowLib workflowLib = Services.get().get(WorkflowStoreService.class).getWorkflowLibWithNoDB(); 110 111 Path configDefault = new Path(new Path(conf.get(OozieClient.APP_PATH)).getParent(), CONFIG_DEFAULT); 112 String user = conf.get(OozieClient.USER_NAME); 113 String group = conf.get(OozieClient.GROUP_NAME); 114 FileSystem fs = Services.get().get(HadoopAccessorService.class).createFileSystem(user, group, 115 configDefault.toUri(), new Configuration()); 116 117 if (fs.exists(configDefault)) { 118 try { 119 Configuration defaultConf = new XConfiguration(fs.open(configDefault)); 120 PropertiesUtils.checkDisallowedProperties(defaultConf, DISALLOWED_DEFAULT_PROPERTIES); 121 XConfiguration.injectDefaults(defaultConf, conf); 122 } 123 catch (IOException ex) { 124 throw new IOException("default configuration file, " + ex.getMessage(), ex); 125 } 126 } 127 128 PropertiesUtils.checkDisallowedProperties(conf, DISALLOWED_USER_PROPERTIES); 129 130 // Resolving all variables in the job properties. 131 // This ensures the Hadoop Configuration semantics is preserved. 132 XConfiguration resolvedVarsConf = new XConfiguration(); 133 for (Map.Entry<String, String> entry : conf) { 134 resolvedVarsConf.set(entry.getKey(), conf.get(entry.getKey())); 135 } 136 conf = resolvedVarsConf; 137 138 WorkflowInstance wfInstance; 139 try { 140 wfInstance = workflowLib.createInstance(app, conf); 141 } 142 catch (WorkflowException e) { 143 throw new StoreException(e); 144 } 145 146 Configuration conf = wfInstance.getConf(); 147 // System.out.println("WF INSTANCE CONF:"); 148 // System.out.println(XmlUtils.prettyPrint(conf).toString()); 149 150 WorkflowJobBean workflow = new WorkflowJobBean(); 151 workflow.setId(wfInstance.getId()); 152 workflow.setAppName(app.getName()); 153 workflow.setAppPath(conf.get(OozieClient.APP_PATH)); 154 workflow.setConf(XmlUtils.prettyPrint(conf).toString()); 155 workflow.setProtoActionConf(protoActionConf.toXmlString()); 156 workflow.setCreatedTime(new Date()); 157 workflow.setLastModifiedTime(new Date()); 158 workflow.setLogToken(conf.get(OozieClient.LOG_TOKEN, "")); 159 workflow.setStatus(WorkflowJob.Status.PREP); 160 workflow.setRun(0); 161 workflow.setUser(conf.get(OozieClient.USER_NAME)); 162 workflow.setGroup(conf.get(OozieClient.GROUP_NAME)); 163 workflow.setAuthToken(authToken); 164 workflow.setWorkflowInstance(wfInstance); 165 workflow.setExternalId(conf.get(OozieClient.EXTERNAL_ID)); 166 167 setLogInfo(workflow); 168 Element wfElem = XmlUtils.parseXml(app.getDefinition()); 169 ELEvaluator evalSla = createELEvaluatorForGroup(conf, "wf-sla-submit"); 170 String jobSlaXml = verifySlaElements(wfElem, evalSla); 171 writeSLARegistration(jobSlaXml, workflow.getId(), workflow.getUser(), workflow.getGroup(), store); 172 workflow.setSlaXml(jobSlaXml); 173 // System.out.println("SlaXml :"+ slaXml); 174 175 store.insertWorkflow(workflow); 176 177 // Configuration conf1 = workflow.getWorkflowInstance().getConf(); 178 // System.out.println("WF1 INSTANCE CONF:"); 179 // System.out.println(XmlUtils.prettyPrint(conf1).toString()); 180 // Add WF_JOB SLA Registration event 181 182 return workflow.getId(); 183 } 184 catch (WorkflowException ex) { 185 throw new CommandException(ex); 186 } 187 catch (HadoopAccessorException ex) { 188 throw new CommandException(ex); 189 } 190 catch (Exception ex) { 191 throw new CommandException(ErrorCode.E0803, ex); 192 } 193 } 194 195 private String verifySlaElements(Element eWfJob, ELEvaluator evalSla) throws CommandException { 196 String jobSlaXml = ""; 197 // String prefix = XmlUtils.getNamespacePrefix(eWfJob, 198 // SchemaService.SLA_NAME_SPACE_URI); 199 // Validate WF job 200 Element eSla = eWfJob.getChild("info", Namespace.getNamespace(SchemaService.SLA_NAME_SPACE_URI)); 201 if (eSla != null) { 202 jobSlaXml = resolveSla(eSla, evalSla); 203 } 204 205 // Validate all actions 206 for (Element action : (List<Element>) eWfJob.getChildren("action", eWfJob.getNamespace())) { 207 eSla = action.getChild("info", Namespace.getNamespace(SchemaService.SLA_NAME_SPACE_URI)); 208 if (eSla != null) { 209 resolveSla(eSla, evalSla); 210 } 211 } 212 return jobSlaXml; 213 } 214 215 private void writeSLARegistration(String slaXml, String id, String user, String group, Store store) 216 throws CommandException { 217 try { 218 if (slaXml != null && slaXml.length() > 0) { 219 Element eSla = XmlUtils.parseXml(slaXml); 220 SLADbOperations.writeSlaRegistrationEvent(eSla, store, id, SlaAppType.WORKFLOW_JOB, user, group); 221 } 222 } 223 catch (Exception e) { 224 // TODO Auto-generated catch block 225 e.printStackTrace(); 226 throw new CommandException(ErrorCode.E1007, "workflow " + id, e); 227 } 228 } 229 230 public static String resolveSla(Element eSla, ELEvaluator evalSla) throws CommandException { 231 // EL evaluation 232 String slaXml = XmlUtils.prettyPrint(eSla).toString(); 233 try { 234 slaXml = XmlUtils.removeComments(slaXml); 235 slaXml = evalSla.evaluate(slaXml, String.class); 236 XmlUtils.validateData(slaXml, SchemaName.SLA_ORIGINAL); 237 return slaXml; 238 } 239 catch (Exception e) { 240 throw new CommandException(ErrorCode.E1004, "Validation erro :" + e.getMessage(), e); 241 } 242 } 243 244 public static ELEvaluator createELEvaluatorForGroup(Configuration conf, String group) { 245 ELEvaluator eval = Services.get().get(ELService.class).createEvaluator(group); 246 for (Map.Entry<String, String> entry : conf) { 247 eval.setVariable(entry.getKey(), entry.getValue()); 248 } 249 return eval; 250 } 251 252 }