markap14 commented on code in PR #9535:
URL: https://github.com/apache/nifi/pull/9535#discussion_r1854522197
##########
nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java:
##########
@@ -2836,6 +2950,331 @@ public Response importProcessGroup(
}
+ /**
+ * Pastes the specified payload into the given Process Group.
+ *
+ * @param pasteRequestEntity A PasteResponseEntity.
+ * @return A pasteResponseEntity.
+ */
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{id}/paste")
+ @Operation(
+ summary = "Pastes into the specified process group",
+ responses = @ApiResponse(content = @Content(schema =
@Schema(implementation = PasteResponseEntity.class))),
+ security = {
+ @SecurityRequirement(name = "Write -
/process-groups/{uuid}")
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(responseCode = "400", description = "NiFi was
unable to complete the request because it was invalid. The request should not
be retried without modification."),
+ @ApiResponse(responseCode = "401", description = "Client
could not be authenticated."),
+ @ApiResponse(responseCode = "403", description = "Client
is not authorized to make this request."),
+ @ApiResponse(responseCode = "409", description = "The
request was valid but NiFi was not in the appropriate state to process it.")
+ }
+ )
+ public Response paste(
+ @Parameter(
+ description = "The process group id.",
+ required = true
+ )
+ @PathParam("id") final String groupId,
+ @Parameter(
+ description = "The request including the components to be
pasted into the specified Process Group.",
+ required = true
+ ) final PasteRequestEntity pasteRequestEntity) {
+
+ // verify the payload was specified
+ if (pasteRequestEntity == null) {
+ throw new IllegalArgumentException("The paste payload must be
specified.");
+ }
+
+ // verify the revision is specified
+ if (pasteRequestEntity.getRevision() == null) {
+ throw new IllegalArgumentException("Revision must be specified.");
+ }
+
+ // verify the copy response is specified
+ if (pasteRequestEntity.getCopyResponse() == null) {
+ throw new IllegalArgumentException("The details of the copied
components must be specified.");
+ }
+
+ if (isReplicateRequest()) {
+ return replicate(HttpMethod.PUT, pasteRequestEntity);
+ } else if (isDisconnectedFromCluster()) {
+
verifyDisconnectedNodeModification(pasteRequestEntity.getDisconnectedNodeAcknowledged());
+ }
+
+ final CopyResponseEntity copyResponseEntity =
pasteRequestEntity.getCopyResponse();
+ final VersionedProcessGroup versionedProcessGroup =
getVersionedProcessGroup(copyResponseEntity);
+ mapVersionedIds(versionedProcessGroup, new HashMap<>(), new
HashMap<>());
+
+ // resolve Bundle info
+ serviceFacade.discoverCompatibleBundles(versionedProcessGroup);
+
+ // prep a pasted flow snapshot to attempt to resolve external services
and referenced parameter providers
+ final RegisteredFlowSnapshot pastedFlowSnapshot = new
RegisteredFlowSnapshot();
+
pastedFlowSnapshot.setExternalControllerServices(copyResponseEntity.getExternalControllerServiceReferences());
+ pastedFlowSnapshot.setFlowContents(versionedProcessGroup);
+
pastedFlowSnapshot.setParameterContexts(copyResponseEntity.getParameterContexts());
+
pastedFlowSnapshot.setParameterProviders(copyResponseEntity.getParameterProviders());
+
+ // if there are any Controller Services referenced that are inherited
from the parent group,
+ // resolve those to point to the appropriate Controller Service, if we
are able to.
+ final FlowSnapshotContainer flowSnapshotContainer = new
FlowSnapshotContainer(pastedFlowSnapshot);
+ final Set<String> unresolvedControllerServices =
serviceFacade.resolveInheritedControllerServices(flowSnapshotContainer,
groupId, NiFiUserUtils.getNiFiUser());
+
+ // If there are any Parameter Providers referenced by Parameter
Contexts, resolve these to point to the appropriate Parameter Provider, if we
are able to.
+ final Set<String> unresolvedParameterProviders =
serviceFacade.resolveParameterProviders(pastedFlowSnapshot,
NiFiUserUtils.getNiFiUser());
+
+ final Revision requestRevision =
getRevision(pasteRequestEntity.getRevision(), groupId);
+ return withWriteLock(
+ serviceFacade,
+ pasteRequestEntity,
+ requestRevision,
+ lookup -> {
+ final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+ // ensure the user can write to the current group
+ final Authorizable processGroup =
lookup.getProcessGroup(groupId).getAuthorizable();
+ processGroup.authorize(authorizer, RequestAction.WRITE,
user);
+
+ // if the pasted content contains restricted components,
ensure the user is allowed those restrictions
+ final Set<ConfigurableComponent> restrictedComponents =
FlowRegistryUtils.getRestrictedComponents(versionedProcessGroup, serviceFacade);
+ restrictedComponents.forEach(restrictedComponent -> {
+ final ComponentAuthorizable
restrictedComponentAuthorizable =
lookup.getConfigurableComponent(restrictedComponent);
+ authorizeRestrictions(authorizer,
restrictedComponentAuthorizable);
+ });
+
+ // authorize controller services
+
AuthorizeControllerServiceReference.authorizeUnresolvedControllerServiceReferences(groupId,
unresolvedControllerServices, authorizer, lookup, user);
+
+ // if the pasted content contains parameter contexts,
ensure the user can create them or add to existing matching contexts
+ final Map<String, VersionedParameterContext>
parameterContexts = copyResponseEntity.getParameterContexts();
+ if (parameterContexts != null) {
+ parameterContexts.values().forEach(context ->
AuthorizeParameterReference.authorizeParameterContextAddition(context,
serviceFacade, authorizer, lookup, user));
+ }
+
+ // authorize parameter providers
+
AuthorizeParameterProviders.authorizeUnresolvedParameterProviders(unresolvedParameterProviders,
authorizer, lookup, user);
+
+ // if the pasted content contains instance ids, ensure the
user can read those instances since sensitive values will be copied over
+ authorizeInstanceIds(versionedProcessGroup, lookup);
+ },
+ () ->
serviceFacade.verifyComponentTypes(versionedProcessGroup),
+ (revision, requestPasteRequestEntity) -> {
+ final CopyResponseEntity requestCopyResponseEntity =
requestPasteRequestEntity.getCopyResponse();
+
+ // prepare the request to add versioned components
+ final VersionedComponentAdditions additions = new
VersionedComponentAdditions.Builder()
+
.setProcessors(requestCopyResponseEntity.getProcessors())
+
.setInputPorts(requestCopyResponseEntity.getInputPorts())
+
.setOutputPorts(requestCopyResponseEntity.getOutputPorts())
+ .setFunnels(requestCopyResponseEntity.getFunnels())
+ .setLabels(requestCopyResponseEntity.getLabels())
+
.setProcessGroups(requestCopyResponseEntity.getProcessGroups())
+
.setRemoteProcessGroups(requestCopyResponseEntity.getRemoteProcessGroups())
+
.setConnections(requestCopyResponseEntity.getConnections())
+
.setParameterContexts(requestCopyResponseEntity.getParameterContexts())
+
.setParameterProviders(requestCopyResponseEntity.getParameterProviders())
+ .build();
+
+ final PasteResponseEntity pasteResponseEntity =
serviceFacade.pasteComponents(revision, groupId, additions,
getIdGenerationSeed().orElse(null));
+
+ // prune response as necessary
+ for (ProcessGroupEntity childGroupEntity :
pasteResponseEntity.getFlow().getProcessGroups()) {
+ childGroupEntity.getComponent().setContents(null);
+ }
+
+ // create the response entity
+
populateRemainingSnippetContent(pasteResponseEntity.getFlow());
+
+ return generateOkResponse(pasteResponseEntity).build();
+ }
+ );
+ }
+
+ private static VersionedProcessGroup getVersionedProcessGroup(final
CopyResponseEntity copyResponse) {
+ final VersionedProcessGroup versionedProcessGroup = new
VersionedProcessGroup();
+ versionedProcessGroup.setProcessors(new
HashSet<>(copyResponse.getProcessors()));
+ versionedProcessGroup.setInputPorts(new
HashSet<>(copyResponse.getInputPorts()));
+ versionedProcessGroup.setOutputPorts(new
HashSet<>(copyResponse.getOutputPorts()));
+ versionedProcessGroup.setProcessGroups(new
HashSet<>(copyResponse.getProcessGroups()));
+ versionedProcessGroup.setRemoteProcessGroups(new
HashSet<>(copyResponse.getRemoteProcessGroups()));
+ versionedProcessGroup.setFunnels(new
HashSet<>(copyResponse.getFunnels()));
+ versionedProcessGroup.setLabels(new
HashSet<>(copyResponse.getLabels()));
+ versionedProcessGroup.setConnections(new
HashSet<>(copyResponse.getConnections()));
+ return versionedProcessGroup;
+ }
+
+ private void mapVersionedIds(final VersionedProcessGroup group, final
Map<String, String> idMapping, final Map<String, String> serviceIdMapping) {
+ group.getControllerServices().forEach(cs -> {
+ final String newId = generateUuid(cs.getIdentifier());
+ idMapping.put(cs.getIdentifier(), newId);
+ serviceIdMapping.put(cs.getIdentifier(), newId);
+ cs.setIdentifier(newId);
+ });
+ group.getControllerServices().forEach(cs -> {
+ cs.getProperties().entrySet().stream()
+ .filter(propertyEntry -> {
+ final Map<String, VersionedPropertyDescriptor>
propertyDescriptors = cs.getPropertyDescriptors();
+ if (propertyDescriptors != null) {
+ final VersionedPropertyDescriptor
propertyDescriptor = propertyDescriptors.get(propertyEntry.getKey());
+ if (propertyDescriptor != null &&
propertyDescriptor.getIdentifiesControllerService()) {
+ return
serviceIdMapping.containsKey(propertyEntry.getValue());
+ }
+ }
+
+ return false;
+ })
+ .findFirst()
+ .ifPresent(serviceEntry ->
serviceEntry.setValue(serviceIdMapping.get(serviceEntry.getValue())));
Review Comment:
I think we want to use `.forEach` here instead of `.findFirst().ifPresent()`
because we want to do this for all properties, right?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]