diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java index 3aac98cd595..ef6ce661953 100644 --- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java +++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java @@ -783,13 +783,13 @@ public class Overseer { if (slices != null) { for (Slice slice : slices) { for (Replica replica : slice.getReplicas()) { - String baseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP); + String nodeName = replica.getStr(ZkStateReader.NODE_NAME_PROP); String core = replica.getStr(ZkStateReader.CORE_NAME_PROP); - String msgBaseUrl = message.getStr(ZkStateReader.BASE_URL_PROP); + String msgNodeName = message.getStr(ZkStateReader.NODE_NAME_PROP); String msgCore = message.getStr(ZkStateReader.CORE_NAME_PROP); - if (baseUrl.equals(msgBaseUrl) && core.equals(msgCore)) { + if (nodeName.equals(msgNodeName) && core.equals(msgCore)) { return replica.getName(); } } diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java index cda36b7a892..59be2db8454 100644 --- a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java +++ b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionProcessor.java @@ -1009,7 +1009,7 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread { for (String subShardName : subShardNames) { // wait for parent leader to acknowledge the sub-shard core log.info("Asking parent leader to wait for: " + subShardName + " to be alive on: " + nodeName); - String coreNodeName = waitForCoreNodeName(collection, zkStateReader.getBaseUrlForNodeName(nodeName), subShardName); + String coreNodeName = waitForCoreNodeName(collection, nodeName, subShardName); CoreAdminRequest.WaitForState cmd = new CoreAdminRequest.WaitForState(); cmd.setCoreName(subShardName); cmd.setNodeName(nodeName); @@ -1137,7 +1137,7 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread { sendShardRequest(subShardNodeName, params); - String coreNodeName = waitForCoreNodeName(collection, zkStateReader.getBaseUrlForNodeName(subShardNodeName), shardName); + String coreNodeName = waitForCoreNodeName(collection, subShardNodeName, shardName); // wait for the replicas to be seen as active on sub shard leader log.info("Asking sub shard leader to wait for: " + shardName + " to be alive on: " + subShardNodeName); CoreAdminRequest.WaitForState cmd = new CoreAdminRequest.WaitForState(); @@ -1232,7 +1232,7 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread { } } - private String waitForCoreNodeName(DocCollection collection, String msgBaseUrl, String msgCore) { + private String waitForCoreNodeName(DocCollection collection, String msgNodeName, String msgCore) { int retryCount = 320; while (retryCount-- > 0) { Map slicesMap = zkStateReader.getClusterState() @@ -1243,10 +1243,10 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread { for (Replica replica : slice.getReplicas()) { // TODO: for really large clusters, we could 'index' on this - String baseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP); + String nodeName = replica.getStr(ZkStateReader.NODE_NAME_PROP); String core = replica.getStr(ZkStateReader.CORE_NAME_PROP); - if (baseUrl.equals(msgBaseUrl) && core.equals(msgCore)) { + if (nodeName.equals(msgNodeName) && core.equals(msgCore)) { return replica.getName(); } } @@ -1530,7 +1530,7 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread { String tempCollectionReplica1 = tempSourceCollectionName + "_" + tempSourceSlice.getName() + "_replica1"; String coreNodeName = waitForCoreNodeName(clusterState.getCollection(tempSourceCollectionName), - zkStateReader.getBaseUrlForNodeName(sourceLeader.getNodeName()), tempCollectionReplica1); + sourceLeader.getNodeName(), tempCollectionReplica1); // wait for the replicas to be seen as active on temp source leader log.info("Asking source leader to wait for: " + tempCollectionReplica1 + " to be alive on: " + sourceLeader.getNodeName()); CoreAdminRequest.WaitForState cmd = new CoreAdminRequest.WaitForState(); @@ -1578,7 +1578,7 @@ public class OverseerCollectionProcessor implements Runnable, ClosableThread { completeAsyncRequest(asyncId, requestMap, results); coreNodeName = waitForCoreNodeName(clusterState.getCollection(tempSourceCollectionName), - zkStateReader.getBaseUrlForNodeName(targetLeader.getNodeName()), tempCollectionReplica2); + targetLeader.getNodeName(), tempCollectionReplica2); // wait for the replicas to be seen as active on temp source leader log.info("Asking temp source leader to wait for: " + tempCollectionReplica2 + " to be alive on: " + targetLeader.getNodeName()); cmd = new CoreAdminRequest.WaitForState(); diff --git a/solr/core/src/test/org/apache/solr/cloud/SSLMigrationTest.java b/solr/core/src/test/org/apache/solr/cloud/SSLMigrationTest.java new file mode 100644 index 00000000000..d833472f6d3 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/cloud/SSLMigrationTest.java @@ -0,0 +1,119 @@ +package org.apache.solr.cloud; + +/* + * 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. + */ + +import static org.apache.solr.common.cloud.ZkNodeProps.makeMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.embedded.JettySolrRunner; +import org.apache.solr.client.solrj.impl.HttpClientUtil; +import org.apache.solr.client.solrj.impl.LBHttpSolrServer; +import org.apache.solr.client.solrj.request.QueryRequest; +import org.apache.solr.common.cloud.DocCollection; +import org.apache.solr.common.cloud.Replica; +import org.apache.solr.common.cloud.Slice; +import org.apache.solr.common.cloud.ZkStateReader; +import org.apache.solr.common.params.CollectionParams.CollectionAction; +import org.apache.solr.common.params.MapSolrParams; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.util.SSLTestConfig; +import org.apache.solr.SolrTestCaseJ4.SuppressSSL; +import org.apache.lucene.util.LuceneTestCase.Slow; + +/** + * We want to make sure that when migrating between http and https modes the + * replicas will not be rejoined as new nodes, but rather take off where it left + * off in the cluster. + */ +@Slow +@SuppressSSL +public class SSLMigrationTest extends AbstractFullDistribZkTestBase { + + @Override + public void doTest() throws Exception { + //Migrate from HTTP -> HTTPS -> HTTP + assertReplicaInformation("http"); + testMigrateSSL(new SSLTestConfig(true, false)); + testMigrateSSL(new SSLTestConfig(false, false)); + } + + public void testMigrateSSL(SSLTestConfig sslConfig) throws Exception { + String urlScheme = sslConfig.isSSLMode() ? "https" : "http"; + setUrlScheme(urlScheme); + + for(JettySolrRunner runner : jettys) { + runner.stop(); + } + + HttpClientUtil.setConfigurer(sslConfig.getHttpClientConfigurer()); + for(int i = 0; i < this.jettys.size(); i++) { + JettySolrRunner runner = jettys.get(i); + JettySolrRunner newRunner = new JettySolrRunner(runner.getSolrHome(), + context, runner.getLocalPort(), getSolrConfigFile(), getSchemaFile(), + false, getExtraServlets(), sslConfig, getExtraRequestFilters()); + newRunner.setDataDir(getDataDir(testDir + "/shard" + i + "/data")); + newRunner.start(true); + jettys.set(i, newRunner); + } + + assertReplicaInformation(urlScheme); + } + + private void assertReplicaInformation(String urlScheme) throws Exception { + List replicas = getReplicas(); + assertEquals("Wrong number of replicas found", 4, replicas.size()); + for(Replica replica : replicas) { + assertTrue("Replica didn't have the proper urlScheme in the ClusterState", + StringUtils.startsWith(replica.getStr(ZkStateReader.BASE_URL_PROP), urlScheme)); + } + } + + private List getReplicas() { + List replicas = new ArrayList(); + + DocCollection collection = this.cloudClient.getZkStateReader().getClusterState().getCollection(DEFAULT_COLLECTION); + for(Slice slice : collection.getSlices()) { + replicas.addAll(slice.getReplicas()); + } + return replicas; + } + + private void setUrlScheme(String value) throws Exception { + @SuppressWarnings("rawtypes") + Map m = makeMap("action", CollectionAction.CLUSTERPROP.toString() + .toLowerCase(Locale.ROOT), "name", "urlScheme", "val", value); + @SuppressWarnings("unchecked") + SolrParams params = new MapSolrParams(m); + SolrRequest request = new QueryRequest(params); + request.setPath("/admin/collections"); + + List urls = new ArrayList(); + for(Replica replica : getReplicas()) { + urls.add(replica.getStr(ZkStateReader.BASE_URL_PROP)); + } + //Create new SolrServer to configure new HttpClient w/ SSL config + new LBHttpSolrServer(urls.toArray(new String[]{})).request(request); + } + +} \ No newline at end of file