Search in sources :

Example 16 with WorkflowException

use of org.apache.oozie.workflow.WorkflowException in project oozie by apache.

the class LiteWorkflowValidator method checkActionNode.

private void checkActionNode(NodeDef node) throws WorkflowException {
    try {
        Element action = XmlUtils.parseXml(node.getConf());
        ActionService actionService = Services.get().get(ActionService.class);
        boolean supportedAction = actionService.hasActionType(action.getName());
        if (!supportedAction) {
            throw new WorkflowException(ErrorCode.E0723, node.getName(), action.getName());
        }
    } catch (JDOMException ex) {
        throw new WorkflowException(ErrorCode.E0700, "JDOMException: " + ex.getMessage());
    }
}
Also used : Element(org.jdom.Element) WorkflowException(org.apache.oozie.workflow.WorkflowException) JDOMException(org.jdom.JDOMException) ActionService(org.apache.oozie.service.ActionService)

Example 17 with WorkflowException

use of org.apache.oozie.workflow.WorkflowException in project oozie by apache.

the class LiteWorkflowValidator method validateForkJoin.

/**
 * This method recursively validates two things:
 * - fork/join methods are properly paired
 * - there are no multiple "okTo" paths to a given node
 *
 * Important: this method assumes that the workflow is not acyclic - therefore this must run after performBasicValidation()
 *
 * @param app The WorkflowApp
 * @param node Current node we're checking
 * @param currentFork Current fork node (null if we are not under a fork path)
 * @param topDecisionParent The top (eldest) decision node along the path to this node, or null if there isn't one
 * @param okPath false if node (or an ancestor of node) was gotten to via an "error to" transition or via a join node that has
 * already been visited at least once before
 * @param forkJoins Map that contains a mapping of fork-join node pairs.
 * @param nodeAndDecisionParents Map that contains a mapping of nodes and their eldest decision node
 * @throws WorkflowException If there is any of the constraints described above is violated
 */
private void validateForkJoin(LiteWorkflowApp app, NodeDef node, NodeDef currentFork, String topDecisionParent, boolean okPath, Deque<String> path, Map<String, String> forkJoins, Map<String, Optional<String>> nodeAndDecisionParents) throws WorkflowException {
    final String nodeName = node.getName();
    path.addLast(nodeName);
    /* If we're walking an "okTo" path and the nodes are not Kill/Join/End, we have to make sure that only a single
         * "okTo" path exists to the current node.
         *
         * The "topDecisionParent" represents the eldest decision in the chain that we've gone through. For example, let's assume
         * that D1, D2, D3 are decision nodes and A is an action node.
         *
         * D1-->D2-->D3---> ... (rest of the WF)
         *  |   |    |
         *  |   |    |
         *  |   |    +----> +---+
         *  |   +---------> | A |
         *  +-------------> +---+
         *
         * In this case, there are three "okTo" paths to "A" but it's still a valid workflow because the eldest decision node
         * is D1 and during every run, there is only one possible execution path that leads to A (D1->A, D1->D2->A or
         * (D1->D2->D3->A). In the code, if we encounter a decision node and we already have one, we don't update it. If it's null
         * then we set it to the current decision node we're under.
         *
         * If the "current" and "top" parents are null, it means that we reached the node from two separate "okTo" paths, which is
         * not acceptable.
         *
         * Also, if we have two distinct top decision parents it means that the node is reachable from two decision paths which
         * are not "chained" (like in the example).
         *
         * It's worth noting that the last two examples can only occur in case of fork-join when we start to execute at least
         * two separate paths in parallel. Without fork-join, multiple parents or two null parents would mean that there is a loop
         * in the workflow but that should not happen since it has been validated.
         */
    if (okPath && !(node instanceof KillNodeDef) && !(node instanceof JoinNodeDef) && !(node instanceof EndNodeDef)) {
        // using Optional here so we can distinguish between "non-visited" and "visited - no parent" state.
        Optional<String> decisionParentOpt = nodeAndDecisionParents.get(nodeName);
        if (decisionParentOpt == null) {
            nodeAndDecisionParents.put(node.getName(), Optional.fromNullable(topDecisionParent));
        } else {
            String decisionParent = decisionParentOpt.isPresent() ? decisionParentOpt.get() : null;
            if ((decisionParent == null && topDecisionParent == null) || !Objects.equal(decisionParent, topDecisionParent)) {
                throw new WorkflowException(ErrorCode.E0743, nodeName);
            }
        }
    }
    /* Fork-Join validation logic:
         *
         * At each Fork node, we recurse to every possible paths, changing the "currentFork" variable to the Fork node. We stop
         * walking as soon as we encounter a Join node. At the Join node, we update the forkJoin mapping, which maintains
         * the relationship between every fork-join pair (actually it's join->fork mapping). We check whether the join->fork
         * mapping already contains another Fork node, which means that the Join is reachable from at least two distinct
         * Fork nodes, so we terminate the validation.
         *
         * From the Join node, we don't recurse further. Therefore, all recursive calls return back to the point where we called
         * validateForkJoin() from the Fork node in question.
         *
         * At this point, we have to check how many different Join nodes we've found at each different paths. We collect them to
         * a set, then we make sure that we have only a single Join node for all Fork paths. Otherwise the workflow is broken.
         *
         * If we have only a single Join, then we get the transition node from the Join and go on with the recursive validation -
         * this time we use the original "currentFork" variable that we have on the stack. With this approach, nested
         * Fork-Joins are handled correctly.
         */
    if (node instanceof ForkNodeDef) {
        final List<String> transitions = node.getTransitions();
        checkForkTransitions(app, transitions, node);
        for (String t : transitions) {
            NodeDef transition = app.getNode(t);
            validateForkJoin(app, transition, node, topDecisionParent, okPath, path, forkJoins, nodeAndDecisionParents);
        }
        // get the Join node for this ForkNode & validate it (we must have only one)
        Set<String> joins = new HashSet<String>();
        collectJoins(app, forkJoins, nodeName, joins);
        checkJoins(joins, nodeName);
        List<String> joinTransitions = app.getNode(joins.iterator().next()).getTransitions();
        NodeDef next = app.getNode(joinTransitions.get(0));
        validateForkJoin(app, next, currentFork, topDecisionParent, okPath, path, forkJoins, nodeAndDecisionParents);
    } else if (node instanceof JoinNodeDef) {
        if (currentFork == null) {
            throw new WorkflowException(ErrorCode.E0742, node.getName());
        }
        // join --> fork mapping
        String forkNode = forkJoins.get(nodeName);
        if (forkNode == null) {
            forkJoins.put(nodeName, currentFork.getName());
        } else if (!forkNode.equals(currentFork.getName())) {
            throw new WorkflowException(ErrorCode.E0758, node.getName(), forkNode + "," + currentFork);
        }
    } else if (node instanceof DecisionNodeDef) {
        List<String> transitions = node.getTransitions();
        // see explanation above - if we already have a topDecisionParent, we don't update it
        String parentDecisionNode = topDecisionParent;
        if (parentDecisionNode == null) {
            parentDecisionNode = nodeName;
        }
        for (String t : transitions) {
            NodeDef transition = app.getNode(t);
            validateForkJoin(app, transition, currentFork, parentDecisionNode, okPath, path, forkJoins, nodeAndDecisionParents);
        }
    } else if (node instanceof KillNodeDef) {
    // no op
    } else if (node instanceof EndNodeDef) {
        // is the current "End") and look at last node again so we know where we came from
        if (currentFork != null) {
            path.removeLast();
            String previous = path.peekLast();
            throw new WorkflowException(ErrorCode.E0737, previous, node.getName());
        }
    } else if (node instanceof ActionNodeDef) {
        // "ok to" transition
        String transition = node.getTransitions().get(0);
        NodeDef okNode = app.getNode(transition);
        validateForkJoin(app, okNode, currentFork, topDecisionParent, okPath, path, forkJoins, nodeAndDecisionParents);
        // "error to" transition
        transition = node.getTransitions().get(1);
        NodeDef errorNode = app.getNode(transition);
        validateForkJoin(app, errorNode, currentFork, topDecisionParent, false, path, forkJoins, nodeAndDecisionParents);
    } else if (node instanceof StartNodeDef) {
        // start always has only 1 transition
        String transition = node.getTransitions().get(0);
        NodeDef tranNode = app.getNode(transition);
        validateForkJoin(app, tranNode, currentFork, topDecisionParent, okPath, path, forkJoins, nodeAndDecisionParents);
    } else {
        throw new WorkflowException(ErrorCode.E0740, node.getClass());
    }
    path.remove(nodeName);
}
Also used : WorkflowException(org.apache.oozie.workflow.WorkflowException) HashSet(java.util.HashSet)

Example 18 with WorkflowException

use of org.apache.oozie.workflow.WorkflowException in project oozie by apache.

the class TestLiteWorkflowAppParser method testParserDefaultNameNodeFail.

public void testParserDefaultNameNodeFail() throws Exception {
    LiteWorkflowAppParser parser = newLiteWorkflowAppParser();
    // No default NN is set
    try {
        parser.validateAndParse(IOUtils.getResourceAsReader("wf-schema-no-namenode.xml", -1), new Configuration());
        fail();
    } catch (WorkflowException e) {
        assertEquals(ErrorCode.E0701, e.getErrorCode());
        assertTrue(e.getMessage().contains("No name-node defined"));
    }
}
Also used : XConfiguration(org.apache.oozie.util.XConfiguration) Configuration(org.apache.hadoop.conf.Configuration) WorkflowException(org.apache.oozie.workflow.WorkflowException)

Example 19 with WorkflowException

use of org.apache.oozie.workflow.WorkflowException in project oozie by apache.

the class TestLiteWorkflowAppParser method testParserDefaultJobTrackerFail.

public void testParserDefaultJobTrackerFail() throws Exception {
    LiteWorkflowAppParser parser = newLiteWorkflowAppParser();
    // No default NN is set
    try {
        parser.validateAndParse(IOUtils.getResourceAsReader("wf-schema-no-jobtracker.xml", -1), new Configuration());
        fail();
    } catch (WorkflowException e) {
        assertEquals(ErrorCode.E0701, e.getErrorCode());
        assertTrue(e.getMessage().contains("E0701: XML schema error, No job-tracker or resource-manager defined"));
    }
}
Also used : XConfiguration(org.apache.oozie.util.XConfiguration) Configuration(org.apache.hadoop.conf.Configuration) WorkflowException(org.apache.oozie.workflow.WorkflowException)

Example 20 with WorkflowException

use of org.apache.oozie.workflow.WorkflowException in project oozie by apache.

the class TestLiteWorkflowLib method testEmptyWorkflow.

public void testEmptyWorkflow() throws WorkflowException {
    LiteWorkflowApp def = new LiteWorkflowApp("wf", "<worklfow-app/>", new StartNodeDef(TestControlNodeHandler.class, "end")).addNode(new EndNodeDef("end", TestControlNodeHandler.class));
    final LiteWorkflowInstance job = new LiteWorkflowInstance(def, new XConfiguration(), "1");
    assertEquals(WorkflowInstance.Status.PREP, job.getStatus());
    job.start();
    waitFor(5 * 1000, new Predicate() {

        @Override
        public boolean evaluate() throws Exception {
            return job.getStatus() == WorkflowInstance.Status.SUCCEEDED;
        }
    });
    assertEquals(WorkflowInstance.Status.SUCCEEDED, job.getStatus());
}
Also used : XConfiguration(org.apache.oozie.util.XConfiguration) WorkflowException(org.apache.oozie.workflow.WorkflowException)

Aggregations

WorkflowException (org.apache.oozie.workflow.WorkflowException)41 XConfiguration (org.apache.oozie.util.XConfiguration)23 IOException (java.io.IOException)15 Configuration (org.apache.hadoop.conf.Configuration)15 CommandException (org.apache.oozie.command.CommandException)8 Date (java.util.Date)7 WorkflowInstance (org.apache.oozie.workflow.WorkflowInstance)7 Element (org.jdom.Element)7 ArrayList (java.util.ArrayList)6 JPAExecutorException (org.apache.oozie.executor.jpa.JPAExecutorException)6 JDOMException (org.jdom.JDOMException)6 WorkflowActionBean (org.apache.oozie.WorkflowActionBean)5 WorkflowJobQuery (org.apache.oozie.executor.jpa.WorkflowJobQueryExecutor.WorkflowJobQuery)5 File (java.io.File)4 Reader (java.io.Reader)4 URI (java.net.URI)4 FileSystem (org.apache.hadoop.fs.FileSystem)4 Path (org.apache.hadoop.fs.Path)4 WorkflowJobBean (org.apache.oozie.WorkflowJobBean)4 WorkflowApp (org.apache.oozie.workflow.WorkflowApp)4