Skip to content

Commit 8cc799f

Browse files
committed
add patch for 2.7.2
1 parent ce80df8 commit 8cc799f

1 file changed

Lines changed: 121 additions & 0 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
From 3893ce8d059f7d9365ba48b3f5e4f898701b71e8 Mon Sep 17 00:00:00 2001
2+
From: Andrew Kenworthy <andrew.kenworthy@stackable.tech>
3+
Date: Thu, 30 Apr 2026 18:05:11 +0200
4+
Subject: check services are disabled before calling updateControllerService
5+
6+
---
7+
...tandardVersionedComponentSynchronizer.java | 54 ++++++++++++++-----
8+
1 file changed, 40 insertions(+), 14 deletions(-)
9+
10+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java
11+
index b79ee4d6e8..d5b4d8c36e 100644
12+
--- a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java
13+
+++ b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java
14+
@@ -269,8 +269,8 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
15+
final ProcessGroup newProcessGroup = addProcessGroup(group, processGroup, options.getComponentIdGenerator(),
16+
additions.getParameterContexts(), additions.getParameterProviders(), group);
17+
additionsBuilder.addProcessGroup(newProcessGroup);
18+
- } catch (final ProcessorInstantiationException pie) {
19+
- throw new RuntimeException(pie);
20+
+ } catch (final ProcessorInstantiationException | FlowSynchronizationException e) {
21+
+ throw new RuntimeException(e);
22+
}
23+
});
24+
25+
@@ -392,8 +392,8 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
26+
final ProcessGroup topLevelGroup = syncOptions.getTopLevelGroupId() == null ? group : context.getFlowManager().getGroup(syncOptions.getTopLevelGroupId());
27+
synchronize(group, versionedExternalFlow.getFlowContents(), versionedExternalFlow.getParameterContexts(),
28+
parameterProviderReferences, topLevelGroup, syncOptions.isUpdateSettings());
29+
- } catch (final ProcessorInstantiationException pie) {
30+
- throw new RuntimeException(pie);
31+
+ } catch (final ProcessorInstantiationException | FlowSynchronizationException e) {
32+
+ throw new RuntimeException(e);
33+
}
34+
});
35+
36+
@@ -422,7 +422,7 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
37+
38+
private void synchronize(final ProcessGroup group, final VersionedProcessGroup proposed, final Map<String, VersionedParameterContext> versionedParameterContexts,
39+
final Map<String, ParameterProviderReference> parameterProviderReferences, final ProcessGroup topLevelGroup, final boolean updateGroupSettings)
40+
- throws ProcessorInstantiationException {
41+
+ throws ProcessorInstantiationException, FlowSynchronizationException {
42+
43+
// Some components, such as Processors, may have a Scheduled State of RUNNING in the proposed flow. However, if we
44+
// transition the service into the RUNNING state, and then we need to update a Connection that is connected to it,
45+
@@ -687,7 +687,7 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
46+
47+
private void synchronizeChildGroups(final ProcessGroup group, final VersionedProcessGroup proposed, final Map<String, VersionedParameterContext> versionedParameterContexts,
48+
final Map<String, ProcessGroup> childGroupsByVersionedId, final Map<String, ParameterProviderReference> parameterProviderReferences,
49+
- final ProcessGroup topLevelGroup) throws ProcessorInstantiationException {
50+
+ final ProcessGroup topLevelGroup) throws ProcessorInstantiationException, FlowSynchronizationException {
51+
52+
for (final VersionedProcessGroup proposedChildGroup : proposed.getProcessGroups()) {
53+
final ProcessGroup childGroup = childGroupsByVersionedId.get(proposedChildGroup.getIdentifier());
54+
@@ -707,7 +707,7 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
55+
}
56+
57+
private void synchronizeControllerServices(final ProcessGroup group, final VersionedProcessGroup proposed, final Map<String, ControllerServiceNode> servicesByVersionedId,
58+
- final ProcessGroup topLevelGroup) {
59+
+ final ProcessGroup topLevelGroup) throws FlowSynchronizationException {
60+
// Controller Services have to be handled a bit differently than other components. This is because Processors and Controller
61+
// Services may reference other Controller Services. Since we may be adding Service A, which depends on Service B, before adding
62+
// Service B, we need to ensure that we create all Controller Services first and then call updateControllerService for each
63+
@@ -741,17 +741,43 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
64+
updateControllerService(addedService, proposedService, topLevelGroup);
65+
}
66+
67+
- // Update all of the Controller Services to match the VersionedControllerService
68+
+ // Update all Controller Services to match the VersionedControllerService.
69+
+ // Services may be ENABLED here if the outer "affected components" pass did not
70+
+ // disable them (e.g. COMPONENT_ADDED diffs are skipped by AffectedComponentSet).
71+
+ // We must disable before calling updateControllerService, which calls setProperties
72+
+ // which calls verifyModifiable and throws IllegalStateException on ENABLED services.
73+
+ final long stopTimeout = System.currentTimeMillis() + syncOptions.getComponentStopTimeout().toMillis();
74+
for (final Map.Entry<ControllerServiceNode, VersionedControllerService> entry : services.entrySet()) {
75+
final ControllerServiceNode service = entry.getKey();
76+
final VersionedControllerService proposedService = entry.getValue();
77+
78+
if (updatedVersionedComponentIds.contains(proposedService.getIdentifier())) {
79+
- updateControllerService(service, proposedService, topLevelGroup);
80+
- // Any existing component that is modified during synchronization may have its properties reverted to a pre-migration state,
81+
- // so we then add it to the set to allow migrateProperties to be called again to get it back to the migrated state
82+
- createdAndModifiedExtensions.add(new CreatedOrModifiedExtension(service, getPropertyValues(service)));
83+
- LOG.info("Updated {}", service);
84+
+ final Set<ComponentNode> referencesToRestart = new HashSet<>();
85+
+ final Set<ControllerServiceNode> servicesToRestart = new HashSet<>();
86+
+
87+
+ try {
88+
+ try {
89+
+ stopControllerService(service, proposedService, stopTimeout,
90+
+ syncOptions.getComponentStopTimeoutAction(),
91+
+ referencesToRestart, servicesToRestart, syncOptions);
92+
+ } catch (final TimeoutException e) {
93+
+ throw new FlowSynchronizationException("Failed to stop Controller Service " + service + " in preparation for update", e);
94+
+ } catch (final InterruptedException e) {
95+
+ Thread.currentThread().interrupt();
96+
+ throw new FlowSynchronizationException("Interrupted while stopping Controller Service " + service, e);
97+
+ }
98+
+ updateControllerService(service, proposedService, topLevelGroup);
99+
+ createdAndModifiedExtensions.add(new CreatedOrModifiedExtension(service, getPropertyValues(service)));
100+
+ LOG.info("Updated {}", service);
101+
+ } finally {
102+
+ // Re-enable services and restart components that were stopped for the update,
103+
+ // restoring the controller to its pre-update running state.
104+
+ if (proposedService.getScheduledState() != org.apache.nifi.flow.ScheduledState.DISABLED) {
105+
+ context.getControllerServiceProvider().enableControllerServicesAsync(servicesToRestart);
106+
+ context.getControllerServiceProvider().scheduleReferencingComponents(
107+
+ service, referencesToRestart, context.getComponentScheduler());
108+
+ }
109+
+ }
110+
}
111+
}
112+
113+
@@ -1375,7 +1401,7 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
114+
115+
private ProcessGroup addProcessGroup(final ProcessGroup destination, final VersionedProcessGroup proposed, final ComponentIdGenerator componentIdGenerator,
116+
final Map<String, VersionedParameterContext> versionedParameterContexts,
117+
- final Map<String, ParameterProviderReference> parameterProviderReferences, ProcessGroup topLevelGroup) throws ProcessorInstantiationException {
118+
+ final Map<String, ParameterProviderReference> parameterProviderReferences, ProcessGroup topLevelGroup) throws ProcessorInstantiationException, FlowSynchronizationException {
119+
final String id = componentIdGenerator.generateUuid(proposed.getIdentifier(), proposed.getInstanceIdentifier(), destination.getIdentifier());
120+
final ProcessGroup group = context.getFlowManager().createProcessGroup(id);
121+
group.setVersionedComponentId(proposed.getIdentifier());

0 commit comments

Comments
 (0)