PingRequestHandler is now directly configured with a "healthcheckFile" instead of looking for the legacy <admin><healthcheck/></admin> syntax. Filenames specified as relative paths have been fixed so that they are resolved against the data dir instead of the CWD of the java process.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1333598 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Chris M. Hostetter 2012-05-03 19:56:13 +00:00
parent b0a4eaba31
commit d5eeb396a5
16 changed files with 296 additions and 181 deletions

View File

@ -78,6 +78,12 @@ Upgrading from Solr 3.6-dev
CommonsHttpSolrServer is now HttpSolrServer, and CommonsHttpSolrServer is now HttpSolrServer, and
StreamingUpdateSolrServer is now ConcurrentUpdateSolrServer. StreamingUpdateSolrServer is now ConcurrentUpdateSolrServer.
* The PingRequestHandler no longer looks for a <healthcheck/> option in the
(legacy) <admin> section of solrconfig.xml. Users who wish to take
advantage of this feature should configure a "healthcheckFile" init param
directly on the PingRequestHandler. As part of this change, relative file
paths have been fixed to be resolved against the data dir. See the example
solrconfig.xml and SOLR-1258 for more details.
Detailed Change List Detailed Change List
---------------------- ----------------------
@ -535,6 +541,12 @@ Other Changes
* SOLR-3403: Deprecated Analysis Factories now log their own deprecation messages. * SOLR-3403: Deprecated Analysis Factories now log their own deprecation messages.
No logging support is provided by Factory parent classes. (Chris Male) No logging support is provided by Factory parent classes. (Chris Male)
* SOLR-1258: PingRequestHandler is now directly configured with a
"healthcheckFile" instead of looking for the legacy
<admin><healthcheck/></admin> syntax. Filenames specified as relative
paths have been fixed so that they are resolved against the data dir
instead of the CWD of the java process. (hossman)
Documentation Documentation
---------------------- ----------------------

View File

@ -464,10 +464,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>solr</defaultQuery> <defaultQuery>solr</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -305,10 +305,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -309,10 +309,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
<updateRequestProcessorChain key="contentstream" default="true"> <updateRequestProcessorChain key="contentstream" default="true">

View File

@ -307,10 +307,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -305,10 +305,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
<updateRequestProcessorChain key="dataimport" default="true"> <updateRequestProcessorChain key="dataimport" default="true">

View File

@ -968,11 +968,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*</defaultQuery> <defaultQuery>*</defaultQuery>
<!--
configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -850,11 +850,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*</defaultQuery> <defaultQuery>*</defaultQuery>
<!--
configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -19,30 +19,154 @@ package org.apache.solr.handler;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.text.SimpleDateFormat; import java.io.IOException;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrCore;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.DateField;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Ping solr core * Ping Request Handler for reporting SolrCore health to a Load Balancer.
*
* <p>
* This handler is designed to be used as the endpoint for an HTTP
* Load-Balancer to use when checking the "health" or "up status" of a
* Solr server.
* </p>
*
* <p>
* In it's simplest form, the PingRequestHandler should be
* configured with some defaults indicating a request that should be
* executed. If the request succeeds, then the PingRequestHandler
* will respond back with a simple "OK" status. If the request fails,
* then the PingRequestHandler will respond back with the
* corrisponding HTTP Error code. Clients (such as load balancers)
* can be configured to poll the PingRequestHandler monitoring for
* these types of responses (or for a simple connection failure) to
* know if there is a problem with the Solr server.
* </p>
*
* <pre class="prettyprint">
* &lt;requestHandler name="/admin/ping" class="solr.PingRequestHandler"&gt;
* &lt;lst name="invariants"&gt;
* &lt;str name="qt"&gt;/search&lt;/str&gt;&lt;!-- handler to delegate to --&gt;
* &lt;str name="q"&gt;some test query&lt;/str&gt;
* &lt;/lst&gt;
* &lt;/requestHandler&gt;
* </pre>
*
* <p>
* A more advanced option available, is to configure the handler with a
* "healthcheckFile" which can be used to enable/disable the PingRequestHandler.
* </p>
*
* <pre class="prettyprint">
* &lt;requestHandler name="/admin/ping" class="solr.PingRequestHandler"&gt;
* &lt;!-- relative paths are resolved against the data dir --&gt;
* &lt;str name="healthcheckFile"&gt;server-enabled.txt&lt;/str&gt;
* &lt;lst name="invariants"&gt;
* &lt;str name="qt"&gt;/search&lt;/str&gt;&lt;!-- handler to delegate to --&gt;
* &lt;str name="q"&gt;some test query&lt;/str&gt;
* &lt;/lst&gt;
* &lt;/requestHandler&gt;
* </pre>
*
* <ul>
* <li>If the health check file exists, the handler will execute the
* delegated query and return status as described above.
* </li>
* <li>If the health check file does not exist, the handler will return
* an HTTP error even if the server is working fine and the delegated
* query would have succeeded
* </li>
* </ul>
*
* <p>
* This health check file feature can be used as a way to indicate
* to some Load Balancers that the server should be "removed from
* rotation" for maintenance, or upgrades, or whatever reason you may
* wish.
* </p>
*
* <p>
* The health check file may be created/deleted by any external
* system, or the PingRequestHandler itself can be used to
* create/delete the file by specifying an "action" param in a
* request:
* </p>
*
* <ul>
* <li><code>http://.../ping?action=enable</code>
* - creates the health check file if it does not already exist
* </li>
* <li><code>http://.../ping?action=disable</code>
* - deletes the health check file if it exists
* </li>
* <li><code>http://.../ping?action=status</code>
* - returns a status code indicating if the healthcheck file exists
* ("<code>enabled</code>") or not ("<code>disabled<code>")
* </li>
* </ul>
* *
* @since solr 1.3 * @since solr 1.3
*/ */
public class PingRequestHandler extends RequestHandlerBase public class PingRequestHandler extends RequestHandlerBase implements SolrCoreAware
{ {
public static Logger log = LoggerFactory.getLogger(PingRequestHandler.class);
SimpleDateFormat formatRFC3339 = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ"); public static final String HEALTHCHECK_FILE_PARAM = "healthcheckFile";
protected enum ACTIONS {STATUS, ENABLE, DISABLE, PING}; protected enum ACTIONS {STATUS, ENABLE, DISABLE, PING};
private String healthcheck = null;
private String healthFileName = null;
private File healthcheck = null;
public void init(NamedList args) {
super.init(args);
Object tmp = args.get(HEALTHCHECK_FILE_PARAM);
healthFileName = (null == tmp ? null : tmp.toString());
}
public void inform( SolrCore core ) {
if (null != healthFileName) {
healthcheck = new File(healthFileName);
if ( ! healthcheck.isAbsolute()) {
healthcheck = new File(core.getDataDir(), healthFileName);
healthcheck = healthcheck.getAbsoluteFile();
}
if ( ! healthcheck.getParentFile().canWrite()) {
// this is not fatal, users may not care about enable/disable via
// solr request, file might be touched/deleted by an external system
log.warn("Directory for configured healthcheck file is not writable by solr, PingRequestHandler will not be able to control enable/disable: {}",
healthcheck.getParentFile().getAbsolutePath());
}
}
}
/**
* Returns true if the healthcheck flag-file is enabled but does not exist,
* otherwise (no file configured, or file configured and exists)
* returns false.
*/
public boolean isPingDisabled() {
return (null != healthcheck && ! healthcheck.exists() );
}
@Override @Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
@ -51,9 +175,6 @@ public class PingRequestHandler extends RequestHandlerBase
SolrParams params = req.getParams(); SolrParams params = req.getParams();
SolrCore core = req.getCore(); SolrCore core = req.getCore();
// Check if the service is available
healthcheck = core.getSolrConfig().get("admin/healthcheck/text()", null );
String actionParam = params.get("action"); String actionParam = params.get("action");
ACTIONS action = null; ACTIONS action = null;
if (actionParam == null){ if (actionParam == null){
@ -70,34 +191,30 @@ public class PingRequestHandler extends RequestHandlerBase
} }
switch(action){ switch(action){
case PING: case PING:
if( healthcheck != null && !new File(healthcheck).exists() ) { if( isPingDisabled() ) {
throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, "Service disabled"); throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE,
"Service disabled");
} }
handlePing(req, rsp); handlePing(req, rsp);
break; break;
case ENABLE: case ENABLE:
handleEnable(healthcheck,true); handleEnable(true);
break; break;
case DISABLE: case DISABLE:
handleEnable(healthcheck,false); handleEnable(false);
break; break;
case STATUS: case STATUS:
if( healthcheck == null){ if( healthcheck == null ){
SolrException e = new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, "healthcheck not configured"); SolrException e = new SolrException
(SolrException.ErrorCode.SERVICE_UNAVAILABLE,
"healthcheck not configured");
rsp.setException(e); rsp.setException(e);
} } else {
else { rsp.add( "status", isPingDisabled() ? "disabled" : "enabled" );
if ( new File(healthcheck).exists() ){
rsp.add( "status", "enabled");
}
else {
rsp.add( "status", "disabled");
} }
} }
} }
}
protected void handlePing(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception protected void handlePing(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
{ {
@ -136,24 +253,25 @@ public class PingRequestHandler extends RequestHandlerBase
rsp.add( "status", "OK" ); rsp.add( "status", "OK" );
} }
protected void handleEnable(String healthcheck, boolean enable) throws Exception protected void handleEnable(boolean enable) throws SolrException {
{
if (healthcheck == null) { if (healthcheck == null) {
throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE,
"No healthcheck file defined."); "No healthcheck file defined.");
} }
File enableFile = new File(healthcheck);
if ( enable ) { if ( enable ) {
enableFile.createNewFile(); try {
// write out when the file was created // write out when the file was created
FileWriter fw = new FileWriter(enableFile); FileUtils.write(healthcheck,
fw.write(formatRFC3339.format(new Date())); DateField.formatExternal(new Date()), "UTF-8");
fw.close(); } catch (IOException e) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Unable to write healthcheck flag file", e);
}
} else { } else {
if (enableFile.exists() && !enableFile.delete()){ if (healthcheck.exists() && !healthcheck.delete()){
throw new SolrException( SolrException.ErrorCode.NOT_FOUND,"Did not successfully delete healthcheck file:'"+healthcheck+"'"); throw new SolrException(SolrException.ErrorCode.NOT_FOUND,
"Did not successfully delete healthcheck file: "
+healthcheck.getAbsolutePath());
} }
} }
} }

View File

@ -20,21 +20,24 @@ package org.apache.solr.handler;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException;
import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.response.SolrQueryResponse;
import org.apache.commons.io.FileUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test;
public class PingRequestHandlerTest extends SolrTestCaseJ4 { public class PingRequestHandlerTest extends SolrTestCaseJ4 {
private String healthcheck = "server-enabled"; private final String fileName = this.getClass().getName() + ".server-enabled";
private File healthcheckFile = new File(healthcheck); private File healthcheckFile = null;
private PingRequestHandler handler = null; private PingRequestHandler handler = null;
@BeforeClass @BeforeClass
@ -43,116 +46,149 @@ public class PingRequestHandlerTest extends SolrTestCaseJ4 {
} }
@Before @Before
public void before() { public void before() throws IOException {
healthcheckFile.delete();
// by default, use relative file in dataDir
healthcheckFile = new File(dataDir, fileName);
String fileNameParam = fileName;
// sometimes randomly use an absolute File path instead
if (random().nextBoolean()) {
healthcheckFile = new File(TEMP_DIR, fileName);
fileNameParam = healthcheckFile.getAbsolutePath();
}
if (healthcheckFile.exists()) FileUtils.forceDelete(healthcheckFile);
handler = new PingRequestHandler(); handler = new PingRequestHandler();
NamedList initParams = new NamedList();
initParams.add(PingRequestHandler.HEALTHCHECK_FILE_PARAM,
fileNameParam);
handler.init(initParams);
handler.inform(h.getCore());
} }
@Test public void testPingWithNoHealthCheck() throws Exception {
public void testPing() throws Exception {
SolrQueryRequest req = req(); // for this test, we don't want any healthcheck file configured at all
SolrQueryResponse rsp = new SolrQueryResponse(); handler = new PingRequestHandler();
handler.init(new NamedList());
handler.inform(h.getCore());
handler.handleRequestBody(req, rsp); SolrQueryResponse rsp = null;
String status = (String) rsp.getValues().get("status");
assertEquals("OK", status);
req.close();
req = req("action","ping"); rsp = makeRequest(handler, req());
rsp = new SolrQueryResponse(); assertEquals("OK", rsp.getValues().get("status"));
rsp = makeRequest(handler, req("action","ping"));
assertEquals("OK", rsp.getValues().get("status"));
handler.handleRequestBody(req, rsp);
status = (String) rsp.getValues().get("status");
assertEquals("OK", status);
req.close();
} }
@Test
public void testEnablingServer() throws Exception { public void testEnablingServer() throws Exception {
assertTrue(! healthcheckFile.exists());
handler.handleEnable(healthcheck, true); // first make sure that ping responds back that the service is disabled
try {
makeRequest(handler, req());
fail("Should have thrown a SolrException because not enabled yet");
} catch (SolrException se){
assertEquals(SolrException.ErrorCode.SERVICE_UNAVAILABLE.code,se.code());
}
// now enable
makeRequest(handler, req("action", "enable"));
assertTrue(healthcheckFile.exists()); assertTrue(healthcheckFile.exists());
assertNotNull(FileUtils.readFileToString(healthcheckFile), "UTF-8");
SolrQueryRequest req = req(); // now verify that the handler response with success
SolrQueryResponse rsp = new SolrQueryResponse();
handler.handlePing(req, rsp); SolrQueryResponse rsp = makeRequest(handler, req());
String status = (String) rsp.getValues().get("status"); assertEquals("OK", rsp.getValues().get("status"));
assertEquals("OK", status);
req.close();
FileReader fr = new FileReader(healthcheckFile); // enable when already enabled shouldn't cause any problems
makeRequest(handler, req("action", "enable"));
BufferedReader br = new BufferedReader(fr); assertTrue(healthcheckFile.exists());
String s = br.readLine();
assertNotNull(s);
} }
@Test
public void testDisablingServer() throws Exception { public void testDisablingServer() throws Exception {
assertTrue(! healthcheckFile.exists());
healthcheckFile.createNewFile(); healthcheckFile.createNewFile();
handler.handleEnable(healthcheck, false); // first make sure that ping responds back that the service is enabled
SolrQueryResponse rsp = makeRequest(handler, req());
assertEquals("OK", rsp.getValues().get("status"));
// now disable
makeRequest(handler, req("action", "disable"));
assertFalse(healthcheckFile.exists()); assertFalse(healthcheckFile.exists());
// now make sure that ping responds back that the service is disabled
}
@Test
@Ignore // because of how we load the healthcheck file, we have to change it in schema.xml
public void testGettingStatus() throws Exception {
handler.handleEnable(healthcheck, true);
SolrQueryRequest req = req("action", "status");
SolrQueryResponse rsp = new SolrQueryResponse();
handler.handleRequestBody(req, rsp);
String status = (String) rsp.getValues().get("status");
assertEquals("enabled", status);
req.close();
handler.handleEnable(healthcheck, false);
req = req("action", "status");
rsp = new SolrQueryResponse();
handler.handleRequestBody(req, rsp);
status = (String) rsp.getValues().get("status");
assertEquals("disabled", status);
req.close();
}
@Test
public void testBadActionRaisesException() throws Exception {
SolrQueryRequest req = req("action", "badaction");
SolrQueryResponse rsp = new SolrQueryResponse();
try { try {
handler.handleRequestBody(req, rsp); makeRequest(handler, req());
fail("Should have thrown a SolrException for the bad action"); fail("Should have thrown a SolrException because not enabled yet");
} catch (SolrException se){
assertEquals(SolrException.ErrorCode.SERVICE_UNAVAILABLE.code,se.code());
} }
catch (SolrException se){
// disable when already disabled shouldn't cause any problems
makeRequest(handler, req("action", "disable"));
assertFalse(healthcheckFile.exists());
}
public void testGettingStatus() throws Exception {
SolrQueryResponse rsp = null;
handler.handleEnable(true);
rsp = makeRequest(handler, req("action", "status"));
assertEquals("enabled", rsp.getValues().get("status"));
handler.handleEnable(false);
rsp = makeRequest(handler, req("action", "status"));
assertEquals("disabled", rsp.getValues().get("status"));
}
public void testBadActionRaisesException() throws Exception {
try {
SolrQueryResponse rsp = makeRequest(handler, req("action", "badaction"));
fail("Should have thrown a SolrException for the bad action");
} catch (SolrException se){
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code,se.code()); assertEquals(SolrException.ErrorCode.BAD_REQUEST.code,se.code());
} }
}
/**
* Helper Method: Executes the request against the handler, returns
* the response, and closes the request.
*/
private SolrQueryResponse makeRequest(PingRequestHandler handler,
SolrQueryRequest req)
throws Exception {
SolrQueryResponse rsp = new SolrQueryResponse();
try {
handler.handleRequestBody(req, rsp);
} finally {
req.close(); req.close();
}
return rsp;
} }
} }

View File

@ -488,10 +488,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -674,10 +674,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>solr</defaultQuery> <defaultQuery>solr</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -487,10 +487,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -486,10 +486,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -311,10 +311,6 @@
<!-- config for the admin interface --> <!-- config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a loadbalancer
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>

View File

@ -1064,6 +1064,12 @@
<lst name="defaults"> <lst name="defaults">
<str name="echoParams">all</str> <str name="echoParams">all</str>
</lst> </lst>
<!-- An optional feature of the PingRequestHandler is to configure the
handler with a "healthcheckFile" which can be used to enable/disable
the PingRequestHandler.
relative paths are resolved against the data dir
-->
<!-- <str name="healthcheckFile">server-enabled.txt</str> -->
</requestHandler> </requestHandler>
<!-- Echo the request contents back to the client --> <!-- Echo the request contents back to the client -->
@ -1683,13 +1689,6 @@
<!-- Legacy config for the admin interface --> <!-- Legacy config for the admin interface -->
<admin> <admin>
<defaultQuery>*:*</defaultQuery> <defaultQuery>*:*</defaultQuery>
<!-- configure a healthcheck file for servers behind a
loadbalancer
-->
<!--
<healthcheck type="file">server-enabled</healthcheck>
-->
</admin> </admin>
</config> </config>