From 96eb1d825a0f23f7b13c4a1f31853b0cef10b7bc Mon Sep 17 00:00:00 2001 From: Bryan Bende Date: Fri, 13 Oct 2023 13:51:47 -0400 Subject: [PATCH] NIFI-12222 Protect against missing parameter context when syncing a PG in component synchronizer (#7877) --- ...tandardVersionedComponentSynchronizer.java | 41 +++++++------- ...ardVersionedComponentSynchronizerTest.java | 53 +++++++++++++++++++ 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java index c63d1587d2..df837ac17e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java @@ -17,7 +17,6 @@ package org.apache.nifi.flow.synchronization; -import org.apache.commons.lang3.StringUtils; import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.connectable.Connectable; @@ -1888,31 +1887,27 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen group.setParameterContext(null); } else if (proposedParameterContextName != null) { final VersionedParameterContext versionedParameterContext = versionedParameterContexts.get(proposedParameterContextName); - createMissingParameterProvider(versionedParameterContext, versionedParameterContext.getParameterProvider(), parameterProviderReferences, componentIdGenerator); - if (currentParamContext == null) { - // Create a new Parameter Context based on the parameters provided + if (versionedParameterContext != null) { + createMissingParameterProvider(versionedParameterContext, versionedParameterContext.getParameterProvider(), parameterProviderReferences, componentIdGenerator); + if (currentParamContext == null) { + // Create a new Parameter Context based on the parameters provided + final ParameterContext contextByName = getParameterContextByName(versionedParameterContext.getName()); + final ParameterContext selectedParameterContext; + if (contextByName == null) { + final String parameterContextId = componentIdGenerator.generateUuid(versionedParameterContext.getName(), + versionedParameterContext.getName(), versionedParameterContext.getName()); + selectedParameterContext = createParameterContext(versionedParameterContext, parameterContextId, versionedParameterContexts, + parameterProviderReferences, componentIdGenerator); + } else { + selectedParameterContext = contextByName; + addMissingConfiguration(versionedParameterContext, selectedParameterContext, versionedParameterContexts, parameterProviderReferences, componentIdGenerator); + } - // Protect against NPE in the event somehow the proposed name is not in the set of contexts - if (versionedParameterContext == null) { - final String paramContextNames = StringUtils.join(versionedParameterContexts.keySet()); - throw new IllegalStateException("Proposed parameter context name '" + proposedParameterContextName - + "' does not exist in set of available parameter contexts [" + paramContextNames + "]"); - } - - final ParameterContext contextByName = getParameterContextByName(versionedParameterContext.getName()); - final ParameterContext selectedParameterContext; - if (contextByName == null) { - final String parameterContextId = componentIdGenerator.generateUuid(versionedParameterContext.getName(), versionedParameterContext.getName(), versionedParameterContext.getName()); - selectedParameterContext = createParameterContext(versionedParameterContext, parameterContextId, versionedParameterContexts, parameterProviderReferences, componentIdGenerator); + group.setParameterContext(selectedParameterContext); } else { - selectedParameterContext = contextByName; - addMissingConfiguration(versionedParameterContext, selectedParameterContext, versionedParameterContexts, parameterProviderReferences, componentIdGenerator); + // Update the current Parameter Context so that it has any Parameters included in the proposed context + addMissingConfiguration(versionedParameterContext, currentParamContext, versionedParameterContexts, parameterProviderReferences, componentIdGenerator); } - - group.setParameterContext(selectedParameterContext); - } else { - // Update the current Parameter Context so that it has any Parameters included in the proposed context - addMissingConfiguration(versionedParameterContext, currentParamContext, versionedParameterContexts, parameterProviderReferences, componentIdGenerator); } } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java index 850ec585b2..66f8eb2ed7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java @@ -40,18 +40,23 @@ import org.apache.nifi.flow.Bundle; import org.apache.nifi.flow.ComponentType; import org.apache.nifi.flow.ConnectableComponent; import org.apache.nifi.flow.ConnectableComponentType; +import org.apache.nifi.flow.ExecutionEngine; import org.apache.nifi.flow.Position; import org.apache.nifi.flow.ScheduledState; import org.apache.nifi.flow.VersionedComponent; import org.apache.nifi.flow.VersionedConnection; import org.apache.nifi.flow.VersionedControllerService; +import org.apache.nifi.flow.VersionedExternalFlow; import org.apache.nifi.flow.VersionedParameter; import org.apache.nifi.flow.VersionedParameterContext; import org.apache.nifi.flow.VersionedPort; +import org.apache.nifi.flow.VersionedProcessGroup; import org.apache.nifi.flow.VersionedProcessor; import org.apache.nifi.flow.VersionedPropertyDescriptor; import org.apache.nifi.groups.ComponentIdGenerator; import org.apache.nifi.groups.ComponentScheduler; +import org.apache.nifi.groups.FlowFileConcurrency; +import org.apache.nifi.groups.FlowFileOutboundPolicy; import org.apache.nifi.groups.FlowSynchronizationOptions; import org.apache.nifi.groups.ProcessGroup; import org.apache.nifi.groups.ScheduledStateChangeListener; @@ -1090,6 +1095,54 @@ public class StandardVersionedComponentSynchronizerTest { assertEquals(new HashSet<>(Arrays.asList("abc", "secret", "Added", "Added 2")), synchronizer.getUpdatedParameterNames(existing, proposed)); } + @Test + public void testUpdateParameterContextWhenContextDoesNotExist() { + final ProcessGroup processGroup = mock(ProcessGroup.class); + when(processGroup.getIdentifier()).thenReturn("pg1"); + when(processGroup.getPosition()).thenReturn(new org.apache.nifi.connectable.Position(0, 0)); + when(processGroup.getFlowFileConcurrency()).thenReturn(FlowFileConcurrency.UNBOUNDED); + when(processGroup.getFlowFileOutboundPolicy()).thenReturn(FlowFileOutboundPolicy.BATCH_OUTPUT); + when(processGroup.getExecutionEngine()).thenReturn(ExecutionEngine.STANDARD); + + final VersionedProcessGroup rootGroup = new VersionedProcessGroup(); + rootGroup.setIdentifier("pg1"); + rootGroup.setParameterContextName("does-not-exist"); + + final VersionedExternalFlow externalFlow = new VersionedExternalFlow(); + externalFlow.setFlowContents(rootGroup); + externalFlow.setParameterContexts(Collections.emptyMap()); + + synchronizer.synchronize(processGroup, externalFlow, synchronizationOptions); + verify(processGroup, times(0)).setParameterContext(any(ParameterContext.class)); + } + + @Test + public void testUpdateParameterContextWhenContextDoesExist() { + final ProcessGroup processGroup = mock(ProcessGroup.class); + when(processGroup.getIdentifier()).thenReturn("pg1"); + when(processGroup.getPosition()).thenReturn(new org.apache.nifi.connectable.Position(0, 0)); + when(processGroup.getFlowFileConcurrency()).thenReturn(FlowFileConcurrency.UNBOUNDED); + when(processGroup.getFlowFileOutboundPolicy()).thenReturn(FlowFileOutboundPolicy.BATCH_OUTPUT); + when(processGroup.getExecutionEngine()).thenReturn(ExecutionEngine.STANDARD); + + final VersionedParameterContext parameterContext = new VersionedParameterContext(); + parameterContext.setName("My Params"); + parameterContext.setParameters(Collections.emptySet()); + + final Map parameterContextMap = new HashMap<>(); + parameterContextMap.put(parameterContext.getName(), parameterContext); + + final VersionedProcessGroup rootGroup = new VersionedProcessGroup(); + rootGroup.setIdentifier("pg1"); + rootGroup.setParameterContextName(parameterContext.getName()); + + final VersionedExternalFlow externalFlow = new VersionedExternalFlow(); + externalFlow.setFlowContents(rootGroup); + externalFlow.setParameterContexts(parameterContextMap); + + synchronizer.synchronize(processGroup, externalFlow, synchronizationOptions); + verify(processGroup, times(1)).setParameterContext(any(ParameterContext.class)); + } private VersionedParameterContext createVersionedParameterContext(final String name, final Map parameters, final Set sensitiveParamNames) { final Set versionedParameters = new HashSet<>();