New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NIFI-6872: support download flow #3931
Conversation
- Added UI versioned flow supportsDownload functionality with download flow menu item - Added VersionsResource endpoint for downloading versioned flow with registry-related info removed - Added ProcessGroupResource endpoint for downloading current flow with registry-related info removed - Added StandardNifiServiceFacade functionality for downloading both current and versioned flow - Added XmlTransient markers on variables introduced by Instantiated model classes so they do not appear in serialized download - Updated NiFiRegistryFlowMapper.mapParameterContexts to handle mapping nested parameter contexts for use in producing a complete VersionedFlowSnapshot - Added ability for NiFiRegistryFlowMapper to map nested process groups ignoring versioning for use in producing a complete VersionedFlowSnapshot - Added unit tests where helpful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @jsferner thanks for the contribution! This is awesome! I made a few minor stylistic comments but those are not a really big deal. You can ignore them if you disagree. The only thing I think needs to be changed is the comment made in the StandardNiFiServiceFacade regarding mapping of the Collection to a Map, which can contain duplicate keys and cause an IllegalStateException. Thanks for an awesome contribution!
} | ||
} | ||
// apply registry versioning according to the lambda below | ||
// NOTE: lambda refers to registry client and map descendant boolean which will not change during recursion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might read more clearly if this lambda were instead created as a method: boolean isMapDescendants(ProcessGroup processGroup, VersionedProcessGroup versionedGroup)
and then referenced here as return mapGroup(group, serviceProvider, this::isMapDescendants)
. I think this would avoid having a lengthy lambda and obviate the need for documentation explaining the point of the lambda.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to make the lambda a separate method but it actually would require taking in 2 more arguments because it's currently referencing those arguments locally where it's defined inline (registryClient and mapDescendantVersionedFlows). The values of these args don't change during recursion, they just get passed down through so it made more sense to just reference them in the lambda rather than expect them to also be passed in when it's called. Does that make sense?
final Set<VersionedParameter> parameters = context.getParameters().values().stream() | ||
.map(this::mapParameter) | ||
.collect(Collectors.toSet()); | ||
public Collection<VersionedParameterContext> mapParameterContexts(final ProcessGroup processGroup, final boolean mapDescendantVersionedFlows) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am thinking out loud a bit here. I don't yet fully understand the entire context around where this will be used. But it seems to me anywhere that we would want a Collection of VersionedParameterContext it would probably make sense to restrict it to a Set<VersionedParameterContext>
. Because we can certainly have the case where descendant Process Groups will reference the same ParameterContext as a parent/ancestor Process Group. I don't think we would actually want the context in the Collection multiple times, would we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, moving everything to a Map to begin with, as we discussed
final boolean includeRemoteProcessGroup, final boolean includeVersionControlInfo, | ||
final List<ProcessGroup> childProcessGroups) { | ||
final String processGroupId = UUID.randomUUID().toString(); | ||
final ProcessGroup processGroup = mock(ProcessGroup.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like there's quite a lot of mocking going on here for the ProcessGroup. There already exists a MockProcessGroup
class that may simplify this quite a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MockProcessGroup was limited in what it was implementing already so I couldn't use it without adding a ton more implementation. Since this mapper exercises almost all the elements of a process group, it was going to take quite a bit to make the MockProcessGroup usable.
final String expectedGroupIdentifier = flowMapper.getGroupId(processGroup.getProcessGroupIdentifier()); | ||
|
||
// verify process group fields | ||
assertEquals(versionedProcessGroup.getName(), processGroup.getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big deal, but I think all of these asserts are passing the arguments backwards. The signature is assertEquals(Object expected, Object actual)
but it looks like all of these assertions are made such that the actual value is passed before the expected value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, updating all
// Create a complete (include descendant flows) map of parameter contexts | ||
final Collection<VersionedParameterContext> parameterContexts = | ||
mapper.mapParameterContexts(processGroup, true); | ||
final Map<String, VersionedParameterContext> parameterContextMap = parameterContexts.stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above, about the creation of Collection<VersionedParameterContext>
with regards to changing to a Set<VersionedParameterContext>
. As this is currently written, if we have Group A with Parameter Context A, and a child group, Group B, also with Parameter Context A, this will result in the Collection<VersionedParameterContext>
containing two VersionedParameterContext
objects with the same name. This line of code will now throw an IllegalStateException
because it will result in the Map that is being formed having duplicate keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, moving everything to a Map as we discussed
Also noticed that Travis flagged 1 checkstyle violation: |
Fixed checkstyle failure |
Will also have a look to review the front end changes... |
* | ||
* @param processGroupId | ||
*/ | ||
downloadFlowVersion: function (processGroupId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not appear to be invoked. I'd recommend removing it as it would need to be updated to support a One Time Password if we wanted to leave it in place.
} | ||
|
||
if (processGroupId !== null) { | ||
window.open('../nifi-api/process-groups/' + encodeURIComponent(processGroupId) + '/download'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For when the user is authenticated and leveraging a token that is presented in a HTTP header, we need to update this endpoint to utilize a One Time Password which is included in a query parameter. This is necessary because the code that adds the token to the header down not execute within the new window from the window.open
call.
Please check out provenance download or content download for an example.
- Updated mapParameterContext to return a Map to handle uniqueness of contexts by name since ultimately everything converted it to a map anyway. The VersionedParameterContext class from the registry model doesn't support hashcode/equals currently so returning a Set wouldn't work. - Updated assert calls to put expected value as first parameter and actual as second parameter - Added one time password (OTP) support for flow download endpoint to support non cert based authentication
Thanks for the update @jsferner ! The code looks good from my perspective. I haven't had a chance yet to test with the update, though. Once I can test and verify behavior I'm a +1. Or if you have a chance to verify behavior, @mcgilman, feel free to merge it in if you're happy with the update as well. |
- Added UI versioned flow supportsDownload functionality with download flow menu item - Added VersionsResource endpoint for downloading versioned flow with registry-related info removed - Added ProcessGroupResource endpoint for downloading current flow with registry-related info removed - Added StandardNifiServiceFacade functionality for downloading both current and versioned flow - Added XmlTransient markers on variables introduced by Instantiated model classes so they do not appear in serialized download - Updated NiFiRegistryFlowMapper.mapParameterContexts to handle mapping nested parameter contexts for use in producing a complete VersionedFlowSnapshot - Added ability for NiFiRegistryFlowMapper to map nested process groups ignoring versioning for use in producing a complete VersionedFlowSnapshot - Added unit tests where helpful NIFI-6872: PR response... - Updated mapParameterContext to return a Map to handle uniqueness of contexts by name since ultimately everything converted it to a map anyway. The VersionedParameterContext class from the registry model doesn't support hashcode/equals currently so returning a Set wouldn't work. - Updated assert calls to put expected value as first parameter and actual as second parameter - Added one time password (OTP) support for flow download endpoint to support non cert based authentication This closes apache#3931
- Added UI versioned flow supportsDownload functionality with download flow menu item - Added VersionsResource endpoint for downloading versioned flow with registry-related info removed - Added ProcessGroupResource endpoint for downloading current flow with registry-related info removed - Added StandardNifiServiceFacade functionality for downloading both current and versioned flow - Added XmlTransient markers on variables introduced by Instantiated model classes so they do not appear in serialized download - Updated NiFiRegistryFlowMapper.mapParameterContexts to handle mapping nested parameter contexts for use in producing a complete VersionedFlowSnapshot - Added ability for NiFiRegistryFlowMapper to map nested process groups ignoring versioning for use in producing a complete VersionedFlowSnapshot - Added unit tests where helpful NIFI-6872: PR response... - Updated mapParameterContext to return a Map to handle uniqueness of contexts by name since ultimately everything converted it to a map anyway. The VersionedParameterContext class from the registry model doesn't support hashcode/equals currently so returning a Set wouldn't work. - Updated assert calls to put expected value as first parameter and actual as second parameter - Added one time password (OTP) support for flow download endpoint to support non cert based authentication This closes apache#3931
NIFI-6872: