You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by st...@apache.org on 2023/09/26 13:13:25 UTC
[solr] branch main updated: SOLR-16980 Connect to SOLR standalone with basic authentication (#1957)
This is an automated email from the ASF dual-hosted git repository.
stillalex 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 61d41e5734f SOLR-16980 Connect to SOLR standalone with basic authentication (#1957)
61d41e5734f is described below
commit 61d41e5734fd8e965b3d7ba9ef5ed86e01d50325
Author: Alex D <st...@apache.org>
AuthorDate: Tue Sep 26 06:13:19 2023 -0700
SOLR-16980 Connect to SOLR standalone with basic authentication (#1957)
---
solr/CHANGES.txt | 2 +
solr/prometheus-exporter/build.gradle | 2 +-
.../prometheus/exporter/SolrClientFactory.java | 41 ++++---
.../solr/prometheus/exporter/SolrExporter.java | 25 +++-
.../exporter/SolrScrapeConfiguration.java | 16 +++
.../prometheus/scraper/SolrCloudScraperTest.java | 25 ++--
.../SolrStandaloneScraperBasicAuthTest.java | 127 +++++++++++++++++++++
.../scraper/SolrStandaloneScraperTest.java | 69 ++++++-----
.../monitoring-with-prometheus-and-grafana.adoc | 12 +-
.../org/apache/solr/util/SolrClientTestRule.java | 20 ++++
10 files changed, 271 insertions(+), 68 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 5849c78767a..ae656b4ad8f 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -213,6 +213,8 @@ Bug Fixes
* SOLR-16997: OTEL configurator NPE when SOLR_HOST not set (janhoy)
+* SOLR-16980: Connect to SOLR standalone with basic authentication (Alex Deparvu)
+
Dependency Upgrades
---------------------
diff --git a/solr/prometheus-exporter/build.gradle b/solr/prometheus-exporter/build.gradle
index a64fa08147d..66beb70aed7 100644
--- a/solr/prometheus-exporter/build.gradle
+++ b/solr/prometheus-exporter/build.gradle
@@ -56,8 +56,8 @@ dependencies {
testImplementation project(':solr:test-framework')
testImplementation 'com.carrotsearch.randomizedtesting:randomizedtesting-runner'
testImplementation 'junit:junit'
+ testImplementation 'org.apache.lucene:lucene-test-framework'
- testImplementation 'commons-io:commons-io'
testImplementation 'org.apache.httpcomponents:httpclient'
testImplementation 'org.apache.httpcomponents:httpcore'
}
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 f34aad926e3..c1c4a891593 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
@@ -17,6 +17,7 @@
package org.apache.solr.prometheus.exporter;
+import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -28,37 +29,43 @@ import org.apache.zookeeper.client.ConnectStringParser;
public class SolrClientFactory {
- private PrometheusExporterSettings settings;
+ private final PrometheusExporterSettings settings;
+ private final SolrScrapeConfiguration configuration;
- public SolrClientFactory(PrometheusExporterSettings settings) {
+ public SolrClientFactory(
+ PrometheusExporterSettings settings, SolrScrapeConfiguration configuration) {
this.settings = settings;
+ this.configuration = configuration;
}
- public Http2SolrClient createStandaloneSolrClient(String solrHost) {
- Http2SolrClient http2SolrClient =
+ private static Http2SolrClient.Builder newHttp2SolrClientBuilder(
+ String solrHost, PrometheusExporterSettings settings, SolrScrapeConfiguration configuration) {
+ var builder =
new Http2SolrClient.Builder(solrHost)
.withIdleTimeout(settings.getHttpReadTimeout(), TimeUnit.MILLISECONDS)
.withConnectionTimeout(settings.getHttpConnectionTimeout(), TimeUnit.MILLISECONDS)
- .withResponseParser(new NoOpResponseParser("json"))
- .build();
+ .withResponseParser(new NoOpResponseParser("json"));
+ if (configuration.getBasicAuthUser() != null) {
+ builder.withBasicAuthCredentials(
+ configuration.getBasicAuthUser(), configuration.getBasicAuthPwd());
+ }
+ return builder;
+ }
- return http2SolrClient;
+ public Http2SolrClient createStandaloneSolrClient(String solrHost) {
+ return newHttp2SolrClientBuilder(solrHost, settings, configuration).build();
}
public CloudSolrClient createCloudSolrClient(String zookeeperConnectionString) {
ConnectStringParser parser = new ConnectStringParser(zookeeperConnectionString);
+ List<String> zkHosts =
+ parser.getServerAddresses().stream()
+ .map(address -> address.getHostString() + ":" + address.getPort())
+ .collect(Collectors.toList());
CloudSolrClient client =
- new CloudHttp2SolrClient.Builder(
- parser.getServerAddresses().stream()
- .map(address -> address.getHostString() + ":" + address.getPort())
- .collect(Collectors.toList()),
- Optional.ofNullable(parser.getChrootPath()))
- .withInternalClientBuilder(
- new Http2SolrClient.Builder()
- .withIdleTimeout(settings.getHttpReadTimeout(), TimeUnit.MILLISECONDS)
- .withConnectionTimeout(
- settings.getHttpConnectionTimeout(), TimeUnit.MILLISECONDS))
+ new CloudHttp2SolrClient.Builder(zkHosts, Optional.ofNullable(parser.getChrootPath()))
+ .withInternalClientBuilder(newHttp2SolrClientBuilder(null, settings, configuration))
.withResponseParser(new NoOpResponseParser("json"))
.build();
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 2cad046fa44..946df18cd78 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
@@ -96,6 +96,13 @@ public class SolrExporter {
+ ARG_NUM_THREADS_DEFAULT
+ ".";
+ private static final String[] ARG_CREDENTIALS_FLAGS = {"-u", "--credentials"};
+ private static final String ARG_CREDENTIALS_METAVAR = "CREDENTIALS";
+ private static final String ARG_CREDENTIALS_DEST = "credentials";
+ private static final String ARG_CREDENTIALS_DEFAULT = "";
+ private static final String ARG_CREDENTIALS_HELP =
+ "Specify the credentials in the format username:password. Example: --credentials solr:SolrRocks";
+
public static final CollectorRegistry defaultRegistry = new CollectorRegistry();
private final int port;
@@ -161,7 +168,7 @@ public class SolrExporter {
SolrScrapeConfiguration configuration,
PrometheusExporterSettings settings,
String clusterId) {
- SolrClientFactory factory = new SolrClientFactory(settings);
+ SolrClientFactory factory = new SolrClientFactory(settings, configuration);
switch (configuration.getType()) {
case STANDALONE:
@@ -242,6 +249,14 @@ public class SolrExporter {
.setDefault(ARG_CLUSTER_ID_DEFAULT)
.help(ARG_CLUSTER_ID_HELP);
+ parser
+ .addArgument(ARG_CREDENTIALS_FLAGS)
+ .metavar(ARG_CREDENTIALS_METAVAR)
+ .dest(ARG_CREDENTIALS_DEST)
+ .type(String.class)
+ .setDefault(ARG_CREDENTIALS_DEFAULT)
+ .help(ARG_CREDENTIALS_HELP);
+
try {
Namespace res = parser.parseArgs(args);
@@ -266,6 +281,14 @@ public class SolrExporter {
clusterId = defaultClusterId;
}
+ if (!res.getString(ARG_CREDENTIALS_DEST).isEmpty()) {
+ String credentials = res.getString(ARG_CREDENTIALS_DEST);
+ if (credentials.indexOf(':') > 0) {
+ String[] credentialsArray = credentials.split(":", 2);
+ scrapeConfiguration.withBasicAuthCredentials(credentialsArray[0], credentialsArray[1]);
+ }
+ }
+
SolrExporter solrExporter =
new SolrExporter(
port,
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 a1e1fbdf27b..f61447b810d 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
@@ -29,6 +29,8 @@ public class SolrScrapeConfiguration {
private final ConnectionType type;
private final String zookeeperConnectionString;
private final String solrHost;
+ private String basicAuthUser;
+ private String basicAuthPwd;
private SolrScrapeConfiguration(
ConnectionType type, String zookeeperConnectionString, String solrHost) {
@@ -57,6 +59,20 @@ public class SolrScrapeConfiguration {
return new SolrScrapeConfiguration(ConnectionType.STANDALONE, null, solrHost);
}
+ public SolrScrapeConfiguration withBasicAuthCredentials(String user, String password) {
+ this.basicAuthUser = user;
+ this.basicAuthPwd = password;
+ return this;
+ }
+
+ public String getBasicAuthUser() {
+ return basicAuthUser;
+ }
+
+ public String getBasicAuthPwd() {
+ return basicAuthPwd;
+ }
+
@Override
public String toString() {
if (type == ConnectionType.CLOUD) {
diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java
index f3839a1d8cd..2ebc3752cae 100644
--- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java
+++ b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java
@@ -21,15 +21,11 @@ import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering;
import io.prometheus.client.Collector;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
-import org.apache.solr.client.solrj.impl.CloudSolrClient;
-import org.apache.solr.client.solrj.impl.NoOpResponseParser;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
@@ -42,6 +38,7 @@ import org.apache.solr.prometheus.collector.MetricSamples;
import org.apache.solr.prometheus.exporter.MetricsConfiguration;
import org.apache.solr.prometheus.exporter.PrometheusExporterSettings;
import org.apache.solr.prometheus.exporter.SolrClientFactory;
+import org.apache.solr.prometheus.exporter.SolrScrapeConfiguration;
import org.apache.solr.prometheus.utils.Helpers;
import org.junit.After;
import org.junit.Before;
@@ -55,16 +52,11 @@ public class SolrCloudScraperTest extends PrometheusExporterTestBase {
private ExecutorService executor;
private SolrCloudScraper createSolrCloudScraper() {
- var solrClient =
- new CloudSolrClient.Builder(
- Collections.singletonList(cluster.getZkServer().getZkAddress()), Optional.empty())
- .withResponseParser(new NoOpResponseParser("json"))
- .build();
-
- solrClient.connect();
-
- SolrClientFactory factory = new SolrClientFactory(PrometheusExporterSettings.builder().build());
-
+ PrometheusExporterSettings settings = PrometheusExporterSettings.builder().build();
+ SolrScrapeConfiguration scrapeConfiguration =
+ SolrScrapeConfiguration.standalone(cluster.getZkServer().getZkAddress());
+ SolrClientFactory factory = new SolrClientFactory(settings, scrapeConfiguration);
+ var solrClient = factory.createCloudSolrClient(cluster.getZkServer().getZkAddress());
return new SolrCloudScraper(solrClient, executor, factory, "test");
}
@@ -93,10 +85,7 @@ public class SolrCloudScraperTest extends PrometheusExporterTestBase {
public void tearDown() throws Exception {
super.tearDown();
IOUtils.closeQuietly(solrCloudScraper);
- if (null != executor) {
- executor.shutdownNow();
- executor = null;
- }
+ ExecutorUtil.shutdownNowAndAwaitTermination(executor);
}
@Test
diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java
new file mode 100644
index 00000000000..b08e771e7d3
--- /dev/null
+++ b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.solr.prometheus.scraper;
+
+import io.prometheus.client.Collector;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import org.apache.lucene.tests.util.LuceneTestCase;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
+import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.IOUtils;
+import org.apache.solr.common.util.SolrNamedThreadFactory;
+import org.apache.solr.prometheus.PrometheusExporterTestBase;
+import org.apache.solr.prometheus.exporter.MetricsConfiguration;
+import org.apache.solr.prometheus.exporter.PrometheusExporterSettings;
+import org.apache.solr.prometheus.exporter.SolrClientFactory;
+import org.apache.solr.prometheus.exporter.SolrScrapeConfiguration;
+import org.apache.solr.prometheus.utils.Helpers;
+import org.apache.solr.util.SolrJettyTestRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class SolrStandaloneScraperBasicAuthTest extends SolrTestCaseJ4 {
+
+ @ClassRule public static final SolrJettyTestRule solrRule = new SolrJettyTestRule();
+
+ private static Http2SolrClient solrClient;
+ private static MetricsConfiguration configuration;
+ private static SolrStandaloneScraper solrScraper;
+ private static ExecutorService executor;
+
+ private static String user = "solr";
+ private static String pass = "SolrRocks";
+ private static String securityJson =
+ "{\n"
+ + "\"authentication\":{ \n"
+ + " \"blockUnknown\": true, \n"
+ + " \"class\":\"solr.BasicAuthPlugin\",\n"
+ + " \"credentials\":{\"solr\":\"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c=\"}, \n"
+ + " \"realm\":\"My Solr users\", \n"
+ + " \"forwardCredentials\": false \n"
+ + "},\n"
+ + "\"authorization\":{\n"
+ + " \"class\":\"solr.RuleBasedAuthorizationPlugin\",\n"
+ + " \"permissions\":[{\"name\":\"security-edit\",\n"
+ + " \"role\":\"admin\"}],\n"
+ + " \"user-role\":{\"solr\":\"admin\"}\n"
+ + "}}";
+
+ @BeforeClass
+ public static void setupSolrHome() throws Exception {
+ Path solrHome = LuceneTestCase.createTempDir();
+ Files.write(solrHome.resolve("security.json"), securityJson.getBytes(StandardCharsets.UTF_8));
+ solrRule.startSolr(solrHome);
+
+ Path configSet = LuceneTestCase.createTempDir();
+ SolrStandaloneScraperTest.createConf(configSet);
+ solrRule
+ .newCollection()
+ .withConfigSet(configSet.toString())
+ .withBasicAuthCredentials(user, pass)
+ .create();
+
+ configuration =
+ Helpers.loadConfiguration("conf/prometheus-solr-exporter-scraper-test-config.xml");
+
+ PrometheusExporterSettings settings = PrometheusExporterSettings.builder().build();
+ SolrScrapeConfiguration scrapeConfiguration =
+ SolrScrapeConfiguration.standalone(solrRule.getBaseUrl())
+ .withBasicAuthCredentials(user, pass);
+ solrClient =
+ new SolrClientFactory(settings, scrapeConfiguration)
+ .createStandaloneSolrClient(solrRule.getBaseUrl());
+ executor =
+ ExecutorUtil.newMDCAwareFixedThreadPool(
+ 25, new SolrNamedThreadFactory("solr-cloud-scraper-tests"));
+ solrScraper = new SolrStandaloneScraper(solrClient, executor, "test");
+
+ Helpers.indexAllDocs(solrClient);
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ // scraper also closes the client
+ IOUtils.closeQuietly(solrScraper);
+ ExecutorUtil.shutdownNowAndAwaitTermination(executor);
+ }
+
+ @Test
+ public void search() throws Exception {
+ List<Collector.MetricFamilySamples> samples =
+ solrScraper.search(configuration.getSearchConfiguration().get(0)).asList();
+
+ assertEquals(1, samples.size());
+
+ Collector.MetricFamilySamples sampleFamily = samples.get(0);
+ assertEquals("solr_facets_category", sampleFamily.name);
+ assertEquals(PrometheusExporterTestBase.FACET_VALUES.size(), sampleFamily.samples.size());
+
+ for (Collector.MetricFamilySamples.Sample sample : sampleFamily.samples) {
+ assertEquals(
+ PrometheusExporterTestBase.FACET_VALUES.get(sample.labelValues.get(0)),
+ sample.value,
+ 0.001);
+ }
+ }
+}
diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
index 1db0142c2ea..7f756c0fb3e 100644
--- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
+++ b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
@@ -18,27 +18,34 @@
package org.apache.solr.prometheus.scraper;
import io.prometheus.client.Collector;
-import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
-import org.apache.commons.io.FileUtils;
+import org.apache.lucene.tests.util.LuceneTestCase;
+import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.impl.Http2SolrClient;
-import org.apache.solr.client.solrj.impl.NoOpResponseParser;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.prometheus.PrometheusExporterTestBase;
import org.apache.solr.prometheus.collector.MetricSamples;
import org.apache.solr.prometheus.exporter.MetricsConfiguration;
+import org.apache.solr.prometheus.exporter.PrometheusExporterSettings;
+import org.apache.solr.prometheus.exporter.SolrClientFactory;
+import org.apache.solr.prometheus.exporter.SolrScrapeConfiguration;
import org.apache.solr.prometheus.utils.Helpers;
-import org.apache.solr.util.RestTestBase;
+import org.apache.solr.util.SolrJettyTestRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
-public class SolrStandaloneScraperTest extends RestTestBase {
+public class SolrStandaloneScraperTest extends SolrTestCaseJ4 {
+
+ @ClassRule public static final SolrJettyTestRule solrRule = new SolrJettyTestRule();
private static MetricsConfiguration configuration;
private static SolrStandaloneScraper solrScraper;
@@ -47,42 +54,45 @@ public class SolrStandaloneScraperTest extends RestTestBase {
@BeforeClass
public static void setupBeforeClass() throws Exception {
- File tmpSolrHome = createTempDir().toFile();
- tmpSolrHome.deleteOnExit();
-
- FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile());
-
- initCore("solrconfig.xml", "managed-schema");
+ solrRule.startSolr(LuceneTestCase.createTempDir());
- createJettyAndHarness(
- tmpSolrHome.getAbsolutePath(), "solrconfig.xml", "managed-schema", "/solr", true, null);
+ Path configSet = LuceneTestCase.createTempDir();
+ createConf(configSet);
+ solrRule.newCollection().withConfigSet(configSet.toString()).create();
+ PrometheusExporterSettings settings = PrometheusExporterSettings.builder().build();
+ SolrScrapeConfiguration scrapeConfiguration =
+ SolrScrapeConfiguration.standalone(solrRule.getBaseUrl());
+ solrClient =
+ new SolrClientFactory(settings, scrapeConfiguration)
+ .createStandaloneSolrClient(solrRule.getBaseUrl());
executor =
ExecutorUtil.newMDCAwareFixedThreadPool(
25, new SolrNamedThreadFactory("solr-cloud-scraper-tests"));
configuration =
Helpers.loadConfiguration("conf/prometheus-solr-exporter-scraper-test-config.xml");
-
- solrClient =
- new Http2SolrClient.Builder(restTestHarness.getAdminURL())
- .withResponseParser(new NoOpResponseParser("json"))
- .build();
solrScraper = new SolrStandaloneScraper(solrClient, executor, "test");
Helpers.indexAllDocs(solrClient);
}
+ public static void createConf(Path configSet) throws IOException {
+ Path subHome = configSet.resolve("conf");
+ Files.createDirectories(subHome);
+
+ Path top = SolrTestCaseJ4.TEST_PATH().resolve("collection1").resolve("conf");
+ Files.copy(top.resolve("managed-schema.xml"), subHome.resolve("schema.xml"));
+ Files.copy(top.resolve("solrconfig.xml"), subHome.resolve("solrconfig.xml"));
+
+ Files.copy(top.resolve("stopwords.txt"), subHome.resolve("stopwords.txt"));
+ Files.copy(top.resolve("synonyms.txt"), subHome.resolve("synonyms.txt"));
+ }
+
@AfterClass
- public static void cleanUp() throws Exception {
+ public static void cleanup() throws Exception {
+ // scraper also closes the client
IOUtils.closeQuietly(solrScraper);
- IOUtils.closeQuietly(solrClient);
- cleanUpHarness();
- if (null != executor) {
- executor.shutdownNow();
- executor = null;
- }
- solrScraper = null;
- solrClient = null;
+ ExecutorUtil.shutdownNowAndAwaitTermination(executor);
}
@Test
@@ -107,8 +117,7 @@ public class SolrStandaloneScraperTest extends RestTestBase {
assertEquals(1, samples.samples.size());
assertEquals(1.0, samples.samples.get(0).value, 0.001);
assertEquals(List.of("base_url", "cluster_id"), samples.samples.get(0).labelNames);
- assertEquals(
- List.of(restTestHarness.getAdminURL(), "test"), samples.samples.get(0).labelValues);
+ assertEquals(List.of(solrRule.getBaseUrl(), "test"), samples.samples.get(0).labelValues);
}
@Test
@@ -127,7 +136,7 @@ public class SolrStandaloneScraperTest extends RestTestBase {
assertEquals(1, metricsByHost.size());
List<Collector.MetricFamilySamples> replicaSamples =
- metricsByHost.get(restTestHarness.getAdminURL()).asList();
+ metricsByHost.get(solrRule.getBaseUrl()).asList();
assertEquals(1, replicaSamples.size());
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 b05631f89a6..3e484647c5d 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
@@ -40,6 +40,8 @@ See the section below <<Prometheus Configuration>>
== Starting the Exporter
You can start `solr-exporter` by running `./bin/solr-exporter` (Linux) or `.\bin\solr-exporter.cmd` (Windows) from the `prometheus-exporter/` directory.
+The metrics exposed by `solr-exporter` can be seen at the metrics endpoint: `\http://localhost:8983/solr/admin/metrics`.
+
See the commands below depending on your operating system and Solr operating mode:
[.dynamic-tabs]
@@ -171,7 +173,15 @@ The freshness of the metrics can be improved by reducing the scrape interval but
+
A unique ID for the cluster to monitor. This ID will be added to all metrics as a label `cluster_id` and can be used as a filter in the Grafana dashboard if you operate multiple Solr clusters reporting to the same Prometheus instance. If this option is omitted, a hash of the `baseUrl` or `zkHost` will be used as ID by default.
-The metrics exposed by `solr-exporter` can be seen at the metrics endpoint: `\http://localhost:8983/solr/admin/metrics`.
+`-u`, `--credentials`, `$CREDENTIALS`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: none
+|===
++
+Specify the credentials in the format `username:password`. Example: `--credentials solr:SolrRocks`.
+
=== Environment Variable Options
diff --git a/solr/test-framework/src/java/org/apache/solr/util/SolrClientTestRule.java b/solr/test-framework/src/java/org/apache/solr/util/SolrClientTestRule.java
index a0407093bb4..cb2d74ff204 100644
--- a/solr/test-framework/src/java/org/apache/solr/util/SolrClientTestRule.java
+++ b/solr/test-framework/src/java/org/apache/solr/util/SolrClientTestRule.java
@@ -61,6 +61,8 @@ public abstract class SolrClientTestRule extends ExternalResource {
private String configSet;
private String configFile;
private String schemaFile;
+ private String basicAuthUser;
+ private String basicAuthPwd;
public NewCollectionBuilder(String name) {
this.name = name;
@@ -93,6 +95,12 @@ public abstract class SolrClientTestRule extends ExternalResource {
return this;
}
+ public NewCollectionBuilder withBasicAuthCredentials(String user, String password) {
+ this.basicAuthUser = user;
+ this.basicAuthPwd = password;
+ return this;
+ }
+
public String getName() {
return name;
}
@@ -112,6 +120,14 @@ public abstract class SolrClientTestRule extends ExternalResource {
public void create() throws SolrServerException, IOException {
SolrClientTestRule.this.create(this);
}
+
+ public String getBasicAuthUser() {
+ return basicAuthUser;
+ }
+
+ public String getBasicAuthPwd() {
+ return basicAuthPwd;
+ }
}
protected void create(NewCollectionBuilder b) throws SolrServerException, IOException {
@@ -132,6 +148,10 @@ public abstract class SolrClientTestRule extends ExternalResource {
req.setSchemaName(b.getSchemaFile());
}
+ if (b.getBasicAuthUser() != null) {
+ req.setBasicAuthCredentials(b.getBasicAuthUser(), b.getBasicAuthPwd());
+ }
+
req.process(getAdminClient());
}