blob: e72c2336ebced1117278c6d9995b23a2652f0938 [file] [log] [blame]
/*
* 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.cloud;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.List;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.cloud.CloudTestUtils.AutoScalingRequest;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.util.LogLevel;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@LogLevel("org.apache.solr.cloud.autoscaling=DEBUG;org.apache.solr.cloud.Overseer=DEBUG;org.apache.solr.cloud.overseer=DEBUG;org.apache.solr.client.solrj.impl.SolrClientDataProvider=DEBUG;org.apache.solr.client.solrj.cloud.autoscaling.PolicyHelper=TRACE")
public class TestUtilizeNode extends SolrCloudTestCase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@BeforeClass
public static void setupCluster() throws Exception {
System.setProperty("metricsEnabled", "true");
configureCluster(3)
.addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-dynamic").resolve("conf"))
.configure();
NamedList<Object> overSeerStatus = cluster.getSolrClient().request(CollectionAdminRequest.getOverseerStatus());
JettySolrRunner overseerJetty = null;
String overseerLeader = (String) overSeerStatus.get("leader");
for (int i = 0; i < cluster.getJettySolrRunners().size(); i++) {
JettySolrRunner jetty = cluster.getJettySolrRunner(i);
if (jetty.getNodeName().equals(overseerLeader)) {
overseerJetty = jetty;
break;
}
}
if (overseerJetty == null) {
fail("no overseer leader!");
}
}
protected String getSolrXml() {
return "solr.xml";
}
@Before
public void beforeTest() throws Exception {
cluster.deleteAllCollections();
}
@Test
public void test() throws Exception {
int REPLICATION = 2;
String coll = "utilizenodecoll";
CloudSolrClient cloudClient = cluster.getSolrClient();
log.info("Creating Collection...");
CollectionAdminRequest.Create create = CollectionAdminRequest.createCollection(coll, "conf1", 2, REPLICATION)
.setMaxShardsPerNode(2);
cloudClient.request(create);
log.info("Spinning up additional jettyX...");
JettySolrRunner jettyX = cluster.startJettySolrRunner();
cluster.waitForAllNodes(30);
assertNoReplicas("jettyX should not yet be utilized: ", coll, jettyX);
if (log.isInfoEnabled()) {
log.info("Sending UTILIZE command for jettyX ({})", jettyX.getNodeName());
}
cloudClient.request(new CollectionAdminRequest.UtilizeNode(jettyX.getNodeName()));
// TODO: aparently we can't assert this? ...
//
// assertSomeReplicas("jettyX should now be utilized: ", coll, jettyX);
//
// ... it appears from the docs that unless there are policy violations,
// this can be ignored unless jettyX has less "load" then other jetty instances?
//
// if the above is true, that means that this test is incredibly weak...
// unless we know jettyX has at least one replica, then all the subsequent testing of the
// port blacklist & additional UTILIZE command for jettyY are a waste of time.
//
// should we skip spinning up a *new* jettyX, and instead just pick an existing jetty?
if (log.isInfoEnabled()) {
log.info("jettyX replicas prior to being blacklisted: {}", getReplicaList(coll, jettyX));
}
String setClusterPolicyCommand = "{" +
" 'set-cluster-policy': [" +
" {'port':" + jettyX.getLocalPort() +
" , 'replica':0}" +
" ]" +
"}";
if (log.isInfoEnabled()) {
log.info("Setting new policy to blacklist jettyX ({}) port={}",
jettyX.getNodeName(), jettyX.getLocalPort());
}
@SuppressWarnings({"rawtypes"})
SolrRequest req = AutoScalingRequest.create(SolrRequest.METHOD.POST, setClusterPolicyCommand);
NamedList<Object> response = cloudClient.request(req);
assertEquals(req + " => " + response,
"success", response.get("result").toString());
log.info("Spinning up additional jettyY...");
JettySolrRunner jettyY = cluster.startJettySolrRunner();
cluster.waitForAllNodes(30);
assertNoReplicas("jettyY should not yet be utilized: ", coll, jettyY);
if (log.isInfoEnabled()) {
log.info("jettyX replicas prior to utilizing jettyY: {}", getReplicaList(coll, jettyX));
log.info("Sending UTILIZE command for jettyY ({})", jettyY.getNodeName()); // logOk
}
cloudClient.request(new CollectionAdminRequest.UtilizeNode(jettyY.getNodeName()));
assertSomeReplicas("jettyY should now be utilized: ", coll, jettyY);
assertNoReplicas("jettyX should no longer be utilized: ", coll, jettyX);
}
/**
* Gets the list of replicas for the specified collection hosted on the specified node
* and then asserts that it has no replicas
*/
private void assertNoReplicas(String prefix, String collectionName, JettySolrRunner jettyNode) throws IOException {
final List<Replica> replicas = getReplicaList(collectionName, jettyNode);
assertEquals(prefix + " " + jettyNode.getNodeName() + " => " + replicas,
0, replicas.size());
}
/**
* Gets the list of replicas for the specified collection hosted on the specified node
* and then asserts that it there is at least one
*/
private void assertSomeReplicas(String prefix, String collectionName, JettySolrRunner jettyNode) throws IOException {
final List<Replica> replicas = getReplicaList(collectionName, jettyNode);
assertTrue(prefix + " " + jettyNode.getNodeName() + " => " + replicas,
0 < replicas.size());
}
/**
* Returns a list of all Replicas for the specified collection hosted on the specified node using
* an <em>uncached</em> ClusterState call (so it should be authoritative from ZK).
*/
private List<Replica> getReplicaList(String collectionName, JettySolrRunner jettyNode) throws IOException {
DocCollection collection = cluster.getSolrClient().getClusterStateProvider()
// we do *NOT* want to trust the cache, because anytime we call this method we have just
// done a lot of mucking with the cluster
.getClusterState().getCollectionOrNull(collectionName, false);
List<Replica> results = new ArrayList<>(3);
if (collection != null) {
collection.forEachReplica((s, replica) -> {
if (replica.getNodeName().equals(jettyNode.getNodeName())) {
results.add(replica);
}
});
}
return results;
}
}