[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user asfgit closed the pull request at: https://github.com/apache/nifi/pull/2990 ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r218682791 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java --- @@ -1060,7 +1069,8 @@ public ProcessGroupStatusDTO createProcessGroupStatusDto(final ProcessGroup proc final Collection childRemoteProcessGroupStatusCollection = processGroupStatus.getRemoteProcessGroupStatus(); if (childRemoteProcessGroupStatusCollection != null) { for (final RemoteProcessGroupStatus childRemoteProcessGroupStatus : childRemoteProcessGroupStatusCollection) { -final RemoteProcessGroupStatusDTO childRemoteProcessGroupStatusDto = createRemoteProcessGroupStatusDto(childRemoteProcessGroupStatus); +final RemoteProcessGroup childRemoteProcessGroup = processGroup.getRemoteProcessGroup(childRemoteProcessGroupStatus.getId()); --- End diff -- Thanks for catching this. FIxed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r218531396 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java --- @@ -1060,7 +1069,8 @@ public ProcessGroupStatusDTO createProcessGroupStatusDto(final ProcessGroup proc final Collection childRemoteProcessGroupStatusCollection = processGroupStatus.getRemoteProcessGroupStatus(); if (childRemoteProcessGroupStatusCollection != null) { for (final RemoteProcessGroupStatus childRemoteProcessGroupStatus : childRemoteProcessGroupStatusCollection) { -final RemoteProcessGroupStatusDTO childRemoteProcessGroupStatusDto = createRemoteProcessGroupStatusDto(childRemoteProcessGroupStatus); +final RemoteProcessGroup childRemoteProcessGroup = processGroup.getRemoteProcessGroup(childRemoteProcessGroupStatus.getId()); --- End diff -- The way this method is called recursively the `childRemoteProcessGroup` is not necessarily a child of `processGroup`. This can be seen by creating a `RemoteProcessGroup` in a nested `ProcessGroup`. Then open the Summary table. You'll see an NPE. I think the fix is pretty trivial. We are actually already getting the `remoteProcessGroup` one line below using the recursive `findXxx` method. Moving this line up and using identifier from the status and not the DTO should address the problem. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r218272926 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js --- @@ -1045,29 +1041,38 @@ var reportingTaskActionFormatter = function (row, cell, value, columnDef, dataContext) { var markup = ''; -if (dataContext.permissions.canRead && dataContext.permissions.canWrite) { -if (dataContext.component.state === 'RUNNING') { +var canWrite = dataContext.permissions.canWrite; +var canRead = dataContext.permissions.canRead; +var canOperate = dataContext.operatePermissions.canWrite || canWrite; +var isStopped = dataContext.status.runStatus === 'STOPPED'; + +if (dataContext.status.runStatus === 'RUNNING') { +if (canOperate) { markup += ''; -} else if (dataContext.component.state === 'STOPPED' || dataContext.component.state === 'DISABLED') { -markup += ''; +} -// support starting when stopped and no validation errors -if (dataContext.component.state === 'STOPPED' && nfCommon.isEmpty(dataContext.component.validationErrors)) { -markup += ''; -} +} else if (isStopped || dataContext.status.runStatus === 'DISABLED') { -if (dataContext.component.multipleVersionsAvailable === true) { -markup += ''; -} +if (canRead && canWrite) { +markup += ''; +} -if (nfCommon.canModifyController()) { -markup += ''; -} +// support starting when stopped and no validation errors +if (canOperate && dataContext.status.runStatus === 'STOPPED' && dataContext.status.validationStatus === 'VALID') { +markup += ''; } -if (dataContext.component.persistsState === true) { -markup += ''; +if (canRead && canWrite && dataContext.component.multipleVersionsAvailable === true) { +markup += ''; } + +if (nfCommon.canModifyController()) { --- End diff -- Thanks @mcgilman , you are right. I accidentally removed the conditions to check if reporting tasks and controller services can be read and write for delete icon. Thanks for catching this. Updated. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217816900 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js --- @@ -1045,29 +1041,38 @@ var reportingTaskActionFormatter = function (row, cell, value, columnDef, dataContext) { var markup = ''; -if (dataContext.permissions.canRead && dataContext.permissions.canWrite) { -if (dataContext.component.state === 'RUNNING') { +var canWrite = dataContext.permissions.canWrite; +var canRead = dataContext.permissions.canRead; +var canOperate = dataContext.operatePermissions.canWrite || canWrite; +var isStopped = dataContext.status.runStatus === 'STOPPED'; + +if (dataContext.status.runStatus === 'RUNNING') { +if (canOperate) { markup += ''; -} else if (dataContext.component.state === 'STOPPED' || dataContext.component.state === 'DISABLED') { -markup += ''; +} -// support starting when stopped and no validation errors -if (dataContext.component.state === 'STOPPED' && nfCommon.isEmpty(dataContext.component.validationErrors)) { -markup += ''; -} +} else if (isStopped || dataContext.status.runStatus === 'DISABLED') { -if (dataContext.component.multipleVersionsAvailable === true) { -markup += ''; -} +if (canRead && canWrite) { +markup += ''; +} -if (nfCommon.canModifyController()) { -markup += ''; -} +// support starting when stopped and no validation errors +if (canOperate && dataContext.status.runStatus === 'STOPPED' && dataContext.status.validationStatus === 'VALID') { +markup += ''; } -if (dataContext.component.persistsState === true) { -markup += ''; +if (canRead && canWrite && dataContext.component.multipleVersionsAvailable === true) { +markup += ''; } + +if (nfCommon.canModifyController()) { --- End diff -- Ah, I see what's changed. I was a little confused. The issue is that component removal requires permissions to `WRITE` both the component in question and it's parent. With the changes introduced here, we are no longer including `canWrite` when determining the visibility of the delete icons. When I was reviewing, I was seeing the delete icon when I shouldn't have been. I only had read and operate permissions to the component but the UI was presenting the delete icon (because I still had write permissions to the parent). However, when I attempted to actually delete it NiFi correctly told me I wasn't allowed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217605699 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js --- @@ -1045,29 +1041,38 @@ var reportingTaskActionFormatter = function (row, cell, value, columnDef, dataContext) { var markup = ''; -if (dataContext.permissions.canRead && dataContext.permissions.canWrite) { -if (dataContext.component.state === 'RUNNING') { +var canWrite = dataContext.permissions.canWrite; +var canRead = dataContext.permissions.canRead; +var canOperate = dataContext.operatePermissions.canWrite || canWrite; +var isStopped = dataContext.status.runStatus === 'STOPPED'; + +if (dataContext.status.runStatus === 'RUNNING') { +if (canOperate) { markup += ''; -} else if (dataContext.component.state === 'STOPPED' || dataContext.component.state === 'DISABLED') { -markup += ''; +} -// support starting when stopped and no validation errors -if (dataContext.component.state === 'STOPPED' && nfCommon.isEmpty(dataContext.component.validationErrors)) { -markup += ''; -} +} else if (isStopped || dataContext.status.runStatus === 'DISABLED') { -if (dataContext.component.multipleVersionsAvailable === true) { -markup += ''; -} +if (canRead && canWrite) { +markup += ''; +} -if (nfCommon.canModifyController()) { -markup += ''; -} +// support starting when stopped and no validation errors +if (canOperate && dataContext.status.runStatus === 'STOPPED' && dataContext.status.validationStatus === 'VALID') { +markup += ''; } -if (dataContext.component.persistsState === true) { -markup += ''; +if (canRead && canWrite && dataContext.component.multipleVersionsAvailable === true) { +markup += ''; } + +if (nfCommon.canModifyController()) { --- End diff -- Is that so? I didn't change the code since I don't fully agree with the suggestion. > The controller permission will have already been considered when determining a value for canWrite server-side since it should be the parent resource for every reporting task. If the reporting task doesn't have its own policy setting, the above assumption would be true. However, if a policy for the reporting task is defined, the parent controller permission will not be taken into account the `canWrite`. The user can have WRITE to a reporting task without having WRITE to the controller. In that case, we still need to check controller's permission. Also, I can see the similar restriction at nf-controller-services.js at line 962, checking only parent WRITE permission: ``` if (isDisabled && canWriteControllerServiceParent(dataContext)) { markup += ''; } ``` Current conditions are consistent at both controller services and reporting tasks. I think it is not an issue. How do you think? ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217604473 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js --- @@ -741,8 +740,8 @@ }) .attr('font-family', function (d) { var family = ''; -if (d.permissions.canRead) { -if (hasIssues(d) || d.component.transmitting) { +if (d.permissions.canRead || d.operatePermissions.canWrite) { --- End diff -- That's true. I've removed permission checks for status icon. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217598519 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, createPortDTOWithDesiredRunStatus(portId, id, requestRemotePortRunStatusEntity)), +(revision, remotePortRunStatusEntity) -> { +// update the specified remote process group +final RemoteProcessGroupPortEntity controllerResponse = serviceFacade.updateRemoteProcessGroupInputPort(revision, id, +createPortDTOWithDesiredRunStatus(portId, id, remotePortRunStatusEntity)); + +// get the
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217598491 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); --- End diff -- Thank you very much for finding this! Fixed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217598443 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java --- @@ -0,0 +1,85 @@ +/* + * 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.authorization.resource; + +import org.apache.nifi.authorization.AccessDeniedException; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.RequestAction; +import org.apache.nifi.authorization.Resource; +import org.apache.nifi.authorization.user.NiFiUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Authorizable for a component that can be scheduled by operators. + */ +public class OperationAuthorizable implements Authorizable, EnforcePolicyPermissionsThroughBaseResource { +private static Logger logger = LoggerFactory.getLogger(OperationAuthorizable.class); +private final Authorizable baseAuthorizable; + +public OperationAuthorizable(final Authorizable baseAuthorizable) { +this.baseAuthorizable = baseAuthorizable; +} + +@Override +public Authorizable getParentAuthorizable() { +// Need to return parent operation authorizable. E.g. /operation/processor/ -> /operation/process-group/ -> /run-status/process-group/root +if (baseAuthorizable.getParentAuthorizable() == null) { +return null; +} else { +return new OperationAuthorizable(baseAuthorizable.getParentAuthorizable()); +} +} + +@Override +public Authorizable getBaseAuthorizable() { +return baseAuthorizable; +} + +@Override +public Resource getResource() { +return ResourceFactory.getOperationResource(baseAuthorizable.getResource()); +} + +/** + * Authorize the request action with the resource using base authorizable and operation authorizable combination. + * + * This method authorizes the request with the base authorizable first. If the request is allowed, then finish authorization. + * If base authorizable denies the request, then it checks if the user has WRITE permission for '/operation/{componentType}/{id}'. + */ +public static void authorize(final Authorizable baseAuthorizable, final Authorizer authorizer, final RequestAction requestAction, final NiFiUser user) { +try { +baseAuthorizable.authorize(authorizer, requestAction, user); +} catch (AccessDeniedException e) { +logger.debug("Authorization failed with {}. Try authorizing with OperationAuthorizable.", baseAuthorizable, e); +// Always use WRITE action for operation. +new OperationAuthorizable(baseAuthorizable).authorize(authorizer, RequestAction.WRITE, user); +} + +} + +/** + * Check if the request is authorized. + * + * @return True if the request is allowed by the base authorizable, or the user has WRITE permission for '/operation/{componentType}/id'. + */ +public static boolean isAuthorized(final Authorizable baseAuthorizable, final Authorizer authorizer, final RequestAction requestAction, final NiFiUser user) { --- End diff -- Renamed this one, too. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217598426 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java --- @@ -0,0 +1,85 @@ +/* + * 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.authorization.resource; + +import org.apache.nifi.authorization.AccessDeniedException; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.RequestAction; +import org.apache.nifi.authorization.Resource; +import org.apache.nifi.authorization.user.NiFiUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Authorizable for a component that can be scheduled by operators. + */ +public class OperationAuthorizable implements Authorizable, EnforcePolicyPermissionsThroughBaseResource { +private static Logger logger = LoggerFactory.getLogger(OperationAuthorizable.class); +private final Authorizable baseAuthorizable; + +public OperationAuthorizable(final Authorizable baseAuthorizable) { +this.baseAuthorizable = baseAuthorizable; +} + +@Override +public Authorizable getParentAuthorizable() { +// Need to return parent operation authorizable. E.g. /operation/processor/ -> /operation/process-group/ -> /run-status/process-group/root +if (baseAuthorizable.getParentAuthorizable() == null) { +return null; +} else { +return new OperationAuthorizable(baseAuthorizable.getParentAuthorizable()); +} +} + +@Override +public Authorizable getBaseAuthorizable() { +return baseAuthorizable; +} + +@Override +public Resource getResource() { +return ResourceFactory.getOperationResource(baseAuthorizable.getResource()); +} + +/** + * Authorize the request action with the resource using base authorizable and operation authorizable combination. + * + * This method authorizes the request with the base authorizable first. If the request is allowed, then finish authorization. + * If base authorizable denies the request, then it checks if the user has WRITE permission for '/operation/{componentType}/{id}'. + */ +public static void authorize(final Authorizable baseAuthorizable, final Authorizer authorizer, final RequestAction requestAction, final NiFiUser user) { --- End diff -- I agree, that's a good idea. I renamed it. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217390883 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java --- @@ -0,0 +1,85 @@ +/* + * 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.authorization.resource; + +import org.apache.nifi.authorization.AccessDeniedException; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.RequestAction; +import org.apache.nifi.authorization.Resource; +import org.apache.nifi.authorization.user.NiFiUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Authorizable for a component that can be scheduled by operators. + */ +public class OperationAuthorizable implements Authorizable, EnforcePolicyPermissionsThroughBaseResource { +private static Logger logger = LoggerFactory.getLogger(OperationAuthorizable.class); +private final Authorizable baseAuthorizable; + +public OperationAuthorizable(final Authorizable baseAuthorizable) { +this.baseAuthorizable = baseAuthorizable; +} + +@Override +public Authorizable getParentAuthorizable() { +// Need to return parent operation authorizable. E.g. /operation/processor/ -> /operation/process-group/ -> /run-status/process-group/root +if (baseAuthorizable.getParentAuthorizable() == null) { +return null; +} else { +return new OperationAuthorizable(baseAuthorizable.getParentAuthorizable()); +} +} + +@Override +public Authorizable getBaseAuthorizable() { +return baseAuthorizable; +} + +@Override +public Resource getResource() { +return ResourceFactory.getOperationResource(baseAuthorizable.getResource()); +} + +/** + * Authorize the request action with the resource using base authorizable and operation authorizable combination. + * + * This method authorizes the request with the base authorizable first. If the request is allowed, then finish authorization. + * If base authorizable denies the request, then it checks if the user has WRITE permission for '/operation/{componentType}/{id}'. + */ +public static void authorize(final Authorizable baseAuthorizable, final Authorizer authorizer, final RequestAction requestAction, final NiFiUser user) { +try { +baseAuthorizable.authorize(authorizer, requestAction, user); +} catch (AccessDeniedException e) { +logger.debug("Authorization failed with {}. Try authorizing with OperationAuthorizable.", baseAuthorizable, e); +// Always use WRITE action for operation. +new OperationAuthorizable(baseAuthorizable).authorize(authorizer, RequestAction.WRITE, user); +} + +} + +/** + * Check if the request is authorized. + * + * @return True if the request is allowed by the base authorizable, or the user has WRITE permission for '/operation/{componentType}/id'. + */ +public static boolean isAuthorized(final Authorizable baseAuthorizable, final Authorizer authorizer, final RequestAction requestAction, final NiFiUser user) { --- End diff -- There is no time when someone should invoke this method with a `requestAction` of `WRITE`. Can we remove that parameter? Also, because of this and that the name is the same as the non-static version (which has admittedly confused me a number of times while reviewing) can we rename this method to more accurately depict its intention. Maybe something along the lines of `isOperationAuthorized`. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217390667 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/OperationAuthorizable.java --- @@ -0,0 +1,85 @@ +/* + * 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.authorization.resource; + +import org.apache.nifi.authorization.AccessDeniedException; +import org.apache.nifi.authorization.Authorizer; +import org.apache.nifi.authorization.RequestAction; +import org.apache.nifi.authorization.Resource; +import org.apache.nifi.authorization.user.NiFiUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Authorizable for a component that can be scheduled by operators. + */ +public class OperationAuthorizable implements Authorizable, EnforcePolicyPermissionsThroughBaseResource { +private static Logger logger = LoggerFactory.getLogger(OperationAuthorizable.class); +private final Authorizable baseAuthorizable; + +public OperationAuthorizable(final Authorizable baseAuthorizable) { +this.baseAuthorizable = baseAuthorizable; +} + +@Override +public Authorizable getParentAuthorizable() { +// Need to return parent operation authorizable. E.g. /operation/processor/ -> /operation/process-group/ -> /run-status/process-group/root +if (baseAuthorizable.getParentAuthorizable() == null) { +return null; +} else { +return new OperationAuthorizable(baseAuthorizable.getParentAuthorizable()); +} +} + +@Override +public Authorizable getBaseAuthorizable() { +return baseAuthorizable; +} + +@Override +public Resource getResource() { +return ResourceFactory.getOperationResource(baseAuthorizable.getResource()); +} + +/** + * Authorize the request action with the resource using base authorizable and operation authorizable combination. + * + * This method authorizes the request with the base authorizable first. If the request is allowed, then finish authorization. + * If base authorizable denies the request, then it checks if the user has WRITE permission for '/operation/{componentType}/{id}'. + */ +public static void authorize(final Authorizable baseAuthorizable, final Authorizer authorizer, final RequestAction requestAction, final NiFiUser user) { --- End diff -- There is no time when someone should invoke this method with a `requestAction` of `WRITE`. Can we remove that parameter? Also, because of this and that the name is the same as the non-static version (which has admittedly confused me a number of times while reviewing) can we rename this method to more accurately depict its intention. Maybe something along the lines of `authorizeOperation`. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217387530 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); --- End diff -- This should be calling `authorize` and not checking `isAuthorized`. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217415480 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-settings.js --- @@ -1045,29 +1041,38 @@ var reportingTaskActionFormatter = function (row, cell, value, columnDef, dataContext) { var markup = ''; -if (dataContext.permissions.canRead && dataContext.permissions.canWrite) { -if (dataContext.component.state === 'RUNNING') { +var canWrite = dataContext.permissions.canWrite; +var canRead = dataContext.permissions.canRead; +var canOperate = dataContext.operatePermissions.canWrite || canWrite; +var isStopped = dataContext.status.runStatus === 'STOPPED'; + +if (dataContext.status.runStatus === 'RUNNING') { +if (canOperate) { markup += ''; -} else if (dataContext.component.state === 'STOPPED' || dataContext.component.state === 'DISABLED') { -markup += ''; +} -// support starting when stopped and no validation errors -if (dataContext.component.state === 'STOPPED' && nfCommon.isEmpty(dataContext.component.validationErrors)) { -markup += ''; -} +} else if (isStopped || dataContext.status.runStatus === 'DISABLED') { -if (dataContext.component.multipleVersionsAvailable === true) { -markup += ''; -} +if (canRead && canWrite) { +markup += ''; +} -if (nfCommon.canModifyController()) { -markup += ''; -} +// support starting when stopped and no validation errors +if (canOperate && dataContext.status.runStatus === 'STOPPED' && dataContext.status.validationStatus === 'VALID') { +markup += ''; } -if (dataContext.component.persistsState === true) { -markup += ''; +if (canRead && canWrite && dataContext.component.multipleVersionsAvailable === true) { +markup += ''; } + +if (nfCommon.canModifyController()) { --- End diff -- I realize this isn't an issue with this PR but I believe this should be checking `canWrite` and not deferring to check the controller permission. The controller permission will have already been considered when determining a value for `canWrite` server-side since it should be the parent resource for every reporting task. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217401802 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js --- @@ -741,8 +740,8 @@ }) .attr('font-family', function (d) { var family = ''; -if (d.permissions.canRead) { -if (hasIssues(d) || d.component.transmitting) { +if (d.permissions.canRead || d.operatePermissions.canWrite) { --- End diff -- These checks (here and below) also need to consider if the user has `d.permission.canWrite`. If the user only has operate permissions they can see the status. But if the user does not have operate but does have write to the RPG they currently cannot see the status icon. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217387691 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, createPortDTOWithDesiredRunStatus(portId, id, requestRemotePortRunStatusEntity)), +(revision, remotePortRunStatusEntity) -> { +// update the specified remote process group +final RemoteProcessGroupPortEntity controllerResponse = serviceFacade.updateRemoteProcessGroupInputPort(revision, id, +createPortDTOWithDesiredRunStatus(portId, id, remotePortRunStatusEntity)); + +// get the
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217405219 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js --- @@ -741,8 +740,8 @@ }) .attr('font-family', function (d) { var family = ''; -if (d.permissions.canRead) { -if (hasIssues(d) || d.component.transmitting) { +if (d.permissions.canRead || d.operatePermissions.canWrite) { --- End diff -- Actually, for determining which icon we show and the appropriate style it appears that we are now only using the status. This is available to everyone so I don't think we need any permission checks here. We should only need them when adding the tooltips. This should be very similar to the Processor Invalid icon and the tooltips for the validation errors. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269769 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java --- @@ -542,6 +547,88 @@ public Response removeReportingTask( ); } +/** + * Updates the operational status for the specified ReportingTask with the specified values. + * + * @param httpServletRequest request + * @param id The id of the reporting task to update. + * @param requestRunStatus A runStatusEntity. + * @return A reportingTaskEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/run-status") +@ApiOperation( +value = "Updates run status of a reporting task", +response = ReportingTaskEntity.class, +authorizations = { +@Authorization(value = "Write - /reporting-tasks/{uuid} or or /operation/reporting-tasks/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The reporting task id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The reporting task run status.", +required = true +) final ReportingTaskRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Reporting task run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create DTO to verify if it can be updated. +final ReportingTaskDTO reportingTaskDTO = new ReportingTaskDTO(); +reportingTaskDTO.setId(id); +reportingTaskDTO.setState(requestRunStatus.getState()); +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +// authorize reporting task +final Authorizable authorizable = lookup.getReportingTask(id).getAuthorizable(); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateReportingTask(reportingTaskDTO), +(revision, reportingTaskEntity) -> { +// update the reporting task +final ReportingTaskEntity entity = serviceFacade.updateReportingTask(revision, reportingTaskDTO); --- End diff -- Fixed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269816 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java --- @@ -68,10 +75,13 @@ default void merge(final EntityType clientEntity, final Map MAX_BULLETINS_PER_COMPONENT) { clientEntity.setBulletins(clientEntity.getBulletins().subList(0, MAX_BULLETINS_PER_COMPONENT)); } +} else { +clientEntity.setBulletins(null); --- End diff -- Fixed. Thanks for caching this! ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269718 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +final RemoteProcessGroupPortDTO remoteProcessGroupPort = new RemoteProcessGroupPortDTO(); +remoteProcessGroupPort.setId(portId); +remoteProcessGroupPort.setGroupId(id); + remoteProcessGroupPort.setTransmitting(shouldTransmit(requestRemotePortRunStatusEntity)); + +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, remoteProcessGroupPort), +(revision, remoteProcessGroupPortEntity) -> { +// update the specified remote process group +final
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269747 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -557,6 +750,90 @@ public Response updateRemoteProcessGroup( ); } +/** + * Updates the operational status for the specified remote process group with the specified value. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param requestRemotePortRunStatusEntity A remotePortRunStatusEntity. + * @return A remoteProcessGroupEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/run-status") +@ApiOperation( +value = "Updates run status of a remote process group", +response = RemoteProcessGroupEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupRunStatus( +@Context HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") String id, +@ApiParam( +value = "The remote process group run status.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +final RemoteProcessGroupDTO remoteProcessGroupDTO = new RemoteProcessGroupDTO(); +remoteProcessGroupDTO.setId(id); + remoteProcessGroupDTO.setTransmitting(shouldTransmit(requestRemotePortRunStatusEntity)); +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +Authorizable authorizable = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroup(remoteProcessGroupDTO), +(revision, remoteProcessGroupEntity) -> { +// update the specified remote process group +final RemoteProcessGroupEntity entity = serviceFacade.updateRemoteProcessGroup(revision, remoteProcessGroupDTO); --- End diff -- Fixed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269686 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +final RemoteProcessGroupPortDTO remoteProcessGroupPort = new RemoteProcessGroupPortDTO(); +remoteProcessGroupPort.setId(portId); +remoteProcessGroupPort.setGroupId(id); + remoteProcessGroupPort.setTransmitting(shouldTransmit(requestRemotePortRunStatusEntity)); + +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, remoteProcessGroupPort), +(revision, remoteProcessGroupPortEntity) -> { +// update the specified remote process group +final
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269622 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java --- @@ -315,6 +319,90 @@ public Response removeOutputPort( ); } + +/** + * Updates the operational status for the specified input port with the specified values. + * + * @param httpServletRequest request + * @param id The id of the port to update. + * @param requestRunStatusA portRunStatusEntity. + * @return A portEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/{id}/run-status") +@ApiOperation( +value = "Updates run status of an output-port", +response = ProcessorEntity.class, +authorizations = { +@Authorization(value = "Write - /output-ports/{uuid} or /operation/output-ports/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The port id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The port run status.", +required = true +) final PortRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Port run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create port DTO to verify if it can be updated. +final PortDTO portDTO = new PortDTO(); +portDTO.setId(id); +portDTO.setState(requestRunStatus.getState()); + +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +final NiFiUser user = NiFiUserUtils.getNiFiUser(); + +final Authorizable authorizable = lookup.getOutputPort(id); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, user); +}, +() -> serviceFacade.verifyUpdateOutputPort(portDTO), +(revision, runStatusEntity) -> { +// update the input port +final PortEntity entity = serviceFacade.updateOutputPort(revision, portDTO); --- End diff -- Fixed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269601 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java --- @@ -315,6 +319,90 @@ public Response removeInputPort( ); } +/** + * Updates the operational status for the specified input port with the specified values. + * + * @param httpServletRequest request + * @param id The id of the port to update. + * @param requestRunStatusA portRunStatusEntity. + * @return A portEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/{id}/run-status") +@ApiOperation( +value = "Updates run status of an input-port", +response = ProcessorEntity.class, +authorizations = { +@Authorization(value = "Write - /input-ports/{uuid} or /operation/input-ports/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The port id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The port run status.", +required = true +) final PortRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Port run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create port DTO to verify if it can be updated. +final PortDTO portDTO = new PortDTO(); +portDTO.setId(id); +portDTO.setState(requestRunStatus.getState()); + +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +final NiFiUser user = NiFiUserUtils.getNiFiUser(); + +final Authorizable authorizable = lookup.getInputPort(id); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, user); +}, +() -> serviceFacade.verifyUpdateInputPort(portDTO), +(revision, runStatusEntity) -> { +// update the input port +final PortEntity entity = serviceFacade.updateInputPort(revision, portDTO); --- End diff -- Fixed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269661 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java --- @@ -668,6 +670,91 @@ public Response deleteProcessor( ); } +/** + * Updates the operational status for the specified processor with the specified values. + * + * @param httpServletRequest request + * @param id The id of the processor to update. + * @param requestRunStatusA processorEntity. + * @return A processorEntity. + * @throws InterruptedException if interrupted + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/{id}/run-status") +@ApiOperation( +value = "Updates run status of a processor", +response = ProcessorEntity.class, +authorizations = { +@Authorization(value = "Write - /processors/{uuid} or /operation/processors/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The processor id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The processor run status.", +required = true +) final ProcessorRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Processor run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create processor DTO to verify if it can be updated. +final ProcessorDTO requestProcessorDTO = new ProcessorDTO(); +requestProcessorDTO.setId(id); +requestProcessorDTO.setState(requestRunStatus.getState()); + +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +final NiFiUser user = NiFiUserUtils.getNiFiUser(); + +final Authorizable authorizable = lookup.getProcessor(id).getAuthorizable(); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, user); +}, +() -> serviceFacade.verifyUpdateProcessor(requestProcessorDTO), +(revision, runStatusEntity) -> { +// update the processor +final ProcessorEntity entity = serviceFacade.updateProcessor(revision, requestProcessorDTO); --- End diff -- Fixed. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217269181 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java --- @@ -741,6 +743,88 @@ public Response removeControllerService( ); } +/** + * Updates the operational status for the specified controller service with the specified values. + * + * @param httpServletRequest request + * @param id The id of the controller service to update. + * @param requestRunStatusA runStatusEntity. + * @return A controllerServiceEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/run-status") +@ApiOperation( +value = "Updates run status of a controller service", +response = ControllerServiceEntity.class, +authorizations = { +@Authorization(value = "Write - /controller-services/{uuid} or /operation/controller-services/{uuid}") +} +) +@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 updateRunStatus( +@Context HttpServletRequest httpServletRequest, +@ApiParam( +value = "The controller service id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The controller service run status.", +required = true +) final ControllerServiceRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Controller service run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create DTO to verify if it can be updated. +final ControllerServiceDTO controllerServiceDTO = new ControllerServiceDTO(); +controllerServiceDTO.setId(id); +controllerServiceDTO.setState(requestRunStatus.getState()); +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +// authorize the service +final Authorizable authorizable = lookup.getControllerService(id).getAuthorizable(); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateControllerService(controllerServiceDTO), +(revision, runStatusEntity) -> { +// update the controller service +final ControllerServiceEntity entity = serviceFacade.updateControllerService(revision, controllerServiceDTO); --- End diff -- To be honest, I don't fully understand how much this is going to be critical as the DTO and entity only have the desired state and guid, those are not changing during the two phase commit. I think I'm missing some scenario here. But I've modified the code to create DTO at each function that is passed to the `withWriteLock` method. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user ijokarumawak commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217233852 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ControllerServiceEntityMerger.java --- @@ -137,7 +138,9 @@ public static void mergeControllerServiceReferences(final Set
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217134368 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java --- @@ -741,6 +743,88 @@ public Response removeControllerService( ); } +/** + * Updates the operational status for the specified controller service with the specified values. + * + * @param httpServletRequest request + * @param id The id of the controller service to update. + * @param requestRunStatusA runStatusEntity. + * @return A controllerServiceEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/run-status") +@ApiOperation( +value = "Updates run status of a controller service", +response = ControllerServiceEntity.class, +authorizations = { +@Authorization(value = "Write - /controller-services/{uuid} or /operation/controller-services/{uuid}") +} +) +@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 updateRunStatus( +@Context HttpServletRequest httpServletRequest, +@ApiParam( +value = "The controller service id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The controller service run status.", +required = true +) final ControllerServiceRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Controller service run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create DTO to verify if it can be updated. +final ControllerServiceDTO controllerServiceDTO = new ControllerServiceDTO(); +controllerServiceDTO.setId(id); +controllerServiceDTO.setState(requestRunStatus.getState()); +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +// authorize the service +final Authorizable authorizable = lookup.getControllerService(id).getAuthorizable(); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateControllerService(controllerServiceDTO), +(revision, runStatusEntity) -> { +// update the controller service +final ControllerServiceEntity entity = serviceFacade.updateControllerService(revision, controllerServiceDTO); --- End diff -- We need to recreate this `controllerServiceDTO` using the `runStatusEntity` due to how we authorize/cache requests during our two phase commit. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217134851 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java --- @@ -315,6 +319,90 @@ public Response removeOutputPort( ); } + +/** + * Updates the operational status for the specified input port with the specified values. + * + * @param httpServletRequest request + * @param id The id of the port to update. + * @param requestRunStatusA portRunStatusEntity. + * @return A portEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/{id}/run-status") +@ApiOperation( +value = "Updates run status of an output-port", +response = ProcessorEntity.class, +authorizations = { +@Authorization(value = "Write - /output-ports/{uuid} or /operation/output-ports/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The port id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The port run status.", +required = true +) final PortRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Port run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create port DTO to verify if it can be updated. +final PortDTO portDTO = new PortDTO(); +portDTO.setId(id); +portDTO.setState(requestRunStatus.getState()); + +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +final NiFiUser user = NiFiUserUtils.getNiFiUser(); + +final Authorizable authorizable = lookup.getOutputPort(id); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, user); +}, +() -> serviceFacade.verifyUpdateOutputPort(portDTO), +(revision, runStatusEntity) -> { +// update the input port +final PortEntity entity = serviceFacade.updateOutputPort(revision, portDTO); --- End diff -- We need to recreate this `portDTO` using the `runStatusEntity` due to how we authorize/cache requests during our two phase commit. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217135024 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java --- @@ -668,6 +670,91 @@ public Response deleteProcessor( ); } +/** + * Updates the operational status for the specified processor with the specified values. + * + * @param httpServletRequest request + * @param id The id of the processor to update. + * @param requestRunStatusA processorEntity. + * @return A processorEntity. + * @throws InterruptedException if interrupted + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/{id}/run-status") +@ApiOperation( +value = "Updates run status of a processor", +response = ProcessorEntity.class, +authorizations = { +@Authorization(value = "Write - /processors/{uuid} or /operation/processors/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The processor id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The processor run status.", +required = true +) final ProcessorRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Processor run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create processor DTO to verify if it can be updated. +final ProcessorDTO requestProcessorDTO = new ProcessorDTO(); +requestProcessorDTO.setId(id); +requestProcessorDTO.setState(requestRunStatus.getState()); + +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +final NiFiUser user = NiFiUserUtils.getNiFiUser(); + +final Authorizable authorizable = lookup.getProcessor(id).getAuthorizable(); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, user); +}, +() -> serviceFacade.verifyUpdateProcessor(requestProcessorDTO), +(revision, runStatusEntity) -> { +// update the processor +final ProcessorEntity entity = serviceFacade.updateProcessor(revision, requestProcessorDTO); --- End diff -- We need to recreate this `requestProcessorDTO` using the `runStatusEntity` due to how we authorize/cache requests during our two phase commit. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217140684 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ComponentEntityMerger.java --- @@ -68,10 +75,13 @@ default void merge(final EntityType clientEntity, final Map MAX_BULLETINS_PER_COMPONENT) { clientEntity.setBulletins(clientEntity.getBulletins().subList(0, MAX_BULLETINS_PER_COMPONENT)); } +} else { +clientEntity.setBulletins(null); --- End diff -- I think we need to continue to set the component to null when `canRead` is false. It may have been changed to accommodate an earlier iteration of this PR. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217134678 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java --- @@ -315,6 +319,90 @@ public Response removeInputPort( ); } +/** + * Updates the operational status for the specified input port with the specified values. + * + * @param httpServletRequest request + * @param id The id of the port to update. + * @param requestRunStatusA portRunStatusEntity. + * @return A portEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/{id}/run-status") +@ApiOperation( +value = "Updates run status of an input-port", +response = ProcessorEntity.class, +authorizations = { +@Authorization(value = "Write - /input-ports/{uuid} or /operation/input-ports/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The port id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The port run status.", +required = true +) final PortRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Port run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create port DTO to verify if it can be updated. +final PortDTO portDTO = new PortDTO(); +portDTO.setId(id); +portDTO.setState(requestRunStatus.getState()); + +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +final NiFiUser user = NiFiUserUtils.getNiFiUser(); + +final Authorizable authorizable = lookup.getInputPort(id); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, user); +}, +() -> serviceFacade.verifyUpdateInputPort(portDTO), +(revision, runStatusEntity) -> { +// update the input port +final PortEntity entity = serviceFacade.updateInputPort(revision, portDTO); --- End diff -- We need to recreate this `portDTO` using the `runStatusEntity` due to how we authorize/cache requests during our two phase commit. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217135735 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -557,6 +750,90 @@ public Response updateRemoteProcessGroup( ); } +/** + * Updates the operational status for the specified remote process group with the specified value. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param requestRemotePortRunStatusEntity A remotePortRunStatusEntity. + * @return A remoteProcessGroupEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/run-status") +@ApiOperation( +value = "Updates run status of a remote process group", +response = RemoteProcessGroupEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupRunStatus( +@Context HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") String id, +@ApiParam( +value = "The remote process group run status.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +final RemoteProcessGroupDTO remoteProcessGroupDTO = new RemoteProcessGroupDTO(); +remoteProcessGroupDTO.setId(id); + remoteProcessGroupDTO.setTransmitting(shouldTransmit(requestRemotePortRunStatusEntity)); +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +Authorizable authorizable = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroup(remoteProcessGroupDTO), +(revision, remoteProcessGroupEntity) -> { +// update the specified remote process group +final RemoteProcessGroupEntity entity = serviceFacade.updateRemoteProcessGroup(revision, remoteProcessGroupDTO); --- End diff -- We need to recreate this `remoteProcessGroupDTO` using the `remoteProcessGroupEntity` due to how we authorize/cache requests during our two phase commit. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217135560 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +final RemoteProcessGroupPortDTO remoteProcessGroupPort = new RemoteProcessGroupPortDTO(); +remoteProcessGroupPort.setId(portId); +remoteProcessGroupPort.setGroupId(id); + remoteProcessGroupPort.setTransmitting(shouldTransmit(requestRemotePortRunStatusEntity)); + +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, remoteProcessGroupPort), +(revision, remoteProcessGroupPortEntity) -> { +// update the specified remote process group +final
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217135375 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java --- @@ -434,6 +436,197 @@ public Response updateRemoteProcessGroupOutputPort( ); } +/** + * Updates the specified remote process group input port run status. + * + * @param httpServletRequest request + * @param id The id of the remote process group to update. + * @param portId The id of the input port to update. + * @param requestRemotePortRunStatusEntity The remoteProcessGroupPortRunStatusEntity + * @return A remoteProcessGroupPortEntity + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/input-ports/{port-id}/run-status") +@ApiOperation( +value = "Updates run status of a remote port", +notes = NON_GUARANTEED_ENDPOINT, +response = RemoteProcessGroupPortEntity.class, +authorizations = { +@Authorization(value = "Write - /remote-process-groups/{uuid} or /operation/remote-process-groups/{uuid}") +} +) +@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 updateRemoteProcessGroupInputPortRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The remote process group id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The remote process group port id.", +required = true +) +@PathParam("port-id") final String portId, +@ApiParam( +value = "The remote process group port.", +required = true +) final RemotePortRunStatusEntity requestRemotePortRunStatusEntity) { + +if (requestRemotePortRunStatusEntity == null) { +throw new IllegalArgumentException("Remote process group port run status must be specified."); +} + +if (requestRemotePortRunStatusEntity.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRemotePortRunStatusEntity.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRemotePortRunStatusEntity); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRemotePortRunStatusEntity.isDisconnectedNodeAcknowledged()); +} + +final Revision requestRevision = getRevision(requestRemotePortRunStatusEntity.getRevision(), id); +final RemoteProcessGroupPortDTO remoteProcessGroupPort = new RemoteProcessGroupPortDTO(); +remoteProcessGroupPort.setId(portId); +remoteProcessGroupPort.setGroupId(id); + remoteProcessGroupPort.setTransmitting(shouldTransmit(requestRemotePortRunStatusEntity)); + +return withWriteLock( +serviceFacade, +requestRemotePortRunStatusEntity, +requestRevision, +lookup -> { +final Authorizable remoteProcessGroup = lookup.getRemoteProcessGroup(id); +OperationAuthorizable.isAuthorized(remoteProcessGroup, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateRemoteProcessGroupInputPort(id, remoteProcessGroupPort), +(revision, remoteProcessGroupPortEntity) -> { +// update the specified remote process group +final
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217136120 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java --- @@ -542,6 +547,88 @@ public Response removeReportingTask( ); } +/** + * Updates the operational status for the specified ReportingTask with the specified values. + * + * @param httpServletRequest request + * @param id The id of the reporting task to update. + * @param requestRunStatus A runStatusEntity. + * @return A reportingTaskEntity. + */ +@PUT +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("{id}/run-status") +@ApiOperation( +value = "Updates run status of a reporting task", +response = ReportingTaskEntity.class, +authorizations = { +@Authorization(value = "Write - /reporting-tasks/{uuid} or or /operation/reporting-tasks/{uuid}") +} +) +@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 updateRunStatus( +@Context final HttpServletRequest httpServletRequest, +@ApiParam( +value = "The reporting task id.", +required = true +) +@PathParam("id") final String id, +@ApiParam( +value = "The reporting task run status.", +required = true +) final ReportingTaskRunStatusEntity requestRunStatus) { + +if (requestRunStatus == null) { +throw new IllegalArgumentException("Reporting task run status must be specified."); +} + +if (requestRunStatus.getRevision() == null) { +throw new IllegalArgumentException("Revision must be specified."); +} + +requestRunStatus.validateState(); + +if (isReplicateRequest()) { +return replicate(HttpMethod.PUT, requestRunStatus); +} else if (isDisconnectedFromCluster()) { + verifyDisconnectedNodeModification(requestRunStatus.isDisconnectedNodeAcknowledged()); +} + +// handle expects request (usually from the cluster manager) +final Revision requestRevision = getRevision(requestRunStatus.getRevision(), id); +// Create DTO to verify if it can be updated. +final ReportingTaskDTO reportingTaskDTO = new ReportingTaskDTO(); +reportingTaskDTO.setId(id); +reportingTaskDTO.setState(requestRunStatus.getState()); +return withWriteLock( +serviceFacade, +requestRunStatus, +requestRevision, +lookup -> { +// authorize reporting task +final Authorizable authorizable = lookup.getReportingTask(id).getAuthorizable(); +OperationAuthorizable.authorize(authorizable, authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); +}, +() -> serviceFacade.verifyUpdateReportingTask(reportingTaskDTO), +(revision, reportingTaskEntity) -> { +// update the reporting task +final ReportingTaskEntity entity = serviceFacade.updateReportingTask(revision, reportingTaskDTO); --- End diff -- We need to recreate this `reportingTaskDTO` using the `reportingTaskEntity` due to how we authorize/cache requests during our two phase commit. ---
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
Github user mcgilman commented on a diff in the pull request: https://github.com/apache/nifi/pull/2990#discussion_r217121570 --- Diff: nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/ControllerServiceEntityMerger.java --- @@ -137,7 +138,9 @@ public static void mergeControllerServiceReferences(final Set
[GitHub] nifi pull request #2990: NIFI-375: Added operation policy
GitHub user ijokarumawak opened a pull request: https://github.com/apache/nifi/pull/2990 NIFI-375: Added operation policy The operation policy allows that a user to operate components even if they does not have direct READ/WRITE permission of the component. Following operations are controlled by the new operate policy: - Start/stop/enable/disable Processors, ControllerServices, ReportingTasks, Input/OuputPorts - Enable/disable transmission of RemoteInput/OutputPorts and RemoteProcessGroups - Terminate Processor threads Thank you for submitting a contribution to Apache NiFi. In order to streamline the review of the contribution we ask you to ensure the following steps have been taken: ### For all changes: - [x] Is there a JIRA ticket associated with this PR? Is it referenced in the commit message? - [x] Does your PR title start with NIFI- where is the JIRA number you are trying to resolve? Pay particular attention to the hyphen "-" character. - [x] Has your PR been rebased against the latest commit within the target branch (typically master)? - [x] Is your initial contribution a single, squashed commit? ### For code changes: - [ ] Have you ensured that the full suite of tests is executed via mvn -Pcontrib-check clean install at the root nifi folder? - [x] Have you written or updated unit tests to verify your changes? - [ ] If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under [ASF 2.0](http://www.apache.org/legal/resolved.html#category-a)? - [ ] If applicable, have you updated the LICENSE file, including the main LICENSE file under nifi-assembly? - [ ] If applicable, have you updated the NOTICE file, including the main NOTICE file found under nifi-assembly? - [ ] If adding new Properties, have you added .displayName in addition to .name (programmatic access) for each of the new properties? ### For documentation related changes: - [x] Have you ensured that format looks appropriate for the output in which it is rendered? ### Note: Please ensure that once the PR is submitted, you check travis-ci for build issues and submit an update to your PR as soon as possible. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ijokarumawak/nifi nifi-375 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/nifi/pull/2990.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #2990 commit 96ec577e63461664511c3ac8da96f976a9166a7d Author: Koji Kawamura Date: 2018-08-24T08:58:25Z NIFI-375: Added operation policy The operation policy allows that a user to operate components even if they does not have direct READ/WRITE permission of the component. Following operations are controlled by the new operate policy: - Start/stop/enable/disable Processors, ControllerServices, ReportingTasks, Input/OuputPorts - Enable/disable transmission of RemoteInput/OutputPorts and RemoteProcessGroups - Terminate Processor threads ---