This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 8e5cf99cd7 NIFI-13556 Fixed logic for identifying components from
uploaded NAR
8e5cf99cd7 is described below
commit 8e5cf99cd71faf6b4954c6f591f49ff3e7423b2d
Author: Bryan Bende <[email protected]>
AuthorDate: Wed Jul 17 12:15:15 2024 -0400
NIFI-13556 Fixed logic for identifying components from uploaded NAR
- Return copied set of Extensions from ExtensionManager to avoid concurrent
modification
This closes #9089
Signed-off-by: David Handermann <[email protected]>
---
.../nifi/nar/ComponentNodeDefinitionPredicate.java | 11 +++----
.../nar/ComponentNodeDefinitionPredicateTest.java | 13 ++++----
.../nar/StandardExtensionDiscoveringManager.java | 2 +-
.../tests/system/nar/NarUploadStandaloneIT.java | 35 ++++++++++++++++++++++
4 files changed, 49 insertions(+), 12 deletions(-)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicate.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicate.java
index fc5515c0e1..8f2ed91ef1 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicate.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicate.java
@@ -42,21 +42,22 @@ class ComponentNodeDefinitionPredicate implements
Predicate<ComponentNode> {
}
private <T extends ComponentNode> boolean isComponentFromType(final T
componentNode, final ExtensionDefinition extensionDefinition) {
- final String componentType = componentNode.getComponentType();
+ final String componentClassName =
componentNode.getCanonicalClassName();
final BundleCoordinate componentCoordinate =
componentNode.getBundleCoordinate();
- final String extensionDefinitionType =
extensionDefinition.getImplementationClassName();
+ final String extensionDefinitionClassName =
extensionDefinition.getImplementationClassName();
final BundleCoordinate extensionDefinitionCoordinate =
extensionDefinition.getBundle().getBundleDetails().getCoordinate();
if (PythonBundle.isPythonCoordinate(componentCoordinate)) {
+ final String componentType = componentNode.getComponentType();
final String pythonComponentType = "python." + componentType;
- return pythonComponentType.equals(extensionDefinitionType) &&
componentCoordinate.equals(extensionDefinitionCoordinate);
+ return pythonComponentType.equals(extensionDefinitionClassName) &&
componentCoordinate.equals(extensionDefinitionCoordinate);
} else if (componentNode.isExtensionMissing()) {
- return componentType.equals(extensionDefinitionType)
+ return componentClassName.equals(extensionDefinitionClassName)
&&
componentCoordinate.getGroup().equals(extensionDefinitionCoordinate.getGroup())
&&
componentCoordinate.getId().equals(extensionDefinitionCoordinate.getId());
} else {
- return componentType.equals(extensionDefinitionType) &&
componentCoordinate.equals(extensionDefinitionCoordinate);
+ return componentClassName.equals(extensionDefinitionClassName) &&
componentCoordinate.equals(extensionDefinitionCoordinate);
}
}
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicateTest.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicateTest.java
index 0ebbd51c27..8c185b8c4a 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicateTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/nar/ComponentNodeDefinitionPredicateTest.java
@@ -34,7 +34,8 @@ import static org.mockito.Mockito.when;
public class ComponentNodeDefinitionPredicateTest {
- private static final String STANDARD_PROCESSOR_TYPE =
"org.apache.nifi.MyProcessor";
+ private static final String STANDARD_PROCESSOR_COMPONENT_TYPE =
"MyProcessor";
+ private static final String STANDARD_PROCESSOR_CLASS_NAME =
"org.apache.nifi." + STANDARD_PROCESSOR_COMPONENT_TYPE;
private static final BundleCoordinate STANDARD_BUNDLE_COORDINATE_V1 = new
BundleCoordinate("org.apache.nifi", "my-processors-nar", "1.0.0");
private static final BundleCoordinate STANDARD_BUNDLE_COORDINATE_V2 = new
BundleCoordinate("org.apache.nifi", "my-processors-nar", "2.0.0");
@@ -55,7 +56,7 @@ public class ComponentNodeDefinitionPredicateTest {
when(standardBundle.getBundleDetails()).thenReturn(standardBundleDetails);
standardProcessorDefinition = mock(ExtensionDefinition.class);
-
when(standardProcessorDefinition.getImplementationClassName()).thenReturn(STANDARD_PROCESSOR_TYPE);
+
when(standardProcessorDefinition.getImplementationClassName()).thenReturn(STANDARD_PROCESSOR_CLASS_NAME);
when(standardProcessorDefinition.getBundle()).thenReturn(standardBundle);
final BundleDetails pythonBundleDetails = mock(BundleDetails.class);
@@ -72,7 +73,7 @@ public class ComponentNodeDefinitionPredicateTest {
@Test
public void testWhenComponentNodeMatchesDefinition() {
final ComponentNode componentNode = mock(ComponentNode.class);
-
when(componentNode.getComponentType()).thenReturn(STANDARD_PROCESSOR_TYPE);
+
when(componentNode.getCanonicalClassName()).thenReturn(STANDARD_PROCESSOR_CLASS_NAME);
when(componentNode.getBundleCoordinate()).thenReturn(STANDARD_BUNDLE_COORDINATE_V1);
final Predicate<ComponentNode> predicate = new
ComponentNodeDefinitionPredicate(Set.of(standardProcessorDefinition));
@@ -82,7 +83,7 @@ public class ComponentNodeDefinitionPredicateTest {
@Test
public void testWhenComponentNodeTypeDoesNotMatchDefinition() {
final ComponentNode componentNode = mock(ComponentNode.class);
-
when(componentNode.getComponentType()).thenReturn("com.SomeOtherProcessor");
+
when(componentNode.getCanonicalClassName()).thenReturn("com.SomeOtherProcessor");
when(componentNode.getBundleCoordinate()).thenReturn(STANDARD_BUNDLE_COORDINATE_V1);
final Predicate<ComponentNode> predicate = new
ComponentNodeDefinitionPredicate(Set.of(standardProcessorDefinition));
@@ -92,7 +93,7 @@ public class ComponentNodeDefinitionPredicateTest {
@Test
public void testWhenComponentNodeCoordinateDoesMatchDefinition() {
final ComponentNode componentNode = mock(ComponentNode.class);
-
when(componentNode.getComponentType()).thenReturn(STANDARD_PROCESSOR_TYPE);
+
when(componentNode.getCanonicalClassName()).thenReturn(STANDARD_PROCESSOR_CLASS_NAME);
when(componentNode.getBundleCoordinate()).thenReturn(STANDARD_BUNDLE_COORDINATE_V2);
final Predicate<ComponentNode> predicate = new
ComponentNodeDefinitionPredicate(Set.of(standardProcessorDefinition));
@@ -102,7 +103,7 @@ public class ComponentNodeDefinitionPredicateTest {
@Test
public void testWhenComponentNodeIsMissingAndCompatibleBundle() {
final ComponentNode componentNode = mock(ComponentNode.class);
-
when(componentNode.getComponentType()).thenReturn(STANDARD_PROCESSOR_TYPE);
+
when(componentNode.getCanonicalClassName()).thenReturn(STANDARD_PROCESSOR_CLASS_NAME);
when(componentNode.getBundleCoordinate()).thenReturn(STANDARD_BUNDLE_COORDINATE_V2);
when(componentNode.isExtensionMissing()).thenReturn(true);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
index cf620a52d0..53623a5619 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
@@ -830,7 +830,7 @@ public class StandardExtensionDiscoveringManager implements
ExtensionDiscovering
throw new IllegalArgumentException("Class cannot be null");
}
final Set<ExtensionDefinition> extensions =
definitionMap.get(definition);
- return (extensions == null) ? Collections.emptySet() : extensions;
+ return (extensions == null) ? Collections.emptySet() : new
HashSet<>(extensions);
}
@Override
diff --git
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/nar/NarUploadStandaloneIT.java
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/nar/NarUploadStandaloneIT.java
index 2cf2876090..45a03955b8 100644
---
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/nar/NarUploadStandaloneIT.java
+++
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/nar/NarUploadStandaloneIT.java
@@ -28,8 +28,11 @@ import
org.apache.nifi.web.api.entity.ControllerServiceTypesEntity;
import org.apache.nifi.web.api.entity.NarDetailsEntity;
import org.apache.nifi.web.api.entity.NarSummariesEntity;
import org.apache.nifi.web.api.entity.NarSummaryEntity;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.apache.nifi.web.api.entity.ProcessorTypesEntity;
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
@@ -43,8 +46,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
public class NarUploadStandaloneIT extends NiFiSystemIT {
+ private static final Logger logger =
LoggerFactory.getLogger(NarUploadStandaloneIT.class);
+
private static final String NAR_PROVIDER_NARS_LOCATION =
"target/nifi-nar-provider-nars";
private static final String PROCESSORS_NAR_ID =
"nifi-nar-provider-processors-nar";
+ private static final String PROCESSOR_CLASS_NAME =
"org.apache.nifi.nar.provider.GetClassLoaderInfo";
private static final String CONTROLLER_SERVICE_API_NAR_ID =
"nifi-nar-provider-service-api-nar";
private static final String CONTROLLER_SERVICE_NAR_ID =
"nifi-nar-provider-service-nar";
@@ -116,6 +122,14 @@ public class NarUploadStandaloneIT extends NiFiSystemIT {
assertNotNull(serviceApiNarDetails.getDependentCoordinates());
assertEquals(2, serviceApiNarDetails.getDependentCoordinates().size());
+ // Create instance of the custom processor
+ final NarCoordinateDTO uploadedProcessorCoordinate =
uploadedProcessorsNar.getCoordinate();
+ final ProcessorEntity customProcessor =
getClientUtil().createProcessor(PROCESSOR_CLASS_NAME,
uploadedProcessorCoordinate.getGroup(),
+ uploadedProcessorCoordinate.getArtifact(),
uploadedProcessorCoordinate.getVersion());
+ assertNotNull(customProcessor.getComponent());
+ assertNotNull(customProcessor.getComponent().getExtensionMissing());
+ assertFalse(customProcessor.getComponent().getExtensionMissing());
+
// Verify service API NAR can't be replaced while other NARs depend on
it
assertThrows(NiFiClientException.class, () ->
narUploadUtil.uploadNar(narsLocation, CONTROLLER_SERVICE_API_NAR_ID));
@@ -137,6 +151,27 @@ public class NarUploadStandaloneIT extends NiFiSystemIT {
// Verify no NARs exist
narUploadUtil.verifyNarSummaries(0);
+
+ // Verify custom processor is ghosted
+ final String customProcessorId = customProcessor.getId();
+ waitFor(() -> {
+ final ProcessorEntity customProcessorAfterDelete =
getNifiClient().getProcessorClient().getProcessor(customProcessorId);
+ logger.info("Waiting for processor {} to be considered missing",
customProcessorId);
+ return
customProcessorAfterDelete.getComponent().getExtensionMissing();
+ });
+
+ // Restore NARs
+ narUploadUtil.uploadNar(narsLocation, CONTROLLER_SERVICE_API_NAR_ID);
+ narUploadUtil.uploadNar(narsLocation, CONTROLLER_SERVICE_NAR_ID);
+ final NarSummaryDTO restoredProcessorsNar =
narUploadUtil.uploadNar(narsLocation, PROCESSORS_NAR_ID);
+
waitFor(narUploadUtil.getWaitForNarStateSupplier(restoredProcessorsNar.getIdentifier(),
NarState.INSTALLED));
+
+ // Verify processor is un-ghosted
+ waitFor(() -> {
+ final ProcessorEntity customProcessorAfterDelete =
getNifiClient().getProcessorClient().getProcessor(customProcessorId);
+ logger.info("Waiting for processor {} to be considered not
missing", customProcessorId);
+ return
!customProcessorAfterDelete.getComponent().getExtensionMissing();
+ });
}
private boolean matchingBundles(final BundleDTO bundleDTO, final
NarCoordinateDTO narCoordinateDTO) {