This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 5bee23c9dea SOLR-17137 - Add configuration for SSL between Solr and
Prometheus exporter. (#2232)
5bee23c9dea is described below
commit 5bee23c9dea32f9262a6d8cf279a03b141636ee1
Author: Eivind Bergstøl <[email protected]>
AuthorDate: Fri May 31 20:34:23 2024 +0200
SOLR-17137 - Add configuration for SSL between Solr and Prometheus
exporter. (#2232)
When running Solr with mTLS the exporter also needs to use mTLS to be
able to talk to Solr api.
This commit also adds a bats test that verifies that solr exporter actually
scrape the running
solr instance by verifying information about a newly made core is present.
---
solr/CHANGES.txt | 2 +
solr/packaging/build.gradle | 1 +
solr/packaging/test/bats_helper.bash | 7 +++-
solr/packaging/test/test_prometheus.bats | 49 ++++++++++++++++++++++
solr/prometheus-exporter/bin/solr-exporter | 8 ++++
solr/prometheus-exporter/bin/solr-exporter.cmd | 2 +
.../prometheus/exporter/SolrClientFactory.java | 11 +++++
.../solr/prometheus/exporter/SolrExporter.java | 30 +++++++++++++
.../exporter/SolrScrapeConfiguration.java | 39 +++++++++++++++++
.../monitoring-with-prometheus-and-grafana.adoc | 11 +++++
10 files changed, 159 insertions(+), 1 deletion(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index e9b495d449c..0b9cefd275b 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -113,6 +113,8 @@ New Features
Improvements
---------------------
+* SOLR-17137: Enable Prometheus exporter to communicate with SSL protected
Solr. (Eivind Bergstøl via Eric Pugh)
+
* SOLR-16921: use -solrUrl to derive the zk host connection for bin/solr zk
subcommands (Eric Pugh)
* SOLR-14115: Add linkconfig, cluster, and updateacls as commands to SolrCLI.
Allow bin/solr commands to have parity with zkcli.sh commands. (Eric Pugh)
diff --git a/solr/packaging/build.gradle b/solr/packaging/build.gradle
index cc48294880a..bf816677a02 100644
--- a/solr/packaging/build.gradle
+++ b/solr/packaging/build.gradle
@@ -267,6 +267,7 @@ task integrationTests(type: BatsTask) {
environment SOLR2_PORT: solrPort + 1
environment SOLR3_PORT: solrPort + 2
environment ZK_PORT: solrPort + 1000
+ environment SOLR_EXPORTER_PORT: solrPort + 100
environment SOLR_LOGS_DIR: "$solrHome/logs"
environment TEST_OUTPUT_DIR: integrationTestOutput
environment TEST_FAILURE_DIR: solrTestFailuresDir
diff --git a/solr/packaging/test/bats_helper.bash
b/solr/packaging/test/bats_helper.bash
index 56c743c8fb2..ccc2aabf2c9 100644
--- a/solr/packaging/test/bats_helper.bash
+++ b/solr/packaging/test/bats_helper.bash
@@ -33,7 +33,7 @@ common_setup() {
load "${BATS_LIB_PREFIX}/bats-assert/load.bash"
load "${BATS_LIB_PREFIX}/bats-file/load.bash"
- PATH="${SOLR_TIP:-.}/bin:$PATH"
+ PATH="${SOLR_TIP:-.}/bin:${SOLR_TIP:-.}/prometheus-exporter/bin:$PATH"
export SOLR_ULIMIT_CHECKS=false
}
@@ -62,6 +62,11 @@ shutdown_all() {
solr stop -all >/dev/null 2>&1
}
+shutdown_exporter(){
+ EXPORTER_PID=$(ps auxww | grep
org.apache.solr.prometheus.exporter.SolrExporter | awk "/-classpath/"' {print
$2}' | sort -r)
+ kill -9 $EXPORTER_PID
+}
+
delete_all_collections() {
local collection_list="$(solr zk ls /collections -z localhost:${ZK_PORT})"
for collection in $collection_list; do
diff --git a/solr/packaging/test/test_prometheus.bats
b/solr/packaging/test/test_prometheus.bats
new file mode 100644
index 00000000000..25353a7e0ab
--- /dev/null
+++ b/solr/packaging/test/test_prometheus.bats
@@ -0,0 +1,49 @@
+#!/usr/bin/env bats
+
+# 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.
+
+load bats_helper
+
+setup() {
+ common_clean_setup
+}
+
+teardown() {
+ # save a snapshot of SOLR_HOME for failed tests
+ save_home_on_failure
+
+ solr stop -all >/dev/null 2>&1
+
+ shutdown_exporter
+}
+
+@test "should start solr prometheus exporter that scrapes solr for metrics" {
+ solr start
+ solr assert --started http://localhost:${SOLR_PORT}/solr --timeout 5000
+
+ run solr create -c COLL_NAME
+ assert_output --partial "Created new core 'COLL_NAME'"
+
+ echo "# starting solr-exporter on ${SOLR_EXPORTER_PORT}" >&3
+ run solr-exporter -p $SOLR_EXPORTER_PORT -b
http://localhost:${SOLR_PORT}/solr >&3 &
+
+ sleep 5
+
+ run curl "http:/localhost:$SOLR_EXPORTER_PORT/"
+
+ assert_output --partial 'solr_metrics_core_query_requests_total'
+ assert_output --partial 'core="COLL_NAME"'
+}
diff --git a/solr/prometheus-exporter/bin/solr-exporter
b/solr/prometheus-exporter/bin/solr-exporter
index 06504457431..b15f7ff9339 100755
--- a/solr/prometheus-exporter/bin/solr-exporter
+++ b/solr/prometheus-exporter/bin/solr-exporter
@@ -129,6 +129,14 @@ if [[ -n "$CLUSTER_ID" ]]; then
EXPORTER_ARGS+=(-i "$CLUSTER_ID")
fi
+if [[ -n "$CREDENTIALS" ]]; then
+ EXPORTER_ARGS+=(-u "$CREDENTIALS")
+fi
+
+if [[ -n "$SSL_ENABLED" ]]; then
+ EXPORTER_ARGS+=(-ssl "$SSL_ENABLED")
+fi
+
exec "$JAVACMD" \
$JAVA_MEM_OPTS \
$GC_TUNE \
diff --git a/solr/prometheus-exporter/bin/solr-exporter.cmd
b/solr/prometheus-exporter/bin/solr-exporter.cmd
index e89b4042ae2..568f4f8b71d 100644
--- a/solr/prometheus-exporter/bin/solr-exporter.cmd
+++ b/solr/prometheus-exporter/bin/solr-exporter.cmd
@@ -83,6 +83,8 @@ IF NOT "%NUM_THREADS%"=="" set EXPORTER_ARGS=%EXPORTER_ARGS%
-n %NUM_THREADS%
IF NOT "%ZK_HOST%"=="" set EXPORTER_ARGS=%EXPORTER_ARGS% -z %ZK_HOST%
IF NOT "%SOLR_URL%"=="" set EXPORTER_ARGS=%EXPORTER_ARGS% -b %SOLR_URL%
IF NOT "%CLUSTER_ID%"=="" set EXPORTER_ARGS=%EXPORTER_ARGS% -i "%CLUSTER_ID%"
+IF NOT "%CREDENTIALS%"=="" set EXPORTER_ARGS=%EXPORTER_ARGS% -u "%CREDENTIALS%"
+IF NOT "%SSL_ENABLED%"=="" set EXPORTER_ARGS=%EXPORTER_ARGS% -ssl
"%SSL_ENABLED%"
goto endInit
@REM Reaching here means variables are defined and arguments have been captured
diff --git
a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrClientFactory.java
b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrClientFactory.java
index c1c4a891593..ede2495c452 100644
---
a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrClientFactory.java
+++
b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrClientFactory.java
@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import org.apache.solr.client.solrj.embedded.SSLConfig;
import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.Http2SolrClient;
@@ -49,6 +50,16 @@ public class SolrClientFactory {
builder.withBasicAuthCredentials(
configuration.getBasicAuthUser(), configuration.getBasicAuthPwd());
}
+ if (configuration.isSSLEnabled()) {
+ builder.withSSLConfig(
+ new SSLConfig(
+ true,
+ true,
+ configuration.getSslConfiguration().keystorePath.toString(),
+ configuration.getSslConfiguration().keystorePassword,
+ configuration.getSslConfiguration().trustStorePath.toString(),
+ configuration.getSslConfiguration().trustStorePassword));
+ }
return builder;
}
diff --git
a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
index 946df18cd78..57b5c52e6e9 100644
---
a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
+++
b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrExporter.java
@@ -21,6 +21,7 @@ import io.prometheus.client.exporter.HTTPServer;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.InetSocketAddress;
+import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
@@ -103,6 +104,13 @@ public class SolrExporter {
private static final String ARG_CREDENTIALS_HELP =
"Specify the credentials in the format username:password. Example:
--credentials solr:SolrRocks";
+ private static final String[] ARG_SSL_FLAGS = {"-ssl", "--ssl-enabled"};
+ private static final String ARG_SSL_METAVAR = "SSL_ENABLED";
+ private static final String ARG_SSL_DEST = "ssl_enabled";
+ private static final boolean ARG_SSL_DEFAULT = false;
+ private static final String ARG_SSL_HELP =
+ "Enable TLS connection to Solr. Expects following env variables:
SOLR_SSL_KEY_STORE, SOLR_SSL_KEY_STORE_PASSWORD, SOLR_SSL_TRUST_STORE,
SOLR_SSL_TRUST_STORE_PASSWORD. Example: --ssl-enabled";
+
public static final CollectorRegistry defaultRegistry = new
CollectorRegistry();
private final int port;
@@ -257,6 +265,14 @@ public class SolrExporter {
.setDefault(ARG_CREDENTIALS_DEFAULT)
.help(ARG_CREDENTIALS_HELP);
+ parser
+ .addArgument(ARG_SSL_FLAGS)
+ .metavar(ARG_SSL_METAVAR)
+ .dest(ARG_SSL_DEST)
+ .type(Boolean.class)
+ .setDefault(ARG_SSL_DEFAULT)
+ .help(ARG_SSL_HELP);
+
try {
Namespace res = parser.parseArgs(args);
@@ -289,6 +305,16 @@ public class SolrExporter {
}
}
+ if (Boolean.TRUE.equals(res.getBoolean(ARG_SSL_DEST))) {
+ log.info("SSL ENABLED");
+
+ scrapeConfiguration.withSslConfiguration(
+ Paths.get(getSystemVariable("SOLR_SSL_KEY_STORE")),
+ getSystemVariable("SOLR_SSL_KEY_STORE_PASSWORD"),
+ Paths.get(getSystemVariable("SOLR_SSL_TRUST_STORE")),
+ getSystemVariable("SOLR_SSL_TRUST_STORE_PASSWORD"));
+ }
+
SolrExporter solrExporter =
new SolrExporter(
port,
@@ -329,4 +355,8 @@ public class SolrExporter {
throw new RuntimeException(e);
}
}
+
+ private static String getSystemVariable(String name) {
+ return System.getProperty(name, System.getenv(name));
+ }
}
diff --git
a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrScrapeConfiguration.java
b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrScrapeConfiguration.java
index f61447b810d..e0550ddc9c4 100644
---
a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrScrapeConfiguration.java
+++
b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/SolrScrapeConfiguration.java
@@ -17,6 +17,7 @@
package org.apache.solr.prometheus.exporter;
+import java.nio.file.Path;
import java.util.Optional;
public class SolrScrapeConfiguration {
@@ -26,12 +27,34 @@ public class SolrScrapeConfiguration {
STANDALONE
}
+ public static class SslConfiguration {
+
+ public final Path keystorePath;
+ public final String keystorePassword;
+ public final Path trustStorePath;
+ public final String trustStorePassword;
+
+ public SslConfiguration(
+ Path keystorePath,
+ String keystorePassword,
+ Path trustStorePath,
+ String trustStorePassword) {
+ this.keystorePath = keystorePath;
+ this.keystorePassword = keystorePassword;
+ this.trustStorePath = trustStorePath;
+ this.trustStorePassword = trustStorePassword;
+ }
+ }
+
private final ConnectionType type;
private final String zookeeperConnectionString;
private final String solrHost;
private String basicAuthUser;
private String basicAuthPwd;
+ private boolean sslEnabled = false;
+ private SslConfiguration sslConfiguration;
+
private SolrScrapeConfiguration(
ConnectionType type, String zookeeperConnectionString, String solrHost) {
this.type = type;
@@ -73,6 +96,22 @@ public class SolrScrapeConfiguration {
return basicAuthPwd;
}
+ public SolrScrapeConfiguration withSslConfiguration(
+ Path keystorePath, String keystorePassword, Path trustStorePath, String
trustStorePassword) {
+ this.sslEnabled = true;
+ this.sslConfiguration =
+ new SslConfiguration(keystorePath, keystorePassword, trustStorePath,
trustStorePassword);
+ return this;
+ }
+
+ public boolean isSSLEnabled() {
+ return this.sslEnabled;
+ }
+
+ public SslConfiguration getSslConfiguration() {
+ return sslConfiguration;
+ }
+
@Override
public String toString() {
if (type == ConnectionType.CLOUD) {
diff --git
a/solr/solr-ref-guide/modules/deployment-guide/pages/monitoring-with-prometheus-and-grafana.adoc
b/solr/solr-ref-guide/modules/deployment-guide/pages/monitoring-with-prometheus-and-grafana.adoc
index 04dcc731ff8..3ed5b081cda 100644
---
a/solr/solr-ref-guide/modules/deployment-guide/pages/monitoring-with-prometheus-and-grafana.adoc
+++
b/solr/solr-ref-guide/modules/deployment-guide/pages/monitoring-with-prometheus-and-grafana.adoc
@@ -183,6 +183,17 @@ A unique ID for the cluster to monitor. This ID will be
added to all metrics as
Specify the credentials in the format `username:password`. Example:
`--credentials solr:SolrRocks`.
+`-ssl`, `--ssl-enabled`, `$SSL_ENABLED`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: false
+|===
++
+
+Enable mTLS connection to Solr. Expects following env variables:
SOLR_SSL_KEY_STORE, SOLR_SSL_KEY_STORE_PASSWORD, SOLR_SSL_TRUST_STORE,
SOLR_SSL_TRUST_STORE_PASSWORD. Example: `--ssl-enabled`
+The environment variables are the same that Solr uses to enable mTLS.
+
=== Environment Variable Options
The `./bin` scripts provided with the Prometheus Exporter support the use of
custom java options through the following environment variables: