mirror of https://github.com/apache/lucene.git
SOLR-5455: add managed schema name to the files the admin UI cannot edit
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1542859 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
194238944c
commit
6e78f9a497
|
@ -36,6 +36,8 @@ import org.apache.solr.handler.RequestHandlerBase;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
import org.apache.solr.response.RawResponseWriter;
|
import org.apache.solr.response.RawResponseWriter;
|
||||||
import org.apache.solr.response.SolrQueryResponse;
|
import org.apache.solr.response.SolrQueryResponse;
|
||||||
|
import org.apache.solr.schema.IndexSchema;
|
||||||
|
import org.apache.solr.schema.ManagedIndexSchema;
|
||||||
import org.apache.zookeeper.KeeperException;
|
import org.apache.zookeeper.KeeperException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -170,13 +172,11 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
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."));
|
||||||
} else {
|
} else {
|
||||||
if (coreContainer.isZooKeeperAware()) {
|
fname = fname.replace('\\', '/');
|
||||||
if (isHiddenFile(rsp, fname) == false) {
|
if (isHiddenFile(req, rsp, fname, true) == false) {
|
||||||
|
if (coreContainer.isZooKeeperAware()) {
|
||||||
writeToZooKeeper(req, rsp, coreContainer);
|
writeToZooKeeper(req, rsp, coreContainer);
|
||||||
}
|
} else {
|
||||||
} else {
|
|
||||||
fname = fname.replace('\\', '/'); // normalize slashes. Should be done above too?
|
|
||||||
if (isHiddenFile(rsp, fname) == false) {
|
|
||||||
writeToFileSystem(req, rsp);
|
writeToFileSystem(req, rsp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,21 +186,38 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
|
|
||||||
// See if we should deal with this file
|
// See if we should deal with this file
|
||||||
|
|
||||||
private boolean isHiddenFile(SolrQueryResponse rsp, String fnameIn) {
|
private boolean isHiddenFile(SolrQueryRequest req, SolrQueryResponse rsp, String fnameIn, boolean reportError) {
|
||||||
String fname = fnameIn.toUpperCase(Locale.ROOT);
|
String fname = fnameIn.toUpperCase(Locale.ROOT);
|
||||||
if (hiddenFiles.contains(fname) || hiddenFiles.contains("*")) {
|
if (hiddenFiles.contains(fname) || hiddenFiles.contains("*")) {
|
||||||
log.error("Cannot access " + fname);
|
if (reportError) {
|
||||||
rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Can not access: " + fnameIn));
|
log.error("Cannot access " + fname);
|
||||||
|
rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Can not access: " + fnameIn));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is slightly off, a valid path is something like ./schema.xml. I don't think it's worth the effort though
|
// This is slightly off, a valid path is something like ./schema.xml. I don't think it's worth the effort though
|
||||||
// to fix it to handle all possibilities though.
|
// to fix it to handle all possibilities though.
|
||||||
if (fname.indexOf("..") >= 0 || fname.startsWith(".")) {
|
if (fname.indexOf("..") >= 0 || fname.startsWith(".")) {
|
||||||
log.error("Invalid path: " + fname);
|
if (reportError) {
|
||||||
rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Invalid path: " + fnameIn));
|
log.error("Invalid path: " + fname);
|
||||||
|
rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Invalid path: " + fnameIn));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that if the schema is managed, we don't allow editing. Don't really want to put
|
||||||
|
// this in the init since we're not entirely sure when the managed schema will get initialized relative to this
|
||||||
|
// handler.
|
||||||
|
SolrCore core = req.getCore();
|
||||||
|
IndexSchema schema = core.getLatestSchema();
|
||||||
|
if (schema instanceof ManagedIndexSchema) {
|
||||||
|
String managed = schema.getResourceName();
|
||||||
|
|
||||||
|
if (fname.equalsIgnoreCase(managed)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +240,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
adminFile = confPath;
|
adminFile = confPath;
|
||||||
} else {
|
} else {
|
||||||
fname = fname.replace('\\', '/'); // normalize slashes
|
fname = fname.replace('\\', '/'); // normalize slashes
|
||||||
if (isHiddenFile(rsp, fname)) {
|
if (isHiddenFile(req, rsp, fname, true)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (fname.startsWith("/")) { // Only files relative to conf are valid
|
if (fname.startsWith("/")) { // Only files relative to conf are valid
|
||||||
|
@ -291,7 +308,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
|
|
||||||
NamedList<SimpleOrderedMap<Object>> files = new SimpleOrderedMap<SimpleOrderedMap<Object>>();
|
NamedList<SimpleOrderedMap<Object>> files = new SimpleOrderedMap<SimpleOrderedMap<Object>>();
|
||||||
for (String f : children) {
|
for (String f : children) {
|
||||||
if (isHiddenFile(rsp, f)) {
|
if (isHiddenFile(req, rsp, f, false)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,13 +469,11 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
for( File f : adminFile.listFiles() ) {
|
for( File f : adminFile.listFiles() ) {
|
||||||
String path = f.getAbsolutePath().substring( basePath );
|
String path = f.getAbsolutePath().substring( basePath );
|
||||||
path = path.replace( '\\', '/' ); // normalize slashes
|
path = path.replace( '\\', '/' ); // normalize slashes
|
||||||
if( hiddenFiles.contains( path.toUpperCase(Locale.ROOT) ) ) {
|
|
||||||
continue; // don't show 'hidden' files
|
if (isHiddenFile(req, rsp, f.getName().replace('\\', '/'), false)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if( f.isHidden() || f.getName().startsWith( "." ) ) {
|
|
||||||
continue; // skip hidden system files...
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleOrderedMap<Object> fileInfo = new SimpleOrderedMap<Object>();
|
SimpleOrderedMap<Object> fileInfo = new SimpleOrderedMap<Object>();
|
||||||
files.add( path, fileInfo );
|
files.add( path, fileInfo );
|
||||||
if( f.isDirectory() ) {
|
if( f.isDirectory() ) {
|
||||||
|
@ -480,7 +495,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase
|
||||||
req.setParams(params);
|
req.setParams(params);
|
||||||
|
|
||||||
ContentStreamBase content = new ContentStreamBase.FileStream( adminFile );
|
ContentStreamBase content = new ContentStreamBase.FileStream( adminFile );
|
||||||
content.setContentType( req.getParams().get( USE_CONTENT_TYPE ) );
|
content.setContentType(req.getParams().get(USE_CONTENT_TYPE));
|
||||||
|
|
||||||
rsp.add(RawResponseWriter.CONTENT, content);
|
rsp.add(RawResponseWriter.CONTENT, content);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,23 +16,20 @@ package org.apache.solr.schema;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.solr.client.solrj.ResponseParser;
|
|
||||||
import org.apache.solr.client.solrj.SolrServer;
|
|
||||||
import org.apache.solr.client.solrj.SolrServerException;
|
import org.apache.solr.client.solrj.SolrServerException;
|
||||||
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
import org.apache.solr.client.solrj.impl.HttpSolrServer;
|
||||||
import org.apache.solr.client.solrj.request.QueryRequest;
|
import org.apache.solr.client.solrj.request.QueryRequest;
|
||||||
import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
|
import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
|
import org.apache.solr.common.cloud.SolrZkClient;
|
||||||
import org.apache.solr.common.params.CoreAdminParams;
|
import org.apache.solr.common.params.CoreAdminParams;
|
||||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
|
import org.apache.zookeeper.KeeperException;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.util.List;
|
||||||
import java.io.Reader;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class TestCloudManagedSchema extends AbstractFullDistribZkTestBase {
|
public class TestCloudManagedSchema extends AbstractFullDistribZkTestBase {
|
||||||
|
|
||||||
|
@ -69,72 +66,40 @@ public class TestCloudManagedSchema extends AbstractFullDistribZkTestBase {
|
||||||
String collectionSchema = (String)collectionStatus.get(CoreAdminParams.SCHEMA);
|
String collectionSchema = (String)collectionStatus.get(CoreAdminParams.SCHEMA);
|
||||||
// Make sure the upgrade to managed schema happened
|
// Make sure the upgrade to managed schema happened
|
||||||
assertEquals("Schema resource name differs from expected name", "managed-schema", collectionSchema);
|
assertEquals("Schema resource name differs from expected name", "managed-schema", collectionSchema);
|
||||||
|
|
||||||
// Make sure "DO NOT EDIT" is in the content of the managed schema
|
|
||||||
String fileContent = getFileContentFromZooKeeper("managed-schema");
|
|
||||||
assertTrue("Managed schema is missing", fileContent.contains("DO NOT EDIT"));
|
|
||||||
|
|
||||||
// Make sure the original non-managed schema is no longer in ZooKeeper
|
|
||||||
assertFileNotInZooKeeper("schema.xml");
|
|
||||||
|
|
||||||
// Make sure the renamed non-managed schema is present in ZooKeeper
|
SolrZkClient zkClient = new SolrZkClient(zkServer.getZkHost(), 30000);
|
||||||
fileContent = getFileContentFromZooKeeper("schema.xml.bak");
|
|
||||||
assertTrue("schema file doesn't contain '<schema'", fileContent.contains("<schema"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getFileContentFromZooKeeper(String fileName) throws IOException, SolrServerException {
|
|
||||||
QueryRequest request = new QueryRequest(params("file", fileName));
|
|
||||||
request.setPath("/admin/file");
|
|
||||||
RawResponseParser responseParser = new RawResponseParser();
|
|
||||||
request.setResponseParser(responseParser);
|
|
||||||
int which = r.nextInt(clients.size());
|
|
||||||
// For some reason, /admin/file requests work without stripping the /collection1 step from the URL
|
|
||||||
// (unlike /admin/cores requests - see above)
|
|
||||||
SolrServer client = clients.get(which);
|
|
||||||
client.request(request);
|
|
||||||
return responseParser.getRawFileContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RawResponseParser extends ResponseParser {
|
|
||||||
// Stolen from ShowFileRequestHandlerTest
|
|
||||||
private String rawFileContent = null;
|
|
||||||
String getRawFileContent() { return rawFileContent; }
|
|
||||||
@Override
|
|
||||||
public String getWriterType() {
|
|
||||||
return "mock";//unfortunately this gets put onto params wt=mock but it apparently has no effect
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public NamedList<Object> processResponse(InputStream body, String encoding) {
|
|
||||||
try {
|
|
||||||
rawFileContent = IOUtils.toString(body, encoding);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public NamedList<Object> processResponse(Reader reader) {
|
|
||||||
throw new UnsupportedOperationException("TODO unimplemented");//TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void assertFileNotInZooKeeper(String fileName) throws Exception {
|
|
||||||
// Stolen from AbstractBadConfigTestBase
|
|
||||||
String errString = "Not Found";
|
|
||||||
ignoreException(Pattern.quote(errString));
|
|
||||||
String rawContent = null;
|
|
||||||
try {
|
try {
|
||||||
rawContent = getFileContentFromZooKeeper(fileName);
|
// Make sure "DO NOT EDIT" is in the content of the managed schema
|
||||||
} catch (Exception e) {
|
String fileContent = getFileContentFromZooKeeper(zkClient, "/solr/configs/conf1/managed-schema");
|
||||||
// short circuit out if we found what we expected
|
assertTrue("Managed schema is missing", fileContent.contains("DO NOT EDIT"));
|
||||||
if (-1 != e.getMessage().indexOf(errString)) return;
|
|
||||||
// otherwise, rethrow it, possibly completely unrelated
|
// Make sure the original non-managed schema is no longer in ZooKeeper
|
||||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
|
assertFileNotInZooKeeper(zkClient, "/solr/configs/conf1", "schema.xml");
|
||||||
"Unexpected error, expected error matching: " + errString, e);
|
|
||||||
|
// Make sure the renamed non-managed schema is present in ZooKeeper
|
||||||
|
fileContent = getFileContentFromZooKeeper(zkClient, "/solr/configs/conf1/schema.xml.bak");
|
||||||
|
assertTrue("schema file doesn't contain '<schema'", fileContent.contains("<schema"));
|
||||||
} finally {
|
} finally {
|
||||||
resetExceptionIgnores();
|
if (zkClient != null) {
|
||||||
|
zkClient.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFileContentFromZooKeeper(SolrZkClient zkClient, String fileName)
|
||||||
|
throws IOException, SolrServerException, KeeperException, InterruptedException {
|
||||||
|
|
||||||
|
return (new String(zkClient.getData(fileName, null, null, true), "UTF-8"));
|
||||||
|
|
||||||
|
}
|
||||||
|
protected final void assertFileNotInZooKeeper(SolrZkClient zkClient, String parent, String fileName) throws Exception {
|
||||||
|
List<String> kids = zkClient.getChildren(parent, null, true);
|
||||||
|
for (String kid : kids) {
|
||||||
|
if (kid.equalsIgnoreCase(fileName)) {
|
||||||
|
String rawContent = new String(zkClient.getData(fileName, null, null, true), "UTF-8");
|
||||||
|
fail("File '" + fileName + "' was unexpectedly found in ZooKeeper. Content starts with '"
|
||||||
|
+ rawContent.substring(0, 100) + " [...]'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fail("File '" + fileName + "' was unexpectedly found in ZooKeeper. Content starts with '"
|
|
||||||
+ rawContent.substring(0, 100) + " [...]'");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue