mirror of
https://github.com/apache/nifi.git
synced 2025-02-17 23:47:08 +00:00
NIFI-2996
- validate processors only when they are in STOPPED state - report validation errors via REST API on processors/services/tasks/ports only when they are in the STOPPED state - This closes #1192
This commit is contained in:
parent
fb9cbccc38
commit
15af764dd8
@ -2722,16 +2722,16 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||||||
status.setFlowFilesRemoved(entry.getFlowFilesRemoved());
|
status.setFlowFilesRemoved(entry.getFlowFilesRemoved());
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine the run status and get any validation errors... must check
|
// Determine the run status and get any validation error... only validating while STOPPED
|
||||||
// is valid when not disabled since a processors validity could change due
|
// is a trade-off we are willing to make, even though processor validity could change due to
|
||||||
// to environmental conditions (property configured with a file path and
|
// environmental conditions (property configured with a file path and the file being externally
|
||||||
// the file being externally removed)
|
// removed). This saves on validation costs that would be unnecessary most of the time.
|
||||||
if (ScheduledState.DISABLED.equals(procNode.getScheduledState())) {
|
if (ScheduledState.DISABLED.equals(procNode.getScheduledState())) {
|
||||||
status.setRunStatus(RunStatus.Disabled);
|
status.setRunStatus(RunStatus.Disabled);
|
||||||
} else if (!procNode.isValid()) {
|
|
||||||
status.setRunStatus(RunStatus.Invalid);
|
|
||||||
} else if (ScheduledState.RUNNING.equals(procNode.getScheduledState())) {
|
} else if (ScheduledState.RUNNING.equals(procNode.getScheduledState())) {
|
||||||
status.setRunStatus(RunStatus.Running);
|
status.setRunStatus(RunStatus.Running);
|
||||||
|
} else if (!procNode.isValid()) {
|
||||||
|
status.setRunStatus(RunStatus.Invalid);
|
||||||
} else {
|
} else {
|
||||||
status.setRunStatus(RunStatus.Stopped);
|
status.setRunStatus(RunStatus.Stopped);
|
||||||
}
|
}
|
||||||
|
@ -987,6 +987,9 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||||||
public Collection<ValidationResult> getValidationErrors() {
|
public Collection<ValidationResult> getValidationErrors() {
|
||||||
final List<ValidationResult> results = new ArrayList<>();
|
final List<ValidationResult> results = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
|
// Processors may go invalid while RUNNING, but only validating while STOPPED is a trade-off
|
||||||
|
// we are willing to make in order to save on validation costs that would be unnecessary most of the time.
|
||||||
|
if (getScheduledState() == ScheduledState.STOPPED) {
|
||||||
final ValidationContext validationContext = this.getValidationContextFactory()
|
final ValidationContext validationContext = this.getValidationContextFactory()
|
||||||
.newValidationContext(getProperties(), getAnnotationData(), getProcessGroup().getIdentifier(), getIdentifier());
|
.newValidationContext(getProperties(), getAnnotationData(), getProcessGroup().getIdentifier(), getIdentifier());
|
||||||
|
|
||||||
@ -1032,6 +1035,7 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
results.add(new ValidationResult.Builder().explanation("Failed to run validation due to " + t.toString())
|
results.add(new ValidationResult.Builder().explanation("Failed to run validation due to " + t.toString())
|
||||||
.valid(false).build());
|
.valid(false).build());
|
||||||
|
@ -34,6 +34,7 @@ import org.apache.nifi.scheduling.SchedulingStrategy;
|
|||||||
import org.apache.nifi.util.FormatUtils;
|
import org.apache.nifi.util.FormatUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -241,4 +242,13 @@ public abstract class AbstractReportingTaskNode extends AbstractConfiguredCompon
|
|||||||
public String getProcessGroupIdentifier() {
|
public String getProcessGroupIdentifier() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ValidationResult> getValidationErrors(Set<String> serviceIdentifiersNotToValidate) {
|
||||||
|
Collection<ValidationResult> results = null;
|
||||||
|
if (getScheduledState() == ScheduledState.STOPPED) {
|
||||||
|
results = super.getValidationErrors(serviceIdentifiersNotToValidate);
|
||||||
|
}
|
||||||
|
return results != null ? results : Collections.emptySet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,4 +438,13 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||||||
final ProcessGroup procGroup = getProcessGroup();
|
final ProcessGroup procGroup = getProcessGroup();
|
||||||
return procGroup == null ? null : procGroup.getIdentifier();
|
return procGroup == null ? null : procGroup.getIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ValidationResult> getValidationErrors(Set<String> serviceIdentifiersNotToValidate) {
|
||||||
|
Collection<ValidationResult> results = null;
|
||||||
|
if (stateRef.get() == ControllerServiceState.DISABLED) {
|
||||||
|
results = super.getValidationErrors(serviceIdentifiersNotToValidate);
|
||||||
|
}
|
||||||
|
return results != null ? results : Collections.emptySet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,22 @@ public class TestStandardProcessorNode {
|
|||||||
assertEquals(1, processor.onStoppedCount);
|
assertEquals(1, processor.onStoppedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisabledValidationErrors() {
|
||||||
|
final ModifiesClasspathNoAnnotationProcessor processor = new ModifiesClasspathNoAnnotationProcessor();
|
||||||
|
final StandardProcessorNode procNode = createProcessorNode(processor);
|
||||||
|
|
||||||
|
// Set a property to an invalid value
|
||||||
|
final Map<String, String> properties = new HashMap<>();
|
||||||
|
properties.put(ModifiesClasspathNoAnnotationProcessor.CLASSPATH_RESOURCE.getName(), "");
|
||||||
|
procNode.setProperties(properties);
|
||||||
|
Assert.assertTrue(procNode.getValidationErrors().size() > 0);
|
||||||
|
|
||||||
|
// Disabled processors skip property validation
|
||||||
|
procNode.disable();
|
||||||
|
Assert.assertFalse(procNode.getValidationErrors().size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSinglePropertyDynamicallyModifiesClasspath() throws MalformedURLException {
|
public void testSinglePropertyDynamicallyModifiesClasspath() throws MalformedURLException {
|
||||||
final PropertyDescriptor classpathProp = new PropertyDescriptor.Builder().name("Classpath Resources")
|
final PropertyDescriptor classpathProp = new PropertyDescriptor.Builder().name("Classpath Resources")
|
||||||
|
@ -34,6 +34,7 @@ import org.apache.nifi.components.ValidationResult;
|
|||||||
import org.apache.nifi.connectable.ConnectableType;
|
import org.apache.nifi.connectable.ConnectableType;
|
||||||
import org.apache.nifi.connectable.Connection;
|
import org.apache.nifi.connectable.Connection;
|
||||||
import org.apache.nifi.controller.ProcessScheduler;
|
import org.apache.nifi.controller.ProcessScheduler;
|
||||||
|
import org.apache.nifi.controller.ScheduledState;
|
||||||
import org.apache.nifi.flowfile.FlowFile;
|
import org.apache.nifi.flowfile.FlowFile;
|
||||||
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
import org.apache.nifi.flowfile.attributes.CoreAttributes;
|
||||||
import org.apache.nifi.groups.ProcessGroup;
|
import org.apache.nifi.groups.ProcessGroup;
|
||||||
@ -367,7 +368,7 @@ public class StandardRemoteGroupPort extends RemoteGroupPort {
|
|||||||
final String uploadDataRate = stopWatch.calculateDataRate(bytesReceived);
|
final String uploadDataRate = stopWatch.calculateDataRate(bytesReceived);
|
||||||
final long uploadMillis = stopWatch.getDuration(TimeUnit.MILLISECONDS);
|
final long uploadMillis = stopWatch.getDuration(TimeUnit.MILLISECONDS);
|
||||||
final String dataSize = FormatUtils.formatDataSize(bytesReceived);
|
final String dataSize = FormatUtils.formatDataSize(bytesReceived);
|
||||||
logger.info("{} Successfully receveied {} ({}) from {} in {} milliseconds at a rate of {}", new Object[]{
|
logger.info("{} Successfully received {} ({}) from {} in {} milliseconds at a rate of {}", new Object[]{
|
||||||
this, flowFileDescription, dataSize, transaction.getCommunicant().getUrl(), uploadMillis, uploadDataRate});
|
this, flowFileDescription, dataSize, transaction.getCommunicant().getUrl(), uploadMillis, uploadDataRate});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,12 +382,14 @@ public class StandardRemoteGroupPort extends RemoteGroupPort {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return getValidationErrors().isEmpty();
|
return targetExists.get()
|
||||||
|
&& (getConnectableType() == ConnectableType.REMOTE_OUTPUT_PORT ? !getConnections(Relationship.ANONYMOUS).isEmpty() : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ValidationResult> getValidationErrors() {
|
public Collection<ValidationResult> getValidationErrors() {
|
||||||
final Collection<ValidationResult> validationErrors = new ArrayList<>();
|
final Collection<ValidationResult> validationErrors = new ArrayList<>();
|
||||||
|
if (getScheduledState() == ScheduledState.STOPPED) {
|
||||||
ValidationResult error = null;
|
ValidationResult error = null;
|
||||||
if (!targetExists.get()) {
|
if (!targetExists.get()) {
|
||||||
error = new ValidationResult.Builder()
|
error = new ValidationResult.Builder()
|
||||||
@ -405,7 +408,7 @@ public class StandardRemoteGroupPort extends RemoteGroupPort {
|
|||||||
if (error != null) {
|
if (error != null) {
|
||||||
validationErrors.add(error);
|
validationErrors.add(error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return validationErrors;
|
return validationErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import org.apache.nifi.components.ValidationResult;
|
|||||||
import org.apache.nifi.connectable.ConnectableType;
|
import org.apache.nifi.connectable.ConnectableType;
|
||||||
import org.apache.nifi.controller.AbstractPort;
|
import org.apache.nifi.controller.AbstractPort;
|
||||||
import org.apache.nifi.controller.ProcessScheduler;
|
import org.apache.nifi.controller.ProcessScheduler;
|
||||||
|
import org.apache.nifi.controller.ScheduledState;
|
||||||
import org.apache.nifi.events.BulletinFactory;
|
import org.apache.nifi.events.BulletinFactory;
|
||||||
import org.apache.nifi.events.EventReporter;
|
import org.apache.nifi.events.EventReporter;
|
||||||
import org.apache.nifi.groups.ProcessGroup;
|
import org.apache.nifi.groups.ProcessGroup;
|
||||||
@ -273,6 +274,7 @@ public class StandardRootGroupPort extends AbstractPort implements RootGroupPort
|
|||||||
@Override
|
@Override
|
||||||
public Collection<ValidationResult> getValidationErrors() {
|
public Collection<ValidationResult> getValidationErrors() {
|
||||||
final Collection<ValidationResult> validationErrors = new ArrayList<>();
|
final Collection<ValidationResult> validationErrors = new ArrayList<>();
|
||||||
|
if (getScheduledState() == ScheduledState.STOPPED) {
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
final ValidationResult error = new ValidationResult.Builder()
|
final ValidationResult error = new ValidationResult.Builder()
|
||||||
.explanation(String.format("Output connection for port '%s' is not defined.", getName()))
|
.explanation(String.format("Output connection for port '%s' is not defined.", getName()))
|
||||||
@ -281,6 +283,7 @@ public class StandardRootGroupPort extends AbstractPort implements RootGroupPort
|
|||||||
.build();
|
.build();
|
||||||
validationErrors.add(error);
|
validationErrors.add(error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return validationErrors;
|
return validationErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user