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.servlet; 016 017 import java.io.IOException; 018 import java.util.Arrays; 019 020 import javax.servlet.ServletException; 021 import javax.servlet.http.HttpServletRequest; 022 import javax.servlet.http.HttpServletResponse; 023 024 import org.apache.hadoop.conf.Configuration; 025 import org.apache.hadoop.fs.FileStatus; 026 import org.apache.hadoop.fs.FileSystem; 027 import org.apache.hadoop.fs.Path; 028 import org.apache.oozie.BaseEngineException; 029 import org.apache.oozie.ErrorCode; 030 import org.apache.oozie.client.OozieClient; 031 import org.apache.oozie.client.XOozieClient; 032 import org.apache.oozie.client.rest.JsonBean; 033 import org.apache.oozie.client.rest.RestConstants; 034 import org.apache.oozie.service.AuthorizationException; 035 import org.apache.oozie.service.AuthorizationService; 036 import org.apache.oozie.service.HadoopAccessorException; 037 import org.apache.oozie.service.HadoopAccessorService; 038 import org.apache.oozie.service.Services; 039 import org.apache.oozie.service.XLogService; 040 import org.apache.oozie.util.JobUtils; 041 import org.apache.oozie.util.XConfiguration; 042 import org.apache.oozie.util.XLog; 043 import org.json.simple.JSONObject; 044 045 public abstract class BaseJobServlet extends JsonRestServlet { 046 047 private static final ResourceInfo RESOURCES_INFO[] = new ResourceInfo[1]; 048 049 static { 050 RESOURCES_INFO[0] = new ResourceInfo("*", Arrays.asList("PUT", "GET"), Arrays.asList(new ParameterInfo( 051 RestConstants.ACTION_PARAM, String.class, true, Arrays.asList("PUT")), new ParameterInfo( 052 RestConstants.JOB_SHOW_PARAM, String.class, false, Arrays.asList("GET")))); 053 } 054 055 public BaseJobServlet(String instrumentationName) { 056 super(instrumentationName, RESOURCES_INFO); 057 } 058 059 /** 060 * Perform various job related actions - start, suspend, resume, kill, etc. 061 */ 062 @Override 063 protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 064 String jobId = getResourceName(request); 065 request.setAttribute(AUDIT_PARAM, jobId); 066 request.setAttribute(AUDIT_OPERATION, request.getParameter(RestConstants.ACTION_PARAM)); 067 try { 068 AuthorizationService auth = Services.get().get(AuthorizationService.class); 069 auth.authorizeForJob(getUser(request), jobId, true); 070 } 071 catch (AuthorizationException ex) { 072 throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex); 073 } 074 075 String action = request.getParameter(RestConstants.ACTION_PARAM); 076 if (action.equals(RestConstants.JOB_ACTION_START)) { 077 stopCron(); 078 startJob(request, response); 079 startCron(); 080 response.setStatus(HttpServletResponse.SC_OK); 081 } 082 else if (action.equals(RestConstants.JOB_ACTION_RESUME)) { 083 stopCron(); 084 resumeJob(request, response); 085 startCron(); 086 response.setStatus(HttpServletResponse.SC_OK); 087 } 088 else if (action.equals(RestConstants.JOB_ACTION_SUSPEND)) { 089 stopCron(); 090 suspendJob(request, response); 091 startCron(); 092 response.setStatus(HttpServletResponse.SC_OK); 093 } 094 else if (action.equals(RestConstants.JOB_ACTION_KILL)) { 095 stopCron(); 096 killJob(request, response); 097 startCron(); 098 response.setStatus(HttpServletResponse.SC_OK); 099 } 100 else if (action.equals(RestConstants.JOB_ACTION_CHANGE)) { 101 stopCron(); 102 changeJob(request, response); 103 startCron(); 104 response.setStatus(HttpServletResponse.SC_OK); 105 } 106 else if (action.equals(RestConstants.JOB_ACTION_RERUN)) { 107 validateContentType(request, RestConstants.XML_CONTENT_TYPE); 108 Configuration conf = new XConfiguration(request.getInputStream()); 109 stopCron(); 110 checkAuthorizationForApp(getUser(request), conf); 111 JobUtils.normalizeAppPath(conf.get(OozieClient.USER_NAME), conf.get(OozieClient.GROUP_NAME), conf); 112 reRunJob(request, response, conf); 113 startCron(); 114 response.setStatus(HttpServletResponse.SC_OK); 115 } 116 else if (action.equals(RestConstants.JOB_COORD_ACTION_RERUN)) { 117 validateContentType(request, RestConstants.XML_CONTENT_TYPE); 118 stopCron(); 119 JSONObject json = reRunJob(request, response, null); 120 startCron(); 121 if (json != null) { 122 sendJsonResponse(response, HttpServletResponse.SC_OK, json); 123 } 124 else { 125 response.setStatus(HttpServletResponse.SC_OK); 126 } 127 } 128 else if (action.equals(RestConstants.JOB_BUNDLE_ACTION_RERUN)) { 129 validateContentType(request, RestConstants.XML_CONTENT_TYPE); 130 stopCron(); 131 JSONObject json = reRunJob(request, response, null); 132 startCron(); 133 if (json != null) { 134 sendJsonResponse(response, HttpServletResponse.SC_OK, json); 135 } 136 else { 137 response.setStatus(HttpServletResponse.SC_OK); 138 } 139 } 140 else { 141 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303, 142 RestConstants.ACTION_PARAM, action); 143 } 144 } 145 146 /** 147 * Validate the configuration user/group. <p/> 148 * 149 * @param requestUser user in request. 150 * @param conf configuration. 151 * @throws XServletException thrown if the configuration does not have a property {@link 152 * org.apache.oozie.client.OozieClient#USER_NAME}. 153 */ 154 static void checkAuthorizationForApp(String requestUser, Configuration conf) throws XServletException { 155 String user = conf.get(OozieClient.USER_NAME); 156 String group = conf.get(OozieClient.GROUP_NAME); 157 try { 158 if (user == null) { 159 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, OozieClient.USER_NAME); 160 } 161 if (!requestUser.equals(UNDEF) && !user.equals(requestUser)) { 162 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0400, requestUser, user); 163 } 164 AuthorizationService auth = Services.get().get(AuthorizationService.class); 165 if (group == null) { 166 group = auth.getDefaultGroup(user); 167 conf.set(OozieClient.GROUP_NAME, group); 168 } 169 else { 170 auth.authorizeForGroup(user, group); 171 } 172 XLog.Info.get().setParameter(XLogService.GROUP, group); 173 String wfPath = conf.get(OozieClient.APP_PATH); 174 String coordPath = conf.get(OozieClient.COORDINATOR_APP_PATH); 175 String bundlePath = conf.get(OozieClient.BUNDLE_APP_PATH); 176 177 if (wfPath == null && coordPath == null && bundlePath == null) { 178 String libPath = conf.get(XOozieClient.LIBPATH); 179 conf.set(OozieClient.APP_PATH, libPath); 180 wfPath = libPath; 181 } 182 ServletUtilities.ValidateAppPath(wfPath, coordPath, bundlePath); 183 184 if (wfPath != null) { 185 auth.authorizeForApp(user, group, wfPath, "workflow.xml", conf); 186 } 187 else if (coordPath != null){ 188 auth.authorizeForApp(user, group, coordPath, "coordinator.xml", conf); 189 } 190 else if (bundlePath != null){ 191 auth.authorizeForApp(user, group, bundlePath, "bundle.xml", conf); 192 } 193 } 194 catch (AuthorizationException ex) { 195 XLog.getLog(BaseJobServlet.class).info("AuthorizationException ", ex); 196 throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex); 197 } 198 } 199 200 /** 201 * Return information about jobs. 202 */ 203 @Override 204 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 205 String jobId = getResourceName(request); 206 String show = request.getParameter(RestConstants.JOB_SHOW_PARAM); 207 208 try { 209 AuthorizationService auth = Services.get().get(AuthorizationService.class); 210 auth.authorizeForJob(getUser(request), jobId, false); 211 } 212 catch (AuthorizationException ex) { 213 throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex); 214 } 215 216 if (show == null || show.equals(RestConstants.JOB_SHOW_INFO)) { 217 stopCron(); 218 JsonBean job = null; 219 try { 220 job = getJob(request, response); 221 } 222 catch (BaseEngineException e) { 223 // TODO Auto-generated catch block 224 // e.printStackTrace(); 225 226 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, e); 227 } 228 startCron(); 229 sendJsonResponse(response, HttpServletResponse.SC_OK, job); 230 } 231 else if (show.equals(RestConstants.JOB_SHOW_LOG)) { 232 response.setContentType(TEXT_UTF8); 233 streamJobLog(request, response); 234 } 235 else if (show.equals(RestConstants.JOB_SHOW_DEFINITION)) { 236 stopCron(); 237 response.setContentType(XML_UTF8); 238 String wfDefinition = getJobDefinition(request, response); 239 startCron(); 240 response.setStatus(HttpServletResponse.SC_OK); 241 response.getWriter().write(wfDefinition); 242 } 243 else { 244 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303, 245 RestConstants.JOB_SHOW_PARAM, show); 246 } 247 } 248 249 /** 250 * abstract method to start a job, either workflow or coordinator 251 * 252 * @param request 253 * @param response 254 * @throws XServletException 255 * @throws IOException TODO 256 */ 257 abstract void startJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 258 IOException; 259 260 /** 261 * abstract method to resume a job, either workflow or coordinator 262 * 263 * @param request 264 * @param response 265 * @throws XServletException 266 * @throws IOException TODO 267 */ 268 abstract void resumeJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 269 IOException; 270 271 /** 272 * abstract method to suspend a job, either workflow or coordinator 273 * 274 * @param request 275 * @param response 276 * @throws XServletException 277 * @throws IOException TODO 278 */ 279 abstract void suspendJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 280 IOException; 281 282 /** 283 * abstract method to kill a job, either workflow or coordinator 284 * 285 * @param request 286 * @param response 287 * @throws XServletException 288 * @throws IOException TODO 289 */ 290 abstract void killJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 291 IOException; 292 293 /** 294 * abstract method to change a coordinator job 295 * 296 * @param request 297 * @param response 298 * @throws XServletException 299 * @throws IOException TODO 300 */ 301 abstract void changeJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 302 IOException; 303 304 /** 305 * abstract method to re-run a job, either workflow or coordinator 306 * 307 * @param request 308 * @param response 309 * @param conf 310 * @throws XServletException 311 * @throws IOException TODO 312 */ 313 abstract JSONObject reRunJob(HttpServletRequest request, HttpServletResponse response, Configuration conf) 314 throws XServletException, IOException; 315 316 /** 317 * abstract method to get a job, either workflow or coordinator, in JsonBean representation 318 * 319 * @param request 320 * @param response 321 * @return JsonBean representation of a job, either workflow or coordinator 322 * @throws XServletException 323 * @throws IOException TODO 324 * @throws BaseEngineException 325 */ 326 abstract JsonBean getJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 327 IOException, BaseEngineException; 328 329 /** 330 * abstract method to get definition of a job, either workflow or coordinator 331 * 332 * @param request 333 * @param response 334 * @return job, either workflow or coordinator, definition in string format 335 * @throws XServletException 336 * @throws IOException TODO 337 */ 338 abstract String getJobDefinition(HttpServletRequest request, HttpServletResponse response) 339 throws XServletException, IOException; 340 341 /** 342 * abstract method to get and stream log information of job, either workflow or coordinator 343 * 344 * @param request 345 * @param response 346 * @throws XServletException 347 * @throws IOException 348 */ 349 abstract void streamJobLog(HttpServletRequest request, HttpServletResponse response) throws XServletException, 350 IOException; 351 352 }