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.client; 020 021import java.io.BufferedReader; 022import java.io.File; 023import java.io.FileReader; 024import java.io.IOException; 025import java.io.InputStreamReader; 026import java.net.HttpURLConnection; 027import java.util.Properties; 028 029import org.apache.oozie.cli.OozieCLI; 030import org.apache.oozie.client.rest.JsonTags; 031import org.apache.oozie.client.rest.RestConstants; 032import org.json.simple.JSONObject; 033import org.json.simple.JSONValue; 034 035public class XOozieClient extends OozieClient { 036 public static final String RM = "yarn.resourcemanager.address"; 037 public static final String NN = "fs.default.name"; 038 public static final String NN_2 = "fs.defaultFS"; 039 040 public static final String PIG_SCRIPT = "oozie.pig.script"; 041 042 public static final String PIG_OPTIONS = "oozie.pig.options"; 043 044 public static final String PIG_SCRIPT_PARAMS = "oozie.pig.script.params"; 045 046 public static final String HIVE_SCRIPT = "oozie.hive.script"; 047 048 public static final String HIVE_OPTIONS = "oozie.hive.options"; 049 050 public static final String HIVE_SCRIPT_PARAMS = "oozie.hive.script.params"; 051 052 public static final String SQOOP_COMMAND = "oozie.sqoop.command"; 053 054 public static final String SQOOP_OPTIONS = "oozie.sqoop.options"; 055 056 public static final String FILES = "oozie.files"; 057 058 public static final String ARCHIVES = "oozie.archives"; 059 060 public static final String IS_PROXY_SUBMISSION = "oozie.proxysubmission"; 061 062 protected XOozieClient() { 063 } 064 065 /** 066 * Create an eXtended Workflow client instance. 067 * 068 * @param oozieUrl URL of the Oozie instance it will interact with. 069 */ 070 public XOozieClient(String oozieUrl) { 071 super(oozieUrl); 072 } 073 074 private String readScript(String script) throws IOException { 075 if (!new File(script).exists()) { 076 throw new IOException("Error: script file [" + script + "] does not exist"); 077 } 078 079 BufferedReader br = null; 080 try { 081 br = new BufferedReader(new FileReader(script)); 082 StringBuilder sb = new StringBuilder(); 083 String line; 084 while ((line = br.readLine()) != null) { 085 sb.append(line + "\n"); 086 } 087 return sb.toString(); 088 } 089 finally { 090 try { 091 br.close(); 092 } 093 catch (IOException ex) { 094 System.err.println("Error: " + ex.getMessage()); 095 } 096 } 097 } 098 099 private String serializeSqoopCommand(String[] command) { 100 StringBuilder sb = new StringBuilder(); 101 for (String arg : command) { 102 sb.append(arg).append("\n"); 103 } 104 return sb.toString(); 105 } 106 107 static void setStrings(Properties conf, String key, String[] values) { 108 if (values != null) { 109 conf.setProperty(key + ".size", (new Integer(values.length)).toString()); 110 for (int i = 0; i < values.length; i++) { 111 conf.setProperty(key + "." + i, values[i]); 112 } 113 } 114 } 115 116 private void validateHttpSubmitConf(Properties conf) { 117 String RM = conf.getProperty(XOozieClient.RM); 118 if (RM == null) { 119 throw new RuntimeException("Resource manager is not specified in conf"); 120 } 121 122 String NN = conf.getProperty(XOozieClient.NN); 123 String NN_2 = conf.getProperty(XOozieClient.NN_2); 124 if (NN == null) { 125 if(NN_2 == null) { 126 throw new RuntimeException("namenode is not specified in conf"); 127 } else { 128 NN = NN_2; 129 } 130 } 131 132 String libPath = conf.getProperty(LIBPATH); 133 if (libPath == null) { 134 throw new RuntimeException("libpath is not specified in conf"); 135 } 136 if (!libPath.contains(":/")) { 137 String newLibPath; 138 if (libPath.startsWith("/")) { 139 if(NN.endsWith("/")) { 140 newLibPath = NN + libPath.substring(1); 141 } else { 142 newLibPath = NN + libPath; 143 } 144 } else { 145 throw new RuntimeException("libpath should be absolute"); 146 } 147 conf.setProperty(LIBPATH, newLibPath); 148 } 149 150 conf.setProperty(IS_PROXY_SUBMISSION, "true"); 151 } 152 153 /** 154 * Submit a Pig job via HTTP. 155 * 156 * @param conf job configuration. 157 * @param pigScriptFile pig script file. 158 * @param pigArgs pig arguments string. 159 * @return the job Id. 160 * @throws java.io.IOException thrown if there is a problem with pig script file. 161 * @throws OozieClientException thrown if the job could not be submitted. 162 */ 163 @Deprecated 164 public String submitPig(Properties conf, String pigScriptFile, String[] pigArgs) throws IOException, OozieClientException { 165 return submitScriptLanguage(conf, pigScriptFile, pigArgs, OozieCLI.PIG_CMD); 166 } 167 168 /** 169 * Submit a Pig or Hive job via HTTP. 170 * 171 * @param conf job configuration. 172 * @param scriptFile script file. 173 * @param args arguments string. 174 * @param jobType job type. 175 * @return the job Id. 176 * @throws java.io.IOException thrown if there is a problem with script file. 177 * @throws OozieClientException thrown if the job could not be submitted. 178 */ 179 public String submitScriptLanguage(Properties conf, String scriptFile, String[] args, String jobType) 180 throws IOException, OozieClientException { 181 return submitScriptLanguage(conf, scriptFile, args, null, jobType); 182 } 183 184 /** 185 * Submit a Pig or Hive job via HTTP. 186 * 187 * @param conf job configuration. 188 * @param scriptFile script file. 189 * @param args arguments string. 190 * @param params parameters string. 191 * @param jobType job type. 192 * @return the job Id. 193 * @throws java.io.IOException thrown if there is a problem with file. 194 * @throws OozieClientException thrown if the job could not be submitted. 195 */ 196 public String submitScriptLanguage(Properties conf, String scriptFile, String[] args, String[] params, 197 String jobType) 198 throws IOException, OozieClientException { 199 OozieClient.notNull(conf, "conf"); 200 OozieClient.notNull(scriptFile, "scriptFile"); 201 validateHttpSubmitConf(conf); 202 203 String script = ""; 204 String options = ""; 205 String scriptParams = ""; 206 207 if (jobType.equals(OozieCLI.HIVE_CMD)) { 208 script = XOozieClient.HIVE_SCRIPT; 209 options = XOozieClient.HIVE_OPTIONS; 210 scriptParams = XOozieClient.HIVE_SCRIPT_PARAMS; 211 } 212 else if (jobType.equals(OozieCLI.PIG_CMD)) { 213 script = XOozieClient.PIG_SCRIPT; 214 options = XOozieClient.PIG_OPTIONS; 215 scriptParams = XOozieClient.PIG_SCRIPT_PARAMS; 216 } 217 else { 218 throw new IllegalArgumentException("jobType must be either pig or hive"); 219 } 220 221 conf.setProperty(script, readScript(scriptFile)); 222 setStrings(conf, options, args); 223 setStrings(conf, scriptParams, params); 224 225 return (new HttpJobSubmit(conf, jobType)).call(); 226 } 227 228 /** 229 * Submit a Sqoop job via HTTP. 230 * 231 * @param conf job configuration. 232 * @param command sqoop command to run. 233 * @param args arguments string. 234 * @return the job Id. 235 * @throws OozieClientException thrown if the job could not be submitted. 236 */ 237 public String submitSqoop(Properties conf, String[] command, String[] args) 238 throws OozieClientException { 239 OozieClient.notNull(conf, "conf"); 240 OozieClient.notNull(command, "command"); 241 validateHttpSubmitConf(conf); 242 243 conf.setProperty(XOozieClient.SQOOP_COMMAND, serializeSqoopCommand(command)); 244 setStrings(conf, XOozieClient.SQOOP_OPTIONS, args); 245 246 return (new HttpJobSubmit(conf, OozieCLI.SQOOP_CMD)).call(); 247 } 248 249 /** 250 * Submit a Map/Reduce job via HTTP. 251 * 252 * @param conf job configuration. 253 * @return the job Id. 254 * @throws OozieClientException thrown if the job could not be submitted. 255 */ 256 public String submitMapReduce(Properties conf) throws OozieClientException { 257 OozieClient.notNull(conf, "conf"); 258 validateHttpSubmitConf(conf); 259 260 return (new HttpJobSubmit(conf, "mapreduce")).call(); 261 } 262 263 private class HttpJobSubmit extends ClientCallable<String> { 264 private Properties conf; 265 266 HttpJobSubmit(Properties conf, String jobType) { 267 super("POST", RestConstants.JOBS, "", prepareParams(RestConstants.JOBTYPE_PARAM, jobType)); 268 this.conf = notNull(conf, "conf"); 269 } 270 271 @Override 272 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 273 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 274 writeToXml(conf, conn.getOutputStream()); 275 if (conn.getResponseCode() == HttpURLConnection.HTTP_CREATED) { 276 JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(conn.getInputStream())); 277 return (String) json.get(JsonTags.JOB_ID); 278 } 279 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 280 handleError(conn); 281 } 282 return null; 283 } 284 } 285 286 /** 287 * set LIBPATH for HTTP submission job. 288 * 289 * @param conf Configuration object. 290 * @param pathStr lib HDFS path. 291 */ 292 public void setLib(Properties conf, String pathStr) { 293 conf.setProperty(LIBPATH, pathStr); 294 } 295 296 /** 297 * The equivalent to <file> tag in oozie's workflow xml. 298 * 299 * @param conf Configuration object. 300 * @param file file HDFS path. A "#..." symbolic string can be appended to the path to specify symbolic link name. 301 * For example, "/user/oozie/parameter_file#myparams". If no "#..." is specified, file name will be used as 302 * symbolic link name. 303 */ 304 public void addFile(Properties conf, String file) { 305 OozieClient.notEmpty(file, "file"); 306 String files = conf.getProperty(FILES); 307 conf.setProperty(FILES, files == null ? file : files + "," + file); 308 } 309 310 /** 311 * The equivalent to <archive> tag in oozie's workflow xml. 312 * 313 * @param conf Configuration object. 314 * @param file file HDFS path. A "#..." symbolic string can be appended to the path to specify symbolic link name. 315 * For example, "/user/oozie/udf1.jar#my.jar". If no "#..." is specified, file name will be used as 316 * symbolic link name. 317 */ 318 public void addArchive(Properties conf, String file) { 319 OozieClient.notEmpty(file, "file"); 320 String files = conf.getProperty(ARCHIVES); 321 conf.setProperty(ARCHIVES, files == null ? file : files + "," + file); 322 } 323}