Create a failover administration server using mediator and WedDAV
Managed by | Updated .
Background
This article describes how to setup a hot-standby, failover administration server. It uses the same building blocks as supporting multiple query processor, but with additional automation to keep the failover administration server in sync with the main one.
Primary administration server
Configure the primary administration server as per the official instructions for configuring multiple query processors.
A number of additional additional steps should be configured as outlined below.
Optionally disable the WebDAV service
The WebDAV service used to transfer files between Funnelback servers. As no other Funnelback server is supposed to push files to the main admin server, the WebDAV service can be disabled on the main admin server.
It is optional, and is just a safety measure to ensure that any misconfiguration will not result in other servers pushing files to the main admin server.
To disable the WebDAV service, locate the daemon.services
line from $SEARCH_HOME/conf/global.cfg.default
. It will be similar to daemon.services=FilterService,WebDavService
. Copy this line to $SEARCH_HOME/conf/global.cfg
, but remove the WebDavService
item from the comma delimited list, e.g.:
daemon.services=FilterService
After changing this setting the Funnelback daemon will need to be restarted.
Please note: disabling the Funnelback daemon webdav service will have no impact on the ability to access template and associated files via webdav for 15.20 or newer servers. The Jetty webserver is responsible for providing this (which just happens to also use the webdav protocol).
Ensure that the list of query processors contain the additional failover admin
Ensure the query processors and failover admin servers are listed as query processors in global.cfg
, as per the original instructions to support multiple query processors:
query_processors=qp1.mycluster.com,qp2.mycluster.com,ad2.mycluster.com
This will ensure that new crawls and indexes are pushed to the failover admin servers whenever a collection updates, identically to what happens for every query processor.
Configure periodic sync between admin servers
The previous configuration will ensure that the data of each collection is updated on the failover admin whenever a collection updates. An additional script must be used to keep collection and server configuration in sync, so that configuration changes on the main admin server are reflected on the failover server.
The following folders need to be kept in sync between servers:
conf/
- Contains the global and collection configuration. Note: The global.cfg file must be excluded as it contains server-specific settings that will differ on the failover admin serveradmin/
- Contains the user accountsdatabases/
- Contains internal, embedded databases
The synchronization of folders can be done via any mean (e.g. rsync or lsyncd on Linux, or other means on Windows). An example Groovy script taking advantage of the Funnelback WebDAV facility is provided below to achieve this synchronization without other external tools.
Save the code below to $SEARCH_HOME/conf/sync_ad.groovy
import com.funnelback.common.config.*
import com.funnelback.mediator.core.webdav.*
import java.nio.file.*
/*
* Command line tool to transfer arbitrary files to a remote Funnelback server
* using the WebDAV protocol. It assumes that:
*
* - Both Funnelback instances share the same server_secret in global.cfg
* - The WebDAV service is up and running on the remote side
* - Access to the WebDAV port (usually 8076) has been opened in the firewall
*
* Only files from within the local Funnelback install can be transferred.
* conf/global.cfg is always skipped.
*/
// Port of the remote WebDAV service
def final DEFAULT_WEBDAV_PORT = 8076;
// Setup command line options
def cli = new CliBuilder(usage: getClass().simpleName+' -h <remote_host> <file or folder> [file or folder] ...')
cli.with {
header = "Transfer a file to a remote Funnelback server.\n" + "Both Funnnelback servers must have the same server_secret"
h longOpt: "host", argName: 'hostname', args:1, type: String.class, "Remote host name"
p longOpt: "port", argName: 'port', args:1, type: Number.class, "Remote host WebDAV port (Defaults to $DEFAULT_WEBDAV_PORT)"
d longOpt: "delete", "Delete remote files that don't exist locally (Default: false)"
s longOpt: "smart", "Do not transfer file that already exist remotely, based on the filesize (Default: false)"
r longOpt: "recursive", "Transfer folders recursively (Default: false)"
v longOpt: "verbose", "Verbose mode"
}
def options = cli.parse(args)
if (!options) return;
if (!options.h || !options.arguments()) {
// No host name, or no file to transfer
cli.usage()
return;
}
def port = DEFAULT_WEBDAV_PORT
if (options.p) port = options.p
def fs = FileSystems.getDefault()
def searchHome = fs.getPath(new File(System.getenv("SEARCH_HOME")).absolutePath)
def config = new GlobalOnlyConfig(searchHome.toFile()) // Global config data, for the server_secret
def webdav = new FunnelbackSardine(config.value("server_secret")) // WebDAV client, to push files
def urlHelper = new WebDAVUrlFactory(options.'host', port) // Helper to build URL to the remote machine
// For each file or folder...
options.arguments().each {
// The actual file
def file = new File(it)
// A path object makes it easer to manipulate
def path = fs.getPath(file.absolutePath)
if (! file.exists()) {
println "Skipping '$path' as it doesn't exist"
} else if (file =~ /global\.cfg$/) {
println "Skipping '$path' as it's global.cfg"
} else if (! path.startsWith(searchHome)) {
println "Skipping '$path' as it doesn't belong to SEARCH_HOME ($searchHome)"
} else {
def targetUrl = urlHelper.root() + searchHome.relativize(path).toString().replace("\\", "/")
println "Transferring '$path' to '$targetUrl'"
if (file.isDirectory()) {
def transferred;
if (options.r) {
transferred = webdav.recursiveSync(
targetUrl,
file,
options.d,
options.s);
} else {
transferred = webdav.sync(
targetUrl,
file,
options.d,
options.s);
}
// Display transferred files
if (options.v) {
println "${transferred.size} files transferred"
transferred.each {
System.out << ((it.success) ? "OK " : "FAIL ")
System.out << it.filename.padRight(40) << " "
System.out << ((it.success) ? "" : it.statusCode.toString())
System.out << ((it.errorMessage) ? " " + it.errorMessage : "")
System.out << "\n"
}
}
} else {
webdav.put(targetUrl, file);
}
}
}
Schedule a periodic sync
The above script (or alternate syncing process using rsync, lsyncd etc.) needs to be called on the 3 folders mentioned previously (conf/
, admin/
and databases/
). This can be achieved via the OS scheduler (crontab on Linux, Scheduled Tasks control panel on Windows). Running the script every 10min is recommended (depending how often the main admin server configuration changes).
The above script will need to be invoked via Groovy with the correct classpath and options:
-h
: To specify the target hostname-s
: To enable a "smart" mode that will not re-transfer identical files-d
: To delete files on the failover admin that were deleted on the main admin server-r
: To recursively transfer all files-v
; Optional, for verbose mode
Example of a Linux wrapper script
The following bash script can be saved to $SEARCH_HOME/conf/sync_ad_wrapper.sh
. Ensure that the script is made executable after it is saved.
#!/bin/bash
$SEARCH_HOME/linbin/java/bin/java -Djna.library.path=$SEARCH_HOME/bin -cp $SEARCH_HOME/lib/java/all/*:$SEARCH_HOME/lib/java/groovy -Xms32m -Xmx350m -Dfile.encoding=UTF-8 groovy.ui.GroovyMain $SEARCH_HOME/conf/sync_ad.groovy -h ad2.mycluster.com -s -d -v -r $SEARCH_HOME/conf $SEARCH_HOME/admin $SEARCH_HOME/databases
Example of a Windows wrapper script
The following batch file can be saved to \conf\sync_ad_wapper.bat
@echo off
REM Note the caret to prevent the shell from interpreting the star (*)
\tools\groovy\bin\groovy -cp \lib\java\all\^\* \conf\sync_ad.groovy -h ad2.mycluster.com -s -d -v -r \conf %SEARCH_HOME\admin %SEARCH_HOME\databases
Failover administration server
The following instructions cover server configuration for a failover administration server that provides limited failover services:
- Read only access to server configuration
- Access to analytics
- Updates are disabled
Configure the failover administration server as per the official instructions for configuring a query processor server.
The following additional steps should be configured:
- Ensure the server shares the same server_secret as other servers in the cluster (as the other query processors - refer to the official instructions)
- Ensure the WebDAV port is configured correctly and accessible (default is port 8076)
Configure the administration UI to operate in read only mode by editing
global.cfg
. This prevents changes being made on the failover administration server via the admin UI.admin.read-only-mode=true
Disable scheduled tasks/cron jobs for Funnelback related updates (analytics and trend alerts updates)
- (optional) Configure load balancer rules as appropriate to failover users to this server.
Failover admin service to the hot standby server
The following instructions can be used to convert a failover admin server into the primary admin server:
If the primary admin server is still available the following tasks need to be performed on the main admin server to prevent it from continuing to run updates and push new configuration and data files to the failover admin and query processors:
One the primary admin server:
- Stop any running updates
- Disable scheduled tasks/cron jobs (Sync configuration, collection updates, report updates, trend alerts updates)
- Enable Admin UI read only mode
- Run the sync configuration scheduled task manually to ensure the failover admin has the latest configuration.
- Comment out the
query_processors
line inglobal.cfg
to prevent any further pushing of files.
Perform the following operations on the failover admin server to convert it to the primary admin server:
- Disable Admin UI read only mode.
- Disable the WebDAV service (prevents the main admin server for erroneously pushing files to the failover one, while the failover has the service)
- Configure the
query_processors
line inglobal.cfg
so that the failover admin server can push new configuration and data to them - Schedule collection updates, analytics and trend alerts updates
- (optional) Setup and configure a sync configuration task to clone configuration to any other failover administration server.