diff --git a/heartbeat/mysql-proxy b/heartbeat/mysql-proxy index 4cb0bc9d9..b79f31125 100755 --- a/heartbeat/mysql-proxy +++ b/heartbeat/mysql-proxy @@ -1,719 +1,741 @@ #!/bin/sh # # Resource script for MySQL Proxy # # Description: Manages MySQL Proxy as an OCF resource in # an high-availability setup. # # Tested with MySQL Proxy 0.8.1 and 0.8.3 on Debian 6.0. # # Based on the mysql and Pure-Ftpd OCF resource agents. # # Author: Raoul Bhatia : Original Author # License: GNU General Public License (GPL) # # # usage: $0 {start|stop|reload|status|monitor|validate-all|meta-data} # # The "start" arg starts a MySQL Proxy instance # # The "stop" arg stops it. # # TODO # * add in-depth monitoring by querying the mysql-proxy admin port # # Test via # (note: this did not work with MySQL Proxy 0.8.1 and ocf-tester from resource-agents 3.9.2 on Debian 6.0) # # * /usr/sbin/ocf-tester -n mp -o binary="/usr/sbin/mysql-proxy" -o defaults_file="" -o parameters="--proxy-skip-profiling" \ # -o admin_address="127.0.0.1:4041" -o admin_username="root" -o admin_password="la" -o admin_lua_script="/usr/lib/mysql-proxy/lua/admin.lua" \ # -o proxy_backend_addresses="192.168.100.200:42006" -o proxy_address="/var/run/mysqld/mysqld.sock" /usr/lib/ocf/resource.d/heartbeat/mysql-proxy # # # OCF parameters: # OCF_RESKEY_binary # OCF_RESKEY_client_binary # OCF_RESKEY_defaults_file # OCF_RESKEY_proxy_backend_addresses # OCF_RESKEY_proxy_read_only_backend_addresses # OCF_RESKEY_proxy_address # OCF_RESKEY_log_level # OCF_RESKEY_keepalive # OCF_RESKEY_plugins # OCF_RESKEY_admin_address # OCF_RESKEY_admin_username # OCF_RESKEY_admin_password # OCF_RESKEY_admin_lua_script # OCF_RESKEY_test_table # OCF_RESKEY_test_user # OCF_RESKEY_test_passwd # OCF_RESKEY_parameters # OCF_RESKEY_pidfile # ########################################################################## # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs -: ${OCF_RESKEY_binary="/usr/sbin/mysql-proxy"} -: ${OCF_RESKEY_client_binary="mysql"} -: ${OCF_RESKEY_defaults_file=""} -: ${OCF_RESKEY_proxy_backend_addresses="127.0.0.1:3306"} -: ${OCF_RESKEY_proxy_read_only_backend_addresses=""} -: ${OCF_RESKEY_proxy_address=":4040"} -: ${OCF_RESKEY_log_level=""} -: ${OCF_RESKEY_keepalive=""} -: ${OCF_RESKEY_plugins=""} -: ${OCF_RESKEY_admin_address="127.0.0.1:4041"} -: ${OCF_RESKEY_admin_username=""} -: ${OCF_RESKEY_admin_password=""} -: ${OCF_RESKEY_admin_lua_script=""} -: ${OCF_RESKEY_test_table="mysql.user"} -: ${OCF_RESKEY_test_user=""} -: ${OCF_RESKEY_test_passwd=""} -: ${OCF_RESKEY_parameters=""} -: ${OCF_RESKEY_pidfile="${HA_RSCTMP}/mysql-proxy-${OCF_RESOURCE_INSTANCE}.pid"} +# Parameter defaults + +OCF_RESKEY_binary_default="/usr/sbin/mysql-proxy" +OCF_RESKEY_client_binary_default="mysql" +OCF_RESKEY_defaults_file_default="" +OCF_RESKEY_proxy_backend_addresses_default="127.0.0.1:3306" +OCF_RESKEY_proxy_read_only_backend_addresses_default="" +OCF_RESKEY_proxy_address_default=":4040" +OCF_RESKEY_log_level_default="" +OCF_RESKEY_keepalive_default="" +OCF_RESKEY_plugins_default="" +OCF_RESKEY_admin_address_default="127.0.0.1:4041" +OCF_RESKEY_admin_username_default="" +OCF_RESKEY_admin_password_default="" +OCF_RESKEY_admin_lua_script_default="" +OCF_RESKEY_test_table_default="mysql.user" +OCF_RESKEY_test_user_default="" +OCF_RESKEY_test_passwd_default="" +OCF_RESKEY_parameters_default="" +OCF_RESKEY_pidfile_default="${HA_RSCTMP}/mysql-proxy-${OCF_RESOURCE_INSTANCE}.pid" + +: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} +: ${OCF_RESKEY_client_binary=${OCF_RESKEY_client_binary_default}} +: ${OCF_RESKEY_defaults_file=${OCF_RESKEY_defaults_file_default}} +: ${OCF_RESKEY_proxy_backend_addresses=${OCF_RESKEY_proxy_backend_addresses_default}} +: ${OCF_RESKEY_proxy_read_only_backend_addresses=${OCF_RESKEY_proxy_read_only_backend_addresses_default}} +: ${OCF_RESKEY_proxy_address=${OCF_RESKEY_proxy_address_default}} +: ${OCF_RESKEY_log_level=${OCF_RESKEY_log_level_default}} +: ${OCF_RESKEY_keepalive=${OCF_RESKEY_keepalive_default}} +: ${OCF_RESKEY_plugins=${OCF_RESKEY_plugins_default}} +: ${OCF_RESKEY_admin_address=${OCF_RESKEY_admin_address_default}} +: ${OCF_RESKEY_admin_username=${OCF_RESKEY_admin_username_default}} +: ${OCF_RESKEY_admin_password=${OCF_RESKEY_admin_password_default}} +: ${OCF_RESKEY_admin_lua_script=${OCF_RESKEY_admin_lua_script_default}} +: ${OCF_RESKEY_test_table=${OCF_RESKEY_test_table_default}} +: ${OCF_RESKEY_test_user=${OCF_RESKEY_test_user_default}} +: ${OCF_RESKEY_test_passwd=${OCF_RESKEY_test_passwd_default}} +: ${OCF_RESKEY_parameters=${OCF_RESKEY_parameters_default}} +: ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}} + USAGE="Usage: $0 {start|stop|reload|status|monitor|validate-all|meta-data}" ########################################################################## usage() { echo $USAGE >&2 } meta_data() { cat < 0.1 This script manages MySQL Proxy as an OCF resource in a high-availability setup. The default monitor operation will verify that mysql-proxy is running. The level 10 monitor operation is left out intentionally for possible future enhancements in conjunction with the admin plugin. The level 20 monitor operation will perform a SELECT on a given table to verify that the connection to a back-end server is actually working. Tested with MySQL Proxy 0.8.1 and 0.8.3 on Debian 6.0. Manages a MySQL Proxy instance Full path to the MySQL Proxy binary. For example, "/usr/sbin/mysql-proxy". Full path to MySQL Proxy binary - + Location of the MySQL client binary. MySQL client binary - + Full path to a MySQL Proxy configuration file. For example, "/etc/mysql-proxy.conf". Full path to configuration file - + Address:port of the remote back-end servers (default: 127.0.0.1:3306). MySQL Proxy back-end servers - + Address:port of the remote (read only) slave-server (default: ). MySql Proxy read only back-end servers - + Listening address:port of the proxy server (default: :4040). You can also specify a socket like "/tmp/mysql-proxy.sock". MySQL Proxy listening address - + Log all messages of level (error|warning|info|message|debug|) or higher. An empty value disables logging. MySQL Proxy log level. - + Try to restart the proxy if it crashed (default: ). Valid values: true or false. An empty value equals "false". Use keepalive option - + Whitespace separated list of plugins to load (default: ). Note: The admin plugin will be auto-loaded in case you specify an admin_* parameter. MySQL Proxy plugins - + Listening address:port of the admin plugin (default: 127.0.0.1:4041). Note: The admin plugin will be auto-loaded in case you specify an admin_* parameter. MySQL Proxy admin plugin listening address - + Username for the admin plugin (default: ). Required since MySQL Proxy 0.8.1, if the admin plugin is loaded. Note: The admin plugin will be auto-loaded in case you specify an admin_* parameter. MySQL Proxy admin plugin username - + Password for the admin plugin (default: ). Required since MySQL Proxy 0.8.1, if the admin plugin is loaded. Note: The admin plugin will be auto-loaded in case you specify an admin_* parameter. MySQL Proxy admin plugin password - + Script to execute by the admin plugin. Required since MySQL Proxy 0.8.1, if the admin plugin is loaded. Note: The admin plugin will be auto-loaded in case you specify an admin_* parameter. MySQL Proxy admin plugin lua script - + Table to be tested in monitor statement (in database.table notation) MySQL test table - + MySQL test user MySQL test user - + MySQL test user password MySQL test user password - + The MySQL Proxy daemon may be called with additional parameters. Specify any of them here. MySQL Proxy additional parameters - + PID file PID file - + END } isRunning() { kill -s 0 "$1" 2>/dev/null } mysqlproxy_status() { local PID if [ -f "${pidfile}" ]; then # MySQL Proxy is probably running PID=`head -n 1 "${pidfile}"` if [ ! -z "$PID" ] ; then isRunning "$PID" return $? fi fi # MySQL Proxy is not running false } mysqlproxy_start() { local PARAM_PREFIX OPTIONS local p pa pba proba local pid_dir socket_dir # if MySQL Proxy is running return success if mysqlproxy_status ; then ocf_log info "MySQL Proxy already running." return $OCF_SUCCESS fi PARAM_PREFIX='' # MySQL Proxy plugins to load # @TODO check if the plugins are actually available? if ocf_is_true $plugin_support; then for p in $plugins; do PARAM_PREFIX="$PARAM_PREFIX --plugins=$p" done fi # check if the MySQL Proxy defaults-file exist if [ -f "$defaults_file" ]; then PARAM_PREFIX="$PARAM_PREFIX --defaults-file=$defaults_file" fi # set log-level if [ ! -z "$log_level" ]; then PARAM_PREFIX="$PARAM_PREFIX --log-level=$log_level" fi # set keepalive if [ "$keepalive" = "true" ]; then PARAM_PREFIX="$PARAM_PREFIX --keepalive" fi # honor admin_* options if [ ! -z "$admin_username" ]; then PARAM_PREFIX="$PARAM_PREFIX --admin-username=$admin_username" fi if [ ! -z "$admin_password" ]; then PARAM_PREFIX="$PARAM_PREFIX --admin-password=$admin_password" fi if [ ! -z "$admin_lua_script" ]; then PARAM_PREFIX="$PARAM_PREFIX --admin-lua-script=$admin_lua_script" fi # make sure that the pid directory exists pid_dir=`dirname $pidfile` if [ ! -d $pid_dir ] ; then ocf_log info "Creating PID directory '$pid_dir'." mkdir -p $pid_dir #chown $OCF_RESKEY_user:$OCF_RESKEY_group $pid_dir # c/p from mysql ra; currently not needed fi # split multiple proxy-address options. # currently unsupported but let us hope for the future ;) for pa in $proxy_address; do [ -z "$pa" ] && continue OPTIONS=" $OPTIONS --proxy-address=$pa" # if $pa contains a slash, we are dealing with a socket # make sure that the socket directory exists if echo "$pa" | grep -q '/' ; then socket_dir=`dirname $pa` if [ ! -d $socket_dir ] ; then ocf_log info "Creating socket directory '$socket_dir'." mkdir -p $socket_dir #chown $OCF_RESKEY_user:$OCF_RESKEY_group $socket_dir # c/p from mysql ra; currently not needed fi fi done # split multiple proxy-backend-addresses options. for pba in $proxy_backend_addresses; do [ -z "$pba" ] && continue OPTIONS=" $OPTIONS --proxy-backend-addresses=$pba" done # split multiple proxy-backend-addresses options. for proba in $proxy_read_only_backend_addresses; do [ -z "$proba" ] && continue OPTIONS=" $OPTIONS --proxy-read-only-backend-addresses=$proba" done # build $OPTIONS and add admin-address and pidfile OPTIONS="$PARAM_PREFIX $OPTIONS --admin-address=$admin_address --pid-file=${pidfile}" # add additional parameters if [ -n "$parameters" ]; then OPTIONS="$OPTIONS $parameters" fi # start MySQL Proxy #start-stop-daemon --start --quiet --pidfile $pidfile --make-pidfile --name mysql-proxy --startas $binary -b -- $OPTIONS $binary --daemon $OPTIONS ret=$? if [ $ret -ne 0 ]; then ocf_log err "MySQL Proxy returned error: " $ret return $OCF_ERR_GENERIC fi # @TODO add an initial monitoring action? return $OCF_SUCCESS } mysqlproxy_stop() { local ret local pa if mysqlproxy_status ; then #start-stop-daemon --stop --quiet --retry 3 --exec $binary --pidfile $pidfile /bin/kill `cat "${pidfile}"` ret=$? if [ $ret -ne 0 ]; then ocf_log err "MySQL Proxy returned an error while stopping: " $ret return $OCF_ERR_GENERIC fi # grant some time for shutdown and recheck sleep 1 if mysqlproxy_status ; then ocf_log err "MySQL Proxy failed to stop." return $OCF_ERR_GENERIC fi # remove dangling socketfile, if specified for pa in $proxy_address; do if [ -S "$pa" ]; then ocf_log info "Removing dangling socket file '$pa'." rm -f "$pa" fi done # remove dangling pidfile if [ -f "${pidfile}" ]; then ocf_log info "Removing dangling pidfile '${pidfile}'." rm -f "${pidfile}" fi fi return $OCF_SUCCESS } mysqlproxy_reload() { # @TODO check if pidfile is empty # PID=`head -n 1 "${pidfile}"` # if [ ! -z "$PID" ] ; then if mysqlproxy_status; then ocf_log info "Reloading MySQL Proxy." kill -s HUP `cat ${pidfile}` fi } mysqlproxy_monitor() { local rc if [ "${OCF_RESKEY_CRM_meta_interval:-0}" -eq "0" ]; then # in case of probe, monitor operation is surely treated as # under suspension. This will call start operation. # (c/p from ocf:heartbeat:sfex) mysqlproxy_validate_all rc=$? [ $rc -ne 0 ] && return $rc fi if ! mysqlproxy_status ; then return $OCF_NOT_RUNNING fi if [ $OCF_CHECK_LEVEL -eq 20 ]; then mysqlproxy_monitor_20 rc=$? [ $rc -ne 0 ] && return $rc fi return $OCF_SUCCESS } mysqlproxy_monitor_20() { local rc local mysql_options pa local mysql_server_parameter mysql_server_host mysql_server_port if [ -z "$OCF_RESKEY_test_table" -o -z "$OCF_RESKEY_test_user" -a -z "$OCF_RESKEY_test_passwd" ]; then ocf_log warn "Missing proper configuration for OCF_CHECK_LEVEL=20 (test_table=[$OCF_RESKEY_test_table] test_user=[$OCF_RESKEY_test_user] test_password=[$OCF_RESKEY_test_passwd]). Not running in-depth monitoring." return $OCF_SUCCESS fi mysql_options="--connect_timeout=10 --user=$OCF_RESKEY_test_user --password=$OCF_RESKEY_test_passwd" # cycle each address for pa in $proxy_address; do # build correct connect parameter if [ -S "$pa" ]; then # we need to monitor a mysql socket mysql_server_parameter="--socket=$pa" else # we need to monitor a host address mysql_server_parameter="" # split host:port # @TODO correctly handle IPv6 address # @TODO correctly handle 0.0.0.0 address mysql_server_host=`echo $pa | cut -d : -f 1` mysql_server_port=`echo $pa | cut -d : -f 2` if [ -n "$mysql_server_host" ]; then mysql_server_parameter="$mysql_server_parameter --host=$mysql_server_host" fi if [ -n "$mysql_server_port" ]; then mysql_server_parameter="$mysql_server_parameter --port=$mysql_server_port" fi fi # Check for test table ocf_run $mysql $mysql_server_parameter $mysql_options \ -e "SELECT COUNT(*) FROM $OCF_RESKEY_test_table" rc=$? if [ $rc -ne 0 ]; then ocf_log err "Failed to select from $OCF_RESKEY_test_table: " $rc return $OCF_ERR_GENERIC fi done return $OCF_SUCCESS } mysqlproxy_validate_all() { # local variables local config_error=0 # check that the MySQL Proxy binary exists and can be executed check_binary $binary # check MySQL client binary only if in-depth monitoring is requested # do not break backwards compatibility otherwise if [ $OCF_CHECK_LEVEL -gt 0 ]; then check_binary $mysql fi # check for valid log-level echo $log_level | egrep -q "^(error|warning|info|message|debug|)$" if [ $? -ne 0 ]; then ocf_log err "MySQL Proxy log level '$log_level' not in valid range error|warning|info|message|debug" return $OCF_ERR_CONFIGURED fi # if we're running MySQL Proxy > 0.8.1 and there is any admin parameter set, # explicitly load the admin (and the proxy) plugin. # (version 0.8.2 does not load the admin plugin by default anymore) ocf_version_cmp "$version" "0.8.1" ret=$? if [ $ret -eq 2 ]; then # simple check: concat all parameters and check if the string has non-zero length if [ -n "$admin_username$admin_password$admin_lua_script$admin_address" ]; then plugins="proxy admin" has_plugin_admin=1 else has_plugin_admin=0 fi fi # check for required admin_* parameters for 0.8.1 and 0.8.2 (with admin module) # translated: if (version == 0.8.1 or (version > 0.8.1 and has_plugin_admin)) if [ $ret -eq 1 -o \( $ret -eq 2 -a $has_plugin_admin -eq 1 \) ]; then if [ -z "$admin_username" ]; then ocf_log err "Missing required parameter \"admin_username\"" config_error=1 fi if [ -z "$admin_password" ]; then ocf_log err "Missing required parameter \"admin_password\"" config_error=1 fi if [ -z "$admin_lua_script" ]; then ocf_log err "Missing required parameter \"admin_lua_script\"" config_error=1 fi # check if the admin_lua_script, if specified, exists if [ -n "$admin_lua_script" -a ! -e "$admin_lua_script" ]; then ocf_log err "MySQL Proxy admin lua script '$admin_lua_script' does not exist or is not readable." fi fi # issue a warning during start if the user wants to load a plugin # but this version of MySQL Proxy does not support the plugin architecture. if [ -n "$plugins" ] && ocf_is_false "$plugin_support" && [ $__OCF_ACTION = 'start' ]; then ocf_log warn "You are running MySQL Proxy version '$version'. This version does not support the plugin architecture. Please use version 0.7.0 or later to load the plugins '$plugins'." fi # exit in case we have found relevant config errors if [ $config_error -eq 1 ]; then exit $OCF_ERR_CONFIGURED fi return $OCF_SUCCESS } # # Main # if [ $# -ne 1 ]; then usage exit $OCF_ERR_ARGS fi pidfile=$OCF_RESKEY_pidfile binary=$OCF_RESKEY_binary defaults_file=$OCF_RESKEY_defaults_file proxy_backend_addresses=$OCF_RESKEY_proxy_backend_addresses proxy_read_only_backend_addresses=$OCF_RESKEY_proxy_read_only_backend_addresses admin_address=$OCF_RESKEY_admin_address admin_username=$OCF_RESKEY_admin_username admin_password=$OCF_RESKEY_admin_password admin_lua_script=$OCF_RESKEY_admin_lua_script proxy_address=$OCF_RESKEY_proxy_address log_level=$OCF_RESKEY_log_level keepalive=$OCF_RESKEY_keepalive plugins=`echo $OCF_RESKEY_plugins | tr "[:space:]" "\n" | sort -u` mysql=$OCF_RESKEY_client_binary parameters=$OCF_RESKEY_parameters plugin_support=false has_plugin_admin=0 # 0 because this simplifies the if statements # debugging stuff #echo OCF_RESKEY_binary=$OCF_RESKEY_binary >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_defaults_file=$OCF_RESKEY_defaults_file >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_proxy_backend_addresses=$OCF_RESKEY_proxy_backend_addresses >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_proxy_read_only_backend_addresses=$OCF_RESKEY_proxy_read_only_backend_addresses >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_proxy_address=$OCF_RESKEY_proxy_address >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_log_level=$OCF_RESKEY_log_level >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_keepalive=$OCF_RESKEY_keepalive >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_admin_address=$OCF_RESKEY_admin_address >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_admin_username=$OCF_RESKEY_admin_username >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_admin_password=$OCF_RESKEY_admin_password >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_admin_lua_script=$OCF_RESKEY_admin_lua_script >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_parameters=$OCF_RESKEY_parameters >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE #echo OCF_RESKEY_pidfile=$OCF_RESKEY_pidfile >> /tmp/prox_conf_$OCF_RESOURCE_INSTANCE # handle some parameters before performing any additional checks case $1 in meta-data) meta_data exit $? ;; usage) usage exit $OCF_SUCCESS ;; esac # determine MySQL Proxy version check_binary $binary version=`$binary --version | grep ^mysql-proxy | awk '{print $NF}'` # version 0.7.0 (and later) support the plugin architecture and load the admin plugin by default # version 0.8.1 loads admin plugin by default and requires the admin parameters to be set # version 0.8.2 does not load the admin plugin by default anymore ocf_version_cmp "$version" "0.7.0" ret=$? if [ $ret -eq 1 -o $ret -eq 2 ]; then plugin_support=true has_plugin_admin=1 fi # perform action case $1 in start) mysqlproxy_validate_all && mysqlproxy_start exit $? ;; stop) mysqlproxy_validate_all && mysqlproxy_stop exit $? ;; reload) mysqlproxy_reload exit $? ;; status) if mysqlproxy_status; then ocf_log info "MySQL Proxy is running." exit $OCF_SUCCESS else ocf_log info "MySQL Proxy is stopped." exit $OCF_NOT_RUNNING fi ;; monitor) mysqlproxy_monitor exit $? ;; validate-all) mysqlproxy_validate_all exit $? ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac