use of org.apache.nifi.cluster.manager.NodeResponse in project nifi by apache.
the class TestThreadPoolRequestReplicator method testResponseRemovedWhenCompletedAndFetched.
/**
* If we replicate a request, whenever we obtain the merged response from
* the AsyncClusterResponse object, the response should no longer be
* available and should be cleared from internal state. This test is to
* verify that this behavior occurs.
*/
@Test
public void testResponseRemovedWhenCompletedAndFetched() {
withReplicator(replicator -> {
final Set<NodeIdentifier> nodeIds = new HashSet<>();
nodeIds.add(new NodeIdentifier("1", "localhost", 8000, "localhost", 8001, "localhost", 8002, 8003, false));
final URI uri = new URI("http://localhost:8080/processors/1");
final Entity entity = new ProcessorEntity();
// set the user
final Authentication authentication = new NiFiAuthenticationToken(new NiFiUserDetails(StandardNiFiUser.ANONYMOUS));
SecurityContextHolder.getContext().setAuthentication(authentication);
final AsyncClusterResponse response = replicator.replicate(nodeIds, HttpMethod.GET, uri, entity, new HashMap<>(), true, true);
// We should get back the same response object
assertTrue(response == replicator.getClusterResponse(response.getRequestIdentifier()));
assertEquals(HttpMethod.GET, response.getMethod());
assertEquals(nodeIds, response.getNodesInvolved());
assertTrue(response == replicator.getClusterResponse(response.getRequestIdentifier()));
final NodeResponse nodeResponse = response.awaitMergedResponse(3, TimeUnit.SECONDS);
assertEquals(8000, nodeResponse.getNodeId().getApiPort());
assertEquals(Response.Status.OK.getStatusCode(), nodeResponse.getStatus());
assertNull(replicator.getClusterResponse(response.getRequestIdentifier()));
});
}
use of org.apache.nifi.cluster.manager.NodeResponse in project nifi by apache.
the class TestThreadPoolRequestReplicator method testLongWaitForResponse.
@Test(timeout = 15000)
public void testLongWaitForResponse() {
withReplicator(replicator -> {
final Set<NodeIdentifier> nodeIds = new HashSet<>();
final NodeIdentifier nodeId = new NodeIdentifier("1", "localhost", 8000, "localhost", 8001, "localhost", 8002, 8003, false);
nodeIds.add(nodeId);
final URI uri = new URI("http://localhost:8080/processors/1");
final Entity entity = new ProcessorEntity();
// set the user
final Authentication authentication = new NiFiAuthenticationToken(new NiFiUserDetails(StandardNiFiUser.ANONYMOUS));
SecurityContextHolder.getContext().setAuthentication(authentication);
final AsyncClusterResponse response = replicator.replicate(nodeIds, HttpMethod.GET, uri, entity, new HashMap<>(), true, true);
// We should get back the same response object
assertTrue(response == replicator.getClusterResponse(response.getRequestIdentifier()));
final NodeResponse completedNodeResponse = response.awaitMergedResponse(2, TimeUnit.SECONDS);
assertNotNull(completedNodeResponse);
assertNotNull(completedNodeResponse.getThrowable());
assertEquals(500, completedNodeResponse.getStatus());
assertTrue(response.isComplete());
assertNotNull(response.getMergedResponse());
assertNull(replicator.getClusterResponse(response.getRequestIdentifier()));
}, Status.OK, 1000, new ProcessingException(new SocketTimeoutException()));
}
use of org.apache.nifi.cluster.manager.NodeResponse in project nifi by apache.
the class StandardNiFiContentAccess method getContent.
@Override
public DownloadableContent getContent(final ContentRequestContext request) {
// if clustered, send request to cluster manager
if (properties.isClustered() && clusterCoordinator != null && clusterCoordinator.isConnected()) {
// get the URI
URI dataUri;
try {
dataUri = new URI(request.getDataUri());
} catch (final URISyntaxException use) {
throw new ClusterRequestException(use);
}
// set the request parameters
final MultivaluedMap<String, String> parameters = new MultivaluedHashMap();
parameters.add(CLIENT_ID_PARAM, request.getClientId());
// set the headers
final Map<String, String> headers = new HashMap<>();
// ensure we were able to detect the cluster node id
if (request.getClusterNodeId() == null) {
throw new IllegalArgumentException("Unable to determine the which node has the content.");
}
// get the target node and ensure it exists
final NodeIdentifier nodeId = clusterCoordinator.getNodeIdentifier(request.getClusterNodeId());
// replicate the request to the cluster coordinator, indicating the target node
NodeResponse nodeResponse;
try {
headers.put(RequestReplicator.REPLICATION_TARGET_NODE_UUID_HEADER, nodeId.getId());
final NodeIdentifier coordinatorNode = clusterCoordinator.getElectedActiveCoordinatorNode();
if (coordinatorNode == null) {
throw new NoClusterCoordinatorException();
}
final Set<NodeIdentifier> coordinatorNodes = Collections.singleton(coordinatorNode);
nodeResponse = requestReplicator.replicate(coordinatorNodes, HttpMethod.GET, dataUri, parameters, headers, false, true).awaitMergedResponse();
} catch (InterruptedException e) {
throw new IllegalClusterStateException("Interrupted while waiting for a response from node");
}
final Response clientResponse = nodeResponse.getClientResponse();
final MultivaluedMap<String, String> responseHeaders = clientResponse.getStringHeaders();
// ensure an appropriate response
if (Response.Status.NOT_FOUND.getStatusCode() == clientResponse.getStatusInfo().getStatusCode()) {
throw new ResourceNotFoundException(clientResponse.readEntity(String.class));
} else if (Response.Status.FORBIDDEN.getStatusCode() == clientResponse.getStatusInfo().getStatusCode() || Response.Status.UNAUTHORIZED.getStatusCode() == clientResponse.getStatusInfo().getStatusCode()) {
throw new AccessDeniedException(clientResponse.readEntity(String.class));
} else if (Response.Status.OK.getStatusCode() != clientResponse.getStatusInfo().getStatusCode()) {
throw new IllegalStateException(clientResponse.readEntity(String.class));
}
// get the file name
final String contentDisposition = responseHeaders.getFirst("Content-Disposition");
final String filename = StringUtils.substringBetween(contentDisposition, "filename=\"", "\"");
// get the content type
final String contentType = responseHeaders.getFirst("Content-Type");
// create the downloadable content
return new DownloadableContent(filename, contentType, nodeResponse.getInputStream());
} else {
// example URIs:
// http://localhost:8080/nifi-api/provenance/events/{id}/content/{input|output}
// http://localhost:8080/nifi-api/flowfile-queues/{uuid}/flowfiles/{uuid}/content
// get just the context path for comparison
final String dataUri = StringUtils.substringAfter(request.getDataUri(), "/nifi-api");
if (StringUtils.isBlank(dataUri)) {
throw new IllegalArgumentException("The specified data reference URI is not valid.");
}
// flowfile listing content
final Matcher flowFileMatcher = FLOWFILE_CONTENT_URI_PATTERN.matcher(dataUri);
if (flowFileMatcher.matches()) {
final String connectionId = flowFileMatcher.group(1);
final String flowfileId = flowFileMatcher.group(2);
return getFlowFileContent(connectionId, flowfileId, dataUri);
}
// provenance event content
final Matcher provenanceMatcher = PROVENANCE_CONTENT_URI_PATTERN.matcher(dataUri);
if (provenanceMatcher.matches()) {
try {
final Long eventId = Long.parseLong(provenanceMatcher.group(1));
final ContentDirection direction = ContentDirection.valueOf(provenanceMatcher.group(2).toUpperCase());
return getProvenanceEventContent(eventId, dataUri, direction);
} catch (final IllegalArgumentException iae) {
throw new IllegalArgumentException("The specified data reference URI is not valid.");
}
}
// invalid uri
throw new IllegalArgumentException("The specified data reference URI is not valid.");
}
}
use of org.apache.nifi.cluster.manager.NodeResponse in project nifi by apache.
the class StandardHttpResponseMapper method mapResponses.
@Override
public NodeResponse mapResponses(final URI uri, final String httpMethod, final Set<NodeResponse> nodeResponses, final boolean merge) {
final boolean hasSuccess = hasSuccessfulResponse(nodeResponses);
if (!hasSuccess) {
// If we have a response that is a 3xx, 4xx, or 5xx, then we want to choose that.
// Otherwise, it doesn't matter which one we choose. We do this because if we replicate
// a mutable request, it's possible that one node will respond with a 409, for instance, while
// others respond with a 150-Continue. We do not want to pick the 150-Continue; instead, we want
// the failed response.
final NodeResponse clientResponse = nodeResponses.stream().filter(p -> p.getStatus() > 299).findAny().orElse(nodeResponses.iterator().next());
// Drain the response from all nodes except for the 'chosen one'. This ensures that we don't
// leave data lingering on the socket and ensures that we don't consume the content of the response
// that we intend to respond with
drainResponses(nodeResponses, clientResponse);
return clientResponse;
}
// Determine which responses are successful
final Set<NodeResponse> successResponses = nodeResponses.stream().filter(p -> p.is2xx()).collect(Collectors.toSet());
final Set<NodeResponse> problematicResponses = nodeResponses.stream().filter(p -> !p.is2xx()).collect(Collectors.toSet());
final NodeResponse clientResponse;
if ("GET".equalsIgnoreCase(httpMethod) && problematicResponses.size() > 0) {
// If there are problematic responses, at least one of the nodes couldn't complete the request
clientResponse = problematicResponses.stream().filter(p -> p.getStatus() >= 400 && p.getStatus() < 500).findFirst().orElse(problematicResponses.stream().filter(p -> p.getStatus() > 500).findFirst().orElse(problematicResponses.iterator().next()));
return clientResponse;
} else {
// Choose any of the successful responses to be the 'chosen one'.
clientResponse = successResponses.iterator().next();
}
if (merge == false) {
return clientResponse;
}
EndpointResponseMerger merger = getEndpointResponseMerger(uri, httpMethod);
if (merger == null) {
return clientResponse;
}
final NodeResponse response = merger.merge(uri, httpMethod, successResponses, problematicResponses, clientResponse);
return response;
}
use of org.apache.nifi.cluster.manager.NodeResponse in project nifi by apache.
the class AbstractNodeStatusEndpoint method mergeResponses.
@Override
protected final void mergeResponses(DtoType clientDto, Map<NodeIdentifier, DtoType> dtoMap, Set<NodeResponse> successfulResponses, Set<NodeResponse> problematicResponses) {
final NodeIdentifier selectedNodeId = dtoMap.entrySet().stream().filter(e -> e.getValue() == clientDto).map(e -> e.getKey()).findFirst().orElse(null);
if (selectedNodeId == null) {
throw new IllegalArgumentException("Attempted to merge Status request but could not find the appropriate Node Identifier");
}
mergeResponses(clientDto, dtoMap, selectedNodeId);
}
Aggregations