From 9152a9fdbb804930e4d3e6dfb44cddfa866d9338 Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Thu, 26 May 2016 10:20:52 -0400 Subject: [PATCH] NIFI-1800: - UI style updates to make the components stand out better. - Reusing controller service table in different contexts (controller, process group, etc). - This closes #469 --- .../api/dto/ControllerConfigurationDTO.java | 51 +- .../entity/ControllerConfigurationEntity.java | 19 +- .../apache/nifi/audit/ControllerAuditor.java | 117 +-- .../apache/nifi/web/NiFiServiceFacade.java | 5 +- .../nifi/web/StandardNiFiServiceFacade.java | 98 +- .../nifi/web/api/ControllerResource.java | 241 +++-- .../org/apache/nifi/web/api/FlowResource.java | 130 ++- .../apache/nifi/web/api/dto/DtoFactory.java | 19 + .../nifi/web/api/dto/EntityFactory.java | 14 + .../main/resources/nifi-web-api-context.xml | 3 + .../accesscontrol/AdminAccessControlTest.java | 1 - .../accesscontrol/DfmAccessControlTest.java | 2 - .../ReadOnlyAccessControlTest.java | 1 - .../nifi-web/nifi-web-ui/pom.xml | 1 + .../main/resources/filters/canvas.properties | 1 + .../WEB-INF/partials/canvas/navigation.jsp | 14 +- .../canvas/process-group-configuration.jsp | 55 +- .../partials/canvas/settings-content.jsp | 41 +- .../src/main/webapp/css/flow-status.css | 7 +- .../nifi-web-ui/src/main/webapp/css/graph.css | 6 + .../src/main/webapp/css/header.css | 8 +- .../src/main/webapp/css/navigation.css | 19 +- .../css/process-group-configuration.css | 59 +- .../src/main/webapp/css/settings.css | 37 +- .../propertytable/jquery.propertytable.js | 77 +- .../nf-ng-canvas-global-menu-controller.js | 4 +- .../nf-ng-canvas-header-controller.js | 26 - .../main/webapp/js/nf/canvas/nf-actions.js | 13 +- .../src/main/webapp/js/nf/canvas/nf-canvas.js | 54 +- .../js/nf/canvas/nf-controller-service.js | 254 +++-- .../js/nf/canvas/nf-controller-services.js | 883 +++++++++++++++++ .../canvas/nf-process-group-configuration.js | 321 ++++-- .../webapp/js/nf/canvas/nf-reporting-task.js | 15 +- .../main/webapp/js/nf/canvas/nf-settings.js | 918 ++++-------------- .../src/main/webapp/js/nf/nf-common.js | 13 +- 35 files changed, 2050 insertions(+), 1477 deletions(-) create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-controller-services.js diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java index c6a7766171..2c7edf7784 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java @@ -17,10 +17,11 @@ package org.apache.nifi.web.api.dto; import com.wordnik.swagger.annotations.ApiModelProperty; -import java.util.Date; +import org.apache.nifi.web.api.dto.util.TimeAdapter; + import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.apache.nifi.web.api.dto.util.TimeAdapter; +import java.util.Date; /** * Details for the controller configuration. @@ -28,13 +29,10 @@ import org.apache.nifi.web.api.dto.util.TimeAdapter; @XmlType(name = "config") public class ControllerConfigurationDTO { - private String name; - private String comments; private Integer maxTimerDrivenThreadCount; private Integer maxEventDrivenThreadCount; private Long autoRefreshIntervalSeconds; - private Boolean siteToSiteSecure; private Date currentTime; private Integer timeOffset; @@ -67,34 +65,6 @@ public class ControllerConfigurationDTO { this.maxEventDrivenThreadCount = maxEventDrivenThreadCount; } - /** - * @return name of this NiFi - */ - @ApiModelProperty( - value = "The name of this NiFi." - ) - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - /** - * @return comments for this NiFi - */ - @ApiModelProperty( - value = "The comments for this NiFi." - ) - public String getComments() { - return comments; - } - - public void setComments(String comments) { - this.comments = comments; - } - /** * @return interval in seconds between the automatic NiFi refresh requests. This value is read only */ @@ -110,21 +80,6 @@ public class ControllerConfigurationDTO { this.autoRefreshIntervalSeconds = autoRefreshIntervalSeconds; } - /** - * @return Indicates whether or not Site-to-Site communications with this instance is secure (2-way authentication). This value is read only - */ - @ApiModelProperty( - value = "Indicates whether site to site communication with the NiFi is secure (requires 2-way authenticiation).", - readOnly = true - ) - public Boolean isSiteToSiteSecure() { - return siteToSiteSecure; - } - - public void setSiteToSiteSecure(Boolean siteToSiteSecure) { - this.siteToSiteSecure = siteToSiteSecure; - } - /** * @return current time on the server */ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java index 5aa7acd532..4b1188c165 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java @@ -17,6 +17,7 @@ package org.apache.nifi.web.api.entity; import com.wordnik.swagger.annotations.ApiModelProperty; +import org.apache.nifi.web.api.dto.AccessPolicyDTO; import org.apache.nifi.web.api.dto.ControllerConfigurationDTO; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -26,10 +27,11 @@ import javax.xml.bind.annotation.XmlRootElement; * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a ControllerConfigurationDTO. */ @XmlRootElement(name = "controllerConfigurationEntity") -public class ControllerConfigurationEntity extends ComponentEntity { +public class ControllerConfigurationEntity extends Entity { private ControllerConfigurationDTO config; private RevisionDTO revision; + private AccessPolicyDTO accessPolicy; /** * @return revision for this request/response @@ -65,4 +67,19 @@ public class ControllerConfigurationEntity extends ComponentEntity { this.config = config; } + /** + * The access policy for this component. + * + * @return The access policy + */ + @ApiModelProperty( + value = "The access policy for the controller." + ) + public AccessPolicyDTO getAccessPolicy() { + return accessPolicy; + } + + public void setAccessPolicy(AccessPolicyDTO accessPolicy) { + this.accessPolicy = accessPolicy; + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java index 5a6c59099e..d8c27360b4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java @@ -16,9 +16,6 @@ */ package org.apache.nifi.audit; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; import org.apache.nifi.action.Action; import org.apache.nifi.action.Component; import org.apache.nifi.action.FlowChangeAction; @@ -33,6 +30,10 @@ import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + /** * Audits configuration changes to the controller. */ @@ -41,112 +42,6 @@ public class ControllerAuditor extends NiFiAuditor { private static final Logger logger = LoggerFactory.getLogger(ControllerAuditor.class); - /** - * Audits updating the name of the controller. - * - * @param proceedingJoinPoint join point - * @param name name - * @param controllerFacade facade - * @throws java.lang.Throwable ex - */ - @Around("within(org.apache.nifi.web.controller.ControllerFacade) && " - + "execution(void setName(java.lang.String)) && " - + "args(name) && " - + "target(controllerFacade)") - public void updateControllerNameAdvice(ProceedingJoinPoint proceedingJoinPoint, String name, ControllerFacade controllerFacade) throws Throwable { - // get the previous name - String previousName = controllerFacade.getName(); - - // update the configuraion - proceedingJoinPoint.proceed(); - - // if no exception were thrown, add the configuration action... - // ensure the name changed - if (!name.equals(previousName)) { - // get the current user - NiFiUser user = NiFiUserUtils.getNiFiUser(); - - // ensure the user was found - if (user != null) { - Collection actions = new ArrayList<>(); - - // create the configuration details - FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails(); - configDetails.setName("Controller Name"); - configDetails.setValue(name); - configDetails.setPreviousValue(previousName); - - // create the config action - FlowChangeAction configAction = new FlowChangeAction(); - configAction.setUserIdentity(user.getIdentity()); - configAction.setUserName(user.getUserName()); - configAction.setOperation(Operation.Configure); - configAction.setTimestamp(new Date()); - configAction.setSourceId("Flow Controller"); - configAction.setSourceName(controllerFacade.getName()); - configAction.setSourceType(Component.Controller); - configAction.setActionDetails(configDetails); - actions.add(configAction); - - // record the action - saveActions(actions, logger); - } - } - } - - /** - * Audits updating the comments of the controller. - * - * @param proceedingJoinPoint join point - * @param comments comments - * @param controllerFacade facade - * @throws java.lang.Throwable ex - */ - @Around("within(org.apache.nifi.web.controller.ControllerFacade) && " - + "execution(void setComments(java.lang.String)) && " - + "args(comments) && " - + "target(controllerFacade)") - public void updateControllerCommentsAdvice(ProceedingJoinPoint proceedingJoinPoint, String comments, ControllerFacade controllerFacade) throws Throwable { - // get the previous name - String previousComments = controllerFacade.getComments(); - - // update the configuraion - proceedingJoinPoint.proceed(); - - // if no exception were thrown, add the configuration action... - // ensure the name changed - if (!comments.equals(previousComments)) { - // get the current user - NiFiUser user = NiFiUserUtils.getNiFiUser(); - - // ensure the user was found - if (user != null) { - Collection actions = new ArrayList<>(); - - // create the configuration details - FlowChangeConfigureDetails configDetails = new FlowChangeConfigureDetails(); - configDetails.setName("Controller Comments"); - configDetails.setValue(comments); - configDetails.setPreviousValue(previousComments); - - // create the config action - FlowChangeAction configAction = new FlowChangeAction(); - configAction.setUserIdentity(user.getIdentity()); - configAction.setUserName(user.getUserName()); - configAction.setOperation(Operation.Configure); - configAction.setTimestamp(new Date()); - configAction.setSourceId("Flow Controller"); - configAction.setSourceName(controllerFacade.getName()); - configAction.setSourceType(Component.Controller); - configAction.setActionDetails(configDetails); - actions.add(configAction); - - // record the action - saveActions(actions, logger); - } - } - } - /** * Audits updating the max number of timer driven threads for the controller. * @@ -189,7 +84,7 @@ public class ControllerAuditor extends NiFiAuditor { configAction.setOperation(Operation.Configure); configAction.setTimestamp(new Date()); configAction.setSourceId("Flow Controller"); - configAction.setSourceName(controllerFacade.getName()); + configAction.setSourceName("Flow Controller"); configAction.setSourceType(Component.Controller); configAction.setActionDetails(configDetails); actions.add(configAction); @@ -242,7 +137,7 @@ public class ControllerAuditor extends NiFiAuditor { configAction.setOperation(Operation.Configure); configAction.setTimestamp(new Date()); configAction.setSourceId("Flow Controller"); - configAction.setSourceName(controllerFacade.getName()); + configAction.setSourceName("Flow Controller"); configAction.setSourceType(Component.Controller); configAction.setActionDetails(configDetails); actions.add(configAction); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java index f3728126c6..c4dc34d954 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java @@ -66,6 +66,7 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO; import org.apache.nifi.web.api.dto.status.StatusHistoryDTO; import org.apache.nifi.web.api.entity.ConnectionEntity; +import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentsEntity; import org.apache.nifi.web.api.entity.FlowEntity; @@ -262,7 +263,7 @@ public interface NiFiServiceFacade { * * @return Controller configuration transfer object */ - ControllerConfigurationDTO getControllerConfiguration(); + ControllerConfigurationEntity getControllerConfiguration(); /** * Updates the configuration for this controller. @@ -271,7 +272,7 @@ public interface NiFiServiceFacade { * @param controllerConfigurationDTO Controller configuration DTO * @return Controller configuration DTO */ - ConfigurationSnapshot updateControllerConfiguration(Revision revision, ControllerConfigurationDTO controllerConfigurationDTO); + ControllerConfigurationEntity updateControllerConfiguration(Revision revision, ControllerConfigurationDTO controllerConfigurationDTO); /** * Creates a new archive of the flow configuration. diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index cb4483463c..d4f235a6e6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -45,6 +45,7 @@ import org.apache.nifi.connectable.Funnel; import org.apache.nifi.connectable.Port; import org.apache.nifi.controller.ConfiguredComponent; import org.apache.nifi.controller.Counter; +import org.apache.nifi.controller.FlowController; import org.apache.nifi.controller.ProcessorNode; import org.apache.nifi.controller.ReportingTaskNode; import org.apache.nifi.controller.ScheduledState; @@ -67,7 +68,6 @@ import org.apache.nifi.remote.RootGroupPort; import org.apache.nifi.reporting.Bulletin; import org.apache.nifi.reporting.BulletinQuery; import org.apache.nifi.reporting.BulletinRepository; -import org.apache.nifi.util.FormatUtils; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.web.api.dto.AccessPolicyDTO; import org.apache.nifi.web.api.dto.BulletinBoardDTO; @@ -127,6 +127,7 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO; import org.apache.nifi.web.api.dto.status.StatusHistoryDTO; import org.apache.nifi.web.api.entity.ConnectionEntity; +import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentsEntity; @@ -183,9 +184,7 @@ import java.util.ListIterator; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.TimeZone; import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -886,32 +885,25 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public ConfigurationSnapshot updateControllerConfiguration(final Revision revision, final ControllerConfigurationDTO controllerConfigurationDTO) { - final Supplier daoUpdate = () -> { - // update the controller configuration through the proxy - if (controllerConfigurationDTO.getName() != null) { - controllerFacade.setName(controllerConfigurationDTO.getName()); - } - if (controllerConfigurationDTO.getComments() != null) { - controllerFacade.setComments(controllerConfigurationDTO.getComments()); - } - if (controllerConfigurationDTO.getMaxTimerDrivenThreadCount() != null) { - controllerFacade.setMaxTimerDrivenThreadCount(controllerConfigurationDTO.getMaxTimerDrivenThreadCount()); - } - if (controllerConfigurationDTO.getMaxEventDrivenThreadCount() != null) { - controllerFacade.setMaxEventDrivenThreadCount(controllerConfigurationDTO.getMaxEventDrivenThreadCount()); - } - - return controllerConfigurationDTO; - }; - + public ControllerConfigurationEntity updateControllerConfiguration(final Revision revision, final ControllerConfigurationDTO controllerConfigurationDTO) { final RevisionUpdate updatedComponent = updateComponent( revision, controllerFacade, - daoUpdate, - controller -> getControllerConfiguration()); + () -> { + if (controllerConfigurationDTO.getMaxTimerDrivenThreadCount() != null) { + controllerFacade.setMaxTimerDrivenThreadCount(controllerConfigurationDTO.getMaxTimerDrivenThreadCount()); + } + if (controllerConfigurationDTO.getMaxEventDrivenThreadCount() != null) { + controllerFacade.setMaxEventDrivenThreadCount(controllerConfigurationDTO.getMaxEventDrivenThreadCount()); + } - return new ConfigurationSnapshot<>(updatedComponent.getLastModification().getRevision().getVersion()); + return controllerConfigurationDTO; + }, + controller -> dtoFactory.createControllerConfigurationDto(controllerFacade, properties.getAutoRefreshInterval())); + + final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerFacade); + final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(updatedComponent.getLastModification()); + return entityFactory.createControllerConfigurationEntity(updatedComponent.getComponent(), updateRevision, accessPolicy); } @Override @@ -1266,9 +1258,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { * * @return a RevisionUpdate that represents the updated configuration */ - private RevisionUpdate createComponent(final ComponentDTO componentDto, - final Supplier daoCreation, final Function dtoCreation) { - + private RevisionUpdate createComponent(final ComponentDTO componentDto, final Supplier daoCreation, final Function dtoCreation) { final String modifier = NiFiUserUtils.getNiFiUserName(); // ensure id is set @@ -1638,6 +1628,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public ControllerServiceEntity createControllerService(final String groupId, final ControllerServiceDTO controllerServiceDTO) { + final String normalizedGroupId = groupId == null ? controllerFacade.getRootGroupId() : groupId; + controllerServiceDTO.setParentGroupId(normalizedGroupId); + final RevisionUpdate snapshot = createComponent( controllerServiceDTO, () -> { @@ -1645,7 +1638,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO); // TODO - this logic should be part of the controllerServiceDAO - final ProcessGroup group = processGroupDAO.getProcessGroup(groupId); + final ProcessGroup group = processGroupDAO.getProcessGroup(normalizedGroupId); group.addControllerService(controllerService); return controllerService; }, @@ -2350,8 +2343,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final ControllerDTO controllerDTO = new ControllerDTO(); controllerDTO.setId(controllerFacade.getRootGroupId()); controllerDTO.setInstanceId(controllerFacade.getInstanceId()); - controllerDTO.setName(controllerFacade.getName()); - controllerDTO.setComments(controllerFacade.getComments()); controllerDTO.setInputPorts(inputPortDtos); controllerDTO.setOutputPorts(outputPortDtos); controllerDTO.setInputPortCount(inputPorts.size()); @@ -2374,29 +2365,13 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public ControllerConfigurationDTO getControllerConfiguration() { - ControllerConfigurationDTO controllerConfig = new ControllerConfigurationDTO(); - controllerConfig.setName(controllerFacade.getName()); - controllerConfig.setComments(controllerFacade.getComments()); - controllerConfig.setMaxTimerDrivenThreadCount(controllerFacade.getMaxTimerDrivenThreadCount()); - controllerConfig.setMaxEventDrivenThreadCount(controllerFacade.getMaxEventDrivenThreadCount()); - - // get the refresh interval - final long refreshInterval = FormatUtils.getTimeDuration(properties.getAutoRefreshInterval(), TimeUnit.SECONDS); - controllerConfig.setAutoRefreshIntervalSeconds(refreshInterval); - - final Date now = new Date(); - controllerConfig.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime())); - controllerConfig.setCurrentTime(now); - - // determine the site to site configuration - if (isClustered()) { - controllerConfig.setSiteToSiteSecure(controllerFacade.isClusterManagerRemoteSiteCommsSecure()); - } else { - controllerConfig.setSiteToSiteSecure(controllerFacade.isRemoteSiteCommsSecure()); - } - - return controllerConfig; + public ControllerConfigurationEntity getControllerConfiguration() { + return revisionManager.get(FlowController.class.getSimpleName(), rev -> { + final ControllerConfigurationDTO dto = dtoFactory.createControllerConfigurationDto(controllerFacade, properties.getAutoRefreshInterval()); + final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(controllerFacade); + final RevisionDTO revision = dtoFactory.createRevisionDTO(rev); + return entityFactory.createControllerConfigurationEntity(dto, revision, accessPolicy); + }); } @Override @@ -2656,9 +2631,18 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public Set getControllerServices(String groupId) { // TODO - move this logic into the ControllerServiceDAO - final ProcessGroup group = processGroupDAO.getProcessGroup(groupId); - final Set serviceNodes = group.getControllerServices(true); - final Set serviceIds = serviceNodes.stream().map(service -> service.getIdentifier()).collect(Collectors.toSet()); + + final Set serviceNodes; + final Set serviceIds; + if (groupId == null) { + // TODO - controller services scoped by the controller + serviceNodes = controllerServiceDAO.getControllerServices(); + serviceIds = serviceNodes.stream().map(service -> service.getIdentifier()).collect(Collectors.toSet()); + } else { + final ProcessGroup group = processGroupDAO.getProcessGroup(groupId); + serviceNodes = group.getControllerServices(true); + serviceIds = serviceNodes.stream().map(service -> service.getIdentifier()).collect(Collectors.toSet()); + } return revisionManager.get(serviceIds, () -> { return serviceNodes.stream() diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java index 695898e2c7..59484a0f7e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java @@ -16,10 +16,43 @@ */ package org.apache.nifi.web.api; -import java.net.URI; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +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.Authorizer; +import org.apache.nifi.authorization.RequestAction; +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.cluster.coordination.http.replication.RequestReplicator; +import org.apache.nifi.cluster.manager.NodeResponse; +import org.apache.nifi.cluster.manager.exception.UnknownNodeException; +import org.apache.nifi.cluster.manager.impl.WebClusterManager; +import org.apache.nifi.cluster.node.Node; +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.controller.FlowController; +import org.apache.nifi.util.NiFiProperties; +import org.apache.nifi.web.NiFiServiceFacade; +import org.apache.nifi.web.Revision; +import org.apache.nifi.web.api.dto.CounterDTO; +import org.apache.nifi.web.api.dto.CountersDTO; +import org.apache.nifi.web.api.entity.AuthorityEntity; +import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; +import org.apache.nifi.web.api.entity.ControllerServiceEntity; +import org.apache.nifi.web.api.entity.CounterEntity; +import org.apache.nifi.web.api.entity.CountersEntity; +import org.apache.nifi.web.api.entity.Entity; +import org.apache.nifi.web.api.entity.ProcessGroupEntity; +import org.apache.nifi.web.api.entity.ReportingTaskEntity; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -36,41 +69,10 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; - -import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.authorization.user.NiFiUser; -import org.apache.nifi.authorization.user.NiFiUserUtils; -import org.apache.nifi.cluster.coordination.http.replication.RequestReplicator; -import org.apache.nifi.cluster.manager.NodeResponse; -import org.apache.nifi.cluster.manager.exception.UnknownNodeException; -import org.apache.nifi.cluster.manager.impl.WebClusterManager; -import org.apache.nifi.cluster.node.Node; -import org.apache.nifi.cluster.protocol.NodeIdentifier; -import org.apache.nifi.util.NiFiProperties; -import org.apache.nifi.web.ConfigurationSnapshot; -import org.apache.nifi.web.NiFiServiceFacade; -import org.apache.nifi.web.Revision; -import org.apache.nifi.web.api.dto.ControllerConfigurationDTO; -import org.apache.nifi.web.api.dto.CounterDTO; -import org.apache.nifi.web.api.dto.CountersDTO; -import org.apache.nifi.web.api.dto.RevisionDTO; -import org.apache.nifi.web.api.entity.AuthorityEntity; -import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; -import org.apache.nifi.web.api.entity.CounterEntity; -import org.apache.nifi.web.api.entity.CountersEntity; -import org.apache.nifi.web.api.entity.Entity; -import org.apache.nifi.web.api.entity.ProcessGroupEntity; -import org.apache.nifi.web.api.entity.ReportingTaskEntity; -import org.apache.nifi.web.api.entity.ReportingTasksEntity; -import org.apache.nifi.web.api.request.ClientIdParameter; - -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 java.net.URI; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; /** * RESTful endpoint for managing a Flow Controller. @@ -85,12 +87,35 @@ public class ControllerResource extends ApplicationResource { private NiFiServiceFacade serviceFacade; private WebClusterManager clusterManager; private NiFiProperties properties; + 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 AuthorizationRequest request = new AuthorizationRequest.Builder() + .resource(ResourceFactory.getControllerResource()) + .identity(user.getIdentity()) + .anonymous(user.isAnonymous()) + .accessAttempt(true) + .action(action) + .build(); + + final AuthorizationResult result = authorizer.authorize(request); + if (!Result.Approved.equals(result.getResult())) { + final String message = StringUtils.isNotBlank(result.getExplanation()) ? result.getExplanation() : "Access is denied"; + throw new AccessDeniedException(message); + } + } + /** * Creates a new archive of this flow controller. Note, this is a POST operation that returns a URI that is not representative of the thing that was actually created. The archive that is created * cannot be referenced at a later time, therefore there is no corresponding URI. Instead the request URI is returned. @@ -311,19 +336,15 @@ public class ControllerResource extends ApplicationResource { } ) public Response getControllerConfig() { + // TODO +// authorizeController(RequestAction.READ); // replicate if cluster manager if (properties.isClusterManager()) { return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse(); } - final ControllerConfigurationDTO controllerConfig = serviceFacade.getControllerConfiguration(); - - // create the response entity - final ControllerConfigurationEntity entity = new ControllerConfigurationEntity(); - entity.setConfig(controllerConfig); - - // generate the response + final ControllerConfigurationEntity entity = serviceFacade.getControllerConfiguration(); return clusterContext(generateOkResponse(entity)).build(); } @@ -374,31 +395,19 @@ public class ControllerResource extends ApplicationResource { return clusterManager.applyRequest(HttpMethod.PUT, getAbsolutePath(), configEntity, getHeaders()).getResponse(); } - final RevisionDTO revisionDto = configEntity.getRevision(); - final Revision revision = new Revision(revisionDto.getVersion(), revisionDto.getClientId(), "controller"); - - // handle expects request (usually from the cluster manager) - final String expects = httpServletRequest.getHeader(RequestReplicator.REQUEST_VALIDATION_HTTP_HEADER); - if (expects != null) { - return generateContinueResponse().build(); - } - - final ConfigurationSnapshot controllerResponse - = serviceFacade.updateControllerConfiguration(revision, configEntity.getConfig()); - final ControllerConfigurationDTO controllerConfig = controllerResponse.getConfiguration(); - - // get the updated revision - final RevisionDTO updatedRevision = new RevisionDTO(); - updatedRevision.setClientId(revision.getClientId()); - updatedRevision.setVersion(controllerResponse.getVersion()); - - // create the response entity - final ControllerConfigurationEntity entity = new ControllerConfigurationEntity(); - entity.setRevision(updatedRevision); - entity.setConfig(controllerConfig); - - // generate the response - return clusterContext(generateOkResponse(entity)).build(); + final Revision revision = getRevision(configEntity.getRevision(), FlowController.class.getSimpleName()); + return withWriteLock( + serviceFacade, + revision, + lookup -> { + authorizeController(RequestAction.WRITE); + }, + null, + () -> { + final ControllerConfigurationEntity entity = serviceFacade.updateControllerConfiguration(revision, configEntity.getConfig()); + return clusterContext(generateOkResponse(entity)).build(); + } + ); } /**x @@ -519,26 +528,27 @@ public class ControllerResource extends ApplicationResource { return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build(); } + // ------------------- + // controller services + // ------------------- + /** - * Retrieves all the of reporting tasks in this NiFi. + * Creates a new Controller Service. * - * @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. - * @return A reportingTasksEntity. + * @param httpServletRequest request + * @param controllerServiceEntity A controllerServiceEntity. + * @return A controllerServiceEntity. */ - @GET - @Consumes(MediaType.WILDCARD) + @POST + @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @Path("reporting-tasks") - // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')") + @Path("controller-services") + // TODO - @PreAuthorize("hasRole('ROLE_DFM')") @ApiOperation( - value = "Gets all reporting tasks", - response = ReportingTasksEntity.class, + value = "Creates a new controller service", + response = ControllerServiceEntity.class, authorizations = { - @Authorization(value = "Read Only", type = "ROLE_MONITOR"), - @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"), - @Authorization(value = "Administrator", type = "ROLE_ADMIN") + @Authorization(value = "Data Flow Manager", type = "ROLE_DFM") } ) @ApiResponses( @@ -549,28 +559,50 @@ public class ControllerResource extends ApplicationResource { @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 getReportingTasks( + public Response createControllerService( + @Context final HttpServletRequest httpServletRequest, @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) ClientIdParameter clientId) { + value = "The controller service configuration details.", + required = true + ) final ControllerServiceEntity controllerServiceEntity) { - // replicate if cluster manager - if (properties.isClusterManager()) { - return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse(); + if (controllerServiceEntity == null || controllerServiceEntity.getComponent() == null) { + throw new IllegalArgumentException("Controller service details must be specified."); } - // get all the reporting tasks - final Set reportingTasks = serviceFacade.getReportingTasks(); - reportingTaskResource.populateRemainingReportingTaskEntitiesContent(reportingTasks); + if (controllerServiceEntity.getComponent().getId() != null) { + throw new IllegalArgumentException("Controller service ID cannot be specified."); + } - // create the response entity - final ReportingTasksEntity entity = new ReportingTasksEntity(); - entity.setReportingTasks(reportingTasks); + if (StringUtils.isBlank(controllerServiceEntity.getComponent().getType())) { + throw new IllegalArgumentException("The type of controller service to create must be specified."); + } - // generate the response - return clusterContext(generateOkResponse(entity)).build(); + if (properties.isClusterManager()) { + return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), controllerServiceEntity, getHeaders()).getResponse(); + } + + // handle expects request (usually from the cluster manager) + final boolean validationPhase = isValidationPhase(httpServletRequest); + if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) { + // authorize access + serviceFacade.authorizeAccess(lookup -> { + // TODO - authorize controller access + }); + } + if (validationPhase) { + return generateContinueResponse().build(); + } + + // set the processor id as appropriate + controllerServiceEntity.getComponent().setId(generateUuid()); + + // create the controller service and generate the json + final ControllerServiceEntity entity = serviceFacade.createControllerService(null, controllerServiceEntity.getComponent()); + controllerServiceResource.populateRemainingControllerServiceContent(entity.getComponent()); + + // build the response + return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build(); } // setters @@ -586,8 +618,15 @@ public class ControllerResource extends ApplicationResource { this.reportingTaskResource = reportingTaskResource; } + public void setControllerServiceResource(ControllerServiceResource controllerServiceResource) { + this.controllerServiceResource = controllerServiceResource; + } + public void setProperties(NiFiProperties properties) { this.properties = properties; } + public void setAuthorizer(Authorizer authorizer) { + this.authorizer = authorizer; + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java index e02dac5b0f..a181a848b0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java @@ -48,7 +48,6 @@ import org.apache.nifi.web.api.dto.AboutDTO; import org.apache.nifi.web.api.dto.BannerDTO; import org.apache.nifi.web.api.dto.BulletinBoardDTO; import org.apache.nifi.web.api.dto.BulletinQueryDTO; -import org.apache.nifi.web.api.dto.ControllerConfigurationDTO; import org.apache.nifi.web.api.dto.ProcessGroupDTO; import org.apache.nifi.web.api.dto.RevisionDTO; import org.apache.nifi.web.api.dto.flow.FlowDTO; @@ -81,7 +80,9 @@ import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity; import org.apache.nifi.web.api.entity.ProcessorStatusEntity; import org.apache.nifi.web.api.entity.ProcessorTypesEntity; import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusEntity; +import org.apache.nifi.web.api.entity.ReportingTaskEntity; import org.apache.nifi.web.api.entity.ReportingTaskTypesEntity; +import org.apache.nifi.web.api.entity.ReportingTasksEntity; import org.apache.nifi.web.api.entity.ScheduleComponentsEntity; import org.apache.nifi.web.api.entity.SearchResultsEntity; import org.apache.nifi.web.api.entity.StatusHistoryEntity; @@ -141,6 +142,7 @@ public class FlowResource extends ApplicationResource { private TemplateResource templateResource; private ProcessGroupResource processGroupResource; private ControllerServiceResource controllerServiceResource; + private ReportingTaskResource reportingTaskResource; /** * Populates the remaining fields in the specified process group. @@ -186,6 +188,9 @@ public class FlowResource extends ApplicationResource { return flowStructure; } + /** + * Authorizes access to the flow. + */ private void authorizeFlow() { final NiFiUser user = NiFiUserUtils.getNiFiUser(); @@ -269,6 +274,56 @@ public class FlowResource extends ApplicationResource { return clusterContext(generateOkResponse(entity)).build(); } + // ------------------- + // controller services + // ------------------- + + /** + * Retrieves all the of controller services in this NiFi. + * + * @return A controllerServicesEntity. + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("controller/controller-services") + // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')") + @ApiOperation( + value = "Gets all controller services", + response = ControllerServicesEntity.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 = 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 getControllerServicesFromController() { + + // replicate if cluster manager + if (properties.isClusterManager()) { + return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse(); + } + + // get all the controller services + final Set controllerServices = serviceFacade.getControllerServices(null); + controllerServiceResource.populateRemainingControllerServiceEntitiesContent(controllerServices); + + // create the response entity + final ControllerServicesEntity entity = new ControllerServicesEntity(); + entity.setControllerServices(controllerServices); + + // generate the response + return clusterContext(generateOkResponse(entity)).build(); + } + /** * Retrieves all the of controller services in this NiFi. * @@ -296,7 +351,7 @@ public class FlowResource extends ApplicationResource { @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 getControllerServices( + public Response getControllerServicesFromGroup( @ApiParam( value = "The process group id.", required = true @@ -320,6 +375,64 @@ public class FlowResource extends ApplicationResource { return clusterContext(generateOkResponse(entity)).build(); } + // --------------- + // reporting-tasks + // --------------- + + /** + * Retrieves all the of reporting tasks in this NiFi. + * + * @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. + * @return A reportingTasksEntity. + */ + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("reporting-tasks") + // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')") + @ApiOperation( + value = "Gets all reporting tasks", + response = ReportingTasksEntity.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 = 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 getReportingTasks( + @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) ClientIdParameter clientId) { + + // replicate if cluster manager + if (properties.isClusterManager()) { + return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse(); + } + + // get all the reporting tasks + final Set reportingTasks = serviceFacade.getReportingTasks(); + reportingTaskResource.populateRemainingReportingTaskEntitiesContent(reportingTasks); + + // create the response entity + final ReportingTasksEntity entity = new ReportingTasksEntity(); + entity.setReportingTasks(reportingTasks); + + // generate the response + return clusterContext(generateOkResponse(entity)).build(); + } + /** * Updates the specified process group. * @@ -358,8 +471,6 @@ public class FlowResource extends ApplicationResource { @PathParam("id") String id, ScheduleComponentsEntity scheduleComponentsEntity) { - authorizeFlow(); - // ensure the same id is being used if (!id.equals(scheduleComponentsEntity.getId())) { throw new IllegalArgumentException(String.format("The process group id (%s) in the request body does " @@ -441,6 +552,9 @@ public class FlowResource extends ApplicationResource { serviceFacade, revisions, lookup -> { + // ensure access to the flow + authorizeFlow(); + // ensure access to every component being scheduled componentsToSchedule.keySet().forEach(componentId -> { final Authorizable connectable = lookup.getConnectable(componentId); @@ -875,11 +989,9 @@ public class FlowResource extends ApplicationResource { return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse(); } - final ControllerConfigurationDTO controllerConfig = serviceFacade.getControllerConfiguration(); - // create the about dto final AboutDTO aboutDTO = new AboutDTO(); - aboutDTO.setTitle(controllerConfig.getName()); + aboutDTO.setTitle("NiFi"); // TODO - where to load title from aboutDTO.setVersion(properties.getUiTitle()); aboutDTO.setUri(generateResourceUri()); @@ -1853,6 +1965,10 @@ public class FlowResource extends ApplicationResource { this.controllerServiceResource = controllerServiceResource; } + public void setReportingTaskResource(ReportingTaskResource reportingTaskResource) { + this.reportingTaskResource = reportingTaskResource; + } + public void setAuthorizer(Authorizer authorizer) { this.authorizer = authorizer; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java index 8c8b12143a..4e15e3b801 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java @@ -134,6 +134,7 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusSnapshotDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO; import org.apache.nifi.web.api.entity.FlowBreadcrumbEntity; +import org.apache.nifi.web.controller.ControllerFacade; import org.apache.nifi.web.revision.RevisionManager; import javax.ws.rs.WebApplicationException; @@ -154,6 +155,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.TimeZone; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.TimeUnit; @@ -174,6 +176,22 @@ public final class DtoFactory { private EntityFactory entityFactory; private Authorizer authorizer; + public ControllerConfigurationDTO createControllerConfigurationDto(final ControllerFacade controllerFacade, final String autoRefreshInterval) { + final ControllerConfigurationDTO dto = new ControllerConfigurationDTO(); + dto.setMaxTimerDrivenThreadCount(controllerFacade.getMaxTimerDrivenThreadCount()); + dto.setMaxEventDrivenThreadCount(controllerFacade.getMaxEventDrivenThreadCount()); + + // get the refresh interval + final long refreshInterval = FormatUtils.getTimeDuration(autoRefreshInterval, TimeUnit.SECONDS); + dto.setAutoRefreshIntervalSeconds(refreshInterval); + + final Date now = new Date(); + dto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime())); + dto.setCurrentTime(now); + + return dto; + } + /** * Creates an ActionDTO for the specified Action. * @@ -1143,6 +1161,7 @@ public final class DtoFactory { public ControllerServiceDTO createControllerServiceDto(final ControllerServiceNode controllerServiceNode) { final ControllerServiceDTO dto = new ControllerServiceDTO(); dto.setId(controllerServiceNode.getIdentifier()); + dto.setParentGroupId(controllerServiceNode.getProcessGroup() == null ? null : controllerServiceNode.getProcessGroup().getIdentifier()); dto.setName(controllerServiceNode.getName()); dto.setType(controllerServiceNode.getControllerServiceImplementation().getClass().getName()); dto.setState(controllerServiceNode.getState().name()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java index 70155a65f7..667730111e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java @@ -24,6 +24,7 @@ import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO; import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO; import org.apache.nifi.web.api.entity.ConnectionEntity; +import org.apache.nifi.web.api.entity.ControllerConfigurationEntity; import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; import org.apache.nifi.web.api.entity.FlowBreadcrumbEntity; @@ -40,6 +41,19 @@ import org.apache.nifi.web.api.entity.SnippetEntity; public final class EntityFactory { + public ControllerConfigurationEntity createControllerConfigurationEntity(final ControllerConfigurationDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) { + final ControllerConfigurationEntity entity = new ControllerConfigurationEntity(); + entity.setRevision(revision); + if (dto != null) { + entity.setAccessPolicy(accessPolicy); + // TODO - remove this once contents of ControllerConfigurationEntity is updated +// if (accessPolicy != null && accessPolicy.getCanRead()) { + entity.setConfig(dto); +// } + } + return entity; + } + public ProcessGroupFlowEntity createProcessGroupFlowEntity(final ProcessGroupFlowDTO dto, final AccessPolicyDTO accessPolicy) { final ProcessGroupFlowEntity entity = new ProcessGroupFlowEntity(); entity.setProcessGroupFlow(dto); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml index 99dfe6fcb7..aceb693188 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml @@ -177,6 +177,7 @@ + @@ -190,6 +191,8 @@ + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java index 12693b26c7..7f61e0ed9e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java @@ -184,7 +184,6 @@ public class AdminAccessControlTest { ControllerConfigurationEntity entity = response.getEntity(ControllerConfigurationEntity.class); Assert.assertNotNull(entity); Assert.assertNotNull(entity.getConfig()); - Assert.assertEquals("NiFi Flow", entity.getConfig().getName()); Assert.assertEquals(10, entity.getConfig().getMaxTimerDrivenThreadCount().intValue()); Assert.assertEquals(5, entity.getConfig().getMaxEventDrivenThreadCount().intValue()); Assert.assertEquals(30, entity.getConfig().getAutoRefreshIntervalSeconds().intValue()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java index 83033f11c8..769c9965ce 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java @@ -207,7 +207,6 @@ public class DfmAccessControlTest { // create the controller configuration ControllerConfigurationDTO controllerConfig = new ControllerConfigurationDTO(); - controllerConfig.setName("new name"); // create the revision final RevisionDTO revision = new RevisionDTO(); @@ -229,7 +228,6 @@ public class DfmAccessControlTest { entity = response.getEntity(ControllerConfigurationEntity.class); Assert.assertNotNull(entity); Assert.assertNotNull(entity.getConfig()); - Assert.assertEquals("new name", entity.getConfig().getName()); Assert.assertEquals(10, entity.getConfig().getMaxTimerDrivenThreadCount().intValue()); Assert.assertEquals(5, entity.getConfig().getMaxEventDrivenThreadCount().intValue()); Assert.assertEquals(30, entity.getConfig().getAutoRefreshIntervalSeconds().intValue()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java index 98a8cd05d2..d7e6a7abff 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java @@ -180,7 +180,6 @@ public class ReadOnlyAccessControlTest { ControllerConfigurationEntity entity = response.getEntity(ControllerConfigurationEntity.class); Assert.assertNotNull(entity); Assert.assertNotNull(entity.getConfig()); - Assert.assertEquals("NiFi Flow", entity.getConfig().getName()); Assert.assertEquals(10, entity.getConfig().getMaxTimerDrivenThreadCount().intValue()); Assert.assertEquals(5, entity.getConfig().getMaxEventDrivenThreadCount().intValue()); Assert.assertEquals(30, entity.getConfig().getAutoRefreshIntervalSeconds().intValue()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml index a2c4daafe3..9337b12383 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml @@ -339,6 +339,7 @@ ${staging.dir}/js/nf/canvas/nf-queue-listing.js ${staging.dir}/js/nf/canvas/nf-component-state.js ${staging.dir}/js/nf/canvas/nf-controller-service.js + ${staging.dir}/js/nf/canvas/nf-controller-services.js ${staging.dir}/js/nf/canvas/nf-reporting-task.js ${staging.dir}/js/nf/canvas/nf-processor-configuration.js ${staging.dir}/js/nf/nf-processor-details.js diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties index cd58d9fc83..fc1f2c92b1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties @@ -27,6 +27,7 @@ nf.canvas.script.tags=\n\ \n\ \n\ +\n\ \n\ \n\ \n\ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp index 23a514a18b..c74a94532f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/navigation.jsp @@ -83,6 +83,12 @@