Skip to content

Commit

Permalink
Merge pull request #4235 from rundeck/issue/4178-redux
Browse files Browse the repository at this point in the history
Fix flow control status handling for job state conditional step
  • Loading branch information
gschueler committed Nov 20, 2018
2 parents 4d4dbac + e4a9906 commit 078c820
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import com.dtolabs.rundeck.core.Constants;
import com.dtolabs.rundeck.core.common.Framework;
import com.dtolabs.rundeck.core.common.IFramework;
import com.dtolabs.rundeck.core.common.INodeEntry;
import com.dtolabs.rundeck.core.common.SelectorUtils;
import com.dtolabs.rundeck.core.data.BaseDataContext;
Expand All @@ -33,12 +34,7 @@
import com.dtolabs.rundeck.core.execution.*;
import com.dtolabs.rundeck.core.execution.dispatch.DispatcherException;
import com.dtolabs.rundeck.core.execution.dispatch.DispatcherResult;
import com.dtolabs.rundeck.core.execution.workflow.steps.FailureReason;
import com.dtolabs.rundeck.core.execution.workflow.steps.NodeDispatchStepExecutor;
import com.dtolabs.rundeck.core.execution.workflow.steps.StepException;
import com.dtolabs.rundeck.core.execution.workflow.steps.StepExecutionResultImpl;
import com.dtolabs.rundeck.core.execution.workflow.steps.StepFailureReason;
import com.dtolabs.rundeck.core.execution.workflow.steps.StepExecutionResult;
import com.dtolabs.rundeck.core.execution.workflow.steps.*;
import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepException;
import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepResult;
import com.dtolabs.rundeck.core.execution.workflow.steps.node.NodeStepResultImpl;
Expand All @@ -62,9 +58,9 @@ public abstract class BaseWorkflowExecutor implements WorkflowExecutor {
protected static final String SECURE_OPTION_KEY = "secureOption";
protected static final String SECURE_OPTION_VALUE = "****";

private final Framework framework;
private final IFramework framework;

public BaseWorkflowExecutor(final Framework framework) {
public BaseWorkflowExecutor(final IFramework framework) {
this.framework = framework;
}

Expand Down Expand Up @@ -99,7 +95,7 @@ static boolean isInnerLoop(final WorkflowExecutionItem item) {
return item.getWorkflow() instanceof StepFirstWrapper;
}

protected Framework getFramework() {
protected IFramework getFramework() {
return framework;
}

Expand Down Expand Up @@ -691,7 +687,6 @@ public StepResultCapture executeWorkflowStep(
cmd
);

result.setSuccess(stepResult.isSuccess());

//node recorder report
Map<String, NodeStepResult> nodeFailures = stepCaptureFailedNodesListener.getFailedNodes();
Expand All @@ -701,11 +696,14 @@ public StepResultCapture executeWorkflowStep(
WFSharedContext combinedResultData = new WFSharedContext();
combineResultData(c, outputContext, combinedResultData, stepResult);


if (stepController.isControlled()) {
result = WorkflowStatusResultImpl.with(stepController);
stepResult = controlledStepResult(stepController, stepResult);
executionContext.getExecutionListener().log(3, result.toString());
}

result.setSuccess(stepResult.isSuccess());

try {
if (!result.isSuccess() && cmd instanceof HasFailureHandler) {
final HasFailureHandler handles = (HasFailureHandler) cmd;
Expand Down Expand Up @@ -822,6 +820,31 @@ public StepResultCapture executeWorkflowStep(
return new StepResultCapture(stepResult, result, combinedResultData);
}

private StepExecutionResult controlledStepResult(
final FlowController stepController,
final StepExecutionResult stepResult
)
{
return new StepExecutionResultWrapper(stepResult) {
@Override
public boolean isSuccess() {
return stepController.getControlBehavior() == ControlBehavior.Continue
? stepResult.isSuccess()
: stepController.isSuccess();
}

@Override
public FailureReason getFailureReason() {
return stepController.getFailureReason(super.getFailureReason());
}

@Override
public String toString() {
return "[" + stepController + "]: " + super.toString();
}
};
}

public void combineResultData(
final int c,
final DataOutput outputContext,
Expand Down Expand Up @@ -917,7 +940,7 @@ public String toString() {
"stepResult=" + stepResult +
", stepSuccess=" + isSuccess() +
", statusString='" + getStatusString() + '\'' +
", controlBehavior=" + getStepResult() +
", controlBehavior=" + getControlBehavior() +
", resultData=" + resultData +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.dtolabs.rundeck.core.execution.workflow;

import com.dtolabs.rundeck.core.execution.workflow.steps.FailureReason;

/**
* record flow control
*/
Expand Down Expand Up @@ -72,4 +74,30 @@ public boolean isSuccess() {
public boolean isControlled() {
return controlled;
}

FailureReason getFailureReason(FailureReason defVal) {
if (isSuccess()) {
return null;
}
if (controlBehavior == ControlBehavior.Halt) {
return FlowControlFailureReason.FlowControlHalted;
}
return defVal;
}

static enum FlowControlFailureReason
implements FailureReason
{
FlowControlHalted
}

@Override
public String toString() {
return "FlowController{" +
"controlBehavior=" + controlBehavior +
", statusString='" + statusString + '\'' +
", success=" + success +
", controlled=" + controlled +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,10 @@ private Map<String, Object> resultMetadata(StepExecutionResult result) {
if (null != result && null != result.getFailureData()) {
map.putAll(result.getFailureData());
}
map.put("failureReason", null != result ? result.getFailureReason().toString() : "Unknown");
map.put(
"failureReason",
null != result && result.getFailureReason() != null ? result.getFailureReason().toString() : "Unknown"
);
return map;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2018 Rundeck, Inc. (http://rundeck.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.dtolabs.rundeck.core.execution.workflow.steps;

public interface HasSourceStepExecutionResult {
StepExecutionResult getSourceStepExecutionResult();
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.Optional;


/**
Expand Down Expand Up @@ -168,33 +169,65 @@ public DispatcherException getDispatcherException(){
}

public static boolean isWrappedDispatcherException(final StepExecutionResult result) {
return (result instanceof NodeDispatchStepExecutorExceptionResult);
return extractNodeDispatchStepExecutorExceptionResult(result).isPresent();
}

public static Optional<NodeDispatchStepExecutorExceptionResult> extractNodeDispatchStepExecutorExceptionResult(final StepExecutionResult result) {
boolean isa = (result instanceof NodeDispatchStepExecutorExceptionResult);
if (isa) {
return Optional.of((NodeDispatchStepExecutorExceptionResult) result);
} else if (result instanceof HasSourceStepExecutionResult) {
StepExecutionResult
sourceStepExecutionResult =
((HasSourceStepExecutionResult) result).getSourceStepExecutionResult();
if (sourceStepExecutionResult != null && sourceStepExecutionResult != result) {
return extractNodeDispatchStepExecutorExceptionResult(sourceStepExecutionResult);
}
}
return Optional.empty();
}
public static boolean isWrappedDispatcherResult(final StepExecutionResult result) {
return (result instanceof NodeDispatchStepExecutorResult);
return extractNodeDispatchStepExecutorResult(result).isPresent();
}

public static Optional<NodeDispatchStepExecutorResult> extractNodeDispatchStepExecutorResult(final StepExecutionResult result) {
boolean isa = (result instanceof NodeDispatchStepExecutorResult);
if (isa) {
return Optional.of((NodeDispatchStepExecutorResult) result);
} else if (result instanceof HasSourceStepExecutionResult) {
StepExecutionResult
sourceStepExecutionResult =
((HasSourceStepExecutionResult) result).getSourceStepExecutionResult();
if (sourceStepExecutionResult != null && sourceStepExecutionResult != result) {
return extractNodeDispatchStepExecutorResult(sourceStepExecutionResult);
}
}
return Optional.empty();
}
/**
* Return the DispatcherResult from a StepExecutionResult created by this class.
* @param result step result
* @return dispatcher result
*/
public static DispatcherResult extractDispatcherResult(final StepExecutionResult result) {
if(!isWrappedDispatcherResult(result)) {
Optional<NodeDispatchStepExecutorResult> extracted = extractNodeDispatchStepExecutorResult(result);
if (!extracted.isPresent()) {
throw new IllegalArgumentException("Cannot extract result: unexpected type: " + result);
}
NodeDispatchStepExecutorResult nr = (NodeDispatchStepExecutorResult) result;
return nr.getDispatcherResult();
return extracted.get().getDispatcherResult();
}
/**
* Return the DispatcherResult from a StepExecutionResult created by this class.
* @param result step exception
* @return dispatcher exception
*/
public static DispatcherException extractDispatcherException(final StepExecutionResult result) {
if(!isWrappedDispatcherException(result)) {
Optional<NodeDispatchStepExecutorExceptionResult>
extracted =
extractNodeDispatchStepExecutorExceptionResult(result);
if (!extracted.isPresent()) {
throw new IllegalArgumentException("Cannot extract result: unexpected type: " + result);
}
NodeDispatchStepExecutorExceptionResult nr = (NodeDispatchStepExecutorExceptionResult) result;
return nr.getDispatcherException();
return extracted.get().getDispatcherException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2018 Rundeck, Inc. (http://rundeck.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.dtolabs.rundeck.core.execution.workflow.steps;

import java.util.Map;

public class StepExecutionResultWrapper
implements StepExecutionResult, HasSourceStepExecutionResult
{
StepExecutionResult wrapped;

public StepExecutionResultWrapper(final StepExecutionResult wrapped) {
this.wrapped = wrapped;
}

@Override
public Map<String, Object> getFailureData() {
return wrapped.getFailureData();
}

@Override
public FailureReason getFailureReason() {
return wrapped.getFailureReason();
}

@Override
public String getFailureMessage() {
return wrapped.getFailureMessage();
}

@Override
public Throwable getException() {
return wrapped.getException();
}

@Override
public boolean isSuccess() {
return wrapped.isSuccess();
}

@Override
public StepExecutionResult getSourceStepExecutionResult() {
return wrapped;
}

@Override
public String toString() {
return "(source: " + wrapped + ")";
}
}
Loading

0 comments on commit 078c820

Please sign in to comment.