use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.
the class TestFlowController method testReloadProcessor.
@Test
public void testReloadProcessor() throws ProcessorInstantiationException {
final String id = "1234-ScheduledProcessor" + System.currentTimeMillis();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
final ProcessorNode processorNode = controller.createProcessor(DummyScheduledProcessor.class.getName(), id, coordinate);
final String originalName = processorNode.getName();
assertEquals(id, processorNode.getIdentifier());
assertEquals(id, processorNode.getComponent().getIdentifier());
assertEquals(coordinate.getCoordinate(), processorNode.getBundleCoordinate().getCoordinate());
assertEquals(DummyScheduledProcessor.class.getCanonicalName(), processorNode.getCanonicalClassName());
assertEquals(DummyScheduledProcessor.class.getSimpleName(), processorNode.getComponentType());
assertEquals(DummyScheduledProcessor.class.getCanonicalName(), processorNode.getComponent().getClass().getCanonicalName());
assertEquals(5, processorNode.getMaxConcurrentTasks());
assertEquals(SchedulingStrategy.CRON_DRIVEN, processorNode.getSchedulingStrategy());
assertEquals("0 0 0 1/1 * ?", processorNode.getSchedulingPeriod());
assertEquals("1 sec", processorNode.getYieldPeriod());
assertEquals("30 sec", processorNode.getPenalizationPeriod());
assertEquals(LogLevel.WARN, processorNode.getBulletinLevel());
// now change the type of the processor from DummyScheduledProcessor to DummySettingsProcessor
controller.reload(processorNode, DummySettingsProcessor.class.getName(), coordinate, Collections.emptySet());
// ids and coordinate should stay the same
assertEquals(id, processorNode.getIdentifier());
assertEquals(id, processorNode.getComponent().getIdentifier());
assertEquals(coordinate.getCoordinate(), processorNode.getBundleCoordinate().getCoordinate());
// in this test we happened to change between two processors that have different canonical class names
// but in the running application the DAO layer would call verifyCanUpdateBundle and would prevent this so
// for the sake of this test it is ok that the canonical class name hasn't changed
assertEquals(originalName, processorNode.getName());
assertEquals(DummyScheduledProcessor.class.getCanonicalName(), processorNode.getCanonicalClassName());
assertEquals(DummyScheduledProcessor.class.getSimpleName(), processorNode.getComponentType());
assertEquals(DummySettingsProcessor.class.getCanonicalName(), processorNode.getComponent().getClass().getCanonicalName());
// all these settings should have stayed the same
assertEquals(5, processorNode.getMaxConcurrentTasks());
assertEquals(SchedulingStrategy.CRON_DRIVEN, processorNode.getSchedulingStrategy());
assertEquals("0 0 0 1/1 * ?", processorNode.getSchedulingPeriod());
assertEquals("1 sec", processorNode.getYieldPeriod());
assertEquals("30 sec", processorNode.getPenalizationPeriod());
assertEquals(LogLevel.WARN, processorNode.getBulletinLevel());
}
use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.
the class TestFlowController method testReloadControllerService.
@Test
public void testReloadControllerService() {
final String id = "ServiceA" + System.currentTimeMillis();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, null, true);
final String originalName = controllerServiceNode.getName();
assertEquals(id, controllerServiceNode.getIdentifier());
assertEquals(id, controllerServiceNode.getComponent().getIdentifier());
assertEquals(coordinate.getCoordinate(), controllerServiceNode.getBundleCoordinate().getCoordinate());
assertEquals(ServiceA.class.getCanonicalName(), controllerServiceNode.getCanonicalClassName());
assertEquals(ServiceA.class.getSimpleName(), controllerServiceNode.getComponentType());
assertEquals(ServiceA.class.getCanonicalName(), controllerServiceNode.getComponent().getClass().getCanonicalName());
controller.reload(controllerServiceNode, ServiceB.class.getName(), coordinate, Collections.emptySet());
// ids and coordinate should stay the same
assertEquals(id, controllerServiceNode.getIdentifier());
assertEquals(id, controllerServiceNode.getComponent().getIdentifier());
assertEquals(coordinate.getCoordinate(), controllerServiceNode.getBundleCoordinate().getCoordinate());
// in this test we happened to change between two services that have different canonical class names
// but in the running application the DAO layer would call verifyCanUpdateBundle and would prevent this so
// for the sake of this test it is ok that the canonical class name hasn't changed
assertEquals(originalName, controllerServiceNode.getName());
assertEquals(ServiceA.class.getCanonicalName(), controllerServiceNode.getCanonicalClassName());
assertEquals(ServiceA.class.getSimpleName(), controllerServiceNode.getComponentType());
assertEquals(ServiceB.class.getCanonicalName(), controllerServiceNode.getComponent().getClass().getCanonicalName());
}
use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.
the class TestFlowController method testInstantiateSnippetWithDisabledProcessor.
@Test
public void testInstantiateSnippetWithDisabledProcessor() throws ProcessorInstantiationException {
final String id = UUID.randomUUID().toString();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
final ProcessorNode processorNode = controller.createProcessor(DummyProcessor.class.getName(), id, coordinate);
processorNode.disable();
// create a processor dto
final ProcessorDTO processorDTO = new ProcessorDTO();
// use a different id here
processorDTO.setId(UUID.randomUUID().toString());
processorDTO.setPosition(new PositionDTO(new Double(0), new Double(0)));
processorDTO.setStyle(processorNode.getStyle());
processorDTO.setParentGroupId("1234");
processorDTO.setInputRequirement(processorNode.getInputRequirement().name());
processorDTO.setPersistsState(processorNode.getProcessor().getClass().isAnnotationPresent(Stateful.class));
processorDTO.setRestricted(processorNode.isRestricted());
processorDTO.setExtensionMissing(processorNode.isExtensionMissing());
processorDTO.setType(processorNode.getCanonicalClassName());
processorDTO.setBundle(new BundleDTO(coordinate.getGroup(), coordinate.getId(), coordinate.getVersion()));
processorDTO.setName(processorNode.getName());
processorDTO.setState(processorNode.getScheduledState().toString());
processorDTO.setRelationships(new ArrayList<>());
processorDTO.setDescription("description");
processorDTO.setSupportsParallelProcessing(!processorNode.isTriggeredSerially());
processorDTO.setSupportsEventDriven(processorNode.isEventDrivenSupported());
processorDTO.setSupportsBatching(processorNode.isSessionBatchingSupported());
ProcessorConfigDTO configDTO = new ProcessorConfigDTO();
configDTO.setSchedulingPeriod(processorNode.getSchedulingPeriod());
configDTO.setPenaltyDuration(processorNode.getPenalizationPeriod());
configDTO.setYieldDuration(processorNode.getYieldPeriod());
configDTO.setRunDurationMillis(processorNode.getRunDuration(TimeUnit.MILLISECONDS));
configDTO.setConcurrentlySchedulableTaskCount(processorNode.getMaxConcurrentTasks());
configDTO.setLossTolerant(processorNode.isLossTolerant());
configDTO.setComments(processorNode.getComments());
configDTO.setBulletinLevel(processorNode.getBulletinLevel().name());
configDTO.setSchedulingStrategy(processorNode.getSchedulingStrategy().name());
configDTO.setExecutionNode(processorNode.getExecutionNode().name());
configDTO.setAnnotationData(processorNode.getAnnotationData());
processorDTO.setConfig(configDTO);
// create the snippet with the processor
final FlowSnippetDTO flowSnippetDTO = new FlowSnippetDTO();
flowSnippetDTO.setProcessors(Collections.singleton(processorDTO));
// instantiate the snippet
assertEquals(0, controller.getRootGroup().getProcessors().size());
controller.instantiateSnippet(controller.getRootGroup(), flowSnippetDTO);
assertEquals(1, controller.getRootGroup().getProcessors().size());
assertTrue(controller.getRootGroup().getProcessors().iterator().next().getScheduledState().equals(ScheduledState.DISABLED));
}
use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.
the class StandardProcessGroup method updateControllerService.
private void updateControllerService(final ControllerServiceNode service, final VersionedControllerService proposed) {
service.setAnnotationData(proposed.getAnnotationData());
service.setComments(proposed.getComments());
service.setName(proposed.getName());
final Map<String, String> properties = populatePropertiesMap(service.getProperties(), proposed.getProperties(), proposed.getPropertyDescriptors(), service.getProcessGroup());
service.setProperties(properties, true);
if (!isEqual(service.getBundleCoordinate(), proposed.getBundle())) {
final BundleCoordinate newBundleCoordinate = toCoordinate(proposed.getBundle());
final List<PropertyDescriptor> descriptors = new ArrayList<>(service.getProperties().keySet());
final Set<URL> additionalUrls = service.getAdditionalClasspathResources(descriptors);
flowController.reload(service, proposed.getType(), newBundleCoordinate, additionalUrls);
}
}
use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.
the class StandardProcessGroup method verifyCanUpdate.
@Override
public void verifyCanUpdate(final VersionedFlowSnapshot updatedFlow, final boolean verifyConnectionRemoval, final boolean verifyNotDirty) {
readLock.lock();
try {
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");
}
if (verifyNotDirty) {
final VersionedFlowState flowState = versionControlInfo.getStatus().getState();
final boolean modified = flowState == VersionedFlowState.LOCALLY_MODIFIED || flowState == VersionedFlowState.LOCALLY_MODIFIED_AND_STALE;
final Set<FlowDifference> modifications = getModifications();
if (modified) {
final String changes = modifications.stream().map(FlowDifference::toString).collect(Collectors.joining("\n"));
LOG.error("Cannot change the Version of the flow for {} because the Process Group has been modified ({} modifications) " + "since it was last synchronized with the Flow Registry. The following differences were found:\n{}", this, modifications.size(), changes);
throw new IllegalStateException("Cannot change the Version of the flow for " + this + " because the Process Group has been modified (" + modifications.size() + " modifications) since it was last synchronized with the Flow Registry. The Process Group must be" + " reverted to its original form before changing the version.");
}
}
verifyNoDescendantsWithLocalModifications("be updated");
}
final VersionedProcessGroup flowContents = updatedFlow.getFlowContents();
if (verifyConnectionRemoval) {
// Determine which Connections have been removed.
final Map<String, Connection> removedConnectionByVersionedId = new HashMap<>();
// Populate the 'removedConnectionByVersionId' map with all Connections. We key off of the connection's VersionedComponentID
// if it is populated. Otherwise, we key off of its actual ID. We do this because it allows us to then remove from this Map
// any connection that does exist in the proposed flow. This results in us having a Map whose values are those Connections
// that were removed. We can then check for any connections that have data in them. If any Connection is to be removed but
// has data, then we should throw an IllegalStateException.
findAllConnections().stream().forEach(conn -> removedConnectionByVersionedId.put(conn.getVersionedComponentId().orElse(conn.getIdentifier()), conn));
final Set<String> proposedFlowConnectionIds = new HashSet<>();
findAllConnectionIds(flowContents, proposedFlowConnectionIds);
for (final String proposedConnectionId : proposedFlowConnectionIds) {
removedConnectionByVersionedId.remove(proposedConnectionId);
}
// If any connection that was removed has data in it, throw an IllegalStateException
for (final Connection connection : removedConnectionByVersionedId.values()) {
final FlowFileQueue flowFileQueue = connection.getFlowFileQueue();
if (!flowFileQueue.isEmpty()) {
throw new IllegalStateException(this + " cannot be updated to the proposed version of the flow because the " + "proposed version does not contain " + connection + " and the connection currently has data in the queue.");
}
}
}
// Determine which input ports were removed from this process group
final Map<String, Port> removedInputPortsByVersionId = new HashMap<>();
getInputPorts().stream().filter(port -> port.getVersionedComponentId().isPresent()).forEach(port -> removedInputPortsByVersionId.put(port.getVersionedComponentId().get(), port));
flowContents.getInputPorts().stream().map(VersionedPort::getIdentifier).forEach(id -> removedInputPortsByVersionId.remove(id));
// Ensure that there are no incoming connections for any Input Port that was removed.
for (final Port inputPort : removedInputPortsByVersionId.values()) {
final List<Connection> incomingConnections = inputPort.getIncomingConnections();
if (!incomingConnections.isEmpty()) {
throw new IllegalStateException(this + " cannot be updated to the proposed version of the flow because the proposed version does not contain the Input Port " + inputPort + " and the Input Port currently has an incoming connections");
}
}
// Determine which output ports were removed from this process group
final Map<String, Port> removedOutputPortsByVersionId = new HashMap<>();
getOutputPorts().stream().filter(port -> port.getVersionedComponentId().isPresent()).forEach(port -> removedOutputPortsByVersionId.put(port.getVersionedComponentId().get(), port));
flowContents.getOutputPorts().stream().map(VersionedPort::getIdentifier).forEach(id -> removedOutputPortsByVersionId.remove(id));
// Ensure that there are no outgoing connections for any Output Port that was removed.
for (final Port outputPort : removedOutputPortsByVersionId.values()) {
final Set<Connection> outgoingConnections = outputPort.getConnections();
if (!outgoingConnections.isEmpty()) {
throw new IllegalStateException(this + " cannot be updated to the proposed version of the flow because the proposed version does not contain the Output Port " + outputPort + " and the Output Port currently has an outgoing connections");
}
}
// Find any Process Groups that may have been deleted. If we find any Process Group that was deleted, and that Process Group
// has Templates, then we fail because the Templates have to be removed first.
final Map<String, VersionedProcessGroup> proposedProcessGroups = new HashMap<>();
findAllProcessGroups(updatedFlow.getFlowContents(), proposedProcessGroups);
for (final ProcessGroup childGroup : findAllProcessGroups()) {
if (childGroup.getTemplates().isEmpty()) {
continue;
}
final Optional<String> versionedIdOption = childGroup.getVersionedComponentId();
if (!versionedIdOption.isPresent()) {
continue;
}
final String versionedId = versionedIdOption.get();
if (!proposedProcessGroups.containsKey(versionedId)) {
// Process Group was removed.
throw new IllegalStateException(this + " cannot be updated to the proposed version of the flow because the child " + childGroup + " that exists locally has one or more Templates, and the proposed flow does not contain these templates. " + "A Process Group cannot be deleted while it contains Templates. Please remove the Templates before attempting to change the version of the flow.");
}
}
// Ensure that all Processors are instantiate-able.
final Map<String, VersionedProcessor> proposedProcessors = new HashMap<>();
findAllProcessors(updatedFlow.getFlowContents(), proposedProcessors);
findAllProcessors().stream().filter(proc -> proc.getVersionedComponentId().isPresent()).forEach(proc -> proposedProcessors.remove(proc.getVersionedComponentId().get()));
for (final VersionedProcessor processorToAdd : proposedProcessors.values()) {
final BundleCoordinate coordinate = toCoordinate(processorToAdd.getBundle());
try {
flowController.createProcessor(processorToAdd.getType(), UUID.randomUUID().toString(), coordinate, false);
} catch (Exception e) {
throw new IllegalArgumentException("Unable to create Processor of type " + processorToAdd.getType(), e);
}
}
// Ensure that all Controller Services are instantiate-able.
final Map<String, VersionedControllerService> proposedServices = new HashMap<>();
findAllControllerServices(updatedFlow.getFlowContents(), proposedServices);
findAllControllerServices().stream().filter(service -> service.getVersionedComponentId().isPresent()).forEach(service -> proposedServices.remove(service.getVersionedComponentId().get()));
for (final VersionedControllerService serviceToAdd : proposedServices.values()) {
final BundleCoordinate coordinate = toCoordinate(serviceToAdd.getBundle());
try {
flowController.createControllerService(serviceToAdd.getType(), UUID.randomUUID().toString(), coordinate, Collections.emptySet(), false);
} catch (Exception e) {
throw new IllegalArgumentException("Unable to create Controller Service of type " + serviceToAdd.getType(), e);
}
}
// Ensure that all Prioritizers are instantiate-able.
final Map<String, VersionedConnection> proposedConnections = new HashMap<>();
findAllConnections(updatedFlow.getFlowContents(), proposedConnections);
findAllConnections().stream().filter(conn -> conn.getVersionedComponentId().isPresent()).forEach(conn -> proposedConnections.remove(conn.getVersionedComponentId().get()));
for (final VersionedConnection connectionToAdd : proposedConnections.values()) {
if (connectionToAdd.getPrioritizers() != null) {
for (final String prioritizerType : connectionToAdd.getPrioritizers()) {
try {
flowController.createPrioritizer(prioritizerType);
} catch (Exception e) {
throw new IllegalArgumentException("Unable to create Prioritizer of type " + prioritizerType, e);
}
}
}
}
} finally {
readLock.unlock();
}
}
Aggregations