Search in sources :

Example 1 with NodeConnectionState

use of org.apache.nifi.cluster.coordination.node.NodeConnectionState in project nifi by apache.

the class AbstractHeartbeatMonitor method processHeartbeat.

private void processHeartbeat(final NodeHeartbeat heartbeat) {
    final NodeIdentifier nodeId = heartbeat.getNodeIdentifier();
    // Do not process heartbeat if it's blocked by firewall.
    if (clusterCoordinator.isBlockedByFirewall(nodeId.getSocketAddress())) {
        clusterCoordinator.reportEvent(nodeId, Severity.WARNING, "Firewall blocked received heartbeat. Issuing disconnection request.");
        // request node to disconnect
        clusterCoordinator.requestNodeDisconnect(nodeId, DisconnectionCode.BLOCKED_BY_FIREWALL, "Blocked by Firewall");
        removeHeartbeat(nodeId);
        return;
    }
    final NodeConnectionStatus connectionStatus = clusterCoordinator.getConnectionStatus(nodeId);
    if (connectionStatus == null) {
        // Unknown node. Issue reconnect request
        clusterCoordinator.reportEvent(nodeId, Severity.INFO, "Received heartbeat from unknown node. Removing heartbeat and requesting that node connect to cluster.");
        removeHeartbeat(nodeId);
        clusterCoordinator.requestNodeConnect(nodeId, null);
        return;
    }
    final NodeConnectionState connectionState = connectionStatus.getState();
    if (heartbeat.getConnectionStatus().getState() != NodeConnectionState.CONNECTED && connectionState == NodeConnectionState.CONNECTED) {
        // Cluster Coordinator believes that node is connected, but node does not believe so.
        clusterCoordinator.reportEvent(nodeId, Severity.WARNING, "Received heartbeat from node that thinks it is not yet part of the cluster," + "though the Cluster Coordinator thought it was (node claimed state was " + heartbeat.getConnectionStatus().getState() + "). Marking as Disconnected and requesting that Node reconnect to cluster");
        clusterCoordinator.requestNodeConnect(nodeId, null);
        return;
    }
    if (NodeConnectionState.DISCONNECTED == connectionState) {
        // ignore heartbeats from nodes disconnected by means other than lack of heartbeat, unless it is
        // the only node. We allow it if it is the only node because if we have a one-node cluster, then
        // we cannot manually reconnect it.
        final DisconnectionCode disconnectionCode = connectionStatus.getDisconnectCode();
        // Determine whether or not the node should be allowed to be in the cluster still, depending on its reason for disconnection.
        switch(disconnectionCode) {
            case LACK_OF_HEARTBEAT:
            case UNABLE_TO_COMMUNICATE:
            case NOT_YET_CONNECTED:
            case STARTUP_FAILURE:
                {
                    clusterCoordinator.reportEvent(nodeId, Severity.INFO, "Received heartbeat from node previously " + "disconnected due to " + disconnectionCode + ". Issuing reconnection request.");
                    clusterCoordinator.requestNodeConnect(nodeId, null);
                    break;
                }
            default:
                {
                    // disconnected nodes should not heartbeat, so we need to issue a disconnection request.
                    logger.info("Ignoring received heartbeat from disconnected node " + nodeId + ".  Issuing disconnection request.");
                    clusterCoordinator.requestNodeDisconnect(nodeId, disconnectionCode, connectionStatus.getDisconnectReason());
                    removeHeartbeat(nodeId);
                    break;
                }
        }
        return;
    }
    if (NodeConnectionState.DISCONNECTING == connectionStatus.getState()) {
        // ignore spurious heartbeat
        removeHeartbeat(nodeId);
        return;
    }
    // first heartbeat causes status change from connecting to connected
    if (NodeConnectionState.CONNECTING == connectionState) {
        final Long connectionRequestTime = connectionStatus.getConnectionRequestTime();
        if (connectionRequestTime != null && heartbeat.getTimestamp() < connectionRequestTime) {
            clusterCoordinator.reportEvent(nodeId, Severity.INFO, "Received heartbeat but ignoring because it was reported before the node was last asked to reconnect.");
            removeHeartbeat(nodeId);
            return;
        }
        // connection complete
        clusterCoordinator.finishNodeConnection(nodeId);
        clusterCoordinator.reportEvent(nodeId, Severity.INFO, "Received first heartbeat from connecting node. Node connected.");
    }
}
Also used : NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) DisconnectionCode(org.apache.nifi.cluster.coordination.node.DisconnectionCode) NodeConnectionState(org.apache.nifi.cluster.coordination.node.NodeConnectionState) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus)

Example 2 with NodeConnectionState

use of org.apache.nifi.cluster.coordination.node.NodeConnectionState in project nifi by apache.

the class TestThreadPoolRequestReplicator method testMutableRequestRequiresAllNodesConnected.

@Test
public void testMutableRequestRequiresAllNodesConnected() throws URISyntaxException {
    final ClusterCoordinator coordinator = createClusterCoordinator();
    // build a map of connection state to node ids
    final Map<NodeConnectionState, List<NodeIdentifier>> nodeMap = new HashMap<>();
    final List<NodeIdentifier> connectedNodes = new ArrayList<>();
    connectedNodes.add(new NodeIdentifier("1", "localhost", 8100, "localhost", 8101, "localhost", 8102, 8103, false));
    connectedNodes.add(new NodeIdentifier("2", "localhost", 8200, "localhost", 8201, "localhost", 8202, 8203, false));
    nodeMap.put(NodeConnectionState.CONNECTED, connectedNodes);
    final List<NodeIdentifier> otherState = new ArrayList<>();
    otherState.add(new NodeIdentifier("3", "localhost", 8300, "localhost", 8301, "localhost", 8302, 8303, false));
    nodeMap.put(NodeConnectionState.CONNECTING, otherState);
    when(coordinator.getConnectionStates()).thenReturn(nodeMap);
    final NiFiProperties props = NiFiProperties.createBasicNiFiProperties(null, null);
    final ThreadPoolRequestReplicator replicator = new ThreadPoolRequestReplicator(2, 5, 100, ClientBuilder.newClient(), coordinator, "1 sec", "1 sec", null, null, props) {

        @Override
        public AsyncClusterResponse replicate(Set<NodeIdentifier> nodeIds, String method, URI uri, Object entity, Map<String, String> headers, boolean indicateReplicated, boolean verify) {
            return null;
        }
    };
    try {
        // set the user
        final Authentication authentication = new NiFiAuthenticationToken(new NiFiUserDetails(StandardNiFiUser.ANONYMOUS));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        try {
            replicator.replicate(HttpMethod.POST, new URI("http://localhost:80/processors/1"), new ProcessorEntity(), new HashMap<>());
            Assert.fail("Expected ConnectingNodeMutableRequestException");
        } catch (final ConnectingNodeMutableRequestException e) {
        // expected behavior
        }
        nodeMap.remove(NodeConnectionState.CONNECTING);
        nodeMap.put(NodeConnectionState.DISCONNECTED, otherState);
        try {
            replicator.replicate(HttpMethod.POST, new URI("http://localhost:80/processors/1"), new ProcessorEntity(), new HashMap<>());
            Assert.fail("Expected DisconnectedNodeMutableRequestException");
        } catch (final DisconnectedNodeMutableRequestException e) {
        // expected behavior
        }
        nodeMap.remove(NodeConnectionState.DISCONNECTED);
        nodeMap.put(NodeConnectionState.DISCONNECTING, otherState);
        try {
            replicator.replicate(HttpMethod.POST, new URI("http://localhost:80/processors/1"), new ProcessorEntity(), new HashMap<>());
            Assert.fail("Expected DisconnectedNodeMutableRequestException");
        } catch (final DisconnectedNodeMutableRequestException e) {
        // expected behavior
        }
        // should not throw an Exception because it's a GET
        replicator.replicate(HttpMethod.GET, new URI("http://localhost:80/processors/1"), new MultiValueMap<>(), new HashMap<>());
        // should not throw an Exception because all nodes are now connected
        nodeMap.remove(NodeConnectionState.DISCONNECTING);
        replicator.replicate(HttpMethod.POST, new URI("http://localhost:80/processors/1"), new ProcessorEntity(), new HashMap<>());
    } finally {
        replicator.shutdown();
    }
}
Also used : NiFiProperties(org.apache.nifi.util.NiFiProperties) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ConnectingNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.ConnectingNodeMutableRequestException) ArrayList(java.util.ArrayList) ClusterCoordinator(org.apache.nifi.cluster.coordination.ClusterCoordinator) NodeConnectionState(org.apache.nifi.cluster.coordination.node.NodeConnectionState) ProcessorEntity(org.apache.nifi.web.api.entity.ProcessorEntity) URI(java.net.URI) NiFiAuthenticationToken(org.apache.nifi.web.security.token.NiFiAuthenticationToken) Authentication(org.springframework.security.core.Authentication) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) List(java.util.List) ArrayList(java.util.ArrayList) DisconnectedNodeMutableRequestException(org.apache.nifi.cluster.manager.exception.DisconnectedNodeMutableRequestException) Map(java.util.Map) HashMap(java.util.HashMap) MultiValueMap(org.apache.commons.collections4.map.MultiValueMap) NiFiUserDetails(org.apache.nifi.authorization.user.NiFiUserDetails) Test(org.junit.Test)

Example 3 with NodeConnectionState

use of org.apache.nifi.cluster.coordination.node.NodeConnectionState in project nifi by apache.

the class FlowResource method getClusterSummary.

/**
 * Retrieves the cluster summary for this NiFi.
 *
 * @return A clusterSummaryEntity.
 * @throws InterruptedException if interrupted
 */
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("cluster/summary")
@ApiOperation(value = "The cluster summary for this NiFi", response = ClusteSummaryEntity.class, authorizations = { @Authorization(value = "Read - /flow") })
@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 getClusterSummary() throws InterruptedException {
    authorizeFlow();
    final ClusterSummaryDTO clusterConfiguration = new ClusterSummaryDTO();
    final ClusterCoordinator clusterCoordinator = getClusterCoordinator();
    if (clusterCoordinator != null && clusterCoordinator.isConnected()) {
        final Map<NodeConnectionState, List<NodeIdentifier>> stateMap = clusterCoordinator.getConnectionStates();
        int totalNodeCount = 0;
        for (final List<NodeIdentifier> nodeList : stateMap.values()) {
            totalNodeCount += nodeList.size();
        }
        final List<NodeIdentifier> connectedNodeIds = stateMap.get(NodeConnectionState.CONNECTED);
        final int connectedNodeCount = (connectedNodeIds == null) ? 0 : connectedNodeIds.size();
        clusterConfiguration.setConnectedNodeCount(connectedNodeCount);
        clusterConfiguration.setTotalNodeCount(totalNodeCount);
        clusterConfiguration.setConnectedNodes(connectedNodeCount + " / " + totalNodeCount);
    }
    clusterConfiguration.setClustered(isClustered());
    clusterConfiguration.setConnectedToCluster(isConnectedToCluster());
    // create the response entity
    final ClusteSummaryEntity entity = new ClusteSummaryEntity();
    entity.setClusterSummary(clusterConfiguration);
    // generate the response
    return generateOkResponse(entity).build();
}
Also used : ClusteSummaryEntity(org.apache.nifi.web.api.entity.ClusteSummaryEntity) ClusterSummaryDTO(org.apache.nifi.web.api.dto.ClusterSummaryDTO) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) ClusterCoordinator(org.apache.nifi.cluster.coordination.ClusterCoordinator) ArrayList(java.util.ArrayList) List(java.util.List) NodeConnectionState(org.apache.nifi.cluster.coordination.node.NodeConnectionState) 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)

Aggregations

NodeConnectionState (org.apache.nifi.cluster.coordination.node.NodeConnectionState)3 NodeIdentifier (org.apache.nifi.cluster.protocol.NodeIdentifier)3 ArrayList (java.util.ArrayList)2 List (java.util.List)2 ClusterCoordinator (org.apache.nifi.cluster.coordination.ClusterCoordinator)2 ApiOperation (io.swagger.annotations.ApiOperation)1 ApiResponses (io.swagger.annotations.ApiResponses)1 URI (java.net.URI)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Set (java.util.Set)1 Consumes (javax.ws.rs.Consumes)1 GET (javax.ws.rs.GET)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1 MultiValueMap (org.apache.commons.collections4.map.MultiValueMap)1 NiFiUserDetails (org.apache.nifi.authorization.user.NiFiUserDetails)1 DisconnectionCode (org.apache.nifi.cluster.coordination.node.DisconnectionCode)1 NodeConnectionStatus (org.apache.nifi.cluster.coordination.node.NodeConnectionStatus)1