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 { 129 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303, 130 RestConstants.ACTION_PARAM, action); 131 } 132 } 133 134 /** 135 * Validate the configuration user/group. <p/> 136 * 137 * @param requestUser user in request. 138 * @param conf configuration. 139 * @throws XServletException thrown if the configuration does not have a property {@link 140 * org.apache.oozie.client.OozieClient#USER_NAME}. 141 */ 142 static void checkAuthorizationForApp(String requestUser, Configuration conf) throws XServletException { 143 String user = conf.get(OozieClient.USER_NAME); 144 String group = conf.get(OozieClient.GROUP_NAME); 145 try { 146 if (user == null) { 147 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, OozieClient.USER_NAME); 148 } 149 if (!requestUser.equals(UNDEF) && !user.equals(requestUser)) { 150 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0400, requestUser, user); 151 } 152 AuthorizationService auth = Services.get().get(AuthorizationService.class); 153 if (group == null) { 154 group = auth.getDefaultGroup(user); 155 conf.set(OozieClient.GROUP_NAME, group); 156 } 157 else { 158 auth.authorizeForGroup(user, group); 159 } 160 XLog.Info.get().setParameter(XLogService.GROUP, group); 161 String wfPath = conf.get(OozieClient.APP_PATH); 162 String coordPath = conf.get(OozieClient.COORDINATOR_APP_PATH); 163 if (wfPath == null && coordPath == null) { 164 String libPath = conf.get(OozieClient.LIBPATH); 165 conf.set(OozieClient.APP_PATH, libPath); 166 wfPath = libPath; 167 } 168 ServletUtilities.ValidateAppPath(wfPath, coordPath); 169 170 if (wfPath != null) { 171 auth.authorizeForApp(user, group, wfPath, "workflow.xml", conf); 172 } 173 else { 174 auth.authorizeForApp(user, group, coordPath, "coordinator.xml", conf); 175 } 176 } 177 catch (AuthorizationException ex) { 178 XLog.getLog(BaseJobServlet.class).info("AuthorizationException ", ex); 179 throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex); 180 } 181 } 182 183 /** 184 * Return information about jobs. 185 */ 186 @Override 187 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 188 String jobId = getResourceName(request); 189 String show = request.getParameter(RestConstants.JOB_SHOW_PARAM); 190 191 try { 192 AuthorizationService auth = Services.get().get(AuthorizationService.class); 193 auth.authorizeForJob(getUser(request), jobId, false); 194 } 195 catch (AuthorizationException ex) { 196 throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex); 197 } 198 199 if (show == null || show.equals(RestConstants.JOB_SHOW_INFO)) { 200 stopCron(); 201 JsonBean job = null; 202 try { 203 job = getJob(request, response); 204 } 205 catch (BaseEngineException e) { 206 // TODO Auto-generated catch block 207 // e.printStackTrace(); 208 209 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, e); 210 } 211 startCron(); 212 sendJsonResponse(response, HttpServletResponse.SC_OK, job); 213 } 214 else if (show.equals(RestConstants.JOB_SHOW_LOG)) { 215 response.setContentType(TEXT_UTF8); 216 streamJobLog(request, response); 217 } 218 else if (show.equals(RestConstants.JOB_SHOW_DEFINITION)) { 219 stopCron(); 220 response.setContentType(XML_UTF8); 221 String wfDefinition = getJobDefinition(request, response); 222 startCron(); 223 response.setStatus(HttpServletResponse.SC_OK); 224 response.getWriter().write(wfDefinition); 225 } 226 else { 227 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303, 228 RestConstants.JOB_SHOW_PARAM, show); 229 } 230 } 231 232 /** 233 * abstract method to start a job, either workflow or coordinator 234 * 235 * @param request 236 * @param response 237 * @throws XServletException 238 * @throws IOException TODO 239 */ 240 abstract void startJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 241 IOException; 242 243 /** 244 * abstract method to resume a job, either workflow or coordinator 245 * 246 * @param request 247 * @param response 248 * @throws XServletException 249 * @throws IOException TODO 250 */ 251 abstract void resumeJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 252 IOException; 253 254 /** 255 * abstract method to suspend a job, either workflow or coordinator 256 * 257 * @param request 258 * @param response 259 * @throws XServletException 260 * @throws IOException TODO 261 */ 262 abstract void suspendJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 263 IOException; 264 265 /** 266 * abstract method to kill a job, either workflow or coordinator 267 * 268 * @param request 269 * @param response 270 * @throws XServletException 271 * @throws IOException TODO 272 */ 273 abstract void killJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 274 IOException; 275 276 /** 277 * abstract method to change a coordinator job 278 * 279 * @param request 280 * @param response 281 * @throws XServletException 282 * @throws IOException TODO 283 */ 284 abstract void changeJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 285 IOException; 286 287 /** 288 * abstract method to re-run a job, either workflow or coordinator 289 * 290 * @param request 291 * @param response 292 * @param conf 293 * @throws XServletException 294 * @throws IOException TODO 295 */ 296 abstract JSONObject reRunJob(HttpServletRequest request, HttpServletResponse response, Configuration conf) 297 throws XServletException, IOException; 298 299 /** 300 * abstract method to get a job, either workflow or coordinator, in JsonBean representation 301 * 302 * @param request 303 * @param response 304 * @return JsonBean representation of a job, either workflow or coordinator 305 * @throws XServletException 306 * @throws IOException TODO 307 * @throws BaseEngineException 308 */ 309 abstract JsonBean getJob(HttpServletRequest request, HttpServletResponse response) throws XServletException, 310 IOException, BaseEngineException; 311 312 /** 313 * abstract method to get definition of a job, either workflow or coordinator 314 * 315 * @param request 316 * @param response 317 * @return job, either workflow or coordinator, definition in string format 318 * @throws XServletException 319 * @throws IOException TODO 320 */ 321 abstract String getJobDefinition(HttpServletRequest request, HttpServletResponse response) 322 throws XServletException, IOException; 323 324 /** 325 * abstract method to get and stream log information of job, either workflow or coordinator 326 * 327 * @param request 328 * @param response 329 * @throws XServletException 330 * @throws IOException 331 */ 332 abstract void streamJobLog(HttpServletRequest request, HttpServletResponse response) throws XServletException, 333 IOException; 334 335 }