Search in sources :

Example 6 with NodeIdentifier

use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.

the class CountersResource method getCounters.

/**
 * Retrieves the counters report for this NiFi.
 *
 * @return A countersEntity.
 * @throws InterruptedException if interrupted
 */
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
// necessary due to a bug in swagger
@Path("")
@ApiOperation(value = "Gets the current counters for this NiFi", notes = NON_GUARANTEED_ENDPOINT, response = CountersEntity.class, authorizations = { @Authorization(value = "Read - /counters") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") })
public Response getCounters(@ApiParam(value = "Whether or not to include the breakdown per node. Optional, defaults to false", required = false) @QueryParam("nodewise") @DefaultValue(NODEWISE) final Boolean nodewise, @ApiParam(value = "The id of the node where to get the status.", required = false) @QueryParam("clusterNodeId") final String clusterNodeId) throws InterruptedException {
    authorizeCounters(RequestAction.READ);
    // ensure a valid request
    if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
        throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
    }
    // replicate if necessary
    if (isReplicateRequest()) {
        // determine where this request should be sent
        if (clusterNodeId == null) {
            final NodeResponse nodeResponse;
            // to the cluster nodes themselves.
            if (getReplicationTarget() == ReplicationTarget.CLUSTER_NODES) {
                nodeResponse = getRequestReplicator().replicate(HttpMethod.GET, getAbsolutePath(), getRequestParameters(), getHeaders()).awaitMergedResponse();
            } else {
                nodeResponse = getRequestReplicator().forwardToCoordinator(getClusterCoordinatorNode(), HttpMethod.GET, getAbsolutePath(), getRequestParameters(), getHeaders()).awaitMergedResponse();
            }
            final CountersEntity entity = (CountersEntity) nodeResponse.getUpdatedEntity();
            // ensure there is an updated entity (result of merging) and prune the response as necessary
            if (entity != null && !nodewise) {
                entity.getCounters().setNodeSnapshots(null);
            }
            return nodeResponse.getResponse();
        } else {
            // get the target node and ensure it exists
            final NodeIdentifier targetNode = getClusterCoordinator().getNodeIdentifier(clusterNodeId);
            if (targetNode == null) {
                throw new UnknownNodeException("The specified cluster node does not exist.");
            }
            return replicate(HttpMethod.GET, targetNode);
        }
    }
    final CountersDTO countersReport = serviceFacade.getCounters();
    // create the response entity
    final CountersEntity entity = new CountersEntity();
    entity.setCounters(countersReport);
    // generate the response
    return generateOkResponse(entity).build();
}
Also used : UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) CountersEntity(org.apache.nifi.web.api.entity.CountersEntity) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) NodeResponse(org.apache.nifi.cluster.manager.NodeResponse) CountersDTO(org.apache.nifi.web.api.dto.CountersDTO) Path(javax.ws.rs.Path) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 7 with NodeIdentifier

use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.

the class FlowFileQueueResource method downloadFlowFileContent.

/**
 * Gets the content for the specified flowfile in the specified connection.
 *
 * @param clientId      Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
 * @param connectionId  The connection id
 * @param flowFileUuid  The flowfile uuid
 * @param clusterNodeId The cluster node id
 * @return The content stream
 * @throws InterruptedException if interrupted
 */
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.WILDCARD)
@Path("{id}/flowfiles/{flowfile-uuid}/content")
@ApiOperation(value = "Gets the content for a FlowFile in a Connection.", response = StreamingOutput.class, authorizations = { @Authorization(value = "Read Source Data - /data/{component-type}/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") })
public Response downloadFlowFileContent(@ApiParam(value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.", required = false) @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId, @ApiParam(value = "The connection id.", required = true) @PathParam("id") final String connectionId, @ApiParam(value = "The flowfile uuid.", required = true) @PathParam("flowfile-uuid") final String flowFileUuid, @ApiParam(value = "The id of the node where the content exists if clustered.", required = false) @QueryParam("clusterNodeId") final String clusterNodeId) throws InterruptedException {
    // replicate if cluster manager
    if (isReplicateRequest()) {
        // determine where this request should be sent
        if (clusterNodeId == null) {
            throw new IllegalArgumentException("The id of the node in the cluster is required.");
        } else {
            // get the target node and ensure it exists
            final NodeIdentifier targetNode = getClusterCoordinator().getNodeIdentifier(clusterNodeId);
            if (targetNode == null) {
                throw new UnknownNodeException("The specified cluster node does not exist.");
            }
            return replicate(HttpMethod.GET, targetNode);
        }
    }
    // NOTE - deferred authorization so we can consider flowfile attributes in the access decision
    // get the uri of the request
    final String uri = generateResourceUri("flowfile-queues", connectionId, "flowfiles", flowFileUuid, "content");
    // get an input stream to the content
    final DownloadableContent content = serviceFacade.getContent(connectionId, flowFileUuid, uri);
    // generate a streaming response
    final StreamingOutput response = new StreamingOutput() {

        @Override
        public void write(final OutputStream output) throws IOException, WebApplicationException {
            try (InputStream is = content.getContent()) {
                // stream the content to the response
                StreamUtils.copy(is, output);
                // flush the response
                output.flush();
            }
        }
    };
    // use the appropriate content type
    String contentType = content.getType();
    if (contentType == null) {
        contentType = MediaType.APPLICATION_OCTET_STREAM;
    }
    return generateOkResponse(response).type(contentType).header("Content-Disposition", String.format("attachment; filename=\"%s\"", content.getFilename())).build();
}
Also used : DownloadableContent(org.apache.nifi.web.DownloadableContent) UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) InputStream(java.io.InputStream) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) OutputStream(java.io.OutputStream) StreamingOutput(javax.ws.rs.core.StreamingOutput) Path(javax.ws.rs.Path) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 8 with NodeIdentifier

use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.

the class ProvenanceEventResource method submitReplay.

/**
 * Creates a new replay request for the content associated with the specified provenance event id.
 *
 * @param httpServletRequest  request
 * @param replayRequestEntity The replay request
 * @return A provenanceEventEntity
 */
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("replays")
@ApiOperation(value = "Replays content from a provenance event", response = ProvenanceEventEntity.class, authorizations = { @Authorization(value = "Read Component Data - /data/{component-type}/{uuid}"), @Authorization(value = "Write Component Data - /data/{component-type}/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") })
public Response submitReplay(@Context final HttpServletRequest httpServletRequest, @ApiParam(value = "The replay request.", required = true) final SubmitReplayRequestEntity replayRequestEntity) {
    // ensure the event id is specified
    if (replayRequestEntity == null || replayRequestEntity.getEventId() == null) {
        throw new IllegalArgumentException("The id of the event must be specified.");
    }
    // replicate if cluster manager
    if (isReplicateRequest()) {
        // determine where this request should be sent
        if (replayRequestEntity.getClusterNodeId() == null) {
            throw new IllegalArgumentException("The id of the node in the cluster is required.");
        } else {
            return replicate(HttpMethod.POST, replayRequestEntity, replayRequestEntity.getClusterNodeId());
        }
    }
    // handle expects request (usually from the cluster manager)
    final String expects = httpServletRequest.getHeader(RequestReplicator.REQUEST_VALIDATION_HTTP_HEADER);
    if (expects != null) {
        return generateContinueResponse().build();
    }
    // submit the provenance replay request
    final ProvenanceEventDTO event = serviceFacade.submitReplay(replayRequestEntity.getEventId());
    event.setClusterNodeId(replayRequestEntity.getClusterNodeId());
    // populate the cluster node address
    final ClusterCoordinator coordinator = getClusterCoordinator();
    if (coordinator != null) {
        final NodeIdentifier nodeId = coordinator.getNodeIdentifier(replayRequestEntity.getClusterNodeId());
        event.setClusterNodeAddress(nodeId.getApiAddress() + ":" + nodeId.getApiPort());
    }
    // create a response entity
    final ProvenanceEventEntity entity = new ProvenanceEventEntity();
    entity.setProvenanceEvent(event);
    // generate the response
    URI uri = URI.create(generateResourceUri("provenance-events", event.getId()));
    return generateCreatedResponse(uri, entity).build();
}
Also used : ProvenanceEventDTO(org.apache.nifi.web.api.dto.provenance.ProvenanceEventDTO) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) ProvenanceEventEntity(org.apache.nifi.web.api.entity.ProvenanceEventEntity) ClusterCoordinator(org.apache.nifi.cluster.coordination.ClusterCoordinator) URI(java.net.URI) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 9 with NodeIdentifier

use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.

the class ThreadPoolRequestReplicator method replicate.

/**
 * Replicates the request to all nodes in the given set of node identifiers
 *
 * @param nodeIds             the NodeIdentifiers that identify which nodes to send the request to
 * @param method              the HTTP method to use
 * @param uri                 the URI to send the request to
 * @param entity              the entity to use
 * @param headers             the HTTP Headers
 * @param performVerification whether or not to verify that all nodes in the cluster are connected and that all nodes can perform request. Ignored if request is not mutable.
 * @param response            the response to update with the results
 * @param executionPhase      <code>true</code> if this is the execution phase, <code>false</code> otherwise
 * @param monitor             a monitor that will be notified when the request completes (successfully or otherwise)
 * @return an AsyncClusterResponse that can be used to obtain the result
 */
AsyncClusterResponse replicate(final Set<NodeIdentifier> nodeIds, final String method, final URI uri, final Object entity, final Map<String, String> headers, final boolean performVerification, StandardAsyncClusterResponse response, final boolean executionPhase, final boolean merge, final Object monitor) {
    try {
        // state validation
        Objects.requireNonNull(nodeIds);
        Objects.requireNonNull(method);
        Objects.requireNonNull(uri);
        Objects.requireNonNull(entity);
        Objects.requireNonNull(headers);
        if (nodeIds.isEmpty()) {
            throw new IllegalArgumentException("Cannot replicate request to 0 nodes");
        }
        // verify all of the nodes exist and are in the proper state
        for (final NodeIdentifier nodeId : nodeIds) {
            final NodeConnectionStatus status = clusterCoordinator.getConnectionStatus(nodeId);
            if (status == null) {
                throw new UnknownNodeException("Node " + nodeId + " does not exist in this cluster");
            }
            if (status.getState() != NodeConnectionState.CONNECTED) {
                throw new IllegalClusterStateException("Cannot replicate request to Node " + nodeId + " because the node is not connected");
            }
        }
        logger.debug("Replicating request {} {} with entity {} to {}; response is {}", method, uri, entity, nodeIds, response);
        // Update headers to indicate the current revision so that we can
        // prevent multiple users changing the flow at the same time
        final Map<String, String> updatedHeaders = new HashMap<>(headers);
        final String requestId = updatedHeaders.computeIfAbsent(REQUEST_TRANSACTION_ID_HEADER, key -> UUID.randomUUID().toString());
        long verifyClusterStateNanos = -1;
        if (performVerification) {
            final long start = System.nanoTime();
            verifyClusterState(method, uri.getPath());
            verifyClusterStateNanos = System.nanoTime() - start;
        }
        int numRequests = responseMap.size();
        if (numRequests >= maxConcurrentRequests) {
            numRequests = purgeExpiredRequests();
        }
        if (numRequests >= maxConcurrentRequests) {
            final Map<String, Long> countsByUri = responseMap.values().stream().collect(Collectors.groupingBy(StandardAsyncClusterResponse::getURIPath, Collectors.counting()));
            logger.error("Cannot replicate request {} {} because there are {} outstanding HTTP Requests already. Request Counts Per URI = {}", method, uri.getPath(), numRequests, countsByUri);
            throw new IllegalStateException("There are too many outstanding HTTP requests with a total " + numRequests + " outstanding requests");
        }
        // create a response object if one was not already passed to us
        if (response == null) {
            // create the request objects and replicate to all nodes.
            // When the request has completed, we need to ensure that we notify the monitor, if there is one.
            final CompletionCallback completionCallback = clusterResponse -> {
                try {
                    onCompletedResponse(requestId);
                } finally {
                    if (monitor != null) {
                        synchronized (monitor) {
                            monitor.notify();
                        }
                        logger.debug("Notified monitor {} because request {} {} has completed", monitor, method, uri);
                    }
                }
            };
            final Runnable responseConsumedCallback = () -> onResponseConsumed(requestId);
            response = new StandardAsyncClusterResponse(requestId, uri, method, nodeIds, responseMapper, completionCallback, responseConsumedCallback, merge);
            responseMap.put(requestId, response);
        }
        if (verifyClusterStateNanos > -1) {
            response.addTiming("Verify Cluster State", "All Nodes", verifyClusterStateNanos);
        }
        logger.debug("For Request ID {}, response object is {}", requestId, response);
        // if mutable request, we have to do a two-phase commit where we ask each node to verify
        // that the request can take place and then, if all nodes agree that it can, we can actually
        // issue the request. This is all handled by calling performVerification, which will replicate
        // the 'vote' request to all nodes and then if successful will call back into this method to
        // replicate the actual request.
        final boolean mutableRequest = isMutableRequest(method, uri.getPath());
        if (mutableRequest && performVerification) {
            logger.debug("Performing verification (first phase of two-phase commit) for Request ID {}", requestId);
            performVerification(nodeIds, method, uri, entity, updatedHeaders, response, merge, monitor);
            return response;
        } else if (mutableRequest) {
            response.setPhase(StandardAsyncClusterResponse.COMMIT_PHASE);
        }
        // Callback function for generating a NodeHttpRequestCallable that can be used to perform the work
        final StandardAsyncClusterResponse finalResponse = response;
        NodeRequestCompletionCallback nodeCompletionCallback = nodeResponse -> {
            logger.debug("Received response from {} for {} {}", nodeResponse.getNodeId(), method, uri.getPath());
            finalResponse.add(nodeResponse);
        };
        // instruct the node to actually perform the underlying action
        if (mutableRequest && executionPhase) {
            updatedHeaders.put(REQUEST_EXECUTION_HTTP_HEADER, "true");
        }
        // replicate the request to all nodes
        final Function<NodeIdentifier, NodeHttpRequest> requestFactory = nodeId -> new NodeHttpRequest(nodeId, method, createURI(uri, nodeId), entity, updatedHeaders, nodeCompletionCallback, finalResponse);
        submitAsyncRequest(nodeIds, uri.getScheme(), uri.getPath(), requestFactory, updatedHeaders);
        return response;
    } catch (final Throwable t) {
        if (monitor != null) {
            synchronized (monitor) {
                monitor.notify();
            }
            logger.debug("Notified monitor {} because request {} {} has failed with Throwable {}", monitor, method, uri, t);
        }
        if (response != null) {
            final RuntimeException failure = (t instanceof RuntimeException) ? (RuntimeException) t : new RuntimeException("Failed to submit Replication Request to background thread", t);
            response.setFailure(failure, new NodeIdentifier());
        }
        throw t;
    }
}
Also used : NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) DisconnectedNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.DisconnectedNodeMutableRequestException) URISyntaxException(java.net.URISyntaxException) LoggerFactory(org.slf4j.LoggerFactory) UriConstructionException(org.apache.nifi.cluster.manager.exception.UriConstructionException) StringUtils(org.apache.commons.lang3.StringUtils) MediaType(javax.ws.rs.core.MediaType) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) URI(java.net.URI) ThreadFactory(java.util.concurrent.ThreadFactory) NodeResponse(org.apache.nifi.cluster.manager.NodeResponse) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) ComponentIdGenerator(org.apache.nifi.util.ComponentIdGenerator) HttpHeaders(org.apache.nifi.remote.protocol.http.HttpHeaders) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HttpResponseMapper(org.apache.nifi.cluster.coordination.http.HttpResponseMapper) Set(java.util.Set) ClientProperties(org.glassfish.jersey.client.ClientProperties) Invocation(javax.ws.rs.client.Invocation) UUID(java.util.UUID) EncodingFilter(org.glassfish.jersey.client.filter.EncodingFilter) StandardHttpResponseMapper(org.apache.nifi.cluster.coordination.http.StandardHttpResponseMapper) ProxiedEntitiesUtils(org.apache.nifi.web.security.ProxiedEntitiesUtils) Entity(javax.ws.rs.client.Entity) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) Objects(java.util.Objects) List(java.util.List) GZipEncoder(org.glassfish.jersey.message.GZipEncoder) Stream(java.util.stream.Stream) Response(javax.ws.rs.core.Response) IllegalClusterStateException(org.apache.nifi.cluster.manager.exception.IllegalClusterStateException) Entry(java.util.Map.Entry) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) NoConnectedNodesException(org.apache.nifi.cluster.manager.exception.NoConnectedNodesException) Client(javax.ws.rs.client.Client) AccessDeniedException(org.apache.nifi.authorization.AccessDeniedException) HashMap(java.util.HashMap) ConnectingNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.ConnectingNodeMutableRequestException) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Function(java.util.function.Function) HttpMethod(javax.ws.rs.HttpMethod) ConcurrentMap(java.util.concurrent.ConcurrentMap) HashSet(java.util.HashSet) NiFiUser(org.apache.nifi.authorization.user.NiFiUser) ClusterCoordinator(org.apache.nifi.cluster.coordination.ClusterCoordinator) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) NodeConnectionState(org.apache.nifi.cluster.coordination.node.NodeConnectionState) Status(javax.ws.rs.core.Response.Status) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) LongSummaryStatistics(java.util.LongSummaryStatistics) JwtAuthenticationFilter(org.apache.nifi.web.security.jwt.JwtAuthenticationFilter) Logger(org.slf4j.Logger) MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) MultivaluedMap(javax.ws.rs.core.MultivaluedMap) TimeUnit(java.util.concurrent.TimeUnit) Lock(java.util.concurrent.locks.Lock) EventReporter(org.apache.nifi.events.EventReporter) FormatUtils(org.apache.nifi.util.FormatUtils) NiFiProperties(org.apache.nifi.util.NiFiProperties) NiFiUserUtils(org.apache.nifi.authorization.user.NiFiUserUtils) Severity(org.apache.nifi.reporting.Severity) UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) WebTarget(javax.ws.rs.client.WebTarget) Collections(java.util.Collections) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) IllegalClusterStateException(org.apache.nifi.cluster.manager.exception.IllegalClusterStateException) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier)

Example 10 with NodeIdentifier

use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.

the class ThreadPoolRequestReplicator method performVerification.

private void performVerification(final Set<NodeIdentifier> nodeIds, final String method, final URI uri, final Object entity, final Map<String, String> headers, final StandardAsyncClusterResponse clusterResponse, final boolean merge, final Object monitor) {
    logger.debug("Verifying that mutable request {} {} can be made", method, uri.getPath());
    final Map<String, String> validationHeaders = new HashMap<>(headers);
    validationHeaders.put(REQUEST_VALIDATION_HTTP_HEADER, NODE_CONTINUE);
    final long startNanos = System.nanoTime();
    final int numNodes = nodeIds.size();
    final NodeRequestCompletionCallback completionCallback = new NodeRequestCompletionCallback() {

        final Set<NodeResponse> nodeResponses = Collections.synchronizedSet(new HashSet<>());

        @Override
        public void onCompletion(final NodeResponse nodeResponse) {
            // Add the node response to our collection. We later need to know whether or
            // not this is the last node response, so we add the response and then check
            // the size within a synchronized block to ensure that those two things happen
            // atomically. Otherwise, we could have multiple threads checking the sizes of
            // the sets at the same time, which could result in multiple threads performing
            // the 'all nodes are complete' logic.
            final boolean allNodesResponded;
            synchronized (nodeResponses) {
                nodeResponses.add(nodeResponse);
                allNodesResponded = nodeResponses.size() == numNodes;
            }
            try {
                final long nanos = System.nanoTime() - startNanos;
                clusterResponse.addTiming("Completed Verification", nodeResponse.getNodeId().toString(), nanos);
                // and if good replicate the original request to all of the nodes.
                if (allNodesResponded) {
                    clusterResponse.addTiming("Verification Completed", "All Nodes", nanos);
                    // Check if we have any requests that do not have a 150-Continue status code.
                    final long dissentingCount = nodeResponses.stream().filter(p -> p.getStatus() != NODE_CONTINUE_STATUS_CODE).count();
                    // to all nodes and we are finished.
                    if (dissentingCount == 0) {
                        logger.debug("Received verification from all {} nodes that mutable request {} {} can be made", numNodes, method, uri.getPath());
                        replicate(nodeIds, method, uri, entity, headers, false, clusterResponse, true, merge, monitor);
                        return;
                    }
                    try {
                        final Map<String, String> cancelLockHeaders = new HashMap<>(headers);
                        cancelLockHeaders.put(REQUEST_TRANSACTION_CANCELATION_HTTP_HEADER, "true");
                        final Thread cancelLockThread = new Thread(new Runnable() {

                            @Override
                            public void run() {
                                logger.debug("Found {} dissenting nodes for {} {}; canceling claim request", dissentingCount, method, uri.getPath());
                                final Function<NodeIdentifier, NodeHttpRequest> requestFactory = nodeId -> new NodeHttpRequest(nodeId, method, createURI(uri, nodeId), entity, cancelLockHeaders, null, clusterResponse);
                                submitAsyncRequest(nodeIds, uri.getScheme(), uri.getPath(), requestFactory, cancelLockHeaders);
                            }
                        });
                        cancelLockThread.setName("Cancel Flow Locks");
                        cancelLockThread.start();
                        // Check that all nodes responded successfully.
                        for (final NodeResponse response : nodeResponses) {
                            if (response.getStatus() != NODE_CONTINUE_STATUS_CODE) {
                                final Response clientResponse = response.getClientResponse();
                                final String message;
                                if (clientResponse == null) {
                                    message = "Node " + response.getNodeId() + " is unable to fulfill this request due to: Unexpected Response Code " + response.getStatus();
                                    logger.info("Received a status of {} from {} for request {} {} when performing first stage of two-stage commit. The action will not occur", response.getStatus(), response.getNodeId(), method, uri.getPath());
                                } else {
                                    final String nodeExplanation = clientResponse.readEntity(String.class);
                                    message = "Node " + response.getNodeId() + " is unable to fulfill this request due to: " + nodeExplanation;
                                    logger.info("Received a status of {} from {} for request {} {} when performing first stage of two-stage commit. " + "The action will not occur. Node explanation: {}", response.getStatus(), response.getNodeId(), method, uri.getPath(), nodeExplanation);
                                }
                                // if a node reports forbidden, use that as the response failure
                                final RuntimeException failure;
                                if (response.getStatus() == Status.FORBIDDEN.getStatusCode()) {
                                    if (response.hasThrowable()) {
                                        failure = new AccessDeniedException(message, response.getThrowable());
                                    } else {
                                        failure = new AccessDeniedException(message);
                                    }
                                } else {
                                    if (response.hasThrowable()) {
                                        failure = new IllegalClusterStateException(message, response.getThrowable());
                                    } else {
                                        failure = new IllegalClusterStateException(message);
                                    }
                                }
                                clusterResponse.setFailure(failure, response.getNodeId());
                            }
                        }
                    } finally {
                        if (monitor != null) {
                            synchronized (monitor) {
                                monitor.notify();
                            }
                            logger.debug("Notified monitor {} because request {} {} has failed due to at least 1 dissenting node", monitor, method, uri);
                        }
                    }
                }
            } catch (final Exception e) {
                clusterResponse.add(new NodeResponse(nodeResponse.getNodeId(), method, uri, e));
                // to the Cluster Response so that the Cluster Response is complete.
                for (final NodeResponse otherResponse : nodeResponses) {
                    if (otherResponse.getNodeId().equals(nodeResponse.getNodeId())) {
                        continue;
                    }
                    clusterResponse.add(otherResponse);
                }
            }
        }
    };
    // Callback function for generating a NodeHttpRequestCallable that can be used to perform the work
    final Function<NodeIdentifier, NodeHttpRequest> requestFactory = nodeId -> new NodeHttpRequest(nodeId, method, createURI(uri, nodeId), entity, validationHeaders, completionCallback, clusterResponse);
    // replicate the 'verification request' to all nodes
    submitAsyncRequest(nodeIds, uri.getScheme(), uri.getPath(), requestFactory, validationHeaders);
}
Also used : NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) DisconnectedNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.DisconnectedNodeMutableRequestException) URISyntaxException(java.net.URISyntaxException) LoggerFactory(org.slf4j.LoggerFactory) UriConstructionException(org.apache.nifi.cluster.manager.exception.UriConstructionException) StringUtils(org.apache.commons.lang3.StringUtils) MediaType(javax.ws.rs.core.MediaType) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) URI(java.net.URI) ThreadFactory(java.util.concurrent.ThreadFactory) NodeResponse(org.apache.nifi.cluster.manager.NodeResponse) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) ComponentIdGenerator(org.apache.nifi.util.ComponentIdGenerator) HttpHeaders(org.apache.nifi.remote.protocol.http.HttpHeaders) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HttpResponseMapper(org.apache.nifi.cluster.coordination.http.HttpResponseMapper) Set(java.util.Set) ClientProperties(org.glassfish.jersey.client.ClientProperties) Invocation(javax.ws.rs.client.Invocation) UUID(java.util.UUID) EncodingFilter(org.glassfish.jersey.client.filter.EncodingFilter) StandardHttpResponseMapper(org.apache.nifi.cluster.coordination.http.StandardHttpResponseMapper) ProxiedEntitiesUtils(org.apache.nifi.web.security.ProxiedEntitiesUtils) Entity(javax.ws.rs.client.Entity) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) Objects(java.util.Objects) List(java.util.List) GZipEncoder(org.glassfish.jersey.message.GZipEncoder) Stream(java.util.stream.Stream) Response(javax.ws.rs.core.Response) IllegalClusterStateException(org.apache.nifi.cluster.manager.exception.IllegalClusterStateException) Entry(java.util.Map.Entry) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) NoConnectedNodesException(org.apache.nifi.cluster.manager.exception.NoConnectedNodesException) Client(javax.ws.rs.client.Client) AccessDeniedException(org.apache.nifi.authorization.AccessDeniedException) HashMap(java.util.HashMap) ConnectingNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.ConnectingNodeMutableRequestException) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Function(java.util.function.Function) HttpMethod(javax.ws.rs.HttpMethod) ConcurrentMap(java.util.concurrent.ConcurrentMap) HashSet(java.util.HashSet) NiFiUser(org.apache.nifi.authorization.user.NiFiUser) ClusterCoordinator(org.apache.nifi.cluster.coordination.ClusterCoordinator) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) NodeConnectionState(org.apache.nifi.cluster.coordination.node.NodeConnectionState) Status(javax.ws.rs.core.Response.Status) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) LongSummaryStatistics(java.util.LongSummaryStatistics) JwtAuthenticationFilter(org.apache.nifi.web.security.jwt.JwtAuthenticationFilter) Logger(org.slf4j.Logger) MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) MultivaluedMap(javax.ws.rs.core.MultivaluedMap) TimeUnit(java.util.concurrent.TimeUnit) Lock(java.util.concurrent.locks.Lock) EventReporter(org.apache.nifi.events.EventReporter) FormatUtils(org.apache.nifi.util.FormatUtils) NiFiProperties(org.apache.nifi.util.NiFiProperties) NiFiUserUtils(org.apache.nifi.authorization.user.NiFiUserUtils) Severity(org.apache.nifi.reporting.Severity) UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) WebTarget(javax.ws.rs.client.WebTarget) Collections(java.util.Collections) AccessDeniedException(org.apache.nifi.authorization.AccessDeniedException) Set(java.util.Set) HashSet(java.util.HashSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) MultivaluedHashMap(javax.ws.rs.core.MultivaluedHashMap) IllegalClusterStateException(org.apache.nifi.cluster.manager.exception.IllegalClusterStateException) NodeResponse(org.apache.nifi.cluster.manager.NodeResponse) DisconnectedNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.DisconnectedNodeMutableRequestException) URISyntaxException(java.net.URISyntaxException) UriConstructionException(org.apache.nifi.cluster.manager.exception.UriConstructionException) IllegalClusterStateException(org.apache.nifi.cluster.manager.exception.IllegalClusterStateException) NoConnectedNodesException(org.apache.nifi.cluster.manager.exception.NoConnectedNodesException) AccessDeniedException(org.apache.nifi.authorization.AccessDeniedException) ConnectingNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.ConnectingNodeMutableRequestException) UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) NodeResponse(org.apache.nifi.cluster.manager.NodeResponse) Response(javax.ws.rs.core.Response) Function(java.util.function.Function) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) HashSet(java.util.HashSet)

Aggregations

NodeIdentifier (org.apache.nifi.cluster.protocol.NodeIdentifier)141 HashMap (java.util.HashMap)72 Map (java.util.Map)71 NodeResponse (org.apache.nifi.cluster.manager.NodeResponse)42 Test (org.junit.Test)34 Set (java.util.Set)30 URI (java.net.URI)26 HashSet (java.util.HashSet)26 ArrayList (java.util.ArrayList)24 List (java.util.List)18 ClusterCoordinator (org.apache.nifi.cluster.coordination.ClusterCoordinator)15 ProcessorEntity (org.apache.nifi.web.api.entity.ProcessorEntity)15 NodeConnectionStatus (org.apache.nifi.cluster.coordination.node.NodeConnectionStatus)14 NiFiProperties (org.apache.nifi.util.NiFiProperties)11 Collections (java.util.Collections)10 Pattern (java.util.regex.Pattern)10 NiFiUserDetails (org.apache.nifi.authorization.user.NiFiUserDetails)10 NiFiAuthenticationToken (org.apache.nifi.web.security.token.NiFiAuthenticationToken)10 Authentication (org.springframework.security.core.Authentication)10 Response (javax.ws.rs.core.Response)9