mirror of https://github.com/apache/lucene.git
SOLR-5459: Try loading a temporary core when saving a file in the admin UI config editing mode
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1543660 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
122171155f
commit
fe2e612ebd
|
@ -19,6 +19,7 @@ package org.apache.solr.handler.admin;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.solr.cloud.ZkController;
|
||||||
import org.apache.solr.cloud.ZkSolrResourceLoader;
|
import org.apache.solr.cloud.ZkSolrResourceLoader;
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
import org.apache.solr.common.SolrException.ErrorCode;
|
import org.apache.solr.common.SolrException.ErrorCode;
|
||||||
|
@ -30,6 +31,7 @@ import org.apache.solr.common.util.ContentStreamBase;
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
import org.apache.solr.common.util.SimpleOrderedMap;
|
import org.apache.solr.common.util.SimpleOrderedMap;
|
||||||
import org.apache.solr.core.CoreContainer;
|
import org.apache.solr.core.CoreContainer;
|
||||||
|
import org.apache.solr.core.CoreDescriptor;
|
||||||
import org.apache.solr.core.SolrCore;
|
import org.apache.solr.core.SolrCore;
|
||||||
import org.apache.solr.core.SolrResourceLoader;
|
import org.apache.solr.core.SolrResourceLoader;
|
||||||
import org.apache.solr.handler.RequestHandlerBase;
|
import org.apache.solr.handler.RequestHandlerBase;
|
||||||
|
@ -128,7 +130,12 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
public static final String USE_CONTENT_TYPE = "contentType";
|
public static final String USE_CONTENT_TYPE = "contentType";
|
||||||
|
|
||||||
protected Set<String> hiddenFiles;
|
protected Set<String> hiddenFiles;
|
||||||
|
|
||||||
|
private final static String OP_PARAM = "op";
|
||||||
|
private final static String OP_WRITE = "write";
|
||||||
|
private final static String OP_TEST = "test";
|
||||||
|
|
||||||
|
|
||||||
public ShowFileRequestHandler()
|
public ShowFileRequestHandler()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -160,14 +167,14 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
throws InterruptedException, KeeperException, IOException {
|
throws InterruptedException, KeeperException, IOException {
|
||||||
|
|
||||||
CoreContainer coreContainer = req.getCore().getCoreDescriptor().getCoreContainer();
|
CoreContainer coreContainer = req.getCore().getCoreDescriptor().getCoreContainer();
|
||||||
String op = req.getParams().get("op");
|
String op = req.getParams().get(OP_PARAM);
|
||||||
if (op == null) {
|
if (op == null) {
|
||||||
if (coreContainer.isZooKeeperAware()) {
|
if (coreContainer.isZooKeeperAware()) {
|
||||||
showFromZooKeeper(req, rsp, coreContainer);
|
showFromZooKeeper(req, rsp, coreContainer);
|
||||||
} else {
|
} else {
|
||||||
showFromFileSystem(req, rsp);
|
showFromFileSystem(req, rsp);
|
||||||
}
|
}
|
||||||
} else if ("write".equalsIgnoreCase(op)) {
|
} else if (OP_WRITE.equalsIgnoreCase(op) || OP_TEST.equalsIgnoreCase(op)) {
|
||||||
String fname = req.getParams().get("file", null);
|
String fname = req.getParams().get("file", null);
|
||||||
if (fname == null) {
|
if (fname == null) {
|
||||||
rsp.setException(new SolrException(ErrorCode.BAD_REQUEST, "No file name specified for write operation."));
|
rsp.setException(new SolrException(ErrorCode.BAD_REQUEST, "No file name specified for write operation."));
|
||||||
|
@ -175,7 +182,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
fname = fname.replace('\\', '/');
|
fname = fname.replace('\\', '/');
|
||||||
if (isHiddenFile(req, rsp, fname, true) == false) {
|
if (isHiddenFile(req, rsp, fname, true) == false) {
|
||||||
if (coreContainer.isZooKeeperAware()) {
|
if (coreContainer.isZooKeeperAware()) {
|
||||||
writeToZooKeeper(req, rsp, coreContainer);
|
writeToZooKeeper(req, rsp);
|
||||||
} else {
|
} else {
|
||||||
writeToFileSystem(req, rsp);
|
writeToFileSystem(req, rsp);
|
||||||
}
|
}
|
||||||
|
@ -264,8 +271,10 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
// file=velocity/error.vm or file=schema.xml
|
// file=velocity/error.vm or file=schema.xml
|
||||||
//
|
//
|
||||||
// Important: Assumes that the file already exists in ZK, so far we aren't creating files there.
|
// Important: Assumes that the file already exists in ZK, so far we aren't creating files there.
|
||||||
private void writeToZooKeeper(SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer coreContainer)
|
private void writeToZooKeeper(SolrQueryRequest req, SolrQueryResponse rsp)
|
||||||
throws KeeperException, InterruptedException, IOException {
|
throws KeeperException, InterruptedException, IOException {
|
||||||
|
|
||||||
|
CoreContainer coreContainer = req.getCore().getCoreDescriptor().getCoreContainer();
|
||||||
SolrZkClient zkClient = coreContainer.getZkController().getZkClient();
|
SolrZkClient zkClient = coreContainer.getZkController().getZkClient();
|
||||||
|
|
||||||
String adminFile = getAdminFileFromZooKeeper(req, rsp, zkClient);
|
String adminFile = getAdminFileFromZooKeeper(req, rsp, zkClient);
|
||||||
|
@ -276,6 +285,10 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
|
|
||||||
byte[] data = IOUtils.toByteArray(new InputStreamReader(stream.getStream(), "UTF-8"), "UTF-8");
|
byte[] data = IOUtils.toByteArray(new InputStreamReader(stream.getStream(), "UTF-8"), "UTF-8");
|
||||||
String fname = req.getParams().get("file", null);
|
String fname = req.getParams().get("file", null);
|
||||||
|
if (OP_TEST.equals(req.getParams().get(OP_PARAM))) {
|
||||||
|
testReloadSuccess(req, rsp, stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Persist the managed schema
|
// Persist the managed schema
|
||||||
try {
|
try {
|
||||||
// Assumption: the path exists
|
// Assumption: the path exists
|
||||||
|
@ -395,11 +408,89 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
rsp.setException(new SolrException( ErrorCode.BAD_REQUEST, "File " + fname + " is a directory."));
|
rsp.setException(new SolrException( ErrorCode.BAD_REQUEST, "File " + fname + " is a directory."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (OP_TEST.equals(req.getParams().get(OP_PARAM))) {
|
||||||
|
testReloadSuccess(req, rsp, stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FileUtils.copyInputStreamToFile(stream.getStream(), adminFile);
|
FileUtils.copyInputStreamToFile(stream.getStream(), adminFile);
|
||||||
log.info("Successfully saved file " + adminFile.getAbsolutePath() + " locally");
|
log.info("Successfully saved file " + adminFile.getAbsolutePath() + " locally");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean testReloadSuccess(SolrQueryRequest req, SolrQueryResponse rsp, ContentStream stream) {
|
||||||
|
// Try writing the config to a temporary core and reloading to see that we don't allow people to shoot themselves
|
||||||
|
// in the foot.
|
||||||
|
File home = null;
|
||||||
|
try {
|
||||||
|
home = new File(FileUtils.getTempDirectory(), "SOLR_5459"); // Unlikely to name a core or collection this!
|
||||||
|
FileUtils.writeStringToFile(new File(home, "solr.xml"), "<solr></solr>"); // Use auto-discovery
|
||||||
|
File coll = new File(home, "SOLR_5459");
|
||||||
|
|
||||||
|
SolrCore core = req.getCore();
|
||||||
|
CoreDescriptor desc = core.getCoreDescriptor();
|
||||||
|
CoreContainer coreContainer = desc.getCoreContainer();
|
||||||
|
|
||||||
|
if (coreContainer.isZooKeeperAware()) {
|
||||||
|
try {
|
||||||
|
String confPath = ((ZkSolrResourceLoader) core.getResourceLoader()).getCollectionZkPath();
|
||||||
|
|
||||||
|
ZkController.downloadConfigDir(coreContainer.getZkController().getZkClient(), confPath,
|
||||||
|
new File(coll, "conf"));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Error when attempting to download conf from ZooKeeper: " + ex.getMessage());
|
||||||
|
rsp.setException(new SolrException(ErrorCode.BAD_REQUEST,
|
||||||
|
"Error when attempting to download conf from ZooKeeper" + ex.getMessage()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FileUtils.copyDirectory(new File(desc.getInstanceDir(), "conf"),
|
||||||
|
new File(coll, "conf"));
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils.writeStringToFile(new File(coll, "core.properties"), "name=SOLR_5459");
|
||||||
|
|
||||||
|
FileUtils.copyInputStreamToFile(stream.getStream(),
|
||||||
|
new File(new File(coll, "conf"), req.getParams().get("file", null)));
|
||||||
|
|
||||||
|
return tryReloading(rsp, home);
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
log.warn("Caught IO exception when trying to verify configs. " + ex.getMessage());
|
||||||
|
rsp.setException(new SolrException(ErrorCode.SERVER_ERROR,
|
||||||
|
"Caught IO exception when trying to verify configs. " + ex.getMessage()));
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (home != null) {
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(home);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Caught IO exception trying to delete temporary directory " + home + e.getMessage());
|
||||||
|
return true; // Don't fail for this reason!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryReloading(SolrQueryResponse rsp, File home) {
|
||||||
|
CoreContainer cc = null;
|
||||||
|
try {
|
||||||
|
cc = CoreContainer.createAndLoad(home.getAbsolutePath(), new File(home, "solr.xml"));
|
||||||
|
if (cc.getCoreInitFailures().size() > 0) {
|
||||||
|
for (Exception ex : cc.getCoreInitFailures().values()) {
|
||||||
|
log.error("Error when attempting to reload core: " + ex.getMessage());
|
||||||
|
rsp.setException(new SolrException( ErrorCode.BAD_REQUEST,
|
||||||
|
"Error when attempting to reload core after writing config" + ex.getMessage()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
if (cc != null) {
|
||||||
|
cc.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the file indicated by the "file=XXX" parameter or the root of the conf directory on the local
|
// Find the file indicated by the "file=XXX" parameter or the root of the conf directory on the local
|
||||||
// file system. Respects all the "interesting" stuff around what the resource loader does to find files.
|
// file system. Respects all the "interesting" stuff around what the resource loader does to find files.
|
||||||
private File getAdminFileFromFileSystem(SolrQueryRequest req, SolrQueryResponse rsp) {
|
private File getAdminFileFromFileSystem(SolrQueryRequest req, SolrQueryResponse rsp) {
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class TestModifyConfFiles extends AbstractFullDistribZkTestBase {
|
||||||
|
|
||||||
params.remove("file");
|
params.remove("file");
|
||||||
params.set("stream.body", "Testing rewrite of schema.xml file.");
|
params.set("stream.body", "Testing rewrite of schema.xml file.");
|
||||||
|
params.set("op", "test");
|
||||||
request = new QueryRequest(params);
|
request = new QueryRequest(params);
|
||||||
request.setPath("/admin/file");
|
request.setPath("/admin/file");
|
||||||
try {
|
try {
|
||||||
|
@ -57,6 +58,7 @@ public class TestModifyConfFiles extends AbstractFullDistribZkTestBase {
|
||||||
assertEquals(e.getMessage(), "No file name specified for write operation.");
|
assertEquals(e.getMessage(), "No file name specified for write operation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params.set("op", "write");
|
||||||
params.set("file", "bogus.txt");
|
params.set("file", "bogus.txt");
|
||||||
request = new QueryRequest(params);
|
request = new QueryRequest(params);
|
||||||
request.setPath("/admin/file");
|
request.setPath("/admin/file");
|
||||||
|
@ -76,8 +78,6 @@ public class TestModifyConfFiles extends AbstractFullDistribZkTestBase {
|
||||||
SolrZkClient zkClient = cloudClient.getZkStateReader().getZkClient();
|
SolrZkClient zkClient = cloudClient.getZkStateReader().getZkClient();
|
||||||
String contents = new String(zkClient.getData("/configs/conf1/schema.xml", null, null, true), "UTF-8");
|
String contents = new String(zkClient.getData("/configs/conf1/schema.xml", null, null, true), "UTF-8");
|
||||||
|
|
||||||
//String schema = getFileContentFromZooKeeper("schema.xml");
|
|
||||||
|
|
||||||
assertTrue("Schema contents should have changed!", "Testing rewrite of schema.xml file.".equals(contents));
|
assertTrue("Schema contents should have changed!", "Testing rewrite of schema.xml file.".equals(contents));
|
||||||
|
|
||||||
// Create a velocity/whatever node. Put a bit of data in it. See if you can change it.
|
// Create a velocity/whatever node. Put a bit of data in it. See if you can change it.
|
||||||
|
|
|
@ -86,15 +86,16 @@ public class ModifyConfFileTest extends SolrTestCaseJ4 {
|
||||||
|
|
||||||
ArrayList<ContentStream> streams = new ArrayList<ContentStream>( 2 );
|
ArrayList<ContentStream> streams = new ArrayList<ContentStream>( 2 );
|
||||||
streams.add( new ContentStreamBase.StringStream( "Testing rewrite of schema.xml file." ) );
|
streams.add( new ContentStreamBase.StringStream( "Testing rewrite of schema.xml file." ) );
|
||||||
//streams.add( new ContentStreamBase.StringStream( "there" ) );
|
|
||||||
|
|
||||||
params = params("op", "write", "file", "schema.xml", "stream.body", "Testing rewrite of schema.xml file.");
|
params = params("op", "test", "file", "schema.xml", "stream.body", "Testing rewrite of schema.xml file.");
|
||||||
LocalSolrQueryRequest locReq = new LocalSolrQueryRequest(core, params);
|
LocalSolrQueryRequest locReq = new LocalSolrQueryRequest(core, params);
|
||||||
locReq.setContentStreams(streams);
|
locReq.setContentStreams(streams);
|
||||||
core.execute(handler, locReq, rsp);
|
core.execute(handler, locReq, rsp);
|
||||||
|
|
||||||
|
assertTrue("Schema should have caused core reload to fail!",
|
||||||
|
rsp.getException().getMessage().indexOf("SAXParseException") != -1);
|
||||||
String contents = FileUtils.readFileToString(new File(core.getCoreDescriptor().getInstanceDir(), "conf/schema.xml"));
|
String contents = FileUtils.readFileToString(new File(core.getCoreDescriptor().getInstanceDir(), "conf/schema.xml"));
|
||||||
assertEquals("Schema contents should have changed!", "Testing rewrite of schema.xml file.", contents);
|
assertFalse("Schema contents should NOT have changed!", contents.contains("Testing rewrite of schema.xml file."));
|
||||||
|
|
||||||
streams.add(new ContentStreamBase.StringStream("This should barf"));
|
streams.add(new ContentStreamBase.StringStream("This should barf"));
|
||||||
locReq = new LocalSolrQueryRequest(core, params);
|
locReq = new LocalSolrQueryRequest(core, params);
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
(int, float, boolean, string...)
|
(int, float, boolean, string...)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<fields>
|
<fields>
|
||||||
<!-- Valid attributes for fields:
|
<!-- Valid attributes for fields:
|
||||||
name: mandatory - the name for the field
|
name: mandatory - the name for the field
|
||||||
type: mandatory - the name of a field type from the
|
type: mandatory - the name of a field type from the
|
||||||
|
|
Loading…
Reference in New Issue