You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ex...@apache.org on 2022/08/30 13:39:11 UTC
[nifi] branch main updated: NIFI-10312 Fixed MiNiFi C2 status and Flow ID communication
This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new ff202122e3 NIFI-10312 Fixed MiNiFi C2 status and Flow ID communication
ff202122e3 is described below
commit ff202122e3faa417326a4374aa7799b30a3352d2
Author: rliszli <10...@users.noreply.github.com>
AuthorDate: Tue Aug 9 18:04:30 2022 +0200
NIFI-10312 Fixed MiNiFi C2 status and Flow ID communication
This closes #6281
Signed-off-by: David Handermann <ex...@apache.org>
---
.../nifi/c2/serializer/C2JacksonSerializer.java | 7 ++
.../c2/serializer/OperandTypeDeserializer.java | 44 +++++++
.../UpdateConfigurationOperationHandler.java | 43 ++++---
.../UpdateConfigurationOperationHandlerTest.java | 31 ++++-
.../apache/nifi/c2/protocol/api/OperandType.java | 1 -
.../nifi/minifi/c2/service/ConfigService.java | 4 +-
.../minifi/c2/service/SimpleC2ProtocolService.java | 7 +-
.../integration/c2/C2ProtocolIntegrationTest.java | 123 ++++++++++++++++++++
.../c2-authoritative/conf/authorities.yaml | 21 ++++
.../c2-authoritative/conf/authorizations.yaml | 52 +++++++++
.../protocol/c2-authoritative/conf/c2.properties | 27 +++++
.../c2-authoritative/conf/minifi-c2-context.xml | 63 ++++++++++
.../files/raspi3/config.text.yml.v1 | 129 +++++++++++++++++++++
.../files/raspi4/config.text.yml.v1 | 129 +++++++++++++++++++++
.../c2/protocol/minifi-edge1/bootstrap.conf | 125 ++++++++++++++++++++
.../c2/protocol/minifi-edge1/expected.json | 17 +++
.../c2/protocol/minifi-edge2/bootstrap.conf | 125 ++++++++++++++++++++
.../c2/protocol/minifi-edge2/expected.json | 17 +++
.../c2/protocol/minifi-edge3/bootstrap.conf | 125 ++++++++++++++++++++
.../c2/protocol/minifi-edge3/expected.json | 17 +++
.../test/resources/docker-compose-c2-protocol.yml | 100 ++++++++++++++++
.../src/test/resources/logback.xml | 12 +-
22 files changed, 1191 insertions(+), 28 deletions(-)
diff --git a/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/C2JacksonSerializer.java b/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/C2JacksonSerializer.java
index 03c3ad11d1..8fb81a6f9e 100644
--- a/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/C2JacksonSerializer.java
+++ b/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/C2JacksonSerializer.java
@@ -21,6 +21,9 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Optional;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.nifi.c2.protocol.api.OperandType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,6 +38,10 @@ public class C2JacksonSerializer implements C2Serializer {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+
+ SimpleModule module = new SimpleModule();
+ module.addDeserializer(OperandType.class, new OperandTypeDeserializer());
+ objectMapper.registerModule(module);
}
@Override
diff --git a/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/OperandTypeDeserializer.java b/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/OperandTypeDeserializer.java
new file mode 100644
index 0000000000..a3251237f5
--- /dev/null
+++ b/c2/c2-client-bundle/c2-client-base/src/main/java/org/apache/nifi/c2/serializer/OperandTypeDeserializer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.c2.serializer;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.apache.nifi.c2.protocol.api.OperandType;
+
+import java.io.IOException;
+
+public class OperandTypeDeserializer extends StdDeserializer<OperandType> {
+
+ public OperandTypeDeserializer() {
+ this(null);
+ }
+
+ public OperandTypeDeserializer(Class<?> vc) {
+ super(vc);
+ }
+
+ @Override
+ public OperandType deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+
+ return OperandType.fromString(node.textValue()).orElse(null);
+ }
+}
diff --git a/c2/c2-client-bundle/c2-client-service/src/main/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandler.java b/c2/c2-client-bundle/c2-client-service/src/main/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandler.java
index a597abe189..dc1d15f610 100644
--- a/c2/c2-client-bundle/c2-client-service/src/main/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandler.java
+++ b/c2/c2-client-bundle/c2-client-service/src/main/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandler.java
@@ -21,6 +21,7 @@ import static org.apache.nifi.c2.protocol.api.OperandType.CONFIGURATION;
import static org.apache.nifi.c2.protocol.api.OperationType.UPDATE;
import java.net.URI;
+import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Matcher;
@@ -36,10 +37,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UpdateConfigurationOperationHandler implements C2OperationHandler {
-
private static final Logger logger = LoggerFactory.getLogger(UpdateConfigurationOperationHandler.class);
private static final Pattern FLOW_ID_PATTERN = Pattern.compile("/[^/]+?/[^/]+?/[^/]+?/([^/]+)?/?.*");
-
+ static final String FLOW_ID = "flowId";
static final String LOCATION = "location";
private final C2Client client;
@@ -75,30 +75,44 @@ public class UpdateConfigurationOperationHandler implements C2OperationHandler {
.map(map -> map.get(LOCATION))
.orElse(EMPTY);
- String newFlowId = parseFlowId(updateLocation);
- if (flowIdHolder.getFlowId() == null || !flowIdHolder.getFlowId().equals(newFlowId)) {
- logger.info("Will perform flow update from {} for operation #{}. Previous flow id was {}, replacing with new id {}", updateLocation, opIdentifier,
- flowIdHolder.getFlowId() == null ? "not set" : flowIdHolder.getFlowId(), newFlowId);
+ String flowId = getFlowId(operation.getArgs(), updateLocation);
+ if (flowId == null) {
+ state.setState(C2OperationState.OperationState.NOT_APPLIED);
+ state.setDetails("Could not get flowId from the operation.");
+ logger.info("FlowId is missing, no update will be performed.");
} else {
- logger.info("Flow is current, no update is necessary...");
+ if (flowIdHolder.getFlowId() == null || !flowIdHolder.getFlowId().equals(flowId)) {
+ logger.info("Will perform flow update from {} for operation #{}. Previous flow id was {}, replacing with new id {}", updateLocation, opIdentifier,
+ flowIdHolder.getFlowId() == null ? "not set" : flowIdHolder.getFlowId(), flowId);
+ } else {
+ logger.info("Flow is current, no update is necessary...");
+ }
+ flowIdHolder.setFlowId(flowId);
+ state.setState(updateFlow(opIdentifier, updateLocation));
}
+ return operationAck;
+ }
- flowIdHolder.setFlowId(newFlowId);
+ private C2OperationState.OperationState updateFlow(String opIdentifier, String updateLocation) {
Optional<byte[]> updateContent = client.retrieveUpdateContent(updateLocation);
if (updateContent.isPresent()) {
if (updateFlow.apply(updateContent.get())) {
- state.setState(C2OperationState.OperationState.FULLY_APPLIED);
logger.debug("Update configuration applied for operation #{}.", opIdentifier);
+ return C2OperationState.OperationState.FULLY_APPLIED;
} else {
- state.setState(C2OperationState.OperationState.NOT_APPLIED);
logger.error("Update resulted in error for operation #{}.", opIdentifier);
+ return C2OperationState.OperationState.NOT_APPLIED;
}
} else {
- state.setState(C2OperationState.OperationState.NOT_APPLIED);
logger.error("Update content retrieval resulted in empty content so flow update was omitted for operation #{}.", opIdentifier);
+ return C2OperationState.OperationState.NOT_APPLIED;
}
+ }
- return operationAck;
+ private String getFlowId(Map<String, String> args, String updateLocation) {
+ return Optional.ofNullable(args)
+ .map(map -> map.get(FLOW_ID))
+ .orElseGet(() -> parseFlowId(updateLocation));
}
private String parseFlowId(String flowUpdateUrl) {
@@ -108,11 +122,10 @@ public class UpdateConfigurationOperationHandler implements C2OperationHandler {
if (matcher.matches()) {
return matcher.group(1);
- } else {
- throw new IllegalArgumentException(String.format("Flow Update URL format unexpected [%s]", flowUpdateUrl));
}
} catch (Exception e) {
- throw new IllegalStateException("Could not get flow id from the provided URL", e);
+ logger.error("Could not get flow id from the provided URL, flow update URL format unexpected [{}]", flowUpdateUrl);
}
+ return null;
}
}
diff --git a/c2/c2-client-bundle/c2-client-service/src/test/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandlerTest.java b/c2/c2-client-bundle/c2-client-service/src/test/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandlerTest.java
index 17b18a0f44..a37fc64998 100644
--- a/c2/c2-client-bundle/c2-client-service/src/test/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandlerTest.java
+++ b/c2/c2-client-bundle/c2-client-service/src/test/java/org/apache/nifi/c2/client/service/operation/UpdateConfigurationOperationHandlerTest.java
@@ -18,12 +18,13 @@ package org.apache.nifi.c2.client.service.operation;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.nifi.c2.client.service.operation.UpdateConfigurationOperationHandler.LOCATION;
+import static org.apache.nifi.c2.client.service.operation.UpdateConfigurationOperationHandler.FLOW_ID;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@@ -41,8 +42,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class UpdateConfigurationOperationHandlerTest {
-
- private static final String FLOW_ID = "flowId";
private static final String OPERATION_ID = "operationId";
private static final Map<String, String> CORRECT_LOCATION_MAP = Collections.singletonMap(LOCATION, "/path/for/the/" + FLOW_ID);
private static final Map<String, String> INCORRECT_LOCATION_MAP = Collections.singletonMap(LOCATION, "incorrect/location");
@@ -62,12 +61,34 @@ public class UpdateConfigurationOperationHandlerTest {
}
@Test
- void testHandleThrowsExceptionForIncorrectArg() {
+ void testHandleIncorrectArg() {
UpdateConfigurationOperationHandler handler = new UpdateConfigurationOperationHandler(null, null, null);
C2Operation operation = new C2Operation();
operation.setArgs(INCORRECT_LOCATION_MAP);
- IllegalStateException exception = assertThrows(IllegalStateException.class, () -> handler.handle(operation));
+ C2OperationAck response = handler.handle(operation);
+
+ assertEquals(C2OperationState.OperationState.NOT_APPLIED, response.getOperationState().getState());
+ }
+
+ @Test
+ void testHandleFlowIdInArg() {
+ Function<byte[], Boolean> successUpdate = x -> true;
+ when(flowIdHolder.getFlowId()).thenReturn(FLOW_ID);
+ when(client.retrieveUpdateContent(any())).thenReturn(Optional.of("content".getBytes()));
+ UpdateConfigurationOperationHandler handler = new UpdateConfigurationOperationHandler(client, flowIdHolder, successUpdate);
+ C2Operation operation = new C2Operation();
+ operation.setIdentifier(OPERATION_ID);
+
+ Map<String, String> args = new HashMap<>();
+ args.putAll(INCORRECT_LOCATION_MAP);
+ args.put(FLOW_ID, "argsFlowId");
+ operation.setArgs(args);
+
+ C2OperationAck response = handler.handle(operation);
+
+ assertEquals(OPERATION_ID, response.getOperationId());
+ assertEquals(C2OperationState.OperationState.FULLY_APPLIED, response.getOperationState().getState());
}
@Test
diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/OperandType.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/OperandType.java
index 389d3bed5a..4638f33b44 100644
--- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/OperandType.java
+++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/OperandType.java
@@ -39,4 +39,3 @@ public enum OperandType {
return super.toString().toLowerCase();
}
}
-
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
index 9b70fba527..59d048320d 100644
--- a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
@@ -228,8 +228,8 @@ public class ConfigService {
try {
configuration = configurationProviderValue.getConfiguration();
} catch (ConfigurationProviderException cpe) {
- logger.warn("No flow available for agent class " + agentClass + ", returning No Content (204)");
- response = Response.noContent().build();
+ logger.warn("No flow available for agent class " + agentClass + ", returning OK (200) with no update request");
+ response = Response.ok(new C2HeartbeatResponse()).build();
return response;
}
try (InputStream inputStream = configuration.getInputStream();
diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/SimpleC2ProtocolService.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/SimpleC2ProtocolService.java
index c26e0449bf..132fc8df3d 100644
--- a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/SimpleC2ProtocolService.java
+++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/SimpleC2ProtocolService.java
@@ -42,6 +42,8 @@ public class SimpleC2ProtocolService implements C2ProtocolService {
private static final Logger logger = LoggerFactory.getLogger(SimpleC2ProtocolService.class);
private static final Set<String> issuedOperationIds = new HashSet<>();
+ private static final String LOCATION = "location";
+ private static final String FLOW_ID = "flowId";
private final Map<String, String> currentFlowIds;
@@ -108,7 +110,10 @@ public class SimpleC2ProtocolService implements C2ProtocolService {
c2Operation.setIdentifier(operationID);
c2Operation.setOperation(OperationType.UPDATE);
c2Operation.setOperand(OperandType.CONFIGURATION);
- c2Operation.setArgs(Collections.singletonMap("location", context.getBaseUri().toString()));
+ Map<String, String> args = new HashMap<>();
+ args.put(LOCATION, context.getBaseUri().toString());
+ args.put(FLOW_ID, context.getSha256());
+ c2Operation.setArgs(args);
List<C2Operation> requestedOperations = Collections.singletonList(c2Operation);
c2HeartbeatResponse.setRequestedOperations(requestedOperations);
currentFlowIds.put(heartbeat.getAgentId(), context.getSha256());
diff --git a/minifi/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/C2ProtocolIntegrationTest.java b/minifi/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/C2ProtocolIntegrationTest.java
new file mode 100644
index 0000000000..a8eaa692fa
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/C2ProtocolIntegrationTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.minifi.integration.c2;
+
+import com.palantir.docker.compose.DockerComposeExtension;
+import com.palantir.docker.compose.connection.waiting.HealthChecks;
+import org.apache.nifi.minifi.integration.util.LogUtil;
+import org.apache.nifi.security.util.KeystoreType;
+import org.apache.nifi.security.util.SslContextFactory;
+import org.apache.nifi.security.util.StandardTlsConfiguration;
+import org.apache.nifi.security.util.TlsConfiguration;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandalone;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandaloneCommandLine;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Timeout(60)
+public class C2ProtocolIntegrationTest {
+ private static final String AGENT_1 = "minifi-edge1";
+ private static final String AGENT_2 = "minifi-edge2";
+ private static final String AGENT_3 = "minifi-edge3";
+ private static final String AGENT_CLASS_1 = "raspi3";
+ private static final String AGENT_CLASS_2 = "raspi4";
+ private static final String SERVICE = "c2-authoritative";
+ private static final String CONFIG_YAML = "config.text.yml.v2";
+ private static Path certificatesDirectory;
+ private static SSLContext trustSslContext;
+ private static SSLSocketFactory healthCheckSocketFactory;
+ public static DockerComposeExtension docker = DockerComposeExtension.builder()
+ .file("target/test-classes/docker-compose-c2-protocol.yml")
+ .waitingForService(AGENT_1, HealthChecks.toRespond2xxOverHttp(8000, dockerPort -> "http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort()))
+ .waitingForService(AGENT_2, HealthChecks.toRespond2xxOverHttp(8000, dockerPort -> "http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort()))
+ .waitingForService(AGENT_3, HealthChecks.toRespond2xxOverHttp(8000, dockerPort -> "http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort()))
+ .build();
+
+ private static Path resourceDirectory;
+ private static Path authoritativeFiles;
+ private static Path minifiEdge1Version2;
+ private static Path minifiEdge2Version2;
+ private static Path minifiEdge3Version2;
+
+ /**
+ * Generates certificates with the tls-toolkit and then starts up the docker compose file
+ */
+ @BeforeAll
+ public static void init() throws Exception {
+ resourceDirectory = Paths.get(C2ProtocolIntegrationTest.class.getClassLoader()
+ .getResource("docker-compose-c2-protocol.yml").getFile()).getParent();
+ certificatesDirectory = resourceDirectory.toAbsolutePath().resolve("certificates-c2-protocol");
+ authoritativeFiles = resourceDirectory.resolve("c2").resolve("protocol").resolve(SERVICE).resolve("files");
+ minifiEdge1Version2 = authoritativeFiles.resolve("edge1").resolve(AGENT_CLASS_1).resolve(CONFIG_YAML);
+ minifiEdge2Version2 = authoritativeFiles.resolve("edge2").resolve(AGENT_CLASS_1).resolve(CONFIG_YAML);
+ minifiEdge3Version2 = authoritativeFiles.resolve("edge3").resolve(AGENT_CLASS_2).resolve(CONFIG_YAML);
+
+ if (Files.exists(minifiEdge1Version2)) {
+ Files.delete(minifiEdge1Version2);
+ }
+ if (Files.exists(minifiEdge2Version2)) {
+ Files.delete(minifiEdge2Version2);
+ }
+ if (Files.exists(minifiEdge3Version2)) {
+ Files.delete(minifiEdge3Version2);
+ }
+
+ List<String> toolkitCommandLine = new ArrayList<>(Arrays.asList("-O", "-o", certificatesDirectory.toFile().getAbsolutePath(), "-S", "badKeystorePass", "-P", "badTrustPass"));
+ for (String serverHostname : Arrays.asList(SERVICE, AGENT_1, AGENT_2, AGENT_3)) {
+ toolkitCommandLine.add("-n");
+ toolkitCommandLine.add(serverHostname);
+ }
+ Files.createDirectories(certificatesDirectory);
+ TlsToolkitStandaloneCommandLine tlsToolkitStandaloneCommandLine = new TlsToolkitStandaloneCommandLine();
+ tlsToolkitStandaloneCommandLine.parse(toolkitCommandLine.toArray(new String[toolkitCommandLine.size()]));
+ new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.createConfig());
+
+ TlsConfiguration tlsConfiguration = new StandardTlsConfiguration(
+ null,null,null,
+ certificatesDirectory.resolve(SERVICE).resolve("truststore.jks").toFile().getAbsolutePath(),
+ "badTrustPass",
+ KeystoreType.JKS);
+ trustSslContext = SslContextFactory.createSslContext(tlsConfiguration);
+ healthCheckSocketFactory = trustSslContext.getSocketFactory();
+
+ docker.before();
+ }
+
+ @AfterAll
+ public static void stopDocker() {
+ docker.after();
+ }
+
+ @Test
+ public void testFlowPublishThroughC2Protocol() throws Exception {
+ LogUtil.verifyLogEntries("c2/protocol/minifi-edge1/expected.json", docker.containers().container(AGENT_1));
+ LogUtil.verifyLogEntries("c2/protocol/minifi-edge2/expected.json", docker.containers().container(AGENT_2));
+ LogUtil.verifyLogEntries("c2/protocol/minifi-edge3/expected.json", docker.containers().container(AGENT_3));
+ }
+}
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/authorities.yaml b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/authorities.yaml
new file mode 100644
index 0000000000..0e402f77f6
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/authorities.yaml
@@ -0,0 +1,21 @@
+# 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.
+
+CN=minifi-edge1, OU=NIFI:
+ - EDGE_1
+CN=minifi-edge2, OU=NIFI:
+ - EDGE_2
+CN=minifi-edge3, OU=NIFI:
+ - EDGE_3
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/authorizations.yaml b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/authorizations.yaml
new file mode 100644
index 0000000000..814884855d
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/authorizations.yaml
@@ -0,0 +1,52 @@
+# 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.
+
+Default Action: deny
+Paths:
+ /c2/config:
+ Default Action: deny
+ Actions:
+ - Authorization: EDGE_1
+ Query Parameters:
+ class: raspi3
+ Action: allow
+ - Authorization: EDGE_2
+ Query Parameters:
+ class: raspi3
+ Action: allow
+ - Authorization: EDGE_3
+ Query Parameters:
+ class: raspi4
+ Action: allow
+
+ /c2/config/heartbeat:
+ Default Action: deny
+ Actions:
+ - Authorization: EDGE_1
+ Action: allow
+ - Authorization: EDGE_2
+ Action: allow
+ - Authorization: EDGE_3
+ Action: allow
+
+ /c2/config/acknowledge:
+ Default Action: deny
+ Actions:
+ - Authorization: EDGE_1
+ Action: allow
+ - Authorization: EDGE_2
+ Action: allow
+ - Authorization: EDGE_3
+ Action: allow
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/c2.properties b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/c2.properties
new file mode 100644
index 0000000000..d1b01ee7bf
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/c2.properties
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+minifi.c2.server.port=10443
+
+minifi.c2.server.secure=true
+minifi.c2.server.keystore=./conf/keystore.jks
+minifi.c2.server.keystoreType=JKS
+minifi.c2.server.keystorePasswd=badKeystorePass
+minifi.c2.server.keyPasswd=badKeystorePass
+minifi.c2.server.truststore=./conf/truststore.jks
+minifi.c2.server.truststoreType=JKS
+minifi.c2.server.truststorePasswd=badTrustPass
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/minifi-c2-context.xml b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/minifi-c2-context.xml
new file mode 100644
index 0000000000..44ef049fc7
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/conf/minifi-c2-context.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<beans default-lazy-init="true"
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
+
+ <bean id="configService" class="org.apache.nifi.minifi.c2.service.ConfigService" scope="singleton">
+ <constructor-arg>
+ <list>
+ <bean class="org.apache.nifi.minifi.c2.provider.cache.CacheConfigurationProvider">
+ <constructor-arg>
+ <list>
+ <value>text/yml</value>
+ </list>
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./files</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${class}/config</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ </bean>
+ </list>
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.security.authorization.GrantedAuthorityAuthorizer">
+ <constructor-arg value="classpath:authorizations.yaml"/>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>1000</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>1000</value>
+ </constructor-arg>
+ </bean>
+</beans>
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/files/raspi3/config.text.yml.v1 b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/files/raspi3/config.text.yml.v1
new file mode 100644
index 0000000000..1d5bdf9c4f
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/files/raspi3/config.text.yml.v1
@@ -0,0 +1,129 @@
+# 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.
+
+MiNiFi Config Version: 3
+Flow Controller:
+ name: Edge raspi3 v1.0
+ comment: ''
+Core Properties:
+ flow controller graceful shutdown period: 10 sec
+ flow service write delay interval: 500 ms
+ administrative yield duration: 30 sec
+ bored yield duration: 10 millis
+ max concurrent threads: 1
+ variable registry properties: ''
+FlowFile Repository:
+ implementation: org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
+ partitions: 256
+ checkpoint interval: 2 mins
+ always sync: false
+ Swap:
+ threshold: 20000
+ in period: 5 sec
+ in threads: 1
+ out period: 5 sec
+ out threads: 4
+Content Repository:
+ implementation: org.apache.nifi.controller.repository.FileSystemRepository
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ content repository archive enabled: false
+ content repository archive max retention period: 12 hours
+ content repository archive max usage percentage: 50%
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+ implementation: org.apache.nifi.provenance.WriteAheadProvenanceRepository
+ provenance index shard size: 500 MB
+ provenance max storage size: 1 GB
+ provenance max storage time: 24 hours
+ provenance buffer size: 10000
+Component Status Repository:
+ buffer size: 1440
+ snapshot frequency: 1 min
+Security Properties:
+ keystore: ''
+ keystore type: ''
+ keystore password: ''
+ key password: ''
+ truststore: ''
+ truststore type: ''
+ truststore password: ''
+ ssl protocol: ''
+ Sensitive Props:
+ key: ''
+ algorithm: NIFI_PBKDF2_AES_GCM_256
+Processors:
+- id: c6a06b10-0af2-423b-9927-0bb8e6e04bc3
+ name: GenerateTestText
+ class: org.apache.nifi.processors.standard.GenerateFlowFile
+ max concurrent tasks: 1
+ scheduling strategy: TIMER_DRIVEN
+ scheduling period: 1000 ms
+ penalization period: 30000 ms
+ yield period: 1000 ms
+ run duration nanos: 0
+ auto-terminated relationships list: [
+ ]
+ Properties:
+ Batch Size: '1'
+ Data Format: Text
+ File Size: 0B
+ Unique FlowFiles: 'false'
+ character-set: UTF-8
+ generate-ff-custom-text: __testTextRaspi3__
+- id: 186322b1-4778-40e4-ba9d-a0a511d762f7
+ name: LogAttribute
+ class: org.apache.nifi.processors.standard.LogAttribute
+ max concurrent tasks: 1
+ scheduling strategy: TIMER_DRIVEN
+ scheduling period: 1000 ms
+ penalization period: 30000 ms
+ yield period: 1000 ms
+ run duration nanos: 0
+ auto-terminated relationships list:
+ - success
+ Properties:
+ Log FlowFile Properties: 'true'
+ Log Level: info
+ Log Payload: 'true'
+ Output Format: Line per Attribute
+ attributes-to-log-regex: .*
+ character-set: UTF-8
+Controller Services: [
+ ]
+Process Groups: [
+ ]
+Input Ports: [
+ ]
+Output Ports: [
+ ]
+Funnels: [
+ ]
+Connections:
+- id: 641b0183-8653-4988-9a74-bcf9780b1397
+ name: GenerateTestText/success/LogAttribute
+ source id: c6a06b10-0af2-423b-9927-0bb8e6e04bc3
+ source relationship names:
+ - success
+ destination id: 186322b1-4778-40e4-ba9d-a0a511d762f7
+ max work queue size: 10000
+ max work queue data size: 10 MB
+ flowfile expiration: 0 seconds
+ queue prioritizer class: ''
+Remote Process Groups: [
+ ]
+NiFi Properties Overrides: {
+ }
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/files/raspi4/config.text.yml.v1 b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/files/raspi4/config.text.yml.v1
new file mode 100644
index 0000000000..fc528ae7a2
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/c2-authoritative/files/raspi4/config.text.yml.v1
@@ -0,0 +1,129 @@
+# 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.
+
+MiNiFi Config Version: 3
+Flow Controller:
+ name: Edge raspi4 v1.0
+ comment: ''
+Core Properties:
+ flow controller graceful shutdown period: 10 sec
+ flow service write delay interval: 500 ms
+ administrative yield duration: 30 sec
+ bored yield duration: 10 millis
+ max concurrent threads: 1
+ variable registry properties: ''
+FlowFile Repository:
+ implementation: org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
+ partitions: 256
+ checkpoint interval: 2 mins
+ always sync: false
+ Swap:
+ threshold: 20000
+ in period: 5 sec
+ in threads: 1
+ out period: 5 sec
+ out threads: 4
+Content Repository:
+ implementation: org.apache.nifi.controller.repository.FileSystemRepository
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ content repository archive enabled: false
+ content repository archive max retention period: 12 hours
+ content repository archive max usage percentage: 50%
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+ implementation: org.apache.nifi.provenance.WriteAheadProvenanceRepository
+ provenance index shard size: 500 MB
+ provenance max storage size: 1 GB
+ provenance max storage time: 24 hours
+ provenance buffer size: 10000
+Component Status Repository:
+ buffer size: 1440
+ snapshot frequency: 1 min
+Security Properties:
+ keystore: ''
+ keystore type: ''
+ keystore password: ''
+ key password: ''
+ truststore: ''
+ truststore type: ''
+ truststore password: ''
+ ssl protocol: ''
+ Sensitive Props:
+ key: ''
+ algorithm: NIFI_PBKDF2_AES_GCM_256
+Processors:
+- id: 6ef15904-e69e-425b-b4a9-427c367220a3
+ name: GenerateFlowFile
+ class: org.apache.nifi.processors.standard.GenerateFlowFile
+ max concurrent tasks: 1
+ scheduling strategy: TIMER_DRIVEN
+ scheduling period: 1000 ms
+ penalization period: 30000 ms
+ yield period: 1000 ms
+ run duration nanos: 0
+ auto-terminated relationships list: [
+ ]
+ Properties:
+ Batch Size: '1'
+ Data Format: Text
+ File Size: 0B
+ Unique FlowFiles: 'false'
+ character-set: UTF-8
+ generate-ff-custom-text: __testTextRaspi4__
+- id: 26f9038d-2cd9-4df3-a174-c48dda90fce7
+ name: LogAttribute
+ class: org.apache.nifi.processors.standard.LogAttribute
+ max concurrent tasks: 1
+ scheduling strategy: TIMER_DRIVEN
+ scheduling period: 0 ms
+ penalization period: 30000 ms
+ yield period: 1000 ms
+ run duration nanos: 0
+ auto-terminated relationships list:
+ - success
+ Properties:
+ Log FlowFile Properties: 'true'
+ Log Level: info
+ Log Payload: 'true'
+ Output Format: Line per Attribute
+ attributes-to-log-regex: .*
+ character-set: UTF-8
+Controller Services: [
+ ]
+Process Groups: [
+ ]
+Input Ports: [
+ ]
+Output Ports: [
+ ]
+Funnels: [
+ ]
+Connections:
+- id: 68ebc161-1b82-472b-a2f6-ee4173033f60
+ name: GenerateFlowFile/success/LogAttribute
+ source id: 6ef15904-e69e-425b-b4a9-427c367220a3
+ source relationship names:
+ - success
+ destination id: 26f9038d-2cd9-4df3-a174-c48dda90fce7
+ max work queue size: 10000
+ max work queue data size: 10 MB
+ flowfile expiration: 0 seconds
+ queue prioritizer class: ''
+Remote Process Groups: [
+ ]
+NiFi Properties Overrides: {
+ }
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge1/bootstrap.conf b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge1/bootstrap.conf
new file mode 100644
index 0000000000..35a14acc94
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge1/bootstrap.conf
@@ -0,0 +1,125 @@
+#
+# 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.
+#
+
+# C2 Properties
+c2.enable=true
+c2.rest.url=https://c2-authoritative:10443/c2/config/heartbeat
+c2.rest.url.ack=https://c2-authoritative:10443/c2/config/acknowledge
+c2.rest.connectionTimeout=5 sec
+c2.rest.readTimeout=5 sec
+c2.rest.callTimeout=10 sec
+c2.agent.heartbeat.period=2000
+c2.agent.class=raspi3
+c2.config.directory=./conf
+c2.runtime.manifest.identifier=minifi
+c2.runtime.type=minifi-java
+c2.security.truststore.location=./conf/truststore.jks
+c2.security.truststore.password=badTrustPass
+c2.security.truststore.type=JKS
+c2.security.keystore.location=./conf/keystore.jks
+c2.security.keystore.password=badKeystorePass
+c2.security.keystore.type=JKS
+
+# Java command to use when running MiNiFi
+java=java
+
+# Username to use when running MiNiFi. This value will be ignored on Windows.
+run.as=
+
+# Configure where MiNiFi's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling MiNiFi to shutdown before explicitly killing the Process
+graceful.shutdown.seconds=20
+
+# The location for the configuration file
+nifi.minifi.config=./conf/config.yml
+
+# Notifiers to use for the associated agent, comma separated list of class names
+nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.FileChangeIngestor
+#nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.RestChangeIngestor
+#nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.PullHttpChangeIngestor
+
+# File change notifier configuration
+
+# Path of the file to monitor for changes. When these occur, the FileChangeNotifier, if configured, will begin the configuration reloading process
+nifi.minifi.notifier.ingestors.file.config.path=./conf/config-new.yml
+# How frequently the file specified by 'nifi.minifi.notifier.file.config.path' should be evaluated for changes.
+nifi.minifi.notifier.ingestors.file.polling.period.seconds=2
+
+# Rest change notifier configuration
+
+# Port on which the Jetty server will bind to, keep commented for a random open port
+#nifi.minifi.notifier.ingestors.receive.http.port=8338
+
+#Pull HTTP change notifier configuration
+
+# Hostname on which to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.hostname=c2-authoritative
+# Port on which to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.port=10443
+# Path to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.path=/c2/config
+# Query string to pull configurations with
+# nifi.minifi.notifier.ingestors.pull.http.query=net=edge1&class=raspi3
+# Period on which to pull configurations from, defaults to 5 minutes if commented out
+# nifi.minifi.notifier.ingestors.pull.http.period.ms=3000
+
+# nifi.minifi.notifier.ingestors.pull.http.keystore.location=./conf/keystore.jks
+# nifi.minifi.notifier.ingestors.pull.http.keystore.type=JKS
+# nifi.minifi.notifier.ingestors.pull.http.keystore.password=badKeystorePass
+# nifi.minifi.notifier.ingestors.pull.http.truststore.location=./conf/truststore.jks
+# nifi.minifi.notifier.ingestors.pull.http.truststore.type=JKS
+# nifi.minifi.notifier.ingestors.pull.http.truststore.password=badTrustPass
+
+# Periodic Status Reporters to use for the associated agent, comma separated list of class names
+#nifi.minifi.status.reporter.components=org.apache.nifi.minifi.bootstrap.status.reporters.StatusLogger
+
+# Periodic Status Logger configuration
+
+# The FlowStatus query to submit to the MiNiFi instance
+#nifi.minifi.status.reporter.log.query=instance:health,bulletins
+# The log level at which the status will be logged
+#nifi.minifi.status.reporter.log.level=INFO
+# The period (in milliseconds) at which to log the status
+#nifi.minifi.status.reporter.log.period=60000
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms256m
+java.arg.3=-Xmx256m
+
+# Enable Remote Debugging
+# java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# The G1GC is still considered experimental but has proven to be very advantageous in providing great
+# performance without significant "stop-the-world" delays.
+#java.arg.13=-XX:+UseG1GC
+
+#Set headless mode by default
+java.arg.14=-Djava.awt.headless=true
+
+java.arg.15=-Djava.security.egd=file:/dev/./urandom
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge1/expected.json b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge1/expected.json
new file mode 100644
index 0000000000..3738fc5e7d
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge1/expected.json
@@ -0,0 +1,17 @@
+[
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config/heartbeat"
+ },
+ {
+ "pattern": "\"operation\":\"UPDATE\",\"operand\":\"CONFIGURATION\""
+ },
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config\\?class=raspi3"
+ },
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config/acknowledge"
+ },
+ {
+ "pattern": "^__testTextRaspi3__$"
+ }
+]
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge2/bootstrap.conf b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge2/bootstrap.conf
new file mode 100644
index 0000000000..35a14acc94
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge2/bootstrap.conf
@@ -0,0 +1,125 @@
+#
+# 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.
+#
+
+# C2 Properties
+c2.enable=true
+c2.rest.url=https://c2-authoritative:10443/c2/config/heartbeat
+c2.rest.url.ack=https://c2-authoritative:10443/c2/config/acknowledge
+c2.rest.connectionTimeout=5 sec
+c2.rest.readTimeout=5 sec
+c2.rest.callTimeout=10 sec
+c2.agent.heartbeat.period=2000
+c2.agent.class=raspi3
+c2.config.directory=./conf
+c2.runtime.manifest.identifier=minifi
+c2.runtime.type=minifi-java
+c2.security.truststore.location=./conf/truststore.jks
+c2.security.truststore.password=badTrustPass
+c2.security.truststore.type=JKS
+c2.security.keystore.location=./conf/keystore.jks
+c2.security.keystore.password=badKeystorePass
+c2.security.keystore.type=JKS
+
+# Java command to use when running MiNiFi
+java=java
+
+# Username to use when running MiNiFi. This value will be ignored on Windows.
+run.as=
+
+# Configure where MiNiFi's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling MiNiFi to shutdown before explicitly killing the Process
+graceful.shutdown.seconds=20
+
+# The location for the configuration file
+nifi.minifi.config=./conf/config.yml
+
+# Notifiers to use for the associated agent, comma separated list of class names
+nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.FileChangeIngestor
+#nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.RestChangeIngestor
+#nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.PullHttpChangeIngestor
+
+# File change notifier configuration
+
+# Path of the file to monitor for changes. When these occur, the FileChangeNotifier, if configured, will begin the configuration reloading process
+nifi.minifi.notifier.ingestors.file.config.path=./conf/config-new.yml
+# How frequently the file specified by 'nifi.minifi.notifier.file.config.path' should be evaluated for changes.
+nifi.minifi.notifier.ingestors.file.polling.period.seconds=2
+
+# Rest change notifier configuration
+
+# Port on which the Jetty server will bind to, keep commented for a random open port
+#nifi.minifi.notifier.ingestors.receive.http.port=8338
+
+#Pull HTTP change notifier configuration
+
+# Hostname on which to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.hostname=c2-authoritative
+# Port on which to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.port=10443
+# Path to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.path=/c2/config
+# Query string to pull configurations with
+# nifi.minifi.notifier.ingestors.pull.http.query=net=edge1&class=raspi3
+# Period on which to pull configurations from, defaults to 5 minutes if commented out
+# nifi.minifi.notifier.ingestors.pull.http.period.ms=3000
+
+# nifi.minifi.notifier.ingestors.pull.http.keystore.location=./conf/keystore.jks
+# nifi.minifi.notifier.ingestors.pull.http.keystore.type=JKS
+# nifi.minifi.notifier.ingestors.pull.http.keystore.password=badKeystorePass
+# nifi.minifi.notifier.ingestors.pull.http.truststore.location=./conf/truststore.jks
+# nifi.minifi.notifier.ingestors.pull.http.truststore.type=JKS
+# nifi.minifi.notifier.ingestors.pull.http.truststore.password=badTrustPass
+
+# Periodic Status Reporters to use for the associated agent, comma separated list of class names
+#nifi.minifi.status.reporter.components=org.apache.nifi.minifi.bootstrap.status.reporters.StatusLogger
+
+# Periodic Status Logger configuration
+
+# The FlowStatus query to submit to the MiNiFi instance
+#nifi.minifi.status.reporter.log.query=instance:health,bulletins
+# The log level at which the status will be logged
+#nifi.minifi.status.reporter.log.level=INFO
+# The period (in milliseconds) at which to log the status
+#nifi.minifi.status.reporter.log.period=60000
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms256m
+java.arg.3=-Xmx256m
+
+# Enable Remote Debugging
+# java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# The G1GC is still considered experimental but has proven to be very advantageous in providing great
+# performance without significant "stop-the-world" delays.
+#java.arg.13=-XX:+UseG1GC
+
+#Set headless mode by default
+java.arg.14=-Djava.awt.headless=true
+
+java.arg.15=-Djava.security.egd=file:/dev/./urandom
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge2/expected.json b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge2/expected.json
new file mode 100644
index 0000000000..3738fc5e7d
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge2/expected.json
@@ -0,0 +1,17 @@
+[
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config/heartbeat"
+ },
+ {
+ "pattern": "\"operation\":\"UPDATE\",\"operand\":\"CONFIGURATION\""
+ },
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config\\?class=raspi3"
+ },
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config/acknowledge"
+ },
+ {
+ "pattern": "^__testTextRaspi3__$"
+ }
+]
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge3/bootstrap.conf b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge3/bootstrap.conf
new file mode 100644
index 0000000000..b3ca35c762
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge3/bootstrap.conf
@@ -0,0 +1,125 @@
+#
+# 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.
+#
+
+# C2 Properties
+c2.enable=true
+c2.rest.url=https://c2-authoritative:10443/c2/config/heartbeat
+c2.rest.url.ack=https://c2-authoritative:10443/c2/config/acknowledge
+c2.rest.connectionTimeout=5 sec
+c2.rest.readTimeout=5 sec
+c2.rest.callTimeout=10 sec
+c2.agent.heartbeat.period=2000
+c2.agent.class=raspi4
+c2.config.directory=./conf
+c2.runtime.manifest.identifier=minifi
+c2.runtime.type=minifi-java
+c2.security.truststore.location=./conf/truststore.jks
+c2.security.truststore.password=badTrustPass
+c2.security.truststore.type=JKS
+c2.security.keystore.location=./conf/keystore.jks
+c2.security.keystore.password=badKeystorePass
+c2.security.keystore.type=JKS
+
+# Java command to use when running MiNiFi
+java=java
+
+# Username to use when running MiNiFi. This value will be ignored on Windows.
+run.as=
+
+# Configure where MiNiFi's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling MiNiFi to shutdown before explicitly killing the Process
+graceful.shutdown.seconds=20
+
+# The location for the configuration file
+nifi.minifi.config=./conf/config.yml
+
+# Notifiers to use for the associated agent, comma separated list of class names
+nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.FileChangeIngestor
+#nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.RestChangeIngestor
+#nifi.minifi.notifier.ingestors=org.apache.nifi.minifi.bootstrap.configuration.ingestors.PullHttpChangeIngestor
+
+# File change notifier configuration
+
+# Path of the file to monitor for changes. When these occur, the FileChangeNotifier, if configured, will begin the configuration reloading process
+nifi.minifi.notifier.ingestors.file.config.path=./conf/config-new.yml
+# How frequently the file specified by 'nifi.minifi.notifier.file.config.path' should be evaluated for changes.
+nifi.minifi.notifier.ingestors.file.polling.period.seconds=2
+
+# Rest change notifier configuration
+
+# Port on which the Jetty server will bind to, keep commented for a random open port
+#nifi.minifi.notifier.ingestors.receive.http.port=8338
+
+#Pull HTTP change notifier configuration
+
+# Hostname on which to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.hostname=c2-authoritative
+# Port on which to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.port=10443
+# Path to pull configurations from
+# nifi.minifi.notifier.ingestors.pull.http.path=/c2/config
+# Query string to pull configurations with
+# nifi.minifi.notifier.ingestors.pull.http.query=net=edge1&class=raspi4
+# Period on which to pull configurations from, defaults to 5 minutes if commented out
+# nifi.minifi.notifier.ingestors.pull.http.period.ms=3000
+
+# nifi.minifi.notifier.ingestors.pull.http.keystore.location=./conf/keystore.jks
+# nifi.minifi.notifier.ingestors.pull.http.keystore.type=JKS
+# nifi.minifi.notifier.ingestors.pull.http.keystore.password=badKeystorePass
+# nifi.minifi.notifier.ingestors.pull.http.truststore.location=./conf/truststore.jks
+# nifi.minifi.notifier.ingestors.pull.http.truststore.type=JKS
+# nifi.minifi.notifier.ingestors.pull.http.truststore.password=badTrustPass
+
+# Periodic Status Reporters to use for the associated agent, comma separated list of class names
+#nifi.minifi.status.reporter.components=org.apache.nifi.minifi.bootstrap.status.reporters.StatusLogger
+
+# Periodic Status Logger configuration
+
+# The FlowStatus query to submit to the MiNiFi instance
+#nifi.minifi.status.reporter.log.query=instance:health,bulletins
+# The log level at which the status will be logged
+#nifi.minifi.status.reporter.log.level=INFO
+# The period (in milliseconds) at which to log the status
+#nifi.minifi.status.reporter.log.period=60000
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms256m
+java.arg.3=-Xmx256m
+
+# Enable Remote Debugging
+# java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# The G1GC is still considered experimental but has proven to be very advantageous in providing great
+# performance without significant "stop-the-world" delays.
+#java.arg.13=-XX:+UseG1GC
+
+#Set headless mode by default
+java.arg.14=-Djava.awt.headless=true
+
+java.arg.15=-Djava.security.egd=file:/dev/./urandom
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge3/expected.json b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge3/expected.json
new file mode 100644
index 0000000000..b249269b90
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/c2/protocol/minifi-edge3/expected.json
@@ -0,0 +1,17 @@
+[
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config/heartbeat"
+ },
+ {
+ "pattern": "\"operation\":\"UPDATE\",\"operand\":\"CONFIGURATION\""
+ },
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config\\?class=raspi4"
+ },
+ {
+ "pattern": "200 OK https://c2-authoritative:10443/c2/config/acknowledge"
+ },
+ {
+ "pattern": "^__testTextRaspi4__$"
+ }
+]
\ No newline at end of file
diff --git a/minifi/minifi-integration-tests/src/test/resources/docker-compose-c2-protocol.yml b/minifi/minifi-integration-tests/src/test/resources/docker-compose-c2-protocol.yml
new file mode 100644
index 0000000000..363d2053ea
--- /dev/null
+++ b/minifi/minifi-integration-tests/src/test/resources/docker-compose-c2-protocol.yml
@@ -0,0 +1,100 @@
+# 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.
+
+version: "2"
+
+services:
+ c2-authoritative:
+ build:
+ context: ./
+ dockerfile: Dockerfile.minific2.test
+ image: apacheminific2-test
+ ports:
+ - "10443"
+ hostname: c2-authoritative
+ volumes:
+ - ./c2/protocol/c2-authoritative/files:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/files
+ - ./c2/protocol/c2-authoritative/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
+ - ./c2/protocol/c2-authoritative/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2/protocol/c2-authoritative/conf/authorities.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorities.yaml
+ - ./c2/protocol/c2-authoritative/conf/authorizations.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorizations.yaml
+ - ./certificates-c2-protocol/c2-authoritative/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-c2-protocol/c2-authoritative/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+ networks:
+ - edge
+
+ minifi-edge1:
+ build:
+ context: ./
+ dockerfile: ./Dockerfile.minifi.test
+ image: apacheminifi-test
+ ports:
+ - "8000"
+ volumes:
+ - ./tailFileServer.py:/home/minifi/tailFileServer.py
+ - ./c2/protocol/minifi-edge1/bootstrap.conf:/opt/minifi/minifi-${minifi.version}/conf/bootstrap.conf
+ - ./logback.xml:/opt/minifi/minifi-${minifi.version}/conf/logback.xml
+ - ./certificates-c2-protocol/minifi-edge1/keystore.jks:/opt/minifi/minifi-${minifi.version}/conf/keystore.jks
+ - ./certificates-c2-protocol/minifi-edge1/truststore.jks:/opt/minifi/minifi-${minifi.version}/conf/truststore.jks
+ entrypoint:
+ - sh
+ - -c
+ - /opt/minifi/minifi-${minifi.version}/bin/minifi.sh start && python /home/minifi/tailFileServer.py --file /opt/minifi/minifi-${minifi.version}/logs/minifi-app.log
+ networks:
+ - edge
+
+ minifi-edge2:
+ build:
+ context: ./
+ dockerfile: ./Dockerfile.minifi.test
+ image: apacheminifi-test
+ ports:
+ - "8000"
+ volumes:
+ - ./tailFileServer.py:/home/minifi/tailFileServer.py
+ - ./c2/protocol/minifi-edge2/bootstrap.conf:/opt/minifi/minifi-${minifi.version}/conf/bootstrap.conf
+ - ./logback.xml:/opt/minifi/minifi-${minifi.version}/conf/logback.xml
+ - ./certificates-c2-protocol/minifi-edge2/keystore.jks:/opt/minifi/minifi-${minifi.version}/conf/keystore.jks
+ - ./certificates-c2-protocol/minifi-edge2/truststore.jks:/opt/minifi/minifi-${minifi.version}/conf/truststore.jks
+ entrypoint:
+ - sh
+ - -c
+ - /opt/minifi/minifi-${minifi.version}/bin/minifi.sh start && python /home/minifi/tailFileServer.py --file /opt/minifi/minifi-${minifi.version}/logs/minifi-app.log
+ networks:
+ - edge
+
+ minifi-edge3:
+ build:
+ context: ./
+ dockerfile: ./Dockerfile.minifi.test
+ image: apacheminifi-test
+ ports:
+ - "8000"
+ volumes:
+ - ./tailFileServer.py:/home/minifi/tailFileServer.py
+ - ./c2/protocol/minifi-edge3/bootstrap.conf:/opt/minifi/minifi-${minifi.version}/conf/bootstrap.conf
+ - ./logback.xml:/opt/minifi/minifi-${minifi.version}/conf/logback.xml
+ - ./certificates-c2-protocol/minifi-edge3/keystore.jks:/opt/minifi/minifi-${minifi.version}/conf/keystore.jks
+ - ./certificates-c2-protocol/minifi-edge3/truststore.jks:/opt/minifi/minifi-${minifi.version}/conf/truststore.jks
+ entrypoint:
+ - sh
+ - -c
+ - /opt/minifi/minifi-${minifi.version}/bin/minifi.sh start && python /home/minifi/tailFileServer.py --file /opt/minifi/minifi-${minifi.version}/logs/minifi-app.log
+ networks:
+ - edge
+
+networks:
+ edge:
+ driver: bridge
diff --git a/minifi/minifi-integration-tests/src/test/resources/logback.xml b/minifi/minifi-integration-tests/src/test/resources/logback.xml
index 2c8860e536..d82fbdb9c9 100644
--- a/minifi/minifi-integration-tests/src/test/resources/logback.xml
+++ b/minifi/minifi-integration-tests/src/test/resources/logback.xml
@@ -56,6 +56,7 @@
<!-- valid logging levels: TRACE, DEBUG, INFO, WARN, ERROR -->
<logger name="org.apache.nifi" level="INFO"/>
+ <logger name="org.apache.nifi.c2.client.http.C2HttpClient" level="DEBUG"/>
<logger name="org.apache.nifi.processors" level="WARN"/>
<logger name="org.apache.nifi.processors.standard.LogAttribute" level="INFO"/>
<logger name="org.apache.nifi.controller.repository.StandardProcessSession" level="DEBUG" />
@@ -77,6 +78,7 @@
Logger for capturing Bootstrap logs and MiNiFi's standard error and standard out.
-->
<logger name="org.apache.nifi.minifi.bootstrap" level="INFO" additivity="false">
+ <appender-ref ref="CONSOLE" />
<appender-ref ref="BOOTSTRAP_FILE" />
</logger>
<logger name="org.apache.nifi.minifi.bootstrap.Command" level="INFO" additivity="false">
@@ -86,17 +88,19 @@
<!-- Everything written to MiNiFi's Standard Out will be logged with the logger org.apache.nifi.minifi.StdOut at INFO level -->
<logger name="org.apache.nifi.minifi.StdOut" level="INFO" additivity="false">
+ <appender-ref ref="CONSOLE" />
<appender-ref ref="BOOTSTRAP_FILE" />
</logger>
<!-- Everything written to MiNiFi's Standard Error will be logged with the logger org.apache.nifi.minifi.StdErr at ERROR level -->
- <logger name="org.apache.nifi.minifi.StdErr" level="ERROR" additivity="false">
- <appender-ref ref="BOOTSTRAP_FILE" />
+ <logger name="org.apache.nifi.minifi.StdErr" level="ERROR" additivity="false">
+ <appender-ref ref="CONSOLE" />
+ <appender-ref ref="BOOTSTRAP_FILE" />
</logger>
-
- <root level="INFO">
+ <root level="DEBUG">
<appender-ref ref="APP_FILE"/>
+ <appender-ref ref="CONSOLE"/>
</root>
</configuration>