/*
* 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.sun.jersey.api.core.ResourceContext;
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.commons.lang3.StringUtils;
import org.apache.nifi.authorization.AccessDeniedException;
import org.apache.nifi.authorization.AuthorizationRequest;
import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.ComponentAuthorizable;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.controller.FlowController;
import org.apache.nifi.web.IllegalClusterResourceRequestException;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.api.dto.BulletinDTO;
import org.apache.nifi.web.api.dto.ClusterDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.NodeDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
import org.apache.nifi.web.api.entity.BulletinEntity;
import org.apache.nifi.web.api.entity.ClusterEntity;
import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
import org.apache.nifi.web.api.entity.Entity;
import org.apache.nifi.web.api.entity.HistoryEntity;
import org.apache.nifi.web.api.entity.NodeEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.request.DateTimeParameter;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* RESTful endpoint for managing a Flow Controller.
*/
@Path("/controller")
@Api(
value = "/controller",
description = "Provides realtime command and control of this NiFi instance"
)
public class ControllerResource extends ApplicationResource {
private NiFiServiceFacade serviceFacade;
private Authorizer authorizer;
private ReportingTaskResource reportingTaskResource;
private ControllerServiceResource controllerServiceResource;
@Context
private ResourceContext resourceContext;
/**
* Authorizes access to the flow.
*/
private void authorizeController(final RequestAction action) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final Map<String, String> userContext;
if (!StringUtils.isBlank(user.getClientAddress())) {
userContext = new HashMap<>();
userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
} else {
userContext = null;
}
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getControllerResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
.userContext(userContext)
.explanationSupplier(() -> {
final StringBuilder explanation = new StringBuilder("Unable to ");
if (RequestAction.READ.equals(action)) {
explanation.append("view ");
} else {
explanation.append("modify ");
}
explanation.append("the controller.");
return explanation.toString();
})
.build();
final AuthorizationResult result = authorizer.authorize(request);
if (!Result.Approved.equals(result.getResult())) {
throw new AccessDeniedException(result.getExplanation());
}
}
/**
* Retrieves the configuration for this NiFi.
*
* @return A controllerConfigurationEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("config")
@ApiOperation(
value = "Retrieves the configuration for this NiFi Controller",
response = ControllerConfigurationEntity.class,
authorizations = {
@Authorization(value = "Read - /controller", type = "")
}
)
@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 getControllerConfig() {
authorizeController(RequestAction.READ);
if (isReplicateRequest()) {
return replicate(HttpMethod.GET);
}
final ControllerConfigurationEntity entity = serviceFacade.getControllerConfiguration();
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Update the configuration for this NiFi.
*
* @param httpServletRequest request
* @param requestConfigEntity A controllerConfigurationEntity.
* @return A controllerConfigurationEntity.
*/
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("config")
@ApiOperation(
value = "Retrieves the configuration for this NiFi",
response = ControllerConfigurationEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = "")
}
)
@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 updateControllerConfig(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The controller configuration.",
required = true
) final ControllerConfigurationEntity requestConfigEntity) {
if (requestConfigEntity == null || requestConfigEntity.getComponent() == null) {
throw new IllegalArgumentException("Controller configuration must be specified");
}
if (requestConfigEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.PUT, requestConfigEntity);
}
final Revision requestRevision = getRevision(requestConfigEntity.getRevision(), FlowController.class.getSimpleName());
return withWriteLock(
serviceFacade,
requestConfigEntity,
requestRevision,
lookup -> {
authorizeController(RequestAction.WRITE);
},
null,
(revision, configEntity) -> {
final ControllerConfigurationEntity entity = serviceFacade.updateControllerConfiguration(revision, configEntity.getComponent());
return clusterContext(generateOkResponse(entity)).build();
}
);
}
// ---------------
// reporting tasks
// ---------------
/**
* Creates a new Reporting Task.
*
* @param httpServletRequest request
* @param requestReportingTaskEntity A reportingTaskEntity.
* @return A reportingTaskEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("reporting-tasks")
@ApiOperation(
value = "Creates a new reporting task",
response = ReportingTaskEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = ""),
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = ""),
@Authorization(value = "Write - if the Reporting Task is restricted - /restricted-components", type = "")
}
)
@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 createReportingTask(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The reporting task configuration details.",
required = true
) final ReportingTaskEntity requestReportingTaskEntity) {
if (requestReportingTaskEntity == null || requestReportingTaskEntity.getComponent() == null) {
throw new IllegalArgumentException("Reporting task details must be specified.");
}
if (requestReportingTaskEntity.getRevision() == null || (requestReportingTaskEntity.getRevision().getVersion() == null || requestReportingTaskEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Reporting task.");
}
final ReportingTaskDTO requestReportingTask = requestReportingTaskEntity.getComponent();
if (requestReportingTask.getId() != null) {
throw new IllegalArgumentException("Reporting task ID cannot be specified.");
}
if (StringUtils.isBlank(requestReportingTask.getType())) {
throw new IllegalArgumentException("The type of reporting task to create must be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, requestReportingTaskEntity);
}
return withWriteLock(
serviceFacade,
requestReportingTaskEntity,
lookup -> {
authorizeController(RequestAction.WRITE);
ComponentAuthorizable authorizable = null;
try {
authorizable = lookup.getConfigurableComponent(requestReportingTask.getType(), requestReportingTask.getBundle());
if (authorizable.isRestricted()) {
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
}
if (requestReportingTask.getProperties() != null) {
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestReportingTask.getProperties(), authorizable, authorizer, lookup);
}
} finally {
if (authorizable != null) {
authorizable.cleanUpResources();
}
}
},
() -> serviceFacade.verifyCreateReportingTask(requestReportingTask),
(reportingTaskEntity) -> {
final ReportingTaskDTO reportingTask = reportingTaskEntity.getComponent();
// set the processor id as appropriate
reportingTask.setId(generateUuid());
// create the reporting task and generate the json
final Revision revision = getRevision(reportingTaskEntity, reportingTask.getId());
final ReportingTaskEntity entity = serviceFacade.createReportingTask(revision, reportingTask);
reportingTaskResource.populateRemainingReportingTaskEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getUri()), entity)).build();
}
);
}
/**
* Creates a Bulletin.
*
* @param httpServletRequest request
* @param requestBulletinEntity A bulletinEntity.
* @return A bulletinEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("bulletin")
@ApiOperation(
value = "Creates a new bulletin",
response = BulletinEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = "")
}
)
@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 createBulletin(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The reporting task configuration details.",
required = true
) final BulletinEntity requestBulletinEntity) {
if (requestBulletinEntity == null || requestBulletinEntity.getBulletin() == null) {
throw new IllegalArgumentException("Bulletin details must be specified.");
}
final BulletinDTO requestBulletin = requestBulletinEntity.getBulletin();
if (requestBulletin.getId() != null) {
throw new IllegalArgumentException("A bulletin ID cannot be specified.");
}
if (StringUtils.isBlank(requestBulletin.getMessage())) {
throw new IllegalArgumentException("The bulletin message must be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, requestBulletinEntity);
}
return withWriteLock(
serviceFacade,
requestBulletinEntity,
lookup -> {
authorizeController(RequestAction.WRITE);
},
null,
(bulletinEntity) -> {
final BulletinDTO bulletin = bulletinEntity.getBulletin();
final BulletinEntity entity = serviceFacade.createBulletin(bulletin,true);
return generateOkResponse(entity).build();
}
);
}
// -------------------
// controller services
// -------------------
/**
* Creates a new Controller Service.
*
* @param httpServletRequest request
* @param requestControllerServiceEntity A controllerServiceEntity.
* @return A controllerServiceEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("controller-services")
@ApiOperation(
value = "Creates a new controller service",
response = ControllerServiceEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = ""),
@Authorization(value = "Read - any referenced Controller Services - /controller-services/{uuid}", type = ""),
@Authorization(value = "Write - if the Controller Service is restricted - /restricted-components", type = "")
}
)
@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 createControllerService(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "The controller service configuration details.",
required = true
) final ControllerServiceEntity requestControllerServiceEntity) {
if (requestControllerServiceEntity == null || requestControllerServiceEntity.getComponent() == null) {
throw new IllegalArgumentException("Controller service details must be specified.");
}
if (requestControllerServiceEntity.getRevision() == null
|| (requestControllerServiceEntity.getRevision().getVersion() == null || requestControllerServiceEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Controller service.");
}
final ControllerServiceDTO requestControllerService = requestControllerServiceEntity.getComponent();
if (requestControllerService.getId() != null) {
throw new IllegalArgumentException("Controller service ID cannot be specified.");
}
if (requestControllerService.getParentGroupId() != null) {
throw new IllegalArgumentException("Parent process group ID cannot be specified.");
}
if (StringUtils.isBlank(requestControllerService.getType())) {
throw new IllegalArgumentException("The type of controller service to create must be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, requestControllerServiceEntity);
}
return withWriteLock(
serviceFacade,
requestControllerServiceEntity,
lookup -> {
authorizeController(RequestAction.WRITE);
ComponentAuthorizable authorizable = null;
try {
authorizable = lookup.getConfigurableComponent(requestControllerService.getType(), requestControllerService.getBundle());
if (authorizable.isRestricted()) {
lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
}
if (requestControllerService.getProperties() != null) {
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup);
}
} finally {
if (authorizable != null) {
authorizable.cleanUpResources();
}
}
},
() -> serviceFacade.verifyCreateControllerService(requestControllerService),
(controllerServiceEntity) -> {
final ControllerServiceDTO controllerService = controllerServiceEntity.getComponent();
// set the processor id as appropriate
controllerService.setId(generateUuid());
// create the controller service and generate the json
final Revision revision = getRevision(controllerServiceEntity, controllerService.getId());
final ControllerServiceEntity entity = serviceFacade.createControllerService(revision, null, controllerService);
controllerServiceResource.populateRemainingControllerServiceEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(entity.getUri()), entity)).build();
}
);
}
// -------
// cluster
// -------
/**
* Gets the contents of this NiFi cluster. This includes all nodes and their status.
*
* @return A clusterEntity
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("cluster")
@ApiOperation(
value = "Gets the contents of the cluster",
notes = "Returns the contents of the cluster including all nodes and their status.",
response = ClusterEntity.class,
authorizations = {
@Authorization(value = "Read - /controller", type = "")
}
)
@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 getCluster() {
authorizeController(RequestAction.READ);
// ensure connected to the cluster
if (!isConnectedToCluster()) {
throw new IllegalClusterResourceRequestException("Only a node connected to a cluster can process the request.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.GET, getClusterCoordinatorNode());
}
final ClusterDTO dto = serviceFacade.getCluster();
// create entity
final ClusterEntity entity = new ClusterEntity();
entity.setCluster(dto);
// generate the response
return generateOkResponse(entity).build();
}
/**
* 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("cluster/nodes/{id}")
@ApiOperation(
value = "Gets a node in the cluster",
response = NodeEntity.class,
authorizations = {
@Authorization(value = "Read - /controller", type = "")
}
)
@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) {
authorizeController(RequestAction.READ);
// ensure connected to the cluster
if (!isConnectedToCluster()) {
throw new IllegalClusterResourceRequestException("Only a node connected to a cluster can process the request.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.GET, getClusterCoordinatorNode());
}
// 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();
}
/**
* 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("cluster/nodes/{id}")
@ApiOperation(
value = "Updates a node in the cluster",
response = NodeEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = "")
}
)
@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.",
required = true
) NodeEntity nodeEntity) {
authorizeController(RequestAction.WRITE);
// ensure connected to the cluster
if (!isConnectedToCluster()) {
throw new IllegalClusterResourceRequestException("Only a node connected to a cluster can process the request.");
}
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));
}
if (isReplicateRequest()) {
return replicateToCoordinator(HttpMethod.PUT, nodeEntity);
}
// 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();
}
/**
* 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("cluster/nodes/{id}")
@ApiOperation(
value = "Removes a node from the cluster",
response = NodeEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = "")
}
)
@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) {
authorizeController(RequestAction.WRITE);
// ensure connected to the cluster
if (!isConnectedToCluster()) {
throw new IllegalClusterResourceRequestException("Only a node connected to a cluster can process the request.");
}
if (isReplicateRequest()) {
return replicateToCoordinator(HttpMethod.DELETE, getRequestParameters());
}
serviceFacade.deleteNode(id);
// create the response entity
final NodeEntity entity = new NodeEntity();
// generate the response
return generateOkResponse(entity).build();
}
// -------
// history
// -------
/**
* Deletes flow history from the specified end date.
*
* @param endDate The end date for the purge action.
* @return A historyEntity
*/
@DELETE
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("history")
@ApiOperation(
value = "Purges history",
response = HistoryEntity.class,
authorizations = {
@Authorization(value = "Write - /controller", type = "")
}
)
@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 deleteHistory(
@Context final HttpServletRequest httpServletRequest,
@ApiParam(
value = "Purge actions before this date/time.",
required = true
)
@QueryParam("endDate") DateTimeParameter endDate) {
// ensure the end date is specified
if (endDate == null) {
throw new IllegalArgumentException("The end date must be specified.");
}
// Note: History requests are not replicated throughout the cluster and are instead handled by the nodes independently
return withWriteLock(
serviceFacade,
new EndDateEntity(endDate.getDateTime()),
lookup -> {
authorizeController(RequestAction.WRITE);
},
null,
(endDateEntity) -> {
// purge the actions
serviceFacade.deleteActions(endDateEntity.getEndDate());
// generate the response
return generateOkResponse(new HistoryEntity()).build();
}
);
}
private class EndDateEntity extends Entity {
final Date endDate;
public EndDateEntity(Date endDate) {
this.endDate = endDate;
}
public Date getEndDate() {
return endDate;
}
}
// setters
public void setServiceFacade(final NiFiServiceFacade serviceFacade) {
this.serviceFacade = serviceFacade;
}
public void setReportingTaskResource(final ReportingTaskResource reportingTaskResource) {
this.reportingTaskResource = reportingTaskResource;
}
public void setControllerServiceResource(final ControllerServiceResource controllerServiceResource) {
this.controllerServiceResource = controllerServiceResource;
}
public void setAuthorizer(final Authorizer authorizer) {
this.authorizer = authorizer;
}
}