blob: d5fc5c0b281984bc0cfb64741dc748b7d0f255e8 [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.handler;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.function.Predicate;
import com.google.common.collect.ImmutableMap;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.ResponseParser;
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.SolrServerException;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.BaseHttpSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.response.V2Response;
import org.apache.solr.cloud.ConfigRequest;
import org.apache.solr.cloud.MiniSolrCloudCluster;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.NavigableObject;
import org.apache.solr.common.cloud.ClusterProperties;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.ConfigOverlay;
import org.apache.solr.core.MemClassLoader;
import org.apache.solr.core.PackageBag;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.util.LogLevel;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static org.apache.solr.cloud.SolrCloudAuthTestCase.NOT_NULL_PREDICATE;
import static org.apache.solr.cloud.TestCryptoKeys.readFile;
import static org.apache.solr.common.params.CommonParams.JAVABIN;
import static org.apache.solr.common.params.CommonParams.WT;
import static org.apache.solr.common.util.Utils.JAVABINCONSUMER;
import static org.apache.solr.common.util.Utils.getObjectByPath;
import static org.apache.solr.common.util.Utils.newBytesConsumer;
import static org.apache.solr.core.BlobRepository.sha256Digest;
import static org.apache.solr.core.TestDynamicLoading.getFileContent;
@SolrTestCaseJ4.SuppressSSL
@LogLevel("org.apache.solr.common.cloud.ZkStateReader=DEBUG;org.apache.solr.handler.admin.ClusterAPI=DEBUG;org.apache.solr.core.PackageBag=DEBUG;org.apache.solr.common.cloud.ClusterProperties=DEBUG")
public class TestPackages extends SolrCloudTestCase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@BeforeClass
public static void setupCluster() throws Exception {
System.setProperty("enable.package", "true");
}
static NavigableObject assertResponseValues(int repeats, SolrClient client, SolrRequest req, Map vals) throws Exception {
Callable<NavigableObject> callable = () -> req.process(client);
return assertResponseValues(repeats, callable,vals);
}
static NavigableObject assertResponseValues(int repeats, Callable<NavigableObject> callable,Map vals) throws Exception {
NavigableObject rsp = null;
for (int i = 0; i < repeats; i++) {
if (i > 0) {
Thread.sleep(100);
}
try {
rsp = callable.call();
} catch (Exception e) {
if (i >= repeats - 1) throw e;
continue;
}
for (Object e : vals.entrySet()) {
Map.Entry entry = (Map.Entry) e;
String k = (String) entry.getKey();
List<String> key = StrUtils.split(k, '/');
Object val = entry.getValue();
Predicate p = val instanceof Predicate ? (Predicate) val : o -> {
String v = o == null ? null : String.valueOf(o);
return Objects.equals(val, o);
};
boolean isPass = p.test(rsp._get(key, null));
if (isPass) return rsp;
else if (i >= repeats - 1) {
fail("req: " + callable.toString() +" . attempt: " + i + " Mismatch for value : '" + key + "' in response , " + Utils.toJSONString(rsp));
}
}
}
return rsp;
}
private static Map<String, Object> assertVersionInSync(SolrZkClient zkClient, SolrClient solrClient) throws SolrServerException, IOException {
Stat stat = new Stat();
Map<String, Object> map = new ClusterProperties(zkClient).getClusterProperties(stat);
assertEquals(String.valueOf(stat.getVersion()), getExtResponse(solrClient)._getStr("metadata/version", null));
return map;
}
private static V2Response getExtResponse(SolrClient solrClient) throws SolrServerException, IOException {
return new V2Request.Builder("/node/ext")
.withMethod(SolrRequest.METHOD.GET)
.build().process(solrClient);
}
// @AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/SOLR-13781")
@Test
public void testPackageAPI() throws Exception {
System.setProperty("enable.package", "true");
MiniSolrCloudCluster cluster = configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.configure();
byte[] derFile = readFile("cryptokeys/pub_key512.der");
cluster.getZkClient().makePath("/keys/exe", true);
cluster.getZkClient().create("/keys/exe/pub_key512.der", derFile, CreateMode.PERSISTENT, true);
try {
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs.jar.bin"),
"e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc", "runtimelibs.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs_v2.jar.bin"),
"79298d7d5c3e60d91154efe7d72f4536eac46698edfa22ab894b85492d562ed4", "runtimelibs_v2.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs_v3.jar.bin"),
"20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3","runtimelibs_v3.jar");
String payload = null;
try {
payload = "{add:{name : 'global' , version:'0.1', file: {id : 'wrong-id' , sig:'wrong-sig'}}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
fail("Error expected");
} catch (BaseHttpSolrClient.RemoteExecutionException e) {
assertTrue("actual output : " + Utils.toJSONString(e.getMetaData()),
e.getMetaData()._getStr("error/details[0]/errorMessages[0]", "").contains("No such file: "));
}
payload = "{add:{name : 'global', version :'1' , file : {" +
" id : 'e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar' , " +
"sig : 'L3q/qIGs4NaF6JiO0ZkMUFa88j0OmYc+I6O7BOdNuMct/xoZ4h73aZHZGc0+nmI1f/U3bOlMPINlSOM6LK3JpQ==' }}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "add/file/id"),
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true,
"packages/global/file/id"));
new V2Request.Builder("/cluster")
.withPayload("{add-requesthandler:{name : 'bar', class : 'org.apache.solr.core.RuntimeLibReqHandler', package : global}}")
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
Map<String, Object> map = new ClusterProperties(cluster.getZkClient()).getClusterProperties();
V2Request request = new V2Request.Builder("/node/ext/bar")
.withMethod(SolrRequest.METHOD.POST)
.build();
assertResponseValues(10, cluster.getSolrClient(), request, Utils.makeMap(
"class", "org.apache.solr.core.RuntimeLibReqHandler",
"loader", PackageBag.PackageResourceLoader.class.getName(),
"version", null));
assertEquals("org.apache.solr.core.RuntimeLibReqHandler",
getObjectByPath(map, true, asList("requestHandler", "bar", "class")));
payload = "{update:{name : 'global' , version: '3'," +
" file: {id : '20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3-runtimelibs_v3.jar', " +
"sig: 'a400n4T7FT+2gM0SC6+MfSOExjud8MkhTSFylhvwNjtWwUgKdPFn434Wv7Qc4QEqDVLhQoL3WqYtQmLPti0G4Q==' }}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
Map<String, Object> clusterProperties = new ClusterProperties(cluster.getZkClient()).getClusterProperties();
assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "update/file/id"),
getObjectByPath(clusterProperties, true, "packages/global/file/id"));
request = new V2Request.Builder("/node/ext/bar")
.withMethod(SolrRequest.METHOD.POST)
.build();
assertResponseValues(10, cluster.getSolrClient(), request, Utils.makeMap(
"class", "org.apache.solr.core.RuntimeLibReqHandler",
"loader", MemClassLoader.class.getName(),
"version", "3")
);
new V2Request.Builder("/cluster")
.withPayload("{delete-requesthandler: 'bar'}")
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
request = new V2Request.Builder("/node/ext")
.withMethod(SolrRequest.METHOD.POST)
.build();
assertResponseValues(10, cluster.getSolrClient(), request, ImmutableMap.of(SolrRequestHandler.TYPE,
(Predicate<Object>) o -> o instanceof List && ((List) o).isEmpty()));
new V2Request.Builder("/cluster/package")
.withPayload("{delete : 'global'}")
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
assertResponseValues(10, cluster.getSolrClient(),
new V2Request.Builder("/cluster/package")
.forceV2(true)
.withMethod(SolrRequest.METHOD.GET) .build(),
ImmutableMap.of(CommonParams.PACKAGES,
(Predicate<Object>) o -> o instanceof Map && ((Map) o).isEmpty()));
String baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString();
try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl).build()) {
V2Response rsp = new V2Request.Builder("/node/filestore/package")
.withMethod(SolrRequest.METHOD.GET)
.forceV2(true)
.build()
.process(client);
assertNotNull(rsp._get(asList("files", "package", "e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar"), null));
assertNotNull(rsp._get(asList("files", "package", "20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3-runtimelibs_v3.jar"), null));
ByteBuffer buf = Utils.executeGET(client.getHttpClient(),
baseUrl.replace("/solr", "/api") +
"/node/filestore/package/e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar",
newBytesConsumer(Integer.MAX_VALUE));
assertEquals("e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc", sha256Digest(buf));
buf = Utils.executeGET(client.getHttpClient(), baseUrl.replace("/solr", "/api")
+ "/node/filestore/package/20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3-runtimelibs_v3.jar",
newBytesConsumer(Integer.MAX_VALUE));
assertEquals("20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3", sha256Digest(buf));
}
} finally {
cluster.shutdown();
}
}
@Test
public void testRuntimeLibWithSig2048() throws Exception {
MiniSolrCloudCluster cluster = configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.configure();
try {
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs.jar.bin"),
"e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc", "runtimelibs.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs_v2.jar.bin"),
"79298d7d5c3e60d91154efe7d72f4536eac46698edfa22ab894b85492d562ed4", "runtimelibs_v2.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs_v3.jar.bin"),
"20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3",
"runtimelibs_v3.jar");
byte[] derFile = readFile("cryptokeys/pub_key2048.der");
cluster.getZkClient().makePath("/keys/exe", true);
cluster.getZkClient().create("/keys/exe/pub_key2048.der", derFile, CreateMode.PERSISTENT, true);
String signature = "NaTm3+i99/ZhS8YRsLc3NLz2Y6VuwEbu7DihY8GAWwWIGm+jpXgn1JiuaenfxFCcfNKCC9WgZmEgbTZTzmV/OZMVn90u642YJbF3vTnzelW1pHB43ZRAJ1iesH0anM37w03n3es+vFWQtuxc+2Go888fJoMkUX2C6Zk6Jn116KE45DWjeyPM4mp3vvGzwGvdRxP5K9Q3suA+iuI/ULXM7m9mV4ruvs/MZvL+ELm5Jnmk1bBtixVJhQwJP2z++8tQKJghhyBxPIC/2fkAHobQpkhZrXu56JjP+v33ul3Ku4bbvfVMY/LVwCAEnxlvhk+C6uRCKCeFMrzQ/k5inasXLw==";
String payload = "{add:{name : 'global', version: '1', file: {" +
" sig : 'EdYkvRpMZbvElN93/xUmyKXcj6xHP16AVk71TlTascEwCb5cFQ2AeKhPIlwYpkLWXEOcLZKfeXoWwOLaV5ZNhg==' ," +
"id : 'e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar'}}}";
try {
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
fail("should have failed");
} catch (BaseHttpSolrClient.RemoteExecutionException e) {
//No key matched signature for jar
assertTrue(e.getMetaData()._getStr("/error/details[0]/errorMessages[0]", "")
.contains("Invalid signature for file"));
}
payload = "{add:{name : 'global', version : '1', file:{ sig : '" + signature +
"', id : 'e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar'}}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "add/file/id"),
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true, "packages/global/file/id"));
new V2Request.Builder("/cluster")
.withPayload("{add-requesthandler:{name : 'bar', class : 'org.apache.solr.core.RuntimeLibReqHandler' package : global}}")
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
Map<String, Object> map = new ClusterProperties(cluster.getZkClient()).getClusterProperties();
V2Request request = new V2Request.Builder("/node/ext/bar")
.withMethod(SolrRequest.METHOD.POST)
.build();
assertResponseValues(10, cluster.getSolrClient(), request, Utils.makeMap(
"class", "org.apache.solr.core.RuntimeLibReqHandler",
"loader", MemClassLoader.class.getName(),
"version", null));
assertEquals("org.apache.solr.core.RuntimeLibReqHandler",
getObjectByPath(map, true, asList("requestHandler", "bar", "class")));
payload = "{update:{name : 'global', version : '3', file:{" +
" sig : 'YxFr6SpYrDwG85miDfRWHTjU9UltjtIWQZEhcV55C2rczRUVowCYBxmsDv5mAM8j0CTv854xpI1DtBT86wpoTdbF95LQuP9FJId4TS1j8bZ9cxHP5Cqyz1uBHFfUUNUrnpzTHQkVTp02O9NAjh3c2W41bL4U7j6jQ32+4CW2M+x00TDG0y0H75rQDR8zbLt31oWCz+sBOdZ3rGKJgAvdoGm/wVCTmsabZN+xoz4JaDeBXF16O9Uk9SSq4G0dz5YXFuLxHK7ciB5t0+q6pXlF/tdlDqF76Abze0R3d2/0MhXBzyNp3UxJmj6DiprgysfB0TbQtJG0XGfdSmx0VChvcA==' ," +
"id : '20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3-runtimelibs_v3.jar'}}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "update/file/id"),
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true, "packages/global/file/id"));
request = new V2Request.Builder("/node/ext/bar")
.withMethod(SolrRequest.METHOD.POST)
.build();
assertResponseValues(10, cluster.getSolrClient(), request, Utils.makeMap(
"class", "org.apache.solr.core.RuntimeLibReqHandler",
"loader", MemClassLoader.class.getName(),
"version", "3"));
assertResponseValues(5, cluster.getSolrClient(),
new V2Request.Builder("/cluster/package")
.forceV2(true)
.withMethod(SolrRequest.METHOD.GET)
.build(),
Utils.makeMap("/packages/global/file/id",
"20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3-runtimelibs_v3.jar"));
} finally {
cluster.shutdown();
}
}
@Test
public void testSetClusterReqHandler() throws Exception {
MiniSolrCloudCluster cluster = configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.configure();
try {
SolrZkClient zkClient = cluster.getZkClient();
new V2Request.Builder("/cluster")
.withPayload("{add-requesthandler:{name : 'foo', class : 'org.apache.solr.handler.DumpRequestHandler'}}")
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
Map<String, Object> map = assertVersionInSync(zkClient, cluster.getSolrClient());
assertEquals("org.apache.solr.handler.DumpRequestHandler",
getObjectByPath(map, true, asList("requestHandler", "foo", "class")));
assertVersionInSync(zkClient, cluster.getSolrClient());
V2Response rsp = new V2Request.Builder("/node/ext/foo")
.withMethod(SolrRequest.METHOD.GET)
.withParams(new MapSolrParams((Map) Utils.makeMap("testkey", "testval")))
.build().process(cluster.getSolrClient());
assertEquals("testval", rsp._getStr("params/testkey", null));
new V2Request.Builder("/cluster")
.withPayload("{delete-requesthandler: 'foo'}")
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
assertNull(getObjectByPath(map, true, asList("requestHandler", "foo")));
} finally {
cluster.shutdown();
}
}
@Test
public void testPluginFrompackage() throws Exception {
String COLLECTION_NAME = "globalLoaderColl";
MiniSolrCloudCluster cluster = configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.addConfig("conf", configset("cloud-minimal"))
.configure();
byte[] derFile = readFile("cryptokeys/pub_key512.der");
cluster.getZkClient().makePath("/keys/exe", true);
cluster.getZkClient().create("/keys/exe/pub_key512.der", derFile, CreateMode.PERSISTENT, true);
try {
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs.jar.bin"),
"e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc","runtimelibs.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs_v2.jar.bin"),
"79298d7d5c3e60d91154efe7d72f4536eac46698edfa22ab894b85492d562ed4",
"runtimelibs_v2.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs_v3.jar.bin"),
"20e0bfaec71b2e93c4da9f2ed3745dda04dc3fc915b66cc0275863982e73b2a3",
"runtimelibs_v3.jar");
CollectionAdminRequest
.createCollection(COLLECTION_NAME, "conf", 2, 1)
.setMaxShardsPerNode(100)
.process(cluster.getSolrClient());
cluster.waitForActiveCollection(COLLECTION_NAME, 2, 2);
String payload = "{add:{name : 'global', version : '1'," +
" file:{ id : 'e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar' ," +
"sig : 'L3q/qIGs4NaF6JiO0ZkMUFa88j0OmYc+I6O7BOdNuMct/xoZ4h73aZHZGc0+nmI1f/U3bOlMPINlSOM6LK3JpQ=='}}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
String fileId = (String) getObjectByPath(Utils.fromJSONString(payload), true, "add/file/id");
assertEquals(fileId,
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true,
"packages/global/file/id"));
payload = "{\n" +
"'create-requesthandler' : { 'name' : '/runtime', 'class': 'org.apache.solr.core.RuntimeLibReqHandler' , 'package':global }," +
"'create-searchcomponent' : { 'name' : 'get', 'class': 'org.apache.solr.core.RuntimeLibSearchComponent' , 'package':global }," +
"'create-queryResponseWriter' : { 'name' : 'json1', 'class': 'org.apache.solr.core.RuntimeLibResponseWriter' , 'package':global }" +
"}";
cluster.getSolrClient().request(new ConfigRequest(payload) {
@Override
public String getCollection() {
return COLLECTION_NAME;
}
});
SolrParams params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
GenericSolrRequest req1 = new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/queryResponseWriter/json1", params);
// SimpleSolrResponse rsp = req1.process(cluster.getSolrClient());
// System.out.println(rsp.jsonStr());
assertResponseValues(10,
cluster.getSolrClient(),
req1,
Utils.makeMap(
"/config/queryResponseWriter/json1/_packageinfo_/file/id", fileId
));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/searchComponent/get", params),
Utils.makeMap(
"config/searchComponent/get/_packageinfo_/file/id", fileId
));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/requestHandler/runtime", params),
Utils.makeMap(
":config:requestHandler:/runtime:_packageinfo_:file:id", fileId
));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME, WT, JAVABIN));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/overlay", params),
Utils.makeMap(
"overlay/queryResponseWriter/json1/class", "org.apache.solr.core.RuntimeLibResponseWriter",
"overlay/searchComponent/get/class", "org.apache.solr.core.RuntimeLibSearchComponent"
));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/runtime", params),
Utils.makeMap("class", "org.apache.solr.core.RuntimeLibReqHandler",
"loader", PackageBag.PackageResourceLoader.class.getName()));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/get?abc=xyz", params),
Utils.makeMap("get", "org.apache.solr.core.RuntimeLibSearchComponent",
"loader", PackageBag.PackageResourceLoader.class.getName()));
GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/runtime",
new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME, WT, "json1")));
req.setResponseParser(new ResponseParser() {
@Override
public String getWriterType() {
return "json1";
}
@Override
public NamedList<Object> processResponse(InputStream body, String encoding) {
return new NamedList<>((Map) Utils.fromJSON(body));
}
@Override
public NamedList<Object> processResponse(Reader reader) {
return new NamedList<>((Map) Utils.fromJSON(reader));
}
});
assertResponseValues(10,
cluster.getSolrClient(),
req,
Utils.makeMap("wt", "org.apache.solr.core.RuntimeLibResponseWriter",
"loader", PackageBag.PackageResourceLoader.class.getName()));
payload = "{update:{name : 'global', version : '2'" +
"file : { id : '79298d7d5c3e60d91154efe7d72f4536eac46698edfa22ab894b85492d562ed4-runtimelibs_v2.jar'," +
" sig : 'j+Rflxi64tXdqosIhbusqi6GTwZq8znunC/dzwcWW0/dHlFGKDurOaE1Nz9FSPJuXbHkVLj638yZ0Lp1ssnoYA=='}}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
fileId = (String) getObjectByPath(Utils.fromJSONString(payload), true, "update/file/id");
assertEquals(fileId,
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true,
"packages/global/file/id"));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/queryResponseWriter/json1", params),
Utils.makeMap(
"/config/queryResponseWriter/json1/_packageinfo_/file/id", fileId
));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/searchComponent/get", params),
Utils.makeMap(
"/config/searchComponent/get/_packageinfo_/file/id", fileId
));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/requestHandler/runtime", params),
Utils.makeMap(
":config:requestHandler:/runtime:_packageinfo_:file:id", fileId
));
try {
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
fail("should have failed");
} catch (BaseHttpSolrClient.RemoteExecutionException e) {
assertTrue("actual output : " + Utils.toJSONString(e.getMetaData()), e.getMetaData()._getStr("error/details[0]/errorMessages[0]", "").contains("Trying to update a package with the same data"));
}
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/get?abc=xyz", params),
Utils.makeMap("get", "org.apache.solr.core.RuntimeLibSearchComponent",
"loader", MemClassLoader.class.getName(),
"Version", "2"));
} finally {
cluster.deleteAllCollections();
cluster.shutdown();
}
}
@AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/SOLR-13650")
public void testCacheLoadFromPackage() throws Exception {
String COLLECTION_NAME = "globalCacheColl";
String overlay = "{" +
" \"props\":{\"query\":{\"documentCache\":{\n" +
" \"class\":\"org.apache.solr.core.MyDocCache\",\n" +
" \"size\":\"512\",\n" +
" \"initialSize\":\"512\" , \"package\":\"cache_pkg\"}}}}";
MiniSolrCloudCluster cluster = configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.addConfig("conf", configset("cloud-minimal"),
Collections.singletonMap(ConfigOverlay.RESOURCE_NAME, overlay.getBytes(UTF_8)))
.configure();
try {
postFile(cluster.getSolrClient(), getFileContent("runtimecode/cache.jar.bin"),
"32e8b5b2a95ea306538b52017f0954aa1b0f8a8b2d0acbc498fd0e66a223f7bd","cache.jar");
postFile(cluster.getSolrClient(), getFileContent("runtimecode/cache_v2.jar.bin"),
"0f670f6dcc2b00f9a448a7ebd457d4ff985ab702c85cdb3608dcae9889e8d702",
"cache_v2.jar");
String payload = "{add:{name : 'cache_pkg', version : '1', " +
" file: { id : '32e8b5b2a95ea306538b52017f0954aa1b0f8a8b2d0acbc498fd0e66a223f7bd', " +
"sig : 'A2CDnReirpII005KRN1C3pvt4NM4kItsagQPNaa3ljj/5R3LKVgiPuNvqBsffU8n81LOAfr5VMyGFcb4QMHpyg==' }}}";
try {
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
fail("should have failed");
} catch (BaseHttpSolrClient.RemoteExecutionException e) {
//No key matched signature for jar
assertTrue(e.getMetaData()._getStr("/error/details[0]/errorMessages[0]", "")
.contains("No public keys in ZK : /keys/exe"));
}
byte[] derFile = readFile("cryptokeys/pub_key512.der");
cluster.getZkClient().makePath("/keys/exe", true);
cluster.getZkClient().create("/keys/exe/pub_key512.der", derFile, CreateMode.PERSISTENT, true);
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "add/file/id"),
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(), true, "packages/cache_pkg/file/id"));
CollectionAdminRequest
.createCollection(COLLECTION_NAME, "conf", 2, 1)
.setMaxShardsPerNode(100)
.process(cluster.getSolrClient());
cluster.waitForActiveCollection(COLLECTION_NAME, 2, 2);
SolrParams params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME, WT, JAVABIN));
NamedList<Object> rsp = cluster.getSolrClient().request(new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/overlay", params));
assertEquals("org.apache.solr.core.MyDocCache", rsp._getStr("overlay/props/query/documentCache/class", null));
String fileId = (String) getObjectByPath(Utils.fromJSONString(payload), true, "add/file/id");
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/query/documentCache", params),
Utils.makeMap(
"/config/query/documentCache/_packageinfo_/file/id", fileId
));
UpdateRequest req = new UpdateRequest();
req.add("id", "1", "desc_s", "document 1")
.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true)
.setWaitSearcher(true);
cluster.getSolrClient().request(req, COLLECTION_NAME);
SolrQuery solrQuery = new SolrQuery("q", "id:1", "collection", COLLECTION_NAME);
assertResponseValues(10,
cluster.getSolrClient(),
new QueryRequest(solrQuery),
Utils.makeMap("/response[0]/my_synthetic_fld_s", "version_1"));
payload = "{update:{name : 'cache_pkg', version : '2', " +
"file: { id : '0f670f6dcc2b00f9a448a7ebd457d4ff985ab702c85cdb3608dcae9889e8d702-cache_v2.jar' ," +
" sig : 'SOrekHt+uup+z2z+nZU5indk2huRRfmbM+W+vQ0variHrcZEG9EXt5LuPFl8Ki9Ahr6klMHdVP8nj4wuQhu/Hg==' }}}";
new V2Request.Builder("/cluster/package")
.withPayload(payload)
.withMethod(SolrRequest.METHOD.POST)
.build().process(cluster.getSolrClient());
fileId = (String) getObjectByPath(Utils.fromJSONString(payload), true, "update/file/id");
assertEquals(getObjectByPath(Utils.fromJSONString(payload), true, "update/file/id"),
getObjectByPath(new ClusterProperties(cluster.getZkClient()).getClusterProperties(),
true, "packages/cache_pkg/file/id"));
params = new MapSolrParams((Map) Utils.makeMap("collection", COLLECTION_NAME,
WT, JAVABIN,
"meta", "true"));
assertResponseValues(10,
cluster.getSolrClient(),
new GenericSolrRequest(SolrRequest.METHOD.GET, "/config/query/documentCache", params),
Utils.makeMap(
"/config/query/documentCache/_packageinfo_/file/id", fileId
));
req = new UpdateRequest();
req.add("id", "2", "desc_s", "document 1")
.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true)
.setWaitSearcher(true);
cluster.getSolrClient().request(req, COLLECTION_NAME);
solrQuery = new SolrQuery("q", "id:2", "collection", COLLECTION_NAME);
NavigableObject result = assertResponseValues(10,
cluster.getSolrClient(),
new QueryRequest(solrQuery),
Utils.makeMap("response[0]/my_synthetic_fld_s", "version_2"));
} finally {
cluster.deleteAllCollections();
cluster.shutdown();
}
}
public void testFileStoreManagement() throws Exception {
MiniSolrCloudCluster cluster = configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.addConfig("conf", configset("cloud-minimal"))
.configure();
try {
postFile(cluster.getSolrClient(), getFileContent("runtimecode/runtimelibs.jar.bin"),
"e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc", "runtimelibs.jar" );
assertResponseValues(10,
cluster.getSolrClient(),
new V2Request.Builder("/node/filestore/package")
.withMethod(SolrRequest.METHOD.GET)
.build(),
Utils.makeMap("/files/package/e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar", NOT_NULL_PREDICATE )
);
Map expected = Utils.makeMap("/files/package/e1f9e23988c19619402f1040c9251556dcd6e02b9d3e3b966a129ea1be5c70fc-runtimelibs.jar",
(Predicate<?>) o -> o != null);
for (JettySolrRunner jettySolrRunner : cluster.getJettySolrRunners()) {
String url = jettySolrRunner.getBaseUrl().toString().replace("/solr", "/api") + "/node/filestore/package?wt=javabin";
assertResponseValues(20, new Callable() {
@Override
public NavigableObject call() throws Exception {
try (HttpSolrClient solrClient = (HttpSolrClient) jettySolrRunner.newClient()) {
return (NavigableObject) Utils.executeGET(solrClient.getHttpClient(), url, JAVABINCONSUMER);
}
}
@Override
public String toString() {
return url;
}
}, expected);
}
} finally {
cluster.shutdown();
}
}
private void postFile(SolrClient client, ByteBuffer buffer, String sh256, String name) throws SolrServerException, IOException {
ModifiableSolrParams params = new ModifiableSolrParams();
if(name !=null) {
params.add("name", name);
}
V2Response rsp = new V2Request.Builder("/cluster/filestore/package")
.withMethod(SolrRequest.METHOD.POST)
.withPayload(buffer)
.forceV2(true)
.withParams(params)
.withMimeType("application/octet-stream")
.build()
.process(client);
assertEquals(sh256+"-"+name, rsp.getResponse().get(CommonParams.ID));
}
}