Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOLR-16505: Switch UpdateShardHandler.getRecoveryOnlyHttpClient to Jetty HTTP2 #2276

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c2e578e
SOLR-16505: Switch UpdateShardHandler.getRecoveryOnlyHttpClient to Je…
iamsanjay Feb 18, 2024
d5bc8c4
Merge main
iamsanjay Feb 20, 2024
3572dec
SOLR-16505: Switch UpdateShardHandler.getRecoveryOnlyHttpClient to Je…
iamsanjay Feb 20, 2024
9588fdf
Merge main
iamsanjay Feb 27, 2024
0655f11
Using FutureTask to send PREPRECOVERY, without executor
iamsanjay Feb 27, 2024
e7c346f
Merge main
iamsanjay Feb 29, 2024
0611782
Null check for FutureTask, removed try-catch
iamsanjay Feb 29, 2024
91f3c9d
code format, added test case
iamsanjay Mar 1, 2024
6a0b54b
Merge branch 'main' into SOLR-16367_getRecoveryOnlyHttpClient_to_Jett…
iamsanjay Mar 3, 2024
1c6798b
Remove comment, create method for cancel recovery
iamsanjay Mar 3, 2024
5a62766
Merge main
iamsanjay Mar 7, 2024
ae368b5
Update IndexFetcher Class to Use Http2SolrClient
iamsanjay Mar 7, 2024
9e9b5f7
Adding header for compression to SolrRequests
iamsanjay Mar 7, 2024
8deebcd
Merge branch 'main' into SOLR-16367_getRecoveryOnlyHttpClient_to_Jett…
iamsanjay Mar 12, 2024
625a364
Enable testing resplication handler for externalCompression
iamsanjay Mar 12, 2024
901ef51
Renaming method to more appropriate name
iamsanjay Mar 12, 2024
d574b42
Merge main
iamsanjay Mar 13, 2024
cc4011b
Merge branch 'main' into SOLR-16367_getRecoveryOnlyHttpClient_to_Jett…
iamsanjay Mar 13, 2024
26a4c0e
Resolve conflicts Http2SolrClient
iamsanjay Mar 13, 2024
de5a40c
Merge branch 'main' into SOLR-16367_getRecoveryOnlyHttpClient_to_Jett…
iamsanjay Mar 18, 2024
43dda16
Restoring the old auth of IndexFetcher
iamsanjay Mar 18, 2024
b48c0b9
Merge main
iamsanjay Mar 27, 2024
851109f
Fix retry fetch() IndexFetcher
iamsanjay Mar 27, 2024
6af3d76
Merge main
iamsanjay Mar 30, 2024
73c5ba8
Avoid closing InputStream before receiving zero-length Data field
iamsanjay Mar 30, 2024
4c16404
Read till end-of-file
iamsanjay Mar 30, 2024
19ec489
read till end-of-file
iamsanjay Mar 30, 2024
917509f
Merge main
iamsanjay Apr 18, 2024
c54cd5b
Added Test case for User managed replication with basic auth enabled
iamsanjay Apr 18, 2024
bb1c3b3
Removed isContentDownloaded and updated listener factory setting mech…
iamsanjay Apr 22, 2024
38f532a
Merge main
iamsanjay Apr 22, 2024
377eaa3
Merge branch 'main' into SOLR-16367_getRecoveryOnlyHttpClient_to_Jett…
iamsanjay Apr 30, 2024
1b9b7fc
Change return code when downloaded successfully
iamsanjay Apr 30, 2024
fdb1d1f
Merge branch 'main' into SOLR-16367_getRecoveryOnlyHttpClient_to_Jett…
iamsanjay May 8, 2024
ef92b6b
tidy code
iamsanjay May 8, 2024
6279656
Update basic-authentication-plugin.adoc (#2446)
gspgsp May 8, 2024
b789a71
group operators together (#2450)
epugh May 8, 2024
f39e8ba
SOLR-17192: Add "field-limiting" URP to catch ill-designed schemas (#…
gerlowskija May 8, 2024
6bde352
CHANGES.txt
dsmiley May 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions solr/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ Other Changes

* SOLR-17217: Simplify verbose MatcherAssert.assertThat usage in tests (hossman)

* SOLR-17232: PropertiesOutputStream is renamed IndexOutputOutputStream and overrides write(byte[], int, int).
(Bruno Roustant)

* SOLR-16505: Switch internal replica recovery commands to Jetty HTTP2 (Sanjay Dutt, David Smiley)

================== 9.5.0 ==================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1817,7 +1817,7 @@ private int fetchPackets(FastInputStream fis) throws Exception {
boolean isContentReceived = false;
iamsanjay marked this conversation as resolved.
Show resolved Hide resolved
try {
while (true) {
if(fis.peek() == -1){
if (fis.peek() == -1) {
return NO_CONTENT;
iamsanjay marked this conversation as resolved.
Show resolved Hide resolved
}
if (stop) {
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reference to this file from the test; am I missing something?

If this is actually used, then please consider instead modifying your test to manipulate the temp config files so that we don't have yet another test config file to maintain. For an example of this technique, see org.apache.solr.search.TestCpuAllowedLimit#createConfigSet

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't push this point further because your ...WithAuth test uses ReplicationTestHelper.SolrInstance which has sone conveniences and I'm not sure how compatible it is with my suggestion.

dsmiley marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version="1.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.
-->

<config>
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
<schemaFactory class="ClassicIndexSchemaFactory"/>
<dataDir>${solr.data.dir:}</dataDir>

<xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>

<updateHandler class="solr.DirectUpdateHandler2">
</updateHandler>

<requestHandler name="/select" class="solr.SearchHandler">
<bool name="httpCaching">true</bool>
</requestHandler>

<!-- test query parameter defaults -->
<requestHandler name="/defaults" class="solr.SearchHandler">

</requestHandler>

<!-- test query parameter defaults -->
<requestHandler name="/lazy" class="solr.SearchHandler" startup="lazy">
</requestHandler>

<requestHandler name="/replication" class="solr.ReplicationHandler">
<lst name="follower">
<str name="leaderUrl">http://127.0.0.1:TEST_PORT/solr/collection1</str>
<str name="pollInterval">00:00:01</str>
<str name="compression">COMPRESSION</str>
<str name="httpBasicAuthUser">solr</str>
<str name="httpBasicAuthPassword">SolrRocks</str>
</lst>
</requestHandler>

<requestDispatcher>
<requestParsers multipartUploadLimitInKB="-1"/>
<httpCaching lastModifiedFrom="openTime" etagSeed="Solr" never304="false">
<cacheControl>max-age=30, public</cacheControl>
</httpCaching>
</requestDispatcher>

</config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/*
* 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.handler;

import static org.apache.solr.common.params.CommonParams.JAVABIN;
import static org.apache.solr.handler.ReplicationHandler.CMD_DISABLE_POLL;
import static org.apache.solr.handler.ReplicationHandler.CMD_FETCH_INDEX;
import static org.apache.solr.handler.ReplicationHandler.COMMAND;
import static org.apache.solr.handler.ReplicationTestHelper.createAndStartJetty;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.HealthCheckRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.embedded.JettySolrRunner;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

@SuppressSSL
public class TestUserManagedReplicationWithAuth extends SolrTestCaseJ4 {
JettySolrRunner leaderJetty, followerJetty, followerJettyWithAuth;
SolrClient leaderClient, followerClient, followerClientWithAuth;
ReplicationTestHelper.SolrInstance leader = null, follower = null, followerWithAuth = null;

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"
+ "}}";

@Override
@Before
public void setUp() throws Exception {
super.setUp();
systemSetPropertySolrDisableUrlAllowList("true");
// leader with Basic auth enabled via security.json
leader =
new ReplicationTestHelper.SolrInstance(
createTempDir("solr-instance").toFile(), "leader", null);
leader.setUp();
// Configuring basic auth for Leader
Path solrLeaderHome = Path.of(leader.getHomeDir());
Files.write(
solrLeaderHome.resolve("security.json"), securityJson.getBytes(StandardCharsets.UTF_8));
leaderJetty = ReplicationTestHelper.createAndStartJetty(leader);
leaderClient =
ReplicationTestHelper.createNewSolrClient(
buildUrl(leaderJetty.getLocalPort()), DEFAULT_TEST_CORENAME);

// follower with no basic auth credentials for leader configured.
follower =
new ReplicationTestHelper.SolrInstance(
createTempDir("solr-instance").toFile(), "follower", leaderJetty.getLocalPort());
follower.setUp();
followerJetty = createAndStartJetty(follower);
followerClient =
ReplicationTestHelper.createNewSolrClient(
buildUrl(followerJetty.getLocalPort()), DEFAULT_TEST_CORENAME);

// follower with basic auth credentials for leader configured in solrconfig.xml.
followerWithAuth =
new ReplicationTestHelper.SolrInstance(
createTempDir("solr-instance").toFile(), "follower-auth", leaderJetty.getLocalPort());
dsmiley marked this conversation as resolved.
Show resolved Hide resolved
followerWithAuth.setUp();
followerJettyWithAuth = createAndStartJetty(followerWithAuth);
followerClientWithAuth =
ReplicationTestHelper.createNewSolrClient(
buildUrl(followerJettyWithAuth.getLocalPort()), DEFAULT_TEST_CORENAME);
}

@Override
@After
public void tearDown() throws Exception {
super.tearDown();
if (null != leaderJetty) {
leaderJetty.stop();
leaderJetty = null;
}
if (null != followerJetty) {
followerJetty.stop();
followerJetty = null;
}
if (null != followerJettyWithAuth) {
followerJettyWithAuth.stop();
followerJettyWithAuth = null;
}
if (null != leaderClient) {
leaderClient.close();
leaderClient = null;
}
if (null != followerClient) {
followerClient.close();
followerClient = null;
}
if (null != followerClientWithAuth) {
followerClientWithAuth.close();
followerClientWithAuth = null;
}
}

private <T extends SolrRequest<? extends SolrResponse>> T withBasicAuth(T req) {
req.setBasicAuthCredentials(user, pass);
return req;
}

@Test
public void doTestManualFetchIndexWithAuthEnabled() throws Exception {
disablePoll(followerJetty, followerClient);
int nDocs = 500;
int docsAdded = 0;

UpdateRequest commitReq = new UpdateRequest();
withBasicAuth(commitReq);
for (int i = 0; docsAdded < nDocs / 2; i++, docsAdded++) {
SolrInputDocument doc = new SolrInputDocument();
String[] fields = {"id", i + "", "name", "name = " + i};
for (int j = 0; j < fields.length; j += 2) {
doc.addField(fields[j], fields[j + 1]);
}
UpdateRequest req = new UpdateRequest();
withBasicAuth(req).add(doc);
req.process(leaderClient, DEFAULT_TEST_CORENAME);
if (i % 10 == 0) {
commitReq.commit(leaderClient, DEFAULT_TEST_CORENAME);
}
}
commitReq.commit(leaderClient, DEFAULT_TEST_CORENAME);

assertEquals(
docsAdded,
queryWithBasicAuth(leaderClient, new SolrQuery("*:*")).getResults().getNumFound());

// Without Auth credentials fetchIndex will fail
pullIndexFromTo(leaderJetty, followerJetty, false);
assertNotEquals(
docsAdded,
queryWithBasicAuth(followerClient, new SolrQuery("*:*")).getResults().getNumFound());

// With Auth credentials
pullIndexFromTo(leaderJetty, followerJetty, true);
assertEquals(
docsAdded,
queryWithBasicAuth(followerClient, new SolrQuery("*:*")).getResults().getNumFound());
}

@Test
public void doTestAutoReplicationWithAuthEnabled() throws Exception {
int nDocs = 250;
UpdateRequest commitReq = new UpdateRequest();
withBasicAuth(commitReq);
for (int i = 0; i < nDocs; i++) {
SolrInputDocument doc = new SolrInputDocument();
String[] fields = {"id", i + "", "name", "name = " + i};
for (int j = 0; j < fields.length; j += 2) {
doc.addField(fields[j], fields[j + 1]);
}
UpdateRequest req = new UpdateRequest();
withBasicAuth(req).add(doc);
req.process(leaderClient, DEFAULT_TEST_CORENAME);
if (i % 10 == 0) {
commitReq.commit(leaderClient, DEFAULT_TEST_CORENAME);
}
}
commitReq.commit(leaderClient, DEFAULT_TEST_CORENAME);
// wait for followers to fetchIndex
Thread.sleep(5000);
// follower with auth should be healthy
HealthCheckRequest healthCheckRequestFollower = new HealthCheckRequest();
healthCheckRequestFollower.setMaxGenerationLag(2);
assertEquals(
CommonParams.OK,
healthCheckRequestFollower
.process(followerClientWithAuth)
.getResponse()
.get(CommonParams.STATUS));
// follower with auth should be unhealthy
healthCheckRequestFollower = new HealthCheckRequest();
healthCheckRequestFollower.setMaxGenerationLag(2);
assertEquals(
CommonParams.FAILURE,
healthCheckRequestFollower.process(followerClient).getResponse().get(CommonParams.STATUS));
}

private QueryResponse queryWithBasicAuth(SolrClient client, SolrQuery q)
throws IOException, SolrServerException {
return withBasicAuth(new QueryRequest(q)).process(client);
}

private void disablePoll(JettySolrRunner Jetty, SolrClient solrClient)
throws SolrServerException, IOException {
ModifiableSolrParams disablePollParams = new ModifiableSolrParams();
disablePollParams.set(COMMAND, CMD_DISABLE_POLL);
disablePollParams.set(CommonParams.WT, JAVABIN);
disablePollParams.set(CommonParams.QT, ReplicationHandler.PATH);
QueryRequest req = new QueryRequest(disablePollParams);
withBasicAuth(req);
req.setBasePath(buildUrl(Jetty.getLocalPort()));

solrClient.request(req, DEFAULT_TEST_CORENAME);
}

private void pullIndexFromTo(
JettySolrRunner srcSolr, JettySolrRunner destSolr, boolean authEnabled)
throws SolrServerException, IOException {
String srcUrl = buildUrl(srcSolr.getLocalPort()) + "/" + DEFAULT_TEST_CORENAME;
String destUrl = buildUrl(destSolr.getLocalPort()) + "/" + DEFAULT_TEST_CORENAME;
QueryRequest req = getQueryRequestForFetchIndex(authEnabled, srcUrl);
req.setBasePath(buildUrl(destSolr.getLocalPort()));
followerClient.request(req, DEFAULT_TEST_CORENAME);
}

private QueryRequest getQueryRequestForFetchIndex(boolean authEnabled, String srcUrl) {
ModifiableSolrParams solrParams = new ModifiableSolrParams();
solrParams.set(COMMAND, CMD_FETCH_INDEX);
solrParams.set(CommonParams.WT, JAVABIN);
solrParams.set(CommonParams.QT, ReplicationHandler.PATH);
solrParams.set("leaderUrl", srcUrl);
solrParams.set("wait", "true");
if (authEnabled) {
solrParams.set("httpBasicAuthUser", user);
solrParams.set("httpBasicAuthPassword", pass);
}
QueryRequest req = new QueryRequest(solrParams);
return req;
}
}
Loading