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:
Erick Erickson 2013-11-20 00:15:13 +00:00
parent 122171155f
commit fe2e612ebd
4 changed files with 103 additions and 11 deletions

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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