public VersionControlInformationDTO createVersionControlInformationDto(final ProcessGroup group) { if (group == null) { return null; } final VersionControlInformation versionControlInfo = group.getVersionControlInformation(); if (versionControlInfo == null) { return null; } final VersionControlInformationDTO dto = new VersionControlInformationDTO(); dto.setGroupId(group.getIdentifier()); dto.setRegistryId(versionControlInfo.getRegistryIdentifier()); dto.setRegistryName(versionControlInfo.getRegistryName()); dto.setBucketId(versionControlInfo.getBucketIdentifier()); dto.setBucketName(versionControlInfo.getBucketName()); dto.setFlowId(versionControlInfo.getFlowIdentifier()); dto.setFlowName(versionControlInfo.getFlowName()); dto.setFlowDescription(versionControlInfo.getFlowDescription()); dto.setVersion(versionControlInfo.getVersion()); final VersionedFlowStatus status = versionControlInfo.getStatus(); final VersionedFlowState state = status.getState(); dto.setState(state == null ? null : state.name()); dto.setStateExplanation(status.getStateExplanation()); return dto; }
private static void verifyNoDuplicateVersionControlInfo(final ProcessGroup group, final Collection<VersionControlInformation> snippetVcis) { final VersionControlInformation vci = group.getVersionControlInformation(); if (vci != null) { for (final VersionControlInformation snippetVci : snippetVcis) { if (vci.getBucketIdentifier().equals(snippetVci.getBucketIdentifier()) && vci.getFlowIdentifier().equals(snippetVci.getFlowIdentifier())) { throw new IllegalArgumentException("Cannot place the given Process Group into the desired destination because the destination group or one of its ancestor groups is " + "under Version Control and one of the selected Process Groups is also under Version Control with the same Flow. A Process Group that is under Version Control " + "cannot contain a child Process Group that points to the same Versioned Flow."); } } } final ProcessGroup parent = group.getParent(); if (parent != null) { verifyNoDuplicateVersionControlInfo(parent, snippetVcis); } }
if (versionControlInfo != null) { final Element versionControlInfoElement = doc.createElement("versionControlInformation"); addTextElement(versionControlInfoElement, "registryId", versionControlInfo.getRegistryIdentifier()); addTextElement(versionControlInfoElement, "bucketId", versionControlInfo.getBucketIdentifier()); addTextElement(versionControlInfoElement, "bucketName", versionControlInfo.getBucketName()); addTextElement(versionControlInfoElement, "flowId", versionControlInfo.getFlowIdentifier()); addTextElement(versionControlInfoElement, "flowName", versionControlInfo.getFlowName()); addTextElement(versionControlInfoElement, "flowDescription", versionControlInfo.getFlowDescription()); addTextElement(versionControlInfoElement, "version", versionControlInfo.getVersion()); element.appendChild(versionControlInfoElement);
final FlowRegistry flowRegistry = flowRegistryClient.getFlowRegistry(versionControlInfo.getRegistryIdentifier()); if (flowRegistry == null) { throw new IllegalStateException("Process Group with ID " + processGroupId + " is tracking to a flow in Flow Registry with ID " + versionControlInfo.getRegistryIdentifier() + " but cannot find a Flow Registry with that identifier"); versionedFlowSnapshot = flowRegistry.getFlowContents(versionControlInfo.getBucketIdentifier(), versionControlInfo.getFlowIdentifier(), versionControlInfo.getVersion(), true, NiFiUserUtils.getNiFiUser()); } catch (final IOException | NiFiRegistryException e) { throw new NiFiCoreException("Failed to retrieve flow with Flow Registry in order to calculate local differences due to " + e.getMessage(), e);
final VersionControlInformation versionControlInfo = getVersionControlInformation(); if (versionControlInfo != null) { if (!versionControlInfo.getFlowIdentifier().equals(updatedFlow.getSnapshotMetadata().getFlowIdentifier())) { throw new IllegalStateException(this + " is under version control but the given flow does not match the flow that this Process Group is synchronized with"); final VersionedFlowState flowState = versionControlInfo.getStatus().getState(); final boolean modified = flowState == VersionedFlowState.LOCALLY_MODIFIED || flowState == VersionedFlowState.LOCALLY_MODIFIED_AND_STALE;
private void verifyNoDescendantsWithLocalModifications(final String action) { for (final ProcessGroup descendant : findAllProcessGroups()) { final VersionControlInformation descendantVci = descendant.getVersionControlInformation(); if (descendantVci != null) { final VersionedFlowState flowState = descendantVci.getStatus().getState(); final boolean modified = flowState == VersionedFlowState.LOCALLY_MODIFIED || flowState == VersionedFlowState.LOCALLY_MODIFIED_AND_STALE; if (modified) { throw new IllegalStateException("Process Group cannot " + action + " because it contains a child or descendant Process Group that is under Version Control and " + "has local modifications. Each descendant Process Group that is under Version Control must first be reverted or have its changes pushed to the Flow Registry before " + "this action can be performed on the parent Process Group."); } if (flowState == VersionedFlowState.SYNC_FAILURE) { throw new IllegalStateException("Process Group cannot " + action + " because it contains a child or descendant Process Group that is under Version Control and " + "is not synchronized with the Flow Registry. Each descendant Process Group must first be synchronized with the Flow Registry before this action can be " + "performed on the parent Process Group. NiFi will continue to attempt to communicate with the Flow Registry periodically in the background."); } } } } }
@Override public void verifyDeleteFlowRegistry(String registryId) { final ProcessGroup rootGroup = flowController.getFlowManager().getRootGroup(); final VersionControlInformation versionControlInformation = rootGroup.getVersionControlInformation(); if (versionControlInformation != null && versionControlInformation.getRegistryIdentifier().equals(registryId)) { throw new IllegalStateException("The Registry cannot be removed because a Process Group currently under version control is tracking to it."); } final Set<VersionControlInformation> trackedVersionControlInformation = rootGroup.findAllProcessGroups().stream() .map(group -> group.getVersionControlInformation()) .filter(Objects::nonNull) .filter(vci -> vci.getRegistryIdentifier().equals(registryId)) .collect(Collectors.toSet()); if (!trackedVersionControlInformation.isEmpty()) { throw new IllegalStateException("The Registry cannot be removed because a Process Group currently under version control is tracking to it."); } }
@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 ProcessGroupDAO processGroupDAO = getProcessGroupDAO(); final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId); final VersionControlInformation vci = processGroup.getVersionControlInformation(); 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(groupId, operation); return updatedProcessGroup; }
@Override public VersionedFlowStatus getStatus() { // If current state is a sync failure, then final String syncFailureExplanation = versionControlFields.getSyncFailureExplanation(); if (syncFailureExplanation != null) { return new StandardVersionedFlowStatus(VersionedFlowState.SYNC_FAILURE, syncFailureExplanation); } final boolean modified = isModified(); if (!modified) { final VersionControlInformation vci = StandardProcessGroup.this.versionControlInfo.get(); if (vci.getFlowSnapshot() == null) { return new StandardVersionedFlowStatus(VersionedFlowState.SYNC_FAILURE, "Process Group has not yet been synchronized with Flow Registry"); } } final boolean stale = versionControlFields.isStale(); final VersionedFlowState flowState; if (modified && stale) { flowState = VersionedFlowState.LOCALLY_MODIFIED_AND_STALE; } else if (modified) { flowState = VersionedFlowState.LOCALLY_MODIFIED; } else if (stale) { flowState = VersionedFlowState.STALE; } else { flowState = VersionedFlowState.UP_TO_DATE; } return new StandardVersionedFlowStatus(flowState, flowState.getDescription()); } };
if (versionControlInfo != null) { final VersionedFlowCoordinates coordinates = new VersionedFlowCoordinates(); final String registryId = versionControlInfo.getRegistryIdentifier(); final FlowRegistry registry = registryClient.getFlowRegistry(registryId); if (registry == null) { coordinates.setBucketId(versionControlInfo.getBucketIdentifier()); coordinates.setFlowId(versionControlInfo.getFlowIdentifier()); coordinates.setVersion(versionControlInfo.getVersion()); versionedGroup.setVersionedFlowCoordinates(coordinates);
private static void verifyNoDuplicateVersionControlInfoDtos(final ProcessGroup group, final Collection<VersionControlInformationDTO> snippetVcis) { final VersionControlInformation vci = group.getVersionControlInformation(); if (vci != null) { for (final VersionControlInformationDTO snippetVci : snippetVcis) { if (vci.getBucketIdentifier().equals(snippetVci.getBucketId()) && vci.getFlowIdentifier().equals(snippetVci.getFlowId())) { throw new IllegalArgumentException("Cannot place the given Process Group into the desired destination because the destination group or one of its ancestor groups is " + "under Version Control and one of the selected Process Groups is also under Version Control with the same Flow. A Process Group that is under Version Control " + "cannot contain a child Process Group that points to the same Versioned Flow."); } } } final ProcessGroup parent = group.getParent(); if (parent != null) { verifyNoDuplicateVersionControlInfoDtos(parent, snippetVcis); } }
switch (vci.getStatus().getState()) { case LOCALLY_MODIFIED: locallyModified++;
@Override public String getRegistryName() { final String registryId = versionControlInformation.getRegistryIdentifier(); final FlowRegistry registry = flowController.getFlowRegistryClient().getFlowRegistry(registryId); return registry == null ? registryId : registry.getName(); }
final int expectedVersion = currentVci == null ? 1 : currentVci.getVersion() + 1;
@Override public void setVersionControlInformation(final VersionControlInformation versionControlInformation, final Map<String, String> versionedComponentIds) { final StandardVersionControlInformation svci = new StandardVersionControlInformation( versionControlInformation.getRegistryIdentifier(), versionControlInformation.getRegistryName(), versionControlInformation.getBucketIdentifier(), versionControlInformation.getFlowIdentifier(), versionControlInformation.getVersion(), stripContentsFromRemoteDescendantGroups(versionControlInformation.getFlowSnapshot(), true), versionControlInformation.getStatus()) { svci.setBucketName(versionControlInformation.getBucketName()); svci.setFlowName(versionControlInformation.getFlowName()); svci.setFlowDescription(versionControlInformation.getFlowDescription()); final VersionedFlowState flowState = versionControlInformation.getStatus().getState(); versionControlFields.setStale(flowState == VersionedFlowState.STALE || flowState == VersionedFlowState.LOCALLY_MODIFIED_AND_STALE); versionControlFields.setLocallyModified(flowState == VersionedFlowState.LOCALLY_MODIFIED || flowState == VersionedFlowState.LOCALLY_MODIFIED_AND_STALE);
private void verifyImportProcessGroup(final VersionControlInformationDTO vciDto, final VersionedProcessGroup contents, final ProcessGroup group) { if (group == null) { return; } final VersionControlInformation vci = group.getVersionControlInformation(); if (vci != null) { // Note that we do not compare the Registry ID here because there could be two registry clients // that point to the same server (one could point to localhost while another points to 127.0.0.1, for instance).. if (Objects.equals(vciDto.getBucketId(), vci.getBucketIdentifier()) && Objects.equals(vciDto.getFlowId(), vci.getFlowIdentifier())) { throw new IllegalStateException("Cannot import the specified Versioned Flow into the Process Group because doing so would cause a recursive dataflow. " + "If Process Group A contains Process Group B, then Process Group B is not allowed to contain the flow identified by Process Group A."); } } final Set<VersionedProcessGroup> childGroups = contents.getProcessGroups(); if (childGroups != null) { for (final VersionedProcessGroup childGroup : childGroups) { final VersionedFlowCoordinates childCoordinates = childGroup.getVersionedFlowCoordinates(); if (childCoordinates != null) { final VersionControlInformationDTO childVci = new VersionControlInformationDTO(); childVci.setBucketId(childCoordinates.getBucketId()); childVci.setFlowId(childCoordinates.getFlowId()); verifyImportProcessGroup(childVci, childGroup, group); } } } verifyImportProcessGroup(vciDto, contents, group.getParent()); }