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.oozie.ErrorCode;
018    import org.apache.oozie.WorkflowActionBean;
019    import org.apache.oozie.WorkflowJobBean;
020    import org.apache.oozie.XException;
021    import org.apache.oozie.client.SLAEvent.SlaAppType;
022    import org.apache.oozie.client.SLAEvent.Status;
023    import org.apache.oozie.command.CommandException;
024    import org.apache.oozie.command.PreconditionException;
025    import org.apache.oozie.executor.jpa.JPAExecutorException;
026    import org.apache.oozie.executor.jpa.WorkflowActionGetJPAExecutor;
027    import org.apache.oozie.executor.jpa.WorkflowActionUpdateJPAExecutor;
028    import org.apache.oozie.executor.jpa.WorkflowJobGetJPAExecutor;
029    import org.apache.oozie.executor.jpa.WorkflowJobUpdateJPAExecutor;
030    import org.apache.oozie.action.ActionExecutor;
031    import org.apache.oozie.action.ActionExecutorException;
032    import org.apache.oozie.service.ActionService;
033    import org.apache.oozie.service.JPAService;
034    import org.apache.oozie.service.UUIDService;
035    import org.apache.oozie.service.Services;
036    import org.apache.oozie.util.LogUtils;
037    import org.apache.oozie.util.Instrumentation;
038    import org.apache.oozie.util.db.SLADbXOperations;
039    
040    /**
041     * Kill workflow action and invoke action executor to kill the underlying context.
042     *
043     */
044    public class ActionKillXCommand extends ActionXCommand<Void> {
045        private String actionId;
046        private String jobId;
047        private WorkflowJobBean wfJob;
048        private WorkflowActionBean wfAction;
049        private JPAService jpaService = null;
050    
051        public ActionKillXCommand(String actionId, String type) {
052            super("action.kill", type, 0);
053            this.actionId = actionId;
054            this.jobId = Services.get().get(UUIDService.class).getId(actionId);
055        }
056    
057        public ActionKillXCommand(String actionId) {
058            this(actionId, "action.kill");
059        }
060    
061        @Override
062        protected boolean isLockRequired() {
063            return true;
064        }
065    
066        @Override
067        protected String getEntityKey() {
068            return this.jobId;
069        }
070    
071        @Override
072        protected void loadState() throws CommandException {
073            try {
074                jpaService = Services.get().get(JPAService.class);
075    
076                if (jpaService != null) {
077                    this.wfJob = jpaService.execute(new WorkflowJobGetJPAExecutor(jobId));
078                    this.wfAction = jpaService.execute(new WorkflowActionGetJPAExecutor(actionId));
079                    LogUtils.setLogInfo(wfJob, logInfo);
080                    LogUtils.setLogInfo(wfAction, logInfo);
081                }
082                else {
083                    throw new CommandException(ErrorCode.E0610);
084                }
085            }
086            catch (XException ex) {
087                throw new CommandException(ex);
088            }
089        }
090    
091        @Override
092        protected void verifyPrecondition() throws CommandException, PreconditionException {
093            if (wfAction.getStatus() != WorkflowActionBean.Status.KILLED) {
094                throw new PreconditionException(ErrorCode.E0726, wfAction.getId());
095            }
096        }
097    
098        @Override
099        protected Void execute() throws CommandException {
100            LOG.debug("STARTED WorkflowActionKillXCommand for action " + actionId);
101    
102            if (wfAction.isPending()) {
103                ActionExecutor executor = Services.get().get(ActionService.class).getExecutor(wfAction.getType());
104                if (executor != null) {
105                    try {
106                        boolean isRetry = false;
107                        ActionExecutorContext context = new ActionXCommand.ActionExecutorContext(wfJob, wfAction,
108                                isRetry);
109                        incrActionCounter(wfAction.getType(), 1);
110    
111                        Instrumentation.Cron cron = new Instrumentation.Cron();
112                        cron.start();
113                        executor.kill(context, wfAction);
114                        cron.stop();
115                        addActionCron(wfAction.getType(), cron);
116    
117                        wfAction.resetPending();
118                        wfAction.setStatus(WorkflowActionBean.Status.KILLED);
119    
120                        jpaService.execute(new WorkflowActionUpdateJPAExecutor(wfAction));
121                        jpaService.execute(new WorkflowJobUpdateJPAExecutor(wfJob));
122                        // Add SLA status event (KILLED) for WF_ACTION
123                        SLADbXOperations.writeStausEvent(wfAction.getSlaXml(), wfAction.getId(), Status.KILLED,
124                                SlaAppType.WORKFLOW_ACTION);
125                        queue(new NotificationXCommand(wfJob, wfAction));
126                    }
127                    catch (ActionExecutorException ex) {
128                        wfAction.resetPending();
129                        wfAction.setStatus(WorkflowActionBean.Status.FAILED);
130                        wfAction.setErrorInfo(ex.getErrorCode().toString(),
131                                "KILL COMMAND FAILED - exception while executing job kill");
132                        wfJob.setStatus(WorkflowJobBean.Status.KILLED);
133                        try {
134                            jpaService.execute(new WorkflowActionUpdateJPAExecutor(wfAction));
135                            jpaService.execute(new WorkflowJobUpdateJPAExecutor(wfJob));
136                        }
137                        catch (JPAExecutorException je) {
138                            throw new CommandException(je);
139                        }
140                        // What will happen to WF and COORD_ACTION, NOTIFICATION?
141                        SLADbXOperations.writeStausEvent(wfAction.getSlaXml(), wfAction.getId(), Status.FAILED,
142                                SlaAppType.WORKFLOW_ACTION);
143                        LOG.warn("Exception while executing kill(). Error Code [{0}], Message[{1}]",
144                                ex.getErrorCode(), ex.getMessage(), ex);
145                    }
146                    catch (JPAExecutorException je) {
147                        throw new CommandException(je);
148                    }
149                }
150            }
151            LOG.debug("ENDED WorkflowActionKillXCommand for action " + actionId);
152            return null;
153        }
154    
155    }