mirror of https://github.com/apache/nifi.git
NIFI-4310 - added changes to support detection of reporting tasks and controller services during isEmpty flow check. Added testing scenarios. This closes #2107.
This commit is contained in:
parent
6c426f7a12
commit
0eda71a9a6
|
@ -22,6 +22,9 @@ import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -33,7 +36,9 @@ import java.util.concurrent.TimeUnit;
|
||||||
import org.apache.nifi.cluster.protocol.DataFlow;
|
import org.apache.nifi.cluster.protocol.DataFlow;
|
||||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||||
import org.apache.nifi.cluster.protocol.StandardDataFlow;
|
import org.apache.nifi.cluster.protocol.StandardDataFlow;
|
||||||
|
import org.apache.nifi.encrypt.StringEncryptor;
|
||||||
import org.apache.nifi.fingerprint.FingerprintFactory;
|
import org.apache.nifi.fingerprint.FingerprintFactory;
|
||||||
|
import org.apache.nifi.util.NiFiProperties;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
@ -134,6 +139,71 @@ public class TestPopularVoteFlowElection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoGeneratedVsPopulatedFlowElection() throws IOException {
|
||||||
|
final FingerprintFactory fingerprintFactory = new FingerprintFactory(StringEncryptor.createEncryptor(getNiFiProperties()));
|
||||||
|
final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 4, fingerprintFactory);
|
||||||
|
final byte[] emptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/auto-generated-empty-flow.xml"));
|
||||||
|
final byte[] nonEmptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/reporting-task-flow.xml"));
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
assertFalse(election.isElectionComplete());
|
||||||
|
assertNull(election.getElectedDataFlow());
|
||||||
|
|
||||||
|
final DataFlow dataFlow;
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
dataFlow = createDataFlow(emptyFlow);
|
||||||
|
} else {
|
||||||
|
dataFlow = createDataFlow(nonEmptyFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DataFlow electedDataFlow = election.castVote(dataFlow, createNodeId(i));
|
||||||
|
|
||||||
|
if (i == 3) {
|
||||||
|
assertNotNull(electedDataFlow);
|
||||||
|
assertEquals(new String(nonEmptyFlow), new String(electedDataFlow.getFlow()));
|
||||||
|
} else {
|
||||||
|
assertNull(electedDataFlow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDifferentPopulatedFlowsElection() throws IOException {
|
||||||
|
final FingerprintFactory fingerprintFactory = new FingerprintFactory(StringEncryptor.createEncryptor(getNiFiProperties()));
|
||||||
|
final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 4, fingerprintFactory);
|
||||||
|
final byte[] nonEmptyCandidateA = Files.readAllBytes(Paths.get("src/test/resources/conf/controller-service-flow.xml"));
|
||||||
|
final byte[] nonEmptyCandidateB = Files.readAllBytes(Paths.get("src/test/resources/conf/reporting-task-flow.xml"));
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
assertFalse(election.isElectionComplete());
|
||||||
|
assertNull(election.getElectedDataFlow());
|
||||||
|
|
||||||
|
final DataFlow dataFlow;
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
dataFlow = createDataFlow(nonEmptyCandidateA);
|
||||||
|
} else {
|
||||||
|
dataFlow = createDataFlow(nonEmptyCandidateB);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DataFlow electedDataFlow = election.castVote(dataFlow, createNodeId(i));
|
||||||
|
|
||||||
|
if (i == 3) {
|
||||||
|
assertNotNull(electedDataFlow);
|
||||||
|
assertEquals(new String(nonEmptyCandidateA), new String(electedDataFlow.getFlow()));
|
||||||
|
} else {
|
||||||
|
assertNull(electedDataFlow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NiFiProperties getNiFiProperties() {
|
||||||
|
final NiFiProperties nifiProperties = mock(NiFiProperties.class);
|
||||||
|
when(nifiProperties.getProperty(StringEncryptor.NF_SENSITIVE_PROPS_ALGORITHM)).thenReturn("PBEWITHMD5AND256BITAES-CBC-OPENSSL");
|
||||||
|
when(nifiProperties.getProperty(StringEncryptor.NF_SENSITIVE_PROPS_PROVIDER)).thenReturn("BC");
|
||||||
|
when(nifiProperties.getProperty(anyString(), anyString())).then(invocation -> invocation.getArgumentAt(1, String.class));
|
||||||
|
return nifiProperties;
|
||||||
|
}
|
||||||
|
|
||||||
private NodeIdentifier createNodeId(final int index) {
|
private NodeIdentifier createNodeId(final int index) {
|
||||||
return new NodeIdentifier(UUID.randomUUID().toString(), "localhost", 9000 + index, "localhost", 9000 + index, "localhost", 9000 + index, 9000 + index, true);
|
return new NodeIdentifier(UUID.randomUUID().toString(), "localhost", 9000 + index, "localhost", 9000 + index, "localhost", 9000 + index, 9000 + index, true);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<flowController encoding-version="1.1">
|
||||||
|
<maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
|
||||||
|
<maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
|
||||||
|
<rootGroup>
|
||||||
|
<id>ee207cce-015d-1000-30bf-36cd2fd1ea5c</id>
|
||||||
|
<name>NiFi Flow</name>
|
||||||
|
<position x="0.0" y="0.0"/>
|
||||||
|
<comment/>
|
||||||
|
</rootGroup>
|
||||||
|
<controllerServices/>
|
||||||
|
<reportingTasks/>
|
||||||
|
</flowController>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<flowController>
|
||||||
|
<maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
|
||||||
|
<maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
|
||||||
|
<rootGroup>
|
||||||
|
<id>778f676e-6542-4c18-9d06-24b6fd3a1b29</id>
|
||||||
|
<name>NiFi Flow</name>
|
||||||
|
<position x="0.0" y="0.0"/>
|
||||||
|
</rootGroup>
|
||||||
|
<controllerServices>
|
||||||
|
<controllerService>
|
||||||
|
<id>edf22ee5-376a-46dc-a38a-919351124457</id>
|
||||||
|
<name>ControllerService</name>
|
||||||
|
<comment/>
|
||||||
|
<class>org.apache.nifi.controller.service.mock.ServiceD</class>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
<property>
|
||||||
|
<name>Foo1</name>
|
||||||
|
<value>Bar1</value>
|
||||||
|
</property>
|
||||||
|
</controllerService>
|
||||||
|
</controllerServices>
|
||||||
|
</flowController>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<flowController>
|
||||||
|
<maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
|
||||||
|
<maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
|
||||||
|
<rootGroup>
|
||||||
|
<id>7c84501d-d10c-407c-b9f3-1d80e38fe36a</id>
|
||||||
|
<name>NiFi Flow</name>
|
||||||
|
<position x="0.0" y="0.0"/>
|
||||||
|
<comment/>
|
||||||
|
</rootGroup>
|
||||||
|
<controllerServices/>
|
||||||
|
<reportingTasks>
|
||||||
|
<reportingTask>
|
||||||
|
<id>3b80ba0f-a6c0-48db-b721-4dbc04cef28e</id>
|
||||||
|
<name>AmbariReportingTask</name>
|
||||||
|
<comment/>
|
||||||
|
<class>org.apache.nifi.reporting.ambari.AmbariReportingTask</class>
|
||||||
|
<bundle>
|
||||||
|
<group>org.apache.nifi</group>
|
||||||
|
<artifact>nifi-standard-nar</artifact>
|
||||||
|
<version>1.1.0</version>
|
||||||
|
</bundle>
|
||||||
|
<schedulingPeriod>{{nifi_ambari_reporting_frequency}}</schedulingPeriod>
|
||||||
|
<scheduledState>RUNNING</scheduledState>
|
||||||
|
<schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
|
||||||
|
<property>
|
||||||
|
<name>Metrics Collector URL</name>
|
||||||
|
<value>${ambari.metrics.collector.url}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>Application ID</name>
|
||||||
|
<value>${ambari.application.id}</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>Hostname</name>
|
||||||
|
<value>${hostname(true)}</value>
|
||||||
|
</property>
|
||||||
|
</reportingTask>
|
||||||
|
</reportingTasks>
|
||||||
|
</flowController>
|
|
@ -101,6 +101,7 @@ import org.apache.nifi.util.file.FileUtils;
|
||||||
import org.apache.nifi.web.api.dto.BundleDTO;
|
import org.apache.nifi.web.api.dto.BundleDTO;
|
||||||
import org.apache.nifi.web.api.dto.ConnectableDTO;
|
import org.apache.nifi.web.api.dto.ConnectableDTO;
|
||||||
import org.apache.nifi.web.api.dto.ConnectionDTO;
|
import org.apache.nifi.web.api.dto.ConnectionDTO;
|
||||||
|
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
|
||||||
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
||||||
import org.apache.nifi.web.api.dto.FunnelDTO;
|
import org.apache.nifi.web.api.dto.FunnelDTO;
|
||||||
import org.apache.nifi.web.api.dto.LabelDTO;
|
import org.apache.nifi.web.api.dto.LabelDTO;
|
||||||
|
@ -146,9 +147,15 @@ public class StandardFlowSynchronizer implements FlowSynchronizer {
|
||||||
|
|
||||||
final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
|
final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
|
||||||
final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(rootGroupElement);
|
final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(rootGroupElement);
|
||||||
|
|
||||||
final ProcessGroupDTO rootGroupDto = FlowFromDOMFactory.getProcessGroup(null, rootGroupElement, null, encodingVersion);
|
final ProcessGroupDTO rootGroupDto = FlowFromDOMFactory.getProcessGroup(null, rootGroupElement, null, encodingVersion);
|
||||||
return isEmpty(rootGroupDto);
|
|
||||||
|
final NodeList reportingTasks = rootElement.getElementsByTagName("reportingTask");
|
||||||
|
final ReportingTaskDTO reportingTaskDTO = reportingTasks.getLength() == 0 ? null : FlowFromDOMFactory.getReportingTask((Element)reportingTasks.item(0),null);
|
||||||
|
|
||||||
|
final NodeList controllerServices = rootElement.getElementsByTagName("controllerService");
|
||||||
|
final ControllerServiceDTO controllerServiceDTO = controllerServices.getLength() == 0 ? null : FlowFromDOMFactory.getControllerService((Element)controllerServices.item(0),null);
|
||||||
|
|
||||||
|
return isEmpty(rootGroupDto) && isEmpty(reportingTaskDTO) && isEmpty(controllerServiceDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -537,6 +544,18 @@ public class StandardFlowSynchronizer implements FlowSynchronizer {
|
||||||
&& CollectionUtils.isEmpty(contents.getRemoteProcessGroups());
|
&& CollectionUtils.isEmpty(contents.getRemoteProcessGroups());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isEmpty(final ReportingTaskDTO reportingTaskDTO){
|
||||||
|
|
||||||
|
return reportingTaskDTO == null || StringUtils.isEmpty(reportingTaskDTO.getName()) ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEmpty(final ControllerServiceDTO controllerServiceDTO){
|
||||||
|
|
||||||
|
return controllerServiceDTO == null || StringUtils.isEmpty(controllerServiceDTO.getName());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static Document parseFlowBytes(final byte[] flow) throws FlowSerializationException {
|
private static Document parseFlowBytes(final byte[] flow) throws FlowSerializationException {
|
||||||
// create document by parsing proposed flow bytes
|
// create document by parsing proposed flow bytes
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue