mirror of https://github.com/apache/lucene.git
SOLR-6607 Managing requesthandlers through API
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1642141 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
99b935a881
commit
4fab579c2a
|
@ -217,6 +217,8 @@ New Features
|
|||
|
||||
* SOLR-6533: Support editing common solrconfig.xml values (Noble Paul)
|
||||
|
||||
* SOLR-6607: Managing requesthandlers throuh API (Noble Paul)
|
||||
|
||||
Bug Fixes
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -2235,18 +2235,20 @@ public final class ZkController {
|
|||
log.info("Watcher on {} is removed ", zkDir);
|
||||
return;
|
||||
}
|
||||
final Set<Runnable> listeners = confDirectoryListeners.get(zkDir);
|
||||
Set<Runnable> listeners = confDirectoryListeners.get(zkDir);
|
||||
if (listeners != null && !listeners.isEmpty()) {
|
||||
final Set<Runnable> listenersCopy = new HashSet<>(listeners);
|
||||
new Thread() {
|
||||
//run these in a separate thread because this can be long running
|
||||
public void run() {
|
||||
for (final Runnable listener : listeners)
|
||||
for (final Runnable listener : listenersCopy) {
|
||||
try {
|
||||
listener.run();
|
||||
} catch (Exception e) {
|
||||
log.warn("listener throws error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,17 +28,22 @@ import java.util.Map;
|
|||
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.cloud.ZkStateReader;
|
||||
import org.apache.solr.common.params.CoreAdminParams;
|
||||
import org.apache.solr.common.util.StrUtils;
|
||||
import org.apache.solr.request.SolrRequestHandler;
|
||||
import org.noggit.CharArr;
|
||||
import org.noggit.JSONParser;
|
||||
import org.noggit.JSONWriter;
|
||||
import org.noggit.ObjectBuilder;
|
||||
|
||||
import static org.apache.solr.common.params.CoreAdminParams.NAME;
|
||||
|
||||
public class ConfigOverlay implements MapSerializable{
|
||||
private final int znodeVersion ;
|
||||
private Map<String, Object> data;
|
||||
private Map<String,Object> props;
|
||||
private Map<String,Object> userProps;
|
||||
private Map<String, Map> reqHandlers;
|
||||
|
||||
public ConfigOverlay(Map<String,Object> jsonObj, int znodeVersion){
|
||||
if(jsonObj == null) jsonObj= Collections.EMPTY_MAP;
|
||||
|
@ -48,6 +53,8 @@ public class ConfigOverlay implements MapSerializable{
|
|||
if(props == null) props= Collections.EMPTY_MAP;
|
||||
userProps = (Map<String, Object>) data.get("userProps");
|
||||
if(userProps == null) userProps= Collections.EMPTY_MAP;
|
||||
reqHandlers = (Map<String, Map>) data.get(SolrRequestHandler.TYPE);
|
||||
if(reqHandlers == null) reqHandlers = new LinkedHashMap<>();
|
||||
|
||||
}
|
||||
public Object getXPathProperty(String xpath){
|
||||
|
@ -255,4 +262,28 @@ public class ConfigOverlay implements MapSerializable{
|
|||
result.putAll(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Map> getReqHandlers() {
|
||||
return Collections.unmodifiableMap(reqHandlers);
|
||||
}
|
||||
|
||||
public ConfigOverlay addReqHandler(Map<String, Object> info) {
|
||||
ConfigOverlay copy = copyOverLayWithReqHandler();
|
||||
copy.reqHandlers.put((String)info.get(NAME) , info);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private ConfigOverlay copyOverLayWithReqHandler() {
|
||||
LinkedHashMap<String, Object> newmap = new LinkedHashMap<>(data);
|
||||
ConfigOverlay copy = new ConfigOverlay(newmap, znodeVersion);
|
||||
newmap.put(SolrRequestHandler.TYPE, copy.reqHandlers = new LinkedHashMap<>(reqHandlers));
|
||||
return copy;
|
||||
}
|
||||
|
||||
public ConfigOverlay deleteHandler(String name) {
|
||||
ConfigOverlay copy = copyOverLayWithReqHandler();
|
||||
copy.reqHandlers.remove(name);
|
||||
return copy;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,12 @@ import org.w3c.dom.Node;
|
|||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static org.apache.solr.common.params.CoreAdminParams.NAME;
|
||||
import static org.apache.solr.schema.FieldType.CLASS_NAME;
|
||||
|
||||
/**
|
||||
* An Object which represents a Plugin of any type
|
||||
|
@ -38,8 +42,8 @@ public class PluginInfo implements MapSerializable{
|
|||
|
||||
public PluginInfo(String type, Map<String, String> attrs ,NamedList initArgs, List<PluginInfo> children) {
|
||||
this.type = type;
|
||||
this.name = attrs.get("name");
|
||||
this.className = attrs.get("class");
|
||||
this.name = attrs.get(NAME);
|
||||
this.className = attrs.get(CLASS_NAME);
|
||||
this.initArgs = initArgs;
|
||||
attributes = unmodifiableMap(attrs);
|
||||
this.children = children == null ? Collections.<PluginInfo>emptyList(): unmodifiableList(children);
|
||||
|
@ -49,14 +53,27 @@ public class PluginInfo implements MapSerializable{
|
|||
|
||||
public PluginInfo(Node node, String err, boolean requireName, boolean requireClass) {
|
||||
type = node.getNodeName();
|
||||
name = DOMUtil.getAttr(node, "name", requireName ? err : null);
|
||||
className = DOMUtil.getAttr(node, "class", requireClass ? err : null);
|
||||
name = DOMUtil.getAttr(node, NAME, requireName ? err : null);
|
||||
className = DOMUtil.getAttr(node, CLASS_NAME, requireClass ? err : null);
|
||||
initArgs = DOMUtil.childNodesToNamedList(node);
|
||||
attributes = unmodifiableMap(DOMUtil.toMap(node.getAttributes()));
|
||||
children = loadSubPlugins(node);
|
||||
isFromSolrConfig = true;
|
||||
}
|
||||
|
||||
public PluginInfo(String type, Map<String,Object> map) {
|
||||
LinkedHashMap m = new LinkedHashMap<>(map);
|
||||
NamedList nl = new NamedList();
|
||||
for (String s : asList(DEFAULTS, APPENDS, INVARIANTS)) if (m.get(s) != null) nl.add(s, map.remove(s));
|
||||
this.type = type;
|
||||
this.name = (String) m.get(NAME);
|
||||
this.className = (String) m.get(CLASS_NAME);
|
||||
this.initArgs = nl;
|
||||
attributes = unmodifiableMap(m);
|
||||
this.children = Collections.<PluginInfo>emptyList();
|
||||
isFromSolrConfig = true;
|
||||
}
|
||||
|
||||
private List<PluginInfo> loadSubPlugins(Node node) {
|
||||
List<PluginInfo> children = new ArrayList<>();
|
||||
//if there is another sub tag with a non namedlist tag that has to be another plugin
|
||||
|
@ -131,7 +148,7 @@ public class PluginInfo implements MapSerializable{
|
|||
public static final PluginInfo EMPTY_INFO = new PluginInfo("",Collections.<String,String>emptyMap(), new NamedList(),Collections.<PluginInfo>emptyList());
|
||||
|
||||
private static final HashSet<String> NL_TAGS = new HashSet<>
|
||||
(Arrays.asList("lst", "arr",
|
||||
(asList("lst", "arr",
|
||||
"bool",
|
||||
"str",
|
||||
"int", "long",
|
||||
|
|
|
@ -143,12 +143,15 @@ public final class RequestHandlers {
|
|||
List<PluginInfo> implicits = PluginsRegistry.getHandlers(core);
|
||||
// use link map so we iterate in the same order
|
||||
Map<PluginInfo,SolrRequestHandler> handlers = new LinkedHashMap<>();
|
||||
Map<String, PluginInfo> implicitInfoMap= new HashMap<>();
|
||||
Map<String, PluginInfo> infoMap= new LinkedHashMap<>();
|
||||
//deduping implicit and explicit requesthandlers
|
||||
for (PluginInfo info : implicits) implicitInfoMap.put(info.name,info);
|
||||
for (PluginInfo info : implicits) infoMap.put(info.name,info);
|
||||
for (PluginInfo info : config.getPluginInfos(SolrRequestHandler.class.getName()))
|
||||
if(implicitInfoMap.containsKey(info.name)) implicitInfoMap.remove(info.name);
|
||||
ArrayList<PluginInfo> infos = new ArrayList<>(implicitInfoMap.values());
|
||||
if(infoMap.containsKey(info.name)) infoMap.remove(info.name);
|
||||
for (Map.Entry e : core.getSolrConfig().getOverlay().getReqHandlers().entrySet())
|
||||
infoMap.put((String)e.getKey(), new PluginInfo(SolrRequestHandler.TYPE, (Map)e.getValue()));
|
||||
|
||||
ArrayList<PluginInfo> infos = new ArrayList<>(infoMap.values());
|
||||
infos.addAll(config.getPluginInfos(SolrRequestHandler.class.getName()));
|
||||
for (PluginInfo info : infos) {
|
||||
try {
|
||||
|
|
|
@ -334,13 +334,14 @@ public class SolrConfig extends Config implements MapSerializable{
|
|||
in = loader.openResource(ConfigOverlay.RESOURCE_NAME);
|
||||
} catch (IOException e) {
|
||||
//no problem no overlay.json file
|
||||
return new ConfigOverlay(Collections.EMPTY_MAP,0);
|
||||
return new ConfigOverlay(Collections.EMPTY_MAP,-1);
|
||||
}
|
||||
|
||||
try {
|
||||
int version = 0; //will be always 0 for file based resourceloader
|
||||
if (in instanceof ZkSolrResourceLoader.ZkByteArrayInputStream) {
|
||||
version = ((ZkSolrResourceLoader.ZkByteArrayInputStream) in).getStat().getVersion();
|
||||
log.info("config overlay loaded . version : {} ", version);
|
||||
}
|
||||
Map m = (Map) ObjectBuilder.getVal(new JSONParser(new InputStreamReader(in, StandardCharsets.UTF_8)));
|
||||
return new ConfigOverlay(m,version);
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.apache.solr.request.LocalSolrQueryRequest;
|
|||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.request.SolrRequestHandler;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.schema.FieldType;
|
||||
import org.apache.solr.schema.SchemaManager;
|
||||
import org.apache.solr.util.CommandOperation;
|
||||
import org.apache.solr.util.plugin.SolrCoreAware;
|
||||
|
@ -63,8 +64,10 @@ import static java.text.MessageFormat.format;
|
|||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.apache.solr.common.cloud.ZkNodeProps.makeMap;
|
||||
import static org.apache.solr.common.params.CoreAdminParams.NAME;
|
||||
import static org.apache.solr.core.ConfigOverlay.NOT_EDITABLE;
|
||||
import static org.apache.solr.core.PluginInfo.DEFAULTS;
|
||||
import static org.apache.solr.schema.FieldType.CLASS_NAME;
|
||||
|
||||
public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAware{
|
||||
public static final Logger log = LoggerFactory.getLogger(SolrConfigHandler.class);
|
||||
|
@ -106,7 +109,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("config update_listener called");
|
||||
log.info("config update listener called for core {}", coreName);
|
||||
SolrZkClient zkClient = cc.getZkController().getZkClient();
|
||||
int solrConfigversion,overlayVersion;
|
||||
try (SolrCore core = cc.getCore(coreName)) {
|
||||
|
@ -117,7 +120,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
|
||||
if (checkStale(zkClient, overlayPath, solrConfigversion) ||
|
||||
checkStale(zkClient, solrConfigPath, overlayVersion)) {
|
||||
log.info("core reload");
|
||||
log.info("core reload {}",coreName);
|
||||
cc.reload(coreName);
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +131,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
try {
|
||||
Stat stat = zkClient.exists(zkPath, null, true);
|
||||
if(stat == null){
|
||||
if(currentVersion>0) return true;
|
||||
if(currentVersion > -1) return true;
|
||||
return false;
|
||||
}
|
||||
if (stat.getVersion() > currentVersion) {
|
||||
|
@ -198,7 +201,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
for (CommandOperation op : ops) opsCopy.add(op.getCopy());
|
||||
try {
|
||||
handleCommands(opsCopy, overlay);
|
||||
break;
|
||||
break;//succeeded . so no need to go over the loop again
|
||||
} catch (ZkController.ResourceModifiedInZkException e) {
|
||||
//retry
|
||||
log.info("Race condition, the node is modified in ZK by someone else " +e.getMessage());
|
||||
|
@ -226,6 +229,13 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
case UNSET_USER_PROPERTY:
|
||||
overlay = applyUnsetUserProp(op, overlay);
|
||||
break;
|
||||
case UPDATE_REQHANDLER:
|
||||
case CREATE_REQHANDLER:
|
||||
overlay = applyRequestHandler(op, overlay);
|
||||
break;
|
||||
case DELETE_REQHANDLER:
|
||||
overlay = applyDeleteHandler(op,overlay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
List errs = CommandOperation.captureErrors(ops);
|
||||
|
@ -244,6 +254,50 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
req.getCore().getCoreDescriptor().getCoreContainer().reload(req.getCore().getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ConfigOverlay applyDeleteHandler(CommandOperation op, ConfigOverlay overlay) {
|
||||
String name = op.getStr(CommandOperation.ROOT_OBJ);
|
||||
if(op.hasError()) return overlay;
|
||||
if(overlay.getReqHandlers().containsKey(name)){
|
||||
return overlay.deleteHandler(name);
|
||||
} else {
|
||||
op.addError(MessageFormat.format("NO such requestHandler ''{0}'' ",name));
|
||||
return overlay;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ConfigOverlay applyRequestHandler(CommandOperation op, ConfigOverlay overlay) {
|
||||
String name=op.getStr(NAME);
|
||||
op.getStr(CLASS_NAME);
|
||||
op.getMap(PluginInfo.DEFAULTS, null);
|
||||
op.getMap(PluginInfo.INVARIANTS,null);
|
||||
op.getMap(PluginInfo.APPENDS,null);
|
||||
if(op.hasError()) return overlay;
|
||||
|
||||
|
||||
if(CREATE_REQHANDLER.equals(op.name)) {
|
||||
if (overlay.getReqHandlers().containsKey(name)) {
|
||||
op.addError(MessageFormat.format(" ''{0}'' already exists . Do an ''{1}'' , if you want to change it ", name, UPDATE_REQHANDLER));
|
||||
return overlay;
|
||||
} else {
|
||||
return overlay.addReqHandler(op.getDataMap());
|
||||
}
|
||||
} else if(UPDATE_REQHANDLER.equals(op.name)){
|
||||
if (!overlay.getReqHandlers().containsKey(name)) {
|
||||
op.addError(MessageFormat.format(" ''{0}'' does not exist . Do an ''{1}'' , if you want to create it ", name, CREATE_REQHANDLER));
|
||||
return overlay;
|
||||
} else {
|
||||
return overlay.addReqHandler(op.getDataMap());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return overlay;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private ConfigOverlay applySetUserProp(CommandOperation op, ConfigOverlay overlay) {
|
||||
|
@ -351,7 +405,8 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
|
|||
public static final String UNSET_PROPERTY = "unset-property";
|
||||
public static final String SET_USER_PROPERTY = "set-user-property";
|
||||
public static final String UNSET_USER_PROPERTY = "unset-user-property";
|
||||
|
||||
|
||||
public static final String CREATE_REQHANDLER = "create-requesthandler";
|
||||
public static final String DELETE_REQHANDLER = "delete-requesthandler";
|
||||
public static final String UPDATE_REQHANDLER = "update-requesthandler";
|
||||
|
||||
}
|
||||
|
|
|
@ -214,4 +214,15 @@ public class CommandOperation {
|
|||
return new CommandOperation(name,commandData);
|
||||
}
|
||||
|
||||
public Map getMap(String key, Map def) {
|
||||
Object o =getMapVal(key);
|
||||
if(o==null) return def;
|
||||
if ( !(o instanceof Map)) {
|
||||
addError(MessageFormat.format("''{0}'' must be a map", key));
|
||||
return def;
|
||||
} else {
|
||||
return (Map) o;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,25 @@ package org.apache.solr.core;
|
|||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.client.solrj.impl.CloudSolrServer;
|
||||
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
||||
import org.apache.solr.handler.TestSolrConfigHandlerConcurrent;
|
||||
import org.apache.solr.util.RestTestBase;
|
||||
import org.apache.solr.util.RestTestHarness;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
@ -77,13 +87,11 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
|
||||
|
||||
public void testProperty() throws Exception{
|
||||
RestTestHarness harness = restTestHarness;
|
||||
String payload= "{\n" +
|
||||
" 'set-property' : { 'updateHandler.autoCommit.maxDocs':100, 'updateHandler.autoCommit.maxTime':10 } \n" +
|
||||
" }";
|
||||
RestTestHarness harness = restTestHarness;
|
||||
String response = harness.post("/config?wt=json", SolrTestCaseJ4.json(payload));
|
||||
Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||
assertNull(response, map.get("errors"));
|
||||
runConfigCommand( harness,"/config?wt=json", payload);
|
||||
|
||||
Map m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
|
||||
Map props = (Map) m.get("props");
|
||||
|
@ -99,9 +107,7 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
payload= "{\n" +
|
||||
" 'unset-property' : 'updateHandler.autoCommit.maxDocs'} \n" +
|
||||
" }";
|
||||
response = harness.post("/config?wt=json", SolrTestCaseJ4.json(payload));
|
||||
map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||
assertNull(response, map.get("errors"));
|
||||
runConfigCommand(harness, "/config?wt=json", payload);
|
||||
|
||||
m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
|
||||
props = (Map) m.get("props");
|
||||
|
@ -111,14 +117,12 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
}
|
||||
|
||||
public void testUserProp() throws Exception{
|
||||
RestTestHarness harness = restTestHarness;
|
||||
String payload= "{\n" +
|
||||
" 'set-user-property' : { 'my.custom.variable.a':'MODIFIEDA'," +
|
||||
" 'my.custom.variable.b':'MODIFIEDB' } \n" +
|
||||
" }";
|
||||
RestTestHarness harness = restTestHarness;
|
||||
String response = harness.post("/config?wt=json", SolrTestCaseJ4.json(payload));
|
||||
Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||
assertNull(response, map.get("errors"));
|
||||
runConfigCommand(harness,"/config?wt=json", payload);
|
||||
|
||||
Map m = (Map) getRespMap("/config/overlay?wt=json" ,harness).get("overlay");
|
||||
Map props = (Map) m.get("userProps");
|
||||
|
@ -132,14 +136,93 @@ public class TestSolrConfigHandler extends RestTestBase {
|
|||
assertEquals("MODIFIEDA", m.get("a"));
|
||||
assertEquals("MODIFIEDB", m.get("b"));
|
||||
|
||||
}
|
||||
|
||||
public void testReqHandlerAPIs() throws Exception {
|
||||
reqhandlertests(restTestHarness, null,null);
|
||||
}
|
||||
|
||||
private static void runConfigCommand(RestTestHarness harness, String uri, String payload) throws IOException {
|
||||
String response = harness.post(uri, SolrTestCaseJ4.json(payload));
|
||||
Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||
assertNull(response, map.get("errors"));
|
||||
}
|
||||
|
||||
|
||||
public static void reqhandlertests(RestTestHarness writeHarness,String testServerBaseUrl, CloudSolrServer cloudSolrServer) throws Exception {
|
||||
String payload = "{\n" +
|
||||
"'create-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy'}\n" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness,"/config?wt=json", payload);
|
||||
|
||||
boolean success = false;
|
||||
long startTime = System.nanoTime();
|
||||
long maxTimeoutSeconds = 10;
|
||||
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
String uri = "/config/overlay?wt=json";
|
||||
Map m = testServerBaseUrl ==null? getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
|
||||
if("lazy".equals( ConfigOverlay.getObjectByPath(m, true, Arrays.asList("overlay", "requestHandler", "/x","startup")))) {
|
||||
Map map = getRespMap("/x?wt=json",writeHarness);
|
||||
if(map.containsKey("params")) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Thread.sleep(100);
|
||||
|
||||
}
|
||||
|
||||
assertTrue( "Could not register requestHandler ", success);
|
||||
|
||||
payload = "{\n" +
|
||||
"'update-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy' , 'a':'b'}\n" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness,"/config?wt=json", payload);
|
||||
|
||||
success = false;
|
||||
startTime = System.nanoTime();
|
||||
maxTimeoutSeconds = 10;
|
||||
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
String uri = "/config/overlay?wt=json";
|
||||
Map m = testServerBaseUrl ==null? getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
|
||||
if("b".equals( ConfigOverlay.getObjectByPath(m, true, Arrays.asList("overlay", "requestHandler", "/x","a")))) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
|
||||
}
|
||||
|
||||
assertTrue( "Could not update requestHandler ", success);
|
||||
|
||||
payload = "{\n" +
|
||||
"'delete-requesthandler' : '/x'" +
|
||||
"}";
|
||||
runConfigCommand(writeHarness,"/config?wt=json", payload);
|
||||
success = false;
|
||||
startTime = System.nanoTime();
|
||||
maxTimeoutSeconds = 10;
|
||||
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
String uri = "/config/overlay?wt=json";
|
||||
Map m = testServerBaseUrl ==null? getRespMap(uri,writeHarness) : TestSolrConfigHandlerConcurrent.getAsMap(testServerBaseUrl+uri ,cloudSolrServer) ;
|
||||
if(null == ConfigOverlay.getObjectByPath(m, true, Arrays.asList("overlay", "requestHandler", "/x","a"))) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
Thread.sleep(100);
|
||||
|
||||
}
|
||||
assertTrue( "Could not delete requestHandler ", success);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static Map getRespMap(String path, RestTestHarness restHarness) throws Exception {
|
||||
String response = restHarness.query(path);
|
||||
try {
|
||||
return (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||
} catch (JSONParser.ParseException e) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package org.apache.solr.handler;
|
||||
|
||||
/*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.solr.client.solrj.SolrServer;
|
||||
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
||||
import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
|
||||
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.core.TestSolrConfigHandler;
|
||||
import org.apache.solr.util.RESTfulServerProvider;
|
||||
import org.apache.solr.util.RestTestHarness;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TestSolrConfigHandlerCloud extends AbstractFullDistribZkTestBase {
|
||||
static final Logger log = LoggerFactory.getLogger(TestSolrConfigHandlerCloud.class);
|
||||
private List<RestTestHarness> restTestHarnesses = new ArrayList<>();
|
||||
|
||||
private void setupHarnesses() {
|
||||
for (final SolrServer client : clients) {
|
||||
RestTestHarness harness = new RestTestHarness(new RESTfulServerProvider() {
|
||||
@Override
|
||||
public String getBaseURL() {
|
||||
return ((HttpSolrServer)client).getBaseURL();
|
||||
}
|
||||
});
|
||||
restTestHarnesses.add(harness);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doTest() throws Exception {
|
||||
setupHarnesses();
|
||||
testReqHandlerAPIs();
|
||||
|
||||
}
|
||||
|
||||
private void testReqHandlerAPIs() throws Exception {
|
||||
DocCollection coll = cloudClient.getZkStateReader().getClusterState().getCollection("collection1");
|
||||
List<String> urls = new ArrayList<>();
|
||||
for (Slice slice : coll.getSlices()) {
|
||||
for (Replica replica : slice.getReplicas())
|
||||
urls.add(""+replica.get(ZkStateReader.BASE_URL_PROP) + "/"+replica.get(ZkStateReader.CORE_NAME_PROP));
|
||||
}
|
||||
|
||||
RestTestHarness writeHarness = restTestHarnesses.get(random().nextInt(restTestHarnesses.size()));
|
||||
String testServerBaseUrl = urls.get(random().nextInt(urls.size()));
|
||||
TestSolrConfigHandler.reqhandlertests(writeHarness, testServerBaseUrl , cloudClient);
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ import org.apache.http.client.methods.HttpGet;
|
|||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.client.solrj.SolrServer;
|
||||
import org.apache.solr.client.solrj.impl.CloudSolrServer;
|
||||
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
||||
import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
|
||||
import org.apache.solr.common.cloud.DocCollection;
|
||||
|
@ -164,7 +165,7 @@ public class TestSolrConfigHandlerConcurrent extends AbstractFullDistribZkTestBa
|
|||
while ( TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS) < maxTimeoutSeconds) {
|
||||
Thread.sleep(100);
|
||||
errmessages.clear();
|
||||
Map respMap = getAsMap(url+"/config/overlay?wt=json");
|
||||
Map respMap = getAsMap(url+"/config/overlay?wt=json", cloudClient);
|
||||
Map m = (Map) respMap.get("overlay");
|
||||
if(m!= null) m = (Map) m.get("props");
|
||||
if(m == null) {
|
||||
|
@ -191,7 +192,7 @@ public class TestSolrConfigHandlerConcurrent extends AbstractFullDistribZkTestBa
|
|||
|
||||
}
|
||||
|
||||
private Map getAsMap(String uri) throws Exception {
|
||||
public static Map getAsMap(String uri, CloudSolrServer cloudClient) throws Exception {
|
||||
HttpGet get = new HttpGet(uri) ;
|
||||
HttpEntity entity = null;
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue