mirror of https://github.com/apache/nifi.git
NIFI-1554:
- Refactoring Cluster endpoints. - Updating frontend to accomodate clustering endpoints. - Remove the 'Make Primary' action. - This closes #470
This commit is contained in:
parent
9152a9fdbb
commit
a0ff2f7a9f
|
@ -17,11 +17,12 @@
|
||||||
package org.apache.nifi.web.api.dto;
|
package org.apache.nifi.web.api.dto;
|
||||||
|
|
||||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||||
import java.util.Date;
|
import org.apache.nifi.web.api.dto.util.DateTimeAdapter;
|
||||||
import java.util.List;
|
|
||||||
import javax.xml.bind.annotation.XmlType;
|
import javax.xml.bind.annotation.XmlType;
|
||||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||||
import org.apache.nifi.web.api.dto.util.DateTimeAdapter;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Details of a node within this NiFi.
|
* Details of a node within this NiFi.
|
||||||
|
@ -46,7 +47,8 @@ public class NodeDTO {
|
||||||
*/
|
*/
|
||||||
@XmlJavaTypeAdapter(DateTimeAdapter.class)
|
@XmlJavaTypeAdapter(DateTimeAdapter.class)
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "the time of the nodes's last heartbeat."
|
value = "the time of the nodes's last heartbeat.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public Date getHeartbeat() {
|
public Date getHeartbeat() {
|
||||||
return heartbeat;
|
return heartbeat;
|
||||||
|
@ -61,7 +63,8 @@ public class NodeDTO {
|
||||||
*/
|
*/
|
||||||
@XmlJavaTypeAdapter(DateTimeAdapter.class)
|
@XmlJavaTypeAdapter(DateTimeAdapter.class)
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The time of the node's last connection request."
|
value = "The time of the node's last connection request.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public Date getConnectionRequested() {
|
public Date getConnectionRequested() {
|
||||||
return connectionRequested;
|
return connectionRequested;
|
||||||
|
@ -77,7 +80,8 @@ public class NodeDTO {
|
||||||
* @return The active thread count
|
* @return The active thread count
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The active threads for the NiFi on the node."
|
value = "The active threads for the NiFi on the node.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public Integer getActiveThreadCount() {
|
public Integer getActiveThreadCount() {
|
||||||
return activeThreadCount;
|
return activeThreadCount;
|
||||||
|
@ -91,7 +95,8 @@ public class NodeDTO {
|
||||||
* @return queue for the controller
|
* @return queue for the controller
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The queue the NiFi on the node."
|
value = "The queue the NiFi on the node.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public String getQueued() {
|
public String getQueued() {
|
||||||
return queued;
|
return queued;
|
||||||
|
@ -105,7 +110,8 @@ public class NodeDTO {
|
||||||
* @return node's host/IP address
|
* @return node's host/IP address
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The node's host/ip address."
|
value = "The node's host/ip address.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return address;
|
return address;
|
||||||
|
@ -119,7 +125,8 @@ public class NodeDTO {
|
||||||
* @return node ID
|
* @return node ID
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The id of the node."
|
value = "The id of the node.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public String getNodeId() {
|
public String getNodeId() {
|
||||||
return nodeId;
|
return nodeId;
|
||||||
|
@ -133,7 +140,8 @@ public class NodeDTO {
|
||||||
* @return port the node is listening for API requests
|
* @return port the node is listening for API requests
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The port the node is listening for API requests."
|
value = "The port the node is listening for API requests.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public Integer getApiPort() {
|
public Integer getApiPort() {
|
||||||
return apiPort;
|
return apiPort;
|
||||||
|
@ -161,7 +169,8 @@ public class NodeDTO {
|
||||||
* @return node's events
|
* @return node's events
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The node's events."
|
value = "The node's events.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public List<NodeEventDTO> getEvents() {
|
public List<NodeEventDTO> getEvents() {
|
||||||
return events;
|
return events;
|
||||||
|
@ -175,7 +184,8 @@ public class NodeDTO {
|
||||||
* @return whether this node is the primary node within the cluster
|
* @return whether this node is the primary node within the cluster
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "Whether the node is the primary node within the cluster."
|
value = "Whether the node is the primary node within the cluster.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public Boolean isPrimary() {
|
public Boolean isPrimary() {
|
||||||
return primary;
|
return primary;
|
||||||
|
@ -190,7 +200,8 @@ public class NodeDTO {
|
||||||
*/
|
*/
|
||||||
@XmlJavaTypeAdapter(DateTimeAdapter.class)
|
@XmlJavaTypeAdapter(DateTimeAdapter.class)
|
||||||
@ApiModelProperty(
|
@ApiModelProperty(
|
||||||
value = "The time at which this Node was last refreshed."
|
value = "The time at which this Node was last refreshed.",
|
||||||
|
readOnly = true
|
||||||
)
|
)
|
||||||
public Date getNodeStartTime() {
|
public Date getNodeStartTime() {
|
||||||
return nodeStartTime;
|
return nodeStartTime;
|
||||||
|
|
|
@ -33,12 +33,16 @@ import org.apache.nifi.web.api.dto.NodeDTO;
|
||||||
import org.apache.nifi.web.api.dto.search.NodeSearchResultDTO;
|
import org.apache.nifi.web.api.dto.search.NodeSearchResultDTO;
|
||||||
import org.apache.nifi.web.api.entity.ClusterEntity;
|
import org.apache.nifi.web.api.entity.ClusterEntity;
|
||||||
import org.apache.nifi.web.api.entity.ClusterSearchResultsEntity;
|
import org.apache.nifi.web.api.entity.ClusterSearchResultsEntity;
|
||||||
|
import org.apache.nifi.web.api.entity.NodeEntity;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.DefaultValue;
|
import javax.ws.rs.DefaultValue;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.HEAD;
|
import javax.ws.rs.HEAD;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
|
@ -62,20 +66,6 @@ public class ClusterResource extends ApplicationResource {
|
||||||
private NiFiServiceFacade serviceFacade;
|
private NiFiServiceFacade serviceFacade;
|
||||||
private NiFiProperties properties;
|
private NiFiProperties properties;
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates the ClusterConnection sub-resource.
|
|
||||||
*
|
|
||||||
* @return node resource
|
|
||||||
*/
|
|
||||||
@Path("/nodes")
|
|
||||||
@ApiOperation(
|
|
||||||
value = "Gets the node resource",
|
|
||||||
response = NodeResource.class
|
|
||||||
)
|
|
||||||
public NodeResource getNodeResource() {
|
|
||||||
return resourceContext.getResource(NodeResource.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a 200 OK response to indicate this is a valid cluster endpoint.
|
* Returns a 200 OK response to indicate this is a valid cluster endpoint.
|
||||||
*
|
*
|
||||||
|
@ -83,7 +73,7 @@ public class ClusterResource extends ApplicationResource {
|
||||||
*/
|
*/
|
||||||
@HEAD
|
@HEAD
|
||||||
@Consumes(MediaType.WILDCARD)
|
@Consumes(MediaType.WILDCARD)
|
||||||
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
|
@Produces(MediaType.WILDCARD)
|
||||||
public Response getClusterHead() {
|
public Response getClusterHead() {
|
||||||
if (properties.isClusterManager()) {
|
if (properties.isClusterManager()) {
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
|
@ -99,7 +89,7 @@ public class ClusterResource extends ApplicationResource {
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Consumes(MediaType.WILDCARD)
|
@Consumes(MediaType.WILDCARD)
|
||||||
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
|
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
value = "Gets the contents of the cluster",
|
value = "Gets the contents of the cluster",
|
||||||
|
@ -144,7 +134,7 @@ public class ClusterResource extends ApplicationResource {
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@Consumes(MediaType.WILDCARD)
|
@Consumes(MediaType.WILDCARD)
|
||||||
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Path("/search-results")
|
@Path("/search-results")
|
||||||
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
|
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
|
||||||
@ApiOperation(
|
@ApiOperation(
|
||||||
|
@ -209,6 +199,174 @@ public class ClusterResource extends ApplicationResource {
|
||||||
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the contents of the specified node in this NiFi cluster.
|
||||||
|
*
|
||||||
|
* @param id The node id.
|
||||||
|
* @return A nodeEntity.
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Consumes(MediaType.WILDCARD)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("nodes/{id}")
|
||||||
|
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
|
||||||
|
@ApiOperation(
|
||||||
|
value = "Gets a node in the cluster",
|
||||||
|
response = NodeEntity.class,
|
||||||
|
authorizations = {
|
||||||
|
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
|
||||||
|
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
|
||||||
|
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@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 getNode(
|
||||||
|
@ApiParam(
|
||||||
|
value = "The node id.",
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
@PathParam("id") String id) {
|
||||||
|
|
||||||
|
if (properties.isClusterManager()) {
|
||||||
|
|
||||||
|
// get the specified relationship
|
||||||
|
final NodeDTO dto = serviceFacade.getNode(id);
|
||||||
|
|
||||||
|
// create the response entity
|
||||||
|
final NodeEntity entity = new NodeEntity();
|
||||||
|
entity.setNode(dto);
|
||||||
|
|
||||||
|
// generate the response
|
||||||
|
return generateOkResponse(entity).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the contents of the specified node in this NiFi cluster.
|
||||||
|
*
|
||||||
|
* @param id The id of the node
|
||||||
|
* @param nodeEntity A nodeEntity
|
||||||
|
* @return A nodeEntity
|
||||||
|
*/
|
||||||
|
@PUT
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("nodes/{id}")
|
||||||
|
// TODO - @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
|
||||||
|
@ApiOperation(
|
||||||
|
value = "Updates a node in the cluster",
|
||||||
|
response = NodeEntity.class,
|
||||||
|
authorizations = {
|
||||||
|
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@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 updateNode(
|
||||||
|
@ApiParam(
|
||||||
|
value = "The node id.",
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
@PathParam("id") String id,
|
||||||
|
@ApiParam(
|
||||||
|
value = "The node configuration. The only configuration that will be honored at this endpoint is the status or primary flag.",
|
||||||
|
required = true
|
||||||
|
) NodeEntity nodeEntity) {
|
||||||
|
|
||||||
|
if (properties.isClusterManager()) {
|
||||||
|
|
||||||
|
if (nodeEntity == null || nodeEntity.getNode() == null) {
|
||||||
|
throw new IllegalArgumentException("Node details must be specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the request node
|
||||||
|
final NodeDTO requestNodeDTO = nodeEntity.getNode();
|
||||||
|
if (!id.equals(requestNodeDTO.getNodeId())) {
|
||||||
|
throw new IllegalArgumentException(String.format("The node id (%s) in the request body does "
|
||||||
|
+ "not equal the node id of the requested resource (%s).", requestNodeDTO.getNodeId(), id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the node
|
||||||
|
final NodeDTO node = serviceFacade.updateNode(requestNodeDTO);
|
||||||
|
|
||||||
|
// create the response entity
|
||||||
|
NodeEntity entity = new NodeEntity();
|
||||||
|
entity.setNode(node);
|
||||||
|
|
||||||
|
// generate the response
|
||||||
|
return generateOkResponse(entity).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified from this NiFi cluster.
|
||||||
|
*
|
||||||
|
* @param id The id of the node
|
||||||
|
* @return A nodeEntity
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Consumes(MediaType.WILDCARD)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Path("nodes/{id}")
|
||||||
|
// TODO - @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
|
||||||
|
@ApiOperation(
|
||||||
|
value = "Removes a node from the cluster",
|
||||||
|
response = NodeEntity.class,
|
||||||
|
authorizations = {
|
||||||
|
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@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 deleteNode(
|
||||||
|
@ApiParam(
|
||||||
|
value = "The node id.",
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
@PathParam("id") String id) {
|
||||||
|
|
||||||
|
if (properties.isClusterManager()) {
|
||||||
|
|
||||||
|
serviceFacade.deleteNode(id);
|
||||||
|
|
||||||
|
// create the response entity
|
||||||
|
final NodeEntity entity = new NodeEntity();
|
||||||
|
|
||||||
|
// generate the response
|
||||||
|
return generateOkResponse(entity).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
public void setServiceFacade(NiFiServiceFacade serviceFacade) {
|
public void setServiceFacade(NiFiServiceFacade serviceFacade) {
|
||||||
this.serviceFacade = serviceFacade;
|
this.serviceFacade = serviceFacade;
|
||||||
|
|
|
@ -1,228 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.nifi.web.api;
|
|
||||||
|
|
||||||
import com.wordnik.swagger.annotations.Api;
|
|
||||||
import com.wordnik.swagger.annotations.ApiOperation;
|
|
||||||
import com.wordnik.swagger.annotations.ApiParam;
|
|
||||||
import com.wordnik.swagger.annotations.ApiResponse;
|
|
||||||
import com.wordnik.swagger.annotations.ApiResponses;
|
|
||||||
import com.wordnik.swagger.annotations.Authorization;
|
|
||||||
import org.apache.nifi.util.NiFiProperties;
|
|
||||||
import org.apache.nifi.web.IllegalClusterResourceRequestException;
|
|
||||||
import org.apache.nifi.web.NiFiServiceFacade;
|
|
||||||
import org.apache.nifi.web.api.dto.NodeDTO;
|
|
||||||
import org.apache.nifi.web.api.entity.NodeEntity;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RESTful endpoint for managing a cluster connection.
|
|
||||||
*/
|
|
||||||
@Api(hidden = true)
|
|
||||||
public class NodeResource extends ApplicationResource {
|
|
||||||
|
|
||||||
private NiFiServiceFacade serviceFacade;
|
|
||||||
private NiFiProperties properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the contents of the specified node in this NiFi cluster.
|
|
||||||
*
|
|
||||||
* @param id The node id.
|
|
||||||
* @return A nodeEntity.
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@Consumes(MediaType.WILDCARD)
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@Path("/{id}")
|
|
||||||
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
|
|
||||||
@ApiOperation(
|
|
||||||
value = "Gets a node in the cluster",
|
|
||||||
response = NodeEntity.class,
|
|
||||||
authorizations = {
|
|
||||||
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
|
|
||||||
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
|
|
||||||
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@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 getNode(
|
|
||||||
@ApiParam(
|
|
||||||
value = "The node id.",
|
|
||||||
required = true
|
|
||||||
)
|
|
||||||
@PathParam("id") String id) {
|
|
||||||
|
|
||||||
if (properties.isClusterManager()) {
|
|
||||||
|
|
||||||
// get the specified relationship
|
|
||||||
final NodeDTO dto = serviceFacade.getNode(id);
|
|
||||||
|
|
||||||
// create the response entity
|
|
||||||
final NodeEntity entity = new NodeEntity();
|
|
||||||
entity.setNode(dto);
|
|
||||||
|
|
||||||
// generate the response
|
|
||||||
return generateOkResponse(entity).build();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the contents of the specified node in this NiFi cluster.
|
|
||||||
*
|
|
||||||
* @param id The id of the node
|
|
||||||
* @param nodeEntity A nodeEntity
|
|
||||||
* @return A nodeEntity
|
|
||||||
*/
|
|
||||||
@PUT
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@Path("/{id}")
|
|
||||||
// TODO - @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
|
|
||||||
@ApiOperation(
|
|
||||||
value = "Updates a node in the cluster",
|
|
||||||
response = NodeEntity.class,
|
|
||||||
authorizations = {
|
|
||||||
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@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 updateNode(
|
|
||||||
@ApiParam(
|
|
||||||
value = "The node id.",
|
|
||||||
required = true
|
|
||||||
)
|
|
||||||
@PathParam("id") String id,
|
|
||||||
@ApiParam(
|
|
||||||
value = "The node configuration. The only configuration that will be honored at this endpoint is the status or primary flag.",
|
|
||||||
required = true
|
|
||||||
)
|
|
||||||
NodeEntity nodeEntity) {
|
|
||||||
|
|
||||||
if (properties.isClusterManager()) {
|
|
||||||
|
|
||||||
if (nodeEntity == null || nodeEntity.getNode() == null) {
|
|
||||||
throw new IllegalArgumentException("Node details must be specified.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the request node
|
|
||||||
final NodeDTO requestNodeDTO = nodeEntity.getNode();
|
|
||||||
if (!id.equals(requestNodeDTO.getNodeId())) {
|
|
||||||
throw new IllegalArgumentException(String.format("The node id (%s) in the request body does "
|
|
||||||
+ "not equal the node id of the requested resource (%s).", requestNodeDTO.getNodeId(), id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the node
|
|
||||||
final NodeDTO node = serviceFacade.updateNode(requestNodeDTO);
|
|
||||||
|
|
||||||
// create the response entity
|
|
||||||
NodeEntity entity = new NodeEntity();
|
|
||||||
entity.setNode(node);
|
|
||||||
|
|
||||||
// generate the response
|
|
||||||
return generateOkResponse(entity).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the specified from this NiFi cluster.
|
|
||||||
*
|
|
||||||
* @param id The id of the node
|
|
||||||
* @return A nodeEntity
|
|
||||||
*/
|
|
||||||
@DELETE
|
|
||||||
@Consumes(MediaType.WILDCARD)
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
@Path("/{id}")
|
|
||||||
// TODO - @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
|
|
||||||
@ApiOperation(
|
|
||||||
value = "Removes a node from the cluster",
|
|
||||||
response = NodeEntity.class,
|
|
||||||
authorizations = {
|
|
||||||
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@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 deleteNode(
|
|
||||||
@ApiParam(
|
|
||||||
value = "The node id.",
|
|
||||||
required = true
|
|
||||||
)
|
|
||||||
@PathParam("id") String id) {
|
|
||||||
|
|
||||||
if (properties.isClusterManager()) {
|
|
||||||
|
|
||||||
serviceFacade.deleteNode(id);
|
|
||||||
|
|
||||||
// create the response entity
|
|
||||||
final NodeEntity entity = new NodeEntity();
|
|
||||||
|
|
||||||
// generate the response
|
|
||||||
return generateOkResponse(entity).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// setters
|
|
||||||
public void setServiceFacade(NiFiServiceFacade serviceFacade) {
|
|
||||||
this.serviceFacade = serviceFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProperties(NiFiProperties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -297,10 +297,6 @@
|
||||||
<property name="serviceFacade" ref="serviceFacade"/>
|
<property name="serviceFacade" ref="serviceFacade"/>
|
||||||
<property name="properties" ref="nifiProperties"/>
|
<property name="properties" ref="nifiProperties"/>
|
||||||
</bean>
|
</bean>
|
||||||
<bean id="nodeResource" class="org.apache.nifi.web.api.NodeResource" scope="singleton">
|
|
||||||
<property name="serviceFacade" ref="serviceFacade"/>
|
|
||||||
<property name="properties" ref="nifiProperties"/>
|
|
||||||
</bean>
|
|
||||||
<bean id="systemDiagnosticsResource" class="org.apache.nifi.web.api.SystemDiagnosticsResource" scope="singleton">
|
<bean id="systemDiagnosticsResource" class="org.apache.nifi.web.api.SystemDiagnosticsResource" scope="singleton">
|
||||||
<property name="serviceFacade" ref="serviceFacade"/>
|
<property name="serviceFacade" ref="serviceFacade"/>
|
||||||
<property name="properties" ref="nifiProperties"/>
|
<property name="properties" ref="nifiProperties"/>
|
||||||
|
|
|
@ -134,13 +134,19 @@ nf.ClusterTable = (function () {
|
||||||
* @argument {string} nodeId The node id
|
* @argument {string} nodeId The node id
|
||||||
*/
|
*/
|
||||||
var connect = function (nodeId) {
|
var connect = function (nodeId) {
|
||||||
|
var entity = {
|
||||||
|
'node': {
|
||||||
|
'nodeId': nodeId,
|
||||||
|
'status': 'CONNECTING'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
url: config.urls.nodes + '/' + encodeURIComponent(nodeId),
|
url: config.urls.nodes + '/' + encodeURIComponent(nodeId),
|
||||||
data: {
|
data: JSON.stringify(entity),
|
||||||
status: 'CONNECTING'
|
dataType: 'json',
|
||||||
},
|
contentType: 'application/json'
|
||||||
dataType: 'json'
|
|
||||||
}).done(function (response) {
|
}).done(function (response) {
|
||||||
var node = response.node;
|
var node = response.node;
|
||||||
|
|
||||||
|
@ -173,13 +179,19 @@ nf.ClusterTable = (function () {
|
||||||
* @argument {string} nodeId The node id
|
* @argument {string} nodeId The node id
|
||||||
*/
|
*/
|
||||||
var disconnect = function (nodeId) {
|
var disconnect = function (nodeId) {
|
||||||
|
var entity = {
|
||||||
|
'node': {
|
||||||
|
'nodeId': nodeId,
|
||||||
|
'status': 'DISCONNECTING'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
url: config.urls.nodes + '/' + encodeURIComponent(nodeId),
|
url: config.urls.nodes + '/' + encodeURIComponent(nodeId),
|
||||||
data: {
|
data: JSON.stringify(entity),
|
||||||
status: 'DISCONNECTING'
|
dataType: 'json',
|
||||||
},
|
contentType: 'application/json'
|
||||||
dataType: 'json'
|
|
||||||
}).done(function (response) {
|
}).done(function (response) {
|
||||||
var node = response.node;
|
var node = response.node;
|
||||||
|
|
||||||
|
@ -316,52 +328,6 @@ nf.ClusterTable = (function () {
|
||||||
}).fail(nf.Common.handleAjaxError);
|
}).fail(nf.Common.handleAjaxError);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the specified node the primary node of the cluster.
|
|
||||||
*
|
|
||||||
* @argument {object} item The node item
|
|
||||||
*/
|
|
||||||
var makePrimary = function (item) {
|
|
||||||
$.ajax({
|
|
||||||
type: 'PUT',
|
|
||||||
url: config.urls.nodes + '/' + encodeURIComponent(item.nodeId),
|
|
||||||
data: {
|
|
||||||
primary: true
|
|
||||||
},
|
|
||||||
dataType: 'json'
|
|
||||||
}).done(function (response) {
|
|
||||||
var grid = $('#cluster-table').data('gridInstance');
|
|
||||||
var data = grid.getData();
|
|
||||||
|
|
||||||
var node = response.node;
|
|
||||||
|
|
||||||
// start the update
|
|
||||||
data.beginUpdate();
|
|
||||||
data.updateItem(node.nodeId, node);
|
|
||||||
|
|
||||||
// need to find the previous primary node
|
|
||||||
// get the property grid data
|
|
||||||
var clusterItems = data.getItems();
|
|
||||||
$.each(clusterItems, function (i, otherNode) {
|
|
||||||
// attempt to identify the previous primary node
|
|
||||||
if (node.nodeId !== otherNode.nodeId && otherNode.primary === true) {
|
|
||||||
// reset its primary status
|
|
||||||
otherNode.primary = false;
|
|
||||||
otherNode.status = 'CONNECTED';
|
|
||||||
|
|
||||||
// set the new node state
|
|
||||||
data.updateItem(otherNode.nodeId, otherNode);
|
|
||||||
|
|
||||||
// no need to continue processing
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// end the update
|
|
||||||
data.endUpdate();
|
|
||||||
}).fail(nf.Common.handleAjaxError);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Initializes the cluster list.
|
* Initializes the cluster list.
|
||||||
|
@ -423,7 +389,13 @@ nf.ClusterTable = (function () {
|
||||||
|
|
||||||
// define a custom formatter for the more details column
|
// define a custom formatter for the more details column
|
||||||
var moreDetailsFormatter = function (row, cell, value, columnDef, dataContext) {
|
var moreDetailsFormatter = function (row, cell, value, columnDef, dataContext) {
|
||||||
return '<img src="images/iconDetails.png" title="View Details" class="pointer show-node-details" style="margin-top: 4px;"/>';
|
var markup = '<img src="images/iconDetails.png" title="View Details" class="pointer show-node-details" style="margin-top: 2px;"/>';
|
||||||
|
|
||||||
|
if (dataContext.primary === true) {
|
||||||
|
markup += ' <img src="images/iconPrimary.png" title="Primary Node" style="margin-top: 2px;"/>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return markup;
|
||||||
};
|
};
|
||||||
|
|
||||||
// define a custom formatter for the run status column
|
// define a custom formatter for the run status column
|
||||||
|
@ -431,15 +403,6 @@ nf.ClusterTable = (function () {
|
||||||
return formatNodeAddress(dataContext);
|
return formatNodeAddress(dataContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
// define a custom formatter for the status column
|
|
||||||
var statusFormatter = function (row, cell, value, columnDef, dataContext) {
|
|
||||||
if (dataContext.primary === true) {
|
|
||||||
return value + ', PRIMARY';
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// function for formatting the last accessed time
|
// function for formatting the last accessed time
|
||||||
var valueFormatter = function (row, cell, value, columnDef, dataContext) {
|
var valueFormatter = function (row, cell, value, columnDef, dataContext) {
|
||||||
return nf.Common.formatValue(value);
|
return nf.Common.formatValue(value);
|
||||||
|
@ -450,7 +413,7 @@ nf.ClusterTable = (function () {
|
||||||
{id: 'node', field: 'node', name: 'Node Address', formatter: nodeFormatter, resizable: true, sortable: true},
|
{id: 'node', field: 'node', name: 'Node Address', formatter: nodeFormatter, resizable: true, sortable: true},
|
||||||
{id: 'activeThreadCount', field: 'activeThreadCount', name: 'Active Thread Count', resizable: true, sortable: true, defaultSortAsc: false},
|
{id: 'activeThreadCount', field: 'activeThreadCount', name: 'Active Thread Count', resizable: true, sortable: true, defaultSortAsc: false},
|
||||||
{id: 'queued', field: 'queued', name: '<span class="queued-title">Queue</span> / <span class="queued-size-title">Size</span>', resizable: true, sortable: true, defaultSortAsc: false},
|
{id: 'queued', field: 'queued', name: '<span class="queued-title">Queue</span> / <span class="queued-size-title">Size</span>', resizable: true, sortable: true, defaultSortAsc: false},
|
||||||
{id: 'status', field: 'status', name: 'Status', formatter: statusFormatter, resizable: true, sortable: true},
|
{id: 'status', field: 'status', name: 'Status', resizable: true, sortable: true},
|
||||||
{id: 'uptime', field: 'nodeStartTime', name: 'Uptime', formatter: valueFormatter, resizable: true, sortable: true, defaultSortAsc: false},
|
{id: 'uptime', field: 'nodeStartTime', name: 'Uptime', formatter: valueFormatter, resizable: true, sortable: true, defaultSortAsc: false},
|
||||||
{id: 'heartbeat', field: 'heartbeat', name: 'Last Heartbeat', formatter: valueFormatter, resizable: true, sortable: true, defaultSortAsc: false}
|
{id: 'heartbeat', field: 'heartbeat', name: 'Last Heartbeat', formatter: valueFormatter, resizable: true, sortable: true, defaultSortAsc: false}
|
||||||
];
|
];
|
||||||
|
@ -483,7 +446,7 @@ nf.ClusterTable = (function () {
|
||||||
} else if (canDisconnect) {
|
} else if (canDisconnect) {
|
||||||
var actions = '<img src="images/iconDisconnect.png" title="Disconnect" class="pointer prompt-for-disconnect" style="margin-top: 2px;"/>';
|
var actions = '<img src="images/iconDisconnect.png" title="Disconnect" class="pointer prompt-for-disconnect" style="margin-top: 2px;"/>';
|
||||||
if (canBecomePrimary) {
|
if (canBecomePrimary) {
|
||||||
actions += ' <img src="images/iconPrimary.png" title="Make Primary" class="pointer make-primary" style="margin-top: 2px;"/>';
|
|
||||||
}
|
}
|
||||||
return actions;
|
return actions;
|
||||||
} else {
|
} else {
|
||||||
|
@ -545,8 +508,6 @@ nf.ClusterTable = (function () {
|
||||||
promptForRemoval(item);
|
promptForRemoval(item);
|
||||||
} else if (target.hasClass('prompt-for-disconnect')) {
|
} else if (target.hasClass('prompt-for-disconnect')) {
|
||||||
promptForDisconnect(item);
|
promptForDisconnect(item);
|
||||||
} else if (target.hasClass('make-primary')) {
|
|
||||||
makePrimary(item);
|
|
||||||
}
|
}
|
||||||
} else if (clusterGrid.getColumns()[args.cell].id === 'moreDetails') {
|
} else if (clusterGrid.getColumns()[args.cell].id === 'moreDetails') {
|
||||||
if (target.hasClass('show-node-details')) {
|
if (target.hasClass('show-node-details')) {
|
||||||
|
|
Loading…
Reference in New Issue