You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2017/05/15 13:44:45 UTC
[1/4] nifi-minifi git commit: MINIFI-272 - Delegating C2 Provider,
Caching ConfigService, Tests Proxy auth, caching fixes Added C2 readme
Repository: nifi-minifi
Updated Branches:
refs/heads/master b55618770 -> 4dc0ce303
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/bootstrap.conf
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/bootstrap.conf b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/bootstrap.conf
new file mode 100644
index 0000000..927891f
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/bootstrap.conf
@@ -0,0 +1,99 @@
+#
+# 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.
+#
+
+# 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=
+# 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=5
+
+# 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-edge2
+# Port on which to pull configurations from
+nifi.minifi.notifier.ingestors.pull.http.port=10080
+# 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=edge2&class=raspi2
+# Period on which to pull configurations from, defaults to 5 minutes if commented out
+nifi.minifi.notifier.ingestors.pull.http.period.ms=3000
+
+# 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=n,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
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/expected.json b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/expected.json
new file mode 100644
index 0000000..ef85cef
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge2/expected.json
@@ -0,0 +1,8 @@
+[
+ {
+ "pattern": "ConfigurationChangeCoordinator Notifying Listeners of a change"
+ },
+ {
+ "pattern": "MiNiFi has finished reloading successfully and swap file exists. Deleting old configuration"
+ }
+]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/bootstrap.conf
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/bootstrap.conf b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/bootstrap.conf
new file mode 100644
index 0000000..9ffe7d3
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/bootstrap.conf
@@ -0,0 +1,109 @@
+#
+# 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.
+#
+
+# 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=
+# 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=5
+
+# 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=edge3&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.proxy.hostname=squid-edge3
+nifi.minifi.notifier.ingestors.pull.http.proxy.port=3128
+
+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=n,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
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/expected.json b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/expected.json
new file mode 100644
index 0000000..ef85cef
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge3/expected.json
@@ -0,0 +1,8 @@
+[
+ {
+ "pattern": "ConfigurationChangeCoordinator Notifying Listeners of a change"
+ },
+ {
+ "pattern": "MiNiFi has finished reloading successfully and swap file exists. Deleting old configuration"
+ }
+]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/docker-compose-c2-hierarchical.yml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/docker-compose-c2-hierarchical.yml b/minifi-integration-tests/src/test/resources/docker-compose-c2-hierarchical.yml
new file mode 100644
index 0000000..a07aa5d
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/docker-compose-c2-hierarchical.yml
@@ -0,0 +1,126 @@
+# 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:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10443"
+ hostname: c2-authoritative
+ volumes:
+ - ./c2/hierarchical/c2-authoritative/files:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/files
+ - ./c2/hierarchical/c2-authoritative/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
+
+ - ./c2/hierarchical/c2-authoritative/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2/hierarchical/c2-authoritative/conf/authorities.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorities.yaml
+ - ./c2/hierarchical/c2-authoritative/conf/authorizations.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorizations.yaml
+
+ - ./certificates-c2-hierarchical/c2-authoritative/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-c2-hierarchical/c2-authoritative/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+ networks:
+ - cluster
+ - edge1
+
+ minifi-edge1:
+ image: apacheminifi:${minifi.version}
+ ports:
+ - "8000"
+ volumes:
+ - ./tailFileServer.py:/home/minifi/tailFileServer.py
+
+ - ./c2/hierarchical/minifi-edge1/bootstrap.conf:/opt/minifi/minifi-${minifi.version}/conf/bootstrap.conf
+ - ./logback.xml:/opt/minifi/minifi-${minifi.version}/conf/logback.xml
+
+ - ./certificates-c2-hierarchical/minifi-edge1/keystore.jks:/opt/minifi/minifi-${minifi.version}/conf/keystore.jks
+ - ./certificates-c2-hierarchical/minifi-edge1/truststore.jks:/opt/minifi/minifi-${minifi.version}/conf/truststore.jks
+ entrypoint:
+ - bash
+ - -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 --file /opt/minifi/minifi-${minifi.version}/logs/minifi-bootstrap.log
+ networks:
+ - edge1
+
+ c2-edge2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10080"
+ hostname: c2-edge2
+ volumes:
+ - ./c2/hierarchical/c2-edge2/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2/hierarchical/c2-edge2/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
+
+ - ./certificates-c2-hierarchical/c2-edge2/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-c2-hierarchical/c2-edge2/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+ networks:
+ - cluster
+ - edge2
+
+ minifi-edge2:
+ image: apacheminifi:${minifi.version}
+ ports:
+ - "8000"
+ volumes:
+ - ./tailFileServer.py:/home/minifi/tailFileServer.py
+
+ - ./c2/hierarchical/minifi-edge2/bootstrap.conf:/opt/minifi/minifi-${minifi.version}/conf/bootstrap.conf
+ - ./logback.xml:/opt/minifi/minifi-${minifi.version}/conf/logback.xml
+ entrypoint:
+ - bash
+ - -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 --file /opt/minifi/minifi-${minifi.version}/logs/minifi-bootstrap.log
+ networks:
+ - edge2
+
+ squid-edge3:
+ image: chrisdaish/squid
+ ports:
+ - "3128"
+ hostname: squid-edge3
+ volumes:
+ - ./squid/squid.conf:/etc/squid/squid.conf
+ networks:
+ - cluster
+ - edge3
+
+ minifi-edge3:
+ image: apacheminifi:${minifi.version}
+ ports:
+ - "8000"
+ volumes:
+ - ./tailFileServer.py:/home/minifi/tailFileServer.py
+
+ - ./c2/hierarchical/minifi-edge3/bootstrap.conf:/opt/minifi/minifi-${minifi.version}/conf/bootstrap.conf
+ - ./logback.xml:/opt/minifi/minifi-${minifi.version}/conf/logback.xml
+
+ - ./certificates-c2-hierarchical/minifi-edge3/keystore.jks:/opt/minifi/minifi-${minifi.version}/conf/keystore.jks
+ - ./certificates-c2-hierarchical/minifi-edge3/truststore.jks:/opt/minifi/minifi-${minifi.version}/conf/truststore.jks
+ entrypoint:
+ - bash
+ - -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 --file /opt/minifi/minifi-${minifi.version}/logs/minifi-bootstrap.log
+ networks:
+ - edge3
+
+networks:
+ cluster:
+ driver: bridge
+ edge1:
+ driver: bridge
+ edge2:
+ driver: bridge
+ edge3:
+ driver: bridge
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/logback.xml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/logback.xml b/minifi-integration-tests/src/test/resources/logback.xml
index 168ff9e..7226fe3 100644
--- a/minifi-integration-tests/src/test/resources/logback.xml
+++ b/minifi-integration-tests/src/test/resources/logback.xml
@@ -59,6 +59,8 @@
<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="INFO" />
+ <logger name="org.apache.nifi.minifi.bootstrap.configuration.ingestors.PullHttpChangeIngestor" level="DEBUG" />
+ <logger name="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache" level="DEBUG" />
<!-- Logger for managing logging statements for jetty -->
<logger name="org.eclipse.jetty" level="INFO"/>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/squid/squid.conf
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/squid/squid.conf b/minifi-integration-tests/src/test/resources/squid/squid.conf
new file mode 100644
index 0000000..90a5248
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/squid/squid.conf
@@ -0,0 +1,19 @@
+# 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.
+
+http_access allow all
+
+# Choose the port you want. Below we set it to default 3128.
+http_port 3128
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/xml/expected.json
index ebc43fc..b259ef7 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=1d00089c-78cd-467f-9aa6-31e3bdf90cb0\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 2
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=1d00089c-78cd-467f-9aa6-31e3bdf90cb0\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 2
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/yml/expected.json
index 1f89457..afd1bde 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/CsvToJson/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=2aac227f-e8e9-370f-87c8-4f970e0b260e\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 2
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=2aac227f-e8e9-370f-87c8-4f970e0b260e\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 2
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/xml/expected.json
index 7812559..b12e21e 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=7209cf79-23ba-421c-b1c3-925ed86c302d\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 1
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=7209cf79-23ba-421c-b1c3-925ed86c302d\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 1
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/yml/expected.json
index a486289..f00e675 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/DecompressionCircularFlow/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=59198b81-12fc-374f-bead-7fcd1d5d4823\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 1
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=59198b81-12fc-374f-bead-7fcd1d5d4823\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 1
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/xml/expected.json
index 57ad2d1..5091f4d 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=5a36371c-4884-41cb-8792-073deb6c256a\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=5a36371c-4884-41cb-8792-073deb6c256a\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/yml/expected.json
index f98095b..a602148 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/MiNiFiTailLogAttribute/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=59198b81-12fc-374f-bead-7fcd1d5d4823\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=59198b81-12fc-374f-bead-7fcd1d5d4823\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/xml/expected.json
index 70303df..208e649 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=bfa4fb38-096b-455d-a10f-2a1ed044bd49\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 2
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=bfa4fb38-096b-455d-a10f-2a1ed044bd49\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 2
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/yml/expected.json
index 30eb6c7..45c4446 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v1/ReplaceTextExpressionLanguageCSVReformatting/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=8c6c54be-7db6-333f-8c3b-d6e7b02411ff\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 2
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for UpdateAttribute\\[id=8c6c54be-7db6-333f-8c3b-d6e7b02411ff\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 2
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/xml/expected.json
index 6110f19..02b1c06 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[.*\\] for LogAttribute\\[id=7c75ab71-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[.*\\] for LogAttribute\\[id=7c75ab71-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/yml/expected.json
index 6110f19..02b1c06 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v2/MultipleRelationships/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[.*\\] for LogAttribute\\[id=7c75ab71-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[.*\\] for LogAttribute\\[id=7c75ab71-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/xml/expected.json
index a1e4e43..7f9e81c 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=e25e0e6e-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=e25e0e6e-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/yml/expected.json
index a1e4e43..7f9e81c 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v2/ProcessGroups/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=e25e0e6e-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for LogAttribute\\[id=e25e0e6e-0157-1000-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'success'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/xml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/xml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/xml/expected.json
index 5f3740b..5589030 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/xml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/xml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for RouteOnAttribute\\[id=397a4910-cc01-4c6b-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'unmatched'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for RouteOnAttribute\\[id=397a4910-cc01-4c6b-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'unmatched'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/yml/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/yml/expected.json b/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/yml/expected.json
index 5f3740b..5589030 100644
--- a/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/yml/expected.json
+++ b/minifi-integration-tests/src/test/resources/standalone/v2/StressTestFramework/yml/expected.json
@@ -1,4 +1,6 @@
-{
- "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for RouteOnAttribute\\[id=397a4910-cc01-4c6b-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'unmatched'",
- "occurrences": 20
-}
+[
+ {
+ "pattern": "o.a.n.c.r.StandardProcessSession StandardProcessSession\\[id=.*\\] for RouteOnAttribute\\[id=397a4910-cc01-4c6b-0000-000000000000\\], committed the following events: Transferred FlowFiles \\[.*\\] to 'unmatched'",
+ "occurrences": 20
+ }
+]
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/tailFileServer.py
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/tailFileServer.py b/minifi-integration-tests/src/test/resources/tailFileServer.py
index bec2ccf..6bfd92e 100644
--- a/minifi-integration-tests/src/test/resources/tailFileServer.py
+++ b/minifi-integration-tests/src/test/resources/tailFileServer.py
@@ -31,7 +31,9 @@ class TailHTTPRequestHandler(BaseHTTPRequestHandler):
self.send_response(200)
self.send_header('Content-type','text/plain')
self.end_headers()
- p = Popen(['tail', '-f', '-n', '+1', TAIL_FILE], stdout=PIPE)
+ args = ['tail', '-f', '-n', '+1']
+ args.extend(TAIL_FILES)
+ p = Popen(args, stdout=PIPE)
try:
for line in iter(p.stdout.readline, b''):
self.wfile.write(line)
@@ -43,7 +45,7 @@ class TailHTTPRequestHandler(BaseHTTPRequestHandler):
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
parser = ArgumentParser(description='Tail file over http')
- parser.add_argument('--file')
+ parser.add_argument('--file', action='append')
parser.add_argument('--port', type=int, default=8000)
logging.debug('About to parse arguments')
@@ -52,10 +54,10 @@ if __name__ == '__main__':
if not args.file:
raise Exception('Must specify --file')
- global TAIL_FILE
- TAIL_FILE = args.file
+ global TAIL_FILES
+ TAIL_FILES = args.file
- logging.debug('Serving tail of ' + TAIL_FILE + ' via HTTP at port ' + str(args.port))
+ logging.debug('Serving tail of ' + str(TAIL_FILES) + ' via HTTP at port ' + str(args.port))
server = ThreadedHTTPServer(('', args.port), TailHTTPRequestHandler)
server.serve_forever()
\ No newline at end of file
[2/4] nifi-minifi git commit: MINIFI-272 - Delegating C2 Provider,
Caching ConfigService, Tests Proxy auth, caching fixes Added C2 readme
Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java
index ca20e4a..c8e19b2 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIteratorTest.java
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.JsonFactory;
import com.google.common.collect.Lists;
import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.apache.nifi.minifi.c2.provider.util.HttpConnector;
import org.junit.Before;
import org.junit.Test;
@@ -38,21 +39,21 @@ import static org.mockito.Mockito.when;
public class TemplatesIteratorTest {
private JsonFactory jsonFactory;
private HttpURLConnection httpURLConnection;
- private NiFiRestConnector niFiRestConnector;
+ private HttpConnector httpConnector;
@Before
public void setup() throws ConfigurationProviderException {
jsonFactory = new JsonFactory();
httpURLConnection = mock(HttpURLConnection.class);
- niFiRestConnector = mock(NiFiRestConnector.class);
- when(niFiRestConnector.get(TemplatesIterator.FLOW_TEMPLATES)).thenReturn(httpURLConnection);
+ httpConnector = mock(HttpConnector.class);
+ when(httpConnector.get(TemplatesIterator.FLOW_TEMPLATES)).thenReturn(httpURLConnection);
}
@Test(expected = NoSuchElementException.class)
public void testIteratorNoSuchElementException() throws ConfigurationProviderException, IOException {
when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("noTemplates.json"));
- try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(httpConnector, jsonFactory)) {
assertFalse(templatesIterator.hasNext());
templatesIterator.next();
} finally {
@@ -64,7 +65,7 @@ public class TemplatesIteratorTest {
public void testIteratorNoTemplates() throws ConfigurationProviderException, IOException {
when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("noTemplates.json"));
List<Pair<String, String>> idToNameList;
- try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(httpConnector, jsonFactory)) {
idToNameList = Lists.newArrayList(templatesIterator);
}
assertEquals(0, idToNameList.size());
@@ -76,7 +77,7 @@ public class TemplatesIteratorTest {
public void testIteratorSingleTemplate() throws ConfigurationProviderException, IOException {
when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("oneTemplate.json"));
List<Pair<String, String>> idToNameList;
- try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(httpConnector, jsonFactory)) {
idToNameList = Lists.newArrayList(templatesIterator);
}
assertEquals(1, idToNameList.size());
@@ -91,7 +92,7 @@ public class TemplatesIteratorTest {
public void testIteratorTwoTemplates() throws ConfigurationProviderException, IOException {
when(httpURLConnection.getInputStream()).thenReturn(TemplatesIteratorTest.class.getClassLoader().getResourceAsStream("twoTemplates.json"));
List<Pair<String, String>> idToNameList;
- try (TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory)) {
+ try (TemplatesIterator templatesIterator = new TemplatesIterator(httpConnector, jsonFactory)) {
idToNameList = Lists.newArrayList(templatesIterator);
}
assertEquals(2, idToNameList.size());
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/pom.xml b/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/pom.xml
new file mode 100644
index 0000000..cbb3905
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/pom.xml
@@ -0,0 +1,44 @@
+<?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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2-provider</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-provider-util</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/src/main/java/org/apache/nifi/minifi/c2/provider/util/HttpConnector.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/src/main/java/org/apache/nifi/minifi/c2/provider/util/HttpConnector.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/src/main/java/org/apache/nifi/minifi/c2/provider/util/HttpConnector.java
new file mode 100644
index 0000000..1c8e0c7
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-util/src/main/java/org/apache/nifi/minifi/c2/provider/util/HttpConnector.java
@@ -0,0 +1,130 @@
+/*
+ * 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.c2.provider.util;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.properties.C2Properties;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class HttpConnector {
+ private static final Logger logger = LoggerFactory.getLogger(HttpConnector.class);
+
+ private final String baseUrl;
+ private final SslContextFactory sslContextFactory;
+ private final Proxy proxy;
+ private final String proxyAuthorization;
+
+ public HttpConnector(String baseUrl) throws InvalidParameterException, GeneralSecurityException, IOException {
+ this(baseUrl, null, 0);
+ }
+
+ public HttpConnector(String baseUrl, String proxyHost, int proxyPort) throws InvalidParameterException, GeneralSecurityException, IOException {
+ this(baseUrl, proxyHost, proxyPort, null, null);
+ }
+
+ public HttpConnector(String baseUrl, String proxyHost, int proxyPort, String proxyUsername, String proxyPassword) throws InvalidParameterException, GeneralSecurityException, IOException {
+ if (baseUrl.startsWith("https:")) {
+ sslContextFactory = C2Properties.getInstance().getSslContextFactory();
+ if (sslContextFactory == null) {
+ throw new InvalidParameterException("Need sslContextFactory to connect to https endpoint (" + baseUrl + ")");
+ }
+ } else {
+ sslContextFactory = null;
+ }
+ this.baseUrl = baseUrl;
+ if (proxyHost != null && !proxyHost.isEmpty()) {
+ if (proxyPort == 0) {
+ throw new InvalidParameterException("Must specify proxy port with proxy host");
+ }
+ proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
+ } else {
+ proxy = null;
+ }
+
+ if (proxyUsername != null && !proxyUsername.isEmpty()) {
+ if (proxy == null) {
+ throw new InvalidParameterException("Cannot specify proxy username without proxy host.");
+ }
+ if (proxyPassword == null) {
+ throw new InvalidParameterException("Must specify proxy password with proxy username.");
+ }
+ proxyAuthorization = "Basic " + Base64.getEncoder().encodeToString((proxyHost + ":" + proxyPassword).getBytes(StandardCharsets.UTF_8));
+ } else {
+ proxyAuthorization = null;
+ }
+ }
+
+ public HttpURLConnection get(String endpointPath) throws ConfigurationProviderException {
+ return get(endpointPath, Collections.emptyMap());
+ }
+
+ public HttpURLConnection get(String endpointPath, Map<String, List<String>> headers) throws ConfigurationProviderException {
+ String endpointUrl = baseUrl + endpointPath;
+ if (logger.isDebugEnabled()) {
+ logger.debug("Connecting to endpoint: " + endpointUrl);
+ }
+ URL url;
+ try {
+ url = new URL(endpointUrl);
+ } catch (MalformedURLException e) {
+ throw new ConfigurationProviderException("Malformed url " + endpointUrl, e);
+ }
+
+ HttpURLConnection httpURLConnection;
+ try {
+ if (proxy == null) {
+ httpURLConnection = (HttpURLConnection) url.openConnection();
+ } else {
+ httpURLConnection = (HttpURLConnection) url.openConnection(proxy);
+ }
+ if (sslContextFactory != null) {
+ HttpsURLConnection httpsURLConnection = (HttpsURLConnection) httpURLConnection;
+ SSLContext sslContext = sslContextFactory.getSslContext();
+ SSLSocketFactory socketFactory = sslContext.getSocketFactory();
+ httpsURLConnection.setSSLSocketFactory(socketFactory);
+ }
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to connect to " + url, e);
+ }
+ if (proxyAuthorization != null) {
+ httpURLConnection.setRequestProperty("Proxy-Authorization", proxyAuthorization);
+ }
+ headers.forEach((s, strings) -> httpURLConnection.setRequestProperty(s, strings.stream().collect(Collectors.joining(","))));
+ return httpURLConnection;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/pom.xml b/minifi-c2/minifi-c2-provider/pom.xml
index fc0fbae..4dff466 100644
--- a/minifi-c2/minifi-c2-provider/pom.xml
+++ b/minifi-c2/minifi-c2-provider/pom.xml
@@ -26,7 +26,9 @@ limitations under the License.
<packaging>pom</packaging>
<modules>
+ <module>minifi-c2-provider-util</module>
<module>minifi-c2-provider-cache</module>
+ <module>minifi-c2-provider-delegating</module>
<module>minifi-c2-provider-nifi-rest</module>
</modules>
</project>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-service/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-service/pom.xml b/minifi-c2/minifi-c2-service/pom.xml
index eb52d7d..e403667 100644
--- a/minifi-c2/minifi-c2-service/pom.xml
+++ b/minifi-c2/minifi-c2-service/pom.xml
@@ -58,6 +58,16 @@ limitations under the License.
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.17</version>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
index e57089e..efe334a 100644
--- a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java
@@ -17,9 +17,17 @@
package org.apache.nifi.minifi.c2.service;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.UncheckedExecutionException;
import com.wordnik.swagger.annotations.Api;
import org.apache.nifi.minifi.c2.api.Configuration;
import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.InvalidParameterException;
import org.apache.nifi.minifi.c2.api.security.authorization.AuthorizationException;
import org.apache.nifi.minifi.c2.api.security.authorization.Authorizer;
@@ -32,6 +40,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
@@ -43,10 +52,15 @@ import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Path("/config")
@@ -56,15 +70,108 @@ import java.util.stream.Collectors;
)
public class ConfigService {
private static final Logger logger = LoggerFactory.getLogger(ConfigService.class);
- private final List<Pair<MediaType, ConfigurationProvider>> configurationProviders;
private final Authorizer authorizer;
+ private final ObjectMapper objectMapper;
+ private final Supplier<ConfigurationProviderInfo> configurationProviderInfo;
+ private final LoadingCache<ConfigurationProviderKey, ConfigurationProviderValue> configurationCache;
public ConfigService(List<ConfigurationProvider> configurationProviders, Authorizer authorizer) {
+ this(configurationProviders, authorizer, 1000, 300_000);
+ }
+ public ConfigService(List<ConfigurationProvider> configurationProviders, Authorizer authorizer, long maximumCacheSize, long cacheTtlMillis) {
this.authorizer = authorizer;
+ this.objectMapper = new ObjectMapper();
if (configurationProviders == null || configurationProviders.size() == 0) {
throw new IllegalArgumentException("Expected at least one configuration provider");
}
- this.configurationProviders = configurationProviders.stream().map(c -> new Pair<>(MediaType.valueOf(c.getContentType()), c)).collect(Collectors.toList());
+ this.configurationProviderInfo = Suppliers.memoizeWithExpiration(() -> initContentTypeInfo(configurationProviders), cacheTtlMillis, TimeUnit.MILLISECONDS);
+ CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
+ if (maximumCacheSize >= 0) {
+ cacheBuilder = cacheBuilder.maximumSize(maximumCacheSize);
+ }
+ if (cacheTtlMillis >= 0) {
+ cacheBuilder = cacheBuilder.refreshAfterWrite(cacheTtlMillis, TimeUnit.MILLISECONDS);
+ }
+ this.configurationCache = cacheBuilder
+ .build(new CacheLoader<ConfigurationProviderKey, ConfigurationProviderValue>() {
+ @Override
+ public ConfigurationProviderValue load(ConfigurationProviderKey key) throws Exception {
+ return initConfigurationProviderValue(key);
+ }
+ });
+ }
+
+ public ConfigurationProviderValue initConfigurationProviderValue(ConfigurationProviderKey key) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Attempting to load and cache configuration with key " + key);
+ }
+ try {
+ List<MediaType> acceptValues = key.getAcceptValues();
+ Pair<MediaType, ConfigurationProvider> providerPair = getProvider(acceptValues);
+
+ Map<String, List<String>> parameters = key.getParameters();
+
+ Integer version = null;
+ List<String> versionList = parameters.get("version");
+ if (versionList != null && versionList.size() > 0) {
+ try {
+ version = Integer.parseInt(versionList.get(0));
+ } catch (NumberFormatException e) {
+ throw new InvalidParameterException("Unable to parse " + version + " as integer.", e);
+ }
+ }
+ return new ConfigurationProviderValue(providerPair.getSecond().getConfiguration(providerPair.getFirst().toString(), version, parameters), providerPair.getFirst(), null);
+ } catch (ConfigurationProviderException e) {
+ return new ConfigurationProviderValue(null, null, e);
+ }
+ }
+
+ protected ConfigurationProviderInfo initContentTypeInfo(List<ConfigurationProvider> configurationProviders) {
+ List<Pair<MediaType, ConfigurationProvider>> mediaTypeList = new ArrayList<>();
+ List<String> contentTypes = new ArrayList<>();
+ Set<MediaType> seenMediaTypes = new LinkedHashSet<>();
+
+ for (ConfigurationProvider configurationProvider : configurationProviders) {
+ try {
+ for (String contentTypeString : configurationProvider.getContentTypes()) {
+ MediaType mediaType = MediaType.valueOf(contentTypeString);
+ if (seenMediaTypes.add(mediaType)) {
+ contentTypes.add(contentTypeString);
+ mediaTypeList.add(new Pair<>(mediaType, configurationProvider));
+ }
+ }
+ } catch (ConfigurationProviderException e) {
+ return new ConfigurationProviderInfo(null, null, e);
+ }
+ }
+ return new ConfigurationProviderInfo(mediaTypeList, contentTypes, null);
+ }
+
+ @GET
+ @Path("/contentTypes")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getContentTypes(@Context HttpServletRequest request, @Context UriInfo uriInfo) {
+ try {
+ authorizer.authorize(SecurityContextHolder.getContext().getAuthentication(), uriInfo);
+ } catch (AuthorizationException e) {
+ logger.warn(HttpRequestUtil.getClientString(request) + " not authorized to access " + uriInfo, e);
+ return Response.status(403).build();
+ }
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ List<String> contentTypes;
+ try {
+ contentTypes = configurationProviderInfo.get().getContentTypes();
+ } catch (ConfigurationProviderException e) {
+ logger.warn("Unable to initialize content type information.", e);
+ return Response.status(500).build();
+ }
+ try {
+ objectMapper.writerWithDefaultPrettyPrinter().writeValue(byteArrayOutputStream, contentTypes);
+ } catch (IOException e) {
+ logger.warn("Unable to write configuration providers to output stream.", e);
+ return Response.status(500).build();
+ }
+ return Response.ok().type(MediaType.APPLICATION_JSON_TYPE).entity(byteArrayOutputStream.toByteArray()).build();
}
@GET
@@ -98,29 +205,20 @@ public class ConfigService {
.append(acceptValues.stream().map(Object::toString).collect(Collectors.joining(", ")));
logger.debug(builder.toString());
}
- Pair<MediaType, ConfigurationProvider> providerPair = getProvider(acceptValues);
try {
- Integer version = null;
- List<String> versionList = parameters.get("version");
- if (versionList != null && versionList.size() > 0) {
- try {
- version = Integer.parseInt(versionList.get(0));
- } catch (NumberFormatException e) {
- throw new InvalidParameterException("Unable to parse " + version + " as integer.", e);
- }
- }
+ ConfigurationProviderValue configurationProviderValue = configurationCache.get(new ConfigurationProviderKey(acceptValues, parameters));
+ Configuration configuration = configurationProviderValue.getConfiguration();
Response.ResponseBuilder ok = Response.ok();
- Configuration configuration = providerPair.getSecond().getConfiguration(version, parameters);
ok = ok.header("X-Content-Version", configuration.getVersion());
- ok = ok.type(providerPair.getFirst());
+ ok = ok.type(configurationProviderValue.getMediaType());
byte[] buffer = new byte[1024];
int read;
try (InputStream inputStream = configuration.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
MessageDigest md5 = MessageDigest.getInstance("MD5");
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
- while((read = inputStream.read(buffer)) >= 0) {
+ while ((read = inputStream.read(buffer)) >= 0) {
outputStream.write(buffer, 0, read);
md5.update(buffer, 0, read);
sha256.update(buffer, 0, read);
@@ -128,16 +226,26 @@ public class ConfigService {
ok = ok.header("Content-MD5", bytesToHex(md5.digest()));
ok = ok.header("X-Content-SHA-256", bytesToHex(sha256.digest()));
ok = ok.entity(outputStream.toByteArray());
- } catch (IOException|NoSuchAlgorithmException e) {
+ } catch (ConfigurationProviderException | IOException | NoSuchAlgorithmException e) {
logger.error("Error reading or checksumming configuration file", e);
throw new WebApplicationException(500);
}
return ok.build();
+ } catch (AuthorizationException e) {
+ logger.warn(HttpRequestUtil.getClientString(request) + " not authorized to access " + uriInfo, e);
+ return Response.status(403).build();
} catch (InvalidParameterException e) {
logger.info(HttpRequestUtil.getClientString(request) + " made invalid request with " + HttpRequestUtil.getQueryString(request), e);
return Response.status(400).entity("Invalid request.").build();
- } catch (Throwable t) {
- logger.error(HttpRequestUtil.getClientString(request) + " made request with " + HttpRequestUtil.getQueryString(request) + " that caused error in " + providerPair.getSecond(), t);
+ } catch (ConfigurationProviderException e) {
+ logger.warn("Unable to get configuration.", e);
+ return Response.status(500).build();
+ } catch (ExecutionException|UncheckedExecutionException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof WebApplicationException) {
+ throw (WebApplicationException) cause;
+ }
+ logger.error(HttpRequestUtil.getClientString(request) + " made request with " + HttpRequestUtil.getQueryString(request) + " that caused error.", cause);
return Response.status(500).entity("Internal error").build();
}
}
@@ -145,23 +253,30 @@ public class ConfigService {
// see: http://stackoverflow.com/questions/15429257/how-to-convert-byte-array-to-hexstring-in-java#answer-15429408
protected static String bytesToHex(byte[] in) {
final StringBuilder builder = new StringBuilder();
- for(byte b : in) {
+ for (byte b : in) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
- private Pair<MediaType, ConfigurationProvider> getProvider(List<MediaType> acceptValues) {
+ private Pair<MediaType, ConfigurationProvider> getProvider(List<MediaType> acceptValues) throws ConfigurationProviderException {
+ List<Pair<MediaType, ConfigurationProvider>> mediaTypeList;
+ try {
+ mediaTypeList = this.configurationProviderInfo.get().getMediaTypeList();
+ } catch (ConfigurationProviderException.Wrapper e) {
+ throw e.unwrap();
+ }
for (MediaType accept : acceptValues) {
- for (Pair<MediaType, ConfigurationProvider> configurationProviderPair : configurationProviders) {
- if (accept.isCompatible(configurationProviderPair.getFirst())) {
- return configurationProviderPair;
+ for (Pair<MediaType, ConfigurationProvider> pair : mediaTypeList) {
+ MediaType mediaType = pair.getFirst();
+ if (accept.isCompatible(mediaType)) {
+ return new Pair<>(mediaType, pair.getSecond());
}
}
}
throw new WebApplicationException(Response.status(406).entity("Unable to find configuration provider for " +
"\"Accept: " + acceptValues.stream().map(Object::toString).collect(Collectors.joining(", ")) + "\" supported media types are " +
- configurationProviders.stream().map(Pair::getFirst).map(Object::toString).collect(Collectors.joining(", "))).build());
+ mediaTypeList.stream().map(Pair::getFirst).map(Object::toString).collect(Collectors.joining(", "))).build());
}
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderInfo.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderInfo.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderInfo.java
new file mode 100644
index 0000000..755a4e2
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderInfo.java
@@ -0,0 +1,51 @@
+/*
+ * 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.c2.service;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.util.Pair;
+
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+public class ConfigurationProviderInfo {
+ private final List<Pair<MediaType, ConfigurationProvider>> mediaTypeList;
+ private final List<String> contentTypes;
+ private final ConfigurationProviderException configurationProviderException;
+
+ public ConfigurationProviderInfo(List<Pair<MediaType, ConfigurationProvider>> mediaTypeList, List<String> contentTypes, ConfigurationProviderException configurationProviderException) {
+ this.mediaTypeList = mediaTypeList;
+ this.contentTypes = contentTypes;
+ this.configurationProviderException = configurationProviderException;
+ }
+
+ public List<Pair<MediaType, ConfigurationProvider>> getMediaTypeList() throws ConfigurationProviderException {
+ if (configurationProviderException != null) {
+ throw configurationProviderException;
+ }
+ return mediaTypeList;
+ }
+
+ public List<String> getContentTypes() throws ConfigurationProviderException {
+ if (configurationProviderException != null) {
+ throw configurationProviderException;
+ }
+ return contentTypes;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderKey.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderKey.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderKey.java
new file mode 100644
index 0000000..3bc8919
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderKey.java
@@ -0,0 +1,69 @@
+/*
+ * 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.c2.service;
+
+import javax.ws.rs.core.MediaType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class ConfigurationProviderKey {
+ private final List<MediaType> acceptValues;
+ private final Map<String, List<String>> parameters;
+
+ public ConfigurationProviderKey(List<MediaType> acceptValues, Map<String, List<String>> parameters) {
+ this.acceptValues = Collections.unmodifiableList(new ArrayList<>(acceptValues));
+ this.parameters = Collections.unmodifiableMap(parameters.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> Collections.unmodifiableList(new ArrayList<>(e.getValue())))));
+ }
+
+ public List<MediaType> getAcceptValues() {
+ return acceptValues;
+ }
+
+ public Map<String, List<String>> getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ConfigurationProviderKey that = (ConfigurationProviderKey) o;
+
+ if (!acceptValues.equals(that.acceptValues)) return false;
+ return parameters.equals(that.parameters);
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigurationProviderKey{" +
+ "acceptValues=" + acceptValues +
+ ", parameters=" + parameters +
+ '}';
+ }
+
+ @Override
+ public int hashCode() {
+ int result = acceptValues.hashCode();
+ result = 31 * result + parameters.hashCode();
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderValue.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderValue.java b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderValue.java
new file mode 100644
index 0000000..875f4cb
--- /dev/null
+++ b/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigurationProviderValue.java
@@ -0,0 +1,49 @@
+/*
+ * 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.c2.service;
+
+import org.apache.nifi.minifi.c2.api.Configuration;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+
+import javax.ws.rs.core.MediaType;
+
+public class ConfigurationProviderValue {
+ private final Configuration configuration;
+ private final MediaType mediaType;
+ private final ConfigurationProviderException configurationProviderException;
+
+ public ConfigurationProviderValue(Configuration configuration, MediaType mediaType, ConfigurationProviderException configurationProviderException) {
+ this.configuration = configuration;
+ this.mediaType = mediaType;
+ this.configurationProviderException = configurationProviderException;
+ }
+
+ public Configuration getConfiguration() throws ConfigurationProviderException {
+ if (configurationProviderException != null) {
+ throw configurationProviderException;
+ }
+ return configuration;
+ }
+
+ public MediaType getMediaType() throws ConfigurationProviderException {
+ if (configurationProviderException != null) {
+ throw configurationProviderException;
+ }
+ return mediaType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-docs/src/main/markdown/System_Admin_Guide.md
----------------------------------------------------------------------
diff --git a/minifi-docs/src/main/markdown/System_Admin_Guide.md b/minifi-docs/src/main/markdown/System_Admin_Guide.md
index f1d85c3..9c7115a 100644
--- a/minifi-docs/src/main/markdown/System_Admin_Guide.md
+++ b/minifi-docs/src/main/markdown/System_Admin_Guide.md
@@ -104,6 +104,10 @@ Option | Description
------ | -----------
nifi.minifi.notifier.ingestors.pull.http.hostname | Hostname on which to pull configurations from
nifi.minifi.notifier.ingestors.pull.http.port | Port on which to pull configurations from
+nifi.minifi.notifier.ingestors.pull.http.proxy.hostname | Proxy server hostname
+nifi.minifi.notifier.ingestors.pull.http.proxy.port | Proxy server port
+nifi.minifi.notifier.ingestors.pull.http.proxy.username | Proxy username
+nifi.minifi.notifier.ingestors.pull.http.proxy.password | Proxy password
nifi.minifi.notifier.ingestors.pull.http.path | Path on which to pull configurations from
nifi.minifi.notifier.ingestors.pull.http.period.ms | Period on which to pull configurations from, defaults to 5 minutes if not set.
nifi.minifi.notifier.ingestors.pull.http.use.etag | If the destination server is set up with cache control ability and utilizes an "ETag" header, then this should be set to true to utilize it. Very simply, the Ingestor remembers the "ETag" of the last successful pull (returned 200) then uses that "ETag" in a "If-None-Match" header on the next request.
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/pom.xml b/minifi-integration-tests/pom.xml
index 6356434..224858c 100644
--- a/minifi-integration-tests/pom.xml
+++ b/minifi-integration-tests/pom.xml
@@ -28,6 +28,7 @@ limitations under the License.
<properties>
<minifi.version>${project.version}</minifi.version>
+ <minifi.c2.version>${project.version}</minifi.c2.version>
</properties>
<dependencies>
@@ -45,6 +46,24 @@ limitations under the License.
</dependency>
<dependency>
<groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-integration-tests</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-toolkit-tls</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
<artifactId>minifi-toolkit-configuration</artifactId>
<version>${project.version}</version>
<scope>test</scope>
@@ -71,6 +90,16 @@ limitations under the License.
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
+ <includes>
+ <include>docker-compose-*.yml</include>
+ </includes>
+ </testResource>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>false</filtering>
+ <excludes>
+ <exclude>docker-compose-*.yml</exclude>
+ </excludes>
</testResource>
</testResources>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/HierarchicalC2IntegrationTest.java
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/HierarchicalC2IntegrationTest.java b/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/HierarchicalC2IntegrationTest.java
new file mode 100644
index 0000000..58c936f
--- /dev/null
+++ b/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/c2/HierarchicalC2IntegrationTest.java
@@ -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.
+ */
+
+package org.apache.nifi.minifi.integration.c2;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpsStatusCodeHealthCheck;
+import org.apache.nifi.minifi.integration.util.LogUtil;
+import org.apache.nifi.security.util.SslContextFactory;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandalone;
+import org.apache.nifi.toolkit.tls.standalone.TlsToolkitStandaloneCommandLine;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+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;
+
+public class HierarchicalC2IntegrationTest {
+ private static Path certificatesDirectory;
+ private static SSLContext trustSslContext;
+ private static SSLSocketFactory healthCheckSocketFactory;
+
+ // Not annotated as rule because we need to generate certificatesDirectory first
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-c2-hierarchical.yml")
+ .waitingForServices(Arrays.asList("squid-edge3", "c2"),
+ new HttpsStatusCodeHealthCheck(container -> "https://c2-authoritative:10443/c2/config",
+ containers -> containers.get(0), containers -> containers.get(1), () -> healthCheckSocketFactory, 403))
+ .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
+ */
+ @BeforeClass
+ public static void initCertificates() throws Exception {
+ resourceDirectory = Paths.get(HierarchicalC2IntegrationTest.class.getClassLoader()
+ .getResource("docker-compose-c2-hierarchical.yml").getFile()).getParent();
+ certificatesDirectory = resourceDirectory.toAbsolutePath().resolve("certificates-c2-hierarchical");
+ authoritativeFiles = resourceDirectory.resolve("c2").resolve("hierarchical").resolve("c2-authoritative").resolve("files");
+ minifiEdge1Version2 = authoritativeFiles.resolve("edge1").resolve("raspi3").resolve("config.text.yml.v2");
+ minifiEdge2Version2 = authoritativeFiles.resolve("edge2").resolve("raspi2").resolve("config.text.yml.v2");
+ minifiEdge3Version2 = authoritativeFiles.resolve("edge3").resolve("raspi3").resolve("config.text.yml.v2");
+
+ 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("c2-authoritative", "minifi-edge1", "c2-edge2", "minifi-edge3")) {
+ 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());
+
+ trustSslContext = SslContextFactory.createTrustSslContext(certificatesDirectory.resolve("c2-authoritative")
+ .resolve("truststore.jks").toFile().getAbsolutePath(), "badTrustPass".toCharArray(), "jks", "TLS");
+ healthCheckSocketFactory = trustSslContext.getSocketFactory();
+
+ docker.before();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ docker.after();
+ }
+
+ @Test(timeout = 120_000)
+ public void testMiNiFiEdge1() throws Exception {
+ LogUtil.verifyLogEntries("c2/hierarchical/minifi-edge1/expected.json", docker.containers().container("minifi-edge1"));
+ Path csvToJsonDir = resourceDirectory.resolve("standalone").resolve("v1").resolve("CsvToJson").resolve("yml");
+ Files.copy(csvToJsonDir.resolve("CsvToJson.yml"), minifiEdge1Version2);
+ LogUtil.verifyLogEntries("standalone/v1/CsvToJson/yml/expected.json", docker.containers().container("minifi-edge1"));
+ }
+
+ @Test(timeout = 120_000)
+ public void testMiNiFiEdge2() throws Exception {
+ LogUtil.verifyLogEntries("c2/hierarchical/minifi-edge2/expected.json", docker.containers().container("minifi-edge2"));
+ Path csvToJsonDir = resourceDirectory.resolve("standalone").resolve("v1").resolve("CsvToJson").resolve("yml");
+ Files.copy(csvToJsonDir.resolve("CsvToJson.yml"), minifiEdge2Version2);
+ LogUtil.verifyLogEntries("standalone/v1/CsvToJson/yml/expected.json", docker.containers().container("minifi-edge2"));
+ }
+
+ @Test(timeout = 120_000)
+ public void testMiNiFiEdge3() throws Exception {
+ LogUtil.verifyLogEntries("c2/hierarchical/minifi-edge3/expected.json", docker.containers().container("minifi-edge3"));
+ Path csvToJsonDir = resourceDirectory.resolve("standalone").resolve("v1").resolve("CsvToJson").resolve("yml");
+ Files.copy(csvToJsonDir.resolve("CsvToJson.yml"), minifiEdge3Version2);
+ LogUtil.verifyLogEntries("standalone/v1/CsvToJson/yml/expected.json", docker.containers().container("minifi-edge3"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/standalone/test/StandaloneYamlTest.java
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/standalone/test/StandaloneYamlTest.java b/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/standalone/test/StandaloneYamlTest.java
index bf9cd96..3d3dee8 100644
--- a/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/standalone/test/StandaloneYamlTest.java
+++ b/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/standalone/test/StandaloneYamlTest.java
@@ -18,10 +18,9 @@
package org.apache.nifi.minifi.integration.standalone.test;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.palantir.docker.compose.DockerComposeRule;
-import com.palantir.docker.compose.connection.DockerPort;
import com.palantir.docker.compose.connection.waiting.HealthChecks;
+import org.apache.nifi.minifi.integration.util.LogUtil;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,15 +34,8 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import java.util.regex.Pattern;
-
-import static org.junit.Assert.fail;
@RunWith(Parameterized.class)
public class StandaloneYamlTest {
@@ -98,34 +90,7 @@ public class StandaloneYamlTest {
}
@Test(timeout = 60_000)
- public void verifyLogEntries() throws IOException, InterruptedException, ExecutionException {
- Pattern expectedLine;
- int expectedOccurences;
- try (InputStream inputStream = StandaloneYamlTest.class.getClassLoader().getResourceAsStream(getExpectedJson())) {
- Map<String, Object> map = new ObjectMapper().readValue(inputStream, Map.class);
- expectedLine = Pattern.compile((String) map.get("pattern"));
- expectedOccurences = (int) map.getOrDefault("occurrences", 1);
- }
- DockerPort dockerPort = dockerComposeRule.containers().container("minifi").port(8000);
- URL url = new URL("http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort());
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- try (InputStream inputStream = urlConnection.getInputStream();
- InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
- String line;
- int occurrences = 0;
- while ((line = bufferedReader.readLine()) != null) {
- if (expectedLine.matcher(line).find()) {
- logger.info("Found expected: " + line);
- if (++occurrences >= expectedOccurences) {
- logger.info("Found target " + occurrences + " times");
- return;
- }
- }
- }
- fail("End of log reached without " + expectedOccurences + " match(es)");
- } finally {
- urlConnection.disconnect();
- }
+ public void verifyLogEntries() throws Exception {
+ LogUtil.verifyLogEntries(getExpectedJson(), dockerComposeRule.containers().container("minifi"));
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/util/LogUtil.java
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/util/LogUtil.java b/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/util/LogUtil.java
new file mode 100644
index 0000000..3c60ecd
--- /dev/null
+++ b/minifi-integration-tests/src/test/java/org/apache/nifi/minifi/integration/util/LogUtil.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.palantir.docker.compose.connection.Container;
+import com.palantir.docker.compose.connection.DockerPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.fail;
+
+public class LogUtil {
+ private static final Logger logger = LoggerFactory.getLogger(LogUtil.class);
+
+ public static void verifyLogEntries(String expectedJsonFilename, Container container) throws Exception {
+ List<ExpectedLogEntry> expectedLogEntries;
+ try (InputStream inputStream = LogUtil.class.getClassLoader().getResourceAsStream(expectedJsonFilename)) {
+ List<Map<String, Object>> expected = new ObjectMapper().readValue(inputStream, List.class);
+ expectedLogEntries = expected.stream().map(map -> new ExpectedLogEntry(Pattern.compile((String)map.get("pattern")), (int) map.getOrDefault("occurrences", 1))).collect(Collectors.toList());
+ }
+ DockerPort dockerPort = container.port(8000);
+ URL url = new URL("http://" + dockerPort.getIp() + ":" + dockerPort.getExternalPort());
+ HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ try (InputStream inputStream = urlConnection.getInputStream();
+ InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+ BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
+ String line;
+ for (ExpectedLogEntry expectedLogEntry : expectedLogEntries) {
+ boolean satisfied = false;
+ int occurrences = 0;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (expectedLogEntry.pattern.matcher(line).find()) {
+ logger.info("Found expected: " + line);
+ if (++occurrences >= expectedLogEntry.numOccurrences) {
+ logger.info("Found target " + occurrences + " times");
+ satisfied = true;
+ break;
+ }
+ }
+ }
+ if (!satisfied) {
+ fail("End of log reached without " + expectedLogEntry.numOccurrences + " match(es) of " + expectedLogEntry.pattern);
+ }
+ }
+ } finally {
+ urlConnection.disconnect();
+ }
+ }
+
+ private static class ExpectedLogEntry {
+ private final Pattern pattern;
+ private final int numOccurrences;
+
+ private ExpectedLogEntry(Pattern pattern, int numOccurrences) {
+ this.pattern = pattern;
+ this.numOccurrences = numOccurrences;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorities.yaml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorities.yaml b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorities.yaml
new file mode 100644
index 0000000..426f1b8
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/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=c2-edge2, OU=NIFI:
+ - EDGE_2
+CN=minifi-edge3, OU=NIFI:
+ - EDGE_3
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorizations.yaml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorizations.yaml b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorizations.yaml
new file mode 100644
index 0000000..24097b8
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/authorizations.yaml
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the \"License\"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an \"AS IS\" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Default Action: deny
+Paths:
+ /c2/config:
+ Default Action: deny
+ Actions:
+ - Authorization: EDGE_1
+ Query Parameters:
+ net: edge1
+ class: raspi3
+ Action: allow
+ - Authorization: EDGE_2
+ Query Parameters:
+ net: edge2
+ class: raspi2
+ Action: allow
+ - Authorization: EDGE_3
+ Query Parameters:
+ net: edge3
+ class: raspi3
+ Action: allow
+
+ /c2/config/contentTypes:
+ Default Action: deny
+ Actions:
+ - Authorization: EDGE_2
+ Action: allow
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/c2.properties
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/c2.properties b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/c2.properties
new file mode 100644
index 0000000..d1b01ee
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/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
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/minifi-c2-context.xml b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..95db871
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/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 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://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>${net}/${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>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge1/raspi3/config.text.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge1/raspi3/config.text.yml.v1 b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge1/raspi3/config.text.yml.v1
new file mode 100644
index 0000000..d778600
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge1/raspi3/config.text.yml.v1
@@ -0,0 +1,63 @@
+# 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 1 raspi3.v1
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge2/raspi2/config.text.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge2/raspi2/config.text.yml.v1 b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge2/raspi2/config.text.yml.v1
new file mode 100644
index 0000000..d762ad6
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge2/raspi2/config.text.yml.v1
@@ -0,0 +1,63 @@
+# 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 2 raspi2.v1
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge3/raspi3/config.text.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge3/raspi3/config.text.yml.v1 b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge3/raspi3/config.text.yml.v1
new file mode 100644
index 0000000..da30790
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-authoritative/files/edge3/raspi3/config.text.yml.v1
@@ -0,0 +1,63 @@
+# 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 3 raspi3.v1
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/c2.properties
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/c2.properties b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/c2.properties
new file mode 100644
index 0000000..58522fc
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/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=10080
+
+minifi.c2.server.secure=false
+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
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/minifi-c2-context.xml b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..3c11dd7
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/c2-edge2/conf/minifi-c2-context.xml
@@ -0,0 +1,62 @@
+<?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 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://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.delegating.DelegatingConfigurationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./cache</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${class}/${class}</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>https://c2-authoritative:10443</value>
+ </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>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/bootstrap.conf
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/bootstrap.conf b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/bootstrap.conf
new file mode 100644
index 0000000..8047642
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/bootstrap.conf
@@ -0,0 +1,106 @@
+#
+# 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.
+#
+
+# 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=
+# 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=5
+
+# 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=n,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
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/expected.json
----------------------------------------------------------------------
diff --git a/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/expected.json b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/expected.json
new file mode 100644
index 0000000..ef85cef
--- /dev/null
+++ b/minifi-integration-tests/src/test/resources/c2/hierarchical/minifi-edge1/expected.json
@@ -0,0 +1,8 @@
+[
+ {
+ "pattern": "ConfigurationChangeCoordinator Notifying Listeners of a change"
+ },
+ {
+ "pattern": "MiNiFi has finished reloading successfully and swap file exists. Deleting old configuration"
+ }
+]
\ No newline at end of file
[4/4] nifi-minifi git commit: MINIFI-272 - Delegating C2 Provider,
Caching ConfigService, Tests Proxy auth, caching fixes Added C2 readme
Posted by al...@apache.org.
MINIFI-272 - Delegating C2 Provider, Caching ConfigService, Tests
Proxy auth, caching fixes
Added C2 readme
This closes #79.
Signed-off-by: Aldrin Piri <al...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/nifi-minifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-minifi/commit/4dc0ce30
Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi/tree/4dc0ce30
Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi/diff/4dc0ce30
Branch: refs/heads/master
Commit: 4dc0ce30360f97125f0ae46b130b60e45a986a6d
Parents: b556187
Author: Bryan Rosander <br...@apache.org>
Authored: Tue Apr 18 15:25:08 2017 -0400
Committer: Aldrin Piri <al...@apache.org>
Committed: Mon May 15 09:33:46 2017 -0400
----------------------------------------------------------------------
.../ingestors/PullHttpChangeIngestor.java | 33 +-
minifi-c2/README.md | 33 +
minifi-c2/c2-integration-test.graphml | 630 +++++++++++++++++++
minifi-c2/c2-integration-test.png | Bin 0 -> 26942 bytes
.../nifi/minifi/c2/api/Configuration.java | 2 +
.../minifi/c2/api/ConfigurationProvider.java | 8 +-
.../c2/api/ConfigurationProviderException.java | 14 +
.../minifi/c2/api/cache/ConfigurationCache.java | 2 +-
.../minifi/c2/api/properties/C2Properties.java | 8 +-
.../authorization/AuthorizationException.java | 4 +-
minifi-c2/minifi-c2-assembly/pom.xml | 5 +
.../src/main/resources/conf/authorizations.yaml | 11 +-
.../main/resources/conf/minifi-c2-context.xml | 9 +-
.../resources/files/raspi3/config.text.yml.v1 | 63 ++
.../main/resources/files/raspi3/config.yml.v1 | 63 --
.../FileSystemConfigurationCache.java | 15 +-
minifi-c2/minifi-c2-integration-tests/pom.xml | 11 +
...legatingConfigurationProviderSecureTest.java | 79 +++
...gatingConfigurationProviderUnsecureTest.java | 37 ++
.../conf/minifi-c2-context.xml | 56 ++
.../c2-secure-rest/conf/minifi-c2-context.xml | 3 +
.../conf/minifi-c2-context.xml | 56 ++
.../c2-unsecure-rest/conf/minifi-c2-context.xml | 3 +
.../c2-upstream-secure/conf/authorities.yaml | 17 +
.../c2-upstream-secure/conf/authorizations.yaml | 32 +
.../c2/files/raspi2/config.text.yml.v1 | 63 ++
.../resources/c2/files/raspi2/config.yml.v1 | 63 --
.../c2/files/raspi3/config.text.yml.v1 | 63 ++
.../c2/files/raspi3/config.text.yml.v2 | 63 ++
.../resources/c2/files/raspi3/config.yml.v1 | 63 --
.../resources/c2/files/raspi3/config.yml.v2 | 63 --
...ker-compose-DelegatingProviderSecureTest.yml | 55 ++
...r-compose-DelegatingProviderUnsecureTest.yml | 32 +
.../nifi/minifi/c2/jetty/JettyServer.java | 8 +-
.../cache/CacheConfigurationProvider.java | 14 +-
.../cache/CacheConfigurationProviderTest.java | 18 +-
.../minifi-c2-provider-delegating/pom.xml | 53 ++
.../DelegatingConfigurationProvider.java | 171 +++++
.../DelegatingConfigurationProviderTest.java | 195 ++++++
.../minifi-c2-provider-nifi-rest/pom.xml | 5 +
.../rest/NiFiRestConfigurationProvider.java | 87 ++-
.../provider/nifi/rest/NiFiRestConnector.java | 80 ---
.../provider/nifi/rest/TemplatesIterator.java | 5 +-
.../rest/NiFiRestConfigurationProviderTest.java | 12 +-
.../nifi/rest/TemplatesIteratorTest.java | 15 +-
.../minifi-c2-provider-util/pom.xml | 44 ++
.../minifi/c2/provider/util/HttpConnector.java | 130 ++++
minifi-c2/minifi-c2-provider/pom.xml | 2 +
minifi-c2/minifi-c2-service/pom.xml | 10 +
.../nifi/minifi/c2/service/ConfigService.java | 163 ++++-
.../c2/service/ConfigurationProviderInfo.java | 51 ++
.../c2/service/ConfigurationProviderKey.java | 69 ++
.../c2/service/ConfigurationProviderValue.java | 49 ++
.../src/main/markdown/System_Admin_Guide.md | 4 +
minifi-integration-tests/pom.xml | 29 +
.../c2/HierarchicalC2IntegrationTest.java | 125 ++++
.../standalone/test/StandaloneYamlTest.java | 41 +-
.../nifi/minifi/integration/util/LogUtil.java | 85 +++
.../c2-authoritative/conf/authorities.yaml | 21 +
.../c2-authoritative/conf/authorizations.yaml | 41 ++
.../c2-authoritative/conf/c2.properties | 27 +
.../c2-authoritative/conf/minifi-c2-context.xml | 63 ++
.../files/edge1/raspi3/config.text.yml.v1 | 63 ++
.../files/edge2/raspi2/config.text.yml.v1 | 63 ++
.../files/edge3/raspi3/config.text.yml.v1 | 63 ++
.../c2/hierarchical/c2-edge2/conf/c2.properties | 27 +
.../c2-edge2/conf/minifi-c2-context.xml | 62 ++
.../c2/hierarchical/minifi-edge1/bootstrap.conf | 106 ++++
.../c2/hierarchical/minifi-edge1/expected.json | 8 +
.../c2/hierarchical/minifi-edge2/bootstrap.conf | 99 +++
.../c2/hierarchical/minifi-edge2/expected.json | 8 +
.../c2/hierarchical/minifi-edge3/bootstrap.conf | 109 ++++
.../c2/hierarchical/minifi-edge3/expected.json | 8 +
.../docker-compose-c2-hierarchical.yml | 126 ++++
.../src/test/resources/logback.xml | 2 +
.../src/test/resources/squid/squid.conf | 19 +
.../standalone/v1/CsvToJson/xml/expected.json | 10 +-
.../standalone/v1/CsvToJson/yml/expected.json | 10 +-
.../DecompressionCircularFlow/xml/expected.json | 10 +-
.../DecompressionCircularFlow/yml/expected.json | 10 +-
.../v1/MiNiFiTailLogAttribute/xml/expected.json | 10 +-
.../v1/MiNiFiTailLogAttribute/yml/expected.json | 10 +-
.../xml/expected.json | 10 +-
.../yml/expected.json | 10 +-
.../v2/MultipleRelationships/xml/expected.json | 10 +-
.../v2/MultipleRelationships/yml/expected.json | 10 +-
.../v2/ProcessGroups/xml/expected.json | 10 +-
.../v2/ProcessGroups/yml/expected.json | 10 +-
.../v2/StressTestFramework/xml/expected.json | 10 +-
.../v2/StressTestFramework/yml/expected.json | 10 +-
.../src/test/resources/tailFileServer.py | 12 +-
91 files changed, 3665 insertions(+), 526 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
----------------------------------------------------------------------
diff --git a/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java b/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
index 3ec26d0..6c8adcc 100644
--- a/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
+++ b/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
@@ -18,6 +18,7 @@
package org.apache.nifi.minifi.bootstrap.configuration.ingestors;
import okhttp3.Call;
+import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -37,6 +38,9 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.nio.ByteBuffer;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
@@ -73,6 +77,10 @@ public class PullHttpChangeIngestor extends AbstractPullChangeIngestor {
public static final String HOST_KEY = PULL_HTTP_BASE_KEY + ".hostname";
public static final String PATH_KEY = PULL_HTTP_BASE_KEY + ".path";
public static final String QUERY_KEY = PULL_HTTP_BASE_KEY + ".query";
+ public static final String PROXY_HOST_KEY = PULL_HTTP_BASE_KEY + ".proxy.hostname";
+ public static final String PROXY_PORT_KEY = PULL_HTTP_BASE_KEY + ".proxy.port";
+ public static final String PROXY_USERNAME = PULL_HTTP_BASE_KEY + ".proxy.username";
+ public static final String PROXY_PASSWORD = PULL_HTTP_BASE_KEY + ".proxy.password";
public static final String TRUSTSTORE_LOCATION_KEY = PULL_HTTP_BASE_KEY + ".truststore.location";
public static final String TRUSTSTORE_PASSWORD_KEY = PULL_HTTP_BASE_KEY + ".truststore.password";
public static final String TRUSTSTORE_TYPE_KEY = PULL_HTTP_BASE_KEY + ".truststore.type";
@@ -147,6 +155,23 @@ public class PullHttpChangeIngestor extends AbstractPullChangeIngestor {
// Set whether to follow redirects
okHttpClientBuilder.followRedirects(true);
+ String proxyHost = properties.getProperty(PROXY_HOST_KEY, "");
+ if (!proxyHost.isEmpty()) {
+ String proxyPort = properties.getProperty(PROXY_PORT_KEY);
+ if (proxyPort == null || proxyPort.isEmpty()) {
+ throw new IllegalArgumentException("Proxy port required if proxy specified.");
+ }
+ okHttpClientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort))));
+ String proxyUsername = properties.getProperty(PROXY_USERNAME);
+ if (proxyUsername != null) {
+ String proxyPassword = properties.getProperty(PROXY_PASSWORD);
+ if (proxyPassword == null) {
+ throw new IllegalArgumentException("Must specify proxy password with proxy username.");
+ }
+ okHttpClientBuilder.proxyAuthenticator((route, response) -> response.request().newBuilder().addHeader("Proxy-Authorization", Credentials.basic(proxyUsername, proxyPassword)).build());
+ }
+ }
+
// check if the ssl path is set and add the factory if so
if (properties.containsKey(KEYSTORE_LOCATION_KEY)) {
try {
@@ -210,10 +235,16 @@ public class PullHttpChangeIngestor extends AbstractPullChangeIngestor {
logger.debug("Response received: {}", response.toString());
- if (response.code() == NOT_MODIFIED_STATUS_CODE) {
+ int code = response.code();
+
+ if (code == NOT_MODIFIED_STATUS_CODE) {
return;
}
+ if (code >= 400) {
+ throw new IOException("Got response code " + code + " while trying to pull configuration: " + response.body().string());
+ }
+
ResponseBody body = response.body();
if (body == null) {
logger.warn("No body returned when pulling a new configuration");
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/README.md
----------------------------------------------------------------------
diff --git a/minifi-c2/README.md b/minifi-c2/README.md
new file mode 100644
index 0000000..2440947
--- /dev/null
+++ b/minifi-c2/README.md
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+## Apache NiFi MiNiFi Command and Control (C2) Server
+MiNiFi agents allow us to push data flows down to smaller devices on the edge of the network. This provides many of the niceties of processing data with NiFi in a smaller package. One big challenge with many disparate agents running on all sorts of devices is coordinating their work and pushing out revised flows.
+
+The C2 server is the beginning of an attempt to address this usecase. It provides an endpoint for existing PullHttpChangeIngestor functionality that is intended to facilitate distributing appropriate flow definitions to each class of agent.
+
+In the assumed usecase one or more class of MiNiFi agent polls the C2 server periodically for updates to its flow. When there is a new version available, the C2 server will send it back to the agent at which point the agent will attempt to restart itself with the new flow, rolling back if there is a problem starting.
+
+The C2 server is intended to be extensible and flexibly configurable. The ConfigurationProvider interface is the main extension point where arbitrary logic should be able to be used to get updated flows. The server supports bidirectional TLS authentication and configurable authorization.
+
+### Configuration Providers:
+There are three ConfigurationProvider implementations provided out of the box.
+1. The [CacheConfigurationProvider](./minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml) looks at directory on the filesystem.
+2. The [DelegatingConfigurationProvider](./minifi-c2-integration-tests/src/test/resources/c2-unsecure-delegating/conf/minifi-c2-context.xml) delegates to another C2 server to allow for hierarchical C2 structures to help with scaling and/or bridging networks.
+3. The [NiFiRestConfigurationProvider](./minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml) pulls templates from a NiFi instance over its REST API. (Note: sensitive values are NOT included in templates so this is unsuitable for flows with sensitive configuration currently)
+
+### Example network diagram:
+Below is a network diagram showing the different configurations tested by [our hierarchical integration test docker-compose file.](../minifi-integration-tests/src/test/resources/docker-compose-c2-hierarchical.yml) It consists of a "cluster" network where real processing might occur as well as 3 "edge" networks that can get configuration from the cluster network a few different ways. The edge1 instance can directly access the authoritative C2 server via HTTPS. The edge2 instance is representative of a segmented network where the MiNiFi agents can talk to a local delegating C2 server over HTTP which asks the authoritative C2 server over HTTPS. The edge 3 instance can talk to the authoritative C2 server through a Squid proxy over HTTPS.
+
+
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/c2-integration-test.graphml
----------------------------------------------------------------------
diff --git a/minifi-c2/c2-integration-test.graphml b/minifi-c2/c2-integration-test.graphml
new file mode 100644
index 0000000..82fbbf5
--- /dev/null
+++ b/minifi-c2/c2-integration-test.graphml
@@ -0,0 +1,630 @@
+<?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.
+-->
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.17-->
+ <key attr.name="Description" attr.type="string" for="graph" id="d0"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key for="graphml" id="d7" yfiles.type="resources"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d0"/>
+ <node id="n0">
+ <data key="d5"/>
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="235.78499794006348" width="200.0" x="697.236499786377" y="142.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="n" textColor="#000000" verticalTextPosition="bottom" visible="true" width="100.509765625" x="49.7451171875" y="-21.96875">Cluster Network</y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d5"/>
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="235.78499794006348" width="353.0" x="337.4729995727539" y="142.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="s" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.751953125" x="128.6240234375" y="239.78499794006348">Edge1 Network</y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d5"/>
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="235.78499794006348" width="244.92939949035645" x="673.236499786377" y="383.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="s" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.751953125" x="74.58872318267822" y="239.78499794006348">Edge2 Network</y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d5"/>
+ <data key="d6">
+ <y:SVGNode>
+ <y:Geometry height="46.887996673583984" width="39.527000427246094" x="673.236499786377" y="232.556001663208"/>
+ <y:Fill color="#CCCCFF" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="102.66015625" x="-31.566577911376953" y="50.887996673583984">C2-Authoritative<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:SVGNodeProperties usingVisualBounds="true"/>
+ <y:SVGModel svgBoundsPolicy="0">
+ <y:SVGContent refid="1"/>
+ </y:SVGModel>
+ </y:SVGNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d5"/>
+ <data key="d6">
+ <y:SVGNode>
+ <y:Geometry height="45.56999588012695" width="67.49800109863281" x="406.2509994506836" y="233.21500205993652"/>
+ <y:Fill color="#CCCCFF" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="82.3984375" x="-7.450218200683594" y="49.56999588012695">MiNiFi-Edge1<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:SVGNodeProperties usingVisualBounds="true"/>
+ <y:SVGModel svgBoundsPolicy="0">
+ <y:SVGContent refid="2"/>
+ </y:SVGModel>
+ </y:SVGNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d5"/>
+ <data key="d6">
+ <y:SVGNode>
+ <y:Geometry height="46.887996673583984" width="39.527000427246094" x="777.4729995727539" y="353.556001663208"/>
+ <y:Fill color="#CCCCFF" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="62.177734375" x="-11.325366973876953" y="50.887996673583984">C2-Edge2<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:SVGNodeProperties usingVisualBounds="true"/>
+ <y:SVGModel svgBoundsPolicy="0">
+ <y:SVGContent refid="1"/>
+ </y:SVGModel>
+ </y:SVGNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d5"/>
+ <data key="d6">
+ <y:ShapeNode>
+ <y:Geometry height="235.78499794006348" width="353.0" x="904.0" y="142.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="s" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.751953125" x="128.6240234375" y="239.78499794006348">Edge3 Network</y:NodeLabel>
+ <y:Shape type="rectangle"/>
+ </y:ShapeNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d5"/>
+ <data key="d6">
+ <y:SVGNode>
+ <y:Geometry height="56.231998443603516" width="35.095298767089844" x="883.0706005096436" y="227.88400077819824"/>
+ <y:Fill color="#CCCCFF" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="79.955078125" x="-22.429889678955078" y="60.231998443603516">Squid-Edge3<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:SVGNodeProperties usingVisualBounds="true"/>
+ <y:SVGModel svgBoundsPolicy="0">
+ <y:SVGContent refid="3"/>
+ </y:SVGModel>
+ </y:SVGNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d5"/>
+ <data key="d6">
+ <y:SVGNode>
+ <y:Geometry height="45.56999588012695" width="67.49800109863281" x="763.4874992370605" y="494.2150020599365"/>
+ <y:Fill color="#CCCCFF" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="82.3984375" x="-7.450218200683594" y="49.56999588012695">MiNiFi-Edge2<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:SVGNodeProperties usingVisualBounds="true"/>
+ <y:SVGModel svgBoundsPolicy="0">
+ <y:SVGContent refid="2"/>
+ </y:SVGModel>
+ </y:SVGNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d5"/>
+ <data key="d6">
+ <y:SVGNode>
+ <y:Geometry height="45.56999588012695" width="67.49800109863281" x="1150.2509994506836" y="233.21500205993652"/>
+ <y:Fill color="#CCCCFF" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="82.3984375" x="-7.450218200683594" y="49.56999588012695">MiNiFi-Edge3<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:SVGNodeProperties usingVisualBounds="true"/>
+ <y:SVGModel svgBoundsPolicy="0">
+ <y:SVGContent refid="2"/>
+ </y:SVGModel>
+ </y:SVGNode>
+ </data>
+ </node>
+ <edge id="e0" source="n7" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="4.0" x="-87.13782024383545" y="-32.0">
+ <y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n5" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="797.236499786377" y="307.0"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="34.884765625" x="-49.6274086199204" y="-39.45283459422296">https<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="14.742631550828632" distanceToCenter="false" position="left" ratio="0.5051381794669789" segment="0"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n2" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n8" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="866.0" y="430.0"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="28.6328125" x="62.408460259019535" y="-57.01320364330013">http<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="13.608613619663785" distanceToCenter="false" position="right" ratio="3.4125279749916686" segment="-2"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e4" source="n4" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="34.884765625" x="92.36250114440918" y="21.015625">https<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e5" source="n9" target="n7">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="152.470703125" x="-202.3311014175415" y="-38.984375">https through http proxy<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d7">
+ <y:Resources>
+ <y:Resource id="1"><?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0px" y="0px" width="41px" height="48px" viewBox="-0.875 -0.887 41 48" enable-background="new -0.875 -0.887 41 48"
+ xml:space="preserve">
+<defs>
+</defs>
+<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-979.1445" x2="682.0508" y2="-979.1445" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#3C89C9"/>
+ <stop offset="0.1482" style="stop-color:#60A6DD"/>
+ <stop offset="0.3113" style="stop-color:#81C1F0"/>
+ <stop offset="0.4476" style="stop-color:#95D1FB"/>
+ <stop offset="0.5394" style="stop-color:#9CD7FF"/>
+ <stop offset="0.636" style="stop-color:#98D4FD"/>
+ <stop offset="0.7293" style="stop-color:#8DCAF6"/>
+ <stop offset="0.8214" style="stop-color:#79BBEB"/>
+ <stop offset="0.912" style="stop-color:#5EA5DC"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<path fill="url(#SVGID_1_)" d="M19.625,36.763C8.787,36.763,0,34.888,0,32.575v10c0,2.313,8.787,4.188,19.625,4.188
+ c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,34.888,30.464,36.763,19.625,36.763z"/>
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-973.1445" x2="682.0508" y2="-973.1445" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#9CD7FF"/>
+ <stop offset="0.0039" style="stop-color:#9DD7FF"/>
+ <stop offset="0.2273" style="stop-color:#BDE5FF"/>
+ <stop offset="0.4138" style="stop-color:#D1EEFF"/>
+ <stop offset="0.5394" style="stop-color:#D9F1FF"/>
+ <stop offset="0.6155" style="stop-color:#D5EFFE"/>
+ <stop offset="0.6891" style="stop-color:#C9E7FA"/>
+ <stop offset="0.7617" style="stop-color:#B6DAF3"/>
+ <stop offset="0.8337" style="stop-color:#9AC8EA"/>
+ <stop offset="0.9052" style="stop-color:#77B0DD"/>
+ <stop offset="0.9754" style="stop-color:#4D94CF"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<path fill="url(#SVGID_2_)" d="M19.625,36.763c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.927-18.396,3.927
+ c-9.481,0-17.396-1.959-18.396-3.927l-1.229,2C0,34.888,8.787,36.763,19.625,36.763z"/>
+<path fill="#3C89C9" d="M19.625,26.468c10.16,0,19.625,2.775,19.625,2.775c-0.375,2.721-5.367,5.438-19.554,5.438
+ c-12.125,0-18.467-2.484-19.541-4.918C-0.127,29.125,9.465,26.468,19.625,26.468z"/>
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-965.6948" x2="682.0508" y2="-965.6948" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#3C89C9"/>
+ <stop offset="0.1482" style="stop-color:#60A6DD"/>
+ <stop offset="0.3113" style="stop-color:#81C1F0"/>
+ <stop offset="0.4476" style="stop-color:#95D1FB"/>
+ <stop offset="0.5394" style="stop-color:#9CD7FF"/>
+ <stop offset="0.636" style="stop-color:#98D4FD"/>
+ <stop offset="0.7293" style="stop-color:#8DCAF6"/>
+ <stop offset="0.8214" style="stop-color:#79BBEB"/>
+ <stop offset="0.912" style="stop-color:#5EA5DC"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<path fill="url(#SVGID_3_)" d="M19.625,23.313C8.787,23.313,0,21.438,0,19.125v10c0,2.313,8.787,4.188,19.625,4.188
+ c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,21.438,30.464,23.313,19.625,23.313z"/>
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-959.6948" x2="682.0508" y2="-959.6948" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#9CD7FF"/>
+ <stop offset="0.0039" style="stop-color:#9DD7FF"/>
+ <stop offset="0.2273" style="stop-color:#BDE5FF"/>
+ <stop offset="0.4138" style="stop-color:#D1EEFF"/>
+ <stop offset="0.5394" style="stop-color:#D9F1FF"/>
+ <stop offset="0.6155" style="stop-color:#D5EFFE"/>
+ <stop offset="0.6891" style="stop-color:#C9E7FA"/>
+ <stop offset="0.7617" style="stop-color:#B6DAF3"/>
+ <stop offset="0.8337" style="stop-color:#9AC8EA"/>
+ <stop offset="0.9052" style="stop-color:#77B0DD"/>
+ <stop offset="0.9754" style="stop-color:#4D94CF"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<path fill="url(#SVGID_4_)" d="M19.625,23.313c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.926-18.396,3.926
+ c-9.481,0-17.396-1.959-18.396-3.926l-1.229,2C0,21.438,8.787,23.313,19.625,23.313z"/>
+<path fill="#3C89C9" d="M19.476,13.019c10.161,0,19.625,2.775,19.625,2.775c-0.375,2.721-5.367,5.438-19.555,5.438
+ c-12.125,0-18.467-2.485-19.541-4.918C-0.277,15.674,9.316,13.019,19.476,13.019z"/>
+<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-952.4946" x2="682.0508" y2="-952.4946" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#3C89C9"/>
+ <stop offset="0.1482" style="stop-color:#60A6DD"/>
+ <stop offset="0.3113" style="stop-color:#81C1F0"/>
+ <stop offset="0.4476" style="stop-color:#95D1FB"/>
+ <stop offset="0.5394" style="stop-color:#9CD7FF"/>
+ <stop offset="0.636" style="stop-color:#98D4FD"/>
+ <stop offset="0.7293" style="stop-color:#8DCAF6"/>
+ <stop offset="0.8214" style="stop-color:#79BBEB"/>
+ <stop offset="0.912" style="stop-color:#5EA5DC"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<path fill="url(#SVGID_5_)" d="M19.625,10.113C8.787,10.113,0,8.238,0,5.925v10c0,2.313,8.787,4.188,19.625,4.188
+ c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,8.238,30.464,10.113,19.625,10.113z"/>
+<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-946.4946" x2="682.0508" y2="-946.4946" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#9CD7FF"/>
+ <stop offset="0.0039" style="stop-color:#9DD7FF"/>
+ <stop offset="0.2273" style="stop-color:#BDE5FF"/>
+ <stop offset="0.4138" style="stop-color:#D1EEFF"/>
+ <stop offset="0.5394" style="stop-color:#D9F1FF"/>
+ <stop offset="0.6155" style="stop-color:#D5EFFE"/>
+ <stop offset="0.6891" style="stop-color:#C9E7FA"/>
+ <stop offset="0.7617" style="stop-color:#B6DAF3"/>
+ <stop offset="0.8337" style="stop-color:#9AC8EA"/>
+ <stop offset="0.9052" style="stop-color:#77B0DD"/>
+ <stop offset="0.9754" style="stop-color:#4D94CF"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<path fill="url(#SVGID_6_)" d="M19.625,10.113c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.926-18.396,3.926
+ c-9.481,0-17.396-1.959-18.396-3.926L0,5.925C0,8.238,8.787,10.113,19.625,10.113z"/>
+<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="644.0293" y1="-943.4014" x2="680.8223" y2="-943.4014" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)">
+ <stop offset="0" style="stop-color:#9CD7FF"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</linearGradient>
+<ellipse fill="url(#SVGID_7_)" cx="19.625" cy="3.926" rx="18.396" ry="3.926"/>
+<path opacity="0.24" fill="#FFFFFF" enable-background="new " d="M31.04,45.982c0,0-4.354,0.664-7.29,0.781
+ c-3.125,0.125-8.952,0-8.952,0l-2.384-10.292l0.044-2.108l-1.251-1.154L9.789,23.024l-0.082-0.119L9.5,20.529l-1.65-1.254
+ L5.329,8.793c0,0,4.213,0.903,7.234,1.07s8.375,0.25,8.375,0.25l3,9.875l-0.25,1.313l1.063,2.168l2.312,9.645l-0.521,1.416
+ l1.46,1.834L31.04,45.982z"/>
+</svg>
+</y:Resource>
+ <y:Resource id="2"><?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0px" y="0px" width="68px" height="46px" viewBox="-0.064 -0.075 68 46" enable-background="new -0.064 -0.075 68 46"
+ xml:space="preserve">
+<defs>
+</defs>
+<radialGradient id="SVGID_1_" cx="478.8413" cy="1991.2729" r="21.6001" gradientTransform="matrix(1.15 0 0 1 -526.6598 -1982.4023)" gradientUnits="userSpaceOnUse">
+ <stop offset="0" style="stop-color:#F2F2F2"/>
+ <stop offset="1" style="stop-color:#8D8D8D"/>
+</radialGradient>
+<path fill="url(#SVGID_1_)" d="M10.263,1.903c0-0.987,0.807-1.794,1.794-1.794h43.279c0.986,0,1.795,0.807,1.795,1.794v26.978
+ c0,0.987-0.809,1.794-1.795,1.794h-43.28c-0.987,0-1.794-0.807-1.794-1.794L10.263,1.903L10.263,1.903z"/>
+<path display="none" fill="none" stroke="#3C89C9" stroke-width="0.2185" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
+ M10.263,1.903c0-0.987,0.807-1.794,1.794-1.794h43.279c0.986,0,1.795,0.807,1.795,1.794v26.978c0,0.987-0.809,1.794-1.795,1.794
+ h-43.28c-0.987,0-1.794-0.807-1.794-1.794L10.263,1.903L10.263,1.903z"/>
+<radialGradient id="SVGID_2_" cx="455.894" cy="1983.9624" r="47.8462" fx="493.5344" fy="1977.5143" gradientTransform="matrix(1.1935 0 0 1 -509.6731 -1982.4023)" gradientUnits="userSpaceOnUse">
+ <stop offset="0" style="stop-color:#4D4D4D"/>
+ <stop offset="1" style="stop-color:#999999"/>
+</radialGradient>
+<path fill="url(#SVGID_2_)" d="M11.18,2.819c0-0.987,0.807-1.794,1.794-1.794h41.649c0.986,0,1.795,0.807,1.795,1.794v24.943
+ c0,0.985-0.809,1.794-1.795,1.794H12.974c-0.987,0-1.794-0.809-1.794-1.794V2.819z"/>
+<radialGradient id="SVGID_3_" cx="456.8843" cy="1984.0386" r="30.6699" gradientTransform="matrix(1.1923 0 0 1 -510.1314 -1982.4023)" gradientUnits="userSpaceOnUse">
+ <stop offset="0" style="stop-color:#9CD7FF"/>
+ <stop offset="1" style="stop-color:#3C89C9"/>
+</radialGradient>
+<path fill="url(#SVGID_3_)" d="M11.689,3.228c0-0.987,0.807-1.794,1.794-1.794h40.633c0.986,0,1.795,0.807,1.795,1.794v24.126
+ c0,0.986-0.809,1.794-1.795,1.794H13.483c-0.987,0-1.794-0.809-1.794-1.794V3.228z"/>
+<path opacity="0.24" fill="#F2F2F2" d="M11.689,21.472V3.228c0-0.987,0.807-1.794,1.794-1.794h40.633
+ c0.986,0,1.795,0.807,1.795,1.794v9.454c0,0.987-10.518,5.21-18.256,6.795C29.917,21.062,11.689,21.472,11.689,21.472z"/>
+<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="131.3501" y1="-212.2612" x2="131.3501" y2="-170.6274" gradientTransform="matrix(1 0 0 -1 -97.6001 -165.0498)">
+ <stop offset="0" style="stop-color:#4D4D4D"/>
+ <stop offset="0.0667" style="stop-color:#717171"/>
+ <stop offset="0.069" style="stop-color:#757575"/>
+ <stop offset="0.0831" style="stop-color:#8C8C8C"/>
+ <stop offset="0.0996" style="stop-color:#9E9E9E"/>
+ <stop offset="0.1196" style="stop-color:#AAAAAA"/>
+ <stop offset="0.1466" style="stop-color:#B1B1B1"/>
+ <stop offset="0.2121" style="stop-color:#B3B3B3"/>
+ <stop offset="1" style="stop-color:#C5C5C5"/>
+</linearGradient>
+<path fill="url(#SVGID_4_)" d="M58.385,32.234c-0.689-0.856-2.154-1.559-3.254-1.559H12c-1.1,0-2.552,0.711-3.227,1.579
+ l-7.546,9.717C0,43.55,0.042,43.785,0,44.55v0.125c0.056,0.393,0.311,1.002,1.248,1.002h64.75c0.75,0.002,1.5-0.252,1.5-1.002V44.55
+ c0-0.813,0-0.813-1.254-2.559L58.385,32.234z"/>
+<path opacity="0.23" fill="#F2F2F2" enable-background="new " d="M58.385,32.234c-0.689-0.856-2.154-1.559-3.254-1.559H12
+ c-1.1,0-2.552,0.711-3.227,1.579l-7.055,9.085l58.098-7.33L58.385,32.234z"/>
+<path fill="#6E6E6E" d="M59.75,37.205c0.344,0.431,0.172,0.783-0.377,0.783H8.249c-0.55,0-0.742-0.369-0.427-0.819l2.786-3.986
+ c0.315-0.45,1.023-0.819,1.573-0.819h42.729c0.551,0,1.279,0.354,1.623,0.783L59.75,37.205z"/>
+<path fill="#6E6E6E" d="M40.43,41.906c0.072,0.217-0.057,0.395-0.285,0.395H26.727c-0.229,0-0.364-0.18-0.3-0.398l0.822-2.826
+ c0.064-0.221,0.303-0.399,0.532-0.399h11.167c0.229,0,0.475,0.179,0.547,0.396L40.43,41.906z"/>
+</svg>
+</y:Resource>
+ <y:Resource id="3"><?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0px" y="0px" width="36px" height="57px" viewBox="0 -0.741 36 57" enable-background="new 0 -0.741 36 57"
+ xml:space="preserve">
+<defs>
+</defs>
+<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="230.1768" y1="798.6021" x2="180.3346" y2="798.6021" gradientTransform="matrix(1 0 0 1 -195.2002 -770.8008)">
+ <stop offset="0" style="stop-color:#4D4D4D"/>
+ <stop offset="1" style="stop-color:#8D8D8D"/>
+</linearGradient>
+<rect y="0.943" fill="url(#SVGID_1_)" width="34.977" height="53.716"/>
+<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="224.6807" y1="798.6021" x2="200.6973" y2="798.6021" gradientTransform="matrix(1 0 0 1 -195.2002 -770.8008)">
+ <stop offset="0.0319" style="stop-color:#848484"/>
+ <stop offset="0.1202" style="stop-color:#8C8C8C"/>
+ <stop offset="0.308" style="stop-color:#969696"/>
+ <stop offset="0.5394" style="stop-color:#999999"/>
+ <stop offset="0.5501" style="stop-color:#9C9C9C"/>
+ <stop offset="0.6256" style="stop-color:#B0B0B0"/>
+ <stop offset="0.7118" style="stop-color:#BEBEBE"/>
+ <stop offset="0.8178" style="stop-color:#C7C7C7"/>
+ <stop offset="1" style="stop-color:#C9C9C9"/>
+</linearGradient>
+<path fill="url(#SVGID_2_)" d="M5.497,0.943c7.945-1.258,16.04-1.258,23.983,0c0,17.905,0,35.811,0,53.716
+ c-7.943,1.258-16.039,1.258-23.983,0C5.497,36.753,5.497,18.848,5.497,0.943z"/>
+<path fill="#515151" d="M5.497,14.621c7.995,0,15.989,0,23.983,0c0,13.346,0,26.693,0,40.037c-7.943,1.258-16.039,1.258-23.983,0
+ C5.497,41.314,5.497,27.967,5.497,14.621z"/>
+<path opacity="0.43" fill="#565656" d="M5.497,4.745c7.982-0.628,16.001-0.628,23.983,0c0,2.707,0,5.413,0,8.12
+ c-7.994,0-15.989,0-23.983,0C5.497,10.158,5.497,7.452,5.497,4.745z"/>
+<path opacity="0.43" fill="none" stroke="#4D4D4D" stroke-width="0.0999" stroke-miterlimit="10" d="M5.497,4.745
+ c7.982-0.628,16.001-0.628,23.983,0c0,2.707,0,5.413,0,8.12c-7.994,0-15.989,0-23.983,0C5.497,10.158,5.497,7.452,5.497,4.745z"/>
+<polygon opacity="0.43" fill="#565656" stroke="#4D4D4D" stroke-width="0.0135" stroke-miterlimit="10" enable-background="new " points="
+ 6.496,5.746 9.869,5.606 9.869,6.661 6.496,6.799 "/>
+<rect x="31.307" y="2.517" fill="#E7ED00" stroke="#717171" stroke-width="0.1926" stroke-miterlimit="10" width="3.692" height="1.505"/>
+<rect x="31.307" y="5.8" fill="#C8FF00" stroke="#717171" stroke-width="0.1926" stroke-miterlimit="10" width="3.692" height="1.507"/>
+<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="29.4414" y1="35.1235" x2="5.4995" y2="35.1235">
+ <stop offset="0" style="stop-color:#808080"/>
+ <stop offset="0.1907" style="stop-color:#828282"/>
+ <stop offset="0.2955" style="stop-color:#8A8A8A"/>
+ <stop offset="0.3795" style="stop-color:#989898"/>
+ <stop offset="0.4524" style="stop-color:#ACACAC"/>
+ <stop offset="0.5175" style="stop-color:#C5C5C5"/>
+ <stop offset="0.5273" style="stop-color:#C9C9C9"/>
+ <stop offset="0.5914" style="stop-color:#C9C9C9"/>
+ <stop offset="0.9681" style="stop-color:#C9C9C9"/>
+</linearGradient>
+<path fill="url(#SVGID_3_)" d="M5.5,14.822c0,13.22,0,26.438,0,39.66c7.931,1.256,16.012,1.256,23.941,0c0-13.222,0-26.439,0-39.66
+ C21.461,14.822,13.48,14.822,5.5,14.822z M28.396,18.703c-0.74,0.01-1.482,0.02-2.225,0.029c0-0.951,0-1.901-0.001-2.85
+ c0.742-0.003,1.483-0.005,2.224-0.008C28.396,16.817,28.396,17.76,28.396,18.703z M16.354,42.496c0-0.961,0-1.924,0-2.885
+ c0.744,0.006,1.489,0.006,2.233,0c0,0.961,0,1.924,0,2.885C17.843,42.503,17.098,42.503,16.354,42.496z M18.587,43.568
+ c0,0.955,0,1.91,0,2.866c-0.744,0.009-1.489,0.009-2.234,0c0-0.956,0-1.911,0-2.866C17.098,43.574,17.843,43.574,18.587,43.568z
+ M18.586,27.742c0,0.961,0,1.922,0,2.886c-0.744,0.004-1.488,0.004-2.231,0c0-0.964,0-1.925,0-2.886
+ C17.099,27.746,17.842,27.746,18.586,27.742z M16.354,26.671c0-0.955,0-1.91,0-2.865c0.743,0.002,1.487,0.002,2.23,0
+ c0,0.955,0,1.91,0,2.865C17.842,26.675,17.099,26.675,16.354,26.671z M16.354,34.583c0-0.961,0-1.924,0-2.885
+ c0.744,0.004,1.488,0.004,2.231,0c0,0.961,0,1.924,0,2.885C17.842,34.588,17.099,34.588,16.354,34.583z M18.586,35.656
+ c0,0.961,0,1.924,0.001,2.885c-0.745,0.008-1.489,0.008-2.233,0c0-0.961,0-1.924,0-2.885C17.099,35.66,17.842,35.66,18.586,35.656z
+ M15.307,30.619c-0.742-0.01-1.484-0.021-2.227-0.039c0-0.957,0-1.916,0-2.875c0.742,0.014,1.485,0.023,2.226,0.029
+ C15.307,28.695,15.307,29.656,15.307,30.619z M15.307,31.689c0,0.961,0,1.924,0,2.885c-0.742-0.012-1.485-0.025-2.227-0.047
+ c0-0.959,0.001-1.92,0.001-2.877C13.822,31.667,14.565,31.68,15.307,31.689z M15.307,35.644c0,0.959,0,1.922-0.001,2.883
+ c-0.742-0.012-1.485-0.031-2.228-0.056c0-0.959,0.001-1.918,0.001-2.877C13.821,35.617,14.564,35.633,15.307,35.644z M15.306,39.597
+ c0,0.96,0,1.922,0,2.883c-0.742-0.016-1.486-0.037-2.228-0.064c0-0.959,0-1.916,0.001-2.877
+ C13.82,39.564,14.563,39.585,15.306,39.597z M19.637,39.597c0.742-0.012,1.484-0.033,2.227-0.059c0,0.959,0,1.918,0,2.875
+ c-0.741,0.029-1.483,0.052-2.227,0.064C19.637,41.519,19.637,40.559,19.637,39.597z M19.637,38.527c0-0.961,0-1.924,0-2.883
+ c0.74-0.012,1.482-0.027,2.225-0.05c0,0.959,0,1.918,0.002,2.876C21.121,38.496,20.377,38.515,19.637,38.527z M19.637,34.572
+ c0-0.961,0-1.922-0.002-2.883c0.741-0.01,1.483-0.021,2.225-0.039c0.002,0.957,0.002,1.916,0.002,2.875
+ C21.119,34.547,20.376,34.564,19.637,34.572z M19.635,30.619c0-0.963,0-1.924,0-2.885c0.74-0.006,1.483-0.017,2.225-0.029
+ c0,0.959,0,1.916,0,2.875C21.118,30.599,20.376,30.609,19.635,30.619z M19.633,26.666c0-0.955,0-1.909,0-2.864
+ c0.741-0.005,1.483-0.013,2.227-0.021c0,0.951,0,1.903,0,2.856C21.118,26.65,20.375,26.66,19.633,26.666z M19.633,22.732
+ c-0.001-0.963-0.001-1.924-0.001-2.885c0.741-0.002,1.483-0.006,2.226-0.012c0,0.959,0.002,1.918,0.002,2.877
+ C21.116,22.72,20.374,22.728,19.633,22.732z M18.586,22.736c-0.744,0.002-1.487,0.002-2.23,0c0-0.963,0-1.924,0-2.887
+ c0.743,0.002,1.487,0.002,2.23,0C18.586,20.813,18.586,21.773,18.586,22.736z M15.309,22.732c-0.742-0.004-1.483-0.012-2.226-0.02
+ c0-0.959,0.001-1.918,0.001-2.877c0.742,0.006,1.484,0.01,2.226,0.012C15.31,20.808,15.309,21.769,15.309,22.732z M15.309,23.801
+ c0,0.955,0,1.91,0,2.864c-0.742-0.006-1.483-0.016-2.227-0.027c0-0.953,0-1.906,0-2.859C13.825,23.789,14.566,23.796,15.309,23.801z
+ M12.036,26.617c-0.742-0.017-1.483-0.033-2.225-0.055c0-0.947,0-1.895,0.001-2.841c0.741,0.019,1.483,0.031,2.225,0.042
+ C12.037,24.716,12.036,25.666,12.036,26.617z M12.035,27.683c0,0.957,0,1.916,0,2.873c-0.742-0.021-1.483-0.047-2.225-0.076
+ c0-0.953,0-1.904,0-2.857C10.552,27.646,11.293,27.667,12.035,27.683z M12.035,31.621c0,0.957-0.001,1.914-0.001,2.871
+ c-0.742-0.023-1.483-0.055-2.224-0.092c0-0.953,0-1.906,0-2.859C10.551,31.572,11.292,31.6,12.035,31.621z M12.033,35.56
+ c0,0.956-0.001,1.914-0.001,2.871c-0.742-0.031-1.484-0.066-2.225-0.111c0-0.953,0.001-1.906,0.001-2.858
+ C10.549,35.5,11.291,35.533,12.033,35.56z M12.031,39.498c0,0.955,0,1.914-0.001,2.869c-0.742-0.035-1.484-0.078-2.225-0.129
+ c0-0.953,0-1.904,0.001-2.857C10.547,39.426,11.289,39.465,12.031,39.498z M12.03,43.435c0,0.951-0.001,1.901-0.001,2.854
+ c-0.742-0.041-1.484-0.09-2.225-0.149c0-0.944,0.001-1.892,0.001-2.838C10.546,43.353,11.288,43.4,12.03,43.435z M13.077,43.482
+ c0.743,0.031,1.486,0.053,2.228,0.067c0,0.956,0,1.91,0,2.864c-0.742-0.016-1.486-0.041-2.229-0.074
+ C13.077,45.389,13.077,44.435,13.077,43.482z M15.305,47.486c0,0.961,0,1.922,0,2.883c-0.743-0.019-1.487-0.047-2.23-0.084
+ c0-0.959,0-1.918,0.001-2.875C13.818,47.443,14.562,47.468,15.305,47.486z M16.353,47.504c0.745,0.009,1.49,0.009,2.234,0
+ c0.001,0.96,0.001,1.924,0.001,2.883c-0.745,0.011-1.49,0.011-2.235,0C16.353,49.427,16.353,48.464,16.353,47.504z M19.639,47.486
+ c0.741-0.018,1.483-0.043,2.227-0.076c0,0.957,0.002,1.916,0.002,2.875c-0.742,0.037-1.486,0.065-2.229,0.084
+ C19.639,49.406,19.639,48.447,19.639,47.486z M19.637,46.414c0-0.954,0-1.908,0-2.864c0.742-0.015,1.484-0.036,2.229-0.067
+ c0,0.953,0,1.905,0,2.857C21.122,46.373,20.379,46.398,19.637,46.414z M22.911,43.435c0.741-0.035,1.483-0.082,2.224-0.135
+ c0,0.945,0,1.895,0.002,2.838c-0.74,0.059-1.482,0.107-2.226,0.15C22.911,45.336,22.911,44.386,22.911,43.435z M22.911,42.369
+ c-0.001-0.957-0.001-1.914-0.002-2.871c0.741-0.032,1.483-0.069,2.225-0.117c0,0.954,0.001,1.906,0.001,2.857
+ C24.395,42.289,23.652,42.333,22.911,42.369z M22.909,38.431c0-0.957-0.001-1.915-0.001-2.871c0.742-0.027,1.482-0.061,2.224-0.098
+ c0.001,0.951,0.001,1.904,0.001,2.857C24.393,38.363,23.65,38.4,22.909,38.431z M22.908,34.494c0-0.957-0.002-1.916-0.002-2.871
+ c0.742-0.021,1.482-0.051,2.225-0.079c0,0.952,0,1.903,0.001,2.856C24.391,34.437,23.648,34.468,22.908,34.494z M22.906,30.556
+ c0-0.957,0-1.916-0.002-2.873c0.742-0.016,1.484-0.037,2.226-0.061c0,0.953,0.001,1.904,0.001,2.857
+ C24.391,30.509,23.648,30.535,22.906,30.556z M22.904,26.617c0-0.951,0-1.901,0-2.854c0.74-0.011,1.482-0.025,2.224-0.042
+ c0,0.946,0.001,1.894,0.001,2.841C24.389,26.583,23.646,26.601,22.904,26.617z M22.902,22.699c0-0.957,0-1.916,0-2.874
+ c0.742-0.007,1.482-0.014,2.225-0.023c0.001,0.953,0.001,1.906,0.001,2.859C24.387,22.676,23.646,22.689,22.902,22.699z
+ M22.902,18.76C22.9,17.802,22.9,16.845,22.9,15.887c0.742,0,1.481-0.003,2.225-0.004c0.001,0.953,0.001,1.906,0.002,2.858
+ C24.385,18.75,23.643,18.756,22.902,18.76z M21.855,18.767c-0.742,0.004-1.482,0.007-2.225,0.009c0-0.961,0-1.922,0-2.884
+ c0.741,0,1.482-0.001,2.225-0.002C21.855,16.849,21.855,17.808,21.855,18.767z M18.585,18.779c-0.743,0.001-1.486,0.001-2.229,0
+ c0-0.961,0-1.923,0-2.885c0.742,0,1.486,0,2.229,0C18.585,16.855,18.585,17.817,18.585,18.779z M15.31,18.777
+ c-0.742-0.002-1.483-0.005-2.225-0.009c0-0.959,0-1.918,0-2.877c0.742,0,1.483,0.001,2.225,0.002
+ C15.31,16.854,15.31,17.815,15.31,18.777z M12.039,18.76c-0.742-0.005-1.483-0.011-2.225-0.019c0-0.953,0-1.905,0.001-2.858
+ c0.742,0.001,1.483,0.004,2.224,0.004C12.039,16.845,12.039,17.803,12.039,18.76z M12.039,19.827c0,0.957-0.001,1.915-0.001,2.872
+ c-0.741-0.01-1.483-0.021-2.224-0.035c0-0.953,0-1.906,0-2.859C10.555,19.813,11.296,19.819,12.039,19.827z M8.768,22.64
+ c-0.741-0.018-1.482-0.035-2.223-0.057c0-0.943,0-1.887,0-2.831c0.741,0.013,1.482,0.025,2.223,0.036
+ C8.768,20.739,8.768,21.689,8.768,22.64z M8.767,23.697c0,0.944,0,1.89,0,2.832c-0.741-0.024-1.482-0.053-2.223-0.084
+ c0-0.938,0-1.873,0-2.811C7.284,23.658,8.026,23.679,8.767,23.697z M8.766,27.587c0,0.949-0.001,1.898-0.001,2.85
+ c-0.74-0.033-1.481-0.068-2.222-0.111c0-0.942,0-1.887,0-2.83C7.284,27.529,8.025,27.56,8.766,27.587z M8.765,31.494
+ c0,0.951-0.001,1.9-0.001,2.852c-0.74-0.04-1.481-0.087-2.221-0.139c0-0.943,0-1.887,0-2.831C7.283,31.42,8.023,31.459,8.765,31.494
+ z M8.763,35.404c0,0.949,0,1.899,0,2.851c-0.741-0.052-1.481-0.104-2.22-0.168c0-0.942,0-1.886,0-2.829
+ C7.282,35.31,8.022,35.361,8.763,35.404z M8.762,39.312c0,0.949,0,1.899-0.001,2.852c-0.741-0.059-1.48-0.123-2.219-0.195
+ c0-0.943,0-1.889,0-2.83C7.281,39.203,8.021,39.26,8.762,39.312z M8.76,43.219c0,0.944,0,1.888-0.001,2.832
+ c-0.74-0.065-1.479-0.14-2.218-0.224c0-0.938,0-1.875,0-2.812C7.281,43.092,8.02,43.16,8.76,43.219z M8.759,47.109
+ c0,0.951,0,1.9,0,2.851c-0.741-0.073-1.48-0.158-2.219-0.253c0-0.942,0-1.887,0-2.828C7.279,46.964,8.019,47.039,8.759,47.109z
+ M9.804,47.201c0.741,0.06,1.483,0.111,2.224,0.154c0,0.955,0,1.912,0,2.868c-0.742-0.045-1.484-0.103-2.225-0.166
+ C9.804,49.107,9.804,48.154,9.804,47.201z M12.027,51.291c0,0.957,0,1.916,0,2.873c-0.742-0.053-1.484-0.114-2.225-0.188
+ c0-0.951,0.001-1.904,0.001-2.857C10.544,51.187,11.285,51.244,12.027,51.291z M13.075,51.353c0.743,0.039,1.486,0.067,2.229,0.086
+ c0,0.961,0,1.922,0,2.885c-0.743-0.021-1.487-0.053-2.229-0.094C13.075,53.269,13.075,52.312,13.075,51.353z M16.353,51.459
+ c0.745,0.009,1.49,0.009,2.235,0c0,0.961,0,1.924,0,2.885c-0.745,0.013-1.491,0.013-2.235,0
+ C16.353,53.382,16.353,52.42,16.353,51.459z M19.639,51.439c0.741-0.019,1.485-0.049,2.229-0.086c0,0.959,0,1.92,0.001,2.877
+ c-0.743,0.041-1.485,0.072-2.229,0.094C19.639,53.361,19.639,52.4,19.639,51.439z M22.913,51.291
+ c0.743-0.047,1.483-0.104,2.226-0.172c0,0.953,0,1.906,0,2.857c-0.74,0.073-1.481,0.135-2.224,0.188
+ C22.914,53.205,22.914,52.248,22.913,51.291z M22.913,50.224c-0.001-0.956-0.001-1.912-0.001-2.869
+ c0.742-0.043,1.484-0.095,2.225-0.154c0,0.953,0,1.906,0.002,2.857C24.396,50.123,23.654,50.179,22.913,50.224z M26.184,47.109
+ c0.739-0.066,1.479-0.145,2.217-0.229c0,0.942,0,1.887,0,2.83c-0.736,0.092-1.478,0.177-2.217,0.252
+ C26.184,49.009,26.184,48.06,26.184,47.109z M26.184,46.051c-0.002-0.944-0.002-1.888-0.002-2.832
+ c0.739-0.06,1.48-0.127,2.219-0.202c0,0.938,0,1.873,0,2.811C27.662,45.912,26.923,45.986,26.184,46.051z M26.182,42.162
+ c0-0.95-0.002-1.9-0.002-2.85c0.74-0.052,1.48-0.109,2.219-0.176c0.002,0.943,0.002,1.887,0.002,2.83
+ C27.662,42.039,26.921,42.105,26.182,42.162z M26.18,38.253c0-0.95,0-1.9-0.002-2.852c0.742-0.041,1.482-0.093,2.221-0.146
+ c0,0.942,0,1.887,0,2.829C27.66,38.15,26.92,38.203,26.18,38.253z M26.178,34.345c0-0.949,0-1.898,0-2.852
+ c0.74-0.034,1.481-0.073,2.221-0.117c0,0.943,0,1.887,0,2.83C27.659,34.258,26.918,34.305,26.178,34.345z M26.177,30.437
+ c0-0.949,0-1.9-0.001-2.85c0.741-0.027,1.481-0.059,2.221-0.092c0,0.943,0.002,1.888,0.002,2.83
+ C27.659,30.367,26.918,30.404,26.177,30.437z M26.176,26.529c-0.001-0.942-0.001-1.888-0.001-2.832
+ c0.742-0.018,1.482-0.039,2.222-0.063c0,0.938,0,1.873,0,2.811C27.657,26.476,26.917,26.503,26.176,26.529z M26.174,22.64
+ c0-0.951-0.001-1.901-0.001-2.851c0.741-0.01,1.483-0.022,2.224-0.035c0,0.943,0,1.886,0,2.831
+ C27.657,22.605,26.915,22.623,26.174,22.64z M8.769,15.881c0,0.95,0,1.9-0.001,2.85c-0.741-0.008-1.482-0.018-2.223-0.028
+ c0-0.943,0-1.887,0-2.83C7.286,15.876,8.028,15.878,8.769,15.881z M6.54,50.758c0.738,0.097,1.478,0.183,2.218,0.258
+ c0,0.95,0,1.901,0,2.853c-0.741-0.084-1.48-0.178-2.218-0.28C6.54,52.646,6.54,51.701,6.54,50.758z M26.184,53.869
+ c0-0.95,0-1.899,0-2.853c0.739-0.075,1.479-0.163,2.217-0.259c0.002,0.941,0.002,1.889,0.002,2.83
+ C27.663,53.693,26.925,53.785,26.184,53.869z"/>
+<path id="highlight_2_" opacity="0.17" fill="#FFFFFF" enable-background="new " d="M0,0.943h5.497c0,0,6.847-0.943,11.974-0.943
+ C22.6,0,29.48,0.943,29.48,0.943h5.496v41.951c0,0-12.076-0.521-18.623-2.548C9.807,38.32,0,30.557,0,30.557V0.943z"/>
+</svg>
+</y:Resource>
+ </y:Resources>
+ </data>
+</graphml>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/c2-integration-test.png
----------------------------------------------------------------------
diff --git a/minifi-c2/c2-integration-test.png b/minifi-c2/c2-integration-test.png
new file mode 100644
index 0000000..404063e
Binary files /dev/null and b/minifi-c2/c2-integration-test.png differ
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
index a008f0a..90fbdba 100644
--- a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java
@@ -21,6 +21,8 @@ import java.io.InputStream;
/**
* Represents a MiNiFi configuration of a given version, format matches the format of the ConfigurationProvider
+ *
+ * This object may be cached so it should attempt to minimize the amount of memory used to represent state (input stream should come from persistent storage if possible.)
*/
public interface Configuration {
/**
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java
index a743be3..4892be5 100644
--- a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProvider.java
@@ -25,11 +25,11 @@ import java.util.Map;
*/
public interface ConfigurationProvider {
/**
- * Gets the content type that this provider returns
+ * Gets the content types that this provider returns
*
- * @return the content type that this provider returns
+ * @return the content types that this provider returns
*/
- String getContentType();
+ List<String> getContentTypes() throws ConfigurationProviderException;
/**
* Gets the configuration that corresponds to the passed in parameters
@@ -39,5 +39,5 @@ public interface ConfigurationProvider {
* @return an input stream of the configuration
* @throws ConfigurationProviderException if there is an error in the configuration
*/
- Configuration getConfiguration(Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException;
+ Configuration getConfiguration(String contentType, Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException;
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java
index 16b1ed2..d510482 100644
--- a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/ConfigurationProviderException.java
@@ -25,4 +25,18 @@ public class ConfigurationProviderException extends Exception {
public ConfigurationProviderException(String message, Throwable cause) {
super(message, cause);
}
+
+ public ConfigurationProviderException.Wrapper wrap() {
+ return new Wrapper(this);
+ }
+
+ public static class Wrapper extends RuntimeException {
+ public Wrapper(ConfigurationProviderException cause) {
+ super(cause);
+ }
+
+ public ConfigurationProviderException unwrap() {
+ return (ConfigurationProviderException) getCause();
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java
index 00c271e..43d4b93 100644
--- a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/cache/ConfigurationCache.java
@@ -33,5 +33,5 @@ public interface ConfigurationCache {
* @return information on the entry
* @throws InvalidParameterException if there are illegal/invalid parameters
*/
- ConfigurationCacheFileInfo getCacheFileInfo(Map<String, List<String>> parameters) throws InvalidParameterException;
+ ConfigurationCacheFileInfo getCacheFileInfo(String contentType, Map<String, List<String>> parameters) throws InvalidParameterException;
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java
index 2a8df3a..f249583 100644
--- a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/properties/C2Properties.java
@@ -58,11 +58,11 @@ public class C2Properties extends Properties {
return properties;
}
- public SslContextFactory getSslContextFactory() throws GeneralSecurityException, IOException {
- if (!Boolean.valueOf(getProperty(MINIFI_C2_SERVER_SECURE, "false"))) {
- return null;
- }
+ public boolean isSecure() {
+ return Boolean.valueOf(getProperty(MINIFI_C2_SERVER_SECURE, "false"));
+ }
+ public SslContextFactory getSslContextFactory() throws GeneralSecurityException, IOException {
SslContextFactory sslContextFactory = new SslContextFactory();
KeyStore keyStore = KeyStore.getInstance(properties.getProperty(MINIFI_C2_SERVER_KEYSTORE_TYPE));
Path keyStorePath = Paths.get(C2_SERVER_HOME).resolve(properties.getProperty(MINIFI_C2_SERVER_KEYSTORE)).toAbsolutePath();
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java
index 2c459e0..454288a 100644
--- a/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java
+++ b/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/security/authorization/AuthorizationException.java
@@ -17,7 +17,9 @@
package org.apache.nifi.minifi.c2.api.security.authorization;
-public class AuthorizationException extends Exception {
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+
+public class AuthorizationException extends ConfigurationProviderException {
public AuthorizationException(String message) {
super(message);
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-assembly/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-assembly/pom.xml b/minifi-c2/minifi-c2-assembly/pom.xml
index 957f8bd..dfd43c6 100644
--- a/minifi-c2/minifi-c2-assembly/pom.xml
+++ b/minifi-c2/minifi-c2-assembly/pom.xml
@@ -89,6 +89,11 @@ limitations under the License.
</dependency>
<dependency>
<groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-provider-delegating</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
<artifactId>minifi-c2-provider-nifi-rest</artifactId>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
index 7016ff4..5669451 100644
--- a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml
@@ -27,4 +27,13 @@ Paths:
# Default authorization lets anonymous pull any config. Remove below to change that.
- Authorization: ROLE_ANONYMOUS
- Action: allow
\ No newline at end of file
+ Action: allow
+
+ /c2/config/contentTypes:
+ Default Action: deny
+ Actions:
+ - Authorization: CLASS_RASPI_3
+ Action: allow
+ # Default authorization lets anonymous pull any config. Remove below to change that.
+ - Authorization: ROLE_ANONYMOUS
+ Action: allow
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml
index 82a3dfc..bc23c97 100644
--- a/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/conf/minifi-c2-context.xml
@@ -31,7 +31,9 @@
<list>
<bean class="org.apache.nifi.minifi.c2.provider.cache.CacheConfigurationProvider">
<constructor-arg>
- <value>text/yml</value>
+ <list>
+ <value>text/yml</value>
+ </list>
</constructor-arg>
<constructor-arg>
<bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
@@ -39,7 +41,7 @@
<value>./files</value>
</constructor-arg>
<constructor-arg>
- <value>\${class}/config.yml</value>
+ <value>\${class}/config</value>
</constructor-arg>
</bean>
</constructor-arg>
@@ -58,6 +60,9 @@
<constructor-arg>
<value>${minifi.c2.server.provider.nifi.rest.api.url}</value>
</constructor-arg>
+ <constructor-arg>
+ <value>\${class}.v\${version}</value>
+ </constructor-arg>
</bean>-->
</list>
</constructor-arg>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.text.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.text.yml.v1 b/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.text.yml.v1
new file mode 100644
index 0000000..1a7f872
--- /dev/null
+++ b/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.text.yml.v1
@@ -0,0 +1,63 @@
+# 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: MiNiFi Flow
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1 b/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1
deleted file mode 100644
index 1a7f872..0000000
--- a/minifi-c2/minifi-c2-assembly/src/main/resources/files/raspi3/config.yml.v1
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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: MiNiFi Flow
- 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
-FlowFile Repository:
- 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:
- content claim max appendable size: 10 MB
- content claim max flow files: 100
- always sync: false
-Provenance Repository:
- provenance rollover time: 1 min
-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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
- provider: BC
-Processors: []
-Process Groups: []
-Funnels: []
-Connections: []
-Remote Process Groups: []
-NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java
index ced36a9..1e26009 100644
--- a/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java
+++ b/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemConfigurationCache.java
@@ -21,6 +21,8 @@ import org.apache.nifi.minifi.c2.api.InvalidParameterException;
import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
@@ -29,8 +31,11 @@ import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class FileSystemConfigurationCache implements ConfigurationCache {
+ private static final Logger logger = LoggerFactory.getLogger(FileSystemConfigurationCache.class);
+
private final Path pathRoot;
private final String pathPattern;
@@ -50,7 +55,7 @@ public class FileSystemConfigurationCache implements ConfigurationCache {
}
@Override
- public ConfigurationCacheFileInfo getCacheFileInfo(Map<String, List<String>> parameters) throws InvalidParameterException {
+ public ConfigurationCacheFileInfo getCacheFileInfo(String contentType, Map<String, List<String>> parameters) throws InvalidParameterException {
String pathString = pathPattern;
for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
if (entry.getValue().size() != 1) {
@@ -58,6 +63,7 @@ public class FileSystemConfigurationCache implements ConfigurationCache {
}
pathString = pathString.replaceAll(Pattern.quote("${" + entry.getKey() + "}"), entry.getValue().get(0));
}
+ pathString = pathString + "." + contentType.replace('/', '.');
String[] split = pathString.split("/");
for (String s1 : split) {
int openBrace = s1.indexOf("${");
@@ -75,6 +81,13 @@ public class FileSystemConfigurationCache implements ConfigurationCache {
path = resolveChildAndVerifyParent(path, s);
}
Pair<Path, String> dirPathAndFilename = new Pair<>(path, splitPath[splitPath.length - 1]);
+ if (logger.isDebugEnabled()) {
+ StringBuilder message = new StringBuilder("Parameters {");
+ message.append(parameters.entrySet().stream().map(e -> e.getKey() + ": [" + String.join(", ", e.getValue()) + "]").collect(Collectors.joining(", ")));
+ message.append("} -> ");
+ message.append(dirPathAndFilename.getFirst().resolve(dirPathAndFilename.getSecond()).toAbsolutePath());
+ logger.debug(message.toString());
+ }
return new FileSystemCacheFileInfoImpl(this, dirPathAndFilename.getFirst(), dirPathAndFilename.getSecond() + ".v");
}
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/pom.xml b/minifi-c2/minifi-c2-integration-tests/pom.xml
index 60af910..4662cba 100644
--- a/minifi-c2/minifi-c2-integration-tests/pom.xml
+++ b/minifi-c2/minifi-c2-integration-tests/pom.xml
@@ -96,6 +96,17 @@ limitations under the License.
</excludes>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderSecureTest.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderSecureTest.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderSecureTest.java
new file mode 100644
index 0000000..68cf9f9
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderSecureTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpsStatusCodeHealthCheck;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+public class DelegatingConfigurationProviderSecureTest extends AbstractTestSecure {
+ public static final String C2_UPSTREAM_URL = "https://c2:10443/c2/config";
+ private static SSLSocketFactory healthCheckSocketFactory;
+ private static Path certificatesDirectory;
+ private static SSLContext trustSslContext;
+
+ // Not annotated as rule because we need to generate certificatesDirectory first
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-DelegatingProviderSecureTest.yml")
+ .waitingForServices(Arrays.asList("squid", "c2-upstream"),
+ new HttpsStatusCodeHealthCheck(container -> C2_UPSTREAM_URL, containers -> containers.get(0), containers -> containers.get(1), () -> healthCheckSocketFactory, 403))
+ .waitingForServices(Arrays.asList("squid", "c2"),
+ new HttpsStatusCodeHealthCheck(container -> C2_URL, containers -> containers.get(0), containers -> containers.get(1), () -> healthCheckSocketFactory, 403))
+ .build();
+
+ public DelegatingConfigurationProviderSecureTest() {
+ super(docker, certificatesDirectory, trustSslContext);
+ }
+
+ /**
+ * Generates certificates with the tls-toolkit and then starts up the docker compose file
+ */
+ @BeforeClass
+ public static void initCertificates() throws Exception {
+ certificatesDirectory = Paths.get(DelegatingConfigurationProviderSecureTest.class.getClassLoader()
+ .getResource("docker-compose-DelegatingProviderSecureTest.yml").getFile()).getParent().toAbsolutePath().resolve("certificates-DelegatingConfigurationProviderSecureTest");
+ trustSslContext = initCertificates(certificatesDirectory, Arrays.asList("c2", "c2-upstream"));
+ healthCheckSocketFactory = trustSslContext.getSocketFactory();
+
+ docker.before();
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ docker.after();
+ }
+
+ @Before
+ public void setup() {
+ super.setup(docker);
+ }
+
+ @Test
+ public void testUpstreamPermissionDenied() throws Exception {
+ assertReturnCode("?class=raspi4", loadSslContext("user3"), 403);
+ }
+}
[3/4] nifi-minifi git commit: MINIFI-272 - Delegating C2 Provider,
Caching ConfigService, Tests Proxy auth, caching fixes Added C2 readme
Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderUnsecureTest.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderUnsecureTest.java b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderUnsecureTest.java
new file mode 100644
index 0000000..8394427
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/java/org/apache/nifi/minifi/c2/integration/test/DelegatingConfigurationProviderUnsecureTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.c2.integration.test;
+
+import com.palantir.docker.compose.DockerComposeRule;
+import org.apache.nifi.minifi.c2.integration.test.health.HttpStatusCodeHealthCheck;
+import org.junit.Before;
+import org.junit.ClassRule;
+
+public class DelegatingConfigurationProviderUnsecureTest extends AbstractTestUnsecure {
+ @ClassRule
+ public static DockerComposeRule docker = DockerComposeRule.builder()
+ .file("target/test-classes/docker-compose-DelegatingProviderUnsecureTest.yml")
+ .waitingForService("c2-upstream", new HttpStatusCodeHealthCheck(DelegatingConfigurationProviderUnsecureTest::getUnsecureConfigUrl, 400))
+ .waitingForService("c2", new HttpStatusCodeHealthCheck(DelegatingConfigurationProviderUnsecureTest::getUnsecureConfigUrl, 400))
+ .build();
+
+ @Before
+ public void setup() {
+ super.setup(docker);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-delegating/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-delegating/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-delegating/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..e3e4976
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-delegating/conf/minifi-c2-context.xml
@@ -0,0 +1,56 @@
+<?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 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://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.delegating.DelegatingConfigurationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./cache</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${class}/${class}</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>https://c2-upstream:10443</value>
+ </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>
+ </bean>
+</beans>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml
index d648d88..42c98ea 100644
--- a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-secure-rest/conf/minifi-c2-context.xml
@@ -45,6 +45,9 @@
<constructor-arg>
<value>https://mocknifi:8443/nifi-api</value>
</constructor-arg>
+ <constructor-arg>
+ <value>${class}.v${version}</value>
+ </constructor-arg>
</bean>
</list>
</constructor-arg>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-delegating/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-delegating/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-delegating/conf/minifi-c2-context.xml
new file mode 100644
index 0000000..a246219
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-delegating/conf/minifi-c2-context.xml
@@ -0,0 +1,56 @@
+<?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 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/aop http://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.delegating.DelegatingConfigurationProvider">
+ <constructor-arg>
+ <bean class="org.apache.nifi.minifi.c2.cache.filesystem.FileSystemConfigurationCache">
+ <constructor-arg>
+ <value>./cache</value>
+ </constructor-arg>
+ <constructor-arg>
+ <value>${class}/${class}</value>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg>
+ <value>http://c2-upstream:10080</value>
+ </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>
+ </bean>
+</beans>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml
index f2e4eee..3834cc8 100644
--- a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-unsecure-rest/conf/minifi-c2-context.xml
@@ -44,6 +44,9 @@
<constructor-arg>
<value>http://mocknifi:8080/nifi-api</value>
</constructor-arg>
+ <constructor-arg>
+ <value>${class}.v${version}</value>
+ </constructor-arg>
</bean>
</list>
</constructor-arg>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorities.yaml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorities.yaml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorities.yaml
new file mode 100644
index 0000000..22be134
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorities.yaml
@@ -0,0 +1,17 @@
+# 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=c2, OU=NIFI:
+ - C2
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorizations.yaml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorizations.yaml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorizations.yaml
new file mode 100644
index 0000000..6d626f7
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2-upstream-secure/conf/authorizations.yaml
@@ -0,0 +1,32 @@
+# 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: C2
+ Query Parameters:
+ class: raspi4
+ Action: deny
+ - Authorization: C2
+ Action: allow
+
+ /c2/config/contentTypes:
+ Default Action: deny
+ Actions:
+ - Authorization: C2
+ Action: allow
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.text.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.text.yml.v1 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.text.yml.v1
new file mode 100644
index 0000000..116426f
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.text.yml.v1
@@ -0,0 +1,63 @@
+# 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: raspi2.v1
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1
deleted file mode 100644
index 116426f..0000000
--- a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi2/config.yml.v1
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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: raspi2.v1
- 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
-FlowFile Repository:
- 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:
- content claim max appendable size: 10 MB
- content claim max flow files: 100
- always sync: false
-Provenance Repository:
- provenance rollover time: 1 min
-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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
- provider: BC
-Processors: []
-Process Groups: []
-Funnels: []
-Connections: []
-Remote Process Groups: []
-NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v1 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v1
new file mode 100644
index 0000000..690cdaa
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v1
@@ -0,0 +1,63 @@
+# 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: raspi3.v1
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v2
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v2 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v2
new file mode 100644
index 0000000..14750b6
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.text.yml.v2
@@ -0,0 +1,63 @@
+# 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: raspi3.v2
+ 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
+FlowFile Repository:
+ 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:
+ content claim max appendable size: 10 MB
+ content claim max flow files: 100
+ always sync: false
+Provenance Repository:
+ provenance rollover time: 1 min
+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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ provider: BC
+Processors: []
+Process Groups: []
+Funnels: []
+Connections: []
+Remote Process Groups: []
+NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1
deleted file mode 100644
index 690cdaa..0000000
--- a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v1
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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: raspi3.v1
- 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
-FlowFile Repository:
- 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:
- content claim max appendable size: 10 MB
- content claim max flow files: 100
- always sync: false
-Provenance Repository:
- provenance rollover time: 1 min
-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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
- provider: BC
-Processors: []
-Process Groups: []
-Funnels: []
-Connections: []
-Remote Process Groups: []
-NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2 b/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2
deleted file mode 100644
index 14750b6..0000000
--- a/minifi-c2/minifi-c2-integration-tests/src/test/resources/c2/files/raspi3/config.yml.v2
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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: raspi3.v2
- 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
-FlowFile Repository:
- 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:
- content claim max appendable size: 10 MB
- content claim max flow files: 100
- always sync: false
-Provenance Repository:
- provenance rollover time: 1 min
-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: PBEWITHMD5AND256BITAES-CBC-OPENSSL
- provider: BC
-Processors: []
-Process Groups: []
-Funnels: []
-Connections: []
-Remote Process Groups: []
-NiFi Properties Overrides: {}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderSecureTest.yml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderSecureTest.yml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderSecureTest.yml
new file mode 100644
index 0000000..2c19308
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderSecureTest.yml
@@ -0,0 +1,55 @@
+# 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-upstream:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10443"
+ hostname: c2-upstream
+ volumes:
+ - ./c2/files:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/files
+
+ - ./c2-secure/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2-upstream-secure/conf/authorities.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorities.yaml
+ - ./c2-upstream-secure/conf/authorizations.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorizations.yaml
+
+ - ./certificates-DelegatingConfigurationProviderSecureTest/c2-upstream/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-DelegatingConfigurationProviderSecureTest/c2-upstream/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+
+ c2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10443"
+ hostname: c2
+ volumes:
+ - ./c2-secure-delegating/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
+
+ - ./c2-secure/conf/c2.properties:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/c2.properties
+ - ./c2-secure/conf/authorities.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorities.yaml
+ - ./c2-secure/conf/authorizations.yaml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/authorizations.yaml
+
+ - ./certificates-DelegatingConfigurationProviderSecureTest/c2/keystore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/keystore.jks
+ - ./certificates-DelegatingConfigurationProviderSecureTest/c2/truststore.jks:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/truststore.jks
+
+ squid:
+ image: chrisdaish/squid
+ ports:
+ - "3128"
+ hostname: squid
+ volumes:
+ - ./squid/squid.conf:/etc/squid/squid.conf
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderUnsecureTest.yml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderUnsecureTest.yml b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderUnsecureTest.yml
new file mode 100644
index 0000000..a5d0da4
--- /dev/null
+++ b/minifi-c2/minifi-c2-integration-tests/src/test/resources/docker-compose-DelegatingProviderUnsecureTest.yml
@@ -0,0 +1,32 @@
+# 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-upstream:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10080"
+ hostname: c2-upstream
+ volumes:
+ - ./c2/files:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/files
+ c2:
+ image: apacheminific2:${minifi.c2.version}
+ ports:
+ - "10080"
+ hostname: c2
+ volumes:
+ - ./c2-unsecure-delegating/conf/minifi-c2-context.xml:/opt/minifi-c2/minifi-c2-${minifi.c2.version}/conf/minifi-c2-context.xml
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java b/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java
index 5c8b1f8..abace06 100644
--- a/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java
+++ b/minifi-c2/minifi-c2-jetty/src/main/java/org/apache/nifi/minifi/c2/jetty/JettyServer.java
@@ -57,10 +57,8 @@ public class JettyServer {
Server server;
int port = Integer.parseInt(properties.getProperty("minifi.c2.server.port", "10080"));
- SslContextFactory sslContextFactory = properties.getSslContextFactory();
- if (sslContextFactory == null) {
- server = new Server(port);
- } else {
+ if (properties.isSecure()) {
+ SslContextFactory sslContextFactory = properties.getSslContextFactory();
HttpConfiguration config = new HttpConfiguration();
config.setSecureScheme("https");
config.setSecurePort(port);
@@ -72,6 +70,8 @@ public class JettyServer {
serverConnector.setPort(port);
server.addConnector(serverConnector);
+ } else {
+ server = new Server(port);
}
server.setHandler(handlers);
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java
index b0864ac..f65a86b 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/main/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProvider.java
@@ -26,21 +26,21 @@ import java.util.List;
import java.util.Map;
public class CacheConfigurationProvider implements ConfigurationProvider {
- private final String contentType;
+ private final List<String> contentTypes;
private final ConfigurationCache configurationCache;
- public CacheConfigurationProvider(String contentType, ConfigurationCache configurationCache) {
- this.contentType = contentType;
+ public CacheConfigurationProvider(List<String> contentTypes, ConfigurationCache configurationCache) {
+ this.contentTypes = contentTypes;
this.configurationCache = configurationCache;
}
@Override
- public String getContentType() {
- return contentType;
+ public List<String> getContentTypes() {
+ return contentTypes;
}
@Override
- public Configuration getConfiguration(Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
- return configurationCache.getCacheFileInfo(parameters).getConfiguration(version);
+ public Configuration getConfiguration(String contentType, Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
+ return configurationCache.getCacheFileInfo(contentType, parameters).getConfiguration(version);
}
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java
index d038194..bcc37e9 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-cache/src/test/java/org/apache/nifi/minifi/c2/provider/cache/CacheConfigurationProviderTest.java
@@ -21,10 +21,10 @@ import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
-import org.apache.nifi.minifi.c2.provider.cache.CacheConfigurationProvider;
import org.junit.Before;
import org.junit.Test;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -34,6 +34,7 @@ import static org.mockito.Mockito.when;
public class CacheConfigurationProviderTest {
public static final String TEST_CONTENT_TYPE = "test/contenttype";
+ public static final String TEST_CONTENT_TYPE_2 = "test/contenttype2";
private CacheConfigurationProvider cacheConfigurationProvider;
private ConfigurationCache configConfigurationCache;
@@ -41,25 +42,30 @@ public class CacheConfigurationProviderTest {
@Before
public void setup() {
configConfigurationCache = mock(ConfigurationCache.class);
- cacheConfigurationProvider = new CacheConfigurationProvider(TEST_CONTENT_TYPE, configConfigurationCache);
+ cacheConfigurationProvider = new CacheConfigurationProvider(Arrays.asList(TEST_CONTENT_TYPE, TEST_CONTENT_TYPE_2), configConfigurationCache);
}
@Test
public void testContentType() {
- assertEquals(TEST_CONTENT_TYPE, cacheConfigurationProvider.getContentType());
+ assertEquals(Arrays.asList(TEST_CONTENT_TYPE, TEST_CONTENT_TYPE_2), cacheConfigurationProvider.getContentTypes());
}
@Test
public void testGetConfiguration() throws ConfigurationProviderException {
int version = 99;
- Map<String, List<String>> parameters = mock(Map.class);
ConfigurationCacheFileInfo configurationCacheFileInfo = mock(ConfigurationCacheFileInfo.class);
+ ConfigurationCacheFileInfo configurationCacheFileInfo2 = mock(ConfigurationCacheFileInfo.class);
WriteableConfiguration configuration = mock(WriteableConfiguration.class);
+ WriteableConfiguration configuration2 = mock(WriteableConfiguration.class);
- when(configConfigurationCache.getCacheFileInfo(parameters)).thenReturn(configurationCacheFileInfo);
+ Map<String, List<String>> parameters = mock(Map.class);
+ when(configConfigurationCache.getCacheFileInfo(TEST_CONTENT_TYPE, parameters)).thenReturn(configurationCacheFileInfo);
+ when(configConfigurationCache.getCacheFileInfo(TEST_CONTENT_TYPE_2, parameters)).thenReturn(configurationCacheFileInfo2);
when(configurationCacheFileInfo.getConfiguration(version)).thenReturn(configuration);
+ when(configurationCacheFileInfo2.getConfiguration(version)).thenReturn(configuration2);
- assertEquals(configuration, cacheConfigurationProvider.getConfiguration(version, parameters));
+ assertEquals(configuration, cacheConfigurationProvider.getConfiguration(TEST_CONTENT_TYPE, version, parameters));
+ assertEquals(configuration2, cacheConfigurationProvider.getConfiguration(TEST_CONTENT_TYPE_2, version, parameters));
}
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/pom.xml b/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/pom.xml
new file mode 100644
index 0000000..4b7e7ab
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/pom.xml
@@ -0,0 +1,53 @@
+<?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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>minifi-c2-provider</artifactId>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>minifi-c2-provider-delegating</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-provider-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/main/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/main/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProvider.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/main/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProvider.java
new file mode 100644
index 0000000..04f6017
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/main/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProvider.java
@@ -0,0 +1,171 @@
+/*
+ * 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.c2.provider.delegating;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
+import org.apache.nifi.minifi.c2.api.Configuration;
+import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
+import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
+import org.apache.nifi.minifi.c2.api.security.authorization.AuthorizationException;
+import org.apache.nifi.minifi.c2.provider.util.HttpConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class DelegatingConfigurationProvider implements ConfigurationProvider {
+ public static final Pattern errorPattern = Pattern.compile("^Server returned HTTP response code: ([0-9]+) for URL:.*");
+ private static final Logger logger = LoggerFactory.getLogger(DelegatingConfigurationProvider.class);
+ private final ConfigurationCache configurationCache;
+ private final HttpConnector httpConnector;
+ private final ObjectMapper objectMapper;
+
+ public DelegatingConfigurationProvider(ConfigurationCache configurationCache, String delegateUrl) throws InvalidParameterException, GeneralSecurityException, IOException {
+ this(configurationCache, new HttpConnector(delegateUrl));
+ }
+
+ public DelegatingConfigurationProvider(ConfigurationCache configurationCache, HttpConnector httpConnector) {
+ this.configurationCache = configurationCache;
+ this.httpConnector = httpConnector;
+ this.objectMapper = new ObjectMapper();
+ }
+
+ @Override
+ public List<String> getContentTypes() throws ConfigurationProviderException {
+ try {
+ HttpURLConnection httpURLConnection = httpConnector.get("/c2/config/contentTypes");
+ try {
+ List<String> contentTypes = objectMapper.readValue(httpURLConnection.getInputStream(), List.class);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Got content types: " + contentTypes);
+ }
+ return contentTypes;
+ } finally {
+ httpURLConnection.disconnect();
+ }
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to get content types from delegate.", e);
+ }
+ }
+
+ @Override
+ public Configuration getConfiguration(String contentType, Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
+ HttpURLConnection remoteC2ServerConnection = null;
+ try {
+ if (version == null) {
+ remoteC2ServerConnection = getDelegateConnection(contentType, parameters);
+ version = Integer.parseInt(remoteC2ServerConnection.getHeaderField("X-Content-Version"));
+ if (logger.isDebugEnabled()) {
+ logger.debug("Got current version " + version + " from upstream.");
+ }
+ }
+ ConfigurationCacheFileInfo cacheFileInfo = configurationCache.getCacheFileInfo(contentType, parameters);
+ WriteableConfiguration configuration = cacheFileInfo.getConfiguration(version);
+ if (!configuration.exists()) {
+ if (remoteC2ServerConnection == null) {
+ remoteC2ServerConnection = getDelegateConnection(contentType, parameters);
+ }
+ try (InputStream inputStream = remoteC2ServerConnection.getInputStream();
+ OutputStream outputStream = configuration.getOutputStream()) {
+ IOUtils.copy(inputStream, outputStream);
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to copy remote configuration to cache.", e);
+ }
+ }
+ return configuration;
+ } finally {
+ if (remoteC2ServerConnection != null) {
+ remoteC2ServerConnection.disconnect();
+ }
+ }
+ }
+
+ protected HttpURLConnection getDelegateConnection(String contentType, Map<String, List<String>> parameters) throws ConfigurationProviderException {
+ StringBuilder queryStringBuilder = new StringBuilder();
+ try {
+ parameters.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEachOrdered(e -> e.getValue().stream().sorted().forEachOrdered(v -> {
+ try {
+ queryStringBuilder.append(URLEncoder.encode(e.getKey(), "UTF-8")).append("=").append(URLEncoder.encode(v, "UTF-8"));
+ } catch (UnsupportedEncodingException ex) {
+ throw new ConfigurationProviderException("Unsupported encoding.", ex).wrap();
+ }
+ queryStringBuilder.append("&");
+ }));
+ } catch (ConfigurationProviderException.Wrapper e) {
+ throw e.unwrap();
+ }
+ String url = "/c2/config";
+ if (queryStringBuilder.length() > 0) {
+ queryStringBuilder.setLength(queryStringBuilder.length() - 1);
+ url = url + "?" + queryStringBuilder.toString();
+ }
+ HttpURLConnection httpURLConnection = httpConnector.get(url);
+ httpURLConnection.setRequestProperty("Accepts", contentType);
+ try {
+ int responseCode;
+ try {
+ responseCode = httpURLConnection.getResponseCode();
+ } catch (IOException e) {
+ Matcher matcher = errorPattern.matcher(e.getMessage());
+ if (matcher.matches()) {
+ responseCode = Integer.parseInt(matcher.group(1));
+ } else {
+ throw e;
+ }
+ }
+ if (responseCode >= 400) {
+ String message = "";
+ InputStream inputStream = httpURLConnection.getErrorStream();
+ if (inputStream != null) {
+ try {
+ message = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+ } finally {
+ inputStream.close();
+ }
+ }
+ if (responseCode == 400) {
+ throw new InvalidParameterException(message);
+ } else if (responseCode == 403) {
+ throw new AuthorizationException("Got authorization exception from upstream server " + message);
+ } else {
+ throw new ConfigurationProviderException(message);
+ }
+ }
+ } catch (IOException e) {
+ throw new ConfigurationProviderException("Unable to get response code from upstream server.", e);
+ }
+ return httpURLConnection;
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/test/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProviderTest.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/test/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProviderTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/test/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProviderTest.java
new file mode 100644
index 0000000..3127ca7
--- /dev/null
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-delegating/src/test/java/org/apache/nifi/minifi/c2/provider/delegating/DelegatingConfigurationProviderTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.c2.provider.delegating;
+
+import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
+import org.apache.nifi.minifi.c2.api.InvalidParameterException;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
+import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
+import org.apache.nifi.minifi.c2.api.security.authorization.AuthorizationException;
+import org.apache.nifi.minifi.c2.provider.util.HttpConnector;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DelegatingConfigurationProviderTest {
+ private ConfigurationCache configurationCache;
+ private HttpConnector httpConnector;
+ private HttpURLConnection httpURLConnection;
+ private DelegatingConfigurationProvider delegatingConfigurationProvider;
+ private Map<String, List<String>> parameters;
+ private Integer version;
+ private String endpointPath;
+ private String contentType;
+
+ @Before
+ public void setup() throws ConfigurationProviderException {
+ contentType = "text/yml";
+ version = 2;
+ parameters = new HashMap<>();
+ parameters.put("net", Collections.singletonList("edge"));
+ parameters.put("class", Collections.singletonList("raspi3"));
+ parameters.put("version", Collections.singletonList(Integer.toString(version)));
+ endpointPath = "/c2/config?class=raspi3&net=edge&version=2";
+ initMocks();
+ }
+
+ public void initMocks() throws ConfigurationProviderException {
+ configurationCache = mock(ConfigurationCache.class);
+ httpConnector = mock(HttpConnector.class);
+ httpURLConnection = mock(HttpURLConnection.class);
+ delegatingConfigurationProvider = new DelegatingConfigurationProvider(configurationCache, httpConnector);
+ when(httpConnector.get(endpointPath)).thenReturn(httpURLConnection);
+ }
+
+ @Test
+ public void testGetDelegateConnectionNoParameters() throws ConfigurationProviderException {
+ endpointPath = "/c2/config";
+ initMocks();
+ assertEquals(httpURLConnection, delegatingConfigurationProvider.getDelegateConnection(contentType, Collections.emptyMap()));
+ verify(httpURLConnection).setRequestProperty("Accepts", contentType);
+ }
+
+ @Test
+ public void testGetDelegateConnectionParameters() throws ConfigurationProviderException {
+ assertEquals(httpURLConnection, delegatingConfigurationProvider.getDelegateConnection(contentType, parameters));
+ verify(httpURLConnection).setRequestProperty("Accepts", contentType);
+ }
+
+ @Test(expected = AuthorizationException.class)
+ public void testGetDelegateConnection403() throws ConfigurationProviderException, IOException {
+ when(httpURLConnection.getResponseCode()).thenReturn(403);
+ delegatingConfigurationProvider.getDelegateConnection(contentType, parameters);
+ }
+
+ @Test(expected = InvalidParameterException.class)
+ public void testGetDelegateConnection400() throws IOException, ConfigurationProviderException {
+ when(httpURLConnection.getResponseCode()).thenThrow(new IOException("Server returned HTTP response code: 400 for URL: " + endpointPath));
+ delegatingConfigurationProvider.getDelegateConnection(contentType, parameters);
+ }
+
+ @Test(expected = ConfigurationProviderException.class)
+ public void testGetDelegateConnection401() throws IOException, ConfigurationProviderException {
+ when(httpURLConnection.getResponseCode()).thenReturn(401);
+ delegatingConfigurationProvider.getDelegateConnection(contentType, parameters);
+ }
+
+ @Test(expected = ConfigurationProviderException.class)
+ public void testGetContentTypesMalformed() throws ConfigurationProviderException, IOException {
+ endpointPath = "/c2/config/contentTypes";
+ initMocks();
+ when(httpURLConnection.getInputStream()).thenReturn(new ByteArrayInputStream("[malformed".getBytes(StandardCharsets.UTF_8)));
+ delegatingConfigurationProvider.getContentTypes();
+ }
+
+ @Test(expected = ConfigurationProviderException.class)
+ public void testGetContentTypesIOE() throws ConfigurationProviderException, IOException {
+ endpointPath = "/c2/config/contentTypes";
+ initMocks();
+ when(httpURLConnection.getInputStream()).thenThrow(new IOException());
+ delegatingConfigurationProvider.getContentTypes();
+ }
+
+ @Test
+ public void testGetContentTypes() throws ConfigurationProviderException, IOException {
+ endpointPath = "/c2/config/contentTypes";
+ initMocks();
+ List<String> contentTypes = Arrays.asList(contentType, "application/json");
+ when(httpURLConnection.getInputStream()).thenReturn(new ByteArrayInputStream(("[\"" + String.join("\", \"", contentTypes) + "\"]").getBytes(StandardCharsets.UTF_8)));
+ assertEquals(contentTypes, delegatingConfigurationProvider.getContentTypes());
+ }
+
+ @Test
+ public void testGetConfigurationExistsWithVersion() throws ConfigurationProviderException {
+ ConfigurationCacheFileInfo configurationCacheFileInfo = mock(ConfigurationCacheFileInfo.class);
+ WriteableConfiguration configuration = mock(WriteableConfiguration.class);
+ when(configurationCache.getCacheFileInfo(contentType, parameters)).thenReturn(configurationCacheFileInfo);
+ when(configurationCacheFileInfo.getConfiguration(version)).thenReturn(configuration);
+ when(configuration.exists()).thenReturn(true);
+
+ assertEquals(configuration, delegatingConfigurationProvider.getConfiguration(contentType, version, parameters));
+ }
+
+ @Test
+ public void testGetConfigurationDoesntExistWithVersion() throws ConfigurationProviderException, IOException {
+ ConfigurationCacheFileInfo configurationCacheFileInfo = mock(ConfigurationCacheFileInfo.class);
+ WriteableConfiguration configuration = mock(WriteableConfiguration.class);
+ byte[] payload = "payload".getBytes(StandardCharsets.UTF_8);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ when(httpURLConnection.getInputStream()).thenReturn(new ByteArrayInputStream(payload));
+ when(configuration.getOutputStream()).thenReturn(output);
+ when(configurationCache.getCacheFileInfo(contentType, parameters)).thenReturn(configurationCacheFileInfo);
+ when(configurationCacheFileInfo.getConfiguration(version)).thenReturn(configuration);
+ when(configuration.exists()).thenReturn(false);
+
+ assertEquals(configuration, delegatingConfigurationProvider.getConfiguration(contentType, version, parameters));
+ assertArrayEquals(payload, output.toByteArray());
+ }
+
+ @Test
+ public void testGetConfigurationExistsWithNoVersion() throws ConfigurationProviderException {
+ parameters.remove("version");
+ endpointPath = "/c2/config?class=raspi3&net=edge";
+ initMocks();
+ ConfigurationCacheFileInfo configurationCacheFileInfo = mock(ConfigurationCacheFileInfo.class);
+ WriteableConfiguration configuration = mock(WriteableConfiguration.class);
+ when(httpURLConnection.getHeaderField("X-Content-Version")).thenReturn("2");
+ when(configurationCache.getCacheFileInfo(contentType, parameters)).thenReturn(configurationCacheFileInfo);
+ when(configurationCacheFileInfo.getConfiguration(version)).thenReturn(configuration);
+ when(configuration.exists()).thenReturn(true);
+
+ assertEquals(configuration, delegatingConfigurationProvider.getConfiguration(contentType, null, parameters));
+ }
+
+ @Test
+ public void testGetConfigurationDoesntExistWithNoVersion() throws ConfigurationProviderException, IOException {
+ parameters.remove("version");
+ endpointPath = "/c2/config?class=raspi3&net=edge";
+ initMocks();
+ ConfigurationCacheFileInfo configurationCacheFileInfo = mock(ConfigurationCacheFileInfo.class);
+ WriteableConfiguration configuration = mock(WriteableConfiguration.class);
+ byte[] payload = "payload".getBytes(StandardCharsets.UTF_8);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ when(httpURLConnection.getInputStream()).thenReturn(new ByteArrayInputStream(payload));
+ when(configuration.getOutputStream()).thenReturn(output);
+ when(httpURLConnection.getHeaderField("X-Content-Version")).thenReturn("2");
+ when(configurationCache.getCacheFileInfo(contentType, parameters)).thenReturn(configurationCacheFileInfo);
+ when(configurationCacheFileInfo.getConfiguration(version)).thenReturn(configuration);
+ when(configuration.exists()).thenReturn(false);
+
+ assertEquals(configuration, delegatingConfigurationProvider.getConfiguration(contentType, null, parameters));
+ assertArrayEquals(payload, output.toByteArray());
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
index 8595246..43c5225 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/pom.xml
@@ -32,6 +32,11 @@ limitations under the License.
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.nifi.minifi</groupId>
+ <artifactId>minifi-c2-provider-util</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.7</version>
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java
index 77175d7..8f0bf2c 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProvider.java
@@ -23,9 +23,9 @@ import org.apache.nifi.minifi.c2.api.ConfigurationProvider;
import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.InvalidParameterException;
import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
-import org.apache.nifi.minifi.c2.api.cache.ConfigurationCacheFileInfo;
import org.apache.nifi.minifi.c2.api.cache.WriteableConfiguration;
import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.apache.nifi.minifi.c2.provider.util.HttpConnector;
import org.apache.nifi.minifi.commons.schema.ConfigSchema;
import org.apache.nifi.minifi.commons.schema.serialization.SchemaSaver;
import org.apache.nifi.minifi.toolkit.configuration.ConfigMain;
@@ -38,12 +38,17 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.security.GeneralSecurityException;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -52,32 +57,58 @@ public class NiFiRestConfigurationProvider implements ConfigurationProvider {
private static final Logger logger = LoggerFactory.getLogger(NiFiRestConfigurationProvider.class);
private final JsonFactory jsonFactory = new JsonFactory();
private final ConfigurationCache configurationCache;
- private final NiFiRestConnector niFiRestConnector;
+ private final HttpConnector httpConnector;
+ private final String templateNamePattern;
- public NiFiRestConfigurationProvider(ConfigurationCache configurationCache, String nifiUrl) throws InvalidParameterException, GeneralSecurityException, IOException {
- this(configurationCache, new NiFiRestConnector(nifiUrl));
+ public NiFiRestConfigurationProvider(ConfigurationCache configurationCache, String nifiUrl, String templateNamePattern) throws InvalidParameterException, GeneralSecurityException, IOException {
+ this(configurationCache, new HttpConnector(nifiUrl), templateNamePattern);
}
- public NiFiRestConfigurationProvider(ConfigurationCache configurationCache, NiFiRestConnector niFiRestConnector) {
+ public NiFiRestConfigurationProvider(ConfigurationCache configurationCache, HttpConnector httpConnector, String templateNamePattern) {
this.configurationCache = configurationCache;
- this.niFiRestConnector = niFiRestConnector;
+ this.httpConnector = httpConnector;
+ this.templateNamePattern = templateNamePattern;
}
@Override
- public String getContentType() {
- return CONTENT_TYPE;
+ public List<String> getContentTypes() {
+ return Collections.singletonList(CONTENT_TYPE);
}
@Override
- public Configuration getConfiguration(Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
- ConfigurationCacheFileInfo configurationCacheFileInfo = configurationCache.getCacheFileInfo(parameters);
+ public Configuration getConfiguration(String contentType, Integer version, Map<String, List<String>> parameters) throws ConfigurationProviderException {
+ if (!CONTENT_TYPE.equals(contentType)) {
+ throw new ConfigurationProviderException("Unsupported content type: " + contentType + " supported value is " + CONTENT_TYPE);
+ }
+ String filename = templateNamePattern;
+ for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+ if (entry.getValue().size() != 1) {
+ throw new InvalidParameterException("Multiple values for same parameter not supported in this provider.");
+ }
+ filename = filename.replaceAll(Pattern.quote("${" + entry.getKey() + "}"), entry.getValue().get(0));
+ }
+ int index = filename.indexOf("${");
+ while (index != -1) {
+ int endIndex = filename.indexOf("}", index);
+ if (endIndex == -1) {
+ break;
+ }
+ String variable = filename.substring(index + 2, endIndex);
+ if (!"version".equals(variable)) {
+ throw new InvalidParameterException("Found unsubstituted parameter " + variable);
+ }
+ index = endIndex + 1;
+ }
+
String id = null;
if (version == null) {
- Pair<String, Integer> maxIdAndVersion = getMaxIdAndVersion(configurationCacheFileInfo);
+ String filenamePattern = Arrays.stream(filename.split(Pattern.quote("${version}"), -1)).map(Pattern::quote).collect(Collectors.joining("([0-9+])"));
+ Pair<String, Integer> maxIdAndVersion = getMaxIdAndVersion(filenamePattern);
id = maxIdAndVersion.getFirst();
version = maxIdAndVersion.getSecond();
}
- WriteableConfiguration configuration = configurationCacheFileInfo.getConfiguration(version);
+ filename = filename.replaceAll(Pattern.quote("${version}"), Integer.toString(version));
+ WriteableConfiguration configuration = configurationCache.getCacheFileInfo(contentType, parameters).getConfiguration(version);
if (configuration.exists()) {
if (logger.isDebugEnabled()) {
logger.debug("Configuration " + configuration + " exists and can be served from configurationCache.");
@@ -88,11 +119,18 @@ public class NiFiRestConfigurationProvider implements ConfigurationProvider {
}
if (id == null) {
try {
- String filename = configuration.getName();
+ String tmpFilename = templateNamePattern;
+ for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
+ if (entry.getValue().size() != 1) {
+ throw new InvalidParameterException("Multiple values for same parameter not supported in this provider.");
+ }
+ tmpFilename = tmpFilename.replaceAll(Pattern.quote("${" + entry.getKey() + "}"), entry.getValue().get(0));
+ }
Pair<Stream<Pair<String, String>>, Closeable> streamCloseablePair = getIdAndFilenameStream();
try {
- id = streamCloseablePair.getFirst().filter(p -> filename.equals(p.getSecond())).map(Pair::getFirst).findFirst()
- .orElseThrow(() -> new InvalidParameterException("Unable to find template named " + filename));
+ String finalFilename = filename;
+ id = streamCloseablePair.getFirst().filter(p -> finalFilename.equals(p.getSecond())).map(Pair::getFirst).findFirst()
+ .orElseThrow(() -> new InvalidParameterException("Unable to find template named " + finalFilename));
} finally {
streamCloseablePair.getSecond().close();
}
@@ -101,7 +139,7 @@ public class NiFiRestConfigurationProvider implements ConfigurationProvider {
}
}
- HttpURLConnection urlConnection = niFiRestConnector.get("/templates/" + id + "/download");
+ HttpURLConnection urlConnection = httpConnector.get("/templates/" + id + "/download");
try (InputStream inputStream = urlConnection.getInputStream()){
ConfigSchema configSchema = ConfigMain.transformTemplateToSchema(inputStream);
@@ -118,27 +156,28 @@ public class NiFiRestConfigurationProvider implements ConfigurationProvider {
}
private Pair<Stream<Pair<String, String>>, Closeable> getIdAndFilenameStream() throws ConfigurationProviderException, IOException {
- TemplatesIterator templatesIterator = new TemplatesIterator(niFiRestConnector, jsonFactory);
+ TemplatesIterator templatesIterator = new TemplatesIterator(httpConnector, jsonFactory);
return new Pair<>(StreamSupport.stream(Spliterators.spliteratorUnknownSize(templatesIterator, Spliterator.ORDERED), false), templatesIterator);
}
- private Pair<Stream<Pair<String, Integer>>, Closeable> getIdAndVersionStream(ConfigurationCacheFileInfo configurationCacheFileInfo) throws ConfigurationProviderException, IOException {
+ private Pair<Stream<Pair<String, Integer>>, Closeable> getIdAndVersionStream(String filenamePattern) throws ConfigurationProviderException, IOException {
+ Pattern filename = Pattern.compile(filenamePattern);
Pair<Stream<Pair<String, String>>, Closeable> streamCloseablePair = getIdAndFilenameStream();
return new Pair<>(streamCloseablePair.getFirst().map(p -> {
- Integer version = configurationCacheFileInfo.getVersionIfMatch(p.getSecond());
- if (version == null) {
+ Matcher matcher = filename.matcher(p.getSecond());
+ if (!matcher.matches()) {
return null;
}
- return new Pair<>(p.getFirst(), version);
+ return new Pair<>(p.getFirst(), Integer.parseInt(matcher.group(1)));
}).filter(Objects::nonNull), streamCloseablePair.getSecond());
}
- private Pair<String, Integer> getMaxIdAndVersion(ConfigurationCacheFileInfo configurationCacheFileInfo) throws ConfigurationProviderException {
+ private Pair<String, Integer> getMaxIdAndVersion(String filenamePattern) throws ConfigurationProviderException {
try {
- Pair<Stream<Pair<String, Integer>>, Closeable> streamCloseablePair = getIdAndVersionStream(configurationCacheFileInfo);
+ Pair<Stream<Pair<String, Integer>>, Closeable> streamCloseablePair = getIdAndVersionStream(filenamePattern);
try {
return streamCloseablePair.getFirst().sorted(Comparator.comparing(p -> ((Pair<String, Integer>) p).getSecond()).reversed()).findFirst()
- .orElseThrow(() -> new ConfigurationProviderException("Didn't find any templates that matched " + configurationCacheFileInfo + ".v[0-9]+"));
+ .orElseThrow(() -> new ConfigurationProviderException("Didn't find any templates that matched " + filenamePattern));
} finally {
streamCloseablePair.getSecond().close();
}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java
deleted file mode 100644
index 9a0befc..0000000
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConnector.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.c2.provider.nifi.rest;
-
-import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
-import org.apache.nifi.minifi.c2.api.InvalidParameterException;
-import org.apache.nifi.minifi.c2.api.properties.C2Properties;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.GeneralSecurityException;
-
-public class NiFiRestConnector {
- private static final Logger logger = LoggerFactory.getLogger(NiFiRestConnector.class);
-
- private final String nifiApiUrl;
- private final SslContextFactory sslContextFactory;
-
- public NiFiRestConnector(String nifiApiUrl) throws InvalidParameterException, GeneralSecurityException, IOException {
- if (nifiApiUrl.startsWith("https:")) {
- sslContextFactory = C2Properties.getInstance().getSslContextFactory();
- if (sslContextFactory == null) {
- throw new InvalidParameterException("Need sslContextFactory to connect to https NiFi endpoint (" + nifiApiUrl + ")");
- }
- } else {
- sslContextFactory = null;
- }
- this.nifiApiUrl = nifiApiUrl;
- }
-
- protected HttpURLConnection get(String endpointPath) throws ConfigurationProviderException {
- String endpointUrl = nifiApiUrl + endpointPath;
- if (logger.isDebugEnabled()) {
- logger.debug("Connecting to NiFi endpoint: " + endpointUrl);
- }
- URL url;
- try {
- url = new URL(endpointUrl);
- } catch (MalformedURLException e) {
- throw new ConfigurationProviderException("Malformed url " + endpointUrl, e);
- }
-
- try {
- if (sslContextFactory == null) {
- return (HttpURLConnection) url.openConnection();
- } else {
- HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
- SSLContext sslContext = sslContextFactory.getSslContext();
- SSLSocketFactory socketFactory = sslContext.getSocketFactory();
- httpsURLConnection.setSSLSocketFactory(socketFactory);
- return httpsURLConnection;
- }
- } catch (IOException e) {
- throw new ConfigurationProviderException("Unable to connect to " + url, e);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java
index afe6c6e..947a853 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/main/java/org/apache/nifi/minifi/c2/provider/nifi/rest/TemplatesIterator.java
@@ -22,6 +22,7 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import org.apache.nifi.minifi.c2.api.ConfigurationProviderException;
import org.apache.nifi.minifi.c2.api.util.Pair;
+import org.apache.nifi.minifi.c2.provider.util.HttpConnector;
import java.io.Closeable;
import java.io.IOException;
@@ -38,8 +39,8 @@ public class TemplatesIterator implements Iterator<Pair<String, String>>, Closea
private final JsonParser parser;
private Pair<String, String> next;
- public TemplatesIterator(NiFiRestConnector niFiRestConnector, JsonFactory jsonFactory) throws ConfigurationProviderException, IOException {
- urlConnection = niFiRestConnector.get(FLOW_TEMPLATES);
+ public TemplatesIterator(HttpConnector httpConnector, JsonFactory jsonFactory) throws ConfigurationProviderException, IOException {
+ urlConnection = httpConnector.get(FLOW_TEMPLATES);
inputStream = urlConnection.getInputStream();
parser = jsonFactory.createParser(inputStream);
while (parser.nextToken() != JsonToken.END_OBJECT) {
http://git-wip-us.apache.org/repos/asf/nifi-minifi/blob/4dc0ce30/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java
----------------------------------------------------------------------
diff --git a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java
index 2cb3a8d..efc7f6c 100644
--- a/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java
+++ b/minifi-c2/minifi-c2-provider/minifi-c2-provider-nifi-rest/src/test/java/org/apache/nifi/minifi/c2/provider/nifi/rest/NiFiRestConfigurationProviderTest.java
@@ -18,6 +18,7 @@
package org.apache.nifi.minifi.c2.provider.nifi.rest;
import org.apache.nifi.minifi.c2.api.cache.ConfigurationCache;
+import org.apache.nifi.minifi.c2.provider.util.HttpConnector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -25,6 +26,7 @@ import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Collections;
import java.util.Comparator;
import static org.junit.Assert.assertEquals;
@@ -32,15 +34,15 @@ import static org.mockito.Mockito.mock;
public class NiFiRestConfigurationProviderTest {
private ConfigurationCache configConfigurationCache;
- private NiFiRestConnector niFiRestConnector;
+ private HttpConnector httpConnector;
private NiFiRestConfigurationProvider niFiRestConfigurationProvider;
private Path cachePath;
@Before
public void setup() throws IOException {
configConfigurationCache = mock(ConfigurationCache.class);
- niFiRestConnector = mock(NiFiRestConnector.class);
- niFiRestConfigurationProvider = new NiFiRestConfigurationProvider(configConfigurationCache, niFiRestConnector);
+ httpConnector = mock(HttpConnector.class);
+ niFiRestConfigurationProvider = new NiFiRestConfigurationProvider(configConfigurationCache, httpConnector, "${class}.v${version}");
cachePath = Files.createTempDirectory(NiFiRestConfigurationProviderTest.class.getCanonicalName());
}
@@ -59,8 +61,6 @@ public class NiFiRestConfigurationProviderTest {
@Test
public void testContentType() {
- assertEquals(NiFiRestConfigurationProvider.CONTENT_TYPE, niFiRestConfigurationProvider.getContentType());
+ assertEquals(Collections.singletonList(NiFiRestConfigurationProvider.CONTENT_TYPE), niFiRestConfigurationProvider.getContentTypes());
}
-
-
}