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    import java.util.List;
020    
021    import javax.servlet.ServletException;
022    import javax.servlet.http.HttpServletRequest;
023    import javax.servlet.http.HttpServletResponse;
024    
025    import org.apache.hadoop.conf.Configuration;
026    import org.apache.oozie.BaseEngineException;
027    import org.apache.oozie.CoordinatorActionBean;
028    import org.apache.oozie.CoordinatorActionInfo;
029    import org.apache.oozie.CoordinatorEngine;
030    import org.apache.oozie.DagEngine;
031    import org.apache.oozie.DagEngineException;
032    import org.apache.oozie.ErrorCode;
033    import org.apache.oozie.client.OozieClient;
034    import org.apache.oozie.client.rest.JsonTags;
035    import org.apache.oozie.client.rest.JsonWorkflowJob;
036    import org.apache.oozie.client.rest.RestConstants;
037    import org.apache.oozie.service.AuthorizationException;
038    import org.apache.oozie.service.AuthorizationService;
039    import org.apache.oozie.service.CoordinatorEngineService;
040    import org.apache.oozie.service.DagEngineService;
041    import org.apache.oozie.service.Services;
042    import org.apache.oozie.service.XLogService;
043    import org.apache.oozie.util.XConfiguration;
044    import org.apache.oozie.util.XLog;
045    import org.json.simple.JSONObject;
046    
047    public class JobServlet extends JsonRestServlet {
048        private static final String INSTRUMENTATION_NAME = "job";
049    
050        private static final ResourceInfo RESOURCES_INFO[] = new ResourceInfo[1];
051    
052        static {
053            RESOURCES_INFO[0] = new ResourceInfo("*", Arrays.asList("PUT", "GET"), Arrays.asList(new ParameterInfo(
054                    RestConstants.ACTION_PARAM, String.class, true, Arrays.asList("PUT")), new ParameterInfo(
055                    RestConstants.JOB_SHOW_PARAM, String.class, false, Arrays.asList("GET"))));
056        }
057    
058        public JobServlet() {
059            super(INSTRUMENTATION_NAME, RESOURCES_INFO);
060        }
061    
062        /**
063         * Perform various job related actions - start, suspend, resume, kill, etc.
064         */
065        @SuppressWarnings("unchecked")
066        @Override
067        protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
068            String jobId = getResourceName(request);
069            request.setAttribute(AUDIT_PARAM, jobId);
070            request.setAttribute(AUDIT_OPERATION, request.getParameter(RestConstants.ACTION_PARAM));
071            try {
072                AuthorizationService auth = Services.get().get(AuthorizationService.class);
073                auth.authorizeForJob(getUser(request), jobId, true);
074            }
075            catch (AuthorizationException ex) {
076                throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex);
077            }
078    
079            DagEngine dagEngine = Services.get().get(DagEngineService.class).getDagEngine(getUser(request),
080                                                                                          getAuthToken(request));
081            CoordinatorEngine coordEngine = Services.get().get(CoordinatorEngineService.class).getCoordinatorEngine(
082                    getUser(request), getAuthToken(request));
083            try {
084                String action = request.getParameter(RestConstants.ACTION_PARAM);
085                if (action.equals(RestConstants.JOB_ACTION_START)) {
086                    stopCron();
087                    dagEngine.start(jobId);
088                    startCron();
089                    response.setStatus(HttpServletResponse.SC_OK);
090                }
091                else if (action.equals(RestConstants.JOB_ACTION_RESUME)) {
092                    stopCron();
093                    dagEngine.resume(jobId);
094                    startCron();
095                    response.setStatus(HttpServletResponse.SC_OK);
096                }
097                else if (action.equals(RestConstants.JOB_ACTION_SUSPEND)) {
098                    stopCron();
099                    dagEngine.suspend(jobId);
100                    startCron();
101                    response.setStatus(HttpServletResponse.SC_OK);
102                }
103                else if (action.equals(RestConstants.JOB_ACTION_KILL)) {
104                    stopCron();
105                    dagEngine.kill(jobId);
106                    startCron();
107                    response.setStatus(HttpServletResponse.SC_OK);
108                }
109                else if (action.equals(RestConstants.JOB_ACTION_RERUN)) {
110                    validateContentType(request, RestConstants.XML_CONTENT_TYPE);
111                    XConfiguration conf = new XConfiguration(request.getInputStream());
112                    stopCron();
113                    conf = conf.trim();
114                    conf = conf.resolve();
115                    JobsServlet.validateJobConfiguration(conf);
116                    checkAuthorizationForApp(getUser(request), conf);
117                    dagEngine.reRun(jobId, conf);
118                    startCron();
119                    response.setStatus(HttpServletResponse.SC_OK);
120                }
121                else if (action.equals(RestConstants.JOB_COORD_ACTION_RERUN)) {
122                    validateContentType(request, RestConstants.XML_CONTENT_TYPE);
123                    stopCron();
124                    String rerunType = request.getParameter(RestConstants.JOB_COORD_RERUN_TYPE_PARAM);
125                    String scope = request.getParameter(RestConstants.JOB_COORD_RERUN_SCOPE_PARAM);
126                    String refresh = request.getParameter(RestConstants.JOB_COORD_RERUN_REFRESH_PARAM);
127                    String noCleanup = request.getParameter(RestConstants.JOB_COORD_RERUN_NOCLEANUP_PARAM);
128                    CoordinatorActionInfo coordInfo = coordEngine.reRun(jobId, rerunType, scope, Boolean.valueOf(refresh),
129                            Boolean.valueOf(noCleanup));
130                    List<CoordinatorActionBean> actions = coordInfo.getCoordActions();
131                    JSONObject json = new JSONObject();
132                    json.put(JsonTags.COORDINATOR_ACTIONS, CoordinatorActionBean.toJSONArray(actions));
133                    startCron();
134                    sendJsonResponse(response, HttpServletResponse.SC_OK, json);
135                }
136                else {
137                    throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303,
138                            RestConstants.ACTION_PARAM, action);
139                }
140            }
141            catch (DagEngineException ex) {
142                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ex);
143            }
144            catch (BaseEngineException ex) {
145                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ex);
146            }
147        }
148    
149        /**
150         * Validate the configuration user/group. <p/>
151         *
152         * @param requestUser user in request.
153         * @param conf configuration.
154         * @throws XServletException thrown if the configuration does not have a property {@link
155         * org.apache.oozie.client.OozieClient#USER_NAME}.
156         */
157        static void checkAuthorizationForApp(String requestUser, Configuration conf) throws XServletException {
158            String user = conf.get(OozieClient.USER_NAME);
159            String group = conf.get(OozieClient.GROUP_NAME);
160            try {
161                if (user == null) {
162                    throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, OozieClient.USER_NAME);
163                }
164                if (!requestUser.equals(UNDEF) && !user.equals(requestUser)) {
165                    throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0400, requestUser, user);
166                }
167                AuthorizationService auth = Services.get().get(AuthorizationService.class);
168                if (group == null) {
169                    group = auth.getDefaultGroup(user);
170                    conf.set(OozieClient.GROUP_NAME, group);
171                }
172                else {
173                    auth.authorizeForGroup(user, group);
174                }
175                XLog.Info.get().setParameter(XLogService.GROUP, group);
176                auth.authorizeForApp(user, group, conf.get(OozieClient.APP_PATH), conf);
177            }
178            catch (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            DagEngine dagEngine = Services.get().get(DagEngineService.class).getDagEngine(getUser(request),
200                                                                                          getAuthToken(request));
201            try {
202                if (show == null || show.equals(RestConstants.JOB_SHOW_INFO)) {
203                    stopCron();
204                    JsonWorkflowJob job = (JsonWorkflowJob) dagEngine.getJob(jobId);
205                    startCron();
206                    sendJsonResponse(response, HttpServletResponse.SC_OK, job);
207                }
208                else {
209                    if (show.equals(RestConstants.JOB_SHOW_LOG)) {
210                        response.setContentType(TEXT_UTF8);
211                        dagEngine.streamLog(jobId, response.getWriter());
212                    }
213                    else {
214                        if (show.equals(RestConstants.JOB_SHOW_DEFINITION)) {
215                            stopCron();
216                            response.setContentType(XML_UTF8);
217                            String wfDefinition = dagEngine.getDefinition(jobId);
218                            startCron();
219                            response.setStatus(HttpServletResponse.SC_OK);
220                            response.getWriter().write(wfDefinition);
221                        }
222                        else {
223                            throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303,
224                                                        RestConstants.JOB_SHOW_PARAM, show);
225                        }
226                    }
227                }
228            }
229            catch (DagEngineException ex) {
230                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ex);
231            }
232        }
233    
234    }