rfellows commented on code in PR #11175:
URL: https://github.com/apache/nifi/pull/11175#discussion_r3250856181
##########
nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java:
##########
@@ -637,12 +663,155 @@ public void verifyCanDelete() {
@Override
public void verifyCanStart() {
+ if (getCurrentState() == ConnectorState.TROUBLESHOOTING) {
+ throw new IllegalStateException("Cannot start " + this + " because
it is in Troubleshooting mode.");
+ }
final ValidationState state = performValidation();
if (state.getStatus() != ValidationStatus.VALID) {
throw new IllegalStateException("Cannot start " + this + " because
it is not valid: " + state.getValidationErrors());
}
}
+ @Override
+ public void verifyCanEnterTroubleshooting() {
+ if (isExtensionMissing()) {
+ throw new IllegalStateException("Cannot enter Troubleshooting mode
for " + this + " because it is a Ghost Connector (its underlying extension is
missing).");
+ }
+
+ final ConnectorState currentState = getCurrentState();
+ switch (currentState) {
+ case TROUBLESHOOTING -> throw new IllegalStateException("Cannot
enter Troubleshooting mode for " + this + " because it is already in
Troubleshooting mode.");
+ case STARTING, STOPPING, DRAINING, PURGING, PREPARING_FOR_UPDATE,
UPDATING ->
+ throw new IllegalStateException("Cannot enter Troubleshooting
mode for " + this + " because its state is currently "
+ + currentState + "; it must be in a stable state before
entering Troubleshooting.");
+ default -> {
+ // STOPPED, RUNNING, UPDATED, UPDATE_FAILED are all acceptable
to enter Troubleshooting from
+ }
+ }
+ }
+
+ @Override
+ public void verifyCanEndTroubleshooting() {
+ if (getCurrentState() != ConnectorState.TROUBLESHOOTING) {
+ throw new IllegalStateException("Cannot end Troubleshooting mode
for " + this + " because it is not currently in Troubleshooting mode; current
state is " + getCurrentState());
+ }
+
+ // Verify that every component inside the managed flow is
stopped/disabled BEFORE doing any other validation.
+ // The flow-update check below relies on components being
stopped/disabled in order to produce meaningful results. Otherwise,
+ // the update check may succeed and then the running flow puts it into
a bad state.
+ final ProcessGroup managedGroup =
getActiveFlowContext().getManagedProcessGroup();
+ verifyAllComponentsStoppedAndDisabled(managedGroup);
+
+ // After confirming all components are stopped or disabled, check if
the managed flow can be safely reverted.
+ // Connector's authoritative flow would succeed. This mirrors exactly
what endTroubleshooting() will do so that
+ // any problem (e.g. a Connection whose contents cannot be preserved
or a component that cannot be replaced)
+ // is reported synchronously at the REST verify-phase rather than
surfacing halfway through the state change.
+ final VersionedExternalFlow authoritativeFlow =
resolveAuthoritativeFlow();
+ try {
+ initializationContext.verifyUpdateFlow(activeFlowContext,
authoritativeFlow, BundleCompatibility.RESOLVE_BUNDLE);
+ } catch (final FlowUpdateException e) {
+ throw new IllegalStateException("Cannot end Troubleshooting mode
for " + this
+ + " because the Managed Process Group cannot be reverted to
the Connector's authoritative flow: " + e.getMessage(), e);
+ }
+ }
+
+ private VersionedExternalFlow resolveAuthoritativeFlow() {
+ final VersionedExternalFlow authoritativeFlow;
+ try (final NarCloseable ignored =
NarCloseable.withComponentNarLoader(extensionManager,
getConnector().getClass(), getIdentifier())) {
+ authoritativeFlow =
getConnector().getActiveFlow(activeFlowContext);
+ }
+
+ if (authoritativeFlow == null || authoritativeFlow.getFlowContents()
== null) {
+ logger.warn("Connector {} returned a null authoritative flow from
getActiveFlow; using an empty flow.", this);
+ final VersionedExternalFlow empty = new VersionedExternalFlow();
+ empty.setFlowContents(new VersionedProcessGroup());
+ return empty;
+ }
+
+ return authoritativeFlow;
+ }
+
+ private void verifyAllComponentsStoppedAndDisabled(final ProcessGroup
group) {
+ for (final ProcessorNode processor : group.getProcessors()) {
+ if (!STOPPED_STATES.contains(processor.getScheduledState())) {
+ throw new IllegalStateException("Cannot end Troubleshooting
mode for " + this + " because Processor " + processor.getIdentifier()
+ + " is in state " + processor.getScheduledState() + "; it
must be STOPPED or DISABLED.");
+ }
Review Comment:
The way this works currently is a bit confusing. You can enter
troubleshooting mode while the processor is running, but you can't end
troubleshooting with it still running. This forces the user to have to manually
stop all processors before they would be allowed to end troubleshooting. For
large connectors, this will be a tedious process of manually stopping
everything.
It might be more palatable if STOP was a valid action on the connector as a
whole while in troubleshooting mode. But it is explicitly not allowed in the
current state.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]