Skip to content

Commit b172633

Browse files
committed
add property for root name and patch 2.6.0
1 parent ce9a8db commit b172633

File tree

2 files changed

+260
-32
lines changed

2 files changed

+260
-32
lines changed

nifi/stackable/patches/2.4.0/0005-replace-process-groups-root-with-root-ID.patch

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
1-
From 1caea87a7a4806dd0a233cfac2ee2a4dc7994dd7 Mon Sep 17 00:00:00 2001
1+
From cd8d70c7fc112bfe1cd4478bb477b15e70744da1 Mon Sep 17 00:00:00 2001
22
From: Andrew Kenworthy <andrew.kenworthy@stackable.tech>
33
Date: Fri, 10 Oct 2025 15:28:56 +0200
44
Subject: replace process groups root with root ID
55

66
---
7-
.../nifi/flow/FlowInitializationCallback.java | 9 +++++
8-
.../FileAccessPolicyProvider.java | 37 +++++++++++++++++++
9-
.../FileAuthorizerInitializer.java | 25 +++++++++++++
10-
.../nifi/controller/StandardFlowService.java | 17 +++++++++
11-
4 files changed, 88 insertions(+)
7+
.../org/apache/nifi/util/NiFiProperties.java | 3 ++
8+
.../nifi/flow/FlowInitializationCallback.java | 9 ++++
9+
.../FileAccessPolicyProvider.java | 43 +++++++++++++++++++
10+
.../FileAuthorizerInitializer.java | 25 +++++++++++
11+
.../nifi/controller/StandardFlowService.java | 17 ++++++++
12+
5 files changed, 97 insertions(+)
1213
create mode 100644 nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
1314
create mode 100644 nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
1415

16+
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
17+
index 4bd2f4f810..24d31960b7 100644
18+
--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
19+
+++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
20+
@@ -336,6 +336,9 @@ public class NiFiProperties extends ApplicationProperties {
21+
// performance tracking defaults
22+
public static final int DEFAULT_TRACK_PERFORMANCE_PERCENTAGE = 0;
23+
24+
+ // root process group replacement
25+
+ public static final String ROOT_PROCESS_GROUP_PLACEHOLDER ="nifi.process.group.root.placeholder";
26+
+
27+
// defaults
28+
public static final Boolean DEFAULT_AUTO_RESUME_STATE = true;
29+
public static final String DEFAULT_AUTHORIZER_CONFIGURATION_FILE = "conf/authorizers.xml";
1530
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
1631
new file mode 100644
1732
index 0000000000..3039c97497
@@ -28,18 +43,35 @@ index 0000000000..3039c97497
2843
+ void onRootGroupLoaded();
2944
+}
3045
diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
31-
index 5363bb5619..5ed48a5af9 100644
46+
index 5363bb5619..db377bb9d3 100644
3247
--- a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
3348
+++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
34-
@@ -29,6 +29,7 @@ import org.apache.nifi.authorization.resource.ResourceType;
49+
@@ -16,6 +16,7 @@
50+
*/
51+
package org.apache.nifi.authorization;
52+
53+
+import com.google.common.base.Strings;
54+
import org.apache.commons.lang3.StringUtils;
55+
import org.apache.nifi.authorization.annotation.AuthorizerContext;
56+
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
57+
@@ -29,6 +30,7 @@ import org.apache.nifi.authorization.resource.ResourceType;
3558
import org.apache.nifi.authorization.util.IdentityMapping;
3659
import org.apache.nifi.authorization.util.IdentityMappingUtil;
3760
import org.apache.nifi.components.PropertyValue;
3861
+import org.apache.nifi.controller.StandardFlowService;
3962
import org.apache.nifi.util.FlowInfo;
4063
import org.apache.nifi.util.FlowParser;
4164
import org.apache.nifi.util.NiFiProperties;
42-
@@ -133,6 +134,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
65+
@@ -77,6 +79,8 @@ import java.util.concurrent.atomic.AtomicReference;
66+
import java.util.regex.Matcher;
67+
import java.util.regex.Pattern;
68+
69+
+import static org.apache.nifi.util.NiFiProperties.ROOT_PROCESS_GROUP_PLACEHOLDER;
70+
+
71+
public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvider {
72+
73+
private static final Logger logger = LoggerFactory.getLogger(FileAccessPolicyProvider.class);
74+
@@ -133,6 +137,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
4375
public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
4476
userGroupProviderLookup = initializationContext.getUserGroupProviderLookup();
4577

@@ -49,7 +81,7 @@ index 5363bb5619..5ed48a5af9 100644
4981
try {
5082
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
5183
authorizationsSchema = schemaFactory.newSchema(FileAccessPolicyProvider.class.getResource(AUTHORIZATIONS_XSD));
52-
@@ -744,6 +748,39 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
84+
@@ -744,6 +751,42 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
5385
}
5486
}
5587

@@ -59,30 +91,33 @@ index 5363bb5619..5ed48a5af9 100644
5991
+ * then use "root" as a placeholder.
6092
+ */
6193
+ public void replaceWithRootGroupId() throws JAXBException {
62-
+ if (rootGroupId == null) {
63-
+ logger.info("Parsing flow as rootGroupId is not yet defined");
64-
+ parseFlow();
65-
+ }
66-
+ if (rootGroupId != null) {
67-
+ logger.info("Parsing root group with {}", rootGroupId);
68-
+ Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
69-
+ boolean authorizationsChanged = false;
70-
+ for (Policy policy: authorizations.getPolicies().getPolicy()) {
71-
+ String resource = policy.getResource();
72-
+ String processGroupRoot = ResourceType.ProcessGroup.getValue() + "/root";
73-
+ if (resource.endsWith(processGroupRoot)) {
74-
+ int pos = resource.indexOf(processGroupRoot);
75-
+ policy.setResource(resource.substring(0, pos) + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId);
76-
+ authorizationsChanged = true;
77-
+ }
94+
+ String placeholder = this.properties.getProperty(ROOT_PROCESS_GROUP_PLACEHOLDER, "");
95+
+ if (!Strings.isNullOrEmpty(placeholder)) {
96+
+ if (rootGroupId == null) {
97+
+ logger.info("Parsing flow as rootGroupId is not yet defined");
98+
+ parseFlow();
7899
+ }
79-
+ if (authorizationsChanged) {
80-
+ saveAndRefreshHolder(authorizations);
100+
+ if (rootGroupId != null) {
101+
+ logger.info("Parsing root group with {}", rootGroupId);
102+
+ Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
103+
+ boolean authorizationsChanged = false;
104+
+ for (Policy policy: authorizations.getPolicies().getPolicy()) {
105+
+ String resource = policy.getResource();
106+
+ String processGroupRoot = ResourceType.ProcessGroup.getValue() + "/" + placeholder;
107+
+ if (resource.endsWith(processGroupRoot)) {
108+
+ int pos = resource.indexOf(processGroupRoot);
109+
+ policy.setResource(resource.substring(0, pos) + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId);
110+
+ authorizationsChanged = true;
111+
+ }
112+
+ }
113+
+ if (authorizationsChanged) {
114+
+ saveAndRefreshHolder(authorizations);
115+
+ }
116+
+ } else {
117+
+ // this is not expected as this is called from the flow service
118+
+ // once it has been configured
119+
+ logger.info("rootGroupId still not established!");
81120
+ }
82-
+ } else {
83-
+ // this is not expected as this is called from the flow service
84-
+ // once it has been configured
85-
+ logger.info("rootGroupId still not established!");
86121
+ }
87122
+ }
88123
+
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
From 5abbf351e769a64019332335da5f7d12c6c85868 Mon Sep 17 00:00:00 2001
2+
From: Andrew Kenworthy <andrew.kenworthy@stackable.tech>
3+
Date: Thu, 4 Dec 2025 15:07:07 +0100
4+
Subject: replace process groups root with root ID
5+
6+
---
7+
.../org/apache/nifi/util/NiFiProperties.java | 3 ++
8+
.../nifi/flow/FlowInitializationCallback.java | 9 ++++
9+
.../FileAccessPolicyProvider.java | 43 +++++++++++++++++++
10+
.../FileAuthorizerInitializer.java | 25 +++++++++++
11+
.../nifi/controller/StandardFlowService.java | 17 ++++++++
12+
5 files changed, 97 insertions(+)
13+
create mode 100644 nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
14+
create mode 100644 nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
15+
16+
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
17+
index 9c26cb7eb3..3a4d79eaea 100644
18+
--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
19+
+++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
20+
@@ -335,6 +335,9 @@ public class NiFiProperties extends ApplicationProperties {
21+
// performance tracking defaults
22+
public static final int DEFAULT_TRACK_PERFORMANCE_PERCENTAGE = 0;
23+
24+
+ // root process group replacement
25+
+ public static final String ROOT_PROCESS_GROUP_PLACEHOLDER ="nifi.process.group.root.placeholder";
26+
+
27+
// defaults
28+
public static final Boolean DEFAULT_AUTO_RESUME_STATE = true;
29+
public static final String DEFAULT_AUTHORIZER_CONFIGURATION_FILE = "conf/authorizers.xml";
30+
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
31+
new file mode 100644
32+
index 0000000000..3039c97497
33+
--- /dev/null
34+
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
35+
@@ -0,0 +1,9 @@
36+
+package org.apache.nifi.flow;
37+
+
38+
+/**
39+
+ * Simple callback interface invoked when the root process group has been
40+
+ * loaded and the flow is fully initialized for the first time.
41+
+ */
42+
+public interface FlowInitializationCallback {
43+
+ void onRootGroupLoaded();
44+
+}
45+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
46+
index b4a0be42d3..5100a3ba21 100644
47+
--- a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
48+
+++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
49+
@@ -34,6 +34,7 @@ import org.apache.nifi.authorization.resource.ResourceType;
50+
import org.apache.nifi.authorization.util.IdentityMapping;
51+
import org.apache.nifi.authorization.util.IdentityMappingUtil;
52+
import org.apache.nifi.components.PropertyValue;
53+
+import org.apache.nifi.controller.StandardFlowService;
54+
import org.apache.nifi.util.FlowInfo;
55+
import org.apache.nifi.util.FlowParser;
56+
import org.apache.nifi.util.NiFiProperties;
57+
@@ -77,6 +78,8 @@ import java.util.concurrent.atomic.AtomicReference;
58+
import java.util.regex.Matcher;
59+
import java.util.regex.Pattern;
60+
61+
+import static org.apache.nifi.util.NiFiProperties.ROOT_PROCESS_GROUP_PLACEHOLDER;
62+
+
63+
public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvider {
64+
65+
private static final Logger logger = LoggerFactory.getLogger(FileAccessPolicyProvider.class);
66+
@@ -135,6 +138,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
67+
public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
68+
userGroupProviderLookup = initializationContext.getUserGroupProviderLookup();
69+
70+
+ // Register flow initialization hook
71+
+ StandardFlowService.registerInitializationCallback(new FileAuthorizerInitializer(this));
72+
+
73+
try {
74+
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
75+
authorizationsSchema = schemaFactory.newSchema(FileAccessPolicyProvider.class.getResource(AUTHORIZATIONS_XSD));
76+
@@ -764,6 +770,43 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
77+
}
78+
}
79+
80+
+ /**
81+
+ * Replaces process group root references with the process group ID.
82+
+ * Relevant when a static authorizations file is provided, which can
83+
+ * then use "root" as a placeholder.
84+
+ */
85+
+ public void replaceWithRootGroupId() throws JAXBException {
86+
+ String placeholder = this.properties.getProperty(ROOT_PROCESS_GROUP_PLACEHOLDER, "");
87+
+
88+
+ if (!StringUtils.isNotBlank(placeholder)) {
89+
+ if (rootGroupId == null) {
90+
+ logger.info("Parsing flow as rootGroupId is not yet defined");
91+
+ parseFlow();
92+
+ }
93+
+ if (rootGroupId != null) {
94+
+ logger.info("Parsing root group with {}", rootGroupId);
95+
+ Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
96+
+ boolean authorizationsChanged = false;
97+
+ for (Policy policy: authorizations.getPolicies().getPolicy()) {
98+
+ String resource = policy.getResource();
99+
+ String processGroupRoot = ResourceType.ProcessGroup.getValue() + "/" + placeholder;
100+
+ if (resource.endsWith(processGroupRoot)) {
101+
+ int pos = resource.indexOf(processGroupRoot);
102+
+ policy.setResource(resource.substring(0, pos) + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId);
103+
+ authorizationsChanged = true;
104+
+ }
105+
+ }
106+
+ if (authorizationsChanged) {
107+
+ saveAndRefreshHolder(authorizations);
108+
+ }
109+
+ } else {
110+
+ // this is not expected as this is called from the flow service
111+
+ // once it has been configured
112+
+ logger.info("rootGroupId still not established!");
113+
+ }
114+
+ }
115+
+ }
116+
+
117+
/**
118+
* Creates and adds an access policy for the given resource, identity, and actions to the specified authorizations.
119+
*
120+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
121+
new file mode 100644
122+
index 0000000000..f67328ef84
123+
--- /dev/null
124+
+++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
125+
@@ -0,0 +1,25 @@
126+
+package org.apache.nifi.authorization;
127+
+
128+
+import org.apache.nifi.flow.FlowInitializationCallback;
129+
+import org.slf4j.Logger;
130+
+import org.slf4j.LoggerFactory;
131+
+
132+
+
133+
+public class FileAuthorizerInitializer implements FlowInitializationCallback {
134+
+ private static final Logger logger = LoggerFactory.getLogger(FileAuthorizerInitializer.class);
135+
+private FileAccessPolicyProvider fileAccessPolicyProvider;
136+
+
137+
+ public FileAuthorizerInitializer(FileAccessPolicyProvider fileAccessPolicyProvider) {
138+
+ this.fileAccessPolicyProvider = fileAccessPolicyProvider;
139+
+ }
140+
+
141+
+ @Override
142+
+ public void onRootGroupLoaded() {
143+
+ try {
144+
+ logger.info("Flow initialized; ensuring root group ID is recorded in authorizations.xml");
145+
+ this.fileAccessPolicyProvider.replaceWithRootGroupId();
146+
+ } catch (Exception e) {
147+
+ logger.warn("Unable to update authorizations.xml with root group ID", e);
148+
+ }
149+
+ }
150+
+}
151+
\ No newline at end of file
152+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
153+
index 5de3486164..2873b26644 100644
154+
--- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
155+
+++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
156+
@@ -55,6 +55,7 @@ import org.apache.nifi.controller.serialization.FlowSynchronizationException;
157+
import org.apache.nifi.controller.status.ProcessGroupStatus;
158+
import org.apache.nifi.engine.FlowEngine;
159+
import org.apache.nifi.events.BulletinFactory;
160+
+import org.apache.nifi.flow.FlowInitializationCallback;
161+
import org.apache.nifi.groups.BundleUpdateStrategy;
162+
import org.apache.nifi.groups.ProcessGroup;
163+
import org.apache.nifi.groups.RemoteProcessGroup;
164+
@@ -148,6 +149,13 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
165+
private static final String CONNECTION_EXCEPTION_MSG_PREFIX = "Failed to connect node to cluster";
166+
private static final Logger logger = LoggerFactory.getLogger(StandardFlowService.class);
167+
168+
+ // Static callback registration for post-initialization hooks
169+
+ private static volatile FlowInitializationCallback initializationCallback;
170+
+
171+
+ public static void registerInitializationCallback(FlowInitializationCallback callback) {
172+
+ initializationCallback = callback;
173+
+ }
174+
+
175+
public static StandardFlowService createStandaloneInstance(
176+
final FlowController controller,
177+
final NiFiProperties nifiProperties,
178+
@@ -935,6 +943,15 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
179+
// start the processors as indicated by the dataflow
180+
controller.onFlowInitialized(autoResumeState);
181+
182+
+ // this should be done once the flow has been initialized
183+
+ if (initializationCallback != null) {
184+
+ try {
185+
+ initializationCallback.onRootGroupLoaded();
186+
+ } catch (Exception e) {
187+
+ logger.warn("Error invoking FlowInitializationCallback", e);
188+
+ }
189+
+ }
190+
+
191+
loadSnippets(dataFlow.getSnippets());
192+
193+
controller.startHeartbeating();

0 commit comments

Comments
 (0)