[ 
https://issues.apache.org/jira/browse/NIFI-11192?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Matt Burgess updated NIFI-11192:
--------------------------------
    Resolution: Fixed
        Status: Resolved  (was: Patch Available)

> If Port moved from parent to child group or vice versa between flow versions, 
> version change can leave nifi in bad state
> ------------------------------------------------------------------------------------------------------------------------
>
>                 Key: NIFI-11192
>                 URL: https://issues.apache.org/jira/browse/NIFI-11192
>             Project: Apache NiFi
>          Issue Type: Bug
>          Components: Core Framework
>            Reporter: Mark Payne
>            Assignee: Mark Payne
>            Priority: Blocker
>             Fix For: 2.0.0, 1.21.0
>
>          Time Spent: 40m
>  Remaining Estimate: 0h
>
> To reproduce:
> Create a Process Group, Parent.
> Inside of Parent, create:
>  * A processor, for example, ReplaceText
>  * A Process Group, Child.
> Inside of Child, create:
>  * An Input Port, In
>  * A Processor, for example, UpdateAttribute
>  * A connection between the two components
> Then connect ReplaceText to the Input Port, In.
> Save the Parent PG flow as Version 1 of a flow.
> Now, create a new Processor, say RouteOnAttribute, within the Parent PG.
> Move the destination of the connection from the Input Port to 
> RouteOnAttribute.
> Step into the Child PG. Select all components, right-click, and choose "Move 
> to Parent"
> Save Parent PG as Version 2 of the flow.
> Now, attempt to Change Version on the Parent Group. Change the version to 
> Version 1.
> The version change will fail with an error: "Failed to perform update flow 
> request due to 42fb2904-c774-359b-5368-2e48b60ac02d is the destination of 
> another component" and the logs will have a stack trace:
> {code:java}
> 2023-02-16 15:18:28,830 ERROR [Process Group Update Thread-1] 
> o.apache.nifi.web.api.FlowUpdateResource Failed to perform update flow request
> java.lang.IllegalStateException: 42fb2904-c774-359b-5368-2e48b60ac02d is the 
> destination of another component
>     at 
> org.apache.nifi.controller.AbstractPort.verifyCanDelete(AbstractPort.java:562)
>     at 
> org.apache.nifi.controller.AbstractPort.verifyCanDelete(AbstractPort.java:542)
>     at 
> org.apache.nifi.groups.StandardProcessGroup.removeInputPort(StandardProcessGroup.java:637)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.removeMissingComponents(StandardVersionedComponentSynchronizer.java:948)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.removeMissingInputPorts(StandardVersionedComponentSynchronizer.java:873)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronize(StandardVersionedComponentSynchronizer.java:410)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.lambda$synchronize$0(StandardVersionedComponentSynchronizer.java:260)
>     at 
> org.apache.nifi.controller.flow.AbstractFlowManager.withParameterContextResolution(AbstractFlowManager.java:556)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronize(StandardVersionedComponentSynchronizer.java:255)
>     at 
> org.apache.nifi.groups.StandardProcessGroup.synchronizeFlow(StandardProcessGroup.java:3972)
>     at 
> org.apache.nifi.groups.StandardProcessGroup.updateFlow(StandardProcessGroup.java:3952)
>     at 
> org.apache.nifi.web.dao.impl.StandardProcessGroupDAO.updateProcessGroupFlow(StandardProcessGroupDAO.java:435)
>     at 
> org.apache.nifi.web.dao.impl.StandardProcessGroupDAO$$FastClassBySpringCGLIB$$10a99b47.invoke(<generated>)
>     at 
> org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
>     at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
>     at 
> org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
>     at 
> org.apache.nifi.audit.ProcessGroupAuditor.updateProcessGroupFlowAdvice(ProcessGroupAuditor.java:308)
>     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native 
> Method)
>     at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>     at 
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>     at java.base/java.lang.reflect.Method.invoke(Method.java:566)
>     at 
> org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
>     at 
> org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
>     at 
> org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
>     at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
>     at 
> org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
>     at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
>     at 
> org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
>     at 
> org.apache.nifi.web.dao.impl.StandardProcessGroupDAO$$EnhancerBySpringCGLIB$$2edbbc7e.updateProcessGroupFlow(<generated>)
>     at 
> org.apache.nifi.web.StandardNiFiServiceFacade$13.update(StandardNiFiServiceFacade.java:5848)
>     at 
> org.apache.nifi.web.revision.NaiveRevisionManager.updateRevision(NaiveRevisionManager.java:130)
>     at 
> org.apache.nifi.web.StandardNiFiServiceFacade.updateProcessGroupContents(StandardNiFiServiceFacade.java:5843)
>     at 
> org.apache.nifi.web.StandardNiFiServiceFacade$$FastClassBySpringCGLIB$$358780e0.invoke(<generated>)
>     at 
> org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
>     at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
>     at 
> org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89)
>     at 
> org.apache.nifi.web.NiFiServiceFacadeLock.proceedWithWriteLock(NiFiServiceFacadeLock.java:179)
>     at 
> org.apache.nifi.web.NiFiServiceFacadeLock.updateLock(NiFiServiceFacadeLock.java:66)
>     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native 
> Method)
>     at 
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>     at 
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>     at java.base/java.lang.reflect.Method.invoke(Method.java:566)
>     at 
> org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
>     at 
> org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
>     at 
> org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
>     at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
>     at 
> org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
>     at 
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
>     at 
> org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
>     at 
> org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
>     at 
> org.apache.nifi.web.StandardNiFiServiceFacade$$EnhancerBySpringCGLIB$$cd414c69.updateProcessGroupContents(<generated>)
>     at 
> org.apache.nifi.web.api.VersionsResource.performUpdateFlow(VersionsResource.java:1221)
>     at 
> org.apache.nifi.web.api.VersionsResource.performUpdateFlow(VersionsResource.java:85)
>     at 
> org.apache.nifi.web.api.FlowUpdateResource.updateFlow(FlowUpdateResource.java:428)
>     at 
> org.apache.nifi.web.api.FlowUpdateResource.lambda$submitFlowUpdateRequest$5(FlowUpdateResource.java:281)
>     at 
> org.apache.nifi.web.api.concurrent.AsyncRequestManager$2.run(AsyncRequestManager.java:117)
>     at 
> java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
>     at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
>     at 
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
>     at 
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
>     at java.base/java.lang.Thread.run(Thread.java:829) {code}
> This now leaves NiFi in a bad state, where the flow is partially updated but 
> not fully. What's worse, though, is that it leaves the ReplaceText Processor 
> connected to an Input Port within the same Process Group, which is not legal.
> At this point, the flow has not be written to the flow.json.gz/flow.xml.gz 
> because the update operation failed.
> Now, move the ReplaceText Processor to the side a bit, in order to trigger 
> the flow to be written out again.
> Now, attempt to restart NiFI, and it will fail to startup, yielding the 
> following error in the logs:
> {code:java}
> 2023-02-16 15:23:10,770 WARN [main] org.eclipse.jetty.webapp.WebAppContext 
> Failed startup of context 
> o.e.j.w.WebAppContext@3fe8ad3f{nifi-api,/nifi-api,file:///Users/mpayne/devel/nifi/nifi-assembly/target/nifi-2.0.0-SNAPSHOT-bin/nifi-2.0.0-SNAPSHOT/work/jetty/nifi-web-api-2.0.0-SNAPSHOT.war/webapp/,UNAVAILABLE}{./work/nar/extensions/nifi-server-nar-2.0.0-SNAPSHOT.nar-unpacked/NAR-INF/bundled-dependencies/nifi-web-api-2.0.0-SNAPSHOT.war}
> org.apache.nifi.controller.serialization.FlowSynchronizationException: 
> java.lang.IllegalStateException: Cannot add Connection from 
> PROCESSOR[7a6913fa-3a97-3ce2-c128-d915258fae47] from Process Group 
> [5bd874fd-0186-1000-222a-d40ae014c2d3] to Process Group 
> [5bd874fd-0186-1000-222a-d40ae014c2d3] because its destination 
> [42fb2904-c774-359b-5368-2e48b60ac02d] is an Input Port but the Input Port 
> does not belong to a child Process Group
>     at 
> org.apache.nifi.controller.serialization.VersionedFlowSynchronizer.synchronizeFlow(VersionedFlowSynchronizer.java:448)
>     at 
> org.apache.nifi.controller.serialization.VersionedFlowSynchronizer.sync(VersionedFlowSynchronizer.java:206)
>     at 
> org.apache.nifi.controller.serialization.StandardFlowSynchronizer.sync(StandardFlowSynchronizer.java:42)
>     at 
> org.apache.nifi.controller.FlowController.synchronize(FlowController.java:1638)
>     at 
> org.apache.nifi.persistence.StandardFlowConfigurationDAO.load(StandardFlowConfigurationDAO.java:104)
>     at 
> org.apache.nifi.controller.StandardFlowService.loadFromBytes(StandardFlowService.java:817)
>     at 
> org.apache.nifi.controller.StandardFlowService.load(StandardFlowService.java:538)
>     at 
> org.apache.nifi.web.contextlistener.ApplicationStartupContextListener.contextInitialized(ApplicationStartupContextListener.java:67)
>     at 
> org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:1073)
>     at 
> org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:572)
>     at 
> org.eclipse.jetty.server.handler.ContextHandler.contextInitialized(ContextHandler.java:1002)
>     at 
> org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:765)
>     at 
> org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:379)
>     at 
> org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1449)
>     at 
> org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1414)
>     at 
> org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:916)
>     at 
> org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:288)
>     at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:524)
>     at 
> org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117)
>     at 
> org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
>     at 
> org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:110)
>     at 
> org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
>     at 
> org.eclipse.jetty.server.handler.gzip.GzipHandler.doStart(GzipHandler.java:426)
>     at 
> org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117)
>     at 
> org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
>     at 
> org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117)
>     at 
> org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
>     at 
> org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
>     at org.eclipse.jetty.server.Server.start(Server.java:423)
>     at 
> org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:110)
>     at 
> org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97)
>     at org.eclipse.jetty.server.Server.doStart(Server.java:387)
>     at 
> org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
>     at org.apache.nifi.web.server.JettyServer.start(JettyServer.java:815)
>     at org.apache.nifi.NiFi.<init>(NiFi.java:172)
>     at org.apache.nifi.NiFi.<init>(NiFi.java:83)
>     at org.apache.nifi.NiFi.main(NiFi.java:332)
> Caused by: java.lang.IllegalStateException: Cannot add Connection from 
> PROCESSOR[7a6913fa-3a97-3ce2-c128-d915258fae47] from Process Group 
> [5bd874fd-0186-1000-222a-d40ae014c2d3] to Process Group 
> [5bd874fd-0186-1000-222a-d40ae014c2d3] because its destination 
> [42fb2904-c774-359b-5368-2e48b60ac02d] is an Input Port but the Input Port 
> does not belong to a child Process Group
>     at 
> org.apache.nifi.groups.StandardProcessGroup.addConnection(StandardProcessGroup.java:1310)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.addConnection(StandardVersionedComponentSynchronizer.java:3312)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronizeConnections(StandardVersionedComponentSynchronizer.java:661)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronize(StandardVersionedComponentSynchronizer.java:461)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.addProcessGroup(StandardVersionedComponentSynchronizer.java:1149)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronizeChildGroups(StandardVersionedComponentSynchronizer.java:531)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronize(StandardVersionedComponentSynchronizer.java:417)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.lambda$synchronize$0(StandardVersionedComponentSynchronizer.java:260)
>     at 
> org.apache.nifi.controller.flow.AbstractFlowManager.withParameterContextResolution(AbstractFlowManager.java:556)
>     at 
> org.apache.nifi.flow.synchronization.StandardVersionedComponentSynchronizer.synchronize(StandardVersionedComponentSynchronizer.java:255)
>     at 
> org.apache.nifi.groups.StandardProcessGroup.synchronizeFlow(StandardProcessGroup.java:3972)
>     at 
> org.apache.nifi.controller.serialization.VersionedFlowSynchronizer.synchronizeFlow(VersionedFlowSynchronizer.java:439)
>     ... 45 common frames omitted {code}
> There are two issues here:
>  * We should not fail to update the version of the flow. We need to fix the 
> logic in order to properly handle the moving of a port between groups.
>  * If for some reason, we do fail to perform a Change Version request, we 
> currently leave the flow in a bad state. We should instead revert all changes 
> to the flow for which the change was attempted. This should prevent us from 
> getting the flow into a bad state, even if an update fails.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to