Add ElasticSmokeTest
Resolves: https://jira.duraspace.org/browse/VIVO-1600
This commit is contained in:
parent
6c5fb9beb8
commit
ab2b41260e
5 changed files with 193 additions and 16 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -17,6 +17,7 @@ utilities/sdb_to_tdb/.work
|
||||||
*~
|
*~
|
||||||
|
|
||||||
**/overlays
|
**/overlays
|
||||||
|
*~
|
||||||
|
|
||||||
# Eclipse artifacts
|
# Eclipse artifacts
|
||||||
**/.settings
|
**/.settings
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* $This file is distributed under the terms of the license in LICENSE$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.servlet.setup;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.http.HttpClientFactory;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we can't connect to ElasticSearch, add a Warning item to the StartupStatus.
|
||||||
|
*/
|
||||||
|
public class ElasticSmokeTest {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(ElasticSmokeTest.class);
|
||||||
|
|
||||||
|
private final ServletContextListener listener;
|
||||||
|
|
||||||
|
public ElasticSmokeTest(ServletContextListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doTest(ServletContextEvent sce) {
|
||||||
|
final StartupStatus ss = StartupStatus.getBean(sce.getServletContext());
|
||||||
|
|
||||||
|
String elasticUrlString = ConfigurationProperties.getBean(sce).getProperty("vitro.local.elastic.url", "");
|
||||||
|
if (elasticUrlString.isEmpty()) {
|
||||||
|
ss.fatal(listener, "Can't connect to ElasticSearch engine. "
|
||||||
|
+ "runtime.properties must contain a value for "
|
||||||
|
+ "vitro.local.elastic.url");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
URL elasticUrl = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
elasticUrl = new URL(elasticUrlString);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
ss.fatal(listener, "Can't connect to ElasticSearch engine. "
|
||||||
|
+ "The value for vitro.local.elastic.url "
|
||||||
|
+ "in runtime.properties is not a valid URL: '"
|
||||||
|
+ elasticUrlString + "'", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ss.info(listener, "Starting ElasticSearch test.");
|
||||||
|
|
||||||
|
checkConnection(elasticUrl, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkConnection(URL elasticUrl, StartupStatus ss) {
|
||||||
|
try {
|
||||||
|
new ElasticPinger(elasticUrl).ping();
|
||||||
|
reportGoodPing(ss);
|
||||||
|
} catch (ElasticProblemException e) {
|
||||||
|
reportPingProblem(ss, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportGoodPing(StartupStatus ss) {
|
||||||
|
ss.info(listener, "The ElasticSearch server responded to a 'ping'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportPingProblem(StartupStatus ss, ElasticProblemException e) {
|
||||||
|
ss.warning(listener, "The ElasticSearch engine did not respond to a 'ping' request", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue a "ping" to ElasticSearch. If we get here, we've already established
|
||||||
|
* contact, so any error is a fatal one.
|
||||||
|
*/
|
||||||
|
private static class ElasticPinger {
|
||||||
|
private final URL elasticUrl;
|
||||||
|
private final HttpClient httpClient = HttpClientFactory.getHttpClient();
|
||||||
|
|
||||||
|
public ElasticPinger(URL elasticUrl) {
|
||||||
|
this.elasticUrl = elasticUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ping() throws ElasticProblemException {
|
||||||
|
try {
|
||||||
|
HttpGet method = new HttpGet(elasticUrl.toExternalForm());
|
||||||
|
log.debug("Trying to ping ElasticSearch");
|
||||||
|
HttpResponse response = httpClient.execute(method);
|
||||||
|
try {
|
||||||
|
log.debug("Finished pinging ElasticSearch");
|
||||||
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
|
if (statusCode != HttpStatus.SC_OK) {
|
||||||
|
throw new ElasticProblemException(statusCode);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
EntityUtils.consume(response.getEntity());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ElasticProblemException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ElasticProblemException extends Exception {
|
||||||
|
private final int statusCode;
|
||||||
|
|
||||||
|
ElasticProblemException(int statusCode) {
|
||||||
|
super("HTTP status code = " + statusCode);
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElasticProblemException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.statusCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getStatusCode() {
|
||||||
|
return this.statusCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* $This file is distributed under the terms of the license in LICENSE$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.servlet.setup;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start up the appropriate search engine smoke test based on the configured URL property.
|
||||||
|
*/
|
||||||
|
public class SearchEngineSmokeTest implements ServletContextListener {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(SearchEngineSmokeTest.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
|
final StartupStatus ss = StartupStatus.getBean(sce.getServletContext());
|
||||||
|
|
||||||
|
String solrUrlString = ConfigurationProperties.getBean(sce).getProperty("vitro.local.solr.url", "");
|
||||||
|
String elasticUrlString = ConfigurationProperties.getBean(sce).getProperty("vitro.local.elastic.url", "");
|
||||||
|
|
||||||
|
if (!solrUrlString.isEmpty() && !elasticUrlString.isEmpty()) {
|
||||||
|
ss.fatal(this, "More than one search engine is configured: " + solrUrlString + ", and " + elasticUrlString);
|
||||||
|
|
||||||
|
} else if (solrUrlString.isEmpty() && elasticUrlString.isEmpty()) {
|
||||||
|
ss.fatal(this, "No search engine is configured");
|
||||||
|
|
||||||
|
} else if (!solrUrlString.isEmpty()) {
|
||||||
|
log.debug("Initializing Solr: " + solrUrlString);
|
||||||
|
new SolrSmokeTest(this).doTest(sce);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.debug("Initializing ElasticSearch: " + elasticUrlString);
|
||||||
|
new ElasticSmokeTest(this).doTest(sce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent sce) {
|
||||||
|
// nothing to tear down.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,23 +35,28 @@ import org.apache.http.util.EntityUtils;
|
||||||
*
|
*
|
||||||
* If we can't connect to Solr, add a Warning item to the StartupStatus.
|
* If we can't connect to Solr, add a Warning item to the StartupStatus.
|
||||||
*/
|
*/
|
||||||
public class SolrSmokeTest implements ServletContextListener {
|
public class SolrSmokeTest {
|
||||||
private static final Log log = LogFactory.getLog(SolrSmokeTest.class);
|
private static final Log log = LogFactory.getLog(SolrSmokeTest.class);
|
||||||
|
|
||||||
|
private final ServletContextListener listener;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't want to treat socket timeout as a non-recoverable error like the
|
* We don't want to treat socket timeout as a non-recoverable error like the
|
||||||
* other exceptions. So pretend there's a status code for it instead.
|
* other exceptions. So pretend there's a status code for it instead.
|
||||||
*/
|
*/
|
||||||
private static final int SOCKET_TIMEOUT_STATUS = -500;
|
private static final int SOCKET_TIMEOUT_STATUS = -500;
|
||||||
|
|
||||||
@Override
|
public SolrSmokeTest(ServletContextListener listener) {
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doTest(ServletContextEvent sce) {
|
||||||
final StartupStatus ss = StartupStatus.getBean(sce.getServletContext());
|
final StartupStatus ss = StartupStatus.getBean(sce.getServletContext());
|
||||||
|
|
||||||
String solrUrlString = ConfigurationProperties.getBean(sce)
|
String solrUrlString = ConfigurationProperties.getBean(sce)
|
||||||
.getProperty("vitro.local.solr.url", "");
|
.getProperty("vitro.local.solr.url", "");
|
||||||
if (solrUrlString.isEmpty()) {
|
if (solrUrlString.isEmpty()) {
|
||||||
ss.fatal(this, "Can't connect to Solr search engine. "
|
ss.fatal(listener, "Can't connect to Solr search engine. "
|
||||||
+ "runtime.properties must contain a value for "
|
+ "runtime.properties must contain a value for "
|
||||||
+ "vitro.local.solr.url");
|
+ "vitro.local.solr.url");
|
||||||
return;
|
return;
|
||||||
|
@ -62,27 +67,22 @@ public class SolrSmokeTest implements ServletContextListener {
|
||||||
try {
|
try {
|
||||||
solrUrl = new URL(solrUrlString);
|
solrUrl = new URL(solrUrlString);
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
ss.fatal(this, "Can't connect to Solr search engine. "
|
ss.fatal(listener, "Can't connect to Solr search engine. "
|
||||||
+ "The value for vitro.local.solr.url "
|
+ "The value for vitro.local.solr.url "
|
||||||
+ "in runtime.properties is not a valid URL: '"
|
+ "in runtime.properties is not a valid URL: '"
|
||||||
+ solrUrlString + "'", e);
|
+ solrUrlString + "'", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.info(this, "Starting thread for Solr test.");
|
ss.info(listener, "Starting thread for Solr test.");
|
||||||
new SolrSmokeTestThread(this, solrUrl, ss).start();
|
new SolrSmokeTestThread(listener, solrUrl, ss).start();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contextDestroyed(ServletContextEvent sce) {
|
|
||||||
// nothing to tear down.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SolrSmokeTestThread extends VitroBackgroundThread {
|
private static class SolrSmokeTestThread extends VitroBackgroundThread {
|
||||||
private final SolrSmokeTest listener;
|
private final ServletContextListener listener;
|
||||||
private final URL solrUrl;
|
private final URL solrUrl;
|
||||||
private final StartupStatus ss;
|
private final StartupStatus ss;
|
||||||
|
|
||||||
public SolrSmokeTestThread(SolrSmokeTest listener, URL solrUrl,
|
public SolrSmokeTestThread(ServletContextListener listener, URL solrUrl,
|
||||||
StartupStatus ss) {
|
StartupStatus ss) {
|
||||||
super("SolrSmokeTest");
|
super("SolrSmokeTest");
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
|
@ -67,5 +67,5 @@ org.apache.commons.fileupload.servlet.FileCleanerCleanup
|
||||||
# and the PermissionRegistry must already be set up.
|
# and the PermissionRegistry must already be set up.
|
||||||
edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache$Setup
|
edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache$Setup
|
||||||
|
|
||||||
# This should be near the end, because it will issue a warning if the connection to Solr times out.
|
# This should be near the end, because it will issue a warning if the connection to Solr or ElasticSearch times out.
|
||||||
edu.cornell.mannlib.vitro.webapp.servlet.setup.SolrSmokeTest
|
edu.cornell.mannlib.vitro.webapp.servlet.setup.SearchEngineSmokeTest
|
||||||
|
|
Loading…
Add table
Reference in a new issue