NIFI-4436:

- Code clean up.
- Improved error handling.
- Minor UX improvements.
- Adding message to indicate that variables do not support sensitive values.
- Preventing a user from changing the flow version to the current version.
- Only presenting buckets a user has appropriate permissions to.
- Adding basic auditing to the version control actions.
This commit is contained in:
Matt Gilman 2017-12-06 10:47:28 -05:00 committed by Bryan Bende
parent 014c542f48
commit db2cc9fec1
No known key found for this signature in database
GPG Key ID: A0DDA9ED50711C39
25 changed files with 502 additions and 203 deletions

View File

@ -21,18 +21,34 @@ package org.apache.nifi.action;
*/
public enum Operation {
Add,
Remove,
Paste,
Configure,
Move,
Disconnect,
Connect,
Start,
Stop,
Enable,
Disable,
Batch,
Purge,
ClearState;
Add("Add"),
Remove("Remove"),
Paste("Paste"),
Configure("Configure"),
Move("Move"),
Disconnect("Disconnect"),
Connect("Connect"),
Start("Start"),
Stop("Stop"),
Enable("Enable"),
Disable("Disable"),
Batch("Batch"),
Purge("Purge"),
ClearState("Clear State"),
StartVersionControl("Start Version Control"),
StopVersionControl("Stop Version Control"),
CommitLocalChanges("Commit Local Changes"),
RevertLocalChanges("Revert Local Changes"),
ChangeVersion("Change Version");
private final String label;
Operation(String label) {
this.label = label;
}
@Override
public String toString() {
return label;
}
}

View File

@ -219,8 +219,8 @@ public class StandardActionDAO implements ActionDAO {
statement.setString(1, StringUtils.left(action.getUserIdentity(), 4096));
statement.setString(2, action.getSourceId());
statement.setString(3, StringUtils.left(action.getSourceName(), 1000));
statement.setString(4, action.getSourceType().toString());
statement.setString(5, action.getOperation().toString());
statement.setString(4, action.getSourceType().name());
statement.setString(5, action.getOperation().name());
statement.setTimestamp(6, new java.sql.Timestamp(action.getTimestamp().getTime()));
// insert the action

View File

@ -17,6 +17,7 @@
package org.apache.nifi.web.api.entity;
import org.apache.nifi.web.api.dto.BucketDTO;
import org.apache.nifi.web.api.dto.PermissionsDTO;
import javax.xml.bind.annotation.XmlRootElement;
@ -26,8 +27,17 @@ import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "bucketEntity")
public class BucketEntity extends Entity {
private String id;
private BucketDTO bucket;
private PermissionsDTO permissions;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public BucketDTO getBucket() {
return bucket;
@ -36,4 +46,12 @@ public class BucketEntity extends Entity {
public void setBucket(BucketDTO bucket) {
this.bucket = bucket;
}
public PermissionsDTO getPermissions() {
return permissions;
}
public void setPermissions(PermissionsDTO permissions) {
this.permissions = permissions;
}
}

View File

@ -22,13 +22,13 @@ import java.util.Set;
/**
* A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a set of RegistryEntity's.
*/
@XmlRootElement(name = "registriesEntity")
@XmlRootElement(name = "registryClientsEntity")
public class RegistriesEntity extends Entity {
private Set<RegistryEntity> registries;
/**
* @return collection of LabelEntity's that are being serialized
* @return collection of RegistryEntity's that are being serialized
*/
public Set<RegistryEntity> getRegistries() {
return registries;

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.web.api.entity;
import org.apache.nifi.web.api.dto.RegistryDTO;
import javax.xml.bind.annotation.XmlRootElement;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a RegistryDTO.
*/
@XmlRootElement(name = "registryClientEntity")
public class RegistryClientEntity extends ComponentEntity {
private RegistryDTO component;
public RegistryDTO getComponent() {
return component;
}
public void setComponent(RegistryDTO component) {
this.component = component;
}
}

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.web.api.entity;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Set;
/**
* A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a set of RegistryClientEntity's.
*/
@XmlRootElement(name = "registryClientsEntity")
public class RegistryClientsEntity extends Entity {
private Set<RegistryClientEntity> registries;
/**
* @return collection of RegistryClientEntity's that are being serialized
*/
public Set<RegistryClientEntity> getRegistries() {
return registries;
}
public void setRegistries(Set<RegistryClientEntity> registries) {
this.registries = registries;
}
}

View File

@ -24,16 +24,15 @@ import javax.xml.bind.annotation.XmlRootElement;
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a RegistryDTO.
*/
@XmlRootElement(name = "registryEntity")
public class RegistryEntity extends ComponentEntity {
public class RegistryEntity {
private RegistryDTO component;
private RegistryDTO registry;
public RegistryDTO getComponent() {
return component;
public RegistryDTO getRegistry() {
return registry;
}
public void setComponent(RegistryDTO component) {
this.component = component;
public void setRegistry(RegistryDTO registry) {
this.registry = registry;
}
}

View File

@ -28,7 +28,10 @@ import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.registry.flow.VersionControlInformation;
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
import org.apache.nifi.web.api.dto.VersionControlInformationDTO;
import org.apache.nifi.web.dao.ProcessGroupDAO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
@ -39,6 +42,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.Future;
/**
* Audits process group creation/removal and configuration changes.
@ -173,10 +177,13 @@ public class ProcessGroupAuditor extends NiFiAuditor {
* @throws Throwable ex
*/
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
+ "execution(void scheduleComponents(java.lang.String, org.apache.nifi.controller.ScheduledState, java.util.Set)) && "
+ "execution(java.util.concurrent.Future<Void> scheduleComponents(java.lang.String, org.apache.nifi.controller.ScheduledState, java.util.Set)) && "
+ "args(groupId, state)")
public void scheduleComponentsAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId, ScheduledState state) throws Throwable {
public Future<Void> scheduleComponentsAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId, ScheduledState state) throws Throwable {
final Operation operation;
final Future<Void> result = (Future<Void>) proceedingJoinPoint.proceed();
// determine the running state
if (ScheduledState.RUNNING.equals(state)) {
operation = Operation.Start;
@ -184,7 +191,9 @@ public class ProcessGroupAuditor extends NiFiAuditor {
operation = Operation.Stop;
}
saveUpdateAction(proceedingJoinPoint, groupId, operation);
saveUpdateAction(NiFiUserUtils.getNiFiUser(), groupId, operation);
return result;
}
@ -193,52 +202,118 @@ public class ProcessGroupAuditor extends NiFiAuditor {
*
* @param proceedingJoinPoint join point
* @param groupId group id
* @param state controller serivce state state
* @param state controller service state
* @throws Throwable ex
*/
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
+ "execution(java.util.concurrent.Future activateControllerServices(java.lang.String, org.apache.nifi.controller.service.ControllerServiceState, java.util.Set)) && "
+ "execution(java.util.concurrent.Future<Void> activateControllerServices(java.lang.String, org.apache.nifi.controller.service.ControllerServiceState, java.util.Set)) && "
+ "args(groupId, state)")
public void activateControllerServicesAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId, ControllerServiceState state) throws Throwable {
public Future<Void> activateControllerServicesAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId, ControllerServiceState state) throws Throwable {
final Operation operation;
final Future<Void> result = (Future<Void>) proceedingJoinPoint.proceed();
// determine the service state
final Operation operation;
if (ControllerServiceState.ENABLED.equals(state)) {
operation = Operation.Enable;
} else {
operation = Operation.Disable;
}
saveUpdateAction(proceedingJoinPoint, groupId, operation);
saveUpdateAction(NiFiUserUtils.getNiFiUser(), groupId, operation);
return result;
}
/**
* Audits the update of process group variable registry.
*
* @param proceedingJoinPoint join point
* @param groupId group id
* @param user the user performing the action
* @param variableRegistry variable registry
* @throws Throwable ex
*/
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
+ "execution(org.apache.nifi.groups.ProcessGroup updateVariableRegistry(org.apache.nifi.web.api.dto.VariableRegistryDTO)) && "
+ "args(groupId)")
public void updateVariableRegistryAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId) throws Throwable {
final Operation operation = Operation.Configure;
saveUpdateAction(proceedingJoinPoint, groupId, operation);
+ "execution(org.apache.nifi.groups.ProcessGroup updateVariableRegistry(org.apache.nifi.authorization.user.NiFiUser, org.apache.nifi.web.api.dto.VariableRegistryDTO)) && "
+ "args(user, variableRegistry)")
public ProcessGroup updateVariableRegistryAdvice(final ProceedingJoinPoint proceedingJoinPoint, final NiFiUser user, final VariableRegistryDTO variableRegistry) throws Throwable {
final ProcessGroup updatedProcessGroup = (ProcessGroup) proceedingJoinPoint.proceed();
saveUpdateAction(user, variableRegistry.getProcessGroupId(), Operation.Configure);
return updatedProcessGroup;
}
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
+ "execution(org.apache.nifi.groups.ProcessGroup updateProcessGroupFlow(..))")
public ProcessGroup updateProcessGroupFlowAdvice(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
final Object[] args = proceedingJoinPoint.getArgs();
final String groupId = (String) args[0];
final NiFiUser user = (NiFiUser) args[1];
final ProcessGroupDAO processGroupDAO = getProcessGroupDAO();
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
final VersionControlInformation vci = processGroup.getVersionControlInformation();
private void saveUpdateAction(final ProceedingJoinPoint proceedingJoinPoint, final String groupId, final Operation operation) throws Throwable {
final ProcessGroup updatedProcessGroup = (ProcessGroup) proceedingJoinPoint.proceed();
final VersionControlInformation updatedVci = updatedProcessGroup.getVersionControlInformation();
final Operation operation;
if (vci == null) {
operation = Operation.StartVersionControl;
} else {
if (updatedVci == null) {
operation = Operation.StopVersionControl;
} else if (vci.getVersion() == updatedVci.getVersion()) {
operation = Operation.RevertLocalChanges;
} else {
operation = Operation.ChangeVersion;
}
}
saveUpdateAction(user, groupId, operation);
return updatedProcessGroup;
}
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
+ "execution(org.apache.nifi.groups.ProcessGroup updateVersionControlInformation(..))")
public ProcessGroup updateVersionControlInformationAdvice(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
final VersionControlInformationDTO vciDto = (VersionControlInformationDTO) proceedingJoinPoint.getArgs()[0];
final ProcessGroupDAO processGroupDAO = getProcessGroupDAO();
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(vciDto.getGroupId());
final VersionControlInformation vci = processGroup.getVersionControlInformation();
final ProcessGroup updatedProcessGroup = (ProcessGroup) proceedingJoinPoint.proceed();
final Operation operation;
if (vci == null) {
operation = Operation.StartVersionControl;
} else {
operation = Operation.CommitLocalChanges;
}
saveUpdateAction(NiFiUserUtils.getNiFiUser(), vciDto.getGroupId(), operation);
return updatedProcessGroup;
}
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
+ "execution(org.apache.nifi.groups.ProcessGroup disconnectVersionControl(java.lang.String)) && "
+ "args(groupId)")
public ProcessGroup disconnectVersionControlAdvice(final ProceedingJoinPoint proceedingJoinPoint, final String groupId) throws Throwable {
final ProcessGroup updatedProcessGroup = (ProcessGroup) proceedingJoinPoint.proceed();
saveUpdateAction(NiFiUserUtils.getNiFiUser(), groupId, Operation.StopVersionControl);
return updatedProcessGroup;
}
private void saveUpdateAction(final NiFiUser user, final String groupId, final Operation operation) throws Throwable {
ProcessGroupDAO processGroupDAO = getProcessGroupDAO();
ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
// perform the action
proceedingJoinPoint.proceed();
// get the current user
NiFiUser user = NiFiUserUtils.getNiFiUser();
// if the user was starting/stopping this process group
FlowChangeAction action = new FlowChangeAction();
action.setUserIdentity(user.getIdentity());

View File

@ -16,14 +16,6 @@
*/
package org.apache.nifi.web;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import org.apache.nifi.authorization.AuthorizeAccess;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.user.NiFiUser;
@ -106,6 +98,7 @@ import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
import org.apache.nifi.web.api.entity.RegistryClientEntity;
import org.apache.nifi.web.api.entity.RegistryEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
@ -124,6 +117,14 @@ import org.apache.nifi.web.api.entity.VersionControlInformationEntity;
import org.apache.nifi.web.api.entity.VersionedFlowEntity;
import org.apache.nifi.web.api.entity.VersionedFlowSnapshotMetadataEntity;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
/**
* Defines the NiFiServiceFacade interface.
*/
@ -1929,7 +1930,7 @@ public interface NiFiServiceFacade {
* @param registryDTO The registry DTO
* @return The reporting task DTO
*/
RegistryEntity createRegistryClient(Revision revision, RegistryDTO registryDTO);
RegistryClientEntity createRegistryClient(Revision revision, RegistryDTO registryDTO);
/**
* Gets a registry with the specified id.
@ -1937,14 +1938,14 @@ public interface NiFiServiceFacade {
* @param registryId id
* @return entity
*/
RegistryEntity getRegistryClient(String registryId);
RegistryClientEntity getRegistryClient(String registryId);
/**
* Returns all registry clients.
*
* @return registry clients
*/
Set<RegistryEntity> getRegistryClients();
Set<RegistryClientEntity> getRegistryClients();
/**
* Gets all registries for the current user.
@ -1991,7 +1992,7 @@ public interface NiFiServiceFacade {
* @param registryDTO the registry dto
* @return the updated registry registry entity
*/
RegistryEntity updateRegistryClient(Revision revision, RegistryDTO registryDTO);
RegistryClientEntity updateRegistryClient(Revision revision, RegistryDTO registryDTO);
/**
* Deletes the specified registry using the specified revision.
@ -2000,7 +2001,7 @@ public interface NiFiServiceFacade {
* @param registryId id
* @return the deleted registry entity
*/
RegistryEntity deleteRegistryClient(Revision revision, String registryId);
RegistryClientEntity deleteRegistryClient(Revision revision, String registryId);
/**
* Verifies the specified registry can be removed.

View File

@ -220,6 +220,7 @@ import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
import org.apache.nifi.web.api.entity.ProcessGroupStatusSnapshotEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
import org.apache.nifi.web.api.entity.RegistryClientEntity;
import org.apache.nifi.web.api.entity.RegistryEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
@ -927,7 +928,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(variableRegistryDto.getProcessGroupId());
final RevisionUpdate<VariableRegistryDTO> snapshot = updateComponent(user, revision,
processGroupNode,
() -> processGroupDAO.updateVariableRegistry(variableRegistryDto),
() -> processGroupDAO.updateVariableRegistry(user, variableRegistryDto),
processGroup -> dtoFactory.createVariableRegistryDto(processGroup, revisionManager));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroupNode);
@ -2301,10 +2302,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
@Override
public RegistryEntity createRegistryClient(Revision revision, RegistryDTO registryDTO) {
public RegistryClientEntity createRegistryClient(Revision revision, RegistryDTO registryDTO) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
// read lock on the containing group
// request claim for component to be created... revision already verified (version == 0)
final RevisionClaim claim = new StandardRevisionClaim(revision);
@ -2321,52 +2321,25 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
});
final FlowRegistry registry = revisionUpdate.getComponent();
return createRegistryEntity(registry);
return createRegistryClientEntity(registry);
}
@Override
public RegistryEntity getRegistryClient(final String registryId) {
public RegistryClientEntity getRegistryClient(final String registryId) {
final FlowRegistry registry = registryDAO.getFlowRegistry(registryId);
return createRegistryEntity(registry);
return createRegistryClientEntity(registry);
}
private RegistryEntity createRegistryEntity(final FlowRegistry flowRegistry) {
private RegistryClientEntity createRegistryClientEntity(final FlowRegistry flowRegistry) {
if (flowRegistry == null) {
return null;
}
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(flowRegistry.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getController());
final RegistryDTO dto = dtoFactory.createRegistryDto(flowRegistry);
final Revision revision = revisionManager.getRevision(dto.getId());
final RegistryEntity entity = new RegistryEntity();
entity.setComponent(dto);
entity.setRevision(dtoFactory.createRevisionDTO(revision));
entity.setId(dto.getId());
// User who created it can read/write it.
final PermissionsDTO permissions = new PermissionsDTO();
permissions.setCanRead(true);
permissions.setCanWrite(true);
entity.setPermissions(permissions);
return entity;
}
private BucketEntity createBucketEntity(final Bucket bucket) {
if (bucket == null) {
return null;
}
final BucketDTO dto = new BucketDTO();
dto.setId(bucket.getIdentifier());
dto.setName(bucket.getName());
dto.setDescription(bucket.getDescription());
dto.setCreated(bucket.getCreatedTimestamp());
final BucketEntity entity = new BucketEntity();
entity.setBucket(dto);
return entity;
return entityFactory.createRegistryClientEntity(dto, revision, permissions);
}
private VersionedFlowEntity createVersionedFlowEntity(final String registryId, final VersionedFlow versionedFlow) {
@ -2400,23 +2373,40 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
}
@Override
public Set<RegistryEntity> getRegistryClients() {
public Set<RegistryClientEntity> getRegistryClients() {
return registryDAO.getFlowRegistries().stream()
.map(this::createRegistryEntity)
.map(this::createRegistryClientEntity)
.collect(Collectors.toSet());
}
@Override
public Set<RegistryEntity> getRegistriesForUser(final NiFiUser user) {
return registryDAO.getFlowRegistriesForUser(user).stream()
.map(this::createRegistryEntity)
.map(flowRegistry -> entityFactory.createRegistryEntity(dtoFactory.createRegistryDto(flowRegistry)))
.collect(Collectors.toSet());
}
@Override
public Set<BucketEntity> getBucketsForUser(final String registryId, final NiFiUser user) {
return registryDAO.getBucketsForUser(registryId, user).stream()
.map(this::createBucketEntity)
.map(bucket -> {
if (bucket == null) {
return null;
}
final BucketDTO dto = new BucketDTO();
dto.setId(bucket.getIdentifier());
dto.setName(bucket.getName());
dto.setDescription(bucket.getDescription());
dto.setCreated(bucket.getCreatedTimestamp());
final Set<String> authorizedActions = bucket.getAuthorizedActions();
final PermissionsDTO permissions = new PermissionsDTO();
permissions.setCanRead(authorizedActions.contains("read"));
permissions.setCanWrite(authorizedActions.contains("write"));
return entityFactory.createBucketEntity(dto, permissions);
})
.collect(Collectors.toSet());
}
@ -2435,7 +2425,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
}
@Override
public RegistryEntity updateRegistryClient(Revision revision, RegistryDTO registryDTO) {
public RegistryClientEntity updateRegistryClient(Revision revision, RegistryDTO registryDTO) {
final RevisionClaim revisionClaim = new StandardRevisionClaim(revision);
final NiFiUser user = NiFiUserUtils.getNiFiUser();
@ -2454,7 +2444,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
});
final FlowRegistry updatedReg = revisionUpdate.getComponent();
return createRegistryEntity(updatedReg);
return createRegistryClientEntity(updatedReg);
}
@Override
@ -2463,7 +2453,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
}
@Override
public RegistryEntity deleteRegistryClient(final Revision revision, final String registryId) {
public RegistryClientEntity deleteRegistryClient(final Revision revision, final String registryId) {
final RevisionClaim claim = new StandardRevisionClaim(revision);
final NiFiUser user = NiFiUserUtils.getNiFiUser();
@ -2473,7 +2463,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
return reg;
});
return createRegistryEntity(registry);
return createRegistryClientEntity(registry);
}
@Override
@ -3695,10 +3685,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
// add first snapshot to the flow in the registry
registeredSnapshot = registerVersionedFlowSnapshot(registryId, registeredFlow, versionedProcessGroup, versionedFlowDto.getComments(), expectedVersion);
} catch (final NiFiRegistryException e) {
throw new IllegalArgumentException(e);
throw new IllegalArgumentException(e.getLocalizedMessage());
} catch (final IOException ioe) {
// will result in a 500: Internal Server Error
throw new RuntimeException("Failed to communicate with Flow Registry when attempting to " + action);
throw new IllegalStateException("Failed to communicate with Flow Registry when attempting to " + action);
}
final Bucket bucket = registeredSnapshot.getBucket();
@ -4105,7 +4094,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(groupId);
final RevisionUpdate<ProcessGroupDTO> snapshot = updateComponent(user, revision,
processGroupNode,
() -> processGroupDAO.updateProcessGroupFlow(groupId, proposedFlowSnapshot, versionControlInfo, componentIdSeed, verifyNotModified, updateSettings, updateDescendantVersionedFlows),
() -> processGroupDAO.updateProcessGroupFlow(groupId, user, proposedFlowSnapshot, versionControlInfo, componentIdSeed, verifyNotModified, updateSettings, updateDescendantVersionedFlows),
processGroup -> dtoFactory.createProcessGroupDto(processGroup));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroupNode);

View File

@ -46,8 +46,8 @@ import org.apache.nifi.web.api.entity.ControllerServiceEntity;
import org.apache.nifi.web.api.entity.Entity;
import org.apache.nifi.web.api.entity.HistoryEntity;
import org.apache.nifi.web.api.entity.NodeEntity;
import org.apache.nifi.web.api.entity.RegistriesEntity;
import org.apache.nifi.web.api.entity.RegistryEntity;
import org.apache.nifi.web.api.entity.RegistryClientsEntity;
import org.apache.nifi.web.api.entity.RegistryClientEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.DateTimeParameter;
@ -91,12 +91,12 @@ public class ControllerResource extends ApplicationResource {
/**
* Populate the uri's for the specified registry.
*
* @param registryEntity registry
* @param registryClientEntity registry
* @return dtos
*/
public RegistryEntity populateRemainingRegistryEntityContent(final RegistryEntity registryEntity) {
registryEntity.setUri(generateResourceUri("controller", "registry-clients", registryEntity.getId()));
return registryEntity;
public RegistryClientEntity populateRemainingRegistryEntityContent(final RegistryClientEntity registryClientEntity) {
registryClientEntity.setUri(generateResourceUri("controller", "registry-clients", registryClientEntity.getId()));
return registryClientEntity;
}
/**
@ -316,7 +316,7 @@ public class ControllerResource extends ApplicationResource {
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("registry-clients")
@ApiOperation(value = "Gets the listing of available registry clients", response = RegistriesEntity.class, authorizations = {
@ApiOperation(value = "Gets the listing of available registry clients", response = RegistryClientsEntity.class, authorizations = {
@Authorization(value = "Read - /flow")
})
@ApiResponses(value = {
@ -333,10 +333,10 @@ public class ControllerResource extends ApplicationResource {
return replicate(HttpMethod.GET);
}
final Set<RegistryEntity> registries = serviceFacade.getRegistryClients();
final Set<RegistryClientEntity> registries = serviceFacade.getRegistryClients();
registries.forEach(registry -> populateRemainingRegistryEntityContent(registry));
final RegistriesEntity registryEntities = new RegistriesEntity();
final RegistryClientsEntity registryEntities = new RegistryClientsEntity();
registryEntities.setRegistries(registries);
return generateOkResponse(registryEntities).build();
@ -346,8 +346,8 @@ public class ControllerResource extends ApplicationResource {
* Creates a new Registry.
*
* @param httpServletRequest request
* @param requestRegistryEntity A registryEntity.
* @return A registryEntity.
* @param requestRegistryClientEntity A registryClientEntity.
* @return A registryClientEntity.
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@ -355,7 +355,7 @@ public class ControllerResource extends ApplicationResource {
@Path("registry-clients")
@ApiOperation(
value = "Creates a new registry client",
response = RegistryEntity.class,
response = RegistryClientEntity.class,
authorizations = {
@Authorization(value = "Write - /controller")
}
@ -373,28 +373,28 @@ public class ControllerResource extends ApplicationResource {
@ApiParam(
value = "The registry configuration details.",
required = true
) final RegistryEntity requestRegistryEntity) {
) final RegistryClientEntity requestRegistryClientEntity) {
if (requestRegistryEntity == null || requestRegistryEntity.getComponent() == null) {
if (requestRegistryClientEntity == null || requestRegistryClientEntity.getComponent() == null) {
throw new IllegalArgumentException("Registry details must be specified.");
}
if (requestRegistryEntity.getRevision() == null || (requestRegistryEntity.getRevision().getVersion() == null || requestRegistryEntity.getRevision().getVersion() != 0)) {
if (requestRegistryClientEntity.getRevision() == null || (requestRegistryClientEntity.getRevision().getVersion() == null || requestRegistryClientEntity.getRevision().getVersion() != 0)) {
throw new IllegalArgumentException("A revision of 0 must be specified when creating a new Registry.");
}
final RegistryDTO requestReportingTask = requestRegistryEntity.getComponent();
final RegistryDTO requestReportingTask = requestRegistryClientEntity.getComponent();
if (requestReportingTask.getId() != null) {
throw new IllegalArgumentException("Registry ID cannot be specified.");
}
if (isReplicateRequest()) {
return replicate(HttpMethod.POST, requestRegistryEntity);
return replicate(HttpMethod.POST, requestRegistryClientEntity);
}
return withWriteLock(
serviceFacade,
requestRegistryEntity,
requestRegistryClientEntity,
lookup -> {
authorizeController(RequestAction.WRITE);
},
@ -407,7 +407,7 @@ public class ControllerResource extends ApplicationResource {
// create the reporting task and generate the json
final Revision revision = getRevision(registryEntity, registry.getId());
final RegistryEntity entity = serviceFacade.createRegistryClient(revision, registry);
final RegistryClientEntity entity = serviceFacade.createRegistryClient(revision, registry);
populateRemainingRegistryEntityContent(entity);
// build the response
@ -420,7 +420,7 @@ public class ControllerResource extends ApplicationResource {
* Retrieves the specified registry.
*
* @param id The id of the registry to retrieve
* @return A registryEntity.
* @return A registryClientEntity.
*/
@GET
@Consumes(MediaType.WILDCARD)
@ -428,7 +428,7 @@ public class ControllerResource extends ApplicationResource {
@Path("/registry-clients/{id}")
@ApiOperation(
value = "Gets a registry client",
response = RegistryEntity.class,
response = RegistryClientEntity.class,
authorizations = {
@Authorization(value = "Read - /controller")
}
@ -442,7 +442,7 @@ public class ControllerResource extends ApplicationResource {
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getRegistry(
public Response getRegistryClient(
@ApiParam(
value = "The registry id.",
required = true
@ -457,7 +457,7 @@ public class ControllerResource extends ApplicationResource {
authorizeController(RequestAction.READ);
// get the registry
final RegistryEntity entity = serviceFacade.getRegistryClient(id);
final RegistryClientEntity entity = serviceFacade.getRegistryClient(id);
populateRemainingRegistryEntityContent(entity);
return generateOkResponse(entity).build();
@ -477,7 +477,7 @@ public class ControllerResource extends ApplicationResource {
@Path("/registry-clients/{id}")
@ApiOperation(
value = "Updates a registry client",
response = RegistryEntity.class,
response = RegistryClientEntity.class,
authorizations = {
@Authorization(value = "Write - /controller")
}
@ -501,7 +501,7 @@ public class ControllerResource extends ApplicationResource {
@ApiParam(
value = "The registry configuration details.",
required = true
) final RegistryEntity requestRegsitryEntity) {
) final RegistryClientEntity requestRegsitryEntity) {
if (requestRegsitryEntity == null || requestRegsitryEntity.getComponent() == null) {
throw new IllegalArgumentException("Registry details must be specified.");
@ -536,7 +536,7 @@ public class ControllerResource extends ApplicationResource {
final RegistryDTO registry = registryEntity.getComponent();
// update the controller service
final RegistryEntity entity = serviceFacade.updateRegistryClient(revision, registry);
final RegistryClientEntity entity = serviceFacade.updateRegistryClient(revision, registry);
populateRemainingRegistryEntityContent(entity);
return generateOkResponse(entity).build();
@ -562,7 +562,7 @@ public class ControllerResource extends ApplicationResource {
@Path("/registry-clients/{id}")
@ApiOperation(
value = "Deletes a registry client",
response = RegistryEntity.class,
response = RegistryClientEntity.class,
authorizations = {
@Authorization(value = "Write - /controller")
}
@ -598,14 +598,14 @@ public class ControllerResource extends ApplicationResource {
return replicate(HttpMethod.DELETE);
}
final RegistryEntity requestRegistryEntity = new RegistryEntity();
requestRegistryEntity.setId(id);
final RegistryClientEntity requestRegistryClientEntity = new RegistryClientEntity();
requestRegistryClientEntity.setId(id);
// handle expects request (usually from the cluster manager)
final Revision requestRevision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
return withWriteLock(
serviceFacade,
requestRegistryEntity,
requestRegistryClientEntity,
requestRevision,
lookup -> {
authorizeController(RequestAction.WRITE);
@ -613,7 +613,7 @@ public class ControllerResource extends ApplicationResource {
() -> serviceFacade.verifyDeleteRegistry(id),
(revision, registryEntity) -> {
// delete the specified registry
final RegistryEntity entity = serviceFacade.deleteRegistryClient(revision, registryEntity.getId());
final RegistryClientEntity entity = serviceFacade.deleteRegistryClient(revision, registryEntity.getId());
return generateOkResponse(entity).build();
}
);

View File

@ -88,6 +88,7 @@ import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
import org.apache.nifi.web.api.entity.ProcessorTypesEntity;
import org.apache.nifi.web.api.entity.RegistriesEntity;
import org.apache.nifi.web.api.entity.RegistryClientsEntity;
import org.apache.nifi.web.api.entity.RegistryEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
@ -1316,7 +1317,7 @@ public class FlowResource extends ApplicationResource {
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("registries")
@ApiOperation(value = "Gets the listing of available registries", response = RegistriesEntity.class, authorizations = {
@ApiOperation(value = "Gets the listing of available registries", response = RegistryClientsEntity.class, authorizations = {
@Authorization(value = "Read - /flow")
})
@ApiResponses(value = {

View File

@ -183,7 +183,7 @@ public class VersionsResource extends ApplicationResource {
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
})
public Response createVersionControlRequest(
@ApiParam(value = "The versioned flow details.", required = true) final CreateActiveRequestEntity requestEntity) throws InterruptedException {
@ApiParam(value = "The versioned flow details.", required = true) final CreateActiveRequestEntity requestEntity) {
if (isReplicateRequest()) {
return replicate(HttpMethod.POST);
@ -412,7 +412,7 @@ public class VersionsResource extends ApplicationResource {
})
public Response saveToFlowRegistry(
@ApiParam("The process group id.") @PathParam("id") final String groupId,
@ApiParam(value = "The versioned flow details.", required = true) final StartVersionControlRequestEntity requestEntity) throws IOException {
@ApiParam(value = "The versioned flow details.", required = true) final StartVersionControlRequestEntity requestEntity) {
// Verify the request
final RevisionDTO revisionDto = requestEntity.getProcessGroupRevision();
@ -569,8 +569,9 @@ public class VersionsResource extends ApplicationResource {
return requestId;
}
private void replicateVersionControlMapping(final VersionControlComponentMappingEntity mappingEntity, final StartVersionControlRequestEntity requestEntity, final URI requestUri,
final String groupId) {
private void replicateVersionControlMapping(final VersionControlComponentMappingEntity mappingEntity, final StartVersionControlRequestEntity requestEntity,
final URI requestUri, final String groupId) {
final Map<String, String> headers = new HashMap<>();
headers.put("content-type", MediaType.APPLICATION_JSON);
@ -652,7 +653,7 @@ public class VersionsResource extends ApplicationResource {
value = "If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.",
required = false)
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) final ClientIdParameter clientId,
@ApiParam("The process group id.") @PathParam("id") final String groupId) throws IOException {
@ApiParam("The process group id.") @PathParam("id") final String groupId) {
if (isReplicateRequest()) {
return replicate(HttpMethod.DELETE);
@ -705,7 +706,7 @@ public class VersionsResource extends ApplicationResource {
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
})
public Response updateFlowVersion(@ApiParam("The process group id.") @PathParam("id") final String groupId,
@ApiParam(value = "The controller service configuration details.", required = true) final VersionedFlowSnapshotEntity requestEntity) throws IOException, LifecycleManagementException {
@ApiParam(value = "The controller service configuration details.", required = true) final VersionedFlowSnapshotEntity requestEntity) {
// Verify the request
final RevisionDTO revisionDto = requestEntity.getProcessGroupRevision();

View File

@ -272,10 +272,10 @@ public final class DtoFactory {
actionDto.setId(action.getId());
actionDto.setSourceId(action.getSourceId());
actionDto.setSourceName(action.getSourceName());
actionDto.setSourceType(action.getSourceType().name());
actionDto.setSourceType(action.getSourceType().toString());
actionDto.setTimestamp(action.getTimestamp());
actionDto.setUserIdentity(action.getUserIdentity());
actionDto.setOperation(action.getOperation().name());
actionDto.setOperation(action.getOperation().toString());
actionDto.setActionDetails(createActionDetailsDto(action.getActionDetails()));
actionDto.setComponentDetails(createComponentDetailsDto(action.getComponentDetails()));

View File

@ -35,6 +35,7 @@ import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity;
import org.apache.nifi.web.api.entity.ActionEntity;
import org.apache.nifi.web.api.entity.AffectedComponentEntity;
import org.apache.nifi.web.api.entity.AllowableValueEntity;
import org.apache.nifi.web.api.entity.BucketEntity;
import org.apache.nifi.web.api.entity.BulletinEntity;
import org.apache.nifi.web.api.entity.ComponentReferenceEntity;
import org.apache.nifi.web.api.entity.ConnectionEntity;
@ -56,6 +57,8 @@ import org.apache.nifi.web.api.entity.ProcessGroupStatusSnapshotEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
import org.apache.nifi.web.api.entity.ProcessorStatusSnapshotEntity;
import org.apache.nifi.web.api.entity.RegistryClientEntity;
import org.apache.nifi.web.api.entity.RegistryEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusEntity;
@ -546,4 +549,43 @@ public final class EntityFactory {
entity.setProcessGroupRevision(processGroupRevision);
return entity;
}
public RegistryClientEntity createRegistryClientEntity(final RegistryDTO dto, final RevisionDTO revision, final PermissionsDTO permissions) {
final RegistryClientEntity entity = new RegistryClientEntity();
entity.setRevision(revision);
entity.setPermissions(permissions);
if (dto != null) {
entity.setId(dto.getId());
if (permissions != null && permissions.getCanRead()) {
entity.setComponent(dto);
}
}
return entity;
}
public RegistryEntity createRegistryEntity(final RegistryDTO dto) {
final RegistryEntity entity = new RegistryEntity();
if (dto != null) {
entity.setRegistry(dto);
}
return entity;
}
public BucketEntity createBucketEntity(final BucketDTO dto, final PermissionsDTO permissions) {
final BucketEntity entity = new BucketEntity();
entity.setId(dto.getId());
entity.setPermissions(permissions);
if (permissions != null && permissions.getCanRead()) {
entity.setBucket(dto);
}
return entity;
}
}

View File

@ -16,6 +16,7 @@
*/
package org.apache.nifi.web.dao;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.groups.ProcessGroup;
@ -118,8 +119,8 @@ public interface ProcessGroupDAO {
* update the contents of that Process Group
* @return the process group
*/
ProcessGroup updateProcessGroupFlow(String groupId, VersionedFlowSnapshot proposedSnapshot, VersionControlInformationDTO versionControlInformation, String componentIdSeed,
boolean verifyNotModified, boolean updateSettings, boolean updateDescendantVersionedFlows);
ProcessGroup updateProcessGroupFlow(String groupId, NiFiUser user, VersionedFlowSnapshot proposedSnapshot, VersionControlInformationDTO versionControlInformation, String componentIdSeed,
boolean verifyNotModified, boolean updateSettings, boolean updateDescendantVersionedFlows);
/**
* Applies the given Version Control Information to the Process Group
@ -141,10 +142,11 @@ public interface ProcessGroupDAO {
/**
* Updates the specified variable registry
*
* @param user the user performing the update
* @param variableRegistry the Variable Registry
* @return the Process Group that was updated
*/
ProcessGroup updateVariableRegistry(VariableRegistryDTO variableRegistry);
ProcessGroup updateVariableRegistry(NiFiUser user, VariableRegistryDTO variableRegistry);
/**
* Verifies that the specified updates to a current Process Group can be applied at this time

View File

@ -17,11 +17,6 @@
package org.apache.nifi.web.dao.impl;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.registry.bucket.Bucket;
import org.apache.nifi.registry.client.NiFiRegistryException;
@ -36,6 +31,7 @@ import org.apache.nifi.web.dao.RegistryDAO;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
public class FlowRegistryDAO implements RegistryDAO {
@ -65,7 +61,6 @@ public class FlowRegistryDAO implements RegistryDAO {
@Override
public Set<FlowRegistry> getFlowRegistriesForUser(final NiFiUser user) {
// TODO - implement to be user specific
return getFlowRegistries();
}

View File

@ -16,6 +16,7 @@
*/
package org.apache.nifi.web.dao.impl;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.connectable.Connectable;
import org.apache.nifi.connectable.Port;
import org.apache.nifi.connectable.Position;
@ -143,7 +144,7 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
}
@Override
public CompletableFuture<Void> scheduleComponents(final String groupId, final ScheduledState state, final Set<String> componentIds) {
public Future<Void> scheduleComponents(final String groupId, final ScheduledState state, final Set<String> componentIds) {
final ProcessGroup group = locateProcessGroup(flowController, groupId);
CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
@ -275,8 +276,9 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
}
@Override
public ProcessGroup updateProcessGroupFlow(final String groupId, final VersionedFlowSnapshot proposedSnapshot, final VersionControlInformationDTO versionControlInformation,
final String componentIdSeed, final boolean verifyNotModified, final boolean updateSettings, final boolean updateDescendantVersionedFlows) {
public ProcessGroup updateProcessGroupFlow(final String groupId, final NiFiUser user, final VersionedFlowSnapshot proposedSnapshot, final VersionControlInformationDTO versionControlInformation,
final String componentIdSeed, final boolean verifyNotModified, final boolean updateSettings, final boolean updateDescendantVersionedFlows) {
final ProcessGroup group = locateProcessGroup(flowController, groupId);
group.updateFlow(proposedSnapshot, componentIdSeed, verifyNotModified, updateSettings, updateDescendantVersionedFlows);
@ -291,7 +293,7 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
}
@Override
public ProcessGroup updateVariableRegistry(final VariableRegistryDTO variableRegistry) {
public ProcessGroup updateVariableRegistry(final NiFiUser user, final VariableRegistryDTO variableRegistry) {
final ProcessGroup group = locateProcessGroup(flowController, variableRegistry.getProcessGroupId());
if (group == null) {
throw new ResourceNotFoundException("Could not find Process Group with ID " + variableRegistry.getProcessGroupId());

View File

@ -80,6 +80,7 @@
</div>
</div>
</div>
<div id="variable-message">Variables do not support sensitive values and will be included when versioning a Process Group.</div>
</div>
<div id="new-variable-dialog" class="dialog cancellable small-dialog hidden">
<div class="dialog-content">

View File

@ -15,7 +15,7 @@
limitations under the License.
--%>
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
<div id="nf-ok-dialog" class="hidden small-dialog">
<div id="nf-ok-dialog" class="hidden medium-short-dialog">
<div class="dialog-content">
<div id="nf-ok-dialog-content"></div>
</div>

View File

@ -323,6 +323,13 @@ div.slick-cell div.overridden {
text-decoration: line-through;
}
#variable-message {
position: absolute;
top: 550px;
left: 20px;
font-size: 13px;
}
/*
Registry configuration dialog
*/

View File

@ -43,6 +43,15 @@
min-width: 470px;
}
.medium-short-dialog {
max-height: 32%;
max-width: 34%;
min-height: 250px;
min-width: 440px;
font-size: 13px;
line-height: 1.3;
}
.large-dialog {
max-height: 72%;
max-width: 55%;

View File

@ -920,7 +920,7 @@
'delete': function (selection) {
if (nfCommon.isUndefined(selection) || selection.empty()) {
nfDialog.showOkDialog({
headerText: 'Reload',
headerText: 'Delete Components',
dialogContent: 'No eligible components are selected. Please select the components to be deleted.'
});
} else {

View File

@ -180,9 +180,11 @@
* @param registryCombo
* @param bucketCombo
* @param flowCombo
* @param selectBucket
* @param bucketCheck
* @returns {deferred}
*/
var loadRegistries = function (dialog, registryCombo, bucketCombo, flowCombo, selectBucket) {
var loadRegistries = function (dialog, registryCombo, bucketCombo, flowCombo, selectBucket, bucketCheck) {
return $.ajax({
type: 'GET',
url: '../nifi-api/flow/registries',
@ -192,11 +194,11 @@
if (nfCommon.isDefinedAndNotNull(registriesResponse.registries) && registriesResponse.registries.length > 0) {
registriesResponse.registries.sort(function (a, b) {
return a.component.name > b.component.name;
return a.registry.name > b.registry.name;
});
$.each(registriesResponse.registries, function (_, registryEntity) {
var registry = registryEntity.component;
var registry = registryEntity.registry;
registries.push({
text: registry.name,
value: registry.id,
@ -216,7 +218,7 @@
registryCombo.combo({
options: registries,
select: function (selectedOption) {
selectRegistry(dialog, selectedOption, bucketCombo, flowCombo, selectBucket)
selectRegistry(dialog, selectedOption, bucketCombo, flowCombo, selectBucket, bucketCheck)
}
});
}).fail(nfErrorHandler.handleAjaxError);
@ -229,9 +231,10 @@
* @param bucketCombo
* @param flowCombo
* @param selectBucket
* @param bucketCheck
* @returns {*}
*/
var loadBuckets = function (registryIdentifier, bucketCombo, flowCombo, selectBucket) {
var loadBuckets = function (registryIdentifier, bucketCombo, flowCombo, selectBucket, bucketCheck) {
return $.ajax({
type: 'GET',
url: '../nifi-api/flow/registries/' + encodeURIComponent(registryIdentifier) + '/buckets',
@ -241,18 +244,33 @@
if (nfCommon.isDefinedAndNotNull(response.buckets) && response.buckets.length > 0) {
response.buckets.sort(function (a, b) {
if (a.permissions.canRead === false && b.permissions.canRead === false) {
return 0;
} else if (a.permissions.canRead === false) {
return -1;
} else if (b.permissions.canRead === false) {
return 1;
}
return a.bucket.name > b.bucket.name;
});
$.each(response.buckets, function (_, bucketEntity) {
var bucket = bucketEntity.bucket;
buckets.push({
text: bucket.name,
value: bucket.id,
description: nfCommon.escapeHtml(bucket.description)
});
if (bucketEntity.permissions.canRead === true) {
var bucket = bucketEntity.bucket;
if (bucketCheck(bucketEntity)) {
buckets.push({
text: bucket.name,
value: bucket.id,
description: nfCommon.escapeHtml(bucket.description)
});
}
}
});
} else {
}
if (buckets.length === 0) {
buckets.push({
text: 'No available buckets',
value: null,
@ -285,8 +303,9 @@
* @param bucketCombo
* @param flowCombo
* @param selectBucket
* @param bucketCheck
*/
var selectRegistry = function (dialog, selectedOption, bucketCombo, flowCombo, selectBucket) {
var selectRegistry = function (dialog, selectedOption, bucketCombo, flowCombo, selectBucket, bucketCheck) {
var showNoBucketsAvailable = function () {
bucketCombo.combo('destroy').combo({
options: [{
@ -333,7 +352,7 @@
clearFlowVersionsGrid();
}
loadBuckets(selectedOption.value, bucketCombo, flowCombo, selectBucket).fail(function () {
loadBuckets(selectedOption.value, bucketCombo, flowCombo, selectBucket, bucketCheck).fail(function () {
showNoBucketsAvailable();
});
}
@ -744,7 +763,9 @@
}]
}).show();
loadRegistries($('#import-flow-version-dialog'), registryCombo, bucketCombo, flowCombo, selectBucketImportVersion).done(function () {
loadRegistries($('#import-flow-version-dialog'), registryCombo, bucketCombo, flowCombo, selectBucketImportVersion, function (bucketEntity) {
return true;
}).done(function () {
// show the import dialog
$('#import-flow-version-dialog').modal('setHeaderText', 'Import Version').modal('setButtonModel', [{
buttonText: 'Import',
@ -904,23 +925,35 @@
* @param selectedBucket
*/
var selectBucketImportVersion = function (selectedBucket) {
// mark the flows as loading
$('#import-flow-version-name-combo').combo('destroy').combo({
options: [{
text: 'Loading flows...',
value: null,
optionClass: 'unset',
disabled: true
}]
});
// clear the flow versions grid
clearFlowVersionsGrid();
var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption');
if (nfCommon.isDefinedAndNotNull(selectedBucket.value)) {
// mark the flows as loading
$('#import-flow-version-name-combo').combo('destroy').combo({
options: [{
text: 'Loading flows...',
value: null,
optionClass: 'unset',
disabled: true
}]
});
// load the flows for the currently selected registry and bucket
loadFlows(selectedRegistry.value, selectedBucket.value, selectVersionedFlow);
var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption');
// load the flows for the currently selected registry and bucket
loadFlows(selectedRegistry.value, selectedBucket.value, selectVersionedFlow);
} else {
// mark no flows available
$('#import-flow-version-name-combo').combo('destroy').combo({
options: [{
text: 'No available flows',
value: null,
optionClass: 'unset',
disabled: true
}]
});
}
};
/**
@ -988,7 +1021,22 @@
var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
if (nfCommon.isDefinedAndNotNull(importFlowVersionGrid)) {
var selected = importFlowVersionGrid.getSelectedRows();
return selected.length !== 1;
// if the version label is visible, this is a change version request so disable when
// the version that represents the current version is selected
if ($('#import-flow-version-label').is(':visible')) {
if (selected.length === 1) {
var selectedFlow = importFlowVersionGrid.getDataItem(selected[0]);
var currentVersion = parseInt($('#import-flow-version-label').text(), 10);
return currentVersion === selectedFlow.version;
} else {
return true;
}
} else {
// if importing, enable when a single row is selecting
return selected.length !== 1;
}
} else {
return true;
}
@ -1731,7 +1779,9 @@
// reposition the version label
$('#save-flow-version-label').css('margin-top', '0');
loadRegistries($('#save-flow-version-dialog'), registryCombo, bucketCombo, null, selectBucketSaveFlowVersion).done(function () {
loadRegistries($('#save-flow-version-dialog'), registryCombo, bucketCombo, null, selectBucketSaveFlowVersion, function (bucketEntity) {
return bucketEntity.permissions.canWrite === true;
}).done(function () {
deferred.resolve();
}).fail(function () {
deferred.reject();

View File

@ -1095,6 +1095,7 @@
// up to date current
var upToDate = details.select('text.process-group-up-to-date')
.style('visibility', 'visible')
.classed('up-to-date', function (d) {
return d.component.upToDateCount > 0;
})
@ -1102,6 +1103,7 @@
return d.component.upToDateCount === 0;
});
var upToDateCount = details.select('text.process-group-up-to-date-count')
.style('visibility', 'visible')
.attr('x', function () {
var updateToDateCountX = parseInt(upToDate.attr('x'), 10);
return updateToDateCountX + Math.round(upToDate.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
@ -1112,6 +1114,7 @@
// update locally modified
var locallyModified = details.select('text.process-group-locally-modified')
.style('visibility', 'visible')
.classed('locally-modified', function (d) {
return d.component.locallyModifiedCount > 0;
})
@ -1123,6 +1126,7 @@
return upToDateX + Math.round(upToDateCount.node().getComputedTextLength()) + CONTENTS_SPACER;
});
var locallyModifiedCount = details.select('text.process-group-locally-modified-count')
.style('visibility', 'visible')
.attr('x', function () {
var locallyModifiedCountX = parseInt(locallyModified.attr('x'), 10);
return locallyModifiedCountX + Math.round(locallyModified.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
@ -1133,6 +1137,7 @@
// update stale
var stale = details.select('text.process-group-stale')
.style('visibility', 'visible')
.classed('stale', function (d) {
return d.component.staleCount > 0;
})
@ -1144,6 +1149,7 @@
return locallyModifiedX + Math.round(locallyModifiedCount.node().getComputedTextLength()) + CONTENTS_SPACER;
});
var staleCount = details.select('text.process-group-stale-count')
.style('visibility', 'visible')
.attr('x', function () {
var staleCountX = parseInt(stale.attr('x'), 10);
return staleCountX + Math.round(stale.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
@ -1154,6 +1160,7 @@
// update locally modified and stale
var locallyModifiedAndStale = details.select('text.process-group-locally-modified-and-stale')
.style('visibility', 'visible')
.classed('locally-modified-and-stale', function (d) {
return d.component.locallyModifiedAndStaleCount > 0;
})
@ -1165,6 +1172,7 @@
return staleX + Math.round(staleCount.node().getComputedTextLength()) + CONTENTS_SPACER;
});
var locallyModifiedAndStaleCount = details.select('text.process-group-locally-modified-and-stale-count')
.style('visibility', 'visible')
.attr('x', function () {
var locallyModifiedAndStaleCountX = parseInt(locallyModifiedAndStale.attr('x'), 10);
return locallyModifiedAndStaleCountX + Math.round(locallyModifiedAndStale.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
@ -1175,6 +1183,7 @@
// update sync failure
var syncFailure = details.select('text.process-group-sync-failure')
.style('visibility', 'visible')
.classed('sync-failure', function (d) {
return d.component.syncFailureCount > 0;
})
@ -1186,6 +1195,7 @@
return syncFailureX + Math.round(locallyModifiedAndStaleCount.node().getComputedTextLength()) + CONTENTS_SPACER - 2;
});
details.select('text.process-group-sync-failure-count')
.style('visibility', 'visible')
.attr('x', function () {
var syncFailureCountX = parseInt(syncFailure.attr('x'), 10);
return syncFailureCountX + Math.round(syncFailure.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
@ -1195,20 +1205,22 @@
});
} else {
// update version control information
processGroup.select('text.version-control').style('visibility', false).text('');
processGroup.select('text.version-control').style('visibility', 'hidden');
// clear the process group comments
processGroup.select('path.component-comments').style('visibility', false);
processGroup.select('path.component-comments').style('visibility', 'hidden');
// clear the encapsulate versioned pg counts
details.select('text.process-group-up-to-date').style('visibility', false);
details.select('text.process-group-up-to-date-count').style('visibility', false);
details.select('text.process-group-locally-modified').style('visibility', false);
details.select('text.process-group-locally-modified-count').style('visibility', false);
details.select('text.process-group-stale').style('visibility', false);
details.select('text.process-group-stale-count').style('visibility', false);
details.select('text.process-group-locally-modified-and-stale').style('visibility', false);
details.select('text.process-group-locally-modified-and-stale-count').style('visibility', false);
details.select('text.process-group-up-to-date').style('visibility', 'hidden');
details.select('text.process-group-up-to-date-count').style('visibility', 'hidden');
details.select('text.process-group-locally-modified').style('visibility', 'hidden');
details.select('text.process-group-locally-modified-count').style('visibility', 'hidden');
details.select('text.process-group-stale').style('visibility', 'hidden');
details.select('text.process-group-stale-count').style('visibility', 'hidden');
details.select('text.process-group-locally-modified-and-stale').style('visibility', 'hidden');
details.select('text.process-group-locally-modified-and-stale-count').style('visibility', 'hidden');
details.select('text.process-group-sync-failure').style('visibility', 'hidden');
details.select('text.process-group-sync-failure-count').style('visibility', 'hidden');
// clear the process group name
processGroup.select('text.process-group-name')